Cesium.js 7.1 MB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223262242622526226262272622826229262302623126232262332623426235262362623726238262392624026241262422624326244262452624626247262482624926250262512625226253262542625526256262572625826259262602626126262262632626426265262662626726268262692627026271262722627326274262752627626277262782627926280262812628226283262842628526286262872628826289262902629126292262932629426295262962629726298262992630026301263022630326304263052630626307263082630926310263112631226313263142631526316263172631826319263202632126322263232632426325263262632726328263292633026331263322633326334263352633626337263382633926340263412634226343263442634526346263472634826349263502635126352263532635426355263562635726358263592636026361263622636326364263652636626367263682636926370263712637226373263742637526376263772637826379263802638126382263832638426385263862638726388263892639026391263922639326394263952639626397263982639926400264012640226403264042640526406264072640826409264102641126412264132641426415264162641726418264192642026421264222642326424264252642626427264282642926430264312643226433264342643526436264372643826439264402644126442264432644426445264462644726448264492645026451264522645326454264552645626457264582645926460264612646226463264642646526466264672646826469264702647126472264732647426475264762647726478264792648026481264822648326484264852648626487264882648926490264912649226493264942649526496264972649826499265002650126502265032650426505265062650726508265092651026511265122651326514265152651626517265182651926520265212652226523265242652526526265272652826529265302653126532265332653426535265362653726538265392654026541265422654326544265452654626547265482654926550265512655226553265542655526556265572655826559265602656126562265632656426565265662656726568265692657026571265722657326574265752657626577265782657926580265812658226583265842658526586265872658826589265902659126592265932659426595265962659726598265992660026601266022660326604266052660626607266082660926610266112661226613266142661526616266172661826619266202662126622266232662426625266262662726628266292663026631266322663326634266352663626637266382663926640266412664226643266442664526646266472664826649266502665126652266532665426655266562665726658266592666026661266622666326664266652666626667266682666926670266712667226673266742667526676266772667826679266802668126682266832668426685266862668726688266892669026691266922669326694266952669626697266982669926700267012670226703267042670526706267072670826709267102671126712267132671426715267162671726718267192672026721267222672326724267252672626727267282672926730267312673226733267342673526736267372673826739267402674126742267432674426745267462674726748267492675026751267522675326754267552675626757267582675926760267612676226763267642676526766267672676826769267702677126772267732677426775267762677726778267792678026781267822678326784267852678626787267882678926790267912679226793267942679526796267972679826799268002680126802268032680426805268062680726808268092681026811268122681326814268152681626817268182681926820268212682226823268242682526826268272682826829268302683126832268332683426835268362683726838268392684026841268422684326844268452684626847268482684926850268512685226853268542685526856268572685826859268602686126862268632686426865268662686726868268692687026871268722687326874268752687626877268782687926880268812688226883268842688526886268872688826889268902689126892268932689426895268962689726898268992690026901269022690326904269052690626907269082690926910269112691226913269142691526916269172691826919269202692126922269232692426925269262692726928269292693026931269322693326934269352693626937269382693926940269412694226943269442694526946269472694826949269502695126952269532695426955269562695726958269592696026961269622696326964269652696626967269682696926970269712697226973269742697526976269772697826979269802698126982269832698426985269862698726988269892699026991269922699326994269952699626997269982699927000270012700227003270042700527006270072700827009270102701127012270132701427015270162701727018270192702027021270222702327024270252702627027270282702927030270312703227033270342703527036270372703827039270402704127042270432704427045270462704727048270492705027051270522705327054270552705627057270582705927060270612706227063270642706527066270672706827069270702707127072270732707427075270762707727078270792708027081270822708327084270852708627087270882708927090270912709227093270942709527096270972709827099271002710127102271032710427105271062710727108271092711027111271122711327114271152711627117271182711927120271212712227123271242712527126271272712827129271302713127132271332713427135271362713727138271392714027141271422714327144271452714627147271482714927150271512715227153271542715527156271572715827159271602716127162271632716427165271662716727168271692717027171271722717327174271752717627177271782717927180271812718227183271842718527186271872718827189271902719127192271932719427195271962719727198271992720027201272022720327204272052720627207272082720927210272112721227213272142721527216272172721827219272202722127222272232722427225272262722727228272292723027231272322723327234272352723627237272382723927240272412724227243272442724527246272472724827249272502725127252272532725427255272562725727258272592726027261272622726327264272652726627267272682726927270272712727227273272742727527276272772727827279272802728127282272832728427285272862728727288272892729027291272922729327294272952729627297272982729927300273012730227303273042730527306273072730827309273102731127312273132731427315273162731727318273192732027321273222732327324273252732627327273282732927330273312733227333273342733527336273372733827339273402734127342273432734427345273462734727348273492735027351273522735327354273552735627357273582735927360273612736227363273642736527366273672736827369273702737127372273732737427375273762737727378273792738027381273822738327384273852738627387273882738927390273912739227393273942739527396273972739827399274002740127402274032740427405274062740727408274092741027411274122741327414274152741627417274182741927420274212742227423274242742527426274272742827429274302743127432274332743427435274362743727438274392744027441274422744327444274452744627447274482744927450274512745227453274542745527456274572745827459274602746127462274632746427465274662746727468274692747027471274722747327474274752747627477274782747927480274812748227483274842748527486274872748827489274902749127492274932749427495274962749727498274992750027501275022750327504275052750627507275082750927510275112751227513275142751527516275172751827519275202752127522275232752427525275262752727528275292753027531275322753327534275352753627537275382753927540275412754227543275442754527546275472754827549275502755127552275532755427555275562755727558275592756027561275622756327564275652756627567275682756927570275712757227573275742757527576275772757827579275802758127582275832758427585275862758727588275892759027591275922759327594275952759627597275982759927600276012760227603276042760527606276072760827609276102761127612276132761427615276162761727618276192762027621276222762327624276252762627627276282762927630276312763227633276342763527636276372763827639276402764127642276432764427645276462764727648276492765027651276522765327654276552765627657276582765927660276612766227663276642766527666276672766827669276702767127672276732767427675276762767727678276792768027681276822768327684276852768627687276882768927690276912769227693276942769527696276972769827699277002770127702277032770427705277062770727708277092771027711277122771327714277152771627717277182771927720277212772227723277242772527726277272772827729277302773127732277332773427735277362773727738277392774027741277422774327744277452774627747277482774927750277512775227753277542775527756277572775827759277602776127762277632776427765277662776727768277692777027771277722777327774277752777627777277782777927780277812778227783277842778527786277872778827789277902779127792277932779427795277962779727798277992780027801278022780327804278052780627807278082780927810278112781227813278142781527816278172781827819278202782127822278232782427825278262782727828278292783027831278322783327834278352783627837278382783927840278412784227843278442784527846278472784827849278502785127852278532785427855278562785727858278592786027861278622786327864278652786627867278682786927870278712787227873278742787527876278772787827879278802788127882278832788427885278862788727888278892789027891278922789327894278952789627897278982789927900279012790227903279042790527906279072790827909279102791127912279132791427915279162791727918279192792027921279222792327924279252792627927279282792927930279312793227933279342793527936279372793827939279402794127942279432794427945279462794727948279492795027951279522795327954279552795627957279582795927960279612796227963279642796527966279672796827969279702797127972279732797427975279762797727978279792798027981279822798327984279852798627987279882798927990279912799227993279942799527996279972799827999280002800128002280032800428005280062800728008280092801028011280122801328014280152801628017280182801928020280212802228023280242802528026280272802828029280302803128032280332803428035280362803728038280392804028041280422804328044280452804628047280482804928050280512805228053280542805528056280572805828059280602806128062280632806428065280662806728068280692807028071280722807328074280752807628077280782807928080280812808228083280842808528086280872808828089280902809128092280932809428095280962809728098280992810028101281022810328104281052810628107281082810928110281112811228113281142811528116281172811828119281202812128122281232812428125281262812728128281292813028131281322813328134281352813628137281382813928140281412814228143281442814528146281472814828149281502815128152281532815428155281562815728158281592816028161281622816328164281652816628167281682816928170281712817228173281742817528176281772817828179281802818128182281832818428185281862818728188281892819028191281922819328194281952819628197281982819928200282012820228203282042820528206282072820828209282102821128212282132821428215282162821728218282192822028221282222822328224282252822628227282282822928230282312823228233282342823528236282372823828239282402824128242282432824428245282462824728248282492825028251282522825328254282552825628257282582825928260282612826228263282642826528266282672826828269282702827128272282732827428275282762827728278282792828028281282822828328284282852828628287282882828928290282912829228293282942829528296282972829828299283002830128302283032830428305283062830728308283092831028311283122831328314283152831628317283182831928320283212832228323283242832528326283272832828329283302833128332283332833428335283362833728338283392834028341283422834328344283452834628347283482834928350283512835228353283542835528356283572835828359283602836128362283632836428365283662836728368283692837028371283722837328374283752837628377283782837928380283812838228383283842838528386283872838828389283902839128392283932839428395283962839728398283992840028401284022840328404284052840628407284082840928410284112841228413284142841528416284172841828419284202842128422284232842428425284262842728428284292843028431284322843328434284352843628437284382843928440284412844228443284442844528446284472844828449284502845128452284532845428455284562845728458284592846028461284622846328464284652846628467284682846928470284712847228473284742847528476284772847828479284802848128482284832848428485284862848728488284892849028491284922849328494284952849628497284982849928500285012850228503285042850528506285072850828509285102851128512285132851428515285162851728518285192852028521285222852328524285252852628527285282852928530285312853228533285342853528536285372853828539285402854128542285432854428545285462854728548285492855028551285522855328554285552855628557285582855928560285612856228563285642856528566285672856828569285702857128572285732857428575285762857728578285792858028581285822858328584285852858628587285882858928590285912859228593285942859528596285972859828599286002860128602286032860428605286062860728608286092861028611286122861328614286152861628617286182861928620286212862228623286242862528626286272862828629286302863128632286332863428635286362863728638286392864028641286422864328644286452864628647286482864928650286512865228653286542865528656286572865828659286602866128662286632866428665286662866728668286692867028671286722867328674286752867628677286782867928680286812868228683286842868528686286872868828689286902869128692286932869428695286962869728698286992870028701287022870328704287052870628707287082870928710287112871228713287142871528716287172871828719287202872128722287232872428725287262872728728287292873028731287322873328734287352873628737287382873928740287412874228743287442874528746287472874828749287502875128752287532875428755287562875728758287592876028761287622876328764287652876628767287682876928770287712877228773287742877528776287772877828779287802878128782287832878428785287862878728788287892879028791287922879328794287952879628797287982879928800288012880228803288042880528806288072880828809288102881128812288132881428815288162881728818288192882028821288222882328824288252882628827288282882928830288312883228833288342883528836288372883828839288402884128842288432884428845288462884728848288492885028851288522885328854288552885628857288582885928860288612886228863288642886528866288672886828869288702887128872288732887428875288762887728878288792888028881288822888328884288852888628887288882888928890288912889228893288942889528896288972889828899289002890128902289032890428905289062890728908289092891028911289122891328914289152891628917289182891928920289212892228923289242892528926289272892828929289302893128932289332893428935289362893728938289392894028941289422894328944289452894628947289482894928950289512895228953289542895528956289572895828959289602896128962289632896428965289662896728968289692897028971289722897328974289752897628977289782897928980289812898228983289842898528986289872898828989289902899128992289932899428995289962899728998289992900029001290022900329004290052900629007290082900929010290112901229013290142901529016290172901829019290202902129022290232902429025290262902729028290292903029031290322903329034290352903629037290382903929040290412904229043290442904529046290472904829049290502905129052290532905429055290562905729058290592906029061290622906329064290652906629067290682906929070290712907229073290742907529076290772907829079290802908129082290832908429085290862908729088290892909029091290922909329094290952909629097290982909929100291012910229103291042910529106291072910829109291102911129112291132911429115291162911729118291192912029121291222912329124291252912629127291282912929130291312913229133291342913529136291372913829139291402914129142291432914429145291462914729148291492915029151291522915329154291552915629157291582915929160291612916229163291642916529166291672916829169291702917129172291732917429175291762917729178291792918029181291822918329184291852918629187291882918929190291912919229193291942919529196291972919829199292002920129202292032920429205292062920729208292092921029211292122921329214292152921629217292182921929220292212922229223292242922529226292272922829229292302923129232292332923429235292362923729238292392924029241292422924329244292452924629247292482924929250292512925229253292542925529256292572925829259292602926129262292632926429265292662926729268292692927029271292722927329274292752927629277292782927929280292812928229283292842928529286292872928829289292902929129292292932929429295292962929729298292992930029301293022930329304293052930629307293082930929310293112931229313293142931529316293172931829319293202932129322293232932429325293262932729328293292933029331293322933329334293352933629337293382933929340293412934229343293442934529346293472934829349293502935129352293532935429355293562935729358293592936029361293622936329364293652936629367293682936929370293712937229373293742937529376293772937829379293802938129382293832938429385293862938729388293892939029391293922939329394293952939629397293982939929400294012940229403294042940529406294072940829409294102941129412294132941429415294162941729418294192942029421294222942329424294252942629427294282942929430294312943229433294342943529436294372943829439294402944129442294432944429445294462944729448294492945029451294522945329454294552945629457294582945929460294612946229463294642946529466294672946829469294702947129472294732947429475294762947729478294792948029481294822948329484294852948629487294882948929490294912949229493294942949529496294972949829499295002950129502295032950429505295062950729508295092951029511295122951329514295152951629517295182951929520295212952229523295242952529526295272952829529295302953129532295332953429535295362953729538295392954029541295422954329544295452954629547295482954929550295512955229553295542955529556295572955829559295602956129562295632956429565295662956729568295692957029571295722957329574295752957629577295782957929580295812958229583295842958529586295872958829589295902959129592295932959429595295962959729598295992960029601296022960329604296052960629607296082960929610296112961229613296142961529616296172961829619296202962129622296232962429625296262962729628296292963029631296322963329634296352963629637296382963929640296412964229643296442964529646296472964829649296502965129652296532965429655296562965729658296592966029661296622966329664296652966629667296682966929670296712967229673296742967529676296772967829679296802968129682296832968429685296862968729688296892969029691296922969329694296952969629697296982969929700297012970229703297042970529706297072970829709297102971129712297132971429715297162971729718297192972029721297222972329724297252972629727297282972929730297312973229733297342973529736297372973829739297402974129742297432974429745297462974729748297492975029751297522975329754297552975629757297582975929760297612976229763297642976529766297672976829769297702977129772297732977429775297762977729778297792978029781297822978329784297852978629787297882978929790297912979229793297942979529796297972979829799298002980129802298032980429805298062980729808298092981029811298122981329814298152981629817298182981929820298212982229823298242982529826298272982829829298302983129832298332983429835298362983729838298392984029841298422984329844298452984629847298482984929850298512985229853298542985529856298572985829859298602986129862298632986429865298662986729868298692987029871298722987329874298752987629877298782987929880298812988229883298842988529886298872988829889298902989129892298932989429895298962989729898298992990029901299022990329904299052990629907299082990929910299112991229913299142991529916299172991829919299202992129922299232992429925299262992729928299292993029931299322993329934299352993629937299382993929940299412994229943299442994529946299472994829949299502995129952299532995429955299562995729958299592996029961299622996329964299652996629967299682996929970299712997229973299742997529976299772997829979299802998129982299832998429985299862998729988299892999029991299922999329994299952999629997299982999930000300013000230003300043000530006300073000830009300103001130012300133001430015300163001730018300193002030021300223002330024300253002630027300283002930030300313003230033300343003530036300373003830039300403004130042300433004430045300463004730048300493005030051300523005330054300553005630057300583005930060300613006230063300643006530066300673006830069300703007130072300733007430075300763007730078300793008030081300823008330084300853008630087300883008930090300913009230093300943009530096300973009830099301003010130102301033010430105301063010730108301093011030111301123011330114301153011630117301183011930120301213012230123301243012530126301273012830129301303013130132301333013430135301363013730138301393014030141301423014330144301453014630147301483014930150301513015230153301543015530156301573015830159301603016130162301633016430165301663016730168301693017030171301723017330174301753017630177301783017930180301813018230183301843018530186301873018830189301903019130192301933019430195301963019730198301993020030201302023020330204302053020630207302083020930210302113021230213302143021530216302173021830219302203022130222302233022430225302263022730228302293023030231302323023330234302353023630237302383023930240302413024230243302443024530246302473024830249302503025130252302533025430255302563025730258302593026030261302623026330264302653026630267302683026930270302713027230273302743027530276302773027830279302803028130282302833028430285302863028730288302893029030291302923029330294302953029630297302983029930300303013030230303303043030530306303073030830309303103031130312303133031430315303163031730318303193032030321303223032330324303253032630327303283032930330303313033230333303343033530336303373033830339303403034130342303433034430345303463034730348303493035030351303523035330354303553035630357303583035930360303613036230363303643036530366303673036830369303703037130372303733037430375303763037730378303793038030381303823038330384303853038630387303883038930390303913039230393303943039530396303973039830399304003040130402304033040430405304063040730408304093041030411304123041330414304153041630417304183041930420304213042230423304243042530426304273042830429304303043130432304333043430435304363043730438304393044030441304423044330444304453044630447304483044930450304513045230453304543045530456304573045830459304603046130462304633046430465304663046730468304693047030471304723047330474304753047630477304783047930480304813048230483304843048530486304873048830489304903049130492304933049430495304963049730498304993050030501305023050330504305053050630507305083050930510305113051230513305143051530516305173051830519305203052130522305233052430525305263052730528305293053030531305323053330534305353053630537305383053930540305413054230543305443054530546305473054830549305503055130552305533055430555305563055730558305593056030561305623056330564305653056630567305683056930570305713057230573305743057530576305773057830579305803058130582305833058430585305863058730588305893059030591305923059330594305953059630597305983059930600306013060230603306043060530606306073060830609306103061130612306133061430615306163061730618306193062030621306223062330624306253062630627306283062930630306313063230633306343063530636306373063830639306403064130642306433064430645306463064730648306493065030651306523065330654306553065630657306583065930660306613066230663306643066530666306673066830669306703067130672306733067430675306763067730678306793068030681306823068330684306853068630687306883068930690306913069230693306943069530696306973069830699307003070130702307033070430705307063070730708307093071030711307123071330714307153071630717307183071930720307213072230723307243072530726307273072830729307303073130732307333073430735307363073730738307393074030741307423074330744307453074630747307483074930750307513075230753307543075530756307573075830759307603076130762307633076430765307663076730768307693077030771307723077330774307753077630777307783077930780307813078230783307843078530786307873078830789307903079130792307933079430795307963079730798307993080030801308023080330804308053080630807308083080930810308113081230813308143081530816308173081830819308203082130822308233082430825308263082730828308293083030831308323083330834308353083630837308383083930840308413084230843308443084530846308473084830849308503085130852308533085430855308563085730858308593086030861308623086330864308653086630867308683086930870308713087230873308743087530876308773087830879308803088130882308833088430885308863088730888308893089030891308923089330894308953089630897308983089930900309013090230903309043090530906309073090830909309103091130912309133091430915309163091730918309193092030921309223092330924309253092630927309283092930930309313093230933309343093530936309373093830939309403094130942309433094430945309463094730948309493095030951309523095330954309553095630957309583095930960309613096230963309643096530966309673096830969309703097130972309733097430975309763097730978309793098030981309823098330984309853098630987309883098930990309913099230993309943099530996309973099830999310003100131002310033100431005310063100731008310093101031011310123101331014310153101631017310183101931020310213102231023310243102531026310273102831029310303103131032310333103431035310363103731038310393104031041310423104331044310453104631047310483104931050310513105231053310543105531056310573105831059310603106131062310633106431065310663106731068310693107031071310723107331074310753107631077310783107931080310813108231083310843108531086310873108831089310903109131092310933109431095310963109731098310993110031101311023110331104311053110631107311083110931110311113111231113311143111531116311173111831119311203112131122311233112431125311263112731128311293113031131311323113331134311353113631137311383113931140311413114231143311443114531146311473114831149311503115131152311533115431155311563115731158311593116031161311623116331164311653116631167311683116931170311713117231173311743117531176311773117831179311803118131182311833118431185311863118731188311893119031191311923119331194311953119631197311983119931200312013120231203312043120531206312073120831209312103121131212312133121431215312163121731218312193122031221312223122331224312253122631227312283122931230312313123231233312343123531236312373123831239312403124131242312433124431245312463124731248312493125031251312523125331254312553125631257312583125931260312613126231263312643126531266312673126831269312703127131272312733127431275312763127731278312793128031281312823128331284312853128631287312883128931290312913129231293312943129531296312973129831299313003130131302313033130431305313063130731308313093131031311313123131331314313153131631317313183131931320313213132231323313243132531326313273132831329313303133131332313333133431335313363133731338313393134031341313423134331344313453134631347313483134931350313513135231353313543135531356313573135831359313603136131362313633136431365313663136731368313693137031371313723137331374313753137631377313783137931380313813138231383313843138531386313873138831389313903139131392313933139431395313963139731398313993140031401314023140331404314053140631407314083140931410314113141231413314143141531416314173141831419314203142131422314233142431425314263142731428314293143031431314323143331434314353143631437314383143931440314413144231443314443144531446314473144831449314503145131452314533145431455314563145731458314593146031461314623146331464314653146631467314683146931470314713147231473314743147531476314773147831479314803148131482314833148431485314863148731488314893149031491314923149331494314953149631497314983149931500315013150231503315043150531506315073150831509315103151131512315133151431515315163151731518315193152031521315223152331524315253152631527315283152931530315313153231533315343153531536315373153831539315403154131542315433154431545315463154731548315493155031551315523155331554315553155631557315583155931560315613156231563315643156531566315673156831569315703157131572315733157431575315763157731578315793158031581315823158331584315853158631587315883158931590315913159231593315943159531596315973159831599316003160131602316033160431605316063160731608316093161031611316123161331614316153161631617316183161931620316213162231623316243162531626316273162831629316303163131632316333163431635316363163731638316393164031641316423164331644316453164631647316483164931650316513165231653316543165531656316573165831659316603166131662316633166431665316663166731668316693167031671316723167331674316753167631677316783167931680316813168231683316843168531686316873168831689316903169131692316933169431695316963169731698316993170031701317023170331704317053170631707317083170931710317113171231713317143171531716317173171831719317203172131722317233172431725317263172731728317293173031731317323173331734317353173631737317383173931740317413174231743317443174531746317473174831749317503175131752317533175431755317563175731758317593176031761317623176331764317653176631767317683176931770317713177231773317743177531776317773177831779317803178131782317833178431785317863178731788317893179031791317923179331794317953179631797317983179931800318013180231803318043180531806318073180831809318103181131812318133181431815318163181731818318193182031821318223182331824318253182631827318283182931830318313183231833318343183531836318373183831839318403184131842318433184431845318463184731848318493185031851318523185331854318553185631857318583185931860318613186231863318643186531866318673186831869318703187131872318733187431875318763187731878318793188031881318823188331884318853188631887318883188931890318913189231893318943189531896318973189831899319003190131902319033190431905319063190731908319093191031911319123191331914319153191631917319183191931920319213192231923319243192531926319273192831929319303193131932319333193431935319363193731938319393194031941319423194331944319453194631947319483194931950319513195231953319543195531956319573195831959319603196131962319633196431965319663196731968319693197031971319723197331974319753197631977319783197931980319813198231983319843198531986319873198831989319903199131992319933199431995319963199731998319993200032001320023200332004320053200632007320083200932010320113201232013320143201532016320173201832019320203202132022320233202432025320263202732028320293203032031320323203332034320353203632037320383203932040320413204232043320443204532046320473204832049320503205132052320533205432055320563205732058320593206032061320623206332064320653206632067320683206932070320713207232073320743207532076320773207832079320803208132082320833208432085320863208732088320893209032091320923209332094320953209632097320983209932100321013210232103321043210532106321073210832109321103211132112321133211432115321163211732118321193212032121321223212332124321253212632127321283212932130321313213232133321343213532136321373213832139321403214132142321433214432145321463214732148321493215032151321523215332154321553215632157321583215932160321613216232163321643216532166321673216832169321703217132172321733217432175321763217732178321793218032181321823218332184321853218632187321883218932190321913219232193321943219532196321973219832199322003220132202322033220432205322063220732208322093221032211322123221332214322153221632217322183221932220322213222232223322243222532226322273222832229322303223132232322333223432235322363223732238322393224032241322423224332244322453224632247322483224932250322513225232253322543225532256322573225832259322603226132262322633226432265322663226732268322693227032271322723227332274322753227632277322783227932280322813228232283322843228532286322873228832289322903229132292322933229432295322963229732298322993230032301323023230332304323053230632307323083230932310323113231232313323143231532316323173231832319323203232132322323233232432325323263232732328323293233032331323323233332334323353233632337323383233932340323413234232343323443234532346323473234832349323503235132352323533235432355323563235732358323593236032361323623236332364323653236632367323683236932370323713237232373323743237532376323773237832379323803238132382323833238432385323863238732388323893239032391323923239332394323953239632397323983239932400324013240232403324043240532406324073240832409324103241132412324133241432415324163241732418324193242032421324223242332424324253242632427324283242932430324313243232433324343243532436324373243832439324403244132442324433244432445324463244732448324493245032451324523245332454324553245632457324583245932460324613246232463324643246532466324673246832469324703247132472324733247432475324763247732478324793248032481324823248332484324853248632487324883248932490324913249232493324943249532496324973249832499325003250132502325033250432505325063250732508325093251032511325123251332514325153251632517325183251932520325213252232523325243252532526325273252832529325303253132532325333253432535325363253732538325393254032541325423254332544325453254632547325483254932550325513255232553325543255532556325573255832559325603256132562325633256432565325663256732568325693257032571325723257332574325753257632577325783257932580325813258232583325843258532586325873258832589325903259132592325933259432595325963259732598325993260032601326023260332604326053260632607326083260932610326113261232613326143261532616326173261832619326203262132622326233262432625326263262732628326293263032631326323263332634326353263632637326383263932640326413264232643326443264532646326473264832649326503265132652326533265432655326563265732658326593266032661326623266332664326653266632667326683266932670326713267232673326743267532676326773267832679326803268132682326833268432685326863268732688326893269032691326923269332694326953269632697326983269932700327013270232703327043270532706327073270832709327103271132712327133271432715327163271732718327193272032721327223272332724327253272632727327283272932730327313273232733327343273532736327373273832739327403274132742327433274432745327463274732748327493275032751327523275332754327553275632757327583275932760327613276232763327643276532766327673276832769327703277132772327733277432775327763277732778327793278032781327823278332784327853278632787327883278932790327913279232793327943279532796327973279832799328003280132802328033280432805328063280732808328093281032811328123281332814328153281632817328183281932820328213282232823328243282532826328273282832829328303283132832328333283432835328363283732838328393284032841328423284332844328453284632847328483284932850328513285232853328543285532856328573285832859328603286132862328633286432865328663286732868328693287032871328723287332874328753287632877328783287932880328813288232883328843288532886328873288832889328903289132892328933289432895328963289732898328993290032901329023290332904329053290632907329083290932910329113291232913329143291532916329173291832919329203292132922329233292432925329263292732928329293293032931329323293332934329353293632937329383293932940329413294232943329443294532946329473294832949329503295132952329533295432955329563295732958329593296032961329623296332964329653296632967329683296932970329713297232973329743297532976329773297832979329803298132982329833298432985329863298732988329893299032991329923299332994329953299632997329983299933000330013300233003330043300533006330073300833009330103301133012330133301433015330163301733018330193302033021330223302333024330253302633027330283302933030330313303233033330343303533036330373303833039330403304133042330433304433045330463304733048330493305033051330523305333054330553305633057330583305933060330613306233063330643306533066330673306833069330703307133072330733307433075330763307733078330793308033081330823308333084330853308633087330883308933090330913309233093330943309533096330973309833099331003310133102331033310433105331063310733108331093311033111331123311333114331153311633117331183311933120331213312233123331243312533126331273312833129331303313133132331333313433135331363313733138331393314033141331423314333144331453314633147331483314933150331513315233153331543315533156331573315833159331603316133162331633316433165331663316733168331693317033171331723317333174331753317633177331783317933180331813318233183331843318533186331873318833189331903319133192331933319433195331963319733198331993320033201332023320333204332053320633207332083320933210332113321233213332143321533216332173321833219332203322133222332233322433225332263322733228332293323033231332323323333234332353323633237332383323933240332413324233243332443324533246332473324833249332503325133252332533325433255332563325733258332593326033261332623326333264332653326633267332683326933270332713327233273332743327533276332773327833279332803328133282332833328433285332863328733288332893329033291332923329333294332953329633297332983329933300333013330233303333043330533306333073330833309333103331133312333133331433315333163331733318333193332033321333223332333324333253332633327333283332933330333313333233333333343333533336333373333833339333403334133342333433334433345333463334733348333493335033351333523335333354333553335633357333583335933360333613336233363333643336533366333673336833369333703337133372333733337433375333763337733378333793338033381333823338333384333853338633387333883338933390333913339233393333943339533396333973339833399334003340133402334033340433405334063340733408334093341033411334123341333414334153341633417334183341933420334213342233423334243342533426334273342833429334303343133432334333343433435334363343733438334393344033441334423344333444334453344633447334483344933450334513345233453334543345533456334573345833459334603346133462334633346433465334663346733468334693347033471334723347333474334753347633477334783347933480334813348233483334843348533486334873348833489334903349133492334933349433495334963349733498334993350033501335023350333504335053350633507335083350933510335113351233513335143351533516335173351833519335203352133522335233352433525335263352733528335293353033531335323353333534335353353633537335383353933540335413354233543335443354533546335473354833549335503355133552335533355433555335563355733558335593356033561335623356333564335653356633567335683356933570335713357233573335743357533576335773357833579335803358133582335833358433585335863358733588335893359033591335923359333594335953359633597335983359933600336013360233603336043360533606336073360833609336103361133612336133361433615336163361733618336193362033621336223362333624336253362633627336283362933630336313363233633336343363533636336373363833639336403364133642336433364433645336463364733648336493365033651336523365333654336553365633657336583365933660336613366233663336643366533666336673366833669336703367133672336733367433675336763367733678336793368033681336823368333684336853368633687336883368933690336913369233693336943369533696336973369833699337003370133702337033370433705337063370733708337093371033711337123371333714337153371633717337183371933720337213372233723337243372533726337273372833729337303373133732337333373433735337363373733738337393374033741337423374333744337453374633747337483374933750337513375233753337543375533756337573375833759337603376133762337633376433765337663376733768337693377033771337723377333774337753377633777337783377933780337813378233783337843378533786337873378833789337903379133792337933379433795337963379733798337993380033801338023380333804338053380633807338083380933810338113381233813338143381533816338173381833819338203382133822338233382433825338263382733828338293383033831338323383333834338353383633837338383383933840338413384233843338443384533846338473384833849338503385133852338533385433855338563385733858338593386033861338623386333864338653386633867338683386933870338713387233873338743387533876338773387833879338803388133882338833388433885338863388733888338893389033891338923389333894338953389633897338983389933900339013390233903339043390533906339073390833909339103391133912339133391433915339163391733918339193392033921339223392333924339253392633927339283392933930339313393233933339343393533936339373393833939339403394133942339433394433945339463394733948339493395033951339523395333954339553395633957339583395933960339613396233963339643396533966339673396833969339703397133972339733397433975339763397733978339793398033981339823398333984339853398633987339883398933990339913399233993339943399533996339973399833999340003400134002340033400434005340063400734008340093401034011340123401334014340153401634017340183401934020340213402234023340243402534026340273402834029340303403134032340333403434035340363403734038340393404034041340423404334044340453404634047340483404934050340513405234053340543405534056340573405834059340603406134062340633406434065340663406734068340693407034071340723407334074340753407634077340783407934080340813408234083340843408534086340873408834089340903409134092340933409434095340963409734098340993410034101341023410334104341053410634107341083410934110341113411234113341143411534116341173411834119341203412134122341233412434125341263412734128341293413034131341323413334134341353413634137341383413934140341413414234143341443414534146341473414834149341503415134152341533415434155341563415734158341593416034161341623416334164341653416634167341683416934170341713417234173341743417534176341773417834179341803418134182341833418434185341863418734188341893419034191341923419334194341953419634197341983419934200342013420234203342043420534206342073420834209342103421134212342133421434215342163421734218342193422034221342223422334224342253422634227342283422934230342313423234233342343423534236342373423834239342403424134242342433424434245342463424734248342493425034251342523425334254342553425634257342583425934260342613426234263342643426534266342673426834269342703427134272342733427434275342763427734278342793428034281342823428334284342853428634287342883428934290342913429234293342943429534296342973429834299343003430134302343033430434305343063430734308343093431034311343123431334314343153431634317343183431934320343213432234323343243432534326343273432834329343303433134332343333433434335343363433734338343393434034341343423434334344343453434634347343483434934350343513435234353343543435534356343573435834359343603436134362343633436434365343663436734368343693437034371343723437334374343753437634377343783437934380343813438234383343843438534386343873438834389343903439134392343933439434395343963439734398343993440034401344023440334404344053440634407344083440934410344113441234413344143441534416344173441834419344203442134422344233442434425344263442734428344293443034431344323443334434344353443634437344383443934440344413444234443344443444534446344473444834449344503445134452344533445434455344563445734458344593446034461344623446334464344653446634467344683446934470344713447234473344743447534476344773447834479344803448134482344833448434485344863448734488344893449034491344923449334494344953449634497344983449934500345013450234503345043450534506345073450834509345103451134512345133451434515345163451734518345193452034521345223452334524345253452634527345283452934530345313453234533345343453534536345373453834539345403454134542345433454434545345463454734548345493455034551345523455334554345553455634557345583455934560345613456234563345643456534566345673456834569345703457134572345733457434575345763457734578345793458034581345823458334584345853458634587345883458934590345913459234593345943459534596345973459834599346003460134602346033460434605346063460734608346093461034611346123461334614346153461634617346183461934620346213462234623346243462534626346273462834629346303463134632346333463434635346363463734638346393464034641346423464334644346453464634647346483464934650346513465234653346543465534656346573465834659346603466134662346633466434665346663466734668346693467034671346723467334674346753467634677346783467934680346813468234683346843468534686346873468834689346903469134692346933469434695346963469734698346993470034701347023470334704347053470634707347083470934710347113471234713347143471534716347173471834719347203472134722347233472434725347263472734728347293473034731347323473334734347353473634737347383473934740347413474234743347443474534746347473474834749347503475134752347533475434755347563475734758347593476034761347623476334764347653476634767347683476934770347713477234773347743477534776347773477834779347803478134782347833478434785347863478734788347893479034791347923479334794347953479634797347983479934800348013480234803348043480534806348073480834809348103481134812348133481434815348163481734818348193482034821348223482334824348253482634827348283482934830348313483234833348343483534836348373483834839348403484134842348433484434845348463484734848348493485034851348523485334854348553485634857348583485934860348613486234863348643486534866348673486834869348703487134872348733487434875348763487734878348793488034881348823488334884348853488634887348883488934890348913489234893348943489534896348973489834899349003490134902349033490434905349063490734908349093491034911349123491334914349153491634917349183491934920349213492234923349243492534926349273492834929349303493134932349333493434935349363493734938349393494034941349423494334944349453494634947349483494934950349513495234953349543495534956349573495834959349603496134962349633496434965349663496734968349693497034971349723497334974349753497634977349783497934980349813498234983349843498534986349873498834989349903499134992349933499434995349963499734998349993500035001350023500335004350053500635007350083500935010350113501235013350143501535016350173501835019350203502135022350233502435025350263502735028350293503035031350323503335034350353503635037350383503935040350413504235043350443504535046350473504835049350503505135052350533505435055350563505735058350593506035061350623506335064350653506635067350683506935070350713507235073350743507535076350773507835079350803508135082350833508435085350863508735088350893509035091350923509335094350953509635097350983509935100351013510235103351043510535106351073510835109351103511135112351133511435115351163511735118351193512035121351223512335124351253512635127351283512935130351313513235133351343513535136351373513835139351403514135142351433514435145351463514735148351493515035151351523515335154351553515635157351583515935160351613516235163351643516535166351673516835169351703517135172351733517435175351763517735178351793518035181351823518335184351853518635187351883518935190351913519235193351943519535196351973519835199352003520135202352033520435205352063520735208352093521035211352123521335214352153521635217352183521935220352213522235223352243522535226352273522835229352303523135232352333523435235352363523735238352393524035241352423524335244352453524635247352483524935250352513525235253352543525535256352573525835259352603526135262352633526435265352663526735268352693527035271352723527335274352753527635277352783527935280352813528235283352843528535286352873528835289352903529135292352933529435295352963529735298352993530035301353023530335304353053530635307353083530935310353113531235313353143531535316353173531835319353203532135322353233532435325353263532735328353293533035331353323533335334353353533635337353383533935340353413534235343353443534535346353473534835349353503535135352353533535435355353563535735358353593536035361353623536335364353653536635367353683536935370353713537235373353743537535376353773537835379353803538135382353833538435385353863538735388353893539035391353923539335394353953539635397353983539935400354013540235403354043540535406354073540835409354103541135412354133541435415354163541735418354193542035421354223542335424354253542635427354283542935430354313543235433354343543535436354373543835439354403544135442354433544435445354463544735448354493545035451354523545335454354553545635457354583545935460354613546235463354643546535466354673546835469354703547135472354733547435475354763547735478354793548035481354823548335484354853548635487354883548935490354913549235493354943549535496354973549835499355003550135502355033550435505355063550735508355093551035511355123551335514355153551635517355183551935520355213552235523355243552535526355273552835529355303553135532355333553435535355363553735538355393554035541355423554335544355453554635547355483554935550355513555235553355543555535556355573555835559355603556135562355633556435565355663556735568355693557035571355723557335574355753557635577355783557935580355813558235583355843558535586355873558835589355903559135592355933559435595355963559735598355993560035601356023560335604356053560635607356083560935610356113561235613356143561535616356173561835619356203562135622356233562435625356263562735628356293563035631356323563335634356353563635637356383563935640356413564235643356443564535646356473564835649356503565135652356533565435655356563565735658356593566035661356623566335664356653566635667356683566935670356713567235673356743567535676356773567835679356803568135682356833568435685356863568735688356893569035691356923569335694356953569635697356983569935700357013570235703357043570535706357073570835709357103571135712357133571435715357163571735718357193572035721357223572335724357253572635727357283572935730357313573235733357343573535736357373573835739357403574135742357433574435745357463574735748357493575035751357523575335754357553575635757357583575935760357613576235763357643576535766357673576835769357703577135772357733577435775357763577735778357793578035781357823578335784357853578635787357883578935790357913579235793357943579535796357973579835799358003580135802358033580435805358063580735808358093581035811358123581335814358153581635817358183581935820358213582235823358243582535826358273582835829358303583135832358333583435835358363583735838358393584035841358423584335844358453584635847358483584935850358513585235853358543585535856358573585835859358603586135862358633586435865358663586735868358693587035871358723587335874358753587635877358783587935880358813588235883358843588535886358873588835889358903589135892358933589435895358963589735898358993590035901359023590335904359053590635907359083590935910359113591235913359143591535916359173591835919359203592135922359233592435925359263592735928359293593035931359323593335934359353593635937359383593935940359413594235943359443594535946359473594835949359503595135952359533595435955359563595735958359593596035961359623596335964359653596635967359683596935970359713597235973359743597535976359773597835979359803598135982359833598435985359863598735988359893599035991359923599335994359953599635997359983599936000360013600236003360043600536006360073600836009360103601136012360133601436015360163601736018360193602036021360223602336024360253602636027360283602936030360313603236033360343603536036360373603836039360403604136042360433604436045360463604736048360493605036051360523605336054360553605636057360583605936060360613606236063360643606536066360673606836069360703607136072360733607436075360763607736078360793608036081360823608336084360853608636087360883608936090360913609236093360943609536096360973609836099361003610136102361033610436105361063610736108361093611036111361123611336114361153611636117361183611936120361213612236123361243612536126361273612836129361303613136132361333613436135361363613736138361393614036141361423614336144361453614636147361483614936150361513615236153361543615536156361573615836159361603616136162361633616436165361663616736168361693617036171361723617336174361753617636177361783617936180361813618236183361843618536186361873618836189361903619136192361933619436195361963619736198361993620036201362023620336204362053620636207362083620936210362113621236213362143621536216362173621836219362203622136222362233622436225362263622736228362293623036231362323623336234362353623636237362383623936240362413624236243362443624536246362473624836249362503625136252362533625436255362563625736258362593626036261362623626336264362653626636267362683626936270362713627236273362743627536276362773627836279362803628136282362833628436285362863628736288362893629036291362923629336294362953629636297362983629936300363013630236303363043630536306363073630836309363103631136312363133631436315363163631736318363193632036321363223632336324363253632636327363283632936330363313633236333363343633536336363373633836339363403634136342363433634436345363463634736348363493635036351363523635336354363553635636357363583635936360363613636236363363643636536366363673636836369363703637136372363733637436375363763637736378363793638036381363823638336384363853638636387363883638936390363913639236393363943639536396363973639836399364003640136402364033640436405364063640736408364093641036411364123641336414364153641636417364183641936420364213642236423364243642536426364273642836429364303643136432364333643436435364363643736438364393644036441364423644336444364453644636447364483644936450364513645236453364543645536456364573645836459364603646136462364633646436465364663646736468364693647036471364723647336474364753647636477364783647936480364813648236483364843648536486364873648836489364903649136492364933649436495364963649736498364993650036501365023650336504365053650636507365083650936510365113651236513365143651536516365173651836519365203652136522365233652436525365263652736528365293653036531365323653336534365353653636537365383653936540365413654236543365443654536546365473654836549365503655136552365533655436555365563655736558365593656036561365623656336564365653656636567365683656936570365713657236573365743657536576365773657836579365803658136582365833658436585365863658736588365893659036591365923659336594365953659636597365983659936600366013660236603366043660536606366073660836609366103661136612366133661436615366163661736618366193662036621366223662336624366253662636627366283662936630366313663236633366343663536636366373663836639366403664136642366433664436645366463664736648366493665036651366523665336654366553665636657366583665936660366613666236663366643666536666366673666836669366703667136672366733667436675366763667736678366793668036681366823668336684366853668636687366883668936690366913669236693366943669536696366973669836699367003670136702367033670436705367063670736708367093671036711367123671336714367153671636717367183671936720367213672236723367243672536726367273672836729367303673136732367333673436735367363673736738367393674036741367423674336744367453674636747367483674936750367513675236753367543675536756367573675836759367603676136762367633676436765367663676736768367693677036771367723677336774367753677636777367783677936780367813678236783367843678536786367873678836789367903679136792367933679436795367963679736798367993680036801368023680336804368053680636807368083680936810368113681236813368143681536816368173681836819368203682136822368233682436825368263682736828368293683036831368323683336834368353683636837368383683936840368413684236843368443684536846368473684836849368503685136852368533685436855368563685736858368593686036861368623686336864368653686636867368683686936870368713687236873368743687536876368773687836879368803688136882368833688436885368863688736888368893689036891368923689336894368953689636897368983689936900369013690236903369043690536906369073690836909369103691136912369133691436915369163691736918369193692036921369223692336924369253692636927369283692936930369313693236933369343693536936369373693836939369403694136942369433694436945369463694736948369493695036951369523695336954369553695636957369583695936960369613696236963369643696536966369673696836969369703697136972369733697436975369763697736978369793698036981369823698336984369853698636987369883698936990369913699236993369943699536996369973699836999370003700137002370033700437005370063700737008370093701037011370123701337014370153701637017370183701937020370213702237023370243702537026370273702837029370303703137032370333703437035370363703737038370393704037041370423704337044370453704637047370483704937050370513705237053370543705537056370573705837059370603706137062370633706437065370663706737068370693707037071370723707337074370753707637077370783707937080370813708237083370843708537086370873708837089370903709137092370933709437095370963709737098370993710037101371023710337104371053710637107371083710937110371113711237113371143711537116371173711837119371203712137122371233712437125371263712737128371293713037131371323713337134371353713637137371383713937140371413714237143371443714537146371473714837149371503715137152371533715437155371563715737158371593716037161371623716337164371653716637167371683716937170371713717237173371743717537176371773717837179371803718137182371833718437185371863718737188371893719037191371923719337194371953719637197371983719937200372013720237203372043720537206372073720837209372103721137212372133721437215372163721737218372193722037221372223722337224372253722637227372283722937230372313723237233372343723537236372373723837239372403724137242372433724437245372463724737248372493725037251372523725337254372553725637257372583725937260372613726237263372643726537266372673726837269372703727137272372733727437275372763727737278372793728037281372823728337284372853728637287372883728937290372913729237293372943729537296372973729837299373003730137302373033730437305373063730737308373093731037311373123731337314373153731637317373183731937320373213732237323373243732537326373273732837329373303733137332373333733437335373363733737338373393734037341373423734337344373453734637347373483734937350373513735237353373543735537356373573735837359373603736137362373633736437365373663736737368373693737037371373723737337374373753737637377373783737937380373813738237383373843738537386373873738837389373903739137392373933739437395373963739737398373993740037401374023740337404374053740637407374083740937410374113741237413374143741537416374173741837419374203742137422374233742437425374263742737428374293743037431374323743337434374353743637437374383743937440374413744237443374443744537446374473744837449374503745137452374533745437455374563745737458374593746037461374623746337464374653746637467374683746937470374713747237473374743747537476374773747837479374803748137482374833748437485374863748737488374893749037491374923749337494374953749637497374983749937500375013750237503375043750537506375073750837509375103751137512375133751437515375163751737518375193752037521375223752337524375253752637527375283752937530375313753237533375343753537536375373753837539375403754137542375433754437545375463754737548375493755037551375523755337554375553755637557375583755937560375613756237563375643756537566375673756837569375703757137572375733757437575375763757737578375793758037581375823758337584375853758637587375883758937590375913759237593375943759537596375973759837599376003760137602376033760437605376063760737608376093761037611376123761337614376153761637617376183761937620376213762237623376243762537626376273762837629376303763137632376333763437635376363763737638376393764037641376423764337644376453764637647376483764937650376513765237653376543765537656376573765837659376603766137662376633766437665376663766737668376693767037671376723767337674376753767637677376783767937680376813768237683376843768537686376873768837689376903769137692376933769437695376963769737698376993770037701377023770337704377053770637707377083770937710377113771237713377143771537716377173771837719377203772137722377233772437725377263772737728377293773037731377323773337734377353773637737377383773937740377413774237743377443774537746377473774837749377503775137752377533775437755377563775737758377593776037761377623776337764377653776637767377683776937770377713777237773377743777537776377773777837779377803778137782377833778437785377863778737788377893779037791377923779337794377953779637797377983779937800378013780237803378043780537806378073780837809378103781137812378133781437815378163781737818378193782037821378223782337824378253782637827378283782937830378313783237833378343783537836378373783837839378403784137842378433784437845378463784737848378493785037851378523785337854378553785637857378583785937860378613786237863378643786537866378673786837869378703787137872378733787437875378763787737878378793788037881378823788337884378853788637887378883788937890378913789237893378943789537896378973789837899379003790137902379033790437905379063790737908379093791037911379123791337914379153791637917379183791937920379213792237923379243792537926379273792837929379303793137932379333793437935379363793737938379393794037941379423794337944379453794637947379483794937950379513795237953379543795537956379573795837959379603796137962379633796437965379663796737968379693797037971379723797337974379753797637977379783797937980379813798237983379843798537986379873798837989379903799137992379933799437995379963799737998379993800038001380023800338004380053800638007380083800938010380113801238013380143801538016380173801838019380203802138022380233802438025380263802738028380293803038031380323803338034380353803638037380383803938040380413804238043380443804538046380473804838049380503805138052380533805438055380563805738058380593806038061380623806338064380653806638067380683806938070380713807238073380743807538076380773807838079380803808138082380833808438085380863808738088380893809038091380923809338094380953809638097380983809938100381013810238103381043810538106381073810838109381103811138112381133811438115381163811738118381193812038121381223812338124381253812638127381283812938130381313813238133381343813538136381373813838139381403814138142381433814438145381463814738148381493815038151381523815338154381553815638157381583815938160381613816238163381643816538166381673816838169381703817138172381733817438175381763817738178381793818038181381823818338184381853818638187381883818938190381913819238193381943819538196381973819838199382003820138202382033820438205382063820738208382093821038211382123821338214382153821638217382183821938220382213822238223382243822538226382273822838229382303823138232382333823438235382363823738238382393824038241382423824338244382453824638247382483824938250382513825238253382543825538256382573825838259382603826138262382633826438265382663826738268382693827038271382723827338274382753827638277382783827938280382813828238283382843828538286382873828838289382903829138292382933829438295382963829738298382993830038301383023830338304383053830638307383083830938310383113831238313383143831538316383173831838319383203832138322383233832438325383263832738328383293833038331383323833338334383353833638337383383833938340383413834238343383443834538346383473834838349383503835138352383533835438355383563835738358383593836038361383623836338364383653836638367383683836938370383713837238373383743837538376383773837838379383803838138382383833838438385383863838738388383893839038391383923839338394383953839638397383983839938400384013840238403384043840538406384073840838409384103841138412384133841438415384163841738418384193842038421384223842338424384253842638427384283842938430384313843238433384343843538436384373843838439384403844138442384433844438445384463844738448384493845038451384523845338454384553845638457384583845938460384613846238463384643846538466384673846838469384703847138472384733847438475384763847738478384793848038481384823848338484384853848638487384883848938490384913849238493384943849538496384973849838499385003850138502385033850438505385063850738508385093851038511385123851338514385153851638517385183851938520385213852238523385243852538526385273852838529385303853138532385333853438535385363853738538385393854038541385423854338544385453854638547385483854938550385513855238553385543855538556385573855838559385603856138562385633856438565385663856738568385693857038571385723857338574385753857638577385783857938580385813858238583385843858538586385873858838589385903859138592385933859438595385963859738598385993860038601386023860338604386053860638607386083860938610386113861238613386143861538616386173861838619386203862138622386233862438625386263862738628386293863038631386323863338634386353863638637386383863938640386413864238643386443864538646386473864838649386503865138652386533865438655386563865738658386593866038661386623866338664386653866638667386683866938670386713867238673386743867538676386773867838679386803868138682386833868438685386863868738688386893869038691386923869338694386953869638697386983869938700387013870238703387043870538706387073870838709387103871138712387133871438715387163871738718387193872038721387223872338724387253872638727387283872938730387313873238733387343873538736387373873838739387403874138742387433874438745387463874738748387493875038751387523875338754387553875638757387583875938760387613876238763387643876538766387673876838769387703877138772387733877438775387763877738778387793878038781387823878338784387853878638787387883878938790387913879238793387943879538796387973879838799388003880138802388033880438805388063880738808388093881038811388123881338814388153881638817388183881938820388213882238823388243882538826388273882838829388303883138832388333883438835388363883738838388393884038841388423884338844388453884638847388483884938850388513885238853388543885538856388573885838859388603886138862388633886438865388663886738868388693887038871388723887338874388753887638877388783887938880388813888238883388843888538886388873888838889388903889138892388933889438895388963889738898388993890038901389023890338904389053890638907389083890938910389113891238913389143891538916389173891838919389203892138922389233892438925389263892738928389293893038931389323893338934389353893638937389383893938940389413894238943389443894538946389473894838949389503895138952389533895438955389563895738958389593896038961389623896338964389653896638967389683896938970389713897238973389743897538976389773897838979389803898138982389833898438985389863898738988389893899038991389923899338994389953899638997389983899939000390013900239003390043900539006390073900839009390103901139012390133901439015390163901739018390193902039021390223902339024390253902639027390283902939030390313903239033390343903539036390373903839039390403904139042390433904439045390463904739048390493905039051390523905339054390553905639057390583905939060390613906239063390643906539066390673906839069390703907139072390733907439075390763907739078390793908039081390823908339084390853908639087390883908939090390913909239093390943909539096390973909839099391003910139102391033910439105391063910739108391093911039111391123911339114391153911639117391183911939120391213912239123391243912539126391273912839129391303913139132391333913439135391363913739138391393914039141391423914339144391453914639147391483914939150391513915239153391543915539156391573915839159391603916139162391633916439165391663916739168391693917039171391723917339174391753917639177391783917939180391813918239183391843918539186391873918839189391903919139192391933919439195391963919739198391993920039201392023920339204392053920639207392083920939210392113921239213392143921539216392173921839219392203922139222392233922439225392263922739228392293923039231392323923339234392353923639237392383923939240392413924239243392443924539246392473924839249392503925139252392533925439255392563925739258392593926039261392623926339264392653926639267392683926939270392713927239273392743927539276392773927839279392803928139282392833928439285392863928739288392893929039291392923929339294392953929639297392983929939300393013930239303393043930539306393073930839309393103931139312393133931439315393163931739318393193932039321393223932339324393253932639327393283932939330393313933239333393343933539336393373933839339393403934139342393433934439345393463934739348393493935039351393523935339354393553935639357393583935939360393613936239363393643936539366393673936839369393703937139372393733937439375393763937739378393793938039381393823938339384393853938639387393883938939390393913939239393393943939539396393973939839399394003940139402394033940439405394063940739408394093941039411394123941339414394153941639417394183941939420394213942239423394243942539426394273942839429394303943139432394333943439435394363943739438394393944039441394423944339444394453944639447394483944939450394513945239453394543945539456394573945839459394603946139462394633946439465394663946739468394693947039471394723947339474394753947639477394783947939480394813948239483394843948539486394873948839489394903949139492394933949439495394963949739498394993950039501395023950339504395053950639507395083950939510395113951239513395143951539516395173951839519395203952139522395233952439525395263952739528395293953039531395323953339534395353953639537395383953939540395413954239543395443954539546395473954839549395503955139552395533955439555395563955739558395593956039561395623956339564395653956639567395683956939570395713957239573395743957539576395773957839579395803958139582395833958439585395863958739588395893959039591395923959339594395953959639597395983959939600396013960239603396043960539606396073960839609396103961139612396133961439615396163961739618396193962039621396223962339624396253962639627396283962939630396313963239633396343963539636396373963839639396403964139642396433964439645396463964739648396493965039651396523965339654396553965639657396583965939660396613966239663396643966539666396673966839669396703967139672396733967439675396763967739678396793968039681396823968339684396853968639687396883968939690396913969239693396943969539696396973969839699397003970139702397033970439705397063970739708397093971039711397123971339714397153971639717397183971939720397213972239723397243972539726397273972839729397303973139732397333973439735397363973739738397393974039741397423974339744397453974639747397483974939750397513975239753397543975539756397573975839759397603976139762397633976439765397663976739768397693977039771397723977339774397753977639777397783977939780397813978239783397843978539786397873978839789397903979139792397933979439795397963979739798397993980039801398023980339804398053980639807398083980939810398113981239813398143981539816398173981839819398203982139822398233982439825398263982739828398293983039831398323983339834398353983639837398383983939840398413984239843398443984539846398473984839849398503985139852398533985439855398563985739858398593986039861398623986339864398653986639867398683986939870398713987239873398743987539876398773987839879398803988139882398833988439885398863988739888398893989039891398923989339894398953989639897398983989939900399013990239903399043990539906399073990839909399103991139912399133991439915399163991739918399193992039921399223992339924399253992639927399283992939930399313993239933399343993539936399373993839939399403994139942399433994439945399463994739948399493995039951399523995339954399553995639957399583995939960399613996239963399643996539966399673996839969399703997139972399733997439975399763997739978399793998039981399823998339984399853998639987399883998939990399913999239993399943999539996399973999839999400004000140002400034000440005400064000740008400094001040011400124001340014400154001640017400184001940020400214002240023400244002540026400274002840029400304003140032400334003440035400364003740038400394004040041400424004340044400454004640047400484004940050400514005240053400544005540056400574005840059400604006140062400634006440065400664006740068400694007040071400724007340074400754007640077400784007940080400814008240083400844008540086400874008840089400904009140092400934009440095400964009740098400994010040101401024010340104401054010640107401084010940110401114011240113401144011540116401174011840119401204012140122401234012440125401264012740128401294013040131401324013340134401354013640137401384013940140401414014240143401444014540146401474014840149401504015140152401534015440155401564015740158401594016040161401624016340164401654016640167401684016940170401714017240173401744017540176401774017840179401804018140182401834018440185401864018740188401894019040191401924019340194401954019640197401984019940200402014020240203402044020540206402074020840209402104021140212402134021440215402164021740218402194022040221402224022340224402254022640227402284022940230402314023240233402344023540236402374023840239402404024140242402434024440245402464024740248402494025040251402524025340254402554025640257402584025940260402614026240263402644026540266402674026840269402704027140272402734027440275402764027740278402794028040281402824028340284402854028640287402884028940290402914029240293402944029540296402974029840299403004030140302403034030440305403064030740308403094031040311403124031340314403154031640317403184031940320403214032240323403244032540326403274032840329403304033140332403334033440335403364033740338403394034040341403424034340344403454034640347403484034940350403514035240353403544035540356403574035840359403604036140362403634036440365403664036740368403694037040371403724037340374403754037640377403784037940380403814038240383403844038540386403874038840389403904039140392403934039440395403964039740398403994040040401404024040340404404054040640407404084040940410404114041240413404144041540416404174041840419404204042140422404234042440425404264042740428404294043040431404324043340434404354043640437404384043940440404414044240443404444044540446404474044840449404504045140452404534045440455404564045740458404594046040461404624046340464404654046640467404684046940470404714047240473404744047540476404774047840479404804048140482404834048440485404864048740488404894049040491404924049340494404954049640497404984049940500405014050240503405044050540506405074050840509405104051140512405134051440515405164051740518405194052040521405224052340524405254052640527405284052940530405314053240533405344053540536405374053840539405404054140542405434054440545405464054740548405494055040551405524055340554405554055640557405584055940560405614056240563405644056540566405674056840569405704057140572405734057440575405764057740578405794058040581405824058340584405854058640587405884058940590405914059240593405944059540596405974059840599406004060140602406034060440605406064060740608406094061040611406124061340614406154061640617406184061940620406214062240623406244062540626406274062840629406304063140632406334063440635406364063740638406394064040641406424064340644406454064640647406484064940650406514065240653406544065540656406574065840659406604066140662406634066440665406664066740668406694067040671406724067340674406754067640677406784067940680406814068240683406844068540686406874068840689406904069140692406934069440695406964069740698406994070040701407024070340704407054070640707407084070940710407114071240713407144071540716407174071840719407204072140722407234072440725407264072740728407294073040731407324073340734407354073640737407384073940740407414074240743407444074540746407474074840749407504075140752407534075440755407564075740758407594076040761407624076340764407654076640767407684076940770407714077240773407744077540776407774077840779407804078140782407834078440785407864078740788407894079040791407924079340794407954079640797407984079940800408014080240803408044080540806408074080840809408104081140812408134081440815408164081740818408194082040821408224082340824408254082640827408284082940830408314083240833408344083540836408374083840839408404084140842408434084440845408464084740848408494085040851408524085340854408554085640857408584085940860408614086240863408644086540866408674086840869408704087140872408734087440875408764087740878408794088040881408824088340884408854088640887408884088940890408914089240893408944089540896408974089840899409004090140902409034090440905409064090740908409094091040911409124091340914409154091640917409184091940920409214092240923409244092540926409274092840929409304093140932409334093440935409364093740938409394094040941409424094340944409454094640947409484094940950409514095240953409544095540956409574095840959409604096140962409634096440965409664096740968409694097040971409724097340974409754097640977409784097940980409814098240983409844098540986409874098840989409904099140992409934099440995409964099740998409994100041001410024100341004410054100641007410084100941010410114101241013410144101541016410174101841019410204102141022410234102441025410264102741028410294103041031410324103341034410354103641037410384103941040410414104241043410444104541046410474104841049410504105141052410534105441055410564105741058410594106041061410624106341064410654106641067410684106941070410714107241073410744107541076410774107841079410804108141082410834108441085410864108741088410894109041091410924109341094410954109641097410984109941100411014110241103411044110541106411074110841109411104111141112411134111441115411164111741118411194112041121411224112341124411254112641127411284112941130411314113241133411344113541136411374113841139411404114141142411434114441145411464114741148411494115041151411524115341154411554115641157411584115941160411614116241163411644116541166411674116841169411704117141172411734117441175411764117741178411794118041181411824118341184411854118641187411884118941190411914119241193411944119541196411974119841199412004120141202412034120441205412064120741208412094121041211412124121341214412154121641217412184121941220412214122241223412244122541226412274122841229412304123141232412334123441235412364123741238412394124041241412424124341244412454124641247412484124941250412514125241253412544125541256412574125841259412604126141262412634126441265412664126741268412694127041271412724127341274412754127641277412784127941280412814128241283412844128541286412874128841289412904129141292412934129441295412964129741298412994130041301413024130341304413054130641307413084130941310413114131241313413144131541316413174131841319413204132141322413234132441325413264132741328413294133041331413324133341334413354133641337413384133941340413414134241343413444134541346413474134841349413504135141352413534135441355413564135741358413594136041361413624136341364413654136641367413684136941370413714137241373413744137541376413774137841379413804138141382413834138441385413864138741388413894139041391413924139341394413954139641397413984139941400414014140241403414044140541406414074140841409414104141141412414134141441415414164141741418414194142041421414224142341424414254142641427414284142941430414314143241433414344143541436414374143841439414404144141442414434144441445414464144741448414494145041451414524145341454414554145641457414584145941460414614146241463414644146541466414674146841469414704147141472414734147441475414764147741478414794148041481414824148341484414854148641487414884148941490414914149241493414944149541496414974149841499415004150141502415034150441505415064150741508415094151041511415124151341514415154151641517415184151941520415214152241523415244152541526415274152841529415304153141532415334153441535415364153741538415394154041541415424154341544415454154641547415484154941550415514155241553415544155541556415574155841559415604156141562415634156441565415664156741568415694157041571415724157341574415754157641577415784157941580415814158241583415844158541586415874158841589415904159141592415934159441595415964159741598415994160041601416024160341604416054160641607416084160941610416114161241613416144161541616416174161841619416204162141622416234162441625416264162741628416294163041631416324163341634416354163641637416384163941640416414164241643416444164541646416474164841649416504165141652416534165441655416564165741658416594166041661416624166341664416654166641667416684166941670416714167241673416744167541676416774167841679416804168141682416834168441685416864168741688416894169041691416924169341694416954169641697416984169941700417014170241703417044170541706417074170841709417104171141712417134171441715417164171741718417194172041721417224172341724417254172641727417284172941730417314173241733417344173541736417374173841739417404174141742417434174441745417464174741748417494175041751417524175341754417554175641757417584175941760417614176241763417644176541766417674176841769417704177141772417734177441775417764177741778417794178041781417824178341784417854178641787417884178941790417914179241793417944179541796417974179841799418004180141802418034180441805418064180741808418094181041811418124181341814418154181641817418184181941820418214182241823418244182541826418274182841829418304183141832418334183441835418364183741838418394184041841418424184341844418454184641847418484184941850418514185241853418544185541856418574185841859418604186141862418634186441865418664186741868418694187041871418724187341874418754187641877418784187941880418814188241883418844188541886418874188841889418904189141892418934189441895418964189741898418994190041901419024190341904419054190641907419084190941910419114191241913419144191541916419174191841919419204192141922419234192441925419264192741928419294193041931419324193341934419354193641937419384193941940419414194241943419444194541946419474194841949419504195141952419534195441955419564195741958419594196041961419624196341964419654196641967419684196941970419714197241973419744197541976419774197841979419804198141982419834198441985419864198741988419894199041991419924199341994419954199641997419984199942000420014200242003420044200542006420074200842009420104201142012420134201442015420164201742018420194202042021420224202342024420254202642027420284202942030420314203242033420344203542036420374203842039420404204142042420434204442045420464204742048420494205042051420524205342054420554205642057420584205942060420614206242063420644206542066420674206842069420704207142072420734207442075420764207742078420794208042081420824208342084420854208642087420884208942090420914209242093420944209542096420974209842099421004210142102421034210442105421064210742108421094211042111421124211342114421154211642117421184211942120421214212242123421244212542126421274212842129421304213142132421334213442135421364213742138421394214042141421424214342144421454214642147421484214942150421514215242153421544215542156421574215842159421604216142162421634216442165421664216742168421694217042171421724217342174421754217642177421784217942180421814218242183421844218542186421874218842189421904219142192421934219442195421964219742198421994220042201422024220342204422054220642207422084220942210422114221242213422144221542216422174221842219422204222142222422234222442225422264222742228422294223042231422324223342234422354223642237422384223942240422414224242243422444224542246422474224842249422504225142252422534225442255422564225742258422594226042261422624226342264422654226642267422684226942270422714227242273422744227542276422774227842279422804228142282422834228442285422864228742288422894229042291422924229342294422954229642297422984229942300423014230242303423044230542306423074230842309423104231142312423134231442315423164231742318423194232042321423224232342324423254232642327423284232942330423314233242333423344233542336423374233842339423404234142342423434234442345423464234742348423494235042351423524235342354423554235642357423584235942360423614236242363423644236542366423674236842369423704237142372423734237442375423764237742378423794238042381423824238342384423854238642387423884238942390423914239242393423944239542396423974239842399424004240142402424034240442405424064240742408424094241042411424124241342414424154241642417424184241942420424214242242423424244242542426424274242842429424304243142432424334243442435424364243742438424394244042441424424244342444424454244642447424484244942450424514245242453424544245542456424574245842459424604246142462424634246442465424664246742468424694247042471424724247342474424754247642477424784247942480424814248242483424844248542486424874248842489424904249142492424934249442495424964249742498424994250042501425024250342504425054250642507425084250942510425114251242513425144251542516425174251842519425204252142522425234252442525425264252742528425294253042531425324253342534425354253642537425384253942540425414254242543425444254542546425474254842549425504255142552425534255442555425564255742558425594256042561425624256342564425654256642567425684256942570425714257242573425744257542576425774257842579425804258142582425834258442585425864258742588425894259042591425924259342594425954259642597425984259942600426014260242603426044260542606426074260842609426104261142612426134261442615426164261742618426194262042621426224262342624426254262642627426284262942630426314263242633426344263542636426374263842639426404264142642426434264442645426464264742648426494265042651426524265342654426554265642657426584265942660426614266242663426644266542666426674266842669426704267142672426734267442675426764267742678426794268042681426824268342684426854268642687426884268942690426914269242693426944269542696426974269842699427004270142702427034270442705427064270742708427094271042711427124271342714427154271642717427184271942720427214272242723427244272542726427274272842729427304273142732427334273442735427364273742738427394274042741427424274342744427454274642747427484274942750427514275242753427544275542756427574275842759427604276142762427634276442765427664276742768427694277042771427724277342774427754277642777427784277942780427814278242783427844278542786427874278842789427904279142792427934279442795427964279742798427994280042801428024280342804428054280642807428084280942810428114281242813428144281542816428174281842819428204282142822428234282442825428264282742828428294283042831428324283342834428354283642837428384283942840428414284242843428444284542846428474284842849428504285142852428534285442855428564285742858428594286042861428624286342864428654286642867428684286942870428714287242873428744287542876428774287842879428804288142882428834288442885428864288742888428894289042891428924289342894428954289642897428984289942900429014290242903429044290542906429074290842909429104291142912429134291442915429164291742918429194292042921429224292342924429254292642927429284292942930429314293242933429344293542936429374293842939429404294142942429434294442945429464294742948429494295042951429524295342954429554295642957429584295942960429614296242963429644296542966429674296842969429704297142972429734297442975429764297742978429794298042981429824298342984429854298642987429884298942990429914299242993429944299542996429974299842999430004300143002430034300443005430064300743008430094301043011430124301343014430154301643017430184301943020430214302243023430244302543026430274302843029430304303143032430334303443035430364303743038430394304043041430424304343044430454304643047430484304943050430514305243053430544305543056430574305843059430604306143062430634306443065430664306743068430694307043071430724307343074430754307643077430784307943080430814308243083430844308543086430874308843089430904309143092430934309443095430964309743098430994310043101431024310343104431054310643107431084310943110431114311243113431144311543116431174311843119431204312143122431234312443125431264312743128431294313043131431324313343134431354313643137431384313943140431414314243143431444314543146431474314843149431504315143152431534315443155431564315743158431594316043161431624316343164431654316643167431684316943170431714317243173431744317543176431774317843179431804318143182431834318443185431864318743188431894319043191431924319343194431954319643197431984319943200432014320243203432044320543206432074320843209432104321143212432134321443215432164321743218432194322043221432224322343224432254322643227432284322943230432314323243233432344323543236432374323843239432404324143242432434324443245432464324743248432494325043251432524325343254432554325643257432584325943260432614326243263432644326543266432674326843269432704327143272432734327443275432764327743278432794328043281432824328343284432854328643287432884328943290432914329243293432944329543296432974329843299433004330143302433034330443305433064330743308433094331043311433124331343314433154331643317433184331943320433214332243323433244332543326433274332843329433304333143332433334333443335433364333743338433394334043341433424334343344433454334643347433484334943350433514335243353433544335543356433574335843359433604336143362433634336443365433664336743368433694337043371433724337343374433754337643377433784337943380433814338243383433844338543386433874338843389433904339143392433934339443395433964339743398433994340043401434024340343404434054340643407434084340943410434114341243413434144341543416434174341843419434204342143422434234342443425434264342743428434294343043431434324343343434434354343643437434384343943440434414344243443434444344543446434474344843449434504345143452434534345443455434564345743458434594346043461434624346343464434654346643467434684346943470434714347243473434744347543476434774347843479434804348143482434834348443485434864348743488434894349043491434924349343494434954349643497434984349943500435014350243503435044350543506435074350843509435104351143512435134351443515435164351743518435194352043521435224352343524435254352643527435284352943530435314353243533435344353543536435374353843539435404354143542435434354443545435464354743548435494355043551435524355343554435554355643557435584355943560435614356243563435644356543566435674356843569435704357143572435734357443575435764357743578435794358043581435824358343584435854358643587435884358943590435914359243593435944359543596435974359843599436004360143602436034360443605436064360743608436094361043611436124361343614436154361643617436184361943620436214362243623436244362543626436274362843629436304363143632436334363443635436364363743638436394364043641436424364343644436454364643647436484364943650436514365243653436544365543656436574365843659436604366143662436634366443665436664366743668436694367043671436724367343674436754367643677436784367943680436814368243683436844368543686436874368843689436904369143692436934369443695436964369743698436994370043701437024370343704437054370643707437084370943710437114371243713437144371543716437174371843719437204372143722437234372443725437264372743728437294373043731437324373343734437354373643737437384373943740437414374243743437444374543746437474374843749437504375143752437534375443755437564375743758437594376043761437624376343764437654376643767437684376943770437714377243773437744377543776437774377843779437804378143782437834378443785437864378743788437894379043791437924379343794437954379643797437984379943800438014380243803438044380543806438074380843809438104381143812438134381443815438164381743818438194382043821438224382343824438254382643827438284382943830438314383243833438344383543836438374383843839438404384143842438434384443845438464384743848438494385043851438524385343854438554385643857438584385943860438614386243863438644386543866438674386843869438704387143872438734387443875438764387743878438794388043881438824388343884438854388643887438884388943890438914389243893438944389543896438974389843899439004390143902439034390443905439064390743908439094391043911439124391343914439154391643917439184391943920439214392243923439244392543926439274392843929439304393143932439334393443935439364393743938439394394043941439424394343944439454394643947439484394943950439514395243953439544395543956439574395843959439604396143962439634396443965439664396743968439694397043971439724397343974439754397643977439784397943980439814398243983439844398543986439874398843989439904399143992439934399443995439964399743998439994400044001440024400344004440054400644007440084400944010440114401244013440144401544016440174401844019440204402144022440234402444025440264402744028440294403044031440324403344034440354403644037440384403944040440414404244043440444404544046440474404844049440504405144052440534405444055440564405744058440594406044061440624406344064440654406644067440684406944070440714407244073440744407544076440774407844079440804408144082440834408444085440864408744088440894409044091440924409344094440954409644097440984409944100441014410244103441044410544106441074410844109441104411144112441134411444115441164411744118441194412044121441224412344124441254412644127441284412944130441314413244133441344413544136441374413844139441404414144142441434414444145441464414744148441494415044151441524415344154441554415644157441584415944160441614416244163441644416544166441674416844169441704417144172441734417444175441764417744178441794418044181441824418344184441854418644187441884418944190441914419244193441944419544196441974419844199442004420144202442034420444205442064420744208442094421044211442124421344214442154421644217442184421944220442214422244223442244422544226442274422844229442304423144232442334423444235442364423744238442394424044241442424424344244442454424644247442484424944250442514425244253442544425544256442574425844259442604426144262442634426444265442664426744268442694427044271442724427344274442754427644277442784427944280442814428244283442844428544286442874428844289442904429144292442934429444295442964429744298442994430044301443024430344304443054430644307443084430944310443114431244313443144431544316443174431844319443204432144322443234432444325443264432744328443294433044331443324433344334443354433644337443384433944340443414434244343443444434544346443474434844349443504435144352443534435444355443564435744358443594436044361443624436344364443654436644367443684436944370443714437244373443744437544376443774437844379443804438144382443834438444385443864438744388443894439044391443924439344394443954439644397443984439944400444014440244403444044440544406444074440844409444104441144412444134441444415444164441744418444194442044421444224442344424444254442644427444284442944430444314443244433444344443544436444374443844439444404444144442444434444444445444464444744448444494445044451444524445344454444554445644457444584445944460444614446244463444644446544466444674446844469444704447144472444734447444475444764447744478444794448044481444824448344484444854448644487444884448944490444914449244493444944449544496444974449844499445004450144502445034450444505445064450744508445094451044511445124451344514445154451644517445184451944520445214452244523445244452544526445274452844529445304453144532445334453444535445364453744538445394454044541445424454344544445454454644547445484454944550445514455244553445544455544556445574455844559445604456144562445634456444565445664456744568445694457044571445724457344574445754457644577445784457944580445814458244583445844458544586445874458844589445904459144592445934459444595445964459744598445994460044601446024460344604446054460644607446084460944610446114461244613446144461544616446174461844619446204462144622446234462444625446264462744628446294463044631446324463344634446354463644637446384463944640446414464244643446444464544646446474464844649446504465144652446534465444655446564465744658446594466044661446624466344664446654466644667446684466944670446714467244673446744467544676446774467844679446804468144682446834468444685446864468744688446894469044691446924469344694446954469644697446984469944700447014470244703447044470544706447074470844709447104471144712447134471444715447164471744718447194472044721447224472344724447254472644727447284472944730447314473244733447344473544736447374473844739447404474144742447434474444745447464474744748447494475044751447524475344754447554475644757447584475944760447614476244763447644476544766447674476844769447704477144772447734477444775447764477744778447794478044781447824478344784447854478644787447884478944790447914479244793447944479544796447974479844799448004480144802448034480444805448064480744808448094481044811448124481344814448154481644817448184481944820448214482244823448244482544826448274482844829448304483144832448334483444835448364483744838448394484044841448424484344844448454484644847448484484944850448514485244853448544485544856448574485844859448604486144862448634486444865448664486744868448694487044871448724487344874448754487644877448784487944880448814488244883448844488544886448874488844889448904489144892448934489444895448964489744898448994490044901449024490344904449054490644907449084490944910449114491244913449144491544916449174491844919449204492144922449234492444925449264492744928449294493044931449324493344934449354493644937449384493944940449414494244943449444494544946449474494844949449504495144952449534495444955449564495744958449594496044961449624496344964449654496644967449684496944970449714497244973449744497544976449774497844979449804498144982449834498444985449864498744988449894499044991449924499344994449954499644997449984499945000450014500245003450044500545006450074500845009450104501145012450134501445015450164501745018450194502045021450224502345024450254502645027450284502945030450314503245033450344503545036450374503845039450404504145042450434504445045450464504745048450494505045051450524505345054450554505645057450584505945060450614506245063450644506545066450674506845069450704507145072450734507445075450764507745078450794508045081450824508345084450854508645087450884508945090450914509245093450944509545096450974509845099451004510145102451034510445105451064510745108451094511045111451124511345114451154511645117451184511945120451214512245123451244512545126451274512845129451304513145132451334513445135451364513745138451394514045141451424514345144451454514645147451484514945150451514515245153451544515545156451574515845159451604516145162451634516445165451664516745168451694517045171451724517345174451754517645177451784517945180451814518245183451844518545186451874518845189451904519145192451934519445195451964519745198451994520045201452024520345204452054520645207452084520945210452114521245213452144521545216452174521845219452204522145222452234522445225452264522745228452294523045231452324523345234452354523645237452384523945240452414524245243452444524545246452474524845249452504525145252452534525445255452564525745258452594526045261452624526345264452654526645267452684526945270452714527245273452744527545276452774527845279452804528145282452834528445285452864528745288452894529045291452924529345294452954529645297452984529945300453014530245303453044530545306453074530845309453104531145312453134531445315453164531745318453194532045321453224532345324453254532645327453284532945330453314533245333453344533545336453374533845339453404534145342453434534445345453464534745348453494535045351453524535345354453554535645357453584535945360453614536245363453644536545366453674536845369453704537145372453734537445375453764537745378453794538045381453824538345384453854538645387453884538945390453914539245393453944539545396453974539845399454004540145402454034540445405454064540745408454094541045411454124541345414454154541645417454184541945420454214542245423454244542545426454274542845429454304543145432454334543445435454364543745438454394544045441454424544345444454454544645447454484544945450454514545245453454544545545456454574545845459454604546145462454634546445465454664546745468454694547045471454724547345474454754547645477454784547945480454814548245483454844548545486454874548845489454904549145492454934549445495454964549745498454994550045501455024550345504455054550645507455084550945510455114551245513455144551545516455174551845519455204552145522455234552445525455264552745528455294553045531455324553345534455354553645537455384553945540455414554245543455444554545546455474554845549455504555145552455534555445555455564555745558455594556045561455624556345564455654556645567455684556945570455714557245573455744557545576455774557845579455804558145582455834558445585455864558745588455894559045591455924559345594455954559645597455984559945600456014560245603456044560545606456074560845609456104561145612456134561445615456164561745618456194562045621456224562345624456254562645627456284562945630456314563245633456344563545636456374563845639456404564145642456434564445645456464564745648456494565045651456524565345654456554565645657456584565945660456614566245663456644566545666456674566845669456704567145672456734567445675456764567745678456794568045681456824568345684456854568645687456884568945690456914569245693456944569545696456974569845699457004570145702457034570445705457064570745708457094571045711457124571345714457154571645717457184571945720457214572245723457244572545726457274572845729457304573145732457334573445735457364573745738457394574045741457424574345744457454574645747457484574945750457514575245753457544575545756457574575845759457604576145762457634576445765457664576745768457694577045771457724577345774457754577645777457784577945780457814578245783457844578545786457874578845789457904579145792457934579445795457964579745798457994580045801458024580345804458054580645807458084580945810458114581245813458144581545816458174581845819458204582145822458234582445825458264582745828458294583045831458324583345834458354583645837458384583945840458414584245843458444584545846458474584845849458504585145852458534585445855458564585745858458594586045861458624586345864458654586645867458684586945870458714587245873458744587545876458774587845879458804588145882458834588445885458864588745888458894589045891458924589345894458954589645897458984589945900459014590245903459044590545906459074590845909459104591145912459134591445915459164591745918459194592045921459224592345924459254592645927459284592945930459314593245933459344593545936459374593845939459404594145942459434594445945459464594745948459494595045951459524595345954459554595645957459584595945960459614596245963459644596545966459674596845969459704597145972459734597445975459764597745978459794598045981459824598345984459854598645987459884598945990459914599245993459944599545996459974599845999460004600146002460034600446005460064600746008460094601046011460124601346014460154601646017460184601946020460214602246023460244602546026460274602846029460304603146032460334603446035460364603746038460394604046041460424604346044460454604646047460484604946050460514605246053460544605546056460574605846059460604606146062460634606446065460664606746068460694607046071460724607346074460754607646077460784607946080460814608246083460844608546086460874608846089460904609146092460934609446095460964609746098460994610046101461024610346104461054610646107461084610946110461114611246113461144611546116461174611846119461204612146122461234612446125461264612746128461294613046131461324613346134461354613646137461384613946140461414614246143461444614546146461474614846149461504615146152461534615446155461564615746158461594616046161461624616346164461654616646167461684616946170461714617246173461744617546176461774617846179461804618146182461834618446185461864618746188461894619046191461924619346194461954619646197461984619946200462014620246203462044620546206462074620846209462104621146212462134621446215462164621746218462194622046221462224622346224462254622646227462284622946230462314623246233462344623546236462374623846239462404624146242462434624446245462464624746248462494625046251462524625346254462554625646257462584625946260462614626246263462644626546266462674626846269462704627146272462734627446275462764627746278462794628046281462824628346284462854628646287462884628946290462914629246293462944629546296462974629846299463004630146302463034630446305463064630746308463094631046311463124631346314463154631646317463184631946320463214632246323463244632546326463274632846329463304633146332463334633446335463364633746338463394634046341463424634346344463454634646347463484634946350463514635246353463544635546356463574635846359463604636146362463634636446365463664636746368463694637046371463724637346374463754637646377463784637946380463814638246383463844638546386463874638846389463904639146392463934639446395463964639746398463994640046401464024640346404464054640646407464084640946410464114641246413464144641546416464174641846419464204642146422464234642446425464264642746428464294643046431464324643346434464354643646437464384643946440464414644246443464444644546446464474644846449464504645146452464534645446455464564645746458464594646046461464624646346464464654646646467464684646946470464714647246473464744647546476464774647846479464804648146482464834648446485464864648746488464894649046491464924649346494464954649646497464984649946500465014650246503465044650546506465074650846509465104651146512465134651446515465164651746518465194652046521465224652346524465254652646527465284652946530465314653246533465344653546536465374653846539465404654146542465434654446545465464654746548465494655046551465524655346554465554655646557465584655946560465614656246563465644656546566465674656846569465704657146572465734657446575465764657746578465794658046581465824658346584465854658646587465884658946590465914659246593465944659546596465974659846599466004660146602466034660446605466064660746608466094661046611466124661346614466154661646617466184661946620466214662246623466244662546626466274662846629466304663146632466334663446635466364663746638466394664046641466424664346644466454664646647466484664946650466514665246653466544665546656466574665846659466604666146662466634666446665466664666746668466694667046671466724667346674466754667646677466784667946680466814668246683466844668546686466874668846689466904669146692466934669446695466964669746698466994670046701467024670346704467054670646707467084670946710467114671246713467144671546716467174671846719467204672146722467234672446725467264672746728467294673046731467324673346734467354673646737467384673946740467414674246743467444674546746467474674846749467504675146752467534675446755467564675746758467594676046761467624676346764467654676646767467684676946770467714677246773467744677546776467774677846779467804678146782467834678446785467864678746788467894679046791467924679346794467954679646797467984679946800468014680246803468044680546806468074680846809468104681146812468134681446815468164681746818468194682046821468224682346824468254682646827468284682946830468314683246833468344683546836468374683846839468404684146842468434684446845468464684746848468494685046851468524685346854468554685646857468584685946860468614686246863468644686546866468674686846869468704687146872468734687446875468764687746878468794688046881468824688346884468854688646887468884688946890468914689246893468944689546896468974689846899469004690146902469034690446905469064690746908469094691046911469124691346914469154691646917469184691946920469214692246923469244692546926469274692846929469304693146932469334693446935469364693746938469394694046941469424694346944469454694646947469484694946950469514695246953469544695546956469574695846959469604696146962469634696446965469664696746968469694697046971469724697346974469754697646977469784697946980469814698246983469844698546986469874698846989469904699146992469934699446995469964699746998469994700047001470024700347004470054700647007470084700947010470114701247013470144701547016470174701847019470204702147022470234702447025470264702747028470294703047031470324703347034470354703647037470384703947040470414704247043470444704547046470474704847049470504705147052470534705447055470564705747058470594706047061470624706347064470654706647067470684706947070470714707247073470744707547076470774707847079470804708147082470834708447085470864708747088470894709047091470924709347094470954709647097470984709947100471014710247103471044710547106471074710847109471104711147112471134711447115471164711747118471194712047121471224712347124471254712647127471284712947130471314713247133471344713547136471374713847139471404714147142471434714447145471464714747148471494715047151471524715347154471554715647157471584715947160471614716247163471644716547166471674716847169471704717147172471734717447175471764717747178471794718047181471824718347184471854718647187471884718947190471914719247193471944719547196471974719847199472004720147202472034720447205472064720747208472094721047211472124721347214472154721647217472184721947220472214722247223472244722547226472274722847229472304723147232472334723447235472364723747238472394724047241472424724347244472454724647247472484724947250472514725247253472544725547256472574725847259472604726147262472634726447265472664726747268472694727047271472724727347274472754727647277472784727947280472814728247283472844728547286472874728847289472904729147292472934729447295472964729747298472994730047301473024730347304473054730647307473084730947310473114731247313473144731547316473174731847319473204732147322473234732447325473264732747328473294733047331473324733347334473354733647337473384733947340473414734247343473444734547346473474734847349473504735147352473534735447355473564735747358473594736047361473624736347364473654736647367473684736947370473714737247373473744737547376473774737847379473804738147382473834738447385473864738747388473894739047391473924739347394473954739647397473984739947400474014740247403474044740547406474074740847409474104741147412474134741447415474164741747418474194742047421474224742347424474254742647427474284742947430474314743247433474344743547436474374743847439474404744147442474434744447445474464744747448474494745047451474524745347454474554745647457474584745947460474614746247463474644746547466474674746847469474704747147472474734747447475474764747747478474794748047481474824748347484474854748647487474884748947490474914749247493474944749547496474974749847499475004750147502475034750447505475064750747508475094751047511475124751347514475154751647517475184751947520475214752247523475244752547526475274752847529475304753147532475334753447535475364753747538475394754047541475424754347544475454754647547475484754947550475514755247553475544755547556475574755847559475604756147562475634756447565475664756747568475694757047571475724757347574475754757647577475784757947580475814758247583475844758547586475874758847589475904759147592475934759447595475964759747598475994760047601476024760347604476054760647607476084760947610476114761247613476144761547616476174761847619476204762147622476234762447625476264762747628476294763047631476324763347634476354763647637476384763947640476414764247643476444764547646476474764847649476504765147652476534765447655476564765747658476594766047661476624766347664476654766647667476684766947670476714767247673476744767547676476774767847679476804768147682476834768447685476864768747688476894769047691476924769347694476954769647697476984769947700477014770247703477044770547706477074770847709477104771147712477134771447715477164771747718477194772047721477224772347724477254772647727477284772947730477314773247733477344773547736477374773847739477404774147742477434774447745477464774747748477494775047751477524775347754477554775647757477584775947760477614776247763477644776547766477674776847769477704777147772477734777447775477764777747778477794778047781477824778347784477854778647787477884778947790477914779247793477944779547796477974779847799478004780147802478034780447805478064780747808478094781047811478124781347814478154781647817478184781947820478214782247823478244782547826478274782847829478304783147832478334783447835478364783747838478394784047841478424784347844478454784647847478484784947850478514785247853478544785547856478574785847859478604786147862478634786447865478664786747868478694787047871478724787347874478754787647877478784787947880478814788247883478844788547886478874788847889478904789147892478934789447895478964789747898478994790047901479024790347904479054790647907479084790947910479114791247913479144791547916479174791847919479204792147922479234792447925479264792747928479294793047931479324793347934479354793647937479384793947940479414794247943479444794547946479474794847949479504795147952479534795447955479564795747958479594796047961479624796347964479654796647967479684796947970479714797247973479744797547976479774797847979479804798147982479834798447985479864798747988479894799047991479924799347994479954799647997479984799948000480014800248003480044800548006480074800848009480104801148012480134801448015480164801748018480194802048021480224802348024480254802648027480284802948030480314803248033480344803548036480374803848039480404804148042480434804448045480464804748048480494805048051480524805348054480554805648057480584805948060480614806248063480644806548066480674806848069480704807148072480734807448075480764807748078480794808048081480824808348084480854808648087480884808948090480914809248093480944809548096480974809848099481004810148102481034810448105481064810748108481094811048111481124811348114481154811648117481184811948120481214812248123481244812548126481274812848129481304813148132481334813448135481364813748138481394814048141481424814348144481454814648147481484814948150481514815248153481544815548156481574815848159481604816148162481634816448165481664816748168481694817048171481724817348174481754817648177481784817948180481814818248183481844818548186481874818848189481904819148192481934819448195481964819748198481994820048201482024820348204482054820648207482084820948210482114821248213482144821548216482174821848219482204822148222482234822448225482264822748228482294823048231482324823348234482354823648237482384823948240482414824248243482444824548246482474824848249482504825148252482534825448255482564825748258482594826048261482624826348264482654826648267482684826948270482714827248273482744827548276482774827848279482804828148282482834828448285482864828748288482894829048291482924829348294482954829648297482984829948300483014830248303483044830548306483074830848309483104831148312483134831448315483164831748318483194832048321483224832348324483254832648327483284832948330483314833248333483344833548336483374833848339483404834148342483434834448345483464834748348483494835048351483524835348354483554835648357483584835948360483614836248363483644836548366483674836848369483704837148372483734837448375483764837748378483794838048381483824838348384483854838648387483884838948390483914839248393483944839548396483974839848399484004840148402484034840448405484064840748408484094841048411484124841348414484154841648417484184841948420484214842248423484244842548426484274842848429484304843148432484334843448435484364843748438484394844048441484424844348444484454844648447484484844948450484514845248453484544845548456484574845848459484604846148462484634846448465484664846748468484694847048471484724847348474484754847648477484784847948480484814848248483484844848548486484874848848489484904849148492484934849448495484964849748498484994850048501485024850348504485054850648507485084850948510485114851248513485144851548516485174851848519485204852148522485234852448525485264852748528485294853048531485324853348534485354853648537485384853948540485414854248543485444854548546485474854848549485504855148552485534855448555485564855748558485594856048561485624856348564485654856648567485684856948570485714857248573485744857548576485774857848579485804858148582485834858448585485864858748588485894859048591485924859348594485954859648597485984859948600486014860248603486044860548606486074860848609486104861148612486134861448615486164861748618486194862048621486224862348624486254862648627486284862948630486314863248633486344863548636486374863848639486404864148642486434864448645486464864748648486494865048651486524865348654486554865648657486584865948660486614866248663486644866548666486674866848669486704867148672486734867448675486764867748678486794868048681486824868348684486854868648687486884868948690486914869248693486944869548696486974869848699487004870148702487034870448705487064870748708487094871048711487124871348714487154871648717487184871948720487214872248723487244872548726487274872848729487304873148732487334873448735487364873748738487394874048741487424874348744487454874648747487484874948750487514875248753487544875548756487574875848759487604876148762487634876448765487664876748768487694877048771487724877348774487754877648777487784877948780487814878248783487844878548786487874878848789487904879148792487934879448795487964879748798487994880048801488024880348804488054880648807488084880948810488114881248813488144881548816488174881848819488204882148822488234882448825488264882748828488294883048831488324883348834488354883648837488384883948840488414884248843488444884548846488474884848849488504885148852488534885448855488564885748858488594886048861488624886348864488654886648867488684886948870488714887248873488744887548876488774887848879488804888148882488834888448885488864888748888488894889048891488924889348894488954889648897488984889948900489014890248903489044890548906489074890848909489104891148912489134891448915489164891748918489194892048921489224892348924489254892648927489284892948930489314893248933489344893548936489374893848939489404894148942489434894448945489464894748948489494895048951489524895348954489554895648957489584895948960489614896248963489644896548966489674896848969489704897148972489734897448975489764897748978489794898048981489824898348984489854898648987489884898948990489914899248993489944899548996489974899848999490004900149002490034900449005490064900749008490094901049011490124901349014490154901649017490184901949020490214902249023490244902549026490274902849029490304903149032490334903449035490364903749038490394904049041490424904349044490454904649047490484904949050490514905249053490544905549056490574905849059490604906149062490634906449065490664906749068490694907049071490724907349074490754907649077490784907949080490814908249083490844908549086490874908849089490904909149092490934909449095490964909749098490994910049101491024910349104491054910649107491084910949110491114911249113491144911549116491174911849119491204912149122491234912449125491264912749128491294913049131491324913349134491354913649137491384913949140491414914249143491444914549146491474914849149491504915149152491534915449155491564915749158491594916049161491624916349164491654916649167491684916949170491714917249173491744917549176491774917849179491804918149182491834918449185491864918749188491894919049191491924919349194491954919649197491984919949200492014920249203492044920549206492074920849209492104921149212492134921449215492164921749218492194922049221492224922349224492254922649227492284922949230492314923249233492344923549236492374923849239492404924149242492434924449245492464924749248492494925049251492524925349254492554925649257492584925949260492614926249263492644926549266492674926849269492704927149272492734927449275492764927749278492794928049281492824928349284492854928649287492884928949290492914929249293492944929549296492974929849299493004930149302493034930449305493064930749308493094931049311493124931349314493154931649317493184931949320493214932249323493244932549326493274932849329493304933149332493334933449335493364933749338493394934049341493424934349344493454934649347493484934949350493514935249353493544935549356493574935849359493604936149362493634936449365493664936749368493694937049371493724937349374493754937649377493784937949380493814938249383493844938549386493874938849389493904939149392493934939449395493964939749398493994940049401494024940349404494054940649407494084940949410494114941249413494144941549416494174941849419494204942149422494234942449425494264942749428494294943049431494324943349434494354943649437494384943949440494414944249443494444944549446494474944849449494504945149452494534945449455494564945749458494594946049461494624946349464494654946649467494684946949470494714947249473494744947549476494774947849479494804948149482494834948449485494864948749488494894949049491494924949349494494954949649497494984949949500495014950249503495044950549506495074950849509495104951149512495134951449515495164951749518495194952049521495224952349524495254952649527495284952949530495314953249533495344953549536495374953849539495404954149542495434954449545495464954749548495494955049551495524955349554495554955649557495584955949560495614956249563495644956549566495674956849569495704957149572495734957449575495764957749578495794958049581495824958349584495854958649587495884958949590495914959249593495944959549596495974959849599496004960149602496034960449605496064960749608496094961049611496124961349614496154961649617496184961949620496214962249623496244962549626496274962849629496304963149632496334963449635496364963749638496394964049641496424964349644496454964649647496484964949650496514965249653496544965549656496574965849659496604966149662496634966449665496664966749668496694967049671496724967349674496754967649677496784967949680496814968249683496844968549686496874968849689496904969149692496934969449695496964969749698496994970049701497024970349704497054970649707497084970949710497114971249713497144971549716497174971849719497204972149722497234972449725497264972749728497294973049731497324973349734497354973649737497384973949740497414974249743497444974549746497474974849749497504975149752497534975449755497564975749758497594976049761497624976349764497654976649767497684976949770497714977249773497744977549776497774977849779497804978149782497834978449785497864978749788497894979049791497924979349794497954979649797497984979949800498014980249803498044980549806498074980849809498104981149812498134981449815498164981749818498194982049821498224982349824498254982649827498284982949830498314983249833498344983549836498374983849839498404984149842498434984449845498464984749848498494985049851498524985349854498554985649857498584985949860498614986249863498644986549866498674986849869498704987149872498734987449875498764987749878498794988049881498824988349884498854988649887498884988949890498914989249893498944989549896498974989849899499004990149902499034990449905499064990749908499094991049911499124991349914499154991649917499184991949920499214992249923499244992549926499274992849929499304993149932499334993449935499364993749938499394994049941499424994349944499454994649947499484994949950499514995249953499544995549956499574995849959499604996149962499634996449965499664996749968499694997049971499724997349974499754997649977499784997949980499814998249983499844998549986499874998849989499904999149992499934999449995499964999749998499995000050001500025000350004500055000650007500085000950010500115001250013500145001550016500175001850019500205002150022500235002450025500265002750028500295003050031500325003350034500355003650037500385003950040500415004250043500445004550046500475004850049500505005150052500535005450055500565005750058500595006050061500625006350064500655006650067500685006950070500715007250073500745007550076500775007850079500805008150082500835008450085500865008750088500895009050091500925009350094500955009650097500985009950100501015010250103501045010550106501075010850109501105011150112501135011450115501165011750118501195012050121501225012350124501255012650127501285012950130501315013250133501345013550136501375013850139501405014150142501435014450145501465014750148501495015050151501525015350154501555015650157501585015950160501615016250163501645016550166501675016850169501705017150172501735017450175501765017750178501795018050181501825018350184501855018650187501885018950190501915019250193501945019550196501975019850199502005020150202502035020450205502065020750208502095021050211502125021350214502155021650217502185021950220502215022250223502245022550226502275022850229502305023150232502335023450235502365023750238502395024050241502425024350244502455024650247502485024950250502515025250253502545025550256502575025850259502605026150262502635026450265502665026750268502695027050271502725027350274502755027650277502785027950280502815028250283502845028550286502875028850289502905029150292502935029450295502965029750298502995030050301503025030350304503055030650307503085030950310503115031250313503145031550316503175031850319503205032150322503235032450325503265032750328503295033050331503325033350334503355033650337503385033950340503415034250343503445034550346503475034850349503505035150352503535035450355503565035750358503595036050361503625036350364503655036650367503685036950370503715037250373503745037550376503775037850379503805038150382503835038450385503865038750388503895039050391503925039350394503955039650397503985039950400504015040250403504045040550406504075040850409504105041150412504135041450415504165041750418504195042050421504225042350424504255042650427504285042950430504315043250433504345043550436504375043850439504405044150442504435044450445504465044750448504495045050451504525045350454504555045650457504585045950460504615046250463504645046550466504675046850469504705047150472504735047450475504765047750478504795048050481504825048350484504855048650487504885048950490504915049250493504945049550496504975049850499505005050150502505035050450505505065050750508505095051050511505125051350514505155051650517505185051950520505215052250523505245052550526505275052850529505305053150532505335053450535505365053750538505395054050541505425054350544505455054650547505485054950550505515055250553505545055550556505575055850559505605056150562505635056450565505665056750568505695057050571505725057350574505755057650577505785057950580505815058250583505845058550586505875058850589505905059150592505935059450595505965059750598505995060050601506025060350604506055060650607506085060950610506115061250613506145061550616506175061850619506205062150622506235062450625506265062750628506295063050631506325063350634506355063650637506385063950640506415064250643506445064550646506475064850649506505065150652506535065450655506565065750658506595066050661506625066350664506655066650667506685066950670506715067250673506745067550676506775067850679506805068150682506835068450685506865068750688506895069050691506925069350694506955069650697506985069950700507015070250703507045070550706507075070850709507105071150712507135071450715507165071750718507195072050721507225072350724507255072650727507285072950730507315073250733507345073550736507375073850739507405074150742507435074450745507465074750748507495075050751507525075350754507555075650757507585075950760507615076250763507645076550766507675076850769507705077150772507735077450775507765077750778507795078050781507825078350784507855078650787507885078950790507915079250793507945079550796507975079850799508005080150802508035080450805508065080750808508095081050811508125081350814508155081650817508185081950820508215082250823508245082550826508275082850829508305083150832508335083450835508365083750838508395084050841508425084350844508455084650847508485084950850508515085250853508545085550856508575085850859508605086150862508635086450865508665086750868508695087050871508725087350874508755087650877508785087950880508815088250883508845088550886508875088850889508905089150892508935089450895508965089750898508995090050901509025090350904509055090650907509085090950910509115091250913509145091550916509175091850919509205092150922509235092450925509265092750928509295093050931509325093350934509355093650937509385093950940509415094250943509445094550946509475094850949509505095150952509535095450955509565095750958509595096050961509625096350964509655096650967509685096950970509715097250973509745097550976509775097850979509805098150982509835098450985509865098750988509895099050991509925099350994509955099650997509985099951000510015100251003510045100551006510075100851009510105101151012510135101451015510165101751018510195102051021510225102351024510255102651027510285102951030510315103251033510345103551036510375103851039510405104151042510435104451045510465104751048510495105051051510525105351054510555105651057510585105951060510615106251063510645106551066510675106851069510705107151072510735107451075510765107751078510795108051081510825108351084510855108651087510885108951090510915109251093510945109551096510975109851099511005110151102511035110451105511065110751108511095111051111511125111351114511155111651117511185111951120511215112251123511245112551126511275112851129511305113151132511335113451135511365113751138511395114051141511425114351144511455114651147511485114951150511515115251153511545115551156511575115851159511605116151162511635116451165511665116751168511695117051171511725117351174511755117651177511785117951180511815118251183511845118551186511875118851189511905119151192511935119451195511965119751198511995120051201512025120351204512055120651207512085120951210512115121251213512145121551216512175121851219512205122151222512235122451225512265122751228512295123051231512325123351234512355123651237512385123951240512415124251243512445124551246512475124851249512505125151252512535125451255512565125751258512595126051261512625126351264512655126651267512685126951270512715127251273512745127551276512775127851279512805128151282512835128451285512865128751288512895129051291512925129351294512955129651297512985129951300513015130251303513045130551306513075130851309513105131151312513135131451315513165131751318513195132051321513225132351324513255132651327513285132951330513315133251333513345133551336513375133851339513405134151342513435134451345513465134751348513495135051351513525135351354513555135651357513585135951360513615136251363513645136551366513675136851369513705137151372513735137451375513765137751378513795138051381513825138351384513855138651387513885138951390513915139251393513945139551396513975139851399514005140151402514035140451405514065140751408514095141051411514125141351414514155141651417514185141951420514215142251423514245142551426514275142851429514305143151432514335143451435514365143751438514395144051441514425144351444514455144651447514485144951450514515145251453514545145551456514575145851459514605146151462514635146451465514665146751468514695147051471514725147351474514755147651477514785147951480514815148251483514845148551486514875148851489514905149151492514935149451495514965149751498514995150051501515025150351504515055150651507515085150951510515115151251513515145151551516515175151851519515205152151522515235152451525515265152751528515295153051531515325153351534515355153651537515385153951540515415154251543515445154551546515475154851549515505155151552515535155451555515565155751558515595156051561515625156351564515655156651567515685156951570515715157251573515745157551576515775157851579515805158151582515835158451585515865158751588515895159051591515925159351594515955159651597515985159951600516015160251603516045160551606516075160851609516105161151612516135161451615516165161751618516195162051621516225162351624516255162651627516285162951630516315163251633516345163551636516375163851639516405164151642516435164451645516465164751648516495165051651516525165351654516555165651657516585165951660516615166251663516645166551666516675166851669516705167151672516735167451675516765167751678516795168051681516825168351684516855168651687516885168951690516915169251693516945169551696516975169851699517005170151702517035170451705517065170751708517095171051711517125171351714517155171651717517185171951720517215172251723517245172551726517275172851729517305173151732517335173451735517365173751738517395174051741517425174351744517455174651747517485174951750517515175251753517545175551756517575175851759517605176151762517635176451765517665176751768517695177051771517725177351774517755177651777517785177951780517815178251783517845178551786517875178851789517905179151792517935179451795517965179751798517995180051801518025180351804518055180651807518085180951810518115181251813518145181551816518175181851819518205182151822518235182451825518265182751828518295183051831518325183351834518355183651837518385183951840518415184251843518445184551846518475184851849518505185151852518535185451855518565185751858518595186051861518625186351864518655186651867518685186951870518715187251873518745187551876518775187851879518805188151882518835188451885518865188751888518895189051891518925189351894518955189651897518985189951900519015190251903519045190551906519075190851909519105191151912519135191451915519165191751918519195192051921519225192351924519255192651927519285192951930519315193251933519345193551936519375193851939519405194151942519435194451945519465194751948519495195051951519525195351954519555195651957519585195951960519615196251963519645196551966519675196851969519705197151972519735197451975519765197751978519795198051981519825198351984519855198651987519885198951990519915199251993519945199551996519975199851999520005200152002520035200452005520065200752008520095201052011520125201352014520155201652017520185201952020520215202252023520245202552026520275202852029520305203152032520335203452035520365203752038520395204052041520425204352044520455204652047520485204952050520515205252053520545205552056520575205852059520605206152062520635206452065520665206752068520695207052071520725207352074520755207652077520785207952080520815208252083520845208552086520875208852089520905209152092520935209452095520965209752098520995210052101521025210352104521055210652107521085210952110521115211252113521145211552116521175211852119521205212152122521235212452125521265212752128521295213052131521325213352134521355213652137521385213952140521415214252143521445214552146521475214852149521505215152152521535215452155521565215752158521595216052161521625216352164521655216652167521685216952170521715217252173521745217552176521775217852179521805218152182521835218452185521865218752188521895219052191521925219352194521955219652197521985219952200522015220252203522045220552206522075220852209522105221152212522135221452215522165221752218522195222052221522225222352224522255222652227522285222952230522315223252233522345223552236522375223852239522405224152242522435224452245522465224752248522495225052251522525225352254522555225652257522585225952260522615226252263522645226552266522675226852269522705227152272522735227452275522765227752278522795228052281522825228352284522855228652287522885228952290522915229252293522945229552296522975229852299523005230152302523035230452305523065230752308523095231052311523125231352314523155231652317523185231952320523215232252323523245232552326523275232852329523305233152332523335233452335523365233752338523395234052341523425234352344523455234652347523485234952350523515235252353523545235552356523575235852359523605236152362523635236452365523665236752368523695237052371523725237352374523755237652377523785237952380523815238252383523845238552386523875238852389523905239152392523935239452395523965239752398523995240052401524025240352404524055240652407524085240952410524115241252413524145241552416524175241852419524205242152422524235242452425524265242752428524295243052431524325243352434524355243652437524385243952440524415244252443524445244552446524475244852449524505245152452524535245452455524565245752458524595246052461524625246352464524655246652467524685246952470524715247252473524745247552476524775247852479524805248152482524835248452485524865248752488524895249052491524925249352494524955249652497524985249952500525015250252503525045250552506525075250852509525105251152512525135251452515525165251752518525195252052521525225252352524525255252652527525285252952530525315253252533525345253552536525375253852539525405254152542525435254452545525465254752548525495255052551525525255352554525555255652557525585255952560525615256252563525645256552566525675256852569525705257152572525735257452575525765257752578525795258052581525825258352584525855258652587525885258952590525915259252593525945259552596525975259852599526005260152602526035260452605526065260752608526095261052611526125261352614526155261652617526185261952620526215262252623526245262552626526275262852629526305263152632526335263452635526365263752638526395264052641526425264352644526455264652647526485264952650526515265252653526545265552656526575265852659526605266152662526635266452665526665266752668526695267052671526725267352674526755267652677526785267952680526815268252683526845268552686526875268852689526905269152692526935269452695526965269752698526995270052701527025270352704527055270652707527085270952710527115271252713527145271552716527175271852719527205272152722527235272452725527265272752728527295273052731527325273352734527355273652737527385273952740527415274252743527445274552746527475274852749527505275152752527535275452755527565275752758527595276052761527625276352764527655276652767527685276952770527715277252773527745277552776527775277852779527805278152782527835278452785527865278752788527895279052791527925279352794527955279652797527985279952800528015280252803528045280552806528075280852809528105281152812528135281452815528165281752818528195282052821528225282352824528255282652827528285282952830528315283252833528345283552836528375283852839528405284152842528435284452845528465284752848528495285052851528525285352854528555285652857528585285952860528615286252863528645286552866528675286852869528705287152872528735287452875528765287752878528795288052881528825288352884528855288652887528885288952890528915289252893528945289552896528975289852899529005290152902529035290452905529065290752908529095291052911529125291352914529155291652917529185291952920529215292252923529245292552926529275292852929529305293152932529335293452935529365293752938529395294052941529425294352944529455294652947529485294952950529515295252953529545295552956529575295852959529605296152962529635296452965529665296752968529695297052971529725297352974529755297652977529785297952980529815298252983529845298552986529875298852989529905299152992529935299452995529965299752998529995300053001530025300353004530055300653007530085300953010530115301253013530145301553016530175301853019530205302153022530235302453025530265302753028530295303053031530325303353034530355303653037530385303953040530415304253043530445304553046530475304853049530505305153052530535305453055530565305753058530595306053061530625306353064530655306653067530685306953070530715307253073530745307553076530775307853079530805308153082530835308453085530865308753088530895309053091530925309353094530955309653097530985309953100531015310253103531045310553106531075310853109531105311153112531135311453115531165311753118531195312053121531225312353124531255312653127531285312953130531315313253133531345313553136531375313853139531405314153142531435314453145531465314753148531495315053151531525315353154531555315653157531585315953160531615316253163531645316553166531675316853169531705317153172531735317453175531765317753178531795318053181531825318353184531855318653187531885318953190531915319253193531945319553196531975319853199532005320153202532035320453205532065320753208532095321053211532125321353214532155321653217532185321953220532215322253223532245322553226532275322853229532305323153232532335323453235532365323753238532395324053241532425324353244532455324653247532485324953250532515325253253532545325553256532575325853259532605326153262532635326453265532665326753268532695327053271532725327353274532755327653277532785327953280532815328253283532845328553286532875328853289532905329153292532935329453295532965329753298532995330053301533025330353304533055330653307533085330953310533115331253313533145331553316533175331853319533205332153322533235332453325533265332753328533295333053331533325333353334533355333653337533385333953340533415334253343533445334553346533475334853349533505335153352533535335453355533565335753358533595336053361533625336353364533655336653367533685336953370533715337253373533745337553376533775337853379533805338153382533835338453385533865338753388533895339053391533925339353394533955339653397533985339953400534015340253403534045340553406534075340853409534105341153412534135341453415534165341753418534195342053421534225342353424534255342653427534285342953430534315343253433534345343553436534375343853439534405344153442534435344453445534465344753448534495345053451534525345353454534555345653457534585345953460534615346253463534645346553466534675346853469534705347153472534735347453475534765347753478534795348053481534825348353484534855348653487534885348953490534915349253493534945349553496534975349853499535005350153502535035350453505535065350753508535095351053511535125351353514535155351653517535185351953520535215352253523535245352553526535275352853529535305353153532535335353453535535365353753538535395354053541535425354353544535455354653547535485354953550535515355253553535545355553556535575355853559535605356153562535635356453565535665356753568535695357053571535725357353574535755357653577535785357953580535815358253583535845358553586535875358853589535905359153592535935359453595535965359753598535995360053601536025360353604536055360653607536085360953610536115361253613536145361553616536175361853619536205362153622536235362453625536265362753628536295363053631536325363353634536355363653637536385363953640536415364253643536445364553646536475364853649536505365153652536535365453655536565365753658536595366053661536625366353664536655366653667536685366953670536715367253673536745367553676536775367853679536805368153682536835368453685536865368753688536895369053691536925369353694536955369653697536985369953700537015370253703537045370553706537075370853709537105371153712537135371453715537165371753718537195372053721537225372353724537255372653727537285372953730537315373253733537345373553736537375373853739537405374153742537435374453745537465374753748537495375053751537525375353754537555375653757537585375953760537615376253763537645376553766537675376853769537705377153772537735377453775537765377753778537795378053781537825378353784537855378653787537885378953790537915379253793537945379553796537975379853799538005380153802538035380453805538065380753808538095381053811538125381353814538155381653817538185381953820538215382253823538245382553826538275382853829538305383153832538335383453835538365383753838538395384053841538425384353844538455384653847538485384953850538515385253853538545385553856538575385853859538605386153862538635386453865538665386753868538695387053871538725387353874538755387653877538785387953880538815388253883538845388553886538875388853889538905389153892538935389453895538965389753898538995390053901539025390353904539055390653907539085390953910539115391253913539145391553916539175391853919539205392153922539235392453925539265392753928539295393053931539325393353934539355393653937539385393953940539415394253943539445394553946539475394853949539505395153952539535395453955539565395753958539595396053961539625396353964539655396653967539685396953970539715397253973539745397553976539775397853979539805398153982539835398453985539865398753988539895399053991539925399353994539955399653997539985399954000540015400254003540045400554006540075400854009540105401154012540135401454015540165401754018540195402054021540225402354024540255402654027540285402954030540315403254033540345403554036540375403854039540405404154042540435404454045540465404754048540495405054051540525405354054540555405654057540585405954060540615406254063540645406554066540675406854069540705407154072540735407454075540765407754078540795408054081540825408354084540855408654087540885408954090540915409254093540945409554096540975409854099541005410154102541035410454105541065410754108541095411054111541125411354114541155411654117541185411954120541215412254123541245412554126541275412854129541305413154132541335413454135541365413754138541395414054141541425414354144541455414654147541485414954150541515415254153541545415554156541575415854159541605416154162541635416454165541665416754168541695417054171541725417354174541755417654177541785417954180541815418254183541845418554186541875418854189541905419154192541935419454195541965419754198541995420054201542025420354204542055420654207542085420954210542115421254213542145421554216542175421854219542205422154222542235422454225542265422754228542295423054231542325423354234542355423654237542385423954240542415424254243542445424554246542475424854249542505425154252542535425454255542565425754258542595426054261542625426354264542655426654267542685426954270542715427254273542745427554276542775427854279542805428154282542835428454285542865428754288542895429054291542925429354294542955429654297542985429954300543015430254303543045430554306543075430854309543105431154312543135431454315543165431754318543195432054321543225432354324543255432654327543285432954330543315433254333543345433554336543375433854339543405434154342543435434454345543465434754348543495435054351543525435354354543555435654357543585435954360543615436254363543645436554366543675436854369543705437154372543735437454375543765437754378543795438054381543825438354384543855438654387543885438954390543915439254393543945439554396543975439854399544005440154402544035440454405544065440754408544095441054411544125441354414544155441654417544185441954420544215442254423544245442554426544275442854429544305443154432544335443454435544365443754438544395444054441544425444354444544455444654447544485444954450544515445254453544545445554456544575445854459544605446154462544635446454465544665446754468544695447054471544725447354474544755447654477544785447954480544815448254483544845448554486544875448854489544905449154492544935449454495544965449754498544995450054501545025450354504545055450654507545085450954510545115451254513545145451554516545175451854519545205452154522545235452454525545265452754528545295453054531545325453354534545355453654537545385453954540545415454254543545445454554546545475454854549545505455154552545535455454555545565455754558545595456054561545625456354564545655456654567545685456954570545715457254573545745457554576545775457854579545805458154582545835458454585545865458754588545895459054591545925459354594545955459654597545985459954600546015460254603546045460554606546075460854609546105461154612546135461454615546165461754618546195462054621546225462354624546255462654627546285462954630546315463254633546345463554636546375463854639546405464154642546435464454645546465464754648546495465054651546525465354654546555465654657546585465954660546615466254663546645466554666546675466854669546705467154672546735467454675546765467754678546795468054681546825468354684546855468654687546885468954690546915469254693546945469554696546975469854699547005470154702547035470454705547065470754708547095471054711547125471354714547155471654717547185471954720547215472254723547245472554726547275472854729547305473154732547335473454735547365473754738547395474054741547425474354744547455474654747547485474954750547515475254753547545475554756547575475854759547605476154762547635476454765547665476754768547695477054771547725477354774547755477654777547785477954780547815478254783547845478554786547875478854789547905479154792547935479454795547965479754798547995480054801548025480354804548055480654807548085480954810548115481254813548145481554816548175481854819548205482154822548235482454825548265482754828548295483054831548325483354834548355483654837548385483954840548415484254843548445484554846548475484854849548505485154852548535485454855548565485754858548595486054861548625486354864548655486654867548685486954870548715487254873548745487554876548775487854879548805488154882548835488454885548865488754888548895489054891548925489354894548955489654897548985489954900549015490254903549045490554906549075490854909549105491154912549135491454915549165491754918549195492054921549225492354924549255492654927549285492954930549315493254933549345493554936549375493854939549405494154942549435494454945549465494754948549495495054951549525495354954549555495654957549585495954960549615496254963549645496554966549675496854969549705497154972549735497454975549765497754978549795498054981549825498354984549855498654987549885498954990549915499254993549945499554996549975499854999550005500155002550035500455005550065500755008550095501055011550125501355014550155501655017550185501955020550215502255023550245502555026550275502855029550305503155032550335503455035550365503755038550395504055041550425504355044550455504655047550485504955050550515505255053550545505555056550575505855059550605506155062550635506455065550665506755068550695507055071550725507355074550755507655077550785507955080550815508255083550845508555086550875508855089550905509155092550935509455095550965509755098550995510055101551025510355104551055510655107551085510955110551115511255113551145511555116551175511855119551205512155122551235512455125551265512755128551295513055131551325513355134551355513655137551385513955140551415514255143551445514555146551475514855149551505515155152551535515455155551565515755158551595516055161551625516355164551655516655167551685516955170551715517255173551745517555176551775517855179551805518155182551835518455185551865518755188551895519055191551925519355194551955519655197551985519955200552015520255203552045520555206552075520855209552105521155212552135521455215552165521755218552195522055221552225522355224552255522655227552285522955230552315523255233552345523555236552375523855239552405524155242552435524455245552465524755248552495525055251552525525355254552555525655257552585525955260552615526255263552645526555266552675526855269552705527155272552735527455275552765527755278552795528055281552825528355284552855528655287552885528955290552915529255293552945529555296552975529855299553005530155302553035530455305553065530755308553095531055311553125531355314553155531655317553185531955320553215532255323553245532555326553275532855329553305533155332553335533455335553365533755338553395534055341553425534355344553455534655347553485534955350553515535255353553545535555356553575535855359553605536155362553635536455365553665536755368553695537055371553725537355374553755537655377553785537955380553815538255383553845538555386553875538855389553905539155392553935539455395553965539755398553995540055401554025540355404554055540655407554085540955410554115541255413554145541555416554175541855419554205542155422554235542455425554265542755428554295543055431554325543355434554355543655437554385543955440554415544255443554445544555446554475544855449554505545155452554535545455455554565545755458554595546055461554625546355464554655546655467554685546955470554715547255473554745547555476554775547855479554805548155482554835548455485554865548755488554895549055491554925549355494554955549655497554985549955500555015550255503555045550555506555075550855509555105551155512555135551455515555165551755518555195552055521555225552355524555255552655527555285552955530555315553255533555345553555536555375553855539555405554155542555435554455545555465554755548555495555055551555525555355554555555555655557555585555955560555615556255563555645556555566555675556855569555705557155572555735557455575555765557755578555795558055581555825558355584555855558655587555885558955590555915559255593555945559555596555975559855599556005560155602556035560455605556065560755608556095561055611556125561355614556155561655617556185561955620556215562255623556245562555626556275562855629556305563155632556335563455635556365563755638556395564055641556425564355644556455564655647556485564955650556515565255653556545565555656556575565855659556605566155662556635566455665556665566755668556695567055671556725567355674556755567655677556785567955680556815568255683556845568555686556875568855689556905569155692556935569455695556965569755698556995570055701557025570355704557055570655707557085570955710557115571255713557145571555716557175571855719557205572155722557235572455725557265572755728557295573055731557325573355734557355573655737557385573955740557415574255743557445574555746557475574855749557505575155752557535575455755557565575755758557595576055761557625576355764557655576655767557685576955770557715577255773557745577555776557775577855779557805578155782557835578455785557865578755788557895579055791557925579355794557955579655797557985579955800558015580255803558045580555806558075580855809558105581155812558135581455815558165581755818558195582055821558225582355824558255582655827558285582955830558315583255833558345583555836558375583855839558405584155842558435584455845558465584755848558495585055851558525585355854558555585655857558585585955860558615586255863558645586555866558675586855869558705587155872558735587455875558765587755878558795588055881558825588355884558855588655887558885588955890558915589255893558945589555896558975589855899559005590155902559035590455905559065590755908559095591055911559125591355914559155591655917559185591955920559215592255923559245592555926559275592855929559305593155932559335593455935559365593755938559395594055941559425594355944559455594655947559485594955950559515595255953559545595555956559575595855959559605596155962559635596455965559665596755968559695597055971559725597355974559755597655977559785597955980559815598255983559845598555986559875598855989559905599155992559935599455995559965599755998559995600056001560025600356004560055600656007560085600956010560115601256013560145601556016560175601856019560205602156022560235602456025560265602756028560295603056031560325603356034560355603656037560385603956040560415604256043560445604556046560475604856049560505605156052560535605456055560565605756058560595606056061560625606356064560655606656067560685606956070560715607256073560745607556076560775607856079560805608156082560835608456085560865608756088560895609056091560925609356094560955609656097560985609956100561015610256103561045610556106561075610856109561105611156112561135611456115561165611756118561195612056121561225612356124561255612656127561285612956130561315613256133561345613556136561375613856139561405614156142561435614456145561465614756148561495615056151561525615356154561555615656157561585615956160561615616256163561645616556166561675616856169561705617156172561735617456175561765617756178561795618056181561825618356184561855618656187561885618956190561915619256193561945619556196561975619856199562005620156202562035620456205562065620756208562095621056211562125621356214562155621656217562185621956220562215622256223562245622556226562275622856229562305623156232562335623456235562365623756238562395624056241562425624356244562455624656247562485624956250562515625256253562545625556256562575625856259562605626156262562635626456265562665626756268562695627056271562725627356274562755627656277562785627956280562815628256283562845628556286562875628856289562905629156292562935629456295562965629756298562995630056301563025630356304563055630656307563085630956310563115631256313563145631556316563175631856319563205632156322563235632456325563265632756328563295633056331563325633356334563355633656337563385633956340563415634256343563445634556346563475634856349563505635156352563535635456355563565635756358563595636056361563625636356364563655636656367563685636956370563715637256373563745637556376563775637856379563805638156382563835638456385563865638756388563895639056391563925639356394563955639656397563985639956400564015640256403564045640556406564075640856409564105641156412564135641456415564165641756418564195642056421564225642356424564255642656427564285642956430564315643256433564345643556436564375643856439564405644156442564435644456445564465644756448564495645056451564525645356454564555645656457564585645956460564615646256463564645646556466564675646856469564705647156472564735647456475564765647756478564795648056481564825648356484564855648656487564885648956490564915649256493564945649556496564975649856499565005650156502565035650456505565065650756508565095651056511565125651356514565155651656517565185651956520565215652256523565245652556526565275652856529565305653156532565335653456535565365653756538565395654056541565425654356544565455654656547565485654956550565515655256553565545655556556565575655856559565605656156562565635656456565565665656756568565695657056571565725657356574565755657656577565785657956580565815658256583565845658556586565875658856589565905659156592565935659456595565965659756598565995660056601566025660356604566055660656607566085660956610566115661256613566145661556616566175661856619566205662156622566235662456625566265662756628566295663056631566325663356634566355663656637566385663956640566415664256643566445664556646566475664856649566505665156652566535665456655566565665756658566595666056661566625666356664566655666656667566685666956670566715667256673566745667556676566775667856679566805668156682566835668456685566865668756688566895669056691566925669356694566955669656697566985669956700567015670256703567045670556706567075670856709567105671156712567135671456715567165671756718567195672056721567225672356724567255672656727567285672956730567315673256733567345673556736567375673856739567405674156742567435674456745567465674756748567495675056751567525675356754567555675656757567585675956760567615676256763567645676556766567675676856769567705677156772567735677456775567765677756778567795678056781567825678356784567855678656787567885678956790567915679256793567945679556796567975679856799568005680156802568035680456805568065680756808568095681056811568125681356814568155681656817568185681956820568215682256823568245682556826568275682856829568305683156832568335683456835568365683756838568395684056841568425684356844568455684656847568485684956850568515685256853568545685556856568575685856859568605686156862568635686456865568665686756868568695687056871568725687356874568755687656877568785687956880568815688256883568845688556886568875688856889568905689156892568935689456895568965689756898568995690056901569025690356904569055690656907569085690956910569115691256913569145691556916569175691856919569205692156922569235692456925569265692756928569295693056931569325693356934569355693656937569385693956940569415694256943569445694556946569475694856949569505695156952569535695456955569565695756958569595696056961569625696356964569655696656967569685696956970569715697256973569745697556976569775697856979569805698156982569835698456985569865698756988569895699056991569925699356994569955699656997569985699957000570015700257003570045700557006570075700857009570105701157012570135701457015570165701757018570195702057021570225702357024570255702657027570285702957030570315703257033570345703557036570375703857039570405704157042570435704457045570465704757048570495705057051570525705357054570555705657057570585705957060570615706257063570645706557066570675706857069570705707157072570735707457075570765707757078570795708057081570825708357084570855708657087570885708957090570915709257093570945709557096570975709857099571005710157102571035710457105571065710757108571095711057111571125711357114571155711657117571185711957120571215712257123571245712557126571275712857129571305713157132571335713457135571365713757138571395714057141571425714357144571455714657147571485714957150571515715257153571545715557156571575715857159571605716157162571635716457165571665716757168571695717057171571725717357174571755717657177571785717957180571815718257183571845718557186571875718857189571905719157192571935719457195571965719757198571995720057201572025720357204572055720657207572085720957210572115721257213572145721557216572175721857219572205722157222572235722457225572265722757228572295723057231572325723357234572355723657237572385723957240572415724257243572445724557246572475724857249572505725157252572535725457255572565725757258572595726057261572625726357264572655726657267572685726957270572715727257273572745727557276572775727857279572805728157282572835728457285572865728757288572895729057291572925729357294572955729657297572985729957300573015730257303573045730557306573075730857309573105731157312573135731457315573165731757318573195732057321573225732357324573255732657327573285732957330573315733257333573345733557336573375733857339573405734157342573435734457345573465734757348573495735057351573525735357354573555735657357573585735957360573615736257363573645736557366573675736857369573705737157372573735737457375573765737757378573795738057381573825738357384573855738657387573885738957390573915739257393573945739557396573975739857399574005740157402574035740457405574065740757408574095741057411574125741357414574155741657417574185741957420574215742257423574245742557426574275742857429574305743157432574335743457435574365743757438574395744057441574425744357444574455744657447574485744957450574515745257453574545745557456574575745857459574605746157462574635746457465574665746757468574695747057471574725747357474574755747657477574785747957480574815748257483574845748557486574875748857489574905749157492574935749457495574965749757498574995750057501575025750357504575055750657507575085750957510575115751257513575145751557516575175751857519575205752157522575235752457525575265752757528575295753057531575325753357534575355753657537575385753957540575415754257543575445754557546575475754857549575505755157552575535755457555575565755757558575595756057561575625756357564575655756657567575685756957570575715757257573575745757557576575775757857579575805758157582575835758457585575865758757588575895759057591575925759357594575955759657597575985759957600576015760257603576045760557606576075760857609576105761157612576135761457615576165761757618576195762057621576225762357624576255762657627576285762957630576315763257633576345763557636576375763857639576405764157642576435764457645576465764757648576495765057651576525765357654576555765657657576585765957660576615766257663576645766557666576675766857669576705767157672576735767457675576765767757678576795768057681576825768357684576855768657687576885768957690576915769257693576945769557696576975769857699577005770157702577035770457705577065770757708577095771057711577125771357714577155771657717577185771957720577215772257723577245772557726577275772857729577305773157732577335773457735577365773757738577395774057741577425774357744577455774657747577485774957750577515775257753577545775557756577575775857759577605776157762577635776457765577665776757768577695777057771577725777357774577755777657777577785777957780577815778257783577845778557786577875778857789577905779157792577935779457795577965779757798577995780057801578025780357804578055780657807578085780957810578115781257813578145781557816578175781857819578205782157822578235782457825578265782757828578295783057831578325783357834578355783657837578385783957840578415784257843578445784557846578475784857849578505785157852578535785457855578565785757858578595786057861578625786357864578655786657867578685786957870578715787257873578745787557876578775787857879578805788157882578835788457885578865788757888578895789057891578925789357894578955789657897578985789957900579015790257903579045790557906579075790857909579105791157912579135791457915579165791757918579195792057921579225792357924579255792657927579285792957930579315793257933579345793557936579375793857939579405794157942579435794457945579465794757948579495795057951579525795357954579555795657957579585795957960579615796257963579645796557966579675796857969579705797157972579735797457975579765797757978579795798057981579825798357984579855798657987579885798957990579915799257993579945799557996579975799857999580005800158002580035800458005580065800758008580095801058011580125801358014580155801658017580185801958020580215802258023580245802558026580275802858029580305803158032580335803458035580365803758038580395804058041580425804358044580455804658047580485804958050580515805258053580545805558056580575805858059580605806158062580635806458065580665806758068580695807058071580725807358074580755807658077580785807958080580815808258083580845808558086580875808858089580905809158092580935809458095580965809758098580995810058101581025810358104581055810658107581085810958110581115811258113581145811558116581175811858119581205812158122581235812458125581265812758128581295813058131581325813358134581355813658137581385813958140581415814258143581445814558146581475814858149581505815158152581535815458155581565815758158581595816058161581625816358164581655816658167581685816958170581715817258173581745817558176581775817858179581805818158182581835818458185581865818758188581895819058191581925819358194581955819658197581985819958200582015820258203582045820558206582075820858209582105821158212582135821458215582165821758218582195822058221582225822358224582255822658227582285822958230582315823258233582345823558236582375823858239582405824158242582435824458245582465824758248582495825058251582525825358254582555825658257582585825958260582615826258263582645826558266582675826858269582705827158272582735827458275582765827758278582795828058281582825828358284582855828658287582885828958290582915829258293582945829558296582975829858299583005830158302583035830458305583065830758308583095831058311583125831358314583155831658317583185831958320583215832258323583245832558326583275832858329583305833158332583335833458335583365833758338583395834058341583425834358344583455834658347583485834958350583515835258353583545835558356583575835858359583605836158362583635836458365583665836758368583695837058371583725837358374583755837658377583785837958380583815838258383583845838558386583875838858389583905839158392583935839458395583965839758398583995840058401584025840358404584055840658407584085840958410584115841258413584145841558416584175841858419584205842158422584235842458425584265842758428584295843058431584325843358434584355843658437584385843958440584415844258443584445844558446584475844858449584505845158452584535845458455584565845758458584595846058461584625846358464584655846658467584685846958470584715847258473584745847558476584775847858479584805848158482584835848458485584865848758488584895849058491584925849358494584955849658497584985849958500585015850258503585045850558506585075850858509585105851158512585135851458515585165851758518585195852058521585225852358524585255852658527585285852958530585315853258533585345853558536585375853858539585405854158542585435854458545585465854758548585495855058551585525855358554585555855658557585585855958560585615856258563585645856558566585675856858569585705857158572585735857458575585765857758578585795858058581585825858358584585855858658587585885858958590585915859258593585945859558596585975859858599586005860158602586035860458605586065860758608586095861058611586125861358614586155861658617586185861958620586215862258623586245862558626586275862858629586305863158632586335863458635586365863758638586395864058641586425864358644586455864658647586485864958650586515865258653586545865558656586575865858659586605866158662586635866458665586665866758668586695867058671586725867358674586755867658677586785867958680586815868258683586845868558686586875868858689586905869158692586935869458695586965869758698586995870058701587025870358704587055870658707587085870958710587115871258713587145871558716587175871858719587205872158722587235872458725587265872758728587295873058731587325873358734587355873658737587385873958740587415874258743587445874558746587475874858749587505875158752587535875458755587565875758758587595876058761587625876358764587655876658767587685876958770587715877258773587745877558776587775877858779587805878158782587835878458785587865878758788587895879058791587925879358794587955879658797587985879958800588015880258803588045880558806588075880858809588105881158812588135881458815588165881758818588195882058821588225882358824588255882658827588285882958830588315883258833588345883558836588375883858839588405884158842588435884458845588465884758848588495885058851588525885358854588555885658857588585885958860588615886258863588645886558866588675886858869588705887158872588735887458875588765887758878588795888058881588825888358884588855888658887588885888958890588915889258893588945889558896588975889858899589005890158902589035890458905589065890758908589095891058911589125891358914589155891658917589185891958920589215892258923589245892558926589275892858929589305893158932589335893458935589365893758938589395894058941589425894358944589455894658947589485894958950589515895258953589545895558956589575895858959589605896158962589635896458965589665896758968589695897058971589725897358974589755897658977589785897958980589815898258983589845898558986589875898858989589905899158992589935899458995589965899758998589995900059001590025900359004590055900659007590085900959010590115901259013590145901559016590175901859019590205902159022590235902459025590265902759028590295903059031590325903359034590355903659037590385903959040590415904259043590445904559046590475904859049590505905159052590535905459055590565905759058590595906059061590625906359064590655906659067590685906959070590715907259073590745907559076590775907859079590805908159082590835908459085590865908759088590895909059091590925909359094590955909659097590985909959100591015910259103591045910559106591075910859109591105911159112591135911459115591165911759118591195912059121591225912359124591255912659127591285912959130591315913259133591345913559136591375913859139591405914159142591435914459145591465914759148591495915059151591525915359154591555915659157591585915959160591615916259163591645916559166591675916859169591705917159172591735917459175591765917759178591795918059181591825918359184591855918659187591885918959190591915919259193591945919559196591975919859199592005920159202592035920459205592065920759208592095921059211592125921359214592155921659217592185921959220592215922259223592245922559226592275922859229592305923159232592335923459235592365923759238592395924059241592425924359244592455924659247592485924959250592515925259253592545925559256592575925859259592605926159262592635926459265592665926759268592695927059271592725927359274592755927659277592785927959280592815928259283592845928559286592875928859289592905929159292592935929459295592965929759298592995930059301593025930359304593055930659307593085930959310593115931259313593145931559316593175931859319593205932159322593235932459325593265932759328593295933059331593325933359334593355933659337593385933959340593415934259343593445934559346593475934859349593505935159352593535935459355593565935759358593595936059361593625936359364593655936659367593685936959370593715937259373593745937559376593775937859379593805938159382593835938459385593865938759388593895939059391593925939359394593955939659397593985939959400594015940259403594045940559406594075940859409594105941159412594135941459415594165941759418594195942059421594225942359424594255942659427594285942959430594315943259433594345943559436594375943859439594405944159442594435944459445594465944759448594495945059451594525945359454594555945659457594585945959460594615946259463594645946559466594675946859469594705947159472594735947459475594765947759478594795948059481594825948359484594855948659487594885948959490594915949259493594945949559496594975949859499595005950159502595035950459505595065950759508595095951059511595125951359514595155951659517595185951959520595215952259523595245952559526595275952859529595305953159532595335953459535595365953759538595395954059541595425954359544595455954659547595485954959550595515955259553595545955559556595575955859559595605956159562595635956459565595665956759568595695957059571595725957359574595755957659577595785957959580595815958259583595845958559586595875958859589595905959159592595935959459595595965959759598595995960059601596025960359604596055960659607596085960959610596115961259613596145961559616596175961859619596205962159622596235962459625596265962759628596295963059631596325963359634596355963659637596385963959640596415964259643596445964559646596475964859649596505965159652596535965459655596565965759658596595966059661596625966359664596655966659667596685966959670596715967259673596745967559676596775967859679596805968159682596835968459685596865968759688596895969059691596925969359694596955969659697596985969959700597015970259703597045970559706597075970859709597105971159712597135971459715597165971759718597195972059721597225972359724597255972659727597285972959730597315973259733597345973559736597375973859739597405974159742597435974459745597465974759748597495975059751597525975359754597555975659757597585975959760597615976259763597645976559766597675976859769597705977159772597735977459775597765977759778597795978059781597825978359784597855978659787597885978959790597915979259793597945979559796597975979859799598005980159802598035980459805598065980759808598095981059811598125981359814598155981659817598185981959820598215982259823598245982559826598275982859829598305983159832598335983459835598365983759838598395984059841598425984359844598455984659847598485984959850598515985259853598545985559856598575985859859598605986159862598635986459865598665986759868598695987059871598725987359874598755987659877598785987959880598815988259883598845988559886598875988859889598905989159892598935989459895598965989759898598995990059901599025990359904599055990659907599085990959910599115991259913599145991559916599175991859919599205992159922599235992459925599265992759928599295993059931599325993359934599355993659937599385993959940599415994259943599445994559946599475994859949599505995159952599535995459955599565995759958599595996059961599625996359964599655996659967599685996959970599715997259973599745997559976599775997859979599805998159982599835998459985599865998759988599895999059991599925999359994599955999659997599985999960000600016000260003600046000560006600076000860009600106001160012600136001460015600166001760018600196002060021600226002360024600256002660027600286002960030600316003260033600346003560036600376003860039600406004160042600436004460045600466004760048600496005060051600526005360054600556005660057600586005960060600616006260063600646006560066600676006860069600706007160072600736007460075600766007760078600796008060081600826008360084600856008660087600886008960090600916009260093600946009560096600976009860099601006010160102601036010460105601066010760108601096011060111601126011360114601156011660117601186011960120601216012260123601246012560126601276012860129601306013160132601336013460135601366013760138601396014060141601426014360144601456014660147601486014960150601516015260153601546015560156601576015860159601606016160162601636016460165601666016760168601696017060171601726017360174601756017660177601786017960180601816018260183601846018560186601876018860189601906019160192601936019460195601966019760198601996020060201602026020360204602056020660207602086020960210602116021260213602146021560216602176021860219602206022160222602236022460225602266022760228602296023060231602326023360234602356023660237602386023960240602416024260243602446024560246602476024860249602506025160252602536025460255602566025760258602596026060261602626026360264602656026660267602686026960270602716027260273602746027560276602776027860279602806028160282602836028460285602866028760288602896029060291602926029360294602956029660297602986029960300603016030260303603046030560306603076030860309603106031160312603136031460315603166031760318603196032060321603226032360324603256032660327603286032960330603316033260333603346033560336603376033860339603406034160342603436034460345603466034760348603496035060351603526035360354603556035660357603586035960360603616036260363603646036560366603676036860369603706037160372603736037460375603766037760378603796038060381603826038360384603856038660387603886038960390603916039260393603946039560396603976039860399604006040160402604036040460405604066040760408604096041060411604126041360414604156041660417604186041960420604216042260423604246042560426604276042860429604306043160432604336043460435604366043760438604396044060441604426044360444604456044660447604486044960450604516045260453604546045560456604576045860459604606046160462604636046460465604666046760468604696047060471604726047360474604756047660477604786047960480604816048260483604846048560486604876048860489604906049160492604936049460495604966049760498604996050060501605026050360504605056050660507605086050960510605116051260513605146051560516605176051860519605206052160522605236052460525605266052760528605296053060531605326053360534605356053660537605386053960540605416054260543605446054560546605476054860549605506055160552605536055460555605566055760558605596056060561605626056360564605656056660567605686056960570605716057260573605746057560576605776057860579605806058160582605836058460585605866058760588605896059060591605926059360594605956059660597605986059960600606016060260603606046060560606606076060860609606106061160612606136061460615606166061760618606196062060621606226062360624606256062660627606286062960630606316063260633606346063560636606376063860639606406064160642606436064460645606466064760648606496065060651606526065360654606556065660657606586065960660606616066260663606646066560666606676066860669606706067160672606736067460675606766067760678606796068060681606826068360684606856068660687606886068960690606916069260693606946069560696606976069860699607006070160702607036070460705607066070760708607096071060711607126071360714607156071660717607186071960720607216072260723607246072560726607276072860729607306073160732607336073460735607366073760738607396074060741607426074360744607456074660747607486074960750607516075260753607546075560756607576075860759607606076160762607636076460765607666076760768607696077060771607726077360774607756077660777607786077960780607816078260783607846078560786607876078860789607906079160792607936079460795607966079760798607996080060801608026080360804608056080660807608086080960810608116081260813608146081560816608176081860819608206082160822608236082460825608266082760828608296083060831608326083360834608356083660837608386083960840608416084260843608446084560846608476084860849608506085160852608536085460855608566085760858608596086060861608626086360864608656086660867608686086960870608716087260873608746087560876608776087860879608806088160882608836088460885608866088760888608896089060891608926089360894608956089660897608986089960900609016090260903609046090560906609076090860909609106091160912609136091460915609166091760918609196092060921609226092360924609256092660927609286092960930609316093260933609346093560936609376093860939609406094160942609436094460945609466094760948609496095060951609526095360954609556095660957609586095960960609616096260963609646096560966609676096860969609706097160972609736097460975609766097760978609796098060981609826098360984609856098660987609886098960990609916099260993609946099560996609976099860999610006100161002610036100461005610066100761008610096101061011610126101361014610156101661017610186101961020610216102261023610246102561026610276102861029610306103161032610336103461035610366103761038610396104061041610426104361044610456104661047610486104961050610516105261053610546105561056610576105861059610606106161062610636106461065610666106761068610696107061071610726107361074610756107661077610786107961080610816108261083610846108561086610876108861089610906109161092610936109461095610966109761098610996110061101611026110361104611056110661107611086110961110611116111261113611146111561116611176111861119611206112161122611236112461125611266112761128611296113061131611326113361134611356113661137611386113961140611416114261143611446114561146611476114861149611506115161152611536115461155611566115761158611596116061161611626116361164611656116661167611686116961170611716117261173611746117561176611776117861179611806118161182611836118461185611866118761188611896119061191611926119361194611956119661197611986119961200612016120261203612046120561206612076120861209612106121161212612136121461215612166121761218612196122061221612226122361224612256122661227612286122961230612316123261233612346123561236612376123861239612406124161242612436124461245612466124761248612496125061251612526125361254612556125661257612586125961260612616126261263612646126561266612676126861269612706127161272612736127461275612766127761278612796128061281612826128361284612856128661287612886128961290612916129261293612946129561296612976129861299613006130161302613036130461305613066130761308613096131061311613126131361314613156131661317613186131961320613216132261323613246132561326613276132861329613306133161332613336133461335613366133761338613396134061341613426134361344613456134661347613486134961350613516135261353613546135561356613576135861359613606136161362613636136461365613666136761368613696137061371613726137361374613756137661377613786137961380613816138261383613846138561386613876138861389613906139161392613936139461395613966139761398613996140061401614026140361404614056140661407614086140961410614116141261413614146141561416614176141861419614206142161422614236142461425614266142761428614296143061431614326143361434614356143661437614386143961440614416144261443614446144561446614476144861449614506145161452614536145461455614566145761458614596146061461614626146361464614656146661467614686146961470614716147261473614746147561476614776147861479614806148161482614836148461485614866148761488614896149061491614926149361494614956149661497614986149961500615016150261503615046150561506615076150861509615106151161512615136151461515615166151761518615196152061521615226152361524615256152661527615286152961530615316153261533615346153561536615376153861539615406154161542615436154461545615466154761548615496155061551615526155361554615556155661557615586155961560615616156261563615646156561566615676156861569615706157161572615736157461575615766157761578615796158061581615826158361584615856158661587615886158961590615916159261593615946159561596615976159861599616006160161602616036160461605616066160761608616096161061611616126161361614616156161661617616186161961620616216162261623616246162561626616276162861629616306163161632616336163461635616366163761638616396164061641616426164361644616456164661647616486164961650616516165261653616546165561656616576165861659616606166161662616636166461665616666166761668616696167061671616726167361674616756167661677616786167961680616816168261683616846168561686616876168861689616906169161692616936169461695616966169761698616996170061701617026170361704617056170661707617086170961710617116171261713617146171561716617176171861719617206172161722617236172461725617266172761728617296173061731617326173361734617356173661737617386173961740617416174261743617446174561746617476174861749617506175161752617536175461755617566175761758617596176061761617626176361764617656176661767617686176961770617716177261773617746177561776617776177861779617806178161782617836178461785617866178761788617896179061791617926179361794617956179661797617986179961800618016180261803618046180561806618076180861809618106181161812618136181461815618166181761818618196182061821618226182361824618256182661827618286182961830618316183261833618346183561836618376183861839618406184161842618436184461845618466184761848618496185061851618526185361854618556185661857618586185961860618616186261863618646186561866618676186861869618706187161872618736187461875618766187761878618796188061881618826188361884618856188661887618886188961890618916189261893618946189561896618976189861899619006190161902619036190461905619066190761908619096191061911619126191361914619156191661917619186191961920619216192261923619246192561926619276192861929619306193161932619336193461935619366193761938619396194061941619426194361944619456194661947619486194961950619516195261953619546195561956619576195861959619606196161962619636196461965619666196761968619696197061971619726197361974619756197661977619786197961980619816198261983619846198561986619876198861989619906199161992619936199461995619966199761998619996200062001620026200362004620056200662007620086200962010620116201262013620146201562016620176201862019620206202162022620236202462025620266202762028620296203062031620326203362034620356203662037620386203962040620416204262043620446204562046620476204862049620506205162052620536205462055620566205762058620596206062061620626206362064620656206662067620686206962070620716207262073620746207562076620776207862079620806208162082620836208462085620866208762088620896209062091620926209362094620956209662097620986209962100621016210262103621046210562106621076210862109621106211162112621136211462115621166211762118621196212062121621226212362124621256212662127621286212962130621316213262133621346213562136621376213862139621406214162142621436214462145621466214762148621496215062151621526215362154621556215662157621586215962160621616216262163621646216562166621676216862169621706217162172621736217462175621766217762178621796218062181621826218362184621856218662187621886218962190621916219262193621946219562196621976219862199622006220162202622036220462205622066220762208622096221062211622126221362214622156221662217622186221962220622216222262223622246222562226622276222862229622306223162232622336223462235622366223762238622396224062241622426224362244622456224662247622486224962250622516225262253622546225562256622576225862259622606226162262622636226462265622666226762268622696227062271622726227362274622756227662277622786227962280622816228262283622846228562286622876228862289622906229162292622936229462295622966229762298622996230062301623026230362304623056230662307623086230962310623116231262313623146231562316623176231862319623206232162322623236232462325623266232762328623296233062331623326233362334623356233662337623386233962340623416234262343623446234562346623476234862349623506235162352623536235462355623566235762358623596236062361623626236362364623656236662367623686236962370623716237262373623746237562376623776237862379623806238162382623836238462385623866238762388623896239062391623926239362394623956239662397623986239962400624016240262403624046240562406624076240862409624106241162412624136241462415624166241762418624196242062421624226242362424624256242662427624286242962430624316243262433624346243562436624376243862439624406244162442624436244462445624466244762448624496245062451624526245362454624556245662457624586245962460624616246262463624646246562466624676246862469624706247162472624736247462475624766247762478624796248062481624826248362484624856248662487624886248962490624916249262493624946249562496624976249862499625006250162502625036250462505625066250762508625096251062511625126251362514625156251662517625186251962520625216252262523625246252562526625276252862529625306253162532625336253462535625366253762538625396254062541625426254362544625456254662547625486254962550625516255262553625546255562556625576255862559625606256162562625636256462565625666256762568625696257062571625726257362574625756257662577625786257962580625816258262583625846258562586625876258862589625906259162592625936259462595625966259762598625996260062601626026260362604626056260662607626086260962610626116261262613626146261562616626176261862619626206262162622626236262462625626266262762628626296263062631626326263362634626356263662637626386263962640626416264262643626446264562646626476264862649626506265162652626536265462655626566265762658626596266062661626626266362664626656266662667626686266962670626716267262673626746267562676626776267862679626806268162682626836268462685626866268762688626896269062691626926269362694626956269662697626986269962700627016270262703627046270562706627076270862709627106271162712627136271462715627166271762718627196272062721627226272362724627256272662727627286272962730627316273262733627346273562736627376273862739627406274162742627436274462745627466274762748627496275062751627526275362754627556275662757627586275962760627616276262763627646276562766627676276862769627706277162772627736277462775627766277762778627796278062781627826278362784627856278662787627886278962790627916279262793627946279562796627976279862799628006280162802628036280462805628066280762808628096281062811628126281362814628156281662817628186281962820628216282262823628246282562826628276282862829628306283162832628336283462835628366283762838628396284062841628426284362844628456284662847628486284962850628516285262853628546285562856628576285862859628606286162862628636286462865628666286762868628696287062871628726287362874628756287662877628786287962880628816288262883628846288562886628876288862889628906289162892628936289462895628966289762898628996290062901629026290362904629056290662907629086290962910629116291262913629146291562916629176291862919629206292162922629236292462925629266292762928629296293062931629326293362934629356293662937629386293962940629416294262943629446294562946629476294862949629506295162952629536295462955629566295762958629596296062961629626296362964629656296662967629686296962970629716297262973629746297562976629776297862979629806298162982629836298462985629866298762988629896299062991629926299362994629956299662997629986299963000630016300263003630046300563006630076300863009630106301163012630136301463015630166301763018630196302063021630226302363024630256302663027630286302963030630316303263033630346303563036630376303863039630406304163042630436304463045630466304763048630496305063051630526305363054630556305663057630586305963060630616306263063630646306563066630676306863069630706307163072630736307463075630766307763078630796308063081630826308363084630856308663087630886308963090630916309263093630946309563096630976309863099631006310163102631036310463105631066310763108631096311063111631126311363114631156311663117631186311963120631216312263123631246312563126631276312863129631306313163132631336313463135631366313763138631396314063141631426314363144631456314663147631486314963150631516315263153631546315563156631576315863159631606316163162631636316463165631666316763168631696317063171631726317363174631756317663177631786317963180631816318263183631846318563186631876318863189631906319163192631936319463195631966319763198631996320063201632026320363204632056320663207632086320963210632116321263213632146321563216632176321863219632206322163222632236322463225632266322763228632296323063231632326323363234632356323663237632386323963240632416324263243632446324563246632476324863249632506325163252632536325463255632566325763258632596326063261632626326363264632656326663267632686326963270632716327263273632746327563276632776327863279632806328163282632836328463285632866328763288632896329063291632926329363294632956329663297632986329963300633016330263303633046330563306633076330863309633106331163312633136331463315633166331763318633196332063321633226332363324633256332663327633286332963330633316333263333633346333563336633376333863339633406334163342633436334463345633466334763348633496335063351633526335363354633556335663357633586335963360633616336263363633646336563366633676336863369633706337163372633736337463375633766337763378633796338063381633826338363384633856338663387633886338963390633916339263393633946339563396633976339863399634006340163402634036340463405634066340763408634096341063411634126341363414634156341663417634186341963420634216342263423634246342563426634276342863429634306343163432634336343463435634366343763438634396344063441634426344363444634456344663447634486344963450634516345263453634546345563456634576345863459634606346163462634636346463465634666346763468634696347063471634726347363474634756347663477634786347963480634816348263483634846348563486634876348863489634906349163492634936349463495634966349763498634996350063501635026350363504635056350663507635086350963510635116351263513635146351563516635176351863519635206352163522635236352463525635266352763528635296353063531635326353363534635356353663537635386353963540635416354263543635446354563546635476354863549635506355163552635536355463555635566355763558635596356063561635626356363564635656356663567635686356963570635716357263573635746357563576635776357863579635806358163582635836358463585635866358763588635896359063591635926359363594635956359663597635986359963600636016360263603636046360563606636076360863609636106361163612636136361463615636166361763618636196362063621636226362363624636256362663627636286362963630636316363263633636346363563636636376363863639636406364163642636436364463645636466364763648636496365063651636526365363654636556365663657636586365963660636616366263663636646366563666636676366863669636706367163672636736367463675636766367763678636796368063681636826368363684636856368663687636886368963690636916369263693636946369563696636976369863699637006370163702637036370463705637066370763708637096371063711637126371363714637156371663717637186371963720637216372263723637246372563726637276372863729637306373163732637336373463735637366373763738637396374063741637426374363744637456374663747637486374963750637516375263753637546375563756637576375863759637606376163762637636376463765637666376763768637696377063771637726377363774637756377663777637786377963780637816378263783637846378563786637876378863789637906379163792637936379463795637966379763798637996380063801638026380363804638056380663807638086380963810638116381263813638146381563816638176381863819638206382163822638236382463825638266382763828638296383063831638326383363834638356383663837638386383963840638416384263843638446384563846638476384863849638506385163852638536385463855638566385763858638596386063861638626386363864638656386663867638686386963870638716387263873638746387563876638776387863879638806388163882638836388463885638866388763888638896389063891638926389363894638956389663897638986389963900639016390263903639046390563906639076390863909639106391163912639136391463915639166391763918639196392063921639226392363924639256392663927639286392963930639316393263933639346393563936639376393863939639406394163942639436394463945639466394763948639496395063951639526395363954639556395663957639586395963960639616396263963639646396563966639676396863969639706397163972639736397463975639766397763978639796398063981639826398363984639856398663987639886398963990639916399263993639946399563996639976399863999640006400164002640036400464005640066400764008640096401064011640126401364014640156401664017640186401964020640216402264023640246402564026640276402864029640306403164032640336403464035640366403764038640396404064041640426404364044640456404664047640486404964050640516405264053640546405564056640576405864059640606406164062640636406464065640666406764068640696407064071640726407364074640756407664077640786407964080640816408264083640846408564086640876408864089640906409164092640936409464095640966409764098640996410064101641026410364104641056410664107641086410964110641116411264113641146411564116641176411864119641206412164122641236412464125641266412764128641296413064131641326413364134641356413664137641386413964140641416414264143641446414564146641476414864149641506415164152641536415464155641566415764158641596416064161641626416364164641656416664167641686416964170641716417264173641746417564176641776417864179641806418164182641836418464185641866418764188641896419064191641926419364194641956419664197641986419964200642016420264203642046420564206642076420864209642106421164212642136421464215642166421764218642196422064221642226422364224642256422664227642286422964230642316423264233642346423564236642376423864239642406424164242642436424464245642466424764248642496425064251642526425364254642556425664257642586425964260642616426264263642646426564266642676426864269642706427164272642736427464275642766427764278642796428064281642826428364284642856428664287642886428964290642916429264293642946429564296642976429864299643006430164302643036430464305643066430764308643096431064311643126431364314643156431664317643186431964320643216432264323643246432564326643276432864329643306433164332643336433464335643366433764338643396434064341643426434364344643456434664347643486434964350643516435264353643546435564356643576435864359643606436164362643636436464365643666436764368643696437064371643726437364374643756437664377643786437964380643816438264383643846438564386643876438864389643906439164392643936439464395643966439764398643996440064401644026440364404644056440664407644086440964410644116441264413644146441564416644176441864419644206442164422644236442464425644266442764428644296443064431644326443364434644356443664437644386443964440644416444264443644446444564446644476444864449644506445164452644536445464455644566445764458644596446064461644626446364464644656446664467644686446964470644716447264473644746447564476644776447864479644806448164482644836448464485644866448764488644896449064491644926449364494644956449664497644986449964500645016450264503645046450564506645076450864509645106451164512645136451464515645166451764518645196452064521645226452364524645256452664527645286452964530645316453264533645346453564536645376453864539645406454164542645436454464545645466454764548645496455064551645526455364554645556455664557645586455964560645616456264563645646456564566645676456864569645706457164572645736457464575645766457764578645796458064581645826458364584645856458664587645886458964590645916459264593645946459564596645976459864599646006460164602646036460464605646066460764608646096461064611646126461364614646156461664617646186461964620646216462264623646246462564626646276462864629646306463164632646336463464635646366463764638646396464064641646426464364644646456464664647646486464964650646516465264653646546465564656646576465864659646606466164662646636466464665646666466764668646696467064671646726467364674646756467664677646786467964680646816468264683646846468564686646876468864689646906469164692646936469464695646966469764698646996470064701647026470364704647056470664707647086470964710647116471264713647146471564716647176471864719647206472164722647236472464725647266472764728647296473064731647326473364734647356473664737647386473964740647416474264743647446474564746647476474864749647506475164752647536475464755647566475764758647596476064761647626476364764647656476664767647686476964770647716477264773647746477564776647776477864779647806478164782647836478464785647866478764788647896479064791647926479364794647956479664797647986479964800648016480264803648046480564806648076480864809648106481164812648136481464815648166481764818648196482064821648226482364824648256482664827648286482964830648316483264833648346483564836648376483864839648406484164842648436484464845648466484764848648496485064851648526485364854648556485664857648586485964860648616486264863648646486564866648676486864869648706487164872648736487464875648766487764878648796488064881648826488364884648856488664887648886488964890648916489264893648946489564896648976489864899649006490164902649036490464905649066490764908649096491064911649126491364914649156491664917649186491964920649216492264923649246492564926649276492864929649306493164932649336493464935649366493764938649396494064941649426494364944649456494664947649486494964950649516495264953649546495564956649576495864959649606496164962649636496464965649666496764968649696497064971649726497364974649756497664977649786497964980649816498264983649846498564986649876498864989649906499164992649936499464995649966499764998649996500065001650026500365004650056500665007650086500965010650116501265013650146501565016650176501865019650206502165022650236502465025650266502765028650296503065031650326503365034650356503665037650386503965040650416504265043650446504565046650476504865049650506505165052650536505465055650566505765058650596506065061650626506365064650656506665067650686506965070650716507265073650746507565076650776507865079650806508165082650836508465085650866508765088650896509065091650926509365094650956509665097650986509965100651016510265103651046510565106651076510865109651106511165112651136511465115651166511765118651196512065121651226512365124651256512665127651286512965130651316513265133651346513565136651376513865139651406514165142651436514465145651466514765148651496515065151651526515365154651556515665157651586515965160651616516265163651646516565166651676516865169651706517165172651736517465175651766517765178651796518065181651826518365184651856518665187651886518965190651916519265193651946519565196651976519865199652006520165202652036520465205652066520765208652096521065211652126521365214652156521665217652186521965220652216522265223652246522565226652276522865229652306523165232652336523465235652366523765238652396524065241652426524365244652456524665247652486524965250652516525265253652546525565256652576525865259652606526165262652636526465265652666526765268652696527065271652726527365274652756527665277652786527965280652816528265283652846528565286652876528865289652906529165292652936529465295652966529765298652996530065301653026530365304653056530665307653086530965310653116531265313653146531565316653176531865319653206532165322653236532465325653266532765328653296533065331653326533365334653356533665337653386533965340653416534265343653446534565346653476534865349653506535165352653536535465355653566535765358653596536065361653626536365364653656536665367653686536965370653716537265373653746537565376653776537865379653806538165382653836538465385653866538765388653896539065391653926539365394653956539665397653986539965400654016540265403654046540565406654076540865409654106541165412654136541465415654166541765418654196542065421654226542365424654256542665427654286542965430654316543265433654346543565436654376543865439654406544165442654436544465445654466544765448654496545065451654526545365454654556545665457654586545965460654616546265463654646546565466654676546865469654706547165472654736547465475654766547765478654796548065481654826548365484654856548665487654886548965490654916549265493654946549565496654976549865499655006550165502655036550465505655066550765508655096551065511655126551365514655156551665517655186551965520655216552265523655246552565526655276552865529655306553165532655336553465535655366553765538655396554065541655426554365544655456554665547655486554965550655516555265553655546555565556655576555865559655606556165562655636556465565655666556765568655696557065571655726557365574655756557665577655786557965580655816558265583655846558565586655876558865589655906559165592655936559465595655966559765598655996560065601656026560365604656056560665607656086560965610656116561265613656146561565616656176561865619656206562165622656236562465625656266562765628656296563065631656326563365634656356563665637656386563965640656416564265643656446564565646656476564865649656506565165652656536565465655656566565765658656596566065661656626566365664656656566665667656686566965670656716567265673656746567565676656776567865679656806568165682656836568465685656866568765688656896569065691656926569365694656956569665697656986569965700657016570265703657046570565706657076570865709657106571165712657136571465715657166571765718657196572065721657226572365724657256572665727657286572965730657316573265733657346573565736657376573865739657406574165742657436574465745657466574765748657496575065751657526575365754657556575665757657586575965760657616576265763657646576565766657676576865769657706577165772657736577465775657766577765778657796578065781657826578365784657856578665787657886578965790657916579265793657946579565796657976579865799658006580165802658036580465805658066580765808658096581065811658126581365814658156581665817658186581965820658216582265823658246582565826658276582865829658306583165832658336583465835658366583765838658396584065841658426584365844658456584665847658486584965850658516585265853658546585565856658576585865859658606586165862658636586465865658666586765868658696587065871658726587365874658756587665877658786587965880658816588265883658846588565886658876588865889658906589165892658936589465895658966589765898658996590065901659026590365904659056590665907659086590965910659116591265913659146591565916659176591865919659206592165922659236592465925659266592765928659296593065931659326593365934659356593665937659386593965940659416594265943659446594565946659476594865949659506595165952659536595465955659566595765958659596596065961659626596365964659656596665967659686596965970659716597265973659746597565976659776597865979659806598165982659836598465985659866598765988659896599065991659926599365994659956599665997659986599966000660016600266003660046600566006660076600866009660106601166012660136601466015660166601766018660196602066021660226602366024660256602666027660286602966030660316603266033660346603566036660376603866039660406604166042660436604466045660466604766048660496605066051660526605366054660556605666057660586605966060660616606266063660646606566066660676606866069660706607166072660736607466075660766607766078660796608066081660826608366084660856608666087660886608966090660916609266093660946609566096660976609866099661006610166102661036610466105661066610766108661096611066111661126611366114661156611666117661186611966120661216612266123661246612566126661276612866129661306613166132661336613466135661366613766138661396614066141661426614366144661456614666147661486614966150661516615266153661546615566156661576615866159661606616166162661636616466165661666616766168661696617066171661726617366174661756617666177661786617966180661816618266183661846618566186661876618866189661906619166192661936619466195661966619766198661996620066201662026620366204662056620666207662086620966210662116621266213662146621566216662176621866219662206622166222662236622466225662266622766228662296623066231662326623366234662356623666237662386623966240662416624266243662446624566246662476624866249662506625166252662536625466255662566625766258662596626066261662626626366264662656626666267662686626966270662716627266273662746627566276662776627866279662806628166282662836628466285662866628766288662896629066291662926629366294662956629666297662986629966300663016630266303663046630566306663076630866309663106631166312663136631466315663166631766318663196632066321663226632366324663256632666327663286632966330663316633266333663346633566336663376633866339663406634166342663436634466345663466634766348663496635066351663526635366354663556635666357663586635966360663616636266363663646636566366663676636866369663706637166372663736637466375663766637766378663796638066381663826638366384663856638666387663886638966390663916639266393663946639566396663976639866399664006640166402664036640466405664066640766408664096641066411664126641366414664156641666417664186641966420664216642266423664246642566426664276642866429664306643166432664336643466435664366643766438664396644066441664426644366444664456644666447664486644966450664516645266453664546645566456664576645866459664606646166462664636646466465664666646766468664696647066471664726647366474664756647666477664786647966480664816648266483664846648566486664876648866489664906649166492664936649466495664966649766498664996650066501665026650366504665056650666507665086650966510665116651266513665146651566516665176651866519665206652166522665236652466525665266652766528665296653066531665326653366534665356653666537665386653966540665416654266543665446654566546665476654866549665506655166552665536655466555665566655766558665596656066561665626656366564665656656666567665686656966570665716657266573665746657566576665776657866579665806658166582665836658466585665866658766588665896659066591665926659366594665956659666597665986659966600666016660266603666046660566606666076660866609666106661166612666136661466615666166661766618666196662066621666226662366624666256662666627666286662966630666316663266633666346663566636666376663866639666406664166642666436664466645666466664766648666496665066651666526665366654666556665666657666586665966660666616666266663666646666566666666676666866669666706667166672666736667466675666766667766678666796668066681666826668366684666856668666687666886668966690666916669266693666946669566696666976669866699667006670166702667036670466705667066670766708667096671066711667126671366714667156671666717667186671966720667216672266723667246672566726667276672866729667306673166732667336673466735667366673766738667396674066741667426674366744667456674666747667486674966750667516675266753667546675566756667576675866759667606676166762667636676466765667666676766768667696677066771667726677366774667756677666777667786677966780667816678266783667846678566786667876678866789667906679166792667936679466795667966679766798667996680066801668026680366804668056680666807668086680966810668116681266813668146681566816668176681866819668206682166822668236682466825668266682766828668296683066831668326683366834668356683666837668386683966840668416684266843668446684566846668476684866849668506685166852668536685466855668566685766858668596686066861668626686366864668656686666867668686686966870668716687266873668746687566876668776687866879668806688166882668836688466885668866688766888668896689066891668926689366894668956689666897668986689966900669016690266903669046690566906669076690866909669106691166912669136691466915669166691766918669196692066921669226692366924669256692666927669286692966930669316693266933669346693566936669376693866939669406694166942669436694466945669466694766948669496695066951669526695366954669556695666957669586695966960669616696266963669646696566966669676696866969669706697166972669736697466975669766697766978669796698066981669826698366984669856698666987669886698966990669916699266993669946699566996669976699866999670006700167002670036700467005670066700767008670096701067011670126701367014670156701667017670186701967020670216702267023670246702567026670276702867029670306703167032670336703467035670366703767038670396704067041670426704367044670456704667047670486704967050670516705267053670546705567056670576705867059670606706167062670636706467065670666706767068670696707067071670726707367074670756707667077670786707967080670816708267083670846708567086670876708867089670906709167092670936709467095670966709767098670996710067101671026710367104671056710667107671086710967110671116711267113671146711567116671176711867119671206712167122671236712467125671266712767128671296713067131671326713367134671356713667137671386713967140671416714267143671446714567146671476714867149671506715167152671536715467155671566715767158671596716067161671626716367164671656716667167671686716967170671716717267173671746717567176671776717867179671806718167182671836718467185671866718767188671896719067191671926719367194671956719667197671986719967200672016720267203672046720567206672076720867209672106721167212672136721467215672166721767218672196722067221672226722367224672256722667227672286722967230672316723267233672346723567236672376723867239672406724167242672436724467245672466724767248672496725067251672526725367254672556725667257672586725967260672616726267263672646726567266672676726867269672706727167272672736727467275672766727767278672796728067281672826728367284672856728667287672886728967290672916729267293672946729567296672976729867299673006730167302673036730467305673066730767308673096731067311673126731367314673156731667317673186731967320673216732267323673246732567326673276732867329673306733167332673336733467335673366733767338673396734067341673426734367344673456734667347673486734967350673516735267353673546735567356673576735867359673606736167362673636736467365673666736767368673696737067371673726737367374673756737667377673786737967380673816738267383673846738567386673876738867389673906739167392673936739467395673966739767398673996740067401674026740367404674056740667407674086740967410674116741267413674146741567416674176741867419674206742167422674236742467425674266742767428674296743067431674326743367434674356743667437674386743967440674416744267443674446744567446674476744867449674506745167452674536745467455674566745767458674596746067461674626746367464674656746667467674686746967470674716747267473674746747567476674776747867479674806748167482674836748467485674866748767488674896749067491674926749367494674956749667497674986749967500675016750267503675046750567506675076750867509675106751167512675136751467515675166751767518675196752067521675226752367524675256752667527675286752967530675316753267533675346753567536675376753867539675406754167542675436754467545675466754767548675496755067551675526755367554675556755667557675586755967560675616756267563675646756567566675676756867569675706757167572675736757467575675766757767578675796758067581675826758367584675856758667587675886758967590675916759267593675946759567596675976759867599676006760167602676036760467605676066760767608676096761067611676126761367614676156761667617676186761967620676216762267623676246762567626676276762867629676306763167632676336763467635676366763767638676396764067641676426764367644676456764667647676486764967650676516765267653676546765567656676576765867659676606766167662676636766467665676666766767668676696767067671676726767367674676756767667677676786767967680676816768267683676846768567686676876768867689676906769167692676936769467695676966769767698676996770067701677026770367704677056770667707677086770967710677116771267713677146771567716677176771867719677206772167722677236772467725677266772767728677296773067731677326773367734677356773667737677386773967740677416774267743677446774567746677476774867749677506775167752677536775467755677566775767758677596776067761677626776367764677656776667767677686776967770677716777267773677746777567776677776777867779677806778167782677836778467785677866778767788677896779067791677926779367794677956779667797677986779967800678016780267803678046780567806678076780867809678106781167812678136781467815678166781767818678196782067821678226782367824678256782667827678286782967830678316783267833678346783567836678376783867839678406784167842678436784467845678466784767848678496785067851678526785367854678556785667857678586785967860678616786267863678646786567866678676786867869678706787167872678736787467875678766787767878678796788067881678826788367884678856788667887678886788967890678916789267893678946789567896678976789867899679006790167902679036790467905679066790767908679096791067911679126791367914679156791667917679186791967920679216792267923679246792567926679276792867929679306793167932679336793467935679366793767938679396794067941679426794367944679456794667947679486794967950679516795267953679546795567956679576795867959679606796167962679636796467965679666796767968679696797067971679726797367974679756797667977679786797967980679816798267983679846798567986679876798867989679906799167992679936799467995679966799767998679996800068001680026800368004680056800668007680086800968010680116801268013680146801568016680176801868019680206802168022680236802468025680266802768028680296803068031680326803368034680356803668037680386803968040680416804268043680446804568046680476804868049680506805168052680536805468055680566805768058680596806068061680626806368064680656806668067680686806968070680716807268073680746807568076680776807868079680806808168082680836808468085680866808768088680896809068091680926809368094680956809668097680986809968100681016810268103681046810568106681076810868109681106811168112681136811468115681166811768118681196812068121681226812368124681256812668127681286812968130681316813268133681346813568136681376813868139681406814168142681436814468145681466814768148681496815068151681526815368154681556815668157681586815968160681616816268163681646816568166681676816868169681706817168172681736817468175681766817768178681796818068181681826818368184681856818668187681886818968190681916819268193681946819568196681976819868199682006820168202682036820468205682066820768208682096821068211682126821368214682156821668217682186821968220682216822268223682246822568226682276822868229682306823168232682336823468235682366823768238682396824068241682426824368244682456824668247682486824968250682516825268253682546825568256682576825868259682606826168262682636826468265682666826768268682696827068271682726827368274682756827668277682786827968280682816828268283682846828568286682876828868289682906829168292682936829468295682966829768298682996830068301683026830368304683056830668307683086830968310683116831268313683146831568316683176831868319683206832168322683236832468325683266832768328683296833068331683326833368334683356833668337683386833968340683416834268343683446834568346683476834868349683506835168352683536835468355683566835768358683596836068361683626836368364683656836668367683686836968370683716837268373683746837568376683776837868379683806838168382683836838468385683866838768388683896839068391683926839368394683956839668397683986839968400684016840268403684046840568406684076840868409684106841168412684136841468415684166841768418684196842068421684226842368424684256842668427684286842968430684316843268433684346843568436684376843868439684406844168442684436844468445684466844768448684496845068451684526845368454684556845668457684586845968460684616846268463684646846568466684676846868469684706847168472684736847468475684766847768478684796848068481684826848368484684856848668487684886848968490684916849268493684946849568496684976849868499685006850168502685036850468505685066850768508685096851068511685126851368514685156851668517685186851968520685216852268523685246852568526685276852868529685306853168532685336853468535685366853768538685396854068541685426854368544685456854668547685486854968550685516855268553685546855568556685576855868559685606856168562685636856468565685666856768568685696857068571685726857368574685756857668577685786857968580685816858268583685846858568586685876858868589685906859168592685936859468595685966859768598685996860068601686026860368604686056860668607686086860968610686116861268613686146861568616686176861868619686206862168622686236862468625686266862768628686296863068631686326863368634686356863668637686386863968640686416864268643686446864568646686476864868649686506865168652686536865468655686566865768658686596866068661686626866368664686656866668667686686866968670686716867268673686746867568676686776867868679686806868168682686836868468685686866868768688686896869068691686926869368694686956869668697686986869968700687016870268703687046870568706687076870868709687106871168712687136871468715687166871768718687196872068721687226872368724687256872668727687286872968730687316873268733687346873568736687376873868739687406874168742687436874468745687466874768748687496875068751687526875368754687556875668757687586875968760687616876268763687646876568766687676876868769687706877168772687736877468775687766877768778687796878068781687826878368784687856878668787687886878968790687916879268793687946879568796687976879868799688006880168802688036880468805688066880768808688096881068811688126881368814688156881668817688186881968820688216882268823688246882568826688276882868829688306883168832688336883468835688366883768838688396884068841688426884368844688456884668847688486884968850688516885268853688546885568856688576885868859688606886168862688636886468865688666886768868688696887068871688726887368874688756887668877688786887968880688816888268883688846888568886688876888868889688906889168892688936889468895688966889768898688996890068901689026890368904689056890668907689086890968910689116891268913689146891568916689176891868919689206892168922689236892468925689266892768928689296893068931689326893368934689356893668937689386893968940689416894268943689446894568946689476894868949689506895168952689536895468955689566895768958689596896068961689626896368964689656896668967689686896968970689716897268973689746897568976689776897868979689806898168982689836898468985689866898768988689896899068991689926899368994689956899668997689986899969000690016900269003690046900569006690076900869009690106901169012690136901469015690166901769018690196902069021690226902369024690256902669027690286902969030690316903269033690346903569036690376903869039690406904169042690436904469045690466904769048690496905069051690526905369054690556905669057690586905969060690616906269063690646906569066690676906869069690706907169072690736907469075690766907769078690796908069081690826908369084690856908669087690886908969090690916909269093690946909569096690976909869099691006910169102691036910469105691066910769108691096911069111691126911369114691156911669117691186911969120691216912269123691246912569126691276912869129691306913169132691336913469135691366913769138691396914069141691426914369144691456914669147691486914969150691516915269153691546915569156691576915869159691606916169162691636916469165691666916769168691696917069171691726917369174691756917669177691786917969180691816918269183691846918569186691876918869189691906919169192691936919469195691966919769198691996920069201692026920369204692056920669207692086920969210692116921269213692146921569216692176921869219692206922169222692236922469225692266922769228692296923069231692326923369234692356923669237692386923969240692416924269243692446924569246692476924869249692506925169252692536925469255692566925769258692596926069261692626926369264692656926669267692686926969270692716927269273692746927569276692776927869279692806928169282692836928469285692866928769288692896929069291692926929369294692956929669297692986929969300693016930269303693046930569306693076930869309693106931169312693136931469315693166931769318693196932069321693226932369324693256932669327693286932969330693316933269333693346933569336693376933869339693406934169342693436934469345693466934769348693496935069351693526935369354693556935669357693586935969360693616936269363693646936569366693676936869369693706937169372693736937469375693766937769378693796938069381693826938369384693856938669387693886938969390693916939269393693946939569396693976939869399694006940169402694036940469405694066940769408694096941069411694126941369414694156941669417694186941969420694216942269423694246942569426694276942869429694306943169432694336943469435694366943769438694396944069441694426944369444694456944669447694486944969450694516945269453694546945569456694576945869459694606946169462694636946469465694666946769468694696947069471694726947369474694756947669477694786947969480694816948269483694846948569486694876948869489694906949169492694936949469495694966949769498694996950069501695026950369504695056950669507695086950969510695116951269513695146951569516695176951869519695206952169522695236952469525695266952769528695296953069531695326953369534695356953669537695386953969540695416954269543695446954569546695476954869549695506955169552695536955469555695566955769558695596956069561695626956369564695656956669567695686956969570695716957269573695746957569576695776957869579695806958169582695836958469585695866958769588695896959069591695926959369594695956959669597695986959969600696016960269603696046960569606696076960869609696106961169612696136961469615696166961769618696196962069621696226962369624696256962669627696286962969630696316963269633696346963569636696376963869639696406964169642696436964469645696466964769648696496965069651696526965369654696556965669657696586965969660696616966269663696646966569666696676966869669696706967169672696736967469675696766967769678696796968069681696826968369684696856968669687696886968969690696916969269693696946969569696696976969869699697006970169702697036970469705697066970769708697096971069711697126971369714697156971669717697186971969720697216972269723697246972569726697276972869729697306973169732697336973469735697366973769738697396974069741697426974369744697456974669747697486974969750697516975269753697546975569756697576975869759697606976169762697636976469765697666976769768697696977069771697726977369774697756977669777697786977969780697816978269783697846978569786697876978869789697906979169792697936979469795697966979769798697996980069801698026980369804698056980669807698086980969810698116981269813698146981569816698176981869819698206982169822698236982469825698266982769828698296983069831698326983369834698356983669837698386983969840698416984269843698446984569846698476984869849698506985169852698536985469855698566985769858698596986069861698626986369864698656986669867698686986969870698716987269873698746987569876698776987869879698806988169882698836988469885698866988769888698896989069891698926989369894698956989669897698986989969900699016990269903699046990569906699076990869909699106991169912699136991469915699166991769918699196992069921699226992369924699256992669927699286992969930699316993269933699346993569936699376993869939699406994169942699436994469945699466994769948699496995069951699526995369954699556995669957699586995969960699616996269963699646996569966699676996869969699706997169972699736997469975699766997769978699796998069981699826998369984699856998669987699886998969990699916999269993699946999569996699976999869999700007000170002700037000470005700067000770008700097001070011700127001370014700157001670017700187001970020700217002270023700247002570026700277002870029700307003170032700337003470035700367003770038700397004070041700427004370044700457004670047700487004970050700517005270053700547005570056700577005870059700607006170062700637006470065700667006770068700697007070071700727007370074700757007670077700787007970080700817008270083700847008570086700877008870089700907009170092700937009470095700967009770098700997010070101701027010370104701057010670107701087010970110701117011270113701147011570116701177011870119701207012170122701237012470125701267012770128701297013070131701327013370134701357013670137701387013970140701417014270143701447014570146701477014870149701507015170152701537015470155701567015770158701597016070161701627016370164701657016670167701687016970170701717017270173701747017570176701777017870179701807018170182701837018470185701867018770188701897019070191701927019370194701957019670197701987019970200702017020270203702047020570206702077020870209702107021170212702137021470215702167021770218702197022070221702227022370224702257022670227702287022970230702317023270233702347023570236702377023870239702407024170242702437024470245702467024770248702497025070251702527025370254702557025670257702587025970260702617026270263702647026570266702677026870269702707027170272702737027470275702767027770278702797028070281702827028370284702857028670287702887028970290702917029270293702947029570296702977029870299703007030170302703037030470305703067030770308703097031070311703127031370314703157031670317703187031970320703217032270323703247032570326703277032870329703307033170332703337033470335703367033770338703397034070341703427034370344703457034670347703487034970350703517035270353703547035570356703577035870359703607036170362703637036470365703667036770368703697037070371703727037370374703757037670377703787037970380703817038270383703847038570386703877038870389703907039170392703937039470395703967039770398703997040070401704027040370404704057040670407704087040970410704117041270413704147041570416704177041870419704207042170422704237042470425704267042770428704297043070431704327043370434704357043670437704387043970440704417044270443704447044570446704477044870449704507045170452704537045470455704567045770458704597046070461704627046370464704657046670467704687046970470704717047270473704747047570476704777047870479704807048170482704837048470485704867048770488704897049070491704927049370494704957049670497704987049970500705017050270503705047050570506705077050870509705107051170512705137051470515705167051770518705197052070521705227052370524705257052670527705287052970530705317053270533705347053570536705377053870539705407054170542705437054470545705467054770548705497055070551705527055370554705557055670557705587055970560705617056270563705647056570566705677056870569705707057170572705737057470575705767057770578705797058070581705827058370584705857058670587705887058970590705917059270593705947059570596705977059870599706007060170602706037060470605706067060770608706097061070611706127061370614706157061670617706187061970620706217062270623706247062570626706277062870629706307063170632706337063470635706367063770638706397064070641706427064370644706457064670647706487064970650706517065270653706547065570656706577065870659706607066170662706637066470665706667066770668706697067070671706727067370674706757067670677706787067970680706817068270683706847068570686706877068870689706907069170692706937069470695706967069770698706997070070701707027070370704707057070670707707087070970710707117071270713707147071570716707177071870719707207072170722707237072470725707267072770728707297073070731707327073370734707357073670737707387073970740707417074270743707447074570746707477074870749707507075170752707537075470755707567075770758707597076070761707627076370764707657076670767707687076970770707717077270773707747077570776707777077870779707807078170782707837078470785707867078770788707897079070791707927079370794707957079670797707987079970800708017080270803708047080570806708077080870809708107081170812708137081470815708167081770818708197082070821708227082370824708257082670827708287082970830708317083270833708347083570836708377083870839708407084170842708437084470845708467084770848708497085070851708527085370854708557085670857708587085970860708617086270863708647086570866708677086870869708707087170872708737087470875708767087770878708797088070881708827088370884708857088670887708887088970890708917089270893708947089570896708977089870899709007090170902709037090470905709067090770908709097091070911709127091370914709157091670917709187091970920709217092270923709247092570926709277092870929709307093170932709337093470935709367093770938709397094070941709427094370944709457094670947709487094970950709517095270953709547095570956709577095870959709607096170962709637096470965709667096770968709697097070971709727097370974709757097670977709787097970980709817098270983709847098570986709877098870989709907099170992709937099470995709967099770998709997100071001710027100371004710057100671007710087100971010710117101271013710147101571016710177101871019710207102171022710237102471025710267102771028710297103071031710327103371034710357103671037710387103971040710417104271043710447104571046710477104871049710507105171052710537105471055710567105771058710597106071061710627106371064710657106671067710687106971070710717107271073710747107571076710777107871079710807108171082710837108471085710867108771088710897109071091710927109371094710957109671097710987109971100711017110271103711047110571106711077110871109711107111171112711137111471115711167111771118711197112071121711227112371124711257112671127711287112971130711317113271133711347113571136711377113871139711407114171142711437114471145711467114771148711497115071151711527115371154711557115671157711587115971160711617116271163711647116571166711677116871169711707117171172711737117471175711767117771178711797118071181711827118371184711857118671187711887118971190711917119271193711947119571196711977119871199712007120171202712037120471205712067120771208712097121071211712127121371214712157121671217712187121971220712217122271223712247122571226712277122871229712307123171232712337123471235712367123771238712397124071241712427124371244712457124671247712487124971250712517125271253712547125571256712577125871259712607126171262712637126471265712667126771268712697127071271712727127371274712757127671277712787127971280712817128271283712847128571286712877128871289712907129171292712937129471295712967129771298712997130071301713027130371304713057130671307713087130971310713117131271313713147131571316713177131871319713207132171322713237132471325713267132771328713297133071331713327133371334713357133671337713387133971340713417134271343713447134571346713477134871349713507135171352713537135471355713567135771358713597136071361713627136371364713657136671367713687136971370713717137271373713747137571376713777137871379713807138171382713837138471385713867138771388713897139071391713927139371394713957139671397713987139971400714017140271403714047140571406714077140871409714107141171412714137141471415714167141771418714197142071421714227142371424714257142671427714287142971430714317143271433714347143571436714377143871439714407144171442714437144471445714467144771448714497145071451714527145371454714557145671457714587145971460714617146271463714647146571466714677146871469714707147171472714737147471475714767147771478714797148071481714827148371484714857148671487714887148971490714917149271493714947149571496714977149871499715007150171502715037150471505715067150771508715097151071511715127151371514715157151671517715187151971520715217152271523715247152571526715277152871529715307153171532715337153471535715367153771538715397154071541715427154371544715457154671547715487154971550715517155271553715547155571556715577155871559715607156171562715637156471565715667156771568715697157071571715727157371574715757157671577715787157971580715817158271583715847158571586715877158871589715907159171592715937159471595715967159771598715997160071601716027160371604716057160671607716087160971610716117161271613716147161571616716177161871619716207162171622716237162471625716267162771628716297163071631716327163371634716357163671637716387163971640716417164271643716447164571646716477164871649716507165171652716537165471655716567165771658716597166071661716627166371664716657166671667716687166971670716717167271673716747167571676716777167871679716807168171682716837168471685716867168771688716897169071691716927169371694716957169671697716987169971700717017170271703717047170571706717077170871709717107171171712717137171471715717167171771718717197172071721717227172371724717257172671727717287172971730717317173271733717347173571736717377173871739717407174171742717437174471745717467174771748717497175071751717527175371754717557175671757717587175971760717617176271763717647176571766717677176871769717707177171772717737177471775717767177771778717797178071781717827178371784717857178671787717887178971790717917179271793717947179571796717977179871799718007180171802718037180471805718067180771808718097181071811718127181371814718157181671817718187181971820718217182271823718247182571826718277182871829718307183171832718337183471835718367183771838718397184071841718427184371844718457184671847718487184971850718517185271853718547185571856718577185871859718607186171862718637186471865718667186771868718697187071871718727187371874718757187671877718787187971880718817188271883718847188571886718877188871889718907189171892718937189471895718967189771898718997190071901719027190371904719057190671907719087190971910719117191271913719147191571916719177191871919719207192171922719237192471925719267192771928719297193071931719327193371934719357193671937719387193971940719417194271943719447194571946719477194871949719507195171952719537195471955719567195771958719597196071961719627196371964719657196671967719687196971970719717197271973719747197571976719777197871979719807198171982719837198471985719867198771988719897199071991719927199371994719957199671997719987199972000720017200272003720047200572006720077200872009720107201172012720137201472015720167201772018720197202072021720227202372024720257202672027720287202972030720317203272033720347203572036720377203872039720407204172042720437204472045720467204772048720497205072051720527205372054720557205672057720587205972060720617206272063720647206572066720677206872069720707207172072720737207472075720767207772078720797208072081720827208372084720857208672087720887208972090720917209272093720947209572096720977209872099721007210172102721037210472105721067210772108721097211072111721127211372114721157211672117721187211972120721217212272123721247212572126721277212872129721307213172132721337213472135721367213772138721397214072141721427214372144721457214672147721487214972150721517215272153721547215572156721577215872159721607216172162721637216472165721667216772168721697217072171721727217372174721757217672177721787217972180721817218272183721847218572186721877218872189721907219172192721937219472195721967219772198721997220072201722027220372204722057220672207722087220972210722117221272213722147221572216722177221872219722207222172222722237222472225722267222772228722297223072231722327223372234722357223672237722387223972240722417224272243722447224572246722477224872249722507225172252722537225472255722567225772258722597226072261722627226372264722657226672267722687226972270722717227272273722747227572276722777227872279722807228172282722837228472285722867228772288722897229072291722927229372294722957229672297722987229972300723017230272303723047230572306723077230872309723107231172312723137231472315723167231772318723197232072321723227232372324723257232672327723287232972330723317233272333723347233572336723377233872339723407234172342723437234472345723467234772348723497235072351723527235372354723557235672357723587235972360723617236272363723647236572366723677236872369723707237172372723737237472375723767237772378723797238072381723827238372384723857238672387723887238972390723917239272393723947239572396723977239872399724007240172402724037240472405724067240772408724097241072411724127241372414724157241672417724187241972420724217242272423724247242572426724277242872429724307243172432724337243472435724367243772438724397244072441724427244372444724457244672447724487244972450724517245272453724547245572456724577245872459724607246172462724637246472465724667246772468724697247072471724727247372474724757247672477724787247972480724817248272483724847248572486724877248872489724907249172492724937249472495724967249772498724997250072501725027250372504725057250672507725087250972510725117251272513725147251572516725177251872519725207252172522725237252472525725267252772528725297253072531725327253372534725357253672537725387253972540725417254272543725447254572546725477254872549725507255172552725537255472555725567255772558725597256072561725627256372564725657256672567725687256972570725717257272573725747257572576725777257872579725807258172582725837258472585725867258772588725897259072591725927259372594725957259672597725987259972600726017260272603726047260572606726077260872609726107261172612726137261472615726167261772618726197262072621726227262372624726257262672627726287262972630726317263272633726347263572636726377263872639726407264172642726437264472645726467264772648726497265072651726527265372654726557265672657726587265972660726617266272663726647266572666726677266872669726707267172672726737267472675726767267772678726797268072681726827268372684726857268672687726887268972690726917269272693726947269572696726977269872699727007270172702727037270472705727067270772708727097271072711727127271372714727157271672717727187271972720727217272272723727247272572726727277272872729727307273172732727337273472735727367273772738727397274072741727427274372744727457274672747727487274972750727517275272753727547275572756727577275872759727607276172762727637276472765727667276772768727697277072771727727277372774727757277672777727787277972780727817278272783727847278572786727877278872789727907279172792727937279472795727967279772798727997280072801728027280372804728057280672807728087280972810728117281272813728147281572816728177281872819728207282172822728237282472825728267282772828728297283072831728327283372834728357283672837728387283972840728417284272843728447284572846728477284872849728507285172852728537285472855728567285772858728597286072861728627286372864728657286672867728687286972870728717287272873728747287572876728777287872879728807288172882728837288472885728867288772888728897289072891728927289372894728957289672897728987289972900729017290272903729047290572906729077290872909729107291172912729137291472915729167291772918729197292072921729227292372924729257292672927729287292972930729317293272933729347293572936729377293872939729407294172942729437294472945729467294772948729497295072951729527295372954729557295672957729587295972960729617296272963729647296572966729677296872969729707297172972729737297472975729767297772978729797298072981729827298372984729857298672987729887298972990729917299272993729947299572996729977299872999730007300173002730037300473005730067300773008730097301073011730127301373014730157301673017730187301973020730217302273023730247302573026730277302873029730307303173032730337303473035730367303773038730397304073041730427304373044730457304673047730487304973050730517305273053730547305573056730577305873059730607306173062730637306473065730667306773068730697307073071730727307373074730757307673077730787307973080730817308273083730847308573086730877308873089730907309173092730937309473095730967309773098730997310073101731027310373104731057310673107731087310973110731117311273113731147311573116731177311873119731207312173122731237312473125731267312773128731297313073131731327313373134731357313673137731387313973140731417314273143731447314573146731477314873149731507315173152731537315473155731567315773158731597316073161731627316373164731657316673167731687316973170731717317273173731747317573176731777317873179731807318173182731837318473185731867318773188731897319073191731927319373194731957319673197731987319973200732017320273203732047320573206732077320873209732107321173212732137321473215732167321773218732197322073221732227322373224732257322673227732287322973230732317323273233732347323573236732377323873239732407324173242732437324473245732467324773248732497325073251732527325373254732557325673257732587325973260732617326273263732647326573266732677326873269732707327173272732737327473275732767327773278732797328073281732827328373284732857328673287732887328973290732917329273293732947329573296732977329873299733007330173302733037330473305733067330773308733097331073311733127331373314733157331673317733187331973320733217332273323733247332573326733277332873329733307333173332733337333473335733367333773338733397334073341733427334373344733457334673347733487334973350733517335273353733547335573356733577335873359733607336173362733637336473365733667336773368733697337073371733727337373374733757337673377733787337973380733817338273383733847338573386733877338873389733907339173392733937339473395733967339773398733997340073401734027340373404734057340673407734087340973410734117341273413734147341573416734177341873419734207342173422734237342473425734267342773428734297343073431734327343373434734357343673437734387343973440734417344273443734447344573446734477344873449734507345173452734537345473455734567345773458734597346073461734627346373464734657346673467734687346973470734717347273473734747347573476734777347873479734807348173482734837348473485734867348773488734897349073491734927349373494734957349673497734987349973500735017350273503735047350573506735077350873509735107351173512735137351473515735167351773518735197352073521735227352373524735257352673527735287352973530735317353273533735347353573536735377353873539735407354173542735437354473545735467354773548735497355073551735527355373554735557355673557735587355973560735617356273563735647356573566735677356873569735707357173572735737357473575735767357773578735797358073581735827358373584735857358673587735887358973590735917359273593735947359573596735977359873599736007360173602736037360473605736067360773608736097361073611736127361373614736157361673617736187361973620736217362273623736247362573626736277362873629736307363173632736337363473635736367363773638736397364073641736427364373644736457364673647736487364973650736517365273653736547365573656736577365873659736607366173662736637366473665736667366773668736697367073671736727367373674736757367673677736787367973680736817368273683736847368573686736877368873689736907369173692736937369473695736967369773698736997370073701737027370373704737057370673707737087370973710737117371273713737147371573716737177371873719737207372173722737237372473725737267372773728737297373073731737327373373734737357373673737737387373973740737417374273743737447374573746737477374873749737507375173752737537375473755737567375773758737597376073761737627376373764737657376673767737687376973770737717377273773737747377573776737777377873779737807378173782737837378473785737867378773788737897379073791737927379373794737957379673797737987379973800738017380273803738047380573806738077380873809738107381173812738137381473815738167381773818738197382073821738227382373824738257382673827738287382973830738317383273833738347383573836738377383873839738407384173842738437384473845738467384773848738497385073851738527385373854738557385673857738587385973860738617386273863738647386573866738677386873869738707387173872738737387473875738767387773878738797388073881738827388373884738857388673887738887388973890738917389273893738947389573896738977389873899739007390173902739037390473905739067390773908739097391073911739127391373914739157391673917739187391973920739217392273923739247392573926739277392873929739307393173932739337393473935739367393773938739397394073941739427394373944739457394673947739487394973950739517395273953739547395573956739577395873959739607396173962739637396473965739667396773968739697397073971739727397373974739757397673977739787397973980739817398273983739847398573986739877398873989739907399173992739937399473995739967399773998739997400074001740027400374004740057400674007740087400974010740117401274013740147401574016740177401874019740207402174022740237402474025740267402774028740297403074031740327403374034740357403674037740387403974040740417404274043740447404574046740477404874049740507405174052740537405474055740567405774058740597406074061740627406374064740657406674067740687406974070740717407274073740747407574076740777407874079740807408174082740837408474085740867408774088740897409074091740927409374094740957409674097740987409974100741017410274103741047410574106741077410874109741107411174112741137411474115741167411774118741197412074121741227412374124741257412674127741287412974130741317413274133741347413574136741377413874139741407414174142741437414474145741467414774148741497415074151741527415374154741557415674157741587415974160741617416274163741647416574166741677416874169741707417174172741737417474175741767417774178741797418074181741827418374184741857418674187741887418974190741917419274193741947419574196741977419874199742007420174202742037420474205742067420774208742097421074211742127421374214742157421674217742187421974220742217422274223742247422574226742277422874229742307423174232742337423474235742367423774238742397424074241742427424374244742457424674247742487424974250742517425274253742547425574256742577425874259742607426174262742637426474265742667426774268742697427074271742727427374274742757427674277742787427974280742817428274283742847428574286742877428874289742907429174292742937429474295742967429774298742997430074301743027430374304743057430674307743087430974310743117431274313743147431574316743177431874319743207432174322743237432474325743267432774328743297433074331743327433374334743357433674337743387433974340743417434274343743447434574346743477434874349743507435174352743537435474355743567435774358743597436074361743627436374364743657436674367743687436974370743717437274373743747437574376743777437874379743807438174382743837438474385743867438774388743897439074391743927439374394743957439674397743987439974400744017440274403744047440574406744077440874409744107441174412744137441474415744167441774418744197442074421744227442374424744257442674427744287442974430744317443274433744347443574436744377443874439744407444174442744437444474445744467444774448744497445074451744527445374454744557445674457744587445974460744617446274463744647446574466744677446874469744707447174472744737447474475744767447774478744797448074481744827448374484744857448674487744887448974490744917449274493744947449574496744977449874499745007450174502745037450474505745067450774508745097451074511745127451374514745157451674517745187451974520745217452274523745247452574526745277452874529745307453174532745337453474535745367453774538745397454074541745427454374544745457454674547745487454974550745517455274553745547455574556745577455874559745607456174562745637456474565745667456774568745697457074571745727457374574745757457674577745787457974580745817458274583745847458574586745877458874589745907459174592745937459474595745967459774598745997460074601746027460374604746057460674607746087460974610746117461274613746147461574616746177461874619746207462174622746237462474625746267462774628746297463074631746327463374634746357463674637746387463974640746417464274643746447464574646746477464874649746507465174652746537465474655746567465774658746597466074661746627466374664746657466674667746687466974670746717467274673746747467574676746777467874679746807468174682746837468474685746867468774688746897469074691746927469374694746957469674697746987469974700747017470274703747047470574706747077470874709747107471174712747137471474715747167471774718747197472074721747227472374724747257472674727747287472974730747317473274733747347473574736747377473874739747407474174742747437474474745747467474774748747497475074751747527475374754747557475674757747587475974760747617476274763747647476574766747677476874769747707477174772747737477474775747767477774778747797478074781747827478374784747857478674787747887478974790747917479274793747947479574796747977479874799748007480174802748037480474805748067480774808748097481074811748127481374814748157481674817748187481974820748217482274823748247482574826748277482874829748307483174832748337483474835748367483774838748397484074841748427484374844748457484674847748487484974850748517485274853748547485574856748577485874859748607486174862748637486474865748667486774868748697487074871748727487374874748757487674877748787487974880748817488274883748847488574886748877488874889748907489174892748937489474895748967489774898748997490074901749027490374904749057490674907749087490974910749117491274913749147491574916749177491874919749207492174922749237492474925749267492774928749297493074931749327493374934749357493674937749387493974940749417494274943749447494574946749477494874949749507495174952749537495474955749567495774958749597496074961749627496374964749657496674967749687496974970749717497274973749747497574976749777497874979749807498174982749837498474985749867498774988749897499074991749927499374994749957499674997749987499975000750017500275003750047500575006750077500875009750107501175012750137501475015750167501775018750197502075021750227502375024750257502675027750287502975030750317503275033750347503575036750377503875039750407504175042750437504475045750467504775048750497505075051750527505375054750557505675057750587505975060750617506275063750647506575066750677506875069750707507175072750737507475075750767507775078750797508075081750827508375084750857508675087750887508975090750917509275093750947509575096750977509875099751007510175102751037510475105751067510775108751097511075111751127511375114751157511675117751187511975120751217512275123751247512575126751277512875129751307513175132751337513475135751367513775138751397514075141751427514375144751457514675147751487514975150751517515275153751547515575156751577515875159751607516175162751637516475165751667516775168751697517075171751727517375174751757517675177751787517975180751817518275183751847518575186751877518875189751907519175192751937519475195751967519775198751997520075201752027520375204752057520675207752087520975210752117521275213752147521575216752177521875219752207522175222752237522475225752267522775228752297523075231752327523375234752357523675237752387523975240752417524275243752447524575246752477524875249752507525175252752537525475255752567525775258752597526075261752627526375264752657526675267752687526975270752717527275273752747527575276752777527875279752807528175282752837528475285752867528775288752897529075291752927529375294752957529675297752987529975300753017530275303753047530575306753077530875309753107531175312753137531475315753167531775318753197532075321753227532375324753257532675327753287532975330753317533275333753347533575336753377533875339753407534175342753437534475345753467534775348753497535075351753527535375354753557535675357753587535975360753617536275363753647536575366753677536875369753707537175372753737537475375753767537775378753797538075381753827538375384753857538675387753887538975390753917539275393753947539575396753977539875399754007540175402754037540475405754067540775408754097541075411754127541375414754157541675417754187541975420754217542275423754247542575426754277542875429754307543175432754337543475435754367543775438754397544075441754427544375444754457544675447754487544975450754517545275453754547545575456754577545875459754607546175462754637546475465754667546775468754697547075471754727547375474754757547675477754787547975480754817548275483754847548575486754877548875489754907549175492754937549475495754967549775498754997550075501755027550375504755057550675507755087550975510755117551275513755147551575516755177551875519755207552175522755237552475525755267552775528755297553075531755327553375534755357553675537755387553975540755417554275543755447554575546755477554875549755507555175552755537555475555755567555775558755597556075561755627556375564755657556675567755687556975570755717557275573755747557575576755777557875579755807558175582755837558475585755867558775588755897559075591755927559375594755957559675597755987559975600756017560275603756047560575606756077560875609756107561175612756137561475615756167561775618756197562075621756227562375624756257562675627756287562975630756317563275633756347563575636756377563875639756407564175642756437564475645756467564775648756497565075651756527565375654756557565675657756587565975660756617566275663756647566575666756677566875669756707567175672756737567475675756767567775678756797568075681756827568375684756857568675687756887568975690756917569275693756947569575696756977569875699757007570175702757037570475705757067570775708757097571075711757127571375714757157571675717757187571975720757217572275723757247572575726757277572875729757307573175732757337573475735757367573775738757397574075741757427574375744757457574675747757487574975750757517575275753757547575575756757577575875759757607576175762757637576475765757667576775768757697577075771757727577375774757757577675777757787577975780757817578275783757847578575786757877578875789757907579175792757937579475795757967579775798757997580075801758027580375804758057580675807758087580975810758117581275813758147581575816758177581875819758207582175822758237582475825758267582775828758297583075831758327583375834758357583675837758387583975840758417584275843758447584575846758477584875849758507585175852758537585475855758567585775858758597586075861758627586375864758657586675867758687586975870758717587275873758747587575876758777587875879758807588175882758837588475885758867588775888758897589075891758927589375894758957589675897758987589975900759017590275903759047590575906759077590875909759107591175912759137591475915759167591775918759197592075921759227592375924759257592675927759287592975930759317593275933759347593575936759377593875939759407594175942759437594475945759467594775948759497595075951759527595375954759557595675957759587595975960759617596275963759647596575966759677596875969759707597175972759737597475975759767597775978759797598075981759827598375984759857598675987759887598975990759917599275993759947599575996759977599875999760007600176002760037600476005760067600776008760097601076011760127601376014760157601676017760187601976020760217602276023760247602576026760277602876029760307603176032760337603476035760367603776038760397604076041760427604376044760457604676047760487604976050760517605276053760547605576056760577605876059760607606176062760637606476065760667606776068760697607076071760727607376074760757607676077760787607976080760817608276083760847608576086760877608876089760907609176092760937609476095760967609776098760997610076101761027610376104761057610676107761087610976110761117611276113761147611576116761177611876119761207612176122761237612476125761267612776128761297613076131761327613376134761357613676137761387613976140761417614276143761447614576146761477614876149761507615176152761537615476155761567615776158761597616076161761627616376164761657616676167761687616976170761717617276173761747617576176761777617876179761807618176182761837618476185761867618776188761897619076191761927619376194761957619676197761987619976200762017620276203762047620576206762077620876209762107621176212762137621476215762167621776218762197622076221762227622376224762257622676227762287622976230762317623276233762347623576236762377623876239762407624176242762437624476245762467624776248762497625076251762527625376254762557625676257762587625976260762617626276263762647626576266762677626876269762707627176272762737627476275762767627776278762797628076281762827628376284762857628676287762887628976290762917629276293762947629576296762977629876299763007630176302763037630476305763067630776308763097631076311763127631376314763157631676317763187631976320763217632276323763247632576326763277632876329763307633176332763337633476335763367633776338763397634076341763427634376344763457634676347763487634976350763517635276353763547635576356763577635876359763607636176362763637636476365763667636776368763697637076371763727637376374763757637676377763787637976380763817638276383763847638576386763877638876389763907639176392763937639476395763967639776398763997640076401764027640376404764057640676407764087640976410764117641276413764147641576416764177641876419764207642176422764237642476425764267642776428764297643076431764327643376434764357643676437764387643976440764417644276443764447644576446764477644876449764507645176452764537645476455764567645776458764597646076461764627646376464764657646676467764687646976470764717647276473764747647576476764777647876479764807648176482764837648476485764867648776488764897649076491764927649376494764957649676497764987649976500765017650276503765047650576506765077650876509765107651176512765137651476515765167651776518765197652076521765227652376524765257652676527765287652976530765317653276533765347653576536765377653876539765407654176542765437654476545765467654776548765497655076551765527655376554765557655676557765587655976560765617656276563765647656576566765677656876569765707657176572765737657476575765767657776578765797658076581765827658376584765857658676587765887658976590765917659276593765947659576596765977659876599766007660176602766037660476605766067660776608766097661076611766127661376614766157661676617766187661976620766217662276623766247662576626766277662876629766307663176632766337663476635766367663776638766397664076641766427664376644766457664676647766487664976650766517665276653766547665576656766577665876659766607666176662766637666476665766667666776668766697667076671766727667376674766757667676677766787667976680766817668276683766847668576686766877668876689766907669176692766937669476695766967669776698766997670076701767027670376704767057670676707767087670976710767117671276713767147671576716767177671876719767207672176722767237672476725767267672776728767297673076731767327673376734767357673676737767387673976740767417674276743767447674576746767477674876749767507675176752767537675476755767567675776758767597676076761767627676376764767657676676767767687676976770767717677276773767747677576776767777677876779767807678176782767837678476785767867678776788767897679076791767927679376794767957679676797767987679976800768017680276803768047680576806768077680876809768107681176812768137681476815768167681776818768197682076821768227682376824768257682676827768287682976830768317683276833768347683576836768377683876839768407684176842768437684476845768467684776848768497685076851768527685376854768557685676857768587685976860768617686276863768647686576866768677686876869768707687176872768737687476875768767687776878768797688076881768827688376884768857688676887768887688976890768917689276893768947689576896768977689876899769007690176902769037690476905769067690776908769097691076911769127691376914769157691676917769187691976920769217692276923769247692576926769277692876929769307693176932769337693476935769367693776938769397694076941769427694376944769457694676947769487694976950769517695276953769547695576956769577695876959769607696176962769637696476965769667696776968769697697076971769727697376974769757697676977769787697976980769817698276983769847698576986769877698876989769907699176992769937699476995769967699776998769997700077001770027700377004770057700677007770087700977010770117701277013770147701577016770177701877019770207702177022770237702477025770267702777028770297703077031770327703377034770357703677037770387703977040770417704277043770447704577046770477704877049770507705177052770537705477055770567705777058770597706077061770627706377064770657706677067770687706977070770717707277073770747707577076770777707877079770807708177082770837708477085770867708777088770897709077091770927709377094770957709677097770987709977100771017710277103771047710577106771077710877109771107711177112771137711477115771167711777118771197712077121771227712377124771257712677127771287712977130771317713277133771347713577136771377713877139771407714177142771437714477145771467714777148771497715077151771527715377154771557715677157771587715977160771617716277163771647716577166771677716877169771707717177172771737717477175771767717777178771797718077181771827718377184771857718677187771887718977190771917719277193771947719577196771977719877199772007720177202772037720477205772067720777208772097721077211772127721377214772157721677217772187721977220772217722277223772247722577226772277722877229772307723177232772337723477235772367723777238772397724077241772427724377244772457724677247772487724977250772517725277253772547725577256772577725877259772607726177262772637726477265772667726777268772697727077271772727727377274772757727677277772787727977280772817728277283772847728577286772877728877289772907729177292772937729477295772967729777298772997730077301773027730377304773057730677307773087730977310773117731277313773147731577316773177731877319773207732177322773237732477325773267732777328773297733077331773327733377334773357733677337773387733977340773417734277343773447734577346773477734877349773507735177352773537735477355773567735777358773597736077361773627736377364773657736677367773687736977370773717737277373773747737577376773777737877379773807738177382773837738477385773867738777388773897739077391773927739377394773957739677397773987739977400774017740277403774047740577406774077740877409774107741177412774137741477415774167741777418774197742077421774227742377424774257742677427774287742977430774317743277433774347743577436774377743877439774407744177442774437744477445774467744777448774497745077451774527745377454774557745677457774587745977460774617746277463774647746577466774677746877469774707747177472774737747477475774767747777478774797748077481774827748377484774857748677487774887748977490774917749277493774947749577496774977749877499775007750177502775037750477505775067750777508775097751077511775127751377514775157751677517775187751977520775217752277523775247752577526775277752877529775307753177532775337753477535775367753777538775397754077541775427754377544775457754677547775487754977550775517755277553775547755577556775577755877559775607756177562775637756477565775667756777568775697757077571775727757377574775757757677577775787757977580775817758277583775847758577586775877758877589775907759177592775937759477595775967759777598775997760077601776027760377604776057760677607776087760977610776117761277613776147761577616776177761877619776207762177622776237762477625776267762777628776297763077631776327763377634776357763677637776387763977640776417764277643776447764577646776477764877649776507765177652776537765477655776567765777658776597766077661776627766377664776657766677667776687766977670776717767277673776747767577676776777767877679776807768177682776837768477685776867768777688776897769077691776927769377694776957769677697776987769977700777017770277703777047770577706777077770877709777107771177712777137771477715777167771777718777197772077721777227772377724777257772677727777287772977730777317773277733777347773577736777377773877739777407774177742777437774477745777467774777748777497775077751777527775377754777557775677757777587775977760777617776277763777647776577766777677776877769777707777177772777737777477775777767777777778777797778077781777827778377784777857778677787777887778977790777917779277793777947779577796777977779877799778007780177802778037780477805778067780777808778097781077811778127781377814778157781677817778187781977820778217782277823778247782577826778277782877829778307783177832778337783477835778367783777838778397784077841778427784377844778457784677847778487784977850778517785277853778547785577856778577785877859778607786177862778637786477865778667786777868778697787077871778727787377874778757787677877778787787977880778817788277883778847788577886778877788877889778907789177892778937789477895778967789777898778997790077901779027790377904779057790677907779087790977910779117791277913779147791577916779177791877919779207792177922779237792477925779267792777928779297793077931779327793377934779357793677937779387793977940779417794277943779447794577946779477794877949779507795177952779537795477955779567795777958779597796077961779627796377964779657796677967779687796977970779717797277973779747797577976779777797877979779807798177982779837798477985779867798777988779897799077991779927799377994779957799677997779987799978000780017800278003780047800578006780077800878009780107801178012780137801478015780167801778018780197802078021780227802378024780257802678027780287802978030780317803278033780347803578036780377803878039780407804178042780437804478045780467804778048780497805078051780527805378054780557805678057780587805978060780617806278063780647806578066780677806878069780707807178072780737807478075780767807778078780797808078081780827808378084780857808678087780887808978090780917809278093780947809578096780977809878099781007810178102781037810478105781067810778108781097811078111781127811378114781157811678117781187811978120781217812278123781247812578126781277812878129781307813178132781337813478135781367813778138781397814078141781427814378144781457814678147781487814978150781517815278153781547815578156781577815878159781607816178162781637816478165781667816778168781697817078171781727817378174781757817678177781787817978180781817818278183781847818578186781877818878189781907819178192781937819478195781967819778198781997820078201782027820378204782057820678207782087820978210782117821278213782147821578216782177821878219782207822178222782237822478225782267822778228782297823078231782327823378234782357823678237782387823978240782417824278243782447824578246782477824878249782507825178252782537825478255782567825778258782597826078261782627826378264782657826678267782687826978270782717827278273782747827578276782777827878279782807828178282782837828478285782867828778288782897829078291782927829378294782957829678297782987829978300783017830278303783047830578306783077830878309783107831178312783137831478315783167831778318783197832078321783227832378324783257832678327783287832978330783317833278333783347833578336783377833878339783407834178342783437834478345783467834778348783497835078351783527835378354783557835678357783587835978360783617836278363783647836578366783677836878369783707837178372783737837478375783767837778378783797838078381783827838378384783857838678387783887838978390783917839278393783947839578396783977839878399784007840178402784037840478405784067840778408784097841078411784127841378414784157841678417784187841978420784217842278423784247842578426784277842878429784307843178432784337843478435784367843778438784397844078441784427844378444784457844678447784487844978450784517845278453784547845578456784577845878459784607846178462784637846478465784667846778468784697847078471784727847378474784757847678477784787847978480784817848278483784847848578486784877848878489784907849178492784937849478495784967849778498784997850078501785027850378504785057850678507785087850978510785117851278513785147851578516785177851878519785207852178522785237852478525785267852778528785297853078531785327853378534785357853678537785387853978540785417854278543785447854578546785477854878549785507855178552785537855478555785567855778558785597856078561785627856378564785657856678567785687856978570785717857278573785747857578576785777857878579785807858178582785837858478585785867858778588785897859078591785927859378594785957859678597785987859978600786017860278603786047860578606786077860878609786107861178612786137861478615786167861778618786197862078621786227862378624786257862678627786287862978630786317863278633786347863578636786377863878639786407864178642786437864478645786467864778648786497865078651786527865378654786557865678657786587865978660786617866278663786647866578666786677866878669786707867178672786737867478675786767867778678786797868078681786827868378684786857868678687786887868978690786917869278693786947869578696786977869878699787007870178702787037870478705787067870778708787097871078711787127871378714787157871678717787187871978720787217872278723787247872578726787277872878729787307873178732787337873478735787367873778738787397874078741787427874378744787457874678747787487874978750787517875278753787547875578756787577875878759787607876178762787637876478765787667876778768787697877078771787727877378774787757877678777787787877978780787817878278783787847878578786787877878878789787907879178792787937879478795787967879778798787997880078801788027880378804788057880678807788087880978810788117881278813788147881578816788177881878819788207882178822788237882478825788267882778828788297883078831788327883378834788357883678837788387883978840788417884278843788447884578846788477884878849788507885178852788537885478855788567885778858788597886078861788627886378864788657886678867788687886978870788717887278873788747887578876788777887878879788807888178882788837888478885788867888778888788897889078891788927889378894788957889678897788987889978900789017890278903789047890578906789077890878909789107891178912789137891478915789167891778918789197892078921789227892378924789257892678927789287892978930789317893278933789347893578936789377893878939789407894178942789437894478945789467894778948789497895078951789527895378954789557895678957789587895978960789617896278963789647896578966789677896878969789707897178972789737897478975789767897778978789797898078981789827898378984789857898678987789887898978990789917899278993789947899578996789977899878999790007900179002790037900479005790067900779008790097901079011790127901379014790157901679017790187901979020790217902279023790247902579026790277902879029790307903179032790337903479035790367903779038790397904079041790427904379044790457904679047790487904979050790517905279053790547905579056790577905879059790607906179062790637906479065790667906779068790697907079071790727907379074790757907679077790787907979080790817908279083790847908579086790877908879089790907909179092790937909479095790967909779098790997910079101791027910379104791057910679107791087910979110791117911279113791147911579116791177911879119791207912179122791237912479125791267912779128791297913079131791327913379134791357913679137791387913979140791417914279143791447914579146791477914879149791507915179152791537915479155791567915779158791597916079161791627916379164791657916679167791687916979170791717917279173791747917579176791777917879179791807918179182791837918479185791867918779188791897919079191791927919379194791957919679197791987919979200792017920279203792047920579206792077920879209792107921179212792137921479215792167921779218792197922079221792227922379224792257922679227792287922979230792317923279233792347923579236792377923879239792407924179242792437924479245792467924779248792497925079251792527925379254792557925679257792587925979260792617926279263792647926579266792677926879269792707927179272792737927479275792767927779278792797928079281792827928379284792857928679287792887928979290792917929279293792947929579296792977929879299793007930179302793037930479305793067930779308793097931079311793127931379314793157931679317793187931979320793217932279323793247932579326793277932879329793307933179332793337933479335793367933779338793397934079341793427934379344793457934679347793487934979350793517935279353793547935579356793577935879359793607936179362793637936479365793667936779368793697937079371793727937379374793757937679377793787937979380793817938279383793847938579386793877938879389793907939179392793937939479395793967939779398793997940079401794027940379404794057940679407794087940979410794117941279413794147941579416794177941879419794207942179422794237942479425794267942779428794297943079431794327943379434794357943679437794387943979440794417944279443794447944579446794477944879449794507945179452794537945479455794567945779458794597946079461794627946379464794657946679467794687946979470794717947279473794747947579476794777947879479794807948179482794837948479485794867948779488794897949079491794927949379494794957949679497794987949979500795017950279503795047950579506795077950879509795107951179512795137951479515795167951779518795197952079521795227952379524795257952679527795287952979530795317953279533795347953579536795377953879539795407954179542795437954479545795467954779548795497955079551795527955379554795557955679557795587955979560795617956279563795647956579566795677956879569795707957179572795737957479575795767957779578795797958079581795827958379584795857958679587795887958979590795917959279593795947959579596795977959879599796007960179602796037960479605796067960779608796097961079611796127961379614796157961679617796187961979620796217962279623796247962579626796277962879629796307963179632796337963479635796367963779638796397964079641796427964379644796457964679647796487964979650796517965279653796547965579656796577965879659796607966179662796637966479665796667966779668796697967079671796727967379674796757967679677796787967979680796817968279683796847968579686796877968879689796907969179692796937969479695796967969779698796997970079701797027970379704797057970679707797087970979710797117971279713797147971579716797177971879719797207972179722797237972479725797267972779728797297973079731797327973379734797357973679737797387973979740797417974279743797447974579746797477974879749797507975179752797537975479755797567975779758797597976079761797627976379764797657976679767797687976979770797717977279773797747977579776797777977879779797807978179782797837978479785797867978779788797897979079791797927979379794797957979679797797987979979800798017980279803798047980579806798077980879809798107981179812798137981479815798167981779818798197982079821798227982379824798257982679827798287982979830798317983279833798347983579836798377983879839798407984179842798437984479845798467984779848798497985079851798527985379854798557985679857798587985979860798617986279863798647986579866798677986879869798707987179872798737987479875798767987779878798797988079881798827988379884798857988679887798887988979890798917989279893798947989579896798977989879899799007990179902799037990479905799067990779908799097991079911799127991379914799157991679917799187991979920799217992279923799247992579926799277992879929799307993179932799337993479935799367993779938799397994079941799427994379944799457994679947799487994979950799517995279953799547995579956799577995879959799607996179962799637996479965799667996779968799697997079971799727997379974799757997679977799787997979980799817998279983799847998579986799877998879989799907999179992799937999479995799967999779998799998000080001800028000380004800058000680007800088000980010800118001280013800148001580016800178001880019800208002180022800238002480025800268002780028800298003080031800328003380034800358003680037800388003980040800418004280043800448004580046800478004880049800508005180052800538005480055800568005780058800598006080061800628006380064800658006680067800688006980070800718007280073800748007580076800778007880079800808008180082800838008480085800868008780088800898009080091800928009380094800958009680097800988009980100801018010280103801048010580106801078010880109801108011180112801138011480115801168011780118801198012080121801228012380124801258012680127801288012980130801318013280133801348013580136801378013880139801408014180142801438014480145801468014780148801498015080151801528015380154801558015680157801588015980160801618016280163801648016580166801678016880169801708017180172801738017480175801768017780178801798018080181801828018380184801858018680187801888018980190801918019280193801948019580196801978019880199802008020180202802038020480205802068020780208802098021080211802128021380214802158021680217802188021980220802218022280223802248022580226802278022880229802308023180232802338023480235802368023780238802398024080241802428024380244802458024680247802488024980250802518025280253802548025580256802578025880259802608026180262802638026480265802668026780268802698027080271802728027380274802758027680277802788027980280802818028280283802848028580286802878028880289802908029180292802938029480295802968029780298802998030080301803028030380304803058030680307803088030980310803118031280313803148031580316803178031880319803208032180322803238032480325803268032780328803298033080331803328033380334803358033680337803388033980340803418034280343803448034580346803478034880349803508035180352803538035480355803568035780358803598036080361803628036380364803658036680367803688036980370803718037280373803748037580376803778037880379803808038180382803838038480385803868038780388803898039080391803928039380394803958039680397803988039980400804018040280403804048040580406804078040880409804108041180412804138041480415804168041780418804198042080421804228042380424804258042680427804288042980430804318043280433804348043580436804378043880439804408044180442804438044480445804468044780448804498045080451804528045380454804558045680457804588045980460804618046280463804648046580466804678046880469804708047180472804738047480475804768047780478804798048080481804828048380484804858048680487804888048980490804918049280493804948049580496804978049880499805008050180502805038050480505805068050780508805098051080511805128051380514805158051680517805188051980520805218052280523805248052580526805278052880529805308053180532805338053480535805368053780538805398054080541805428054380544805458054680547805488054980550805518055280553805548055580556805578055880559805608056180562805638056480565805668056780568805698057080571805728057380574805758057680577805788057980580805818058280583805848058580586805878058880589805908059180592805938059480595805968059780598805998060080601806028060380604806058060680607806088060980610806118061280613806148061580616806178061880619806208062180622806238062480625806268062780628806298063080631806328063380634806358063680637806388063980640806418064280643806448064580646806478064880649806508065180652806538065480655806568065780658806598066080661806628066380664806658066680667806688066980670806718067280673806748067580676806778067880679806808068180682806838068480685806868068780688806898069080691806928069380694806958069680697806988069980700807018070280703807048070580706807078070880709807108071180712807138071480715807168071780718807198072080721807228072380724807258072680727807288072980730807318073280733807348073580736807378073880739807408074180742807438074480745807468074780748807498075080751807528075380754807558075680757807588075980760807618076280763807648076580766807678076880769807708077180772807738077480775807768077780778807798078080781807828078380784807858078680787807888078980790807918079280793807948079580796807978079880799808008080180802808038080480805808068080780808808098081080811808128081380814808158081680817808188081980820808218082280823808248082580826808278082880829808308083180832808338083480835808368083780838808398084080841808428084380844808458084680847808488084980850808518085280853808548085580856808578085880859808608086180862808638086480865808668086780868808698087080871808728087380874808758087680877808788087980880808818088280883808848088580886808878088880889808908089180892808938089480895808968089780898808998090080901809028090380904809058090680907809088090980910809118091280913809148091580916809178091880919809208092180922809238092480925809268092780928809298093080931809328093380934809358093680937809388093980940809418094280943809448094580946809478094880949809508095180952809538095480955809568095780958809598096080961809628096380964809658096680967809688096980970809718097280973809748097580976809778097880979809808098180982809838098480985809868098780988809898099080991809928099380994809958099680997809988099981000810018100281003810048100581006810078100881009810108101181012810138101481015810168101781018810198102081021810228102381024810258102681027810288102981030810318103281033810348103581036810378103881039810408104181042810438104481045810468104781048810498105081051810528105381054810558105681057810588105981060810618106281063810648106581066810678106881069810708107181072810738107481075810768107781078810798108081081810828108381084810858108681087810888108981090810918109281093810948109581096810978109881099811008110181102811038110481105811068110781108811098111081111811128111381114811158111681117811188111981120811218112281123811248112581126811278112881129811308113181132811338113481135811368113781138811398114081141811428114381144811458114681147811488114981150811518115281153811548115581156811578115881159811608116181162811638116481165811668116781168811698117081171811728117381174811758117681177811788117981180811818118281183811848118581186811878118881189811908119181192811938119481195811968119781198811998120081201812028120381204812058120681207812088120981210812118121281213812148121581216812178121881219812208122181222812238122481225812268122781228812298123081231812328123381234812358123681237812388123981240812418124281243812448124581246812478124881249812508125181252812538125481255812568125781258812598126081261812628126381264812658126681267812688126981270812718127281273812748127581276812778127881279812808128181282812838128481285812868128781288812898129081291812928129381294812958129681297812988129981300813018130281303813048130581306813078130881309813108131181312813138131481315813168131781318813198132081321813228132381324813258132681327813288132981330813318133281333813348133581336813378133881339813408134181342813438134481345813468134781348813498135081351813528135381354813558135681357813588135981360813618136281363813648136581366813678136881369813708137181372813738137481375813768137781378813798138081381813828138381384813858138681387813888138981390813918139281393813948139581396813978139881399814008140181402814038140481405814068140781408814098141081411814128141381414814158141681417814188141981420814218142281423814248142581426814278142881429814308143181432814338143481435814368143781438814398144081441814428144381444814458144681447814488144981450814518145281453814548145581456814578145881459814608146181462814638146481465814668146781468814698147081471814728147381474814758147681477814788147981480814818148281483814848148581486814878148881489814908149181492814938149481495814968149781498814998150081501815028150381504815058150681507815088150981510815118151281513815148151581516815178151881519815208152181522815238152481525815268152781528815298153081531815328153381534815358153681537815388153981540815418154281543815448154581546815478154881549815508155181552815538155481555815568155781558815598156081561815628156381564815658156681567815688156981570815718157281573815748157581576815778157881579815808158181582815838158481585815868158781588815898159081591815928159381594815958159681597815988159981600816018160281603816048160581606816078160881609816108161181612816138161481615816168161781618816198162081621816228162381624816258162681627816288162981630816318163281633816348163581636816378163881639816408164181642816438164481645816468164781648816498165081651816528165381654816558165681657816588165981660816618166281663816648166581666816678166881669816708167181672816738167481675816768167781678816798168081681816828168381684816858168681687816888168981690816918169281693816948169581696816978169881699817008170181702817038170481705817068170781708817098171081711817128171381714817158171681717817188171981720817218172281723817248172581726817278172881729817308173181732817338173481735817368173781738817398174081741817428174381744817458174681747817488174981750817518175281753817548175581756817578175881759817608176181762817638176481765817668176781768817698177081771817728177381774817758177681777817788177981780817818178281783817848178581786817878178881789817908179181792817938179481795817968179781798817998180081801818028180381804818058180681807818088180981810818118181281813818148181581816818178181881819818208182181822818238182481825818268182781828818298183081831818328183381834818358183681837818388183981840818418184281843818448184581846818478184881849818508185181852818538185481855818568185781858818598186081861818628186381864818658186681867818688186981870818718187281873818748187581876818778187881879818808188181882818838188481885818868188781888818898189081891818928189381894818958189681897818988189981900819018190281903819048190581906819078190881909819108191181912819138191481915819168191781918819198192081921819228192381924819258192681927819288192981930819318193281933819348193581936819378193881939819408194181942819438194481945819468194781948819498195081951819528195381954819558195681957819588195981960819618196281963819648196581966819678196881969819708197181972819738197481975819768197781978819798198081981819828198381984819858198681987819888198981990819918199281993819948199581996819978199881999820008200182002820038200482005820068200782008820098201082011820128201382014820158201682017820188201982020820218202282023820248202582026820278202882029820308203182032820338203482035820368203782038820398204082041820428204382044820458204682047820488204982050820518205282053820548205582056820578205882059820608206182062820638206482065820668206782068820698207082071820728207382074820758207682077820788207982080820818208282083820848208582086820878208882089820908209182092820938209482095820968209782098820998210082101821028210382104821058210682107821088210982110821118211282113821148211582116821178211882119821208212182122821238212482125821268212782128821298213082131821328213382134821358213682137821388213982140821418214282143821448214582146821478214882149821508215182152821538215482155821568215782158821598216082161821628216382164821658216682167821688216982170821718217282173821748217582176821778217882179821808218182182821838218482185821868218782188821898219082191821928219382194821958219682197821988219982200822018220282203822048220582206822078220882209822108221182212822138221482215822168221782218822198222082221822228222382224822258222682227822288222982230822318223282233822348223582236822378223882239822408224182242822438224482245822468224782248822498225082251822528225382254822558225682257822588225982260822618226282263822648226582266822678226882269822708227182272822738227482275822768227782278822798228082281822828228382284822858228682287822888228982290822918229282293822948229582296822978229882299823008230182302823038230482305823068230782308823098231082311823128231382314823158231682317823188231982320823218232282323823248232582326823278232882329823308233182332823338233482335823368233782338823398234082341823428234382344823458234682347823488234982350823518235282353823548235582356823578235882359823608236182362823638236482365823668236782368823698237082371823728237382374823758237682377823788237982380823818238282383823848238582386823878238882389823908239182392823938239482395823968239782398823998240082401824028240382404824058240682407824088240982410824118241282413824148241582416824178241882419824208242182422824238242482425824268242782428824298243082431824328243382434824358243682437824388243982440824418244282443824448244582446824478244882449824508245182452824538245482455824568245782458824598246082461824628246382464824658246682467824688246982470824718247282473824748247582476824778247882479824808248182482824838248482485824868248782488824898249082491824928249382494824958249682497824988249982500825018250282503825048250582506825078250882509825108251182512825138251482515825168251782518825198252082521825228252382524825258252682527825288252982530825318253282533825348253582536825378253882539825408254182542825438254482545825468254782548825498255082551825528255382554825558255682557825588255982560825618256282563825648256582566825678256882569825708257182572825738257482575825768257782578825798258082581825828258382584825858258682587825888258982590825918259282593825948259582596825978259882599826008260182602826038260482605826068260782608826098261082611826128261382614826158261682617826188261982620826218262282623826248262582626826278262882629826308263182632826338263482635826368263782638826398264082641826428264382644826458264682647826488264982650826518265282653826548265582656826578265882659826608266182662826638266482665826668266782668826698267082671826728267382674826758267682677826788267982680826818268282683826848268582686826878268882689826908269182692826938269482695826968269782698826998270082701827028270382704827058270682707827088270982710827118271282713827148271582716827178271882719827208272182722827238272482725827268272782728827298273082731827328273382734827358273682737827388273982740827418274282743827448274582746827478274882749827508275182752827538275482755827568275782758827598276082761827628276382764827658276682767827688276982770827718277282773827748277582776827778277882779827808278182782827838278482785827868278782788827898279082791827928279382794827958279682797827988279982800828018280282803828048280582806828078280882809828108281182812828138281482815828168281782818828198282082821828228282382824828258282682827828288282982830828318283282833828348283582836828378283882839828408284182842828438284482845828468284782848828498285082851828528285382854828558285682857828588285982860828618286282863828648286582866828678286882869828708287182872828738287482875828768287782878828798288082881828828288382884828858288682887828888288982890828918289282893828948289582896828978289882899829008290182902829038290482905829068290782908829098291082911829128291382914829158291682917829188291982920829218292282923829248292582926829278292882929829308293182932829338293482935829368293782938829398294082941829428294382944829458294682947829488294982950829518295282953829548295582956829578295882959829608296182962829638296482965829668296782968829698297082971829728297382974829758297682977829788297982980829818298282983829848298582986829878298882989829908299182992829938299482995829968299782998829998300083001830028300383004830058300683007830088300983010830118301283013830148301583016830178301883019830208302183022830238302483025830268302783028830298303083031830328303383034830358303683037830388303983040830418304283043830448304583046830478304883049830508305183052830538305483055830568305783058830598306083061830628306383064830658306683067830688306983070830718307283073830748307583076830778307883079830808308183082830838308483085830868308783088830898309083091830928309383094830958309683097830988309983100831018310283103831048310583106831078310883109831108311183112831138311483115831168311783118831198312083121831228312383124831258312683127831288312983130831318313283133831348313583136831378313883139831408314183142831438314483145831468314783148831498315083151831528315383154831558315683157831588315983160831618316283163831648316583166831678316883169831708317183172831738317483175831768317783178831798318083181831828318383184831858318683187831888318983190831918319283193831948319583196831978319883199832008320183202832038320483205832068320783208832098321083211832128321383214832158321683217832188321983220832218322283223832248322583226832278322883229832308323183232832338323483235832368323783238832398324083241832428324383244832458324683247832488324983250832518325283253832548325583256832578325883259832608326183262832638326483265832668326783268832698327083271832728327383274832758327683277832788327983280832818328283283832848328583286832878328883289832908329183292832938329483295832968329783298832998330083301833028330383304833058330683307833088330983310833118331283313833148331583316833178331883319833208332183322833238332483325833268332783328833298333083331833328333383334833358333683337833388333983340833418334283343833448334583346833478334883349833508335183352833538335483355833568335783358833598336083361833628336383364833658336683367833688336983370833718337283373833748337583376833778337883379833808338183382833838338483385833868338783388833898339083391833928339383394833958339683397833988339983400834018340283403834048340583406834078340883409834108341183412834138341483415834168341783418834198342083421834228342383424834258342683427834288342983430834318343283433834348343583436834378343883439834408344183442834438344483445834468344783448834498345083451834528345383454834558345683457834588345983460834618346283463834648346583466834678346883469834708347183472834738347483475834768347783478834798348083481834828348383484834858348683487834888348983490834918349283493834948349583496834978349883499835008350183502835038350483505835068350783508835098351083511835128351383514835158351683517835188351983520835218352283523835248352583526835278352883529835308353183532835338353483535835368353783538835398354083541835428354383544835458354683547835488354983550835518355283553835548355583556835578355883559835608356183562835638356483565835668356783568835698357083571835728357383574835758357683577835788357983580835818358283583835848358583586835878358883589835908359183592835938359483595835968359783598835998360083601836028360383604836058360683607836088360983610836118361283613836148361583616836178361883619836208362183622836238362483625836268362783628836298363083631836328363383634836358363683637836388363983640836418364283643836448364583646836478364883649836508365183652836538365483655836568365783658836598366083661836628366383664836658366683667836688366983670836718367283673836748367583676836778367883679836808368183682836838368483685836868368783688836898369083691836928369383694836958369683697836988369983700837018370283703837048370583706837078370883709837108371183712837138371483715837168371783718837198372083721837228372383724837258372683727837288372983730837318373283733837348373583736837378373883739837408374183742837438374483745837468374783748837498375083751837528375383754837558375683757837588375983760837618376283763837648376583766837678376883769837708377183772837738377483775837768377783778837798378083781837828378383784837858378683787837888378983790837918379283793837948379583796837978379883799838008380183802838038380483805838068380783808838098381083811838128381383814838158381683817838188381983820838218382283823838248382583826838278382883829838308383183832838338383483835838368383783838838398384083841838428384383844838458384683847838488384983850838518385283853838548385583856838578385883859838608386183862838638386483865838668386783868838698387083871838728387383874838758387683877838788387983880838818388283883838848388583886838878388883889838908389183892838938389483895838968389783898838998390083901839028390383904839058390683907839088390983910839118391283913839148391583916839178391883919839208392183922839238392483925839268392783928839298393083931839328393383934839358393683937839388393983940839418394283943839448394583946839478394883949839508395183952839538395483955839568395783958839598396083961839628396383964839658396683967839688396983970839718397283973839748397583976839778397883979839808398183982839838398483985839868398783988839898399083991839928399383994839958399683997839988399984000840018400284003840048400584006840078400884009840108401184012840138401484015840168401784018840198402084021840228402384024840258402684027840288402984030840318403284033840348403584036840378403884039840408404184042840438404484045840468404784048840498405084051840528405384054840558405684057840588405984060840618406284063840648406584066840678406884069840708407184072840738407484075840768407784078840798408084081840828408384084840858408684087840888408984090840918409284093840948409584096840978409884099841008410184102841038410484105841068410784108841098411084111841128411384114841158411684117841188411984120841218412284123841248412584126841278412884129841308413184132841338413484135841368413784138841398414084141841428414384144841458414684147841488414984150841518415284153841548415584156841578415884159841608416184162841638416484165841668416784168841698417084171841728417384174841758417684177841788417984180841818418284183841848418584186841878418884189841908419184192841938419484195841968419784198841998420084201842028420384204842058420684207842088420984210842118421284213842148421584216842178421884219842208422184222842238422484225842268422784228842298423084231842328423384234842358423684237842388423984240842418424284243842448424584246842478424884249842508425184252842538425484255842568425784258842598426084261842628426384264842658426684267842688426984270842718427284273842748427584276842778427884279842808428184282842838428484285842868428784288842898429084291842928429384294842958429684297842988429984300843018430284303843048430584306843078430884309843108431184312843138431484315843168431784318843198432084321843228432384324843258432684327843288432984330843318433284333843348433584336843378433884339843408434184342843438434484345843468434784348843498435084351843528435384354843558435684357843588435984360843618436284363843648436584366843678436884369843708437184372843738437484375843768437784378843798438084381843828438384384843858438684387843888438984390843918439284393843948439584396843978439884399844008440184402844038440484405844068440784408844098441084411844128441384414844158441684417844188441984420844218442284423844248442584426844278442884429844308443184432844338443484435844368443784438844398444084441844428444384444844458444684447844488444984450844518445284453844548445584456844578445884459844608446184462844638446484465844668446784468844698447084471844728447384474844758447684477844788447984480844818448284483844848448584486844878448884489844908449184492844938449484495844968449784498844998450084501845028450384504845058450684507845088450984510845118451284513845148451584516845178451884519845208452184522845238452484525845268452784528845298453084531845328453384534845358453684537845388453984540845418454284543845448454584546845478454884549845508455184552845538455484555845568455784558845598456084561845628456384564845658456684567845688456984570845718457284573845748457584576845778457884579845808458184582845838458484585845868458784588845898459084591845928459384594845958459684597845988459984600846018460284603846048460584606846078460884609846108461184612846138461484615846168461784618846198462084621846228462384624846258462684627846288462984630846318463284633846348463584636846378463884639846408464184642846438464484645846468464784648846498465084651846528465384654846558465684657846588465984660846618466284663846648466584666846678466884669846708467184672846738467484675846768467784678846798468084681846828468384684846858468684687846888468984690846918469284693846948469584696846978469884699847008470184702847038470484705847068470784708847098471084711847128471384714847158471684717847188471984720847218472284723847248472584726847278472884729847308473184732847338473484735847368473784738847398474084741847428474384744847458474684747847488474984750847518475284753847548475584756847578475884759847608476184762847638476484765847668476784768847698477084771847728477384774847758477684777847788477984780847818478284783847848478584786847878478884789847908479184792847938479484795847968479784798847998480084801848028480384804848058480684807848088480984810848118481284813848148481584816848178481884819848208482184822848238482484825848268482784828848298483084831848328483384834848358483684837848388483984840848418484284843848448484584846848478484884849848508485184852848538485484855848568485784858848598486084861848628486384864848658486684867848688486984870848718487284873848748487584876848778487884879848808488184882848838488484885848868488784888848898489084891848928489384894848958489684897848988489984900849018490284903849048490584906849078490884909849108491184912849138491484915849168491784918849198492084921849228492384924849258492684927849288492984930849318493284933849348493584936849378493884939849408494184942849438494484945849468494784948849498495084951849528495384954849558495684957849588495984960849618496284963849648496584966849678496884969849708497184972849738497484975849768497784978849798498084981849828498384984849858498684987849888498984990849918499284993849948499584996849978499884999850008500185002850038500485005850068500785008850098501085011850128501385014850158501685017850188501985020850218502285023850248502585026850278502885029850308503185032850338503485035850368503785038850398504085041850428504385044850458504685047850488504985050850518505285053850548505585056850578505885059850608506185062850638506485065850668506785068850698507085071850728507385074850758507685077850788507985080850818508285083850848508585086850878508885089850908509185092850938509485095850968509785098850998510085101851028510385104851058510685107851088510985110851118511285113851148511585116851178511885119851208512185122851238512485125851268512785128851298513085131851328513385134851358513685137851388513985140851418514285143851448514585146851478514885149851508515185152851538515485155851568515785158851598516085161851628516385164851658516685167851688516985170851718517285173851748517585176851778517885179851808518185182851838518485185851868518785188851898519085191851928519385194851958519685197851988519985200852018520285203852048520585206852078520885209852108521185212852138521485215852168521785218852198522085221852228522385224852258522685227852288522985230852318523285233852348523585236852378523885239852408524185242852438524485245852468524785248852498525085251852528525385254852558525685257852588525985260852618526285263852648526585266852678526885269852708527185272852738527485275852768527785278852798528085281852828528385284852858528685287852888528985290852918529285293852948529585296852978529885299853008530185302853038530485305853068530785308853098531085311853128531385314853158531685317853188531985320853218532285323853248532585326853278532885329853308533185332853338533485335853368533785338853398534085341853428534385344853458534685347853488534985350853518535285353853548535585356853578535885359853608536185362853638536485365853668536785368853698537085371853728537385374853758537685377853788537985380853818538285383853848538585386853878538885389853908539185392853938539485395853968539785398853998540085401854028540385404854058540685407854088540985410854118541285413854148541585416854178541885419854208542185422854238542485425854268542785428854298543085431854328543385434854358543685437854388543985440854418544285443854448544585446854478544885449854508545185452854538545485455854568545785458854598546085461854628546385464854658546685467854688546985470854718547285473854748547585476854778547885479854808548185482854838548485485854868548785488854898549085491854928549385494854958549685497854988549985500855018550285503855048550585506855078550885509855108551185512855138551485515855168551785518855198552085521855228552385524855258552685527855288552985530855318553285533855348553585536855378553885539855408554185542855438554485545855468554785548855498555085551855528555385554855558555685557855588555985560855618556285563855648556585566855678556885569855708557185572855738557485575855768557785578855798558085581855828558385584855858558685587855888558985590855918559285593855948559585596855978559885599856008560185602856038560485605856068560785608856098561085611856128561385614856158561685617856188561985620856218562285623856248562585626856278562885629856308563185632856338563485635856368563785638856398564085641856428564385644856458564685647856488564985650856518565285653856548565585656856578565885659856608566185662856638566485665856668566785668856698567085671856728567385674856758567685677856788567985680856818568285683856848568585686856878568885689856908569185692856938569485695856968569785698856998570085701857028570385704857058570685707857088570985710857118571285713857148571585716857178571885719857208572185722857238572485725857268572785728857298573085731857328573385734857358573685737857388573985740857418574285743857448574585746857478574885749857508575185752857538575485755857568575785758857598576085761857628576385764857658576685767857688576985770857718577285773857748577585776857778577885779857808578185782857838578485785857868578785788857898579085791857928579385794857958579685797857988579985800858018580285803858048580585806858078580885809858108581185812858138581485815858168581785818858198582085821858228582385824858258582685827858288582985830858318583285833858348583585836858378583885839858408584185842858438584485845858468584785848858498585085851858528585385854858558585685857858588585985860858618586285863858648586585866858678586885869858708587185872858738587485875858768587785878858798588085881858828588385884858858588685887858888588985890858918589285893858948589585896858978589885899859008590185902859038590485905859068590785908859098591085911859128591385914859158591685917859188591985920859218592285923859248592585926859278592885929859308593185932859338593485935859368593785938859398594085941859428594385944859458594685947859488594985950859518595285953859548595585956859578595885959859608596185962859638596485965859668596785968859698597085971859728597385974859758597685977859788597985980859818598285983859848598585986859878598885989859908599185992859938599485995859968599785998859998600086001860028600386004860058600686007860088600986010860118601286013860148601586016860178601886019860208602186022860238602486025860268602786028860298603086031860328603386034860358603686037860388603986040860418604286043860448604586046860478604886049860508605186052860538605486055860568605786058860598606086061860628606386064860658606686067860688606986070860718607286073860748607586076860778607886079860808608186082860838608486085860868608786088860898609086091860928609386094860958609686097860988609986100861018610286103861048610586106861078610886109861108611186112861138611486115861168611786118861198612086121861228612386124861258612686127861288612986130861318613286133861348613586136861378613886139861408614186142861438614486145861468614786148861498615086151861528615386154861558615686157861588615986160861618616286163861648616586166861678616886169861708617186172861738617486175861768617786178861798618086181861828618386184861858618686187861888618986190861918619286193861948619586196861978619886199862008620186202862038620486205862068620786208862098621086211862128621386214862158621686217862188621986220862218622286223862248622586226862278622886229862308623186232862338623486235862368623786238862398624086241862428624386244862458624686247862488624986250862518625286253862548625586256862578625886259862608626186262862638626486265862668626786268862698627086271862728627386274862758627686277862788627986280862818628286283862848628586286862878628886289862908629186292862938629486295862968629786298862998630086301863028630386304863058630686307863088630986310863118631286313863148631586316863178631886319863208632186322863238632486325863268632786328863298633086331863328633386334863358633686337863388633986340863418634286343863448634586346863478634886349863508635186352863538635486355863568635786358863598636086361863628636386364863658636686367863688636986370863718637286373863748637586376863778637886379863808638186382863838638486385863868638786388863898639086391863928639386394863958639686397863988639986400864018640286403864048640586406864078640886409864108641186412864138641486415864168641786418864198642086421864228642386424864258642686427864288642986430864318643286433864348643586436864378643886439864408644186442864438644486445864468644786448864498645086451864528645386454864558645686457864588645986460864618646286463864648646586466864678646886469864708647186472864738647486475864768647786478864798648086481864828648386484864858648686487864888648986490864918649286493864948649586496864978649886499865008650186502865038650486505865068650786508865098651086511865128651386514865158651686517865188651986520865218652286523865248652586526865278652886529865308653186532865338653486535865368653786538865398654086541865428654386544865458654686547865488654986550865518655286553865548655586556865578655886559865608656186562865638656486565865668656786568865698657086571865728657386574865758657686577865788657986580865818658286583865848658586586865878658886589865908659186592865938659486595865968659786598865998660086601866028660386604866058660686607866088660986610866118661286613866148661586616866178661886619866208662186622866238662486625866268662786628866298663086631866328663386634866358663686637866388663986640866418664286643866448664586646866478664886649866508665186652866538665486655866568665786658866598666086661866628666386664866658666686667866688666986670866718667286673866748667586676866778667886679866808668186682866838668486685866868668786688866898669086691866928669386694866958669686697866988669986700867018670286703867048670586706867078670886709867108671186712867138671486715867168671786718867198672086721867228672386724867258672686727867288672986730867318673286733867348673586736867378673886739867408674186742867438674486745867468674786748867498675086751867528675386754867558675686757867588675986760867618676286763867648676586766867678676886769867708677186772867738677486775867768677786778867798678086781867828678386784867858678686787867888678986790867918679286793867948679586796867978679886799868008680186802868038680486805868068680786808868098681086811868128681386814868158681686817868188681986820868218682286823868248682586826868278682886829868308683186832868338683486835868368683786838868398684086841868428684386844868458684686847868488684986850868518685286853868548685586856868578685886859868608686186862868638686486865868668686786868868698687086871868728687386874868758687686877868788687986880868818688286883868848688586886868878688886889868908689186892868938689486895868968689786898868998690086901869028690386904869058690686907869088690986910869118691286913869148691586916869178691886919869208692186922869238692486925869268692786928869298693086931869328693386934869358693686937869388693986940869418694286943869448694586946869478694886949869508695186952869538695486955869568695786958869598696086961869628696386964869658696686967869688696986970869718697286973869748697586976869778697886979869808698186982869838698486985869868698786988869898699086991869928699386994869958699686997869988699987000870018700287003870048700587006870078700887009870108701187012870138701487015870168701787018870198702087021870228702387024870258702687027870288702987030870318703287033870348703587036870378703887039870408704187042870438704487045870468704787048870498705087051870528705387054870558705687057870588705987060870618706287063870648706587066870678706887069870708707187072870738707487075870768707787078870798708087081870828708387084870858708687087870888708987090870918709287093870948709587096870978709887099871008710187102871038710487105871068710787108871098711087111871128711387114871158711687117871188711987120871218712287123871248712587126871278712887129871308713187132871338713487135871368713787138871398714087141871428714387144871458714687147871488714987150871518715287153871548715587156871578715887159871608716187162871638716487165871668716787168871698717087171871728717387174871758717687177871788717987180871818718287183871848718587186871878718887189871908719187192871938719487195871968719787198871998720087201872028720387204872058720687207872088720987210872118721287213872148721587216872178721887219872208722187222872238722487225872268722787228872298723087231872328723387234872358723687237872388723987240872418724287243872448724587246872478724887249872508725187252872538725487255872568725787258872598726087261872628726387264872658726687267872688726987270872718727287273872748727587276872778727887279872808728187282872838728487285872868728787288872898729087291872928729387294872958729687297872988729987300873018730287303873048730587306873078730887309873108731187312873138731487315873168731787318873198732087321873228732387324873258732687327873288732987330873318733287333873348733587336873378733887339873408734187342873438734487345873468734787348873498735087351873528735387354873558735687357873588735987360873618736287363873648736587366873678736887369873708737187372873738737487375873768737787378873798738087381873828738387384873858738687387873888738987390873918739287393873948739587396873978739887399874008740187402874038740487405874068740787408874098741087411874128741387414874158741687417874188741987420874218742287423874248742587426874278742887429874308743187432874338743487435874368743787438874398744087441874428744387444874458744687447874488744987450874518745287453874548745587456874578745887459874608746187462874638746487465874668746787468874698747087471874728747387474874758747687477874788747987480874818748287483874848748587486874878748887489874908749187492874938749487495874968749787498874998750087501875028750387504875058750687507875088750987510875118751287513875148751587516875178751887519875208752187522875238752487525875268752787528875298753087531875328753387534875358753687537875388753987540875418754287543875448754587546875478754887549875508755187552875538755487555875568755787558875598756087561875628756387564875658756687567875688756987570875718757287573875748757587576875778757887579875808758187582875838758487585875868758787588875898759087591875928759387594875958759687597875988759987600876018760287603876048760587606876078760887609876108761187612876138761487615876168761787618876198762087621876228762387624876258762687627876288762987630876318763287633876348763587636876378763887639876408764187642876438764487645876468764787648876498765087651876528765387654876558765687657876588765987660876618766287663876648766587666876678766887669876708767187672876738767487675876768767787678876798768087681876828768387684876858768687687876888768987690876918769287693876948769587696876978769887699877008770187702877038770487705877068770787708877098771087711877128771387714877158771687717877188771987720877218772287723877248772587726877278772887729877308773187732877338773487735877368773787738877398774087741877428774387744877458774687747877488774987750877518775287753877548775587756877578775887759877608776187762877638776487765877668776787768877698777087771877728777387774877758777687777877788777987780877818778287783877848778587786877878778887789877908779187792877938779487795877968779787798877998780087801878028780387804878058780687807878088780987810878118781287813878148781587816878178781887819878208782187822878238782487825878268782787828878298783087831878328783387834878358783687837878388783987840878418784287843878448784587846878478784887849878508785187852878538785487855878568785787858878598786087861878628786387864878658786687867878688786987870878718787287873878748787587876878778787887879878808788187882878838788487885878868788787888878898789087891878928789387894878958789687897878988789987900879018790287903879048790587906879078790887909879108791187912879138791487915879168791787918879198792087921879228792387924879258792687927879288792987930879318793287933879348793587936879378793887939879408794187942879438794487945879468794787948879498795087951879528795387954879558795687957879588795987960879618796287963879648796587966879678796887969879708797187972879738797487975879768797787978879798798087981879828798387984879858798687987879888798987990879918799287993879948799587996879978799887999880008800188002880038800488005880068800788008880098801088011880128801388014880158801688017880188801988020880218802288023880248802588026880278802888029880308803188032880338803488035880368803788038880398804088041880428804388044880458804688047880488804988050880518805288053880548805588056880578805888059880608806188062880638806488065880668806788068880698807088071880728807388074880758807688077880788807988080880818808288083880848808588086880878808888089880908809188092880938809488095880968809788098880998810088101881028810388104881058810688107881088810988110881118811288113881148811588116881178811888119881208812188122881238812488125881268812788128881298813088131881328813388134881358813688137881388813988140881418814288143881448814588146881478814888149881508815188152881538815488155881568815788158881598816088161881628816388164881658816688167881688816988170881718817288173881748817588176881778817888179881808818188182881838818488185881868818788188881898819088191881928819388194881958819688197881988819988200882018820288203882048820588206882078820888209882108821188212882138821488215882168821788218882198822088221882228822388224882258822688227882288822988230882318823288233882348823588236882378823888239882408824188242882438824488245882468824788248882498825088251882528825388254882558825688257882588825988260882618826288263882648826588266882678826888269882708827188272882738827488275882768827788278882798828088281882828828388284882858828688287882888828988290882918829288293882948829588296882978829888299883008830188302883038830488305883068830788308883098831088311883128831388314883158831688317883188831988320883218832288323883248832588326883278832888329883308833188332883338833488335883368833788338883398834088341883428834388344883458834688347883488834988350883518835288353883548835588356883578835888359883608836188362883638836488365883668836788368883698837088371883728837388374883758837688377883788837988380883818838288383883848838588386883878838888389883908839188392883938839488395883968839788398883998840088401884028840388404884058840688407884088840988410884118841288413884148841588416884178841888419884208842188422884238842488425884268842788428884298843088431884328843388434884358843688437884388843988440884418844288443884448844588446884478844888449884508845188452884538845488455884568845788458884598846088461884628846388464884658846688467884688846988470884718847288473884748847588476884778847888479884808848188482884838848488485884868848788488884898849088491884928849388494884958849688497884988849988500885018850288503885048850588506885078850888509885108851188512885138851488515885168851788518885198852088521885228852388524885258852688527885288852988530885318853288533885348853588536885378853888539885408854188542885438854488545885468854788548885498855088551885528855388554885558855688557885588855988560885618856288563885648856588566885678856888569885708857188572885738857488575885768857788578885798858088581885828858388584885858858688587885888858988590885918859288593885948859588596885978859888599886008860188602886038860488605886068860788608886098861088611886128861388614886158861688617886188861988620886218862288623886248862588626886278862888629886308863188632886338863488635886368863788638886398864088641886428864388644886458864688647886488864988650886518865288653886548865588656886578865888659886608866188662886638866488665886668866788668886698867088671886728867388674886758867688677886788867988680886818868288683886848868588686886878868888689886908869188692886938869488695886968869788698886998870088701887028870388704887058870688707887088870988710887118871288713887148871588716887178871888719887208872188722887238872488725887268872788728887298873088731887328873388734887358873688737887388873988740887418874288743887448874588746887478874888749887508875188752887538875488755887568875788758887598876088761887628876388764887658876688767887688876988770887718877288773887748877588776887778877888779887808878188782887838878488785887868878788788887898879088791887928879388794887958879688797887988879988800888018880288803888048880588806888078880888809888108881188812888138881488815888168881788818888198882088821888228882388824888258882688827888288882988830888318883288833888348883588836888378883888839888408884188842888438884488845888468884788848888498885088851888528885388854888558885688857888588885988860888618886288863888648886588866888678886888869888708887188872888738887488875888768887788878888798888088881888828888388884888858888688887888888888988890888918889288893888948889588896888978889888899889008890188902889038890488905889068890788908889098891088911889128891388914889158891688917889188891988920889218892288923889248892588926889278892888929889308893188932889338893488935889368893788938889398894088941889428894388944889458894688947889488894988950889518895288953889548895588956889578895888959889608896188962889638896488965889668896788968889698897088971889728897388974889758897688977889788897988980889818898288983889848898588986889878898888989889908899188992889938899488995889968899788998889998900089001890028900389004890058900689007890088900989010890118901289013890148901589016890178901889019890208902189022890238902489025890268902789028890298903089031890328903389034890358903689037890388903989040890418904289043890448904589046890478904889049890508905189052890538905489055890568905789058890598906089061890628906389064890658906689067890688906989070890718907289073890748907589076890778907889079890808908189082890838908489085890868908789088890898909089091890928909389094890958909689097890988909989100891018910289103891048910589106891078910889109891108911189112891138911489115891168911789118891198912089121891228912389124891258912689127891288912989130891318913289133891348913589136891378913889139891408914189142891438914489145891468914789148891498915089151891528915389154891558915689157891588915989160891618916289163891648916589166891678916889169891708917189172891738917489175891768917789178891798918089181891828918389184891858918689187891888918989190891918919289193891948919589196891978919889199892008920189202892038920489205892068920789208892098921089211892128921389214892158921689217892188921989220892218922289223892248922589226892278922889229892308923189232892338923489235892368923789238892398924089241892428924389244892458924689247892488924989250892518925289253892548925589256892578925889259892608926189262892638926489265892668926789268892698927089271892728927389274892758927689277892788927989280892818928289283892848928589286892878928889289892908929189292892938929489295892968929789298892998930089301893028930389304893058930689307893088930989310893118931289313893148931589316893178931889319893208932189322893238932489325893268932789328893298933089331893328933389334893358933689337893388933989340893418934289343893448934589346893478934889349893508935189352893538935489355893568935789358893598936089361893628936389364893658936689367893688936989370893718937289373893748937589376893778937889379893808938189382893838938489385893868938789388893898939089391893928939389394893958939689397893988939989400894018940289403894048940589406894078940889409894108941189412894138941489415894168941789418894198942089421894228942389424894258942689427894288942989430894318943289433894348943589436894378943889439894408944189442894438944489445894468944789448894498945089451894528945389454894558945689457894588945989460894618946289463894648946589466894678946889469894708947189472894738947489475894768947789478894798948089481894828948389484894858948689487894888948989490894918949289493894948949589496894978949889499895008950189502895038950489505895068950789508895098951089511895128951389514895158951689517895188951989520895218952289523895248952589526895278952889529895308953189532895338953489535895368953789538895398954089541895428954389544895458954689547895488954989550895518955289553895548955589556895578955889559895608956189562895638956489565895668956789568895698957089571895728957389574895758957689577895788957989580895818958289583895848958589586895878958889589895908959189592895938959489595895968959789598895998960089601896028960389604896058960689607896088960989610896118961289613896148961589616896178961889619896208962189622896238962489625896268962789628896298963089631896328963389634896358963689637896388963989640896418964289643896448964589646896478964889649896508965189652896538965489655896568965789658896598966089661896628966389664896658966689667896688966989670896718967289673896748967589676896778967889679896808968189682896838968489685896868968789688896898969089691896928969389694896958969689697896988969989700897018970289703897048970589706897078970889709897108971189712897138971489715897168971789718897198972089721897228972389724897258972689727897288972989730897318973289733897348973589736897378973889739897408974189742897438974489745897468974789748897498975089751897528975389754897558975689757897588975989760897618976289763897648976589766897678976889769897708977189772897738977489775897768977789778897798978089781897828978389784897858978689787897888978989790897918979289793897948979589796897978979889799898008980189802898038980489805898068980789808898098981089811898128981389814898158981689817898188981989820898218982289823898248982589826898278982889829898308983189832898338983489835898368983789838898398984089841898428984389844898458984689847898488984989850898518985289853898548985589856898578985889859898608986189862898638986489865898668986789868898698987089871898728987389874898758987689877898788987989880898818988289883898848988589886898878988889889898908989189892898938989489895898968989789898898998990089901899028990389904899058990689907899088990989910899118991289913899148991589916899178991889919899208992189922899238992489925899268992789928899298993089931899328993389934899358993689937899388993989940899418994289943899448994589946899478994889949899508995189952899538995489955899568995789958899598996089961899628996389964899658996689967899688996989970899718997289973899748997589976899778997889979899808998189982899838998489985899868998789988899898999089991899928999389994899958999689997899988999990000900019000290003900049000590006900079000890009900109001190012900139001490015900169001790018900199002090021900229002390024900259002690027900289002990030900319003290033900349003590036900379003890039900409004190042900439004490045900469004790048900499005090051900529005390054900559005690057900589005990060900619006290063900649006590066900679006890069900709007190072900739007490075900769007790078900799008090081900829008390084900859008690087900889008990090900919009290093900949009590096900979009890099901009010190102901039010490105901069010790108901099011090111901129011390114901159011690117901189011990120901219012290123901249012590126901279012890129901309013190132901339013490135901369013790138901399014090141901429014390144901459014690147901489014990150901519015290153901549015590156901579015890159901609016190162901639016490165901669016790168901699017090171901729017390174901759017690177901789017990180901819018290183901849018590186901879018890189901909019190192901939019490195901969019790198901999020090201902029020390204902059020690207902089020990210902119021290213902149021590216902179021890219902209022190222902239022490225902269022790228902299023090231902329023390234902359023690237902389023990240902419024290243902449024590246902479024890249902509025190252902539025490255902569025790258902599026090261902629026390264902659026690267902689026990270902719027290273902749027590276902779027890279902809028190282902839028490285902869028790288902899029090291902929029390294902959029690297902989029990300903019030290303903049030590306903079030890309903109031190312903139031490315903169031790318903199032090321903229032390324903259032690327903289032990330903319033290333903349033590336903379033890339903409034190342903439034490345903469034790348903499035090351903529035390354903559035690357903589035990360903619036290363903649036590366903679036890369903709037190372903739037490375903769037790378903799038090381903829038390384903859038690387903889038990390903919039290393903949039590396903979039890399904009040190402904039040490405904069040790408904099041090411904129041390414904159041690417904189041990420904219042290423904249042590426904279042890429904309043190432904339043490435904369043790438904399044090441904429044390444904459044690447904489044990450904519045290453904549045590456904579045890459904609046190462904639046490465904669046790468904699047090471904729047390474904759047690477904789047990480904819048290483904849048590486904879048890489904909049190492904939049490495904969049790498904999050090501905029050390504905059050690507905089050990510905119051290513905149051590516905179051890519905209052190522905239052490525905269052790528905299053090531905329053390534905359053690537905389053990540905419054290543905449054590546905479054890549905509055190552905539055490555905569055790558905599056090561905629056390564905659056690567905689056990570905719057290573905749057590576905779057890579905809058190582905839058490585905869058790588905899059090591905929059390594905959059690597905989059990600906019060290603906049060590606906079060890609906109061190612906139061490615906169061790618906199062090621906229062390624906259062690627906289062990630906319063290633906349063590636906379063890639906409064190642906439064490645906469064790648906499065090651906529065390654906559065690657906589065990660906619066290663906649066590666906679066890669906709067190672906739067490675906769067790678906799068090681906829068390684906859068690687906889068990690906919069290693906949069590696906979069890699907009070190702907039070490705907069070790708907099071090711907129071390714907159071690717907189071990720907219072290723907249072590726907279072890729907309073190732907339073490735907369073790738907399074090741907429074390744907459074690747907489074990750907519075290753907549075590756907579075890759907609076190762907639076490765907669076790768907699077090771907729077390774907759077690777907789077990780907819078290783907849078590786907879078890789907909079190792907939079490795907969079790798907999080090801908029080390804908059080690807908089080990810908119081290813908149081590816908179081890819908209082190822908239082490825908269082790828908299083090831908329083390834908359083690837908389083990840908419084290843908449084590846908479084890849908509085190852908539085490855908569085790858908599086090861908629086390864908659086690867908689086990870908719087290873908749087590876908779087890879908809088190882908839088490885908869088790888908899089090891908929089390894908959089690897908989089990900909019090290903909049090590906909079090890909909109091190912909139091490915909169091790918909199092090921909229092390924909259092690927909289092990930909319093290933909349093590936909379093890939909409094190942909439094490945909469094790948909499095090951909529095390954909559095690957909589095990960909619096290963909649096590966909679096890969909709097190972909739097490975909769097790978909799098090981909829098390984909859098690987909889098990990909919099290993909949099590996909979099890999910009100191002910039100491005910069100791008910099101091011910129101391014910159101691017910189101991020910219102291023910249102591026910279102891029910309103191032910339103491035910369103791038910399104091041910429104391044910459104691047910489104991050910519105291053910549105591056910579105891059910609106191062910639106491065910669106791068910699107091071910729107391074910759107691077910789107991080910819108291083910849108591086910879108891089910909109191092910939109491095910969109791098910999110091101911029110391104911059110691107911089110991110911119111291113911149111591116911179111891119911209112191122911239112491125911269112791128911299113091131911329113391134911359113691137911389113991140911419114291143911449114591146911479114891149911509115191152911539115491155911569115791158911599116091161911629116391164911659116691167911689116991170911719117291173911749117591176911779117891179911809118191182911839118491185911869118791188911899119091191911929119391194911959119691197911989119991200912019120291203912049120591206912079120891209912109121191212912139121491215912169121791218912199122091221912229122391224912259122691227912289122991230912319123291233912349123591236912379123891239912409124191242912439124491245912469124791248912499125091251912529125391254912559125691257912589125991260912619126291263912649126591266912679126891269912709127191272912739127491275912769127791278912799128091281912829128391284912859128691287912889128991290912919129291293912949129591296912979129891299913009130191302913039130491305913069130791308913099131091311913129131391314913159131691317913189131991320913219132291323913249132591326913279132891329913309133191332913339133491335913369133791338913399134091341913429134391344913459134691347913489134991350913519135291353913549135591356913579135891359913609136191362913639136491365913669136791368913699137091371913729137391374913759137691377913789137991380913819138291383913849138591386913879138891389913909139191392913939139491395913969139791398913999140091401914029140391404914059140691407914089140991410914119141291413914149141591416914179141891419914209142191422914239142491425914269142791428914299143091431914329143391434914359143691437914389143991440914419144291443914449144591446914479144891449914509145191452914539145491455914569145791458914599146091461914629146391464914659146691467914689146991470914719147291473914749147591476914779147891479914809148191482914839148491485914869148791488914899149091491914929149391494914959149691497914989149991500915019150291503915049150591506915079150891509915109151191512915139151491515915169151791518915199152091521915229152391524915259152691527915289152991530915319153291533915349153591536915379153891539915409154191542915439154491545915469154791548915499155091551915529155391554915559155691557915589155991560915619156291563915649156591566915679156891569915709157191572915739157491575915769157791578915799158091581915829158391584915859158691587915889158991590915919159291593915949159591596915979159891599916009160191602916039160491605916069160791608916099161091611916129161391614916159161691617916189161991620916219162291623916249162591626916279162891629916309163191632916339163491635916369163791638916399164091641916429164391644916459164691647916489164991650916519165291653916549165591656916579165891659916609166191662916639166491665916669166791668916699167091671916729167391674916759167691677916789167991680916819168291683916849168591686916879168891689916909169191692916939169491695916969169791698916999170091701917029170391704917059170691707917089170991710917119171291713917149171591716917179171891719917209172191722917239172491725917269172791728917299173091731917329173391734917359173691737917389173991740917419174291743917449174591746917479174891749917509175191752917539175491755917569175791758917599176091761917629176391764917659176691767917689176991770917719177291773917749177591776917779177891779917809178191782917839178491785917869178791788917899179091791917929179391794917959179691797917989179991800918019180291803918049180591806918079180891809918109181191812918139181491815918169181791818918199182091821918229182391824918259182691827918289182991830918319183291833918349183591836918379183891839918409184191842918439184491845918469184791848918499185091851918529185391854918559185691857918589185991860918619186291863918649186591866918679186891869918709187191872918739187491875918769187791878918799188091881918829188391884918859188691887918889188991890918919189291893918949189591896918979189891899919009190191902919039190491905919069190791908919099191091911919129191391914919159191691917919189191991920919219192291923919249192591926919279192891929919309193191932919339193491935919369193791938919399194091941919429194391944919459194691947919489194991950919519195291953919549195591956919579195891959919609196191962919639196491965919669196791968919699197091971919729197391974919759197691977919789197991980919819198291983919849198591986919879198891989919909199191992919939199491995919969199791998919999200092001920029200392004920059200692007920089200992010920119201292013920149201592016920179201892019920209202192022920239202492025920269202792028920299203092031920329203392034920359203692037920389203992040920419204292043920449204592046920479204892049920509205192052920539205492055920569205792058920599206092061920629206392064920659206692067920689206992070920719207292073920749207592076920779207892079920809208192082920839208492085920869208792088920899209092091920929209392094920959209692097920989209992100921019210292103921049210592106921079210892109921109211192112921139211492115921169211792118921199212092121921229212392124921259212692127921289212992130921319213292133921349213592136921379213892139921409214192142921439214492145921469214792148921499215092151921529215392154921559215692157921589215992160921619216292163921649216592166921679216892169921709217192172921739217492175921769217792178921799218092181921829218392184921859218692187921889218992190921919219292193921949219592196921979219892199922009220192202922039220492205922069220792208922099221092211922129221392214922159221692217922189221992220922219222292223922249222592226922279222892229922309223192232922339223492235922369223792238922399224092241922429224392244922459224692247922489224992250922519225292253922549225592256922579225892259922609226192262922639226492265922669226792268922699227092271922729227392274922759227692277922789227992280922819228292283922849228592286922879228892289922909229192292922939229492295922969229792298922999230092301923029230392304923059230692307923089230992310923119231292313923149231592316923179231892319923209232192322923239232492325923269232792328923299233092331923329233392334923359233692337923389233992340923419234292343923449234592346923479234892349923509235192352923539235492355923569235792358923599236092361923629236392364923659236692367923689236992370923719237292373923749237592376923779237892379923809238192382923839238492385923869238792388923899239092391923929239392394923959239692397923989239992400924019240292403924049240592406924079240892409924109241192412924139241492415924169241792418924199242092421924229242392424924259242692427924289242992430924319243292433924349243592436924379243892439924409244192442924439244492445924469244792448924499245092451924529245392454924559245692457924589245992460924619246292463924649246592466924679246892469924709247192472924739247492475924769247792478924799248092481924829248392484924859248692487924889248992490924919249292493924949249592496924979249892499925009250192502925039250492505925069250792508925099251092511925129251392514925159251692517925189251992520925219252292523925249252592526925279252892529925309253192532925339253492535925369253792538925399254092541925429254392544925459254692547925489254992550925519255292553925549255592556925579255892559925609256192562925639256492565925669256792568925699257092571925729257392574925759257692577925789257992580925819258292583925849258592586925879258892589925909259192592925939259492595925969259792598925999260092601926029260392604926059260692607926089260992610926119261292613926149261592616926179261892619926209262192622926239262492625926269262792628926299263092631926329263392634926359263692637926389263992640926419264292643926449264592646926479264892649926509265192652926539265492655926569265792658926599266092661926629266392664926659266692667926689266992670926719267292673926749267592676926779267892679926809268192682926839268492685926869268792688926899269092691926929269392694926959269692697926989269992700927019270292703927049270592706927079270892709927109271192712927139271492715927169271792718927199272092721927229272392724927259272692727927289272992730927319273292733927349273592736927379273892739927409274192742927439274492745927469274792748927499275092751927529275392754927559275692757927589275992760927619276292763927649276592766927679276892769927709277192772927739277492775927769277792778927799278092781927829278392784927859278692787927889278992790927919279292793927949279592796927979279892799928009280192802928039280492805928069280792808928099281092811928129281392814928159281692817928189281992820928219282292823928249282592826928279282892829928309283192832928339283492835928369283792838928399284092841928429284392844928459284692847928489284992850928519285292853928549285592856928579285892859928609286192862928639286492865928669286792868928699287092871928729287392874928759287692877928789287992880928819288292883928849288592886928879288892889928909289192892928939289492895928969289792898928999290092901929029290392904929059290692907929089290992910929119291292913929149291592916929179291892919929209292192922929239292492925929269292792928929299293092931929329293392934929359293692937929389293992940929419294292943929449294592946929479294892949929509295192952929539295492955929569295792958929599296092961929629296392964929659296692967929689296992970929719297292973929749297592976929779297892979929809298192982929839298492985929869298792988929899299092991929929299392994929959299692997929989299993000930019300293003930049300593006930079300893009930109301193012930139301493015930169301793018930199302093021930229302393024930259302693027930289302993030930319303293033930349303593036930379303893039930409304193042930439304493045930469304793048930499305093051930529305393054930559305693057930589305993060930619306293063930649306593066930679306893069930709307193072930739307493075930769307793078930799308093081930829308393084930859308693087930889308993090930919309293093930949309593096930979309893099931009310193102931039310493105931069310793108931099311093111931129311393114931159311693117931189311993120931219312293123931249312593126931279312893129931309313193132931339313493135931369313793138931399314093141931429314393144931459314693147931489314993150931519315293153931549315593156931579315893159931609316193162931639316493165931669316793168931699317093171931729317393174931759317693177931789317993180931819318293183931849318593186931879318893189931909319193192931939319493195931969319793198931999320093201932029320393204932059320693207932089320993210932119321293213932149321593216932179321893219932209322193222932239322493225932269322793228932299323093231932329323393234932359323693237932389323993240932419324293243932449324593246932479324893249932509325193252932539325493255932569325793258932599326093261932629326393264932659326693267932689326993270932719327293273932749327593276932779327893279932809328193282932839328493285932869328793288932899329093291932929329393294932959329693297932989329993300933019330293303933049330593306933079330893309933109331193312933139331493315933169331793318933199332093321933229332393324933259332693327933289332993330933319333293333933349333593336933379333893339933409334193342933439334493345933469334793348933499335093351933529335393354933559335693357933589335993360933619336293363933649336593366933679336893369933709337193372933739337493375933769337793378933799338093381933829338393384933859338693387933889338993390933919339293393933949339593396933979339893399934009340193402934039340493405934069340793408934099341093411934129341393414934159341693417934189341993420934219342293423934249342593426934279342893429934309343193432934339343493435934369343793438934399344093441934429344393444934459344693447934489344993450934519345293453934549345593456934579345893459934609346193462934639346493465934669346793468934699347093471934729347393474934759347693477934789347993480934819348293483934849348593486934879348893489934909349193492934939349493495934969349793498934999350093501935029350393504935059350693507935089350993510935119351293513935149351593516935179351893519935209352193522935239352493525935269352793528935299353093531935329353393534935359353693537935389353993540935419354293543935449354593546935479354893549935509355193552935539355493555935569355793558935599356093561935629356393564935659356693567935689356993570935719357293573935749357593576935779357893579935809358193582935839358493585935869358793588935899359093591935929359393594935959359693597935989359993600936019360293603936049360593606936079360893609936109361193612936139361493615936169361793618936199362093621936229362393624936259362693627936289362993630936319363293633936349363593636936379363893639936409364193642936439364493645936469364793648936499365093651936529365393654936559365693657936589365993660936619366293663936649366593666936679366893669936709367193672936739367493675936769367793678936799368093681936829368393684936859368693687936889368993690936919369293693936949369593696936979369893699937009370193702937039370493705937069370793708937099371093711937129371393714937159371693717937189371993720937219372293723937249372593726937279372893729937309373193732937339373493735937369373793738937399374093741937429374393744937459374693747937489374993750937519375293753937549375593756937579375893759937609376193762937639376493765937669376793768937699377093771937729377393774937759377693777937789377993780937819378293783937849378593786937879378893789937909379193792937939379493795937969379793798937999380093801938029380393804938059380693807938089380993810938119381293813938149381593816938179381893819938209382193822938239382493825938269382793828938299383093831938329383393834938359383693837938389383993840938419384293843938449384593846938479384893849938509385193852938539385493855938569385793858938599386093861938629386393864938659386693867938689386993870938719387293873938749387593876938779387893879938809388193882938839388493885938869388793888938899389093891938929389393894938959389693897938989389993900939019390293903939049390593906939079390893909939109391193912939139391493915939169391793918939199392093921939229392393924939259392693927939289392993930939319393293933939349393593936939379393893939939409394193942939439394493945939469394793948939499395093951939529395393954939559395693957939589395993960939619396293963939649396593966939679396893969939709397193972939739397493975939769397793978939799398093981939829398393984939859398693987939889398993990939919399293993939949399593996939979399893999940009400194002940039400494005940069400794008940099401094011940129401394014940159401694017940189401994020940219402294023940249402594026940279402894029940309403194032940339403494035940369403794038940399404094041940429404394044940459404694047940489404994050940519405294053940549405594056940579405894059940609406194062940639406494065940669406794068940699407094071940729407394074940759407694077940789407994080940819408294083940849408594086940879408894089940909409194092940939409494095940969409794098940999410094101941029410394104941059410694107941089410994110941119411294113941149411594116941179411894119941209412194122941239412494125941269412794128941299413094131941329413394134941359413694137941389413994140941419414294143941449414594146941479414894149941509415194152941539415494155941569415794158941599416094161941629416394164941659416694167941689416994170941719417294173941749417594176941779417894179941809418194182941839418494185941869418794188941899419094191941929419394194941959419694197941989419994200942019420294203942049420594206942079420894209942109421194212942139421494215942169421794218942199422094221942229422394224942259422694227942289422994230942319423294233942349423594236942379423894239942409424194242942439424494245942469424794248942499425094251942529425394254942559425694257942589425994260942619426294263942649426594266942679426894269942709427194272942739427494275942769427794278942799428094281942829428394284942859428694287942889428994290942919429294293942949429594296942979429894299943009430194302943039430494305943069430794308943099431094311943129431394314943159431694317943189431994320943219432294323943249432594326943279432894329943309433194332943339433494335943369433794338943399434094341943429434394344943459434694347943489434994350943519435294353943549435594356943579435894359943609436194362943639436494365943669436794368943699437094371943729437394374943759437694377943789437994380943819438294383943849438594386943879438894389943909439194392943939439494395943969439794398943999440094401944029440394404944059440694407944089440994410944119441294413944149441594416944179441894419944209442194422944239442494425944269442794428944299443094431944329443394434944359443694437944389443994440944419444294443944449444594446944479444894449944509445194452944539445494455944569445794458944599446094461944629446394464944659446694467944689446994470944719447294473944749447594476944779447894479944809448194482944839448494485944869448794488944899449094491944929449394494944959449694497944989449994500945019450294503945049450594506945079450894509945109451194512945139451494515945169451794518945199452094521945229452394524945259452694527945289452994530945319453294533945349453594536945379453894539945409454194542945439454494545945469454794548945499455094551945529455394554945559455694557945589455994560945619456294563945649456594566945679456894569945709457194572945739457494575945769457794578945799458094581945829458394584945859458694587945889458994590945919459294593945949459594596945979459894599946009460194602946039460494605946069460794608946099461094611946129461394614946159461694617946189461994620946219462294623946249462594626946279462894629946309463194632946339463494635946369463794638946399464094641946429464394644946459464694647946489464994650946519465294653946549465594656946579465894659946609466194662946639466494665946669466794668946699467094671946729467394674946759467694677946789467994680946819468294683946849468594686946879468894689946909469194692946939469494695946969469794698946999470094701947029470394704947059470694707947089470994710947119471294713947149471594716947179471894719947209472194722947239472494725947269472794728947299473094731947329473394734947359473694737947389473994740947419474294743947449474594746947479474894749947509475194752947539475494755947569475794758947599476094761947629476394764947659476694767947689476994770947719477294773947749477594776947779477894779947809478194782947839478494785947869478794788947899479094791947929479394794947959479694797947989479994800948019480294803948049480594806948079480894809948109481194812948139481494815948169481794818948199482094821948229482394824948259482694827948289482994830948319483294833948349483594836948379483894839948409484194842948439484494845948469484794848948499485094851948529485394854948559485694857948589485994860948619486294863948649486594866948679486894869948709487194872948739487494875948769487794878948799488094881948829488394884948859488694887948889488994890948919489294893948949489594896948979489894899949009490194902949039490494905949069490794908949099491094911949129491394914949159491694917949189491994920949219492294923949249492594926949279492894929949309493194932949339493494935949369493794938949399494094941949429494394944949459494694947949489494994950949519495294953949549495594956949579495894959949609496194962949639496494965949669496794968949699497094971949729497394974949759497694977949789497994980949819498294983949849498594986949879498894989949909499194992949939499494995949969499794998949999500095001950029500395004950059500695007950089500995010950119501295013950149501595016950179501895019950209502195022950239502495025950269502795028950299503095031950329503395034950359503695037950389503995040950419504295043950449504595046950479504895049950509505195052950539505495055950569505795058950599506095061950629506395064950659506695067950689506995070950719507295073950749507595076950779507895079950809508195082950839508495085950869508795088950899509095091950929509395094950959509695097950989509995100951019510295103951049510595106951079510895109951109511195112951139511495115951169511795118951199512095121951229512395124951259512695127951289512995130951319513295133951349513595136951379513895139951409514195142951439514495145951469514795148951499515095151951529515395154951559515695157951589515995160951619516295163951649516595166951679516895169951709517195172951739517495175951769517795178951799518095181951829518395184951859518695187951889518995190951919519295193951949519595196951979519895199952009520195202952039520495205952069520795208952099521095211952129521395214952159521695217952189521995220952219522295223952249522595226952279522895229952309523195232952339523495235952369523795238952399524095241952429524395244952459524695247952489524995250952519525295253952549525595256952579525895259952609526195262952639526495265952669526795268952699527095271952729527395274952759527695277952789527995280952819528295283952849528595286952879528895289952909529195292952939529495295952969529795298952999530095301953029530395304953059530695307953089530995310953119531295313953149531595316953179531895319953209532195322953239532495325953269532795328953299533095331953329533395334953359533695337953389533995340953419534295343953449534595346953479534895349953509535195352953539535495355953569535795358953599536095361953629536395364953659536695367953689536995370953719537295373953749537595376953779537895379953809538195382953839538495385953869538795388953899539095391953929539395394953959539695397953989539995400954019540295403954049540595406954079540895409954109541195412954139541495415954169541795418954199542095421954229542395424954259542695427954289542995430954319543295433954349543595436954379543895439954409544195442954439544495445954469544795448954499545095451954529545395454954559545695457954589545995460954619546295463954649546595466954679546895469954709547195472954739547495475954769547795478954799548095481954829548395484954859548695487954889548995490954919549295493954949549595496954979549895499955009550195502955039550495505955069550795508955099551095511955129551395514955159551695517955189551995520955219552295523955249552595526955279552895529955309553195532955339553495535955369553795538955399554095541955429554395544955459554695547955489554995550955519555295553955549555595556955579555895559955609556195562955639556495565955669556795568955699557095571955729557395574955759557695577955789557995580955819558295583955849558595586955879558895589955909559195592955939559495595955969559795598955999560095601956029560395604956059560695607956089560995610956119561295613956149561595616956179561895619956209562195622956239562495625956269562795628956299563095631956329563395634956359563695637956389563995640956419564295643956449564595646956479564895649956509565195652956539565495655956569565795658956599566095661956629566395664956659566695667956689566995670956719567295673956749567595676956779567895679956809568195682956839568495685956869568795688956899569095691956929569395694956959569695697956989569995700957019570295703957049570595706957079570895709957109571195712957139571495715957169571795718957199572095721957229572395724957259572695727957289572995730957319573295733957349573595736957379573895739957409574195742957439574495745957469574795748957499575095751957529575395754957559575695757957589575995760957619576295763957649576595766957679576895769957709577195772957739577495775957769577795778957799578095781957829578395784957859578695787957889578995790957919579295793957949579595796957979579895799958009580195802958039580495805958069580795808958099581095811958129581395814958159581695817958189581995820958219582295823958249582595826958279582895829958309583195832958339583495835958369583795838958399584095841958429584395844958459584695847958489584995850958519585295853958549585595856958579585895859958609586195862958639586495865958669586795868958699587095871958729587395874958759587695877958789587995880958819588295883958849588595886958879588895889958909589195892958939589495895958969589795898958999590095901959029590395904959059590695907959089590995910959119591295913959149591595916959179591895919959209592195922959239592495925959269592795928959299593095931959329593395934959359593695937959389593995940959419594295943959449594595946959479594895949959509595195952959539595495955959569595795958959599596095961959629596395964959659596695967959689596995970959719597295973959749597595976959779597895979959809598195982959839598495985959869598795988959899599095991959929599395994959959599695997959989599996000960019600296003960049600596006960079600896009960109601196012960139601496015960169601796018960199602096021960229602396024960259602696027960289602996030960319603296033960349603596036960379603896039960409604196042960439604496045960469604796048960499605096051960529605396054960559605696057960589605996060960619606296063960649606596066960679606896069960709607196072960739607496075960769607796078960799608096081960829608396084960859608696087960889608996090960919609296093960949609596096960979609896099961009610196102961039610496105961069610796108961099611096111961129611396114961159611696117961189611996120961219612296123961249612596126961279612896129961309613196132961339613496135961369613796138961399614096141961429614396144961459614696147961489614996150961519615296153961549615596156961579615896159961609616196162961639616496165961669616796168961699617096171961729617396174961759617696177961789617996180961819618296183961849618596186961879618896189961909619196192961939619496195961969619796198961999620096201962029620396204962059620696207962089620996210962119621296213962149621596216962179621896219962209622196222962239622496225962269622796228962299623096231962329623396234962359623696237962389623996240962419624296243962449624596246962479624896249962509625196252962539625496255962569625796258962599626096261962629626396264962659626696267962689626996270962719627296273962749627596276962779627896279962809628196282962839628496285962869628796288962899629096291962929629396294962959629696297962989629996300963019630296303963049630596306963079630896309963109631196312963139631496315963169631796318963199632096321963229632396324963259632696327963289632996330963319633296333963349633596336963379633896339963409634196342963439634496345963469634796348963499635096351963529635396354963559635696357963589635996360963619636296363963649636596366963679636896369963709637196372963739637496375963769637796378963799638096381963829638396384963859638696387963889638996390963919639296393963949639596396963979639896399964009640196402964039640496405964069640796408964099641096411964129641396414964159641696417964189641996420964219642296423964249642596426964279642896429964309643196432964339643496435964369643796438964399644096441964429644396444964459644696447964489644996450964519645296453964549645596456964579645896459964609646196462964639646496465964669646796468964699647096471964729647396474964759647696477964789647996480964819648296483964849648596486964879648896489964909649196492964939649496495964969649796498964999650096501965029650396504965059650696507965089650996510965119651296513965149651596516965179651896519965209652196522965239652496525965269652796528965299653096531965329653396534965359653696537965389653996540965419654296543965449654596546965479654896549965509655196552965539655496555965569655796558965599656096561965629656396564965659656696567965689656996570965719657296573965749657596576965779657896579965809658196582965839658496585965869658796588965899659096591965929659396594965959659696597965989659996600966019660296603966049660596606966079660896609966109661196612966139661496615966169661796618966199662096621966229662396624966259662696627966289662996630966319663296633966349663596636966379663896639966409664196642966439664496645966469664796648966499665096651966529665396654966559665696657966589665996660966619666296663966649666596666966679666896669966709667196672966739667496675966769667796678966799668096681966829668396684966859668696687966889668996690966919669296693966949669596696966979669896699967009670196702967039670496705967069670796708967099671096711967129671396714967159671696717967189671996720967219672296723967249672596726967279672896729967309673196732967339673496735967369673796738967399674096741967429674396744967459674696747967489674996750967519675296753967549675596756967579675896759967609676196762967639676496765967669676796768967699677096771967729677396774967759677696777967789677996780967819678296783967849678596786967879678896789967909679196792967939679496795967969679796798967999680096801968029680396804968059680696807968089680996810968119681296813968149681596816968179681896819968209682196822968239682496825968269682796828968299683096831968329683396834968359683696837968389683996840968419684296843968449684596846968479684896849968509685196852968539685496855968569685796858968599686096861968629686396864968659686696867968689686996870968719687296873968749687596876968779687896879968809688196882968839688496885968869688796888968899689096891968929689396894968959689696897968989689996900969019690296903969049690596906969079690896909969109691196912969139691496915969169691796918969199692096921969229692396924969259692696927969289692996930969319693296933969349693596936969379693896939969409694196942969439694496945969469694796948969499695096951969529695396954969559695696957969589695996960969619696296963969649696596966969679696896969969709697196972969739697496975969769697796978969799698096981969829698396984969859698696987969889698996990969919699296993969949699596996969979699896999970009700197002970039700497005970069700797008970099701097011970129701397014970159701697017970189701997020970219702297023970249702597026970279702897029970309703197032970339703497035970369703797038970399704097041970429704397044970459704697047970489704997050970519705297053970549705597056970579705897059970609706197062970639706497065970669706797068970699707097071970729707397074970759707697077970789707997080970819708297083970849708597086970879708897089970909709197092970939709497095970969709797098970999710097101971029710397104971059710697107971089710997110971119711297113971149711597116971179711897119971209712197122971239712497125971269712797128971299713097131971329713397134971359713697137971389713997140971419714297143971449714597146971479714897149971509715197152971539715497155971569715797158971599716097161971629716397164971659716697167971689716997170971719717297173971749717597176971779717897179971809718197182971839718497185971869718797188971899719097191971929719397194971959719697197971989719997200972019720297203972049720597206972079720897209972109721197212972139721497215972169721797218972199722097221972229722397224972259722697227972289722997230972319723297233972349723597236972379723897239972409724197242972439724497245972469724797248972499725097251972529725397254972559725697257972589725997260972619726297263972649726597266972679726897269972709727197272972739727497275972769727797278972799728097281972829728397284972859728697287972889728997290972919729297293972949729597296972979729897299973009730197302973039730497305973069730797308973099731097311973129731397314973159731697317973189731997320973219732297323973249732597326973279732897329973309733197332973339733497335973369733797338973399734097341973429734397344973459734697347973489734997350973519735297353973549735597356973579735897359973609736197362973639736497365973669736797368973699737097371973729737397374973759737697377973789737997380973819738297383973849738597386973879738897389973909739197392973939739497395973969739797398973999740097401974029740397404974059740697407974089740997410974119741297413974149741597416974179741897419974209742197422974239742497425974269742797428974299743097431974329743397434974359743697437974389743997440974419744297443974449744597446974479744897449974509745197452974539745497455974569745797458974599746097461974629746397464974659746697467974689746997470974719747297473974749747597476974779747897479974809748197482974839748497485974869748797488974899749097491974929749397494974959749697497974989749997500975019750297503975049750597506975079750897509975109751197512975139751497515975169751797518975199752097521975229752397524975259752697527975289752997530975319753297533975349753597536975379753897539975409754197542975439754497545975469754797548975499755097551975529755397554975559755697557975589755997560975619756297563975649756597566975679756897569975709757197572975739757497575975769757797578975799758097581975829758397584975859758697587975889758997590975919759297593975949759597596975979759897599976009760197602976039760497605976069760797608976099761097611976129761397614976159761697617976189761997620976219762297623976249762597626976279762897629976309763197632976339763497635976369763797638976399764097641976429764397644976459764697647976489764997650976519765297653976549765597656976579765897659976609766197662976639766497665976669766797668976699767097671976729767397674976759767697677976789767997680976819768297683976849768597686976879768897689976909769197692976939769497695976969769797698976999770097701977029770397704977059770697707977089770997710977119771297713977149771597716977179771897719977209772197722977239772497725977269772797728977299773097731977329773397734977359773697737977389773997740977419774297743977449774597746977479774897749977509775197752977539775497755977569775797758977599776097761977629776397764977659776697767977689776997770977719777297773977749777597776977779777897779977809778197782977839778497785977869778797788977899779097791977929779397794977959779697797977989779997800978019780297803978049780597806978079780897809978109781197812978139781497815978169781797818978199782097821978229782397824978259782697827978289782997830978319783297833978349783597836978379783897839978409784197842978439784497845978469784797848978499785097851978529785397854978559785697857978589785997860978619786297863978649786597866978679786897869978709787197872978739787497875978769787797878978799788097881978829788397884978859788697887978889788997890978919789297893978949789597896978979789897899979009790197902979039790497905979069790797908979099791097911979129791397914979159791697917979189791997920979219792297923979249792597926979279792897929979309793197932979339793497935979369793797938979399794097941979429794397944979459794697947979489794997950979519795297953979549795597956979579795897959979609796197962979639796497965979669796797968979699797097971979729797397974979759797697977979789797997980979819798297983979849798597986979879798897989979909799197992979939799497995979969799797998979999800098001980029800398004980059800698007980089800998010980119801298013980149801598016980179801898019980209802198022980239802498025980269802798028980299803098031980329803398034980359803698037980389803998040980419804298043980449804598046980479804898049980509805198052980539805498055980569805798058980599806098061980629806398064980659806698067980689806998070980719807298073980749807598076980779807898079980809808198082980839808498085980869808798088980899809098091980929809398094980959809698097980989809998100981019810298103981049810598106981079810898109981109811198112981139811498115981169811798118981199812098121981229812398124981259812698127981289812998130981319813298133981349813598136981379813898139981409814198142981439814498145981469814798148981499815098151981529815398154981559815698157981589815998160981619816298163981649816598166981679816898169981709817198172981739817498175981769817798178981799818098181981829818398184981859818698187981889818998190981919819298193981949819598196981979819898199982009820198202982039820498205982069820798208982099821098211982129821398214982159821698217982189821998220982219822298223982249822598226982279822898229982309823198232982339823498235982369823798238982399824098241982429824398244982459824698247982489824998250982519825298253982549825598256982579825898259982609826198262982639826498265982669826798268982699827098271982729827398274982759827698277982789827998280982819828298283982849828598286982879828898289982909829198292982939829498295982969829798298982999830098301983029830398304983059830698307983089830998310983119831298313983149831598316983179831898319983209832198322983239832498325983269832798328983299833098331983329833398334983359833698337983389833998340983419834298343983449834598346983479834898349983509835198352983539835498355983569835798358983599836098361983629836398364983659836698367983689836998370983719837298373983749837598376983779837898379983809838198382983839838498385983869838798388983899839098391983929839398394983959839698397983989839998400984019840298403984049840598406984079840898409984109841198412984139841498415984169841798418984199842098421984229842398424984259842698427984289842998430984319843298433984349843598436984379843898439984409844198442984439844498445984469844798448984499845098451984529845398454984559845698457984589845998460984619846298463984649846598466984679846898469984709847198472984739847498475984769847798478984799848098481984829848398484984859848698487984889848998490984919849298493984949849598496984979849898499985009850198502985039850498505985069850798508985099851098511985129851398514985159851698517985189851998520985219852298523985249852598526985279852898529985309853198532985339853498535985369853798538985399854098541985429854398544985459854698547985489854998550985519855298553985549855598556985579855898559985609856198562985639856498565985669856798568985699857098571985729857398574985759857698577985789857998580985819858298583985849858598586985879858898589985909859198592985939859498595985969859798598985999860098601986029860398604986059860698607986089860998610986119861298613986149861598616986179861898619986209862198622986239862498625986269862798628986299863098631986329863398634986359863698637986389863998640986419864298643986449864598646986479864898649986509865198652986539865498655986569865798658986599866098661986629866398664986659866698667986689866998670986719867298673986749867598676986779867898679986809868198682986839868498685986869868798688986899869098691986929869398694986959869698697986989869998700987019870298703987049870598706987079870898709987109871198712987139871498715987169871798718987199872098721987229872398724987259872698727987289872998730987319873298733987349873598736987379873898739987409874198742987439874498745987469874798748987499875098751987529875398754987559875698757987589875998760987619876298763987649876598766987679876898769987709877198772987739877498775987769877798778987799878098781987829878398784987859878698787987889878998790987919879298793987949879598796987979879898799988009880198802988039880498805988069880798808988099881098811988129881398814988159881698817988189881998820988219882298823988249882598826988279882898829988309883198832988339883498835988369883798838988399884098841988429884398844988459884698847988489884998850988519885298853988549885598856988579885898859988609886198862988639886498865988669886798868988699887098871988729887398874988759887698877988789887998880988819888298883988849888598886988879888898889988909889198892988939889498895988969889798898988999890098901989029890398904989059890698907989089890998910989119891298913989149891598916989179891898919989209892198922989239892498925989269892798928989299893098931989329893398934989359893698937989389893998940989419894298943989449894598946989479894898949989509895198952989539895498955989569895798958989599896098961989629896398964989659896698967989689896998970989719897298973989749897598976989779897898979989809898198982989839898498985989869898798988989899899098991989929899398994989959899698997989989899999000990019900299003990049900599006990079900899009990109901199012990139901499015990169901799018990199902099021990229902399024990259902699027990289902999030990319903299033990349903599036990379903899039990409904199042990439904499045990469904799048990499905099051990529905399054990559905699057990589905999060990619906299063990649906599066990679906899069990709907199072990739907499075990769907799078990799908099081990829908399084990859908699087990889908999090990919909299093990949909599096990979909899099991009910199102991039910499105991069910799108991099911099111991129911399114991159911699117991189911999120991219912299123991249912599126991279912899129991309913199132991339913499135991369913799138991399914099141991429914399144991459914699147991489914999150991519915299153991549915599156991579915899159991609916199162991639916499165991669916799168991699917099171991729917399174991759917699177991789917999180991819918299183991849918599186991879918899189991909919199192991939919499195991969919799198991999920099201992029920399204992059920699207992089920999210992119921299213992149921599216992179921899219992209922199222992239922499225992269922799228992299923099231992329923399234992359923699237992389923999240992419924299243992449924599246992479924899249992509925199252992539925499255992569925799258992599926099261992629926399264992659926699267992689926999270992719927299273992749927599276992779927899279992809928199282992839928499285992869928799288992899929099291992929929399294992959929699297992989929999300993019930299303993049930599306993079930899309993109931199312993139931499315993169931799318993199932099321993229932399324993259932699327993289932999330993319933299333993349933599336993379933899339993409934199342993439934499345993469934799348993499935099351993529935399354993559935699357993589935999360993619936299363993649936599366993679936899369993709937199372993739937499375993769937799378993799938099381993829938399384993859938699387993889938999390993919939299393993949939599396993979939899399994009940199402994039940499405994069940799408994099941099411994129941399414994159941699417994189941999420994219942299423994249942599426994279942899429994309943199432994339943499435994369943799438994399944099441994429944399444994459944699447994489944999450994519945299453994549945599456994579945899459994609946199462994639946499465994669946799468994699947099471994729947399474994759947699477994789947999480994819948299483994849948599486994879948899489994909949199492994939949499495994969949799498994999950099501995029950399504995059950699507995089950999510995119951299513995149951599516995179951899519995209952199522995239952499525995269952799528995299953099531995329953399534995359953699537995389953999540995419954299543995449954599546995479954899549995509955199552995539955499555995569955799558995599956099561995629956399564995659956699567995689956999570995719957299573995749957599576995779957899579995809958199582995839958499585995869958799588995899959099591995929959399594995959959699597995989959999600996019960299603996049960599606996079960899609996109961199612996139961499615996169961799618996199962099621996229962399624996259962699627996289962999630996319963299633996349963599636996379963899639996409964199642996439964499645996469964799648996499965099651996529965399654996559965699657996589965999660996619966299663996649966599666996679966899669996709967199672996739967499675996769967799678996799968099681996829968399684996859968699687996889968999690996919969299693996949969599696996979969899699997009970199702997039970499705997069970799708997099971099711997129971399714997159971699717997189971999720997219972299723997249972599726997279972899729997309973199732997339973499735997369973799738997399974099741997429974399744997459974699747997489974999750997519975299753997549975599756997579975899759997609976199762997639976499765997669976799768997699977099771997729977399774997759977699777997789977999780997819978299783997849978599786997879978899789997909979199792997939979499795997969979799798997999980099801998029980399804998059980699807998089980999810998119981299813998149981599816998179981899819998209982199822998239982499825998269982799828998299983099831998329983399834998359983699837998389983999840998419984299843998449984599846998479984899849998509985199852998539985499855998569985799858998599986099861998629986399864998659986699867998689986999870998719987299873998749987599876998779987899879998809988199882998839988499885998869988799888998899989099891998929989399894998959989699897998989989999900999019990299903999049990599906999079990899909999109991199912999139991499915999169991799918999199992099921999229992399924999259992699927999289992999930999319993299933999349993599936999379993899939999409994199942999439994499945999469994799948999499995099951999529995399954999559995699957999589995999960999619996299963999649996599966999679996899969999709997199972999739997499975999769997799978999799998099981999829998399984999859998699987999889998999990999919999299993999949999599996999979999899999100000100001100002100003100004100005100006100007100008100009100010100011100012100013100014100015100016100017100018100019100020100021100022100023100024100025100026100027100028100029100030100031100032100033100034100035100036100037100038100039100040100041100042100043100044100045100046100047100048100049100050100051100052100053100054100055100056100057100058100059100060100061100062100063100064100065100066100067100068100069100070100071100072100073100074100075100076100077100078100079100080100081100082100083100084100085100086100087100088100089100090100091100092100093100094100095100096100097100098100099100100100101100102100103100104100105100106100107100108100109100110100111100112100113100114100115100116100117100118100119100120100121100122100123100124100125100126100127100128100129100130100131100132100133100134100135100136100137100138100139100140100141100142100143100144100145100146100147100148100149100150100151100152100153100154100155100156100157100158100159100160100161100162100163100164100165100166100167100168100169100170100171100172100173100174100175100176100177100178100179100180100181100182100183100184100185100186100187100188100189100190100191100192100193100194100195100196100197100198100199100200100201100202100203100204100205100206100207100208100209100210100211100212100213100214100215100216100217100218100219100220100221100222100223100224100225100226100227100228100229100230100231100232100233100234100235100236100237100238100239100240100241100242100243100244100245100246100247100248100249100250100251100252100253100254100255100256100257100258100259100260100261100262100263100264100265100266100267100268100269100270100271100272100273100274100275100276100277100278100279100280100281100282100283100284100285100286100287100288100289100290100291100292100293100294100295100296100297100298100299100300100301100302100303100304100305100306100307100308100309100310100311100312100313100314100315100316100317100318100319100320100321100322100323100324100325100326100327100328100329100330100331100332100333100334100335100336100337100338100339100340100341100342100343100344100345100346100347100348100349100350100351100352100353100354100355100356100357100358100359100360100361100362100363100364100365100366100367100368100369100370100371100372100373100374100375100376100377100378100379100380100381100382100383100384100385100386100387100388100389100390100391100392100393100394100395100396100397100398100399100400100401100402100403100404100405100406100407100408100409100410100411100412100413100414100415100416100417100418100419100420100421100422100423100424100425100426100427100428100429100430100431100432100433100434100435100436100437100438100439100440100441100442100443100444100445100446100447100448100449100450100451100452100453100454100455100456100457100458100459100460100461100462100463100464100465100466100467100468100469100470100471100472100473100474100475100476100477100478100479100480100481100482100483100484100485100486100487100488100489100490100491100492100493100494100495100496100497100498100499100500100501100502100503100504100505100506100507100508100509100510100511100512100513100514100515100516100517100518100519100520100521100522100523100524100525100526100527100528100529100530100531100532100533100534100535100536100537100538100539100540100541100542100543100544100545100546100547100548100549100550100551100552100553100554100555100556100557100558100559100560100561100562100563100564100565100566100567100568100569100570100571100572100573100574100575100576100577100578100579100580100581100582100583100584100585100586100587100588100589100590100591100592100593100594100595100596100597100598100599100600100601100602100603100604100605100606100607100608100609100610100611100612100613100614100615100616100617100618100619100620100621100622100623100624100625100626100627100628100629100630100631100632100633100634100635100636100637100638100639100640100641100642100643100644100645100646100647100648100649100650100651100652100653100654100655100656100657100658100659100660100661100662100663100664100665100666100667100668100669100670100671100672100673100674100675100676100677100678100679100680100681100682100683100684100685100686100687100688100689100690100691100692100693100694100695100696100697100698100699100700100701100702100703100704100705100706100707100708100709100710100711100712100713100714100715100716100717100718100719100720100721100722100723100724100725100726100727100728100729100730100731100732100733100734100735100736100737100738100739100740100741100742100743100744100745100746100747100748100749100750100751100752100753100754100755100756100757100758100759100760100761100762100763100764100765100766100767100768100769100770100771100772100773100774100775100776100777100778100779100780100781100782100783100784100785100786100787100788100789100790100791100792100793100794100795100796100797100798100799100800100801100802100803100804100805100806100807100808100809100810100811100812100813100814100815100816100817100818100819100820100821100822100823100824100825100826100827100828100829100830100831100832100833100834100835100836100837100838100839100840100841100842100843100844100845100846100847100848100849100850100851100852100853100854100855100856100857100858100859100860100861100862100863100864100865100866100867100868100869100870100871100872100873100874100875100876100877100878100879100880100881100882100883100884100885100886100887100888100889100890100891100892100893100894100895100896100897100898100899100900100901100902100903100904100905100906100907100908100909100910100911100912100913100914100915100916100917100918100919100920100921100922100923100924100925100926100927100928100929100930100931100932100933100934100935100936100937100938100939100940100941100942100943100944100945100946100947100948100949100950100951100952100953100954100955100956100957100958100959100960100961100962100963100964100965100966100967100968100969100970100971100972100973100974100975100976100977100978100979100980100981100982100983100984100985100986100987100988100989100990100991100992100993100994100995100996100997100998100999101000101001101002101003101004101005101006101007101008101009101010101011101012101013101014101015101016101017101018101019101020101021101022101023101024101025101026101027101028101029101030101031101032101033101034101035101036101037101038101039101040101041101042101043101044101045101046101047101048101049101050101051101052101053101054101055101056101057101058101059101060101061101062101063101064101065101066101067101068101069101070101071101072101073101074101075101076101077101078101079101080101081101082101083101084101085101086101087101088101089101090101091101092101093101094101095101096101097101098101099101100101101101102101103101104101105101106101107101108101109101110101111101112101113101114101115101116101117101118101119101120101121101122101123101124101125101126101127101128101129101130101131101132101133101134101135101136101137101138101139101140101141101142101143101144101145101146101147101148101149101150101151101152101153101154101155101156101157101158101159101160101161101162101163101164101165101166101167101168101169101170101171101172101173101174101175101176101177101178101179101180101181101182101183101184101185101186101187101188101189101190101191101192101193101194101195101196101197101198101199101200101201101202101203101204101205101206101207101208101209101210101211101212101213101214101215101216101217101218101219101220101221101222101223101224101225101226101227101228101229101230101231101232101233101234101235101236101237101238101239101240101241101242101243101244101245101246101247101248101249101250101251101252101253101254101255101256101257101258101259101260101261101262101263101264101265101266101267101268101269101270101271101272101273101274101275101276101277101278101279101280101281101282101283101284101285101286101287101288101289101290101291101292101293101294101295101296101297101298101299101300101301101302101303101304101305101306101307101308101309101310101311101312101313101314101315101316101317101318101319101320101321101322101323101324101325101326101327101328101329101330101331101332101333101334101335101336101337101338101339101340101341101342101343101344101345101346101347101348101349101350101351101352101353101354101355101356101357101358101359101360101361101362101363101364101365101366101367101368101369101370101371101372101373101374101375101376101377101378101379101380101381101382101383101384101385101386101387101388101389101390101391101392101393101394101395101396101397101398101399101400101401101402101403101404101405101406101407101408101409101410101411101412101413101414101415101416101417101418101419101420101421101422101423101424101425101426101427101428101429101430101431101432101433101434101435101436101437101438101439101440101441101442101443101444101445101446101447101448101449101450101451101452101453101454101455101456101457101458101459101460101461101462101463101464101465101466101467101468101469101470101471101472101473101474101475101476101477101478101479101480101481101482101483101484101485101486101487101488101489101490101491101492101493101494101495101496101497101498101499101500101501101502101503101504101505101506101507101508101509101510101511101512101513101514101515101516101517101518101519101520101521101522101523101524101525101526101527101528101529101530101531101532101533101534101535101536101537101538101539101540101541101542101543101544101545101546101547101548101549101550101551101552101553101554101555101556101557101558101559101560101561101562101563101564101565101566101567101568101569101570101571101572101573101574101575101576101577101578101579101580101581101582101583101584101585101586101587101588101589101590101591101592101593101594101595101596101597101598101599101600101601101602101603101604101605101606101607101608101609101610101611101612101613101614101615101616101617101618101619101620101621101622101623101624101625101626101627101628101629101630101631101632101633101634101635101636101637101638101639101640101641101642101643101644101645101646101647101648101649101650101651101652101653101654101655101656101657101658101659101660101661101662101663101664101665101666101667101668101669101670101671101672101673101674101675101676101677101678101679101680101681101682101683101684101685101686101687101688101689101690101691101692101693101694101695101696101697101698101699101700101701101702101703101704101705101706101707101708101709101710101711101712101713101714101715101716101717101718101719101720101721101722101723101724101725101726101727101728101729101730101731101732101733101734101735101736101737101738101739101740101741101742101743101744101745101746101747101748101749101750101751101752101753101754101755101756101757101758101759101760101761101762101763101764101765101766101767101768101769101770101771101772101773101774101775101776101777101778101779101780101781101782101783101784101785101786101787101788101789101790101791101792101793101794101795101796101797101798101799101800101801101802101803101804101805101806101807101808101809101810101811101812101813101814101815101816101817101818101819101820101821101822101823101824101825101826101827101828101829101830101831101832101833101834101835101836101837101838101839101840101841101842101843101844101845101846101847101848101849101850101851101852101853101854101855101856101857101858101859101860101861101862101863101864101865101866101867101868101869101870101871101872101873101874101875101876101877101878101879101880101881101882101883101884101885101886101887101888101889101890101891101892101893101894101895101896101897101898101899101900101901101902101903101904101905101906101907101908101909101910101911101912101913101914101915101916101917101918101919101920101921101922101923101924101925101926101927101928101929101930101931101932101933101934101935101936101937101938101939101940101941101942101943101944101945101946101947101948101949101950101951101952101953101954101955101956101957101958101959101960101961101962101963101964101965101966101967101968101969101970101971101972101973101974101975101976101977101978101979101980101981101982101983101984101985101986101987101988101989101990101991101992101993101994101995101996101997101998101999102000102001102002102003102004102005102006102007102008102009102010102011102012102013102014102015102016102017102018102019102020102021102022102023102024102025102026102027102028102029102030102031102032102033102034102035102036102037102038102039102040102041102042102043102044102045102046102047102048102049102050102051102052102053102054102055102056102057102058102059102060102061102062102063102064102065102066102067102068102069102070102071102072102073102074102075102076102077102078102079102080102081102082102083102084102085102086102087102088102089102090102091102092102093102094102095102096102097102098102099102100102101102102102103102104102105102106102107102108102109102110102111102112102113102114102115102116102117102118102119102120102121102122102123102124102125102126102127102128102129102130102131102132102133102134102135102136102137102138102139102140102141102142102143102144102145102146102147102148102149102150102151102152102153102154102155102156102157102158102159102160102161102162102163102164102165102166102167102168102169102170102171102172102173102174102175102176102177102178102179102180102181102182102183102184102185102186102187102188102189102190102191102192102193102194102195102196102197102198102199102200102201102202102203102204102205102206102207102208102209102210102211102212102213102214102215102216102217102218102219102220102221102222102223102224102225102226102227102228102229102230102231102232102233102234102235102236102237102238102239102240102241102242102243102244102245102246102247102248102249102250102251102252102253102254102255102256102257102258102259102260102261102262102263102264102265102266102267102268102269102270102271102272102273102274102275102276102277102278102279102280102281102282102283102284102285102286102287102288102289102290102291102292102293102294102295102296102297102298102299102300102301102302102303102304102305102306102307102308102309102310102311102312102313102314102315102316102317102318102319102320102321102322102323102324102325102326102327102328102329102330102331102332102333102334102335102336102337102338102339102340102341102342102343102344102345102346102347102348102349102350102351102352102353102354102355102356102357102358102359102360102361102362102363102364102365102366102367102368102369102370102371102372102373102374102375102376102377102378102379102380102381102382102383102384102385102386102387102388102389102390102391102392102393102394102395102396102397102398102399102400102401102402102403102404102405102406102407102408102409102410102411102412102413102414102415102416102417102418102419102420102421102422102423102424102425102426102427102428102429102430102431102432102433102434102435102436102437102438102439102440102441102442102443102444102445102446102447102448102449102450102451102452102453102454102455102456102457102458102459102460102461102462102463102464102465102466102467102468102469102470102471102472102473102474102475102476102477102478102479102480102481102482102483102484102485102486102487102488102489102490102491102492102493102494102495102496102497102498102499102500102501102502102503102504102505102506102507102508102509102510102511102512102513102514102515102516102517102518102519102520102521102522102523102524102525102526102527102528102529102530102531102532102533102534102535102536102537102538102539102540102541102542102543102544102545102546102547102548102549102550102551102552102553102554102555102556102557102558102559102560102561102562102563102564102565102566102567102568102569102570102571102572102573102574102575102576102577102578102579102580102581102582102583102584102585102586102587102588102589102590102591102592102593102594102595102596102597102598102599102600102601102602102603102604102605102606102607102608102609102610102611102612102613102614102615102616102617102618102619102620102621102622102623102624102625102626102627102628102629102630102631102632102633102634102635102636102637102638102639102640102641102642102643102644102645102646102647102648102649102650102651102652102653102654102655102656102657102658102659102660102661102662102663102664102665102666102667102668102669102670102671102672102673102674102675102676102677102678102679102680102681102682102683102684102685102686102687102688102689102690102691102692102693102694102695102696102697102698102699102700102701102702102703102704102705102706102707102708102709102710102711102712102713102714102715102716102717102718102719102720102721102722102723102724102725102726102727102728102729102730102731102732102733102734102735102736102737102738102739102740102741102742102743102744102745102746102747102748102749102750102751102752102753102754102755102756102757102758102759102760102761102762102763102764102765102766102767102768102769102770102771102772102773102774102775102776102777102778102779102780102781102782102783102784102785102786102787102788102789102790102791102792102793102794102795102796102797102798102799102800102801102802102803102804102805102806102807102808102809102810102811102812102813102814102815102816102817102818102819102820102821102822102823102824102825102826102827102828102829102830102831102832102833102834102835102836102837102838102839102840102841102842102843102844102845102846102847102848102849102850102851102852102853102854102855102856102857102858102859102860102861102862102863102864102865102866102867102868102869102870102871102872102873102874102875102876102877102878102879102880102881102882102883102884102885102886102887102888102889102890102891102892102893102894102895102896102897102898102899102900102901102902102903102904102905102906102907102908102909102910102911102912102913102914102915102916102917102918102919102920102921102922102923102924102925102926102927102928102929102930102931102932102933102934102935102936102937102938102939102940102941102942102943102944102945102946102947102948102949102950102951102952102953102954102955102956102957102958102959102960102961102962102963102964102965102966102967102968102969102970102971102972102973102974102975102976102977102978102979102980102981102982102983102984102985102986102987102988102989102990102991102992102993102994102995102996102997102998102999103000103001103002103003103004103005103006103007103008103009103010103011103012103013103014103015103016103017103018103019103020103021103022103023103024103025103026103027103028103029103030103031103032103033103034103035103036103037103038103039103040103041103042103043103044103045103046103047103048103049103050103051103052103053103054103055103056103057103058103059103060103061103062103063103064103065103066103067103068103069103070103071103072103073103074103075103076103077103078103079103080103081103082103083103084103085103086103087103088103089103090103091103092103093103094103095103096103097103098103099103100103101103102103103103104103105103106103107103108103109103110103111103112103113103114103115103116103117103118103119103120103121103122103123103124103125103126103127103128103129103130103131103132103133103134103135103136103137103138103139103140103141103142103143103144103145103146103147103148103149103150103151103152103153103154103155103156103157103158103159103160103161103162103163103164103165103166103167103168103169103170103171103172103173103174103175103176103177103178103179103180103181103182103183103184103185103186103187103188103189103190103191103192103193103194103195103196103197103198103199103200103201103202103203103204103205103206103207103208103209103210103211103212103213103214103215103216103217103218103219103220103221103222103223103224103225103226103227103228103229103230103231103232103233103234103235103236103237103238103239103240103241103242103243103244103245103246103247103248103249103250103251103252103253103254103255103256103257103258103259103260103261103262103263103264103265103266103267103268103269103270103271103272103273103274103275103276103277103278103279103280103281103282103283103284103285103286103287103288103289103290103291103292103293103294103295103296103297103298103299103300103301103302103303103304103305103306103307103308103309103310103311103312103313103314103315103316103317103318103319103320103321103322103323103324103325103326103327103328103329103330103331103332103333103334103335103336103337103338103339103340103341103342103343103344103345103346103347103348103349103350103351103352103353103354103355103356103357103358103359103360103361103362103363103364103365103366103367103368103369103370103371103372103373103374103375103376103377103378103379103380103381103382103383103384103385103386103387103388103389103390103391103392103393103394103395103396103397103398103399103400103401103402103403103404103405103406103407103408103409103410103411103412103413103414103415103416103417103418103419103420103421103422103423103424103425103426103427103428103429103430103431103432103433103434103435103436103437103438103439103440103441103442103443103444103445103446103447103448103449103450103451103452103453103454103455103456103457103458103459103460103461103462103463103464103465103466103467103468103469103470103471103472103473103474103475103476103477103478103479103480103481103482103483103484103485103486103487103488103489103490103491103492103493103494103495103496103497103498103499103500103501103502103503103504103505103506103507103508103509103510103511103512103513103514103515103516103517103518103519103520103521103522103523103524103525103526103527103528103529103530103531103532103533103534103535103536103537103538103539103540103541103542103543103544103545103546103547103548103549103550103551103552103553103554103555103556103557103558103559103560103561103562103563103564103565103566103567103568103569103570103571103572103573103574103575103576103577103578103579103580103581103582103583103584103585103586103587103588103589103590103591103592103593103594103595103596103597103598103599103600103601103602103603103604103605103606103607103608103609103610103611103612103613103614103615103616103617103618103619103620103621103622103623103624103625103626103627103628103629103630103631103632103633103634103635103636103637103638103639103640103641103642103643103644103645103646103647103648103649103650103651103652103653103654103655103656103657103658103659103660103661103662103663103664103665103666103667103668103669103670103671103672103673103674103675103676103677103678103679103680103681103682103683103684103685103686103687103688103689103690103691103692103693103694103695103696103697103698103699103700103701103702103703103704103705103706103707103708103709103710103711103712103713103714103715103716103717103718103719103720103721103722103723103724103725103726103727103728103729103730103731103732103733103734103735103736103737103738103739103740103741103742103743103744103745103746103747103748103749103750103751103752103753103754103755103756103757103758103759103760103761103762103763103764103765103766103767103768103769103770103771103772103773103774103775103776103777103778103779103780103781103782103783103784103785103786103787103788103789103790103791103792103793103794103795103796103797103798103799103800103801103802103803103804103805103806103807103808103809103810103811103812103813103814103815103816103817103818103819103820103821103822103823103824103825103826103827103828103829103830103831103832103833103834103835103836103837103838103839103840103841103842103843103844103845103846103847103848103849103850103851103852103853103854103855103856103857103858103859103860103861103862103863103864103865103866103867103868103869103870103871103872103873103874103875103876103877103878103879103880103881103882103883103884103885103886103887103888103889103890103891103892103893103894103895103896103897103898103899103900103901103902103903103904103905103906103907103908103909103910103911103912103913103914103915103916103917103918103919103920103921103922103923103924103925103926103927103928103929103930103931103932103933103934103935103936103937103938103939103940103941103942103943103944103945103946103947103948103949103950103951103952103953103954103955103956103957103958103959103960103961103962103963103964103965103966103967103968103969103970103971103972103973103974103975103976103977103978103979103980103981103982103983103984103985103986103987103988103989103990103991103992103993103994103995103996103997103998103999104000104001104002104003104004104005104006104007104008104009104010104011104012104013104014104015104016104017104018104019104020104021104022104023104024104025104026104027104028104029104030104031104032104033104034104035104036104037104038104039104040104041104042104043104044104045104046104047104048104049104050104051104052104053104054104055104056104057104058104059104060104061104062104063104064104065104066104067104068104069104070104071104072104073104074104075104076104077104078104079104080104081104082104083104084104085104086104087104088104089104090104091104092104093104094104095104096104097104098104099104100104101104102104103104104104105104106104107104108104109104110104111104112104113104114104115104116104117104118104119104120104121104122104123104124104125104126104127104128104129104130104131104132104133104134104135104136104137104138104139104140104141104142104143104144104145104146104147104148104149104150104151104152104153104154104155104156104157104158104159104160104161104162104163104164104165104166104167104168104169104170104171104172104173104174104175104176104177104178104179104180104181104182104183104184104185104186104187104188104189104190104191104192104193104194104195104196104197104198104199104200104201104202104203104204104205104206104207104208104209104210104211104212104213104214104215104216104217104218104219104220104221104222104223104224104225104226104227104228104229104230104231104232104233104234104235104236104237104238104239104240104241104242104243104244104245104246104247104248104249104250104251104252104253104254104255104256104257104258104259104260104261104262104263104264104265104266104267104268104269104270104271104272104273104274104275104276104277104278104279104280104281104282104283104284104285104286104287104288104289104290104291104292104293104294104295104296104297104298104299104300104301104302104303104304104305104306104307104308104309104310104311104312104313104314104315104316104317104318104319104320104321104322104323104324104325104326104327104328104329104330104331104332104333104334104335104336104337104338104339104340104341104342104343104344104345104346104347104348104349104350104351104352104353104354104355104356104357104358104359104360104361104362104363104364104365104366104367104368104369104370104371104372104373104374104375104376104377104378104379104380104381104382104383104384104385104386104387104388104389104390104391104392104393104394104395104396104397104398104399104400104401104402104403104404104405104406104407104408104409104410104411104412104413104414104415104416104417104418104419104420104421104422104423104424104425104426104427104428104429104430104431104432104433104434104435104436104437104438104439104440104441104442104443104444104445104446104447104448104449104450104451104452104453104454104455104456104457104458104459104460104461104462104463104464104465104466104467104468104469104470104471104472104473104474104475104476104477104478104479104480104481104482104483104484104485104486104487104488104489104490104491104492104493104494104495104496104497104498104499104500104501104502104503104504104505104506104507104508104509104510104511104512104513104514104515104516104517104518104519104520104521104522104523104524104525104526104527104528104529104530104531104532104533104534104535104536104537104538104539104540104541104542104543104544104545104546104547104548104549104550104551104552104553104554104555104556104557104558104559104560104561104562104563104564104565104566104567104568104569104570104571104572104573104574104575104576104577104578104579104580104581104582104583104584104585104586104587104588104589104590104591104592104593104594104595104596104597104598104599104600104601104602104603104604104605104606104607104608104609104610104611104612104613104614104615104616104617104618104619104620104621104622104623104624104625104626104627104628104629104630104631104632104633104634104635104636104637104638104639104640104641104642104643104644104645104646104647104648104649104650104651104652104653104654104655104656104657104658104659104660104661104662104663104664104665104666104667104668104669104670104671104672104673104674104675104676104677104678104679104680104681104682104683104684104685104686104687104688104689104690104691104692104693104694104695104696104697104698104699104700104701104702104703104704104705104706104707104708104709104710104711104712104713104714104715104716104717104718104719104720104721104722104723104724104725104726104727104728104729104730104731104732104733104734104735104736104737104738104739104740104741104742104743104744104745104746104747104748104749104750104751104752104753104754104755104756104757104758104759104760104761104762104763104764104765104766104767104768104769104770104771104772104773104774104775104776104777104778104779104780104781104782104783104784104785104786104787104788104789104790104791104792104793104794104795104796104797104798104799104800104801104802104803104804104805104806104807104808104809104810104811104812104813104814104815104816104817104818104819104820104821104822104823104824104825104826104827104828104829104830104831104832104833104834104835104836104837104838104839104840104841104842104843104844104845104846104847104848104849104850104851104852104853104854104855104856104857104858104859104860104861104862104863104864104865104866104867104868104869104870104871104872104873104874104875104876104877104878104879104880104881104882104883104884104885104886104887104888104889104890104891104892104893104894104895104896104897104898104899104900104901104902104903104904104905104906104907104908104909104910104911104912104913104914104915104916104917104918104919104920104921104922104923104924104925104926104927104928104929104930104931104932104933104934104935104936104937104938104939104940104941104942104943104944104945104946104947104948104949104950104951104952104953104954104955104956104957104958104959104960104961104962104963104964104965104966104967104968104969104970104971104972104973104974104975104976104977104978104979104980104981104982104983104984104985104986104987104988104989104990104991104992104993104994104995104996104997104998104999105000105001105002105003105004105005105006105007105008105009105010105011105012105013105014105015105016105017105018105019105020105021105022105023105024105025105026105027105028105029105030105031105032105033105034105035105036105037105038105039105040105041105042105043105044105045105046105047105048105049105050105051105052105053105054105055105056105057105058105059105060105061105062105063105064105065105066105067105068105069105070105071105072105073105074105075105076105077105078105079105080105081105082105083105084105085105086105087105088105089105090105091105092105093105094105095105096105097105098105099105100105101105102105103105104105105105106105107105108105109105110105111105112105113105114105115105116105117105118105119105120105121105122105123105124105125105126105127105128105129105130105131105132105133105134105135105136105137105138105139105140105141105142105143105144105145105146105147105148105149105150105151105152105153105154105155105156105157105158105159105160105161105162105163105164105165105166105167105168105169105170105171105172105173105174105175105176105177105178105179105180105181105182105183105184105185105186105187105188105189105190105191105192105193105194105195105196105197105198105199105200105201105202105203105204105205105206105207105208105209105210105211105212105213105214105215105216105217105218105219105220105221105222105223105224105225105226105227105228105229105230105231105232105233105234105235105236105237105238105239105240105241105242105243105244105245105246105247105248105249105250105251105252105253105254105255105256105257105258105259105260105261105262105263105264105265105266105267105268105269105270105271105272105273105274105275105276105277105278105279105280105281105282105283105284105285105286105287105288105289105290105291105292105293105294105295105296105297105298105299105300105301105302105303105304105305105306105307105308105309105310105311105312105313105314105315105316105317105318105319105320105321105322105323105324105325105326105327105328105329105330105331105332105333105334105335105336105337105338105339105340105341105342105343105344105345105346105347105348105349105350105351105352105353105354105355105356105357105358105359105360105361105362105363105364105365105366105367105368105369105370105371105372105373105374105375105376105377105378105379105380105381105382105383105384105385105386105387105388105389105390105391105392105393105394105395105396105397105398105399105400105401105402105403105404105405105406105407105408105409105410105411105412105413105414105415105416105417105418105419105420105421105422105423105424105425105426105427105428105429105430105431105432105433105434105435105436105437105438105439105440105441105442105443105444105445105446105447105448105449105450105451105452105453105454105455105456105457105458105459105460105461105462105463105464105465105466105467105468105469105470105471105472105473105474105475105476105477105478105479105480105481105482105483105484105485105486105487105488105489105490105491105492105493105494105495105496105497105498105499105500105501105502105503105504105505105506105507105508105509105510105511105512105513105514105515105516105517105518105519105520105521105522105523105524105525105526105527105528105529105530105531105532105533105534105535105536105537105538105539105540105541105542105543105544105545105546105547105548105549105550105551105552105553105554105555105556105557105558105559105560105561105562105563105564105565105566105567105568105569105570105571105572105573105574105575105576105577105578105579105580105581105582105583105584105585105586105587105588105589105590105591105592105593105594105595105596105597105598105599105600105601105602105603105604105605105606105607105608105609105610105611105612105613105614105615105616105617105618105619105620105621105622105623105624105625105626105627105628105629105630105631105632105633105634105635105636105637105638105639105640105641105642105643105644105645105646105647105648105649105650105651105652105653105654105655105656105657105658105659105660105661105662105663105664105665105666105667105668105669105670105671105672105673105674105675105676105677105678105679105680105681105682105683105684105685105686105687105688105689105690105691105692105693105694105695105696105697105698105699105700105701105702105703105704105705105706105707105708105709105710105711105712105713105714105715105716105717105718105719105720105721105722105723105724105725105726105727105728105729105730105731105732105733105734105735105736105737105738105739105740105741105742105743105744105745105746105747105748105749105750105751105752105753105754105755105756105757105758105759105760105761105762105763105764105765105766105767105768105769105770105771105772105773105774105775105776105777105778105779105780105781105782105783105784105785105786105787105788105789105790105791105792105793105794105795105796105797105798105799105800105801105802105803105804105805105806105807105808105809105810105811105812105813105814105815105816105817105818105819105820105821105822105823105824105825105826105827105828105829105830105831105832105833105834105835105836105837105838105839105840105841105842105843105844105845105846105847105848105849105850105851105852105853105854105855105856105857105858105859105860105861105862105863105864105865105866105867105868105869105870105871105872105873105874105875105876105877105878105879105880105881105882105883105884105885105886105887105888105889105890105891105892105893105894105895105896105897105898105899105900105901105902105903105904105905105906105907105908105909105910105911105912105913105914105915105916105917105918105919105920105921105922105923105924105925105926105927105928105929105930105931105932105933105934105935105936105937105938105939105940105941105942105943105944105945105946105947105948105949105950105951105952105953105954105955105956105957105958105959105960105961105962105963105964105965105966105967105968105969105970105971105972105973105974105975105976105977105978105979105980105981105982105983105984105985105986105987105988105989105990105991105992105993105994105995105996105997105998105999106000106001106002106003106004106005106006106007106008106009106010106011106012106013106014106015106016106017106018106019106020106021106022106023106024106025106026106027106028106029106030106031106032106033106034106035106036106037106038106039106040106041106042106043106044106045106046106047106048106049106050106051106052106053106054106055106056106057106058106059106060106061106062106063106064106065106066106067106068106069106070106071106072106073106074106075106076106077106078106079106080106081106082106083106084106085106086106087106088106089106090106091106092106093106094106095106096106097106098106099106100106101106102106103106104106105106106106107106108106109106110106111106112106113106114106115106116106117106118106119106120106121106122106123106124106125106126106127106128106129106130106131106132106133106134106135106136106137106138106139106140106141106142106143106144106145106146106147106148106149106150106151106152106153106154106155106156106157106158106159106160106161106162106163106164106165106166106167106168106169106170106171106172106173106174106175106176106177106178106179106180106181106182106183106184106185106186106187106188106189106190106191106192106193106194106195106196106197106198106199106200106201106202106203106204106205106206106207106208106209106210106211106212106213106214106215106216106217106218106219106220106221106222106223106224106225106226106227106228106229106230106231106232106233106234106235106236106237106238106239106240106241106242106243106244106245106246106247106248106249106250106251106252106253106254106255106256106257106258106259106260106261106262106263106264106265106266106267106268106269106270106271106272106273106274106275106276106277106278106279106280106281106282106283106284106285106286106287106288106289106290106291106292106293106294106295106296106297106298106299106300106301106302106303106304106305106306106307106308106309106310106311106312106313106314106315106316106317106318106319106320106321106322106323106324106325106326106327106328106329106330106331106332106333106334106335106336106337106338106339106340106341106342106343106344106345106346106347106348106349106350106351106352106353106354106355106356106357106358106359106360106361106362106363106364106365106366106367106368106369106370106371106372106373106374106375106376106377106378106379106380106381106382106383106384106385106386106387106388106389106390106391106392106393106394106395106396106397106398106399106400106401106402106403106404106405106406106407106408106409106410106411106412106413106414106415106416106417106418106419106420106421106422106423106424106425106426106427106428106429106430106431106432106433106434106435106436106437106438106439106440106441106442106443106444106445106446106447106448106449106450106451106452106453106454106455106456106457106458106459106460106461106462106463106464106465106466106467106468106469106470106471106472106473106474106475106476106477106478106479106480106481106482106483106484106485106486106487106488106489106490106491106492106493106494106495106496106497106498106499106500106501106502106503106504106505106506106507106508106509106510106511106512106513106514106515106516106517106518106519106520106521106522106523106524106525106526106527106528106529106530106531106532106533106534106535106536106537106538106539106540106541106542106543106544106545106546106547106548106549106550106551106552106553106554106555106556106557106558106559106560106561106562106563106564106565106566106567106568106569106570106571106572106573106574106575106576106577106578106579106580106581106582106583106584106585106586106587106588106589106590106591106592106593106594106595106596106597106598106599106600106601106602106603106604106605106606106607106608106609106610106611106612106613106614106615106616106617106618106619106620106621106622106623106624106625106626106627106628106629106630106631106632106633106634106635106636106637106638106639106640106641106642106643106644106645106646106647106648106649106650106651106652106653106654106655106656106657106658106659106660106661106662106663106664106665106666106667106668106669106670106671106672106673106674106675106676106677106678106679106680106681106682106683106684106685106686106687106688106689106690106691106692106693106694106695106696106697106698106699106700106701106702106703106704106705106706106707106708106709106710106711106712106713106714106715106716106717106718106719106720106721106722106723106724106725106726106727106728106729106730106731106732106733106734106735106736106737106738106739106740106741106742106743106744106745106746106747106748106749106750106751106752106753106754106755106756106757106758106759106760106761106762106763106764106765106766106767106768106769106770106771106772106773106774106775106776106777106778106779106780106781106782106783106784106785106786106787106788106789106790106791106792106793106794106795106796106797106798106799106800106801106802106803106804106805106806106807106808106809106810106811106812106813106814106815106816106817106818106819106820106821106822106823106824106825106826106827106828106829106830106831106832106833106834106835106836106837106838106839106840106841106842106843106844106845106846106847106848106849106850106851106852106853106854106855106856106857106858106859106860106861106862106863106864106865106866106867106868106869106870106871106872106873106874106875106876106877106878106879106880106881106882106883106884106885106886106887106888106889106890106891106892106893106894106895106896106897106898106899106900106901106902106903106904106905106906106907106908106909106910106911106912106913106914106915106916106917106918106919106920106921106922106923106924106925106926106927106928106929106930106931106932106933106934106935106936106937106938106939106940106941106942106943106944106945106946106947106948106949106950106951106952106953106954106955106956106957106958106959106960106961106962106963106964106965106966106967106968106969106970106971106972106973106974106975106976106977106978106979106980106981106982106983106984106985106986106987106988106989106990106991106992106993106994106995106996106997106998106999107000107001107002107003107004107005107006107007107008107009107010107011107012107013107014107015107016107017107018107019107020107021107022107023107024107025107026107027107028107029107030107031107032107033107034107035107036107037107038107039107040107041107042107043107044107045107046107047107048107049107050107051107052107053107054107055107056107057107058107059107060107061107062107063107064107065107066107067107068107069107070107071107072107073107074107075107076107077107078107079107080107081107082107083107084107085107086107087107088107089107090107091107092107093107094107095107096107097107098107099107100107101107102107103107104107105107106107107107108107109107110107111107112107113107114107115107116107117107118107119107120107121107122107123107124107125107126107127107128107129107130107131107132107133107134107135107136107137107138107139107140107141107142107143107144107145107146107147107148107149107150107151107152107153107154107155107156107157107158107159107160107161107162107163107164107165107166107167107168107169107170107171107172107173107174107175107176107177107178107179107180107181107182107183107184107185107186107187107188107189107190107191107192107193107194107195107196107197107198107199107200107201107202107203107204107205107206107207107208107209107210107211107212107213107214107215107216107217107218107219107220107221107222107223107224107225107226107227107228107229107230107231107232107233107234107235107236107237107238107239107240107241107242107243107244107245107246107247107248107249107250107251107252107253107254107255107256107257107258107259107260107261107262107263107264107265107266107267107268107269107270107271107272107273107274107275107276107277107278107279107280107281107282107283107284107285107286107287107288107289107290107291107292107293107294107295107296107297107298107299107300107301107302107303107304107305107306107307107308107309107310107311107312107313107314107315107316107317107318107319107320107321107322107323107324107325107326107327107328107329107330107331107332107333107334107335107336107337107338107339107340107341107342107343107344107345107346107347107348107349107350107351107352107353107354107355107356107357107358107359107360107361107362107363107364107365107366107367107368107369107370107371107372107373107374107375107376107377107378107379107380107381107382107383107384107385107386107387107388107389107390107391107392107393107394107395107396107397107398107399107400107401107402107403107404107405107406107407107408107409107410107411107412107413107414107415107416107417107418107419107420107421107422107423107424107425107426107427107428107429107430107431107432107433107434107435107436107437107438107439107440107441107442107443107444107445107446107447107448107449107450107451107452107453107454107455107456107457107458107459107460107461107462107463107464107465107466107467107468107469107470107471107472107473107474107475107476107477107478107479107480107481107482107483107484107485107486107487107488107489107490107491107492107493107494107495107496107497107498107499107500107501107502107503107504107505107506107507107508107509107510107511107512107513107514107515107516107517107518107519107520107521107522107523107524107525107526107527107528107529107530107531107532107533107534107535107536107537107538107539107540107541107542107543107544107545107546107547107548107549107550107551107552107553107554107555107556107557107558107559107560107561107562107563107564107565107566107567107568107569107570107571107572107573107574107575107576107577107578107579107580107581107582107583107584107585107586107587107588107589107590107591107592107593107594107595107596107597107598107599107600107601107602107603107604107605107606107607107608107609107610107611107612107613107614107615107616107617107618107619107620107621107622107623107624107625107626107627107628107629107630107631107632107633107634107635107636107637107638107639107640107641107642107643107644107645107646107647107648107649107650107651107652107653107654107655107656107657107658107659107660107661107662107663107664107665107666107667107668107669107670107671107672107673107674107675107676107677107678107679107680107681107682107683107684107685107686107687107688107689107690107691107692107693107694107695107696107697107698107699107700107701107702107703107704107705107706107707107708107709107710107711107712107713107714107715107716107717107718107719107720107721107722107723107724107725107726107727107728107729107730107731107732107733107734107735107736107737107738107739107740107741107742107743107744107745107746107747107748107749107750107751107752107753107754107755107756107757107758107759107760107761107762107763107764107765107766107767107768107769107770107771107772107773107774107775107776107777107778107779107780107781107782107783107784107785107786107787107788107789107790107791107792107793107794107795107796107797107798107799107800107801107802107803107804107805107806107807107808107809107810107811107812107813107814107815107816107817107818107819107820107821107822107823107824107825107826107827107828107829107830107831107832107833107834107835107836107837107838107839107840107841107842107843107844107845107846107847107848107849107850107851107852107853107854107855107856107857107858107859107860107861107862107863107864107865107866107867107868107869107870107871107872107873107874107875107876107877107878107879107880107881107882107883107884107885107886107887107888107889107890107891107892107893107894107895107896107897107898107899107900107901107902107903107904107905107906107907107908107909107910107911107912107913107914107915107916107917107918107919107920107921107922107923107924107925107926107927107928107929107930107931107932107933107934107935107936107937107938107939107940107941107942107943107944107945107946107947107948107949107950107951107952107953107954107955107956107957107958107959107960107961107962107963107964107965107966107967107968107969107970107971107972107973107974107975107976107977107978107979107980107981107982107983107984107985107986107987107988107989107990107991107992107993107994107995107996107997107998107999108000108001108002108003108004108005108006108007108008108009108010108011108012108013108014108015108016108017108018108019108020108021108022108023108024108025108026108027108028108029108030108031108032108033108034108035108036108037108038108039108040108041108042108043108044108045108046108047108048108049108050108051108052108053108054108055108056108057108058108059108060108061108062108063108064108065108066108067108068108069108070108071108072108073108074108075108076108077108078108079108080108081108082108083108084108085108086108087108088108089108090108091108092108093108094108095108096108097108098108099108100108101108102108103108104108105108106108107108108108109108110108111108112108113108114108115108116108117108118108119108120108121108122108123108124108125108126108127108128108129108130108131108132108133108134108135108136108137108138108139108140108141108142108143108144108145108146108147108148108149108150108151108152108153108154108155108156108157108158108159108160108161108162108163108164108165108166108167108168108169108170108171108172108173108174108175108176108177108178108179108180108181108182108183108184108185108186108187108188108189108190108191108192108193108194108195108196108197108198108199108200108201108202108203108204108205108206108207108208108209108210108211108212108213108214108215108216108217108218108219108220108221108222108223108224108225108226108227108228108229108230108231108232108233108234108235108236108237108238108239108240108241108242108243108244108245108246108247108248108249108250108251108252108253108254108255108256108257108258108259108260108261108262108263108264108265108266108267108268108269108270108271108272108273108274108275108276108277108278108279108280108281108282108283108284108285108286108287108288108289108290108291108292108293108294108295108296108297108298108299108300108301108302108303108304108305108306108307108308108309108310108311108312108313108314108315108316108317108318108319108320108321108322108323108324108325108326108327108328108329108330108331108332108333108334108335108336108337108338108339108340108341108342108343108344108345108346108347108348108349108350108351108352108353108354108355108356108357108358108359108360108361108362108363108364108365108366108367108368108369108370108371108372108373108374108375108376108377108378108379108380108381108382108383108384108385108386108387108388108389108390108391108392108393108394108395108396108397108398108399108400108401108402108403108404108405108406108407108408108409108410108411108412108413108414108415108416108417108418108419108420108421108422108423108424108425108426108427108428108429108430108431108432108433108434108435108436108437108438108439108440108441108442108443108444108445108446108447108448108449108450108451108452108453108454108455108456108457108458108459108460108461108462108463108464108465108466108467108468108469108470108471108472108473108474108475108476108477108478108479108480108481108482108483108484108485108486108487108488108489108490108491108492108493108494108495108496108497108498108499108500108501108502108503108504108505108506108507108508108509108510108511108512108513108514108515108516108517108518108519108520108521108522108523108524108525108526108527108528108529108530108531108532108533108534108535108536108537108538108539108540108541108542108543108544108545108546108547108548108549108550108551108552108553108554108555108556108557108558108559108560108561108562108563108564108565108566108567108568108569108570108571108572108573108574108575108576108577108578108579108580108581108582108583108584108585108586108587108588108589108590108591108592108593108594108595108596108597108598108599108600108601108602108603108604108605108606108607108608108609108610108611108612108613108614108615108616108617108618108619108620108621108622108623108624108625108626108627108628108629108630108631108632108633108634108635108636108637108638108639108640108641108642108643108644108645108646108647108648108649108650108651108652108653108654108655108656108657108658108659108660108661108662108663108664108665108666108667108668108669108670108671108672108673108674108675108676108677108678108679108680108681108682108683108684108685108686108687108688108689108690108691108692108693108694108695108696108697108698108699108700108701108702108703108704108705108706108707108708108709108710108711108712108713108714108715108716108717108718108719108720108721108722108723108724108725108726108727108728108729108730108731108732108733108734108735108736108737108738108739108740108741108742108743108744108745108746108747108748108749108750108751108752108753108754108755108756108757108758108759108760108761108762108763108764108765108766108767108768108769108770108771108772108773108774108775108776108777108778108779108780108781108782108783108784108785108786108787108788108789108790108791108792108793108794108795108796108797108798108799108800108801108802108803108804108805108806108807108808108809108810108811108812108813108814108815108816108817108818108819108820108821108822108823108824108825108826108827108828108829108830108831108832108833108834108835108836108837108838108839108840108841108842108843108844108845108846108847108848108849108850108851108852108853108854108855108856108857108858108859108860108861108862108863108864108865108866108867108868108869108870108871108872108873108874108875108876108877108878108879108880108881108882108883108884108885108886108887108888108889108890108891108892108893108894108895108896108897108898108899108900108901108902108903108904108905108906108907108908108909108910108911108912108913108914108915108916108917108918108919108920108921108922108923108924108925108926108927108928108929108930108931108932108933108934108935108936108937108938108939108940108941108942108943108944108945108946108947108948108949108950108951108952108953108954108955108956108957108958108959108960108961108962108963108964108965108966108967108968108969108970108971108972108973108974108975108976108977108978108979108980108981108982108983108984108985108986108987108988108989108990108991108992108993108994108995108996108997108998108999109000109001109002109003109004109005109006109007109008109009109010109011109012109013109014109015109016109017109018109019109020109021109022109023109024109025109026109027109028109029109030109031109032109033109034109035109036109037109038109039109040109041109042109043109044109045109046109047109048109049109050109051109052109053109054109055109056109057109058109059109060109061109062109063109064109065109066109067109068109069109070109071109072109073109074109075109076109077109078109079109080109081109082109083109084109085109086109087109088109089109090109091109092109093109094109095109096109097109098109099109100109101109102109103109104109105109106109107109108109109109110109111109112109113109114109115109116109117109118109119109120109121109122109123109124109125109126109127109128109129109130109131109132109133109134109135109136109137109138109139109140109141109142109143109144109145109146109147109148109149109150109151109152109153109154109155109156109157109158109159109160109161109162109163109164109165109166109167109168109169109170109171109172109173109174109175109176109177109178109179109180109181109182109183109184109185109186109187109188109189109190109191109192109193109194109195109196109197109198109199109200109201109202109203109204109205109206109207109208109209109210109211109212109213109214109215109216109217109218109219109220109221109222109223109224109225109226109227109228109229109230109231109232109233109234109235109236109237109238109239109240109241109242109243109244109245109246109247109248109249109250109251109252109253109254109255109256109257109258109259109260109261109262109263109264109265109266109267109268109269109270109271109272109273109274109275109276109277109278109279109280109281109282109283109284109285109286109287109288109289109290109291109292109293109294109295109296109297109298109299109300109301109302109303109304109305109306109307109308109309109310109311109312109313109314109315109316109317109318109319109320109321109322109323109324109325109326109327109328109329109330109331109332109333109334109335109336109337109338109339109340109341109342109343109344109345109346109347109348109349109350109351109352109353109354109355109356109357109358109359109360109361109362109363109364109365109366109367109368109369109370109371109372109373109374109375109376109377109378109379109380109381109382109383109384109385109386109387109388109389109390109391109392109393109394109395109396109397109398109399109400109401109402109403109404109405109406109407109408109409109410109411109412109413109414109415109416109417109418109419109420109421109422109423109424109425109426109427109428109429109430109431109432109433109434109435109436109437109438109439109440109441109442109443109444109445109446109447109448109449109450109451109452109453109454109455109456109457109458109459109460109461109462109463109464109465109466109467109468109469109470109471109472109473109474109475109476109477109478109479109480109481109482109483109484109485109486109487109488109489109490109491109492109493109494109495109496109497109498109499109500109501109502109503109504109505109506109507109508109509109510109511109512109513109514109515109516109517109518109519109520109521109522109523109524109525109526109527109528109529109530109531109532109533109534109535109536109537109538109539109540109541109542109543109544109545109546109547109548109549109550109551109552109553109554109555109556109557109558109559109560109561109562109563109564109565109566109567109568109569109570109571109572109573109574109575109576109577109578109579109580109581109582109583109584109585109586109587109588109589109590109591109592109593109594109595109596109597109598109599109600109601109602109603109604109605109606109607109608109609109610109611109612109613109614109615109616109617109618109619109620109621109622109623109624109625109626109627109628109629109630109631109632109633109634109635109636109637109638109639109640109641109642109643109644109645109646109647109648109649109650109651109652109653109654109655109656109657109658109659109660109661109662109663109664109665109666109667109668109669109670109671109672109673109674109675109676109677109678109679109680109681109682109683109684109685109686109687109688109689109690109691109692109693109694109695109696109697109698109699109700109701109702109703109704109705109706109707109708109709109710109711109712109713109714109715109716109717109718109719109720109721109722109723109724109725109726109727109728109729109730109731109732109733109734109735109736109737109738109739109740109741109742109743109744109745109746109747109748109749109750109751109752109753109754109755109756109757109758109759109760109761109762109763109764109765109766109767109768109769109770109771109772109773109774109775109776109777109778109779109780109781109782109783109784109785109786109787109788109789109790109791109792109793109794109795109796109797109798109799109800109801109802109803109804109805109806109807109808109809109810109811109812109813109814109815109816109817109818109819109820109821109822109823109824109825109826109827109828109829109830109831109832109833109834109835109836109837109838109839109840109841109842109843109844109845109846109847109848109849109850109851109852109853109854109855109856109857109858109859109860109861109862109863109864109865109866109867109868109869109870109871109872109873109874109875109876109877109878109879109880109881109882109883109884109885109886109887109888109889109890109891109892109893109894109895109896109897109898109899109900109901109902109903109904109905109906109907109908109909109910109911109912109913109914109915109916109917109918109919109920109921109922109923109924109925109926109927109928109929109930109931109932109933109934109935109936109937109938109939109940109941109942109943109944109945109946109947109948109949109950109951109952109953109954109955109956109957109958109959109960109961109962109963109964109965109966109967109968109969109970109971109972109973109974109975109976109977109978109979109980109981109982109983109984109985109986109987109988109989109990109991109992109993109994109995109996109997109998109999110000110001110002110003110004110005110006110007110008110009110010110011110012110013110014110015110016110017110018110019110020110021110022110023110024110025110026110027110028110029110030110031110032110033110034110035110036110037110038110039110040110041110042110043110044110045110046110047110048110049110050110051110052110053110054110055110056110057110058110059110060110061110062110063110064110065110066110067110068110069110070110071110072110073110074110075110076110077110078110079110080110081110082110083110084110085110086110087110088110089110090110091110092110093110094110095110096110097110098110099110100110101110102110103110104110105110106110107110108110109110110110111110112110113110114110115110116110117110118110119110120110121110122110123110124110125110126110127110128110129110130110131110132110133110134110135110136110137110138110139110140110141110142110143110144110145110146110147110148110149110150110151110152110153110154110155110156110157110158110159110160110161110162110163110164110165110166110167110168110169110170110171110172110173110174110175110176110177110178110179110180110181110182110183110184110185110186110187110188110189110190110191110192110193110194110195110196110197110198110199110200110201110202110203110204110205110206110207110208110209110210110211110212110213110214110215110216110217110218110219110220110221110222110223110224110225110226110227110228110229110230110231110232110233110234110235110236110237110238110239110240110241110242110243110244110245110246110247110248110249110250110251110252110253110254110255110256110257110258110259110260110261110262110263110264110265110266110267110268110269110270110271110272110273110274110275110276110277110278110279110280110281110282110283110284110285110286110287110288110289110290110291110292110293110294110295110296110297110298110299110300110301110302110303110304110305110306110307110308110309110310110311110312110313110314110315110316110317110318110319110320110321110322110323110324110325110326110327110328110329110330110331110332110333110334110335110336110337110338110339110340110341110342110343110344110345110346110347110348110349110350110351110352110353110354110355110356110357110358110359110360110361110362110363110364110365110366110367110368110369110370110371110372110373110374110375110376110377110378110379110380110381110382110383110384110385110386110387110388110389110390110391110392110393110394110395110396110397110398110399110400110401110402110403110404110405110406110407110408110409110410110411110412110413110414110415110416110417110418110419110420110421110422110423110424110425110426110427110428110429110430110431110432110433110434110435110436110437110438110439110440110441110442110443110444110445110446110447110448110449110450110451110452110453110454110455110456110457110458110459110460110461110462110463110464110465110466110467110468110469110470110471110472110473110474110475110476110477110478110479110480110481110482110483110484110485110486110487110488110489110490110491110492110493110494110495110496110497110498110499110500110501110502110503110504110505110506110507110508110509110510110511110512110513110514110515110516110517110518110519110520110521110522110523110524110525110526110527110528110529110530110531110532110533110534110535110536110537110538110539110540110541110542110543110544110545110546110547110548110549110550110551110552110553110554110555110556110557110558110559110560110561110562110563110564110565110566110567110568110569110570110571110572110573110574110575110576110577110578110579110580110581110582110583110584110585110586110587110588110589110590110591110592110593110594110595110596110597110598110599110600110601110602110603110604110605110606110607110608110609110610110611110612110613110614110615110616110617110618110619110620110621110622110623110624110625110626110627110628110629110630110631110632110633110634110635110636110637110638110639110640110641110642110643110644110645110646110647110648110649110650110651110652110653110654110655110656110657110658110659110660110661110662110663110664110665110666110667110668110669110670110671110672110673110674110675110676110677110678110679110680110681110682110683110684110685110686110687110688110689110690110691110692110693110694110695110696110697110698110699110700110701110702110703110704110705110706110707110708110709110710110711110712110713110714110715110716110717110718110719110720110721110722110723110724110725110726110727110728110729110730110731110732110733110734110735110736110737110738110739110740110741110742110743110744110745110746110747110748110749110750110751110752110753110754110755110756110757110758110759110760110761110762110763110764110765110766110767110768110769110770110771110772110773110774110775110776110777110778110779110780110781110782110783110784110785110786110787110788110789110790110791110792110793110794110795110796110797110798110799110800110801110802110803110804110805110806110807110808110809110810110811110812110813110814110815110816110817110818110819110820110821110822110823110824110825110826110827110828110829110830110831110832110833110834110835110836110837110838110839110840110841110842110843110844110845110846110847110848110849110850110851110852110853110854110855110856110857110858110859110860110861110862110863110864110865110866110867110868110869110870110871110872110873110874110875110876110877110878110879110880110881110882110883110884110885110886110887110888110889110890110891110892110893110894110895110896110897110898110899110900110901110902110903110904110905110906110907110908110909110910110911110912110913110914110915110916110917110918110919110920110921110922110923110924110925110926110927110928110929110930110931110932110933110934110935110936110937110938110939110940110941110942110943110944110945110946110947110948110949110950110951110952110953110954110955110956110957110958110959110960110961110962110963110964110965110966110967110968110969110970110971110972110973110974110975110976110977110978110979110980110981110982110983110984110985110986110987110988110989110990110991110992110993110994110995110996110997110998110999111000111001111002111003111004111005111006111007111008111009111010111011111012111013111014111015111016111017111018111019111020111021111022111023111024111025111026111027111028111029111030111031111032111033111034111035111036111037111038111039111040111041111042111043111044111045111046111047111048111049111050111051111052111053111054111055111056111057111058111059111060111061111062111063111064111065111066111067111068111069111070111071111072111073111074111075111076111077111078111079111080111081111082111083111084111085111086111087111088111089111090111091111092111093111094111095111096111097111098111099111100111101111102111103111104111105111106111107111108111109111110111111111112111113111114111115111116111117111118111119111120111121111122111123111124111125111126111127111128111129111130111131111132111133111134111135111136111137111138111139111140111141111142111143111144111145111146111147111148111149111150111151111152111153111154111155111156111157111158111159111160111161111162111163111164111165111166111167111168111169111170111171111172111173111174111175111176111177111178111179111180111181111182111183111184111185111186111187111188111189111190111191111192111193111194111195111196111197111198111199111200111201111202111203111204111205111206111207111208111209111210111211111212111213111214111215111216111217111218111219111220111221111222111223111224111225111226111227111228111229111230111231111232111233111234111235111236111237111238111239111240111241111242111243111244111245111246111247111248111249111250111251111252111253111254111255111256111257111258111259111260111261111262111263111264111265111266111267111268111269111270111271111272111273111274111275111276111277111278111279111280111281111282111283111284111285111286111287111288111289111290111291111292111293111294111295111296111297111298111299111300111301111302111303111304111305111306111307111308111309111310111311111312111313111314111315111316111317111318111319111320111321111322111323111324111325111326111327111328111329111330111331111332111333111334111335111336111337111338111339111340111341111342111343111344111345111346111347111348111349111350111351111352111353111354111355111356111357111358111359111360111361111362111363111364111365111366111367111368111369111370111371111372111373111374111375111376111377111378111379111380111381111382111383111384111385111386111387111388111389111390111391111392111393111394111395111396111397111398111399111400111401111402111403111404111405111406111407111408111409111410111411111412111413111414111415111416111417111418111419111420111421111422111423111424111425111426111427111428111429111430111431111432111433111434111435111436111437111438111439111440111441111442111443111444111445111446111447111448111449111450111451111452111453111454111455111456111457111458111459111460111461111462111463111464111465111466111467111468111469111470111471111472111473111474111475111476111477111478111479111480111481111482111483111484111485111486111487111488111489111490111491111492111493111494111495111496111497111498111499111500111501111502111503111504111505111506111507111508111509111510111511111512111513111514111515111516111517111518111519111520111521111522111523111524111525111526111527111528111529111530111531111532111533111534111535111536111537111538111539111540111541111542111543111544111545111546111547111548111549111550111551111552111553111554111555111556111557111558111559111560111561111562111563111564111565111566111567111568111569111570111571111572111573111574111575111576111577111578111579111580111581111582111583111584111585111586111587111588111589111590111591111592111593111594111595111596111597111598111599111600111601111602111603111604111605111606111607111608111609111610111611111612111613111614111615111616111617111618111619111620111621111622111623111624111625111626111627111628111629111630111631111632111633111634111635111636111637111638111639111640111641111642111643111644111645111646111647111648111649111650111651111652111653111654111655111656111657111658111659111660111661111662111663111664111665111666111667111668111669111670111671111672111673111674111675111676111677111678111679111680111681111682111683111684111685111686111687111688111689111690111691111692111693111694111695111696111697111698111699111700111701111702111703111704111705111706111707111708111709111710111711111712111713111714111715111716111717111718111719111720111721111722111723111724111725111726111727111728111729111730111731111732111733111734111735111736111737111738111739111740111741111742111743111744111745111746111747111748111749111750111751111752111753111754111755111756111757111758111759111760111761111762111763111764111765111766111767111768111769111770111771111772111773111774111775111776111777111778111779111780111781111782111783111784111785111786111787111788111789111790111791111792111793111794111795111796111797111798111799111800111801111802111803111804111805111806111807111808111809111810111811111812111813111814111815111816111817111818111819111820111821111822111823111824111825111826111827111828111829111830111831111832111833111834111835111836111837111838111839111840111841111842111843111844111845111846111847111848111849111850111851111852111853111854111855111856111857111858111859111860111861111862111863111864111865111866111867111868111869111870111871111872111873111874111875111876111877111878111879111880111881111882111883111884111885111886111887111888111889111890111891111892111893111894111895111896111897111898111899111900111901111902111903111904111905111906111907111908111909111910111911111912111913111914111915111916111917111918111919111920111921111922111923111924111925111926111927111928111929111930111931111932111933111934111935111936111937111938111939111940111941111942111943111944111945111946111947111948111949111950111951111952111953111954111955111956111957111958111959111960111961111962111963111964111965111966111967111968111969111970111971111972111973111974111975111976111977111978111979111980111981111982111983111984111985111986111987111988111989111990111991111992111993111994111995111996111997111998111999112000112001112002112003112004112005112006112007112008112009112010112011112012112013112014112015112016112017112018112019112020112021112022112023112024112025112026112027112028112029112030112031112032112033112034112035112036112037112038112039112040112041112042112043112044112045112046112047112048112049112050112051112052112053112054112055112056112057112058112059112060112061112062112063112064112065112066112067112068112069112070112071112072112073112074112075112076112077112078112079112080112081112082112083112084112085112086112087112088112089112090112091112092112093112094112095112096112097112098112099112100112101112102112103112104112105112106112107112108112109112110112111112112112113112114112115112116112117112118112119112120112121112122112123112124112125112126112127112128112129112130112131112132112133112134112135112136112137112138112139112140112141112142112143112144112145112146112147112148112149112150112151112152112153112154112155112156112157112158112159112160112161112162112163112164112165112166112167112168112169112170112171112172112173112174112175112176112177112178112179112180112181112182112183112184112185112186112187112188112189112190112191112192112193112194112195112196112197112198112199112200112201112202112203112204112205112206112207112208112209112210112211112212112213112214112215112216112217112218112219112220112221112222112223112224112225112226112227112228112229112230112231112232112233112234112235112236112237112238112239112240112241112242112243112244112245112246112247112248112249112250112251112252112253112254112255112256112257112258112259112260112261112262112263112264112265112266112267112268112269112270112271112272112273112274112275112276112277112278112279112280112281112282112283112284112285112286112287112288112289112290112291112292112293112294112295112296112297112298112299112300112301112302112303112304112305112306112307112308112309112310112311112312112313112314112315112316112317112318112319112320112321112322112323112324112325112326112327112328112329112330112331112332112333112334112335112336112337112338112339112340112341112342112343112344112345112346112347112348112349112350112351112352112353112354112355112356112357112358112359112360112361112362112363112364112365112366112367112368112369112370112371112372112373112374112375112376112377112378112379112380112381112382112383112384112385112386112387112388112389112390112391112392112393112394112395112396112397112398112399112400112401112402112403112404112405112406112407112408112409112410112411112412112413112414112415112416112417112418112419112420112421112422112423112424112425112426112427112428112429112430112431112432112433112434112435112436112437112438112439112440112441112442112443112444112445112446112447112448112449112450112451112452112453112454112455112456112457112458112459112460112461112462112463112464112465112466112467112468112469112470112471112472112473112474112475112476112477112478112479112480112481112482112483112484112485112486112487112488112489112490112491112492112493112494112495112496112497112498112499112500112501112502112503112504112505112506112507112508112509112510112511112512112513112514112515112516112517112518112519112520112521112522112523112524112525112526112527112528112529112530112531112532112533112534112535112536112537112538112539112540112541112542112543112544112545112546112547112548112549112550112551112552112553112554112555112556112557112558112559112560112561112562112563112564112565112566112567112568112569112570112571112572112573112574112575112576112577112578112579112580112581112582112583112584112585112586112587112588112589112590112591112592112593112594112595112596112597112598112599112600112601112602112603112604112605112606112607112608112609112610112611112612112613112614112615112616112617112618112619112620112621112622112623112624112625112626112627112628112629112630112631112632112633112634112635112636112637112638112639112640112641112642112643112644112645112646112647112648112649112650112651112652112653112654112655112656112657112658112659112660112661112662112663112664112665112666112667112668112669112670112671112672112673112674112675112676112677112678112679112680112681112682112683112684112685112686112687112688112689112690112691112692112693112694112695112696112697112698112699112700112701112702112703112704112705112706112707112708112709112710112711112712112713112714112715112716112717112718112719112720112721112722112723112724112725112726112727112728112729112730112731112732112733112734112735112736112737112738112739112740112741112742112743112744112745112746112747112748112749112750112751112752112753112754112755112756112757112758112759112760112761112762112763112764112765112766112767112768112769112770112771112772112773112774112775112776112777112778112779112780112781112782112783112784112785112786112787112788112789112790112791112792112793112794112795112796112797112798112799112800112801112802112803112804112805112806112807112808112809112810112811112812112813112814112815112816112817112818112819112820112821112822112823112824112825112826112827112828112829112830112831112832112833112834112835112836112837112838112839112840112841112842112843112844112845112846112847112848112849112850112851112852112853112854112855112856112857112858112859112860112861112862112863112864112865112866112867112868112869112870112871112872112873112874112875112876112877112878112879112880112881112882112883112884112885112886112887112888112889112890112891112892112893112894112895112896112897112898112899112900112901112902112903112904112905112906112907112908112909112910112911112912112913112914112915112916112917112918112919112920112921112922112923112924112925112926112927112928112929112930112931112932112933112934112935112936112937112938112939112940112941112942112943112944112945112946112947112948112949112950112951112952112953112954112955112956112957112958112959112960112961112962112963112964112965112966112967112968112969112970112971112972112973112974112975112976112977112978112979112980112981112982112983112984112985112986112987112988112989112990112991112992112993112994112995112996112997112998112999113000113001113002113003113004113005113006113007113008113009113010113011113012113013113014113015113016113017113018113019113020113021113022113023113024113025113026113027113028113029113030113031113032113033113034113035113036113037113038113039113040113041113042113043113044113045113046113047113048113049113050113051113052113053113054113055113056113057113058113059113060113061113062113063113064113065113066113067113068113069113070113071113072113073113074113075113076113077113078113079113080113081113082113083113084113085113086113087113088113089113090113091113092113093113094113095113096113097113098113099113100113101113102113103113104113105113106113107113108113109113110113111113112113113113114113115113116113117113118113119113120113121113122113123113124113125113126113127113128113129113130113131113132113133113134113135113136113137113138113139113140113141113142113143113144113145113146113147113148113149113150113151113152113153113154113155113156113157113158113159113160113161113162113163113164113165113166113167113168113169113170113171113172113173113174113175113176113177113178113179113180113181113182113183113184113185113186113187113188113189113190113191113192113193113194113195113196113197113198113199113200113201113202113203113204113205113206113207113208113209113210113211113212113213113214113215113216113217113218113219113220113221113222113223113224113225113226113227113228113229113230113231113232113233113234113235113236113237113238113239113240113241113242113243113244113245113246113247113248113249113250113251113252113253113254113255113256113257113258113259113260113261113262113263113264113265113266113267113268113269113270113271113272113273113274113275113276113277113278113279113280113281113282113283113284113285113286113287113288113289113290113291113292113293113294113295113296113297113298113299113300113301113302113303113304113305113306113307113308113309113310113311113312113313113314113315113316113317113318113319113320113321113322113323113324113325113326113327113328113329113330113331113332113333113334113335113336113337113338113339113340113341113342113343113344113345113346113347113348113349113350113351113352113353113354113355113356113357113358113359113360113361113362113363113364113365113366113367113368113369113370113371113372113373113374113375113376113377113378113379113380113381113382113383113384113385113386113387113388113389113390113391113392113393113394113395113396113397113398113399113400113401113402113403113404113405113406113407113408113409113410113411113412113413113414113415113416113417113418113419113420113421113422113423113424113425113426113427113428113429113430113431113432113433113434113435113436113437113438113439113440113441113442113443113444113445113446113447113448113449113450113451113452113453113454113455113456113457113458113459113460113461113462113463113464113465113466113467113468113469113470113471113472113473113474113475113476113477113478113479113480113481113482113483113484113485113486113487113488113489113490113491113492113493113494113495113496113497113498113499113500113501113502113503113504113505113506113507113508113509113510113511113512113513113514113515113516113517113518113519113520113521113522113523113524113525113526113527113528113529113530113531113532113533113534113535113536113537113538113539113540113541113542113543113544113545113546113547113548113549113550113551113552113553113554113555113556113557113558113559113560113561113562113563113564113565113566113567113568113569113570113571113572113573113574113575113576113577113578113579113580113581113582113583113584113585113586113587113588113589113590113591113592113593113594113595113596113597113598113599113600113601113602113603113604113605113606113607113608113609113610113611113612113613113614113615113616113617113618113619113620113621113622113623113624113625113626113627113628113629113630113631113632113633113634113635113636113637113638113639113640113641113642113643113644113645113646113647113648113649113650113651113652113653113654113655113656113657113658113659113660113661113662113663113664113665113666113667113668113669113670113671113672113673113674113675113676113677113678113679113680113681113682113683113684113685113686113687113688113689113690113691113692113693113694113695113696113697113698113699113700113701113702113703113704113705113706113707113708113709113710113711113712113713113714113715113716113717113718113719113720113721113722113723113724113725113726113727113728113729113730113731113732113733113734113735113736113737113738113739113740113741113742113743113744113745113746113747113748113749113750113751113752113753113754113755113756113757113758113759113760113761113762113763113764113765113766113767113768113769113770113771113772113773113774113775113776113777113778113779113780113781113782113783113784113785113786113787113788113789113790113791113792113793113794113795113796113797113798113799113800113801113802113803113804113805113806113807113808113809113810113811113812113813113814113815113816113817113818113819113820113821113822113823113824113825113826113827113828113829113830113831113832113833113834113835113836113837113838113839113840113841113842113843113844113845113846113847113848113849113850113851113852113853113854113855113856113857113858113859113860113861113862113863113864113865113866113867113868113869113870113871113872113873113874113875113876113877113878113879113880113881113882113883113884113885113886113887113888113889113890113891113892113893113894113895113896113897113898113899113900113901113902113903113904113905113906113907113908113909113910113911113912113913113914113915113916113917113918113919113920113921113922113923113924113925113926113927113928113929113930113931113932113933113934113935113936113937113938113939113940113941113942113943113944113945113946113947113948113949113950113951113952113953113954113955113956113957113958113959113960113961113962113963113964113965113966113967113968113969113970113971113972113973113974113975113976113977113978113979113980113981113982113983113984113985113986113987113988113989113990113991113992113993113994113995113996113997113998113999114000114001114002114003114004114005114006114007114008114009114010114011114012114013114014114015114016114017114018114019114020114021114022114023114024114025114026114027114028114029114030114031114032114033114034114035114036114037114038114039114040114041114042114043114044114045114046114047114048114049114050114051114052114053114054114055114056114057114058114059114060114061114062114063114064114065114066114067114068114069114070114071114072114073114074114075114076114077114078114079114080114081114082114083114084114085114086114087114088114089114090114091114092114093114094114095114096114097114098114099114100114101114102114103114104114105114106114107114108114109114110114111114112114113114114114115114116114117114118114119114120114121114122114123114124114125114126114127114128114129114130114131114132114133114134114135114136114137114138114139114140114141114142114143114144114145114146114147114148114149114150114151114152114153114154114155114156114157114158114159114160114161114162114163114164114165114166114167114168114169114170114171114172114173114174114175114176114177114178114179114180114181114182114183114184114185114186114187114188114189114190114191114192114193114194114195114196114197114198114199114200114201114202114203114204114205114206114207114208114209114210114211114212114213114214114215114216114217114218114219114220114221114222114223114224114225114226114227114228114229114230114231114232114233114234114235114236114237114238114239114240114241114242114243114244114245114246114247114248114249114250114251114252114253114254114255114256114257114258114259114260114261114262114263114264114265114266114267114268114269114270114271114272114273114274114275114276114277114278114279114280114281114282114283114284114285114286114287114288114289114290114291114292114293114294114295114296114297114298114299114300114301114302114303114304114305114306114307114308114309114310114311114312114313114314114315114316114317114318114319114320114321114322114323114324114325114326114327114328114329114330114331114332114333114334114335114336114337114338114339114340114341114342114343114344114345114346114347114348114349114350114351114352114353114354114355114356114357114358114359114360114361114362114363114364114365114366114367114368114369114370114371114372114373114374114375114376114377114378114379114380114381114382114383114384114385114386114387114388114389114390114391114392114393114394114395114396114397114398114399114400114401114402114403114404114405114406114407114408114409114410114411114412114413114414114415114416114417114418114419114420114421114422114423114424114425114426114427114428114429114430114431114432114433114434114435114436114437114438114439114440114441114442114443114444114445114446114447114448114449114450114451114452114453114454114455114456114457114458114459114460114461114462114463114464114465114466114467114468114469114470114471114472114473114474114475114476114477114478114479114480114481114482114483114484114485114486114487114488114489114490114491114492114493114494114495114496114497114498114499114500114501114502114503114504114505114506114507114508114509114510114511114512114513114514114515114516114517114518114519114520114521114522114523114524114525114526114527114528114529114530114531114532114533114534114535114536114537114538114539114540114541114542114543114544114545114546114547114548114549114550114551114552114553114554114555114556114557114558114559114560114561114562114563114564114565114566114567114568114569114570114571114572114573114574114575114576114577114578114579114580114581114582114583114584114585114586114587114588114589114590114591114592114593114594114595114596114597114598114599114600114601114602114603114604114605114606114607114608114609114610114611114612114613114614114615114616114617114618114619114620114621114622114623114624114625114626114627114628114629114630114631114632114633114634114635114636114637114638114639114640114641114642114643114644114645114646114647114648114649114650114651114652114653114654114655114656114657114658114659114660114661114662114663114664114665114666114667114668114669114670114671114672114673114674114675114676114677114678114679114680114681114682114683114684114685114686114687114688114689114690114691114692114693114694114695114696114697114698114699114700114701114702114703114704114705114706114707114708114709114710114711114712114713114714114715114716114717114718114719114720114721114722114723114724114725114726114727114728114729114730114731114732114733114734114735114736114737114738114739114740114741114742114743114744114745114746114747114748114749114750114751114752114753114754114755114756114757114758114759114760114761114762114763114764114765114766114767114768114769114770114771114772114773114774114775114776114777114778114779114780114781114782114783114784114785114786114787114788114789114790114791114792114793114794114795114796114797114798114799114800114801114802114803114804114805114806114807114808114809114810114811114812114813114814114815114816114817114818114819114820114821114822114823114824114825114826114827114828114829114830114831114832114833114834114835114836114837114838114839114840114841114842114843114844114845114846114847114848114849114850114851114852114853114854114855114856114857114858114859114860114861114862114863114864114865114866114867114868114869114870114871114872114873114874114875114876114877114878114879114880114881114882114883114884114885114886114887114888114889114890114891114892114893114894114895114896114897114898114899114900114901114902114903114904114905114906114907114908114909114910114911114912114913114914114915114916114917114918114919114920114921114922114923114924114925114926114927114928114929114930114931114932114933114934114935114936114937114938114939114940114941114942114943114944114945114946114947114948114949114950114951114952114953114954114955114956114957114958114959114960114961114962114963114964114965114966114967114968114969114970114971114972114973114974114975114976114977114978114979114980114981114982114983114984114985114986114987114988114989114990114991114992114993114994114995114996114997114998114999115000115001115002115003115004115005115006115007115008115009115010115011115012115013115014115015115016115017115018115019115020115021115022115023115024115025115026115027115028115029115030115031115032115033115034115035115036115037115038115039115040115041115042115043115044115045115046115047115048115049115050115051115052115053115054115055115056115057115058115059115060115061115062115063115064115065115066115067115068115069115070115071115072115073115074115075115076115077115078115079115080115081115082115083115084115085115086115087115088115089115090115091115092115093115094115095115096115097115098115099115100115101115102115103115104115105115106115107115108115109115110115111115112115113115114115115115116115117115118115119115120115121115122115123115124115125115126115127115128115129115130115131115132115133115134115135115136115137115138115139115140115141115142115143115144115145115146115147115148115149115150115151115152115153115154115155115156115157115158115159115160115161115162115163115164115165115166115167115168115169115170115171115172115173115174115175115176115177115178115179115180115181115182115183115184115185115186115187115188115189115190115191115192115193115194115195115196115197115198115199115200115201115202115203115204115205115206115207115208115209115210115211115212115213115214115215115216115217115218115219115220115221115222115223115224115225115226115227115228115229115230115231115232115233115234115235115236115237115238115239115240115241115242115243115244115245115246115247115248115249115250115251115252115253115254115255115256115257115258115259115260115261115262115263115264115265115266115267115268115269115270115271115272115273115274115275115276115277115278115279115280115281115282115283115284115285115286115287115288115289115290115291115292115293115294115295115296115297115298115299115300115301115302115303115304115305115306115307115308115309115310115311115312115313115314115315115316115317115318115319115320115321115322115323115324115325115326115327115328115329115330115331115332115333115334115335115336115337115338115339115340115341115342115343115344115345115346115347115348115349115350115351115352115353115354115355115356115357115358115359115360115361115362115363115364115365115366115367115368115369115370115371115372115373115374115375115376115377115378115379115380115381115382115383115384115385115386115387115388115389115390115391115392115393115394115395115396115397115398115399115400115401115402115403115404115405115406115407115408115409115410115411115412115413115414115415115416115417115418115419115420115421115422115423115424115425115426115427115428115429115430115431115432115433115434115435115436115437115438115439115440115441115442115443115444115445115446115447115448115449115450115451115452115453115454115455115456115457115458115459115460115461115462115463115464115465115466115467115468115469115470115471115472115473115474115475115476115477115478115479115480115481115482115483115484115485115486115487115488115489115490115491115492115493115494115495115496115497115498115499115500115501115502115503115504115505115506115507115508115509115510115511115512115513115514115515115516115517115518115519115520115521115522115523115524115525115526115527115528115529115530115531115532115533115534115535115536115537115538115539115540115541115542115543115544115545115546115547115548115549115550115551115552115553115554115555115556115557115558115559115560115561115562115563115564115565115566115567115568115569115570115571115572115573115574115575115576115577115578115579115580115581115582115583115584115585115586115587115588115589115590115591115592115593115594115595115596115597115598115599115600115601115602115603115604115605115606115607115608115609115610115611115612115613115614115615115616115617115618115619115620115621115622115623115624115625115626115627115628115629115630115631115632115633115634115635115636115637115638115639115640115641115642115643115644115645115646115647115648115649115650115651115652115653115654115655115656115657115658115659115660115661115662115663115664115665115666115667115668115669115670115671115672115673115674115675115676115677115678115679115680115681115682115683115684115685115686115687115688115689115690115691115692115693115694115695115696115697115698115699115700115701115702115703115704115705115706115707115708115709115710115711115712115713115714115715115716115717115718115719115720115721115722115723115724115725115726115727115728115729115730115731115732115733115734115735115736115737115738115739115740115741115742115743115744115745115746115747115748115749115750115751115752115753115754115755115756115757115758115759115760115761115762115763115764115765115766115767115768115769115770115771115772115773115774115775115776115777115778115779115780115781115782115783115784115785115786115787115788115789115790115791115792115793115794115795115796115797115798115799115800115801115802115803115804115805115806115807115808115809115810115811115812115813115814115815115816115817115818115819115820115821115822115823115824115825115826115827115828115829115830115831115832115833115834115835115836115837115838115839115840115841115842115843115844115845115846115847115848115849115850115851115852115853115854115855115856115857115858115859115860115861115862115863115864115865115866115867115868115869115870115871115872115873115874115875115876115877115878115879115880115881115882115883115884115885115886115887115888115889115890115891115892115893115894115895115896115897115898115899115900115901115902115903115904115905115906115907115908115909115910115911115912115913115914115915115916115917115918115919115920115921115922115923115924115925115926115927115928115929115930115931115932115933115934115935115936115937115938115939115940115941115942115943115944115945115946115947115948115949115950115951115952115953115954115955115956115957115958115959115960115961115962115963115964115965115966115967115968115969115970115971115972115973115974115975115976115977115978115979115980115981115982115983115984115985115986115987115988115989115990115991115992115993115994115995115996115997115998115999116000116001116002116003116004116005116006116007116008116009116010116011116012116013116014116015116016116017116018116019116020116021116022116023116024116025116026116027116028116029116030116031116032116033116034116035116036116037116038116039116040116041116042116043116044116045116046116047116048116049116050116051116052116053116054116055116056116057116058116059116060116061116062116063116064116065116066116067116068116069116070116071116072116073116074116075116076116077116078116079116080116081116082116083116084116085116086116087116088116089116090116091116092116093116094116095116096116097116098116099116100116101116102116103116104116105116106116107116108116109116110116111116112116113116114116115116116116117116118116119116120116121116122116123116124116125116126116127116128116129116130116131116132116133116134116135116136116137116138116139116140116141116142116143116144116145116146116147116148116149116150116151116152116153116154116155116156116157116158116159116160116161116162116163116164116165116166116167116168116169116170116171116172116173116174116175116176116177116178116179116180116181116182116183116184116185116186116187116188116189116190116191116192116193116194116195116196116197116198116199116200116201116202116203116204116205116206116207116208116209116210116211116212116213116214116215116216116217116218116219116220116221116222116223116224116225116226116227116228116229116230116231116232116233116234116235116236116237116238116239116240116241116242116243116244116245116246116247116248116249116250116251116252116253116254116255116256116257116258116259116260116261116262116263116264116265116266116267116268116269116270116271116272116273116274116275116276116277116278116279116280116281116282116283116284116285116286116287116288116289116290116291116292116293116294116295116296116297116298116299116300116301116302116303116304116305116306116307116308116309116310116311116312116313116314116315116316116317116318116319116320116321116322116323116324116325116326116327116328116329116330116331116332116333116334116335116336116337116338116339116340116341116342116343116344116345116346116347116348116349116350116351116352116353116354116355116356116357116358116359116360116361116362116363116364116365116366116367116368116369116370116371116372116373116374116375116376116377116378116379116380116381116382116383116384116385116386116387116388116389116390116391116392116393116394116395116396116397116398116399116400116401116402116403116404116405116406116407116408116409116410116411116412116413116414116415116416116417116418116419116420116421116422116423116424116425116426116427116428116429116430116431116432116433116434116435116436116437116438116439116440116441116442116443116444116445116446116447116448116449116450116451116452116453116454116455116456116457116458116459116460116461116462116463116464116465116466116467116468116469116470116471116472116473116474116475116476116477116478116479116480116481116482116483116484116485116486116487116488116489116490116491116492116493116494116495116496116497116498116499116500116501116502116503116504116505116506116507116508116509116510116511116512116513116514116515116516116517116518116519116520116521116522116523116524116525116526116527116528116529116530116531116532116533116534116535116536116537116538116539116540116541116542116543116544116545116546116547116548116549116550116551116552116553116554116555116556116557116558116559116560116561116562116563116564116565116566116567116568116569116570116571116572116573116574116575116576116577116578116579116580116581116582116583116584116585116586116587116588116589116590116591116592116593116594116595116596116597116598116599116600116601116602116603116604116605116606116607116608116609116610116611116612116613116614116615116616116617116618116619116620116621116622116623116624116625116626116627116628116629116630116631116632116633116634116635116636116637116638116639116640116641116642116643116644116645116646116647116648116649116650116651116652116653116654116655116656116657116658116659116660116661116662116663116664116665116666116667116668116669116670116671116672116673116674116675116676116677116678116679116680116681116682116683116684116685116686116687116688116689116690116691116692116693116694116695116696116697116698116699116700116701116702116703116704116705116706116707116708116709116710116711116712116713116714116715116716116717116718116719116720116721116722116723116724116725116726116727116728116729116730116731116732116733116734116735116736116737116738116739116740116741116742116743116744116745116746116747116748116749116750116751116752116753116754116755116756116757116758116759116760116761116762116763116764116765116766116767116768116769116770116771116772116773116774116775116776116777116778116779116780116781116782116783116784116785116786116787116788116789116790116791116792116793116794116795116796116797116798116799116800116801116802116803116804116805116806116807116808116809116810116811116812116813116814116815116816116817116818116819116820116821116822116823116824116825116826116827116828116829116830116831116832116833116834116835116836116837116838116839116840116841116842116843116844116845116846116847116848116849116850116851116852116853116854116855116856116857116858116859116860116861116862116863116864116865116866116867116868116869116870116871116872116873116874116875116876116877116878116879116880116881116882116883116884116885116886116887116888116889116890116891116892116893116894116895116896116897116898116899116900116901116902116903116904116905116906116907116908116909116910116911116912116913116914116915116916116917116918116919116920116921116922116923116924116925116926116927116928116929116930116931116932116933116934116935116936116937116938116939116940116941116942116943116944116945116946116947116948116949116950116951116952116953116954116955116956116957116958116959116960116961116962116963116964116965116966116967116968116969116970116971116972116973116974116975116976116977116978116979116980116981116982116983116984116985116986116987116988116989116990116991116992116993116994116995116996116997116998116999117000117001117002117003117004117005117006117007117008117009117010117011117012117013117014117015117016117017117018117019117020117021117022117023117024117025117026117027117028117029117030117031117032117033117034117035117036117037117038117039117040117041117042117043117044117045117046117047117048117049117050117051117052117053117054117055117056117057117058117059117060117061117062117063117064117065117066117067117068117069117070117071117072117073117074117075117076117077117078117079117080117081117082117083117084117085117086117087117088117089117090117091117092117093117094117095117096117097117098117099117100117101117102117103117104117105117106117107117108117109117110117111117112117113117114117115117116117117117118117119117120117121117122117123117124117125117126117127117128117129117130117131117132117133117134117135117136117137117138117139117140117141117142117143117144117145117146117147117148117149117150117151117152117153117154117155117156117157117158117159117160117161117162117163117164117165117166117167117168117169117170117171117172117173117174117175117176117177117178117179117180117181117182117183117184117185117186117187117188117189117190117191117192117193117194117195117196117197117198117199117200117201117202117203117204117205117206117207117208117209117210117211117212117213117214117215117216117217117218117219117220117221117222117223117224117225117226117227117228117229117230117231117232117233117234117235117236117237117238117239117240117241117242117243117244117245117246117247117248117249117250117251117252117253117254117255117256117257117258117259117260117261117262117263117264117265117266117267117268117269117270117271117272117273117274117275117276117277117278117279117280117281117282117283117284117285117286117287117288117289117290117291117292117293117294117295117296117297117298117299117300117301117302117303117304117305117306117307117308117309117310117311117312117313117314117315117316117317117318117319117320117321117322117323117324117325117326117327117328117329117330117331117332117333117334117335117336117337117338117339117340117341117342117343117344117345117346117347117348117349117350117351117352117353117354117355117356117357117358117359117360117361117362117363117364117365117366117367117368117369117370117371117372117373117374117375117376117377117378117379117380117381117382117383117384117385117386117387117388117389117390117391117392117393117394117395117396117397117398117399117400117401117402117403117404117405117406117407117408117409117410117411117412117413117414117415117416117417117418117419117420117421117422117423117424117425117426117427117428117429117430117431117432117433117434117435117436117437117438117439117440117441117442117443117444117445117446117447117448117449117450117451117452117453117454117455117456117457117458117459117460117461117462117463117464117465117466117467117468117469117470117471117472117473117474117475117476117477117478117479117480117481117482117483117484117485117486117487117488117489117490117491117492117493117494117495117496117497117498117499117500117501117502117503117504117505117506117507117508117509117510117511117512117513117514117515117516117517117518117519117520117521117522117523117524117525117526117527117528117529117530117531117532117533117534117535117536117537117538117539117540117541117542117543117544117545117546117547117548117549117550117551117552117553117554117555117556117557117558117559117560117561117562117563117564117565117566117567117568117569117570117571117572117573117574117575117576117577117578117579117580117581117582117583117584117585117586117587117588117589117590117591117592117593117594117595117596117597117598117599117600117601117602117603117604117605117606117607117608117609117610117611117612117613117614117615117616117617117618117619117620117621117622117623117624117625117626117627117628117629117630117631117632117633117634117635117636117637117638117639117640117641117642117643117644117645117646117647117648117649117650117651117652117653117654117655117656117657117658117659117660117661117662117663117664117665117666117667117668117669117670117671117672117673117674117675117676117677117678117679117680117681117682117683117684117685117686117687117688117689117690117691117692117693117694117695117696117697117698117699117700117701117702117703117704117705117706117707117708117709117710117711117712117713117714117715117716117717117718117719117720117721117722117723117724117725117726117727117728117729117730117731117732117733117734117735117736117737117738117739117740117741117742117743117744117745117746117747117748117749117750117751117752117753117754117755117756117757117758117759117760117761117762117763117764117765117766117767117768117769117770117771117772117773117774117775117776117777117778117779117780117781117782117783117784117785117786117787117788117789117790117791117792117793117794117795117796117797117798117799117800117801117802117803117804117805117806117807117808117809117810117811117812117813117814117815117816117817117818117819117820117821117822117823117824117825117826117827117828117829117830117831117832117833117834117835117836117837117838117839117840117841117842117843117844117845117846117847117848117849117850117851117852117853117854117855117856117857117858117859117860117861117862117863117864117865117866117867117868117869117870117871117872117873117874117875117876117877117878117879117880117881117882117883117884117885117886117887117888117889117890117891117892117893117894117895117896117897117898117899117900117901117902117903117904117905117906117907117908117909117910117911117912117913117914117915117916117917117918117919117920117921117922117923117924117925117926117927117928117929117930117931117932117933117934117935117936117937117938117939117940117941117942117943117944117945117946117947117948117949117950117951117952117953117954117955117956117957117958117959117960117961117962117963117964117965117966117967117968117969117970117971117972117973117974117975117976117977117978117979117980117981117982117983117984117985117986117987117988117989117990117991117992117993117994117995117996117997117998117999118000118001118002118003118004118005118006118007118008118009118010118011118012118013118014118015118016118017118018118019118020118021118022118023118024118025118026118027118028118029118030118031118032118033118034118035118036118037118038118039118040118041118042118043118044118045118046118047118048118049118050118051118052118053118054118055118056118057118058118059118060118061118062118063118064118065118066118067118068118069118070118071118072118073118074118075118076118077118078118079118080118081118082118083118084118085118086118087118088118089118090118091118092118093118094118095118096118097118098118099118100118101118102118103118104118105118106118107118108118109118110118111118112118113118114118115118116118117118118118119118120118121118122118123118124118125118126118127118128118129118130118131118132118133118134118135118136118137118138118139118140118141118142118143118144118145118146118147118148118149118150118151118152118153118154118155118156118157118158118159118160118161118162118163118164118165118166118167118168118169118170118171118172118173118174118175118176118177118178118179118180118181118182118183118184118185118186118187118188118189118190118191118192118193118194118195118196118197118198118199118200118201118202118203118204118205118206118207118208118209118210118211118212118213118214118215118216118217118218118219118220118221118222118223118224118225118226118227118228118229118230118231118232118233118234118235118236118237118238118239118240118241118242118243118244118245118246118247118248118249118250118251118252118253118254118255118256118257118258118259118260118261118262118263118264118265118266118267118268118269118270118271118272118273118274118275118276118277118278118279118280118281118282118283118284118285118286118287118288118289118290118291118292118293118294118295118296118297118298118299118300118301118302118303118304118305118306118307118308118309118310118311118312118313118314118315118316118317118318118319118320118321118322118323118324118325118326118327118328118329118330118331118332118333118334118335118336118337118338118339118340118341118342118343118344118345118346118347118348118349118350118351118352118353118354118355118356118357118358118359118360118361118362118363118364118365118366118367118368118369118370118371118372118373118374118375118376118377118378118379118380118381118382118383118384118385118386118387118388118389118390118391118392118393118394118395118396118397118398118399118400118401118402118403118404118405118406118407118408118409118410118411118412118413118414118415118416118417118418118419118420118421118422118423118424118425118426118427118428118429118430118431118432118433118434118435118436118437118438118439118440118441118442118443118444118445118446118447118448118449118450118451118452118453118454118455118456118457118458118459118460118461118462118463118464118465118466118467118468118469118470118471118472118473118474118475118476118477118478118479118480118481118482118483118484118485118486118487118488118489118490118491118492118493118494118495118496118497118498118499118500118501118502118503118504118505118506118507118508118509118510118511118512118513118514118515118516118517118518118519118520118521118522118523118524118525118526118527118528118529118530118531118532118533118534118535118536118537118538118539118540118541118542118543118544118545118546118547118548118549118550118551118552118553118554118555118556118557118558118559118560118561118562118563118564118565118566118567118568118569118570118571118572118573118574118575118576118577118578118579118580118581118582118583118584118585118586118587118588118589118590118591118592118593118594118595118596118597118598118599118600118601118602118603118604118605118606118607118608118609118610118611118612118613118614118615118616118617118618118619118620118621118622118623118624118625118626118627118628118629118630118631118632118633118634118635118636118637118638118639118640118641118642118643118644118645118646118647118648118649118650118651118652118653118654118655118656118657118658118659118660118661118662118663118664118665118666118667118668118669118670118671118672118673118674118675118676118677118678118679118680118681118682118683118684118685118686118687118688118689118690118691118692118693118694118695118696118697118698118699118700118701118702118703118704118705118706118707118708118709118710118711118712118713118714118715118716118717118718118719118720118721118722118723118724118725118726118727118728118729118730118731118732118733118734118735118736118737118738118739118740118741118742118743118744118745118746118747118748118749118750118751118752118753118754118755118756118757118758118759118760118761118762118763118764118765118766118767118768118769118770118771118772118773118774118775118776118777118778118779118780118781118782118783118784118785118786118787118788118789118790118791118792118793118794118795118796118797118798118799118800118801118802118803118804118805118806118807118808118809118810118811118812118813118814118815118816118817118818118819118820118821118822118823118824118825118826118827118828118829118830118831118832118833118834118835118836118837118838118839118840118841118842118843118844118845118846118847118848118849118850118851118852118853118854118855118856118857118858118859118860118861118862118863118864118865118866118867118868118869118870118871118872118873118874118875118876118877118878118879118880118881118882118883118884118885118886118887118888118889118890118891118892118893118894118895118896118897118898118899118900118901118902118903118904118905118906118907118908118909118910118911118912118913118914118915118916118917118918118919118920118921118922118923118924118925118926118927118928118929118930118931118932118933118934118935118936118937118938118939118940118941118942118943118944118945118946118947118948118949118950118951118952118953118954118955118956118957118958118959118960118961118962118963118964118965118966118967118968118969118970118971118972118973118974118975118976118977118978118979118980118981118982118983118984118985118986118987118988118989118990118991118992118993118994118995118996118997118998118999119000119001119002119003119004119005119006119007119008119009119010119011119012119013119014119015119016119017119018119019119020119021119022119023119024119025119026119027119028119029119030119031119032119033119034119035119036119037119038119039119040119041119042119043119044119045119046119047119048119049119050119051119052119053119054119055119056119057119058119059119060119061119062119063119064119065119066119067119068119069119070119071119072119073119074119075119076119077119078119079119080119081119082119083119084119085119086119087119088119089119090119091119092119093119094119095119096119097119098119099119100119101119102119103119104119105119106119107119108119109119110119111119112119113119114119115119116119117119118119119119120119121119122119123119124119125119126119127119128119129119130119131119132119133119134119135119136119137119138119139119140119141119142119143119144119145119146119147119148119149119150119151119152119153119154119155119156119157119158119159119160119161119162119163119164119165119166119167119168119169119170119171119172119173119174119175119176119177119178119179119180119181119182119183119184119185119186119187119188119189119190119191119192119193119194119195119196119197119198119199119200119201119202119203119204119205119206119207119208119209119210119211119212119213119214119215119216119217119218119219119220119221119222119223119224119225119226119227119228119229119230119231119232119233119234119235119236119237119238119239119240119241119242119243119244119245119246119247119248119249119250119251119252119253119254119255119256119257119258119259119260119261119262119263119264119265119266119267119268119269119270119271119272119273119274119275119276119277119278119279119280119281119282119283119284119285119286119287119288119289119290119291119292119293119294119295119296119297119298119299119300119301119302119303119304119305119306119307119308119309119310119311119312119313119314119315119316119317119318119319119320119321119322119323119324119325119326119327119328119329119330119331119332119333119334119335119336119337119338119339119340119341119342119343119344119345119346119347119348119349119350119351119352119353119354119355119356119357119358119359119360119361119362119363119364119365119366119367119368119369119370119371119372119373119374119375119376119377119378119379119380119381119382119383119384119385119386119387119388119389119390119391119392119393119394119395119396119397119398119399119400119401119402119403119404119405119406119407119408119409119410119411119412119413119414119415119416119417119418119419119420119421119422119423119424119425119426119427119428119429119430119431119432119433119434119435119436119437119438119439119440119441119442119443119444119445119446119447119448119449119450119451119452119453119454119455119456119457119458119459119460119461119462119463119464119465119466119467119468119469119470119471119472119473119474119475119476119477119478119479119480119481119482119483119484119485119486119487119488119489119490119491119492119493119494119495119496119497119498119499119500119501119502119503119504119505119506119507119508119509119510119511119512119513119514119515119516119517119518119519119520119521119522119523119524119525119526119527119528119529119530119531119532119533119534119535119536119537119538119539119540119541119542119543119544119545119546119547119548119549119550119551119552119553119554119555119556119557119558119559119560119561119562119563119564119565119566119567119568119569119570119571119572119573119574119575119576119577119578119579119580119581119582119583119584119585119586119587119588119589119590119591119592119593119594119595119596119597119598119599119600119601119602119603119604119605119606119607119608119609119610119611119612119613119614119615119616119617119618119619119620119621119622119623119624119625119626119627119628119629119630119631119632119633119634119635119636119637119638119639119640119641119642119643119644119645119646119647119648119649119650119651119652119653119654119655119656119657119658119659119660119661119662119663119664119665119666119667119668119669119670119671119672119673119674119675119676119677119678119679119680119681119682119683119684119685119686119687119688119689119690119691119692119693119694119695119696119697119698119699119700119701119702119703119704119705119706119707119708119709119710119711119712119713119714119715119716119717119718119719119720119721119722119723119724119725119726119727119728119729119730119731119732119733119734119735119736119737119738119739119740119741119742119743119744119745119746119747119748119749119750119751119752119753119754119755119756119757119758119759119760119761119762119763119764119765119766119767119768119769119770119771119772119773119774119775119776119777119778119779119780119781119782119783119784119785119786119787119788119789119790119791119792119793119794119795119796119797119798119799119800119801119802119803119804119805119806119807119808119809119810119811119812119813119814119815119816119817119818119819119820119821119822119823119824119825119826119827119828119829119830119831119832119833119834119835119836119837119838119839119840119841119842119843119844119845119846119847119848119849119850119851119852119853119854119855119856119857119858119859119860119861119862119863119864119865119866119867119868119869119870119871119872119873119874119875119876119877119878119879119880119881119882119883119884119885119886119887119888119889119890119891119892119893119894119895119896119897119898119899119900119901119902119903119904119905119906119907119908119909119910119911119912119913119914119915119916119917119918119919119920119921119922119923119924119925119926119927119928119929119930119931119932119933119934119935119936119937119938119939119940119941119942119943119944119945119946119947119948119949119950119951119952119953119954119955119956119957119958119959119960119961119962119963119964119965119966119967119968119969119970119971119972119973119974119975119976119977119978119979119980119981119982119983119984119985119986119987119988119989119990119991119992119993119994119995119996119997119998119999120000120001120002120003120004120005120006120007120008120009120010120011120012120013120014120015120016120017120018120019120020120021120022120023120024120025120026120027120028120029120030120031120032120033120034120035120036120037120038120039120040120041120042120043120044120045120046120047120048120049120050120051120052120053120054120055120056120057120058120059120060120061120062120063120064120065120066120067120068120069120070120071120072120073120074120075120076120077120078120079120080120081120082120083120084120085120086120087120088120089120090120091120092120093120094120095120096120097120098120099120100120101120102120103120104120105120106120107120108120109120110120111120112120113120114120115120116120117120118120119120120120121120122120123120124120125120126120127120128120129120130120131120132120133120134120135120136120137120138120139120140120141120142120143120144120145120146120147120148120149120150120151120152120153120154120155120156120157120158120159120160120161120162120163120164120165120166120167120168120169120170120171120172120173120174120175120176120177120178120179120180120181120182120183120184120185120186120187120188120189120190120191120192120193120194120195120196120197120198120199120200120201120202120203120204120205120206120207120208120209120210120211120212120213120214120215120216120217120218120219120220120221120222120223120224120225120226120227120228120229120230120231120232120233120234120235120236120237120238120239120240120241120242120243120244120245120246120247120248120249120250120251120252120253120254120255120256120257120258120259120260120261120262120263120264120265120266120267120268120269120270120271120272120273120274120275120276120277120278120279120280120281120282120283120284120285120286120287120288120289120290120291120292120293120294120295120296120297120298120299120300120301120302120303120304120305120306120307120308120309120310120311120312120313120314120315120316120317120318120319120320120321120322120323120324120325120326120327120328120329120330120331120332120333120334120335120336120337120338120339120340120341120342120343120344120345120346120347120348120349120350120351120352120353120354120355120356120357120358120359120360120361120362120363120364120365120366120367120368120369120370120371120372120373120374120375120376120377120378120379120380120381120382120383120384120385120386120387120388120389120390120391120392120393120394120395120396120397120398120399120400120401120402120403120404120405120406120407120408120409120410120411120412120413120414120415120416120417120418120419120420120421120422120423120424120425120426120427120428120429120430120431120432120433120434120435120436120437120438120439120440120441120442120443120444120445120446120447120448120449120450120451120452120453120454120455120456120457120458120459120460120461120462120463120464120465120466120467120468120469120470120471120472120473120474120475120476120477120478120479120480120481120482120483120484120485120486120487120488120489120490120491120492120493120494120495120496120497120498120499120500120501120502120503120504120505120506120507120508120509120510120511120512120513120514120515120516120517120518120519120520120521120522120523120524120525120526120527120528120529120530120531120532120533120534120535120536120537120538120539120540120541120542120543120544120545120546120547120548120549120550120551120552120553120554120555120556120557120558120559120560120561120562120563120564120565120566120567120568120569120570120571120572120573120574120575120576120577120578120579120580120581120582120583120584120585120586120587120588120589120590120591120592120593120594120595120596120597120598120599120600120601120602120603120604120605120606120607120608120609120610120611120612120613120614120615120616120617120618120619120620120621120622120623120624120625120626120627120628120629120630120631120632120633120634120635120636120637120638120639120640120641120642120643120644120645120646120647120648120649120650120651120652120653120654120655120656120657120658120659120660120661120662120663120664120665120666120667120668120669120670120671120672120673120674120675120676120677120678120679120680120681120682120683120684120685120686120687120688120689120690120691120692120693120694120695120696120697120698120699120700120701120702120703120704120705120706120707120708120709120710120711120712120713120714120715120716120717120718120719120720120721120722120723120724120725120726120727120728120729120730120731120732120733120734120735120736120737120738120739120740120741120742120743120744120745120746120747120748120749120750120751120752120753120754120755120756120757120758120759120760120761120762120763120764120765120766120767120768120769120770120771120772120773120774120775120776120777120778120779120780120781120782120783120784120785120786120787120788120789120790120791120792120793120794120795120796120797120798120799120800120801120802120803120804120805120806120807120808120809120810120811120812120813120814120815120816120817120818120819120820120821120822120823120824120825120826120827120828120829120830120831120832120833120834120835120836120837120838120839120840120841120842120843120844120845120846120847120848120849120850120851120852120853120854120855120856120857120858120859120860120861120862120863120864120865120866120867120868120869120870120871120872120873120874120875120876120877120878120879120880120881120882120883120884120885120886120887120888120889120890120891120892120893120894120895120896120897120898120899120900120901120902120903120904120905120906120907120908120909120910120911120912120913120914120915120916120917120918120919120920120921120922120923120924120925120926120927120928120929120930120931120932120933120934120935120936120937120938120939120940120941120942120943120944120945120946120947120948120949120950120951120952120953120954120955120956120957120958120959120960120961120962120963120964120965120966120967120968120969120970120971120972120973120974120975120976120977120978120979120980120981120982120983120984120985120986120987120988120989120990120991120992120993120994120995120996120997120998120999121000121001121002121003121004121005121006121007121008121009121010121011121012121013121014121015121016121017121018121019121020121021121022121023121024121025121026121027121028121029121030121031121032121033121034121035121036121037121038121039121040121041121042121043121044121045121046121047121048121049121050121051121052121053121054121055121056121057121058121059121060121061121062121063121064121065121066121067121068121069121070121071121072121073121074121075121076121077121078121079121080121081121082121083121084121085121086121087121088121089121090121091121092121093121094121095121096121097121098121099121100121101121102121103121104121105121106121107121108121109121110121111121112121113121114121115121116121117121118121119121120121121121122121123121124121125121126121127121128121129121130121131121132121133121134121135121136121137121138121139121140121141121142121143121144121145121146121147121148121149121150121151121152121153121154121155121156121157121158121159121160121161121162121163121164121165121166121167121168121169121170121171121172121173121174121175121176121177121178121179121180121181121182121183121184121185121186121187121188121189121190121191121192121193121194121195121196121197121198121199121200121201121202121203121204121205121206121207121208121209121210121211121212121213121214121215121216121217121218121219121220121221121222121223121224121225121226121227121228121229121230121231121232121233121234121235121236121237121238121239121240121241121242121243121244121245121246121247121248121249121250121251121252121253121254121255121256121257121258121259121260121261121262121263121264121265121266121267121268121269121270121271121272121273121274121275121276121277121278121279121280121281121282121283121284121285121286121287121288121289121290121291121292121293121294121295121296121297121298121299121300121301121302121303121304121305121306121307121308121309121310121311121312121313121314121315121316121317121318121319121320121321121322121323121324121325121326121327121328121329121330121331121332121333121334121335121336121337121338121339121340121341121342121343121344121345121346121347121348121349121350121351121352121353121354121355121356121357121358121359121360121361121362121363121364121365121366121367121368121369121370121371121372121373121374121375121376121377121378121379121380121381121382121383121384121385121386121387121388121389121390121391121392121393121394121395121396121397121398121399121400121401121402121403121404121405121406121407121408121409121410121411121412121413121414121415121416121417121418121419121420121421121422121423121424121425121426121427121428121429121430121431121432121433121434121435121436121437121438121439121440121441121442121443121444121445121446121447121448121449121450121451121452121453121454121455121456121457121458121459121460121461121462121463121464121465121466121467121468121469121470121471121472121473121474121475121476121477121478121479121480121481121482121483121484121485121486121487121488121489121490121491121492121493121494121495121496121497121498121499121500121501121502121503121504121505121506121507121508121509121510121511121512121513121514121515121516121517121518121519121520121521121522121523121524121525121526121527121528121529121530121531121532121533121534121535121536121537121538121539121540121541121542121543121544121545121546121547121548121549121550121551121552121553121554121555121556121557121558121559121560121561121562121563121564121565121566121567121568121569121570121571121572121573121574121575121576121577121578121579121580121581121582121583121584121585121586121587121588121589121590121591121592121593121594121595121596121597121598121599121600121601121602121603121604121605121606121607121608121609121610121611121612121613121614121615121616121617121618121619121620121621121622121623121624121625121626121627121628121629121630121631121632121633121634121635121636121637121638121639121640121641121642121643121644121645121646121647121648121649121650121651121652121653121654121655121656121657121658121659121660121661121662121663121664121665121666121667121668121669121670121671121672121673121674121675121676121677121678121679121680121681121682121683121684121685121686121687121688121689121690121691121692121693121694121695121696121697121698121699121700121701121702121703121704121705121706121707121708121709121710121711121712121713121714121715121716121717121718121719121720121721121722121723121724121725121726121727121728121729121730121731121732121733121734121735121736121737121738121739121740121741121742121743121744121745121746121747121748121749121750121751121752121753121754121755121756121757121758121759121760121761121762121763121764121765121766121767121768121769121770121771121772121773121774121775121776121777121778121779121780121781121782121783121784121785121786121787121788121789121790121791121792121793121794121795121796121797121798121799121800121801121802121803121804121805121806121807121808121809121810121811121812121813121814121815121816121817121818121819121820121821121822121823121824121825121826121827121828121829121830121831121832121833121834121835121836121837121838121839121840121841121842121843121844121845121846121847121848121849121850121851121852121853121854121855121856121857121858121859121860121861121862121863121864121865121866121867121868121869121870121871121872121873121874121875121876121877121878121879121880121881121882121883121884121885121886121887121888121889121890121891121892121893121894121895121896121897121898121899121900121901121902121903121904121905121906121907121908121909121910121911121912121913121914121915121916121917121918121919121920121921121922121923121924121925121926121927121928121929121930121931121932121933121934121935121936121937121938121939121940121941121942121943121944121945121946121947121948121949121950121951121952121953121954121955121956121957121958121959121960121961121962121963121964121965121966121967121968121969121970121971121972121973121974121975121976121977121978121979121980121981121982121983121984121985121986121987121988121989121990121991121992121993121994121995121996121997121998121999122000122001122002122003122004122005122006122007122008122009122010122011122012122013122014122015122016122017122018122019122020122021122022122023122024122025122026122027122028122029122030122031122032122033122034122035122036122037122038122039122040122041122042122043122044122045122046122047122048122049122050122051122052122053122054122055122056122057122058122059122060122061122062122063122064122065122066122067122068122069122070122071122072122073122074122075122076122077122078122079122080122081122082122083122084122085122086122087122088122089122090122091122092122093122094122095122096122097122098122099122100122101122102122103122104122105122106122107122108122109122110122111122112122113122114122115122116122117122118122119122120122121122122122123122124122125122126122127122128122129122130122131122132122133122134122135122136122137122138122139122140122141122142122143122144122145122146122147122148122149122150122151122152122153122154122155122156122157122158122159122160122161122162122163122164122165122166122167122168122169122170122171122172122173122174122175122176122177122178122179122180122181122182122183122184122185122186122187122188122189122190122191122192122193122194122195122196122197122198122199122200122201122202122203122204122205122206122207122208122209122210122211122212122213122214122215122216122217122218122219122220122221122222122223122224122225122226122227122228122229122230122231122232122233122234122235122236122237122238122239122240122241122242122243122244122245122246122247122248122249122250122251122252122253122254122255122256122257122258122259122260122261122262122263122264122265122266122267122268122269122270122271122272122273122274122275122276122277122278122279122280122281122282122283122284122285122286122287122288122289122290122291122292122293122294122295122296122297122298122299122300122301122302122303122304122305122306122307122308122309122310122311122312122313122314122315122316122317122318122319122320122321122322122323122324122325122326122327122328122329122330122331122332122333122334122335122336122337122338122339122340122341122342122343122344122345122346122347122348122349122350122351122352122353122354122355122356122357122358122359122360122361122362122363122364122365122366122367122368122369122370122371122372122373122374122375122376122377122378122379122380122381122382122383122384122385122386122387122388122389122390122391122392122393122394122395122396122397122398122399122400122401122402122403122404122405122406122407122408122409122410122411122412122413122414122415122416122417122418122419122420122421122422122423122424122425122426122427122428122429122430122431122432122433122434122435122436122437122438122439122440122441122442122443122444122445122446122447122448122449122450122451122452122453122454122455122456122457122458122459122460122461122462122463122464122465122466122467122468122469122470122471122472122473122474122475122476122477122478122479122480122481122482122483122484122485122486122487122488122489122490122491122492122493122494122495122496122497122498122499122500122501122502122503122504122505122506122507122508122509122510122511122512122513122514122515122516122517122518122519122520122521122522122523122524122525122526122527122528122529122530122531122532122533122534122535122536122537122538122539122540122541122542122543122544122545122546122547122548122549122550122551122552122553122554122555122556122557122558122559122560122561122562122563122564122565122566122567122568122569122570122571122572122573122574122575122576122577122578122579122580122581122582122583122584122585122586122587122588122589122590122591122592122593122594122595122596122597122598122599122600122601122602122603122604122605122606122607122608122609122610122611122612122613122614122615122616122617122618122619122620122621122622122623122624122625122626122627122628122629122630122631122632122633122634122635122636122637122638122639122640122641122642122643122644122645122646122647122648122649122650122651122652122653122654122655122656122657122658122659122660122661122662122663122664122665122666122667122668122669122670122671122672122673122674122675122676122677122678122679122680122681122682122683122684122685122686122687122688122689122690122691122692122693122694122695122696122697122698122699122700122701122702122703122704122705122706122707122708122709122710122711122712122713122714122715122716122717122718122719122720122721122722122723122724122725122726122727122728122729122730122731122732122733122734122735122736122737122738122739122740122741122742122743122744122745122746122747122748122749122750122751122752122753122754122755122756122757122758122759122760122761122762122763122764122765122766122767122768122769122770122771122772122773122774122775122776122777122778122779122780122781122782122783122784122785122786122787122788122789122790122791122792122793122794122795122796122797122798122799122800122801122802122803122804122805122806122807122808122809122810122811122812122813122814122815122816122817122818122819122820122821122822122823122824122825122826122827122828122829122830122831122832122833122834122835122836122837122838122839122840122841122842122843122844122845122846122847122848122849122850122851122852122853122854122855122856122857122858122859122860122861122862122863122864122865122866122867122868122869122870122871122872122873122874122875122876122877122878122879122880122881122882122883122884122885122886122887122888122889122890122891122892122893122894122895122896122897122898122899122900122901122902122903122904122905122906122907122908122909122910122911122912122913122914122915122916122917122918122919122920122921122922122923122924122925122926122927122928122929122930122931122932122933122934122935122936122937122938122939122940122941122942122943122944122945122946122947122948122949122950122951122952122953122954122955122956122957122958122959122960122961122962122963122964122965122966122967122968122969122970122971122972122973122974122975122976122977122978122979122980122981122982122983122984122985122986122987122988122989122990122991122992122993122994122995122996122997122998122999123000123001123002123003123004123005123006123007123008123009123010123011123012123013123014123015123016123017123018123019123020123021123022123023123024123025123026123027123028123029123030123031123032123033123034123035123036123037123038123039123040123041123042123043123044123045123046123047123048123049123050123051123052123053123054123055123056123057123058123059123060123061123062123063123064123065123066123067123068123069123070123071123072123073123074123075123076123077123078123079123080123081123082123083123084123085123086123087123088123089123090123091123092123093123094123095123096123097123098123099123100123101123102123103123104123105123106123107123108123109123110123111123112123113123114123115123116123117123118123119123120123121123122123123123124123125123126123127123128123129123130123131123132123133123134123135123136123137123138123139123140123141123142123143123144123145123146123147123148123149123150123151123152123153123154123155123156123157123158123159123160123161123162123163123164123165123166123167123168123169123170123171123172123173123174123175123176123177123178123179123180123181123182123183123184123185123186123187123188123189123190123191123192123193123194123195123196123197123198123199123200123201123202123203123204123205123206123207123208123209123210123211123212123213123214123215123216123217123218123219123220123221123222123223123224123225123226123227123228123229123230123231123232123233123234123235123236123237123238123239123240123241123242123243123244123245123246123247123248123249123250123251123252123253123254123255123256123257123258123259123260123261123262123263123264123265123266123267123268123269123270123271123272123273123274123275123276123277123278123279123280123281123282123283123284123285123286123287123288123289123290123291123292123293123294123295123296123297123298123299123300123301123302123303123304123305123306123307123308123309123310123311123312123313123314123315123316123317123318123319123320123321123322123323123324123325123326123327123328123329123330123331123332123333123334123335123336123337123338123339123340123341123342123343123344123345123346123347123348123349123350123351123352123353123354123355123356123357123358123359123360123361123362123363123364123365123366123367123368123369123370123371123372123373123374123375123376123377123378123379123380123381123382123383123384123385123386123387123388123389123390123391123392123393123394123395123396123397123398123399123400123401123402123403123404123405123406123407123408123409123410123411123412123413123414123415123416123417123418123419123420123421123422123423123424123425123426123427123428123429123430123431123432123433123434123435123436123437123438123439123440123441123442123443123444123445123446123447123448123449123450123451123452123453123454123455123456123457123458123459123460123461123462123463123464123465123466123467123468123469123470123471123472123473123474123475123476123477123478123479123480123481123482123483123484123485123486123487123488123489123490123491123492123493123494123495123496123497123498123499123500123501123502123503123504123505123506123507123508123509123510123511123512123513123514123515123516123517123518123519123520123521123522123523123524123525123526123527123528123529123530123531123532123533123534123535123536123537123538123539123540123541123542123543123544123545123546123547123548123549123550123551123552123553123554123555123556123557123558123559123560123561123562123563123564123565123566123567123568123569123570123571123572123573123574123575123576123577123578123579123580123581123582123583123584123585123586123587123588123589123590123591123592123593123594123595123596123597123598123599123600123601123602123603123604123605123606123607123608123609123610123611123612123613123614123615123616123617123618123619123620123621123622123623123624123625123626123627123628123629123630123631123632123633123634123635123636123637123638123639123640123641123642123643123644123645123646123647123648123649123650123651123652123653123654123655123656123657123658123659123660123661123662123663123664123665123666123667123668123669123670123671123672123673123674123675123676123677123678123679123680123681123682123683123684123685123686123687123688123689123690123691123692123693123694123695123696123697123698123699123700123701123702123703123704123705123706123707123708123709123710123711123712123713123714123715123716123717123718123719123720123721123722123723123724123725123726123727123728123729123730123731123732123733123734123735123736123737123738123739123740123741123742123743123744123745123746123747123748123749123750123751123752123753123754123755123756123757123758123759123760123761123762123763123764123765123766123767123768123769123770123771123772123773123774123775123776123777123778123779123780123781123782123783123784123785123786123787123788123789123790123791123792123793123794123795123796123797123798123799123800123801123802123803123804123805123806123807123808123809123810123811123812123813123814123815123816123817123818123819123820123821123822123823123824123825123826123827123828123829123830123831123832123833123834123835123836123837123838123839123840123841123842123843123844123845123846123847123848123849123850123851123852123853123854123855123856123857123858123859123860123861123862123863123864123865123866123867123868123869123870123871123872123873123874123875123876123877123878123879123880123881123882123883123884123885123886123887123888123889123890123891123892123893123894123895123896123897123898123899123900123901123902123903123904123905123906123907123908123909123910123911123912123913123914123915123916123917123918123919123920123921123922123923123924123925123926123927123928123929123930123931123932123933123934123935123936123937123938123939123940123941123942123943123944123945123946123947123948123949123950123951123952123953123954123955123956123957123958123959123960123961123962123963123964123965123966123967123968123969123970123971123972123973123974123975123976123977123978123979123980123981123982123983123984123985123986123987123988123989123990123991123992123993123994123995123996123997123998123999124000124001124002124003124004124005124006124007124008124009124010124011124012124013124014124015124016124017124018124019124020124021124022124023124024124025124026124027124028124029124030124031124032124033124034124035124036124037124038124039124040124041124042124043124044124045124046124047124048124049124050124051124052124053124054124055124056124057124058124059124060124061124062124063124064124065124066124067124068124069124070124071124072124073124074124075124076124077124078124079124080124081124082124083124084124085124086124087124088124089124090124091124092124093124094124095124096124097124098124099124100124101124102124103124104124105124106124107124108124109124110124111124112124113124114124115124116124117124118124119124120124121124122124123124124124125124126124127124128124129124130124131124132124133124134124135124136124137124138124139124140124141124142124143124144124145124146124147124148124149124150124151124152124153124154124155124156124157124158124159124160124161124162124163124164124165124166124167124168124169124170124171124172124173124174124175124176124177124178124179124180124181124182124183124184124185124186124187124188124189124190124191124192124193124194124195124196124197124198124199124200124201124202124203124204124205124206124207124208124209124210124211124212124213124214124215124216124217124218124219124220124221124222124223124224124225124226124227124228124229124230124231124232124233124234124235124236124237124238124239124240124241124242124243124244124245124246124247124248124249124250124251124252124253124254124255124256124257124258124259124260124261124262124263124264124265124266124267124268124269124270124271124272124273124274124275124276124277124278124279124280124281124282124283124284124285124286124287124288124289124290124291124292124293124294124295124296124297124298124299124300124301124302124303124304124305124306124307124308124309124310124311124312124313124314124315124316124317124318124319124320124321124322124323124324124325124326124327124328124329124330124331124332124333124334124335124336124337124338124339124340124341124342124343124344124345124346124347124348124349124350124351124352124353124354124355124356124357124358124359124360124361124362124363124364124365124366124367124368124369124370124371124372124373124374124375124376124377124378124379124380124381124382124383124384124385124386124387124388124389124390124391124392124393124394124395124396124397124398124399124400124401124402124403124404124405124406124407124408124409124410124411124412124413124414124415124416124417124418124419124420124421124422124423124424124425124426124427124428124429124430124431124432124433124434124435124436124437124438124439124440124441124442124443124444124445124446124447124448124449124450124451124452124453124454124455124456124457124458124459124460124461124462124463124464124465124466124467124468124469124470124471124472124473124474124475124476124477124478124479124480124481124482124483124484124485124486124487124488124489124490124491124492124493124494124495124496124497124498124499124500124501124502124503124504124505124506124507124508124509124510124511124512124513124514124515124516124517124518124519124520124521124522124523124524124525124526124527124528124529124530124531124532124533124534124535124536124537124538124539124540124541124542124543124544124545124546124547124548124549124550124551124552124553124554124555124556124557124558124559124560124561124562124563124564124565124566124567124568124569124570124571124572124573124574124575124576124577124578124579124580124581124582124583124584124585124586124587124588124589124590124591124592124593124594124595124596124597124598124599124600124601124602124603124604124605124606124607124608124609124610124611124612124613124614124615124616124617124618124619124620124621124622124623124624124625124626124627124628124629124630124631124632124633124634124635124636124637124638124639124640124641124642124643124644124645124646124647124648124649124650124651124652124653124654124655124656124657124658124659124660124661124662124663124664124665124666124667124668124669124670124671124672124673124674124675124676124677124678124679124680124681124682124683124684124685124686124687124688124689124690124691124692124693124694124695124696124697124698124699124700124701124702124703124704124705124706124707124708124709124710124711124712124713124714124715124716124717124718124719124720124721124722124723124724124725124726124727124728124729124730124731124732124733124734124735124736124737124738124739124740124741124742124743124744124745124746124747124748124749124750124751124752124753124754124755124756124757124758124759124760124761124762124763124764124765124766124767124768124769124770124771124772124773124774124775124776124777124778124779124780124781124782124783124784124785124786124787124788124789124790124791124792124793124794124795124796124797124798124799124800124801124802124803124804124805124806124807124808124809124810124811124812124813124814124815124816124817124818124819124820124821124822124823124824124825124826124827124828124829124830124831124832124833124834124835124836124837124838124839124840124841124842124843124844124845124846124847124848124849124850124851124852124853124854124855124856124857124858124859124860124861124862124863124864124865124866124867124868124869124870124871124872124873124874124875124876124877124878124879124880124881124882124883124884124885124886124887124888124889124890124891124892124893124894124895124896124897124898124899124900124901124902124903124904124905124906124907124908124909124910124911124912124913124914124915124916124917124918124919124920124921124922124923124924124925124926124927124928124929124930124931124932124933124934124935124936124937124938124939124940124941124942124943124944124945124946124947124948124949124950124951124952124953124954124955124956124957124958124959124960124961124962124963124964124965124966124967124968124969124970124971124972124973124974124975124976124977124978124979124980124981124982124983124984124985124986124987124988124989124990124991124992124993124994124995124996124997124998124999125000125001125002125003125004125005125006125007125008125009125010125011125012125013125014125015125016125017125018125019125020125021125022125023125024125025125026125027125028125029125030125031125032125033125034125035125036125037125038125039125040125041125042125043125044125045125046125047125048125049125050125051125052125053125054125055125056125057125058125059125060125061125062125063125064125065125066125067125068125069125070125071125072125073125074125075125076125077125078125079125080125081125082125083125084125085125086125087125088125089125090125091125092125093125094125095125096125097125098125099125100125101125102125103125104125105125106125107125108125109125110125111125112125113125114125115125116125117125118125119125120125121125122125123125124125125125126125127125128125129125130125131125132125133125134125135125136125137125138125139125140125141125142125143125144125145125146125147125148125149125150125151125152125153125154125155125156125157125158125159125160125161125162125163125164125165125166125167125168125169125170125171125172125173125174125175125176125177125178125179125180125181125182125183125184125185125186125187125188125189125190125191125192125193125194125195125196125197125198125199125200125201125202125203125204125205125206125207125208125209125210125211125212125213125214125215125216125217125218125219125220125221125222125223125224125225125226125227125228125229125230125231125232125233125234125235125236125237125238125239125240125241125242125243125244125245125246125247125248125249125250125251125252125253125254125255125256125257125258125259125260125261125262125263125264125265125266125267125268125269125270125271125272125273125274125275125276125277125278125279125280125281125282125283125284125285125286125287125288125289125290125291125292125293125294125295125296125297125298125299125300125301125302125303125304125305125306125307125308125309125310125311125312125313125314125315125316125317125318125319125320125321125322125323125324125325125326125327125328125329125330125331125332125333125334125335125336125337125338125339125340125341125342125343125344125345125346125347125348125349125350125351125352125353125354125355125356125357125358125359125360125361125362125363125364125365125366125367125368125369125370125371125372125373125374125375125376125377125378125379125380125381125382125383125384125385125386125387125388125389125390125391125392125393125394125395125396125397125398125399125400125401125402125403125404125405125406125407125408125409125410125411125412125413125414125415125416125417125418125419125420125421125422125423125424125425125426125427125428125429125430125431125432125433125434125435125436125437125438125439125440125441125442125443125444125445125446125447125448125449125450125451125452125453125454125455125456125457125458125459125460125461125462125463125464125465125466125467125468125469125470125471125472125473125474125475125476125477125478125479125480125481125482125483125484125485125486125487125488125489125490125491125492125493125494125495125496125497125498125499125500125501125502125503125504125505125506125507125508125509125510125511125512125513125514125515125516125517125518125519125520125521125522125523125524125525125526125527125528125529125530125531125532125533125534125535125536125537125538125539125540125541125542125543125544125545125546125547125548125549125550125551125552125553125554125555125556125557125558125559125560125561125562125563125564125565125566125567125568125569125570125571125572125573125574125575125576125577125578125579125580125581125582125583125584125585125586125587125588125589125590125591125592125593125594125595125596125597125598125599125600125601125602125603125604125605125606125607125608125609125610125611125612125613125614125615125616125617125618125619125620125621125622125623125624125625125626125627125628125629125630125631125632125633125634125635125636125637125638125639125640125641125642125643125644125645125646125647125648125649125650125651125652125653125654125655125656125657125658125659125660125661125662125663125664125665125666125667125668125669125670125671125672125673125674125675125676125677125678125679125680125681125682125683125684125685125686125687125688125689125690125691125692125693125694125695125696125697125698125699125700125701125702125703125704125705125706125707125708125709125710125711125712125713125714125715125716125717125718125719125720125721125722125723125724125725125726125727125728125729125730125731125732125733125734125735125736125737125738125739125740125741125742125743125744125745125746125747125748125749125750125751125752125753125754125755125756125757125758125759125760125761125762125763125764125765125766125767125768125769125770125771125772125773125774125775125776125777125778125779125780125781125782125783125784125785125786125787125788125789125790125791125792125793125794125795125796125797125798125799125800125801125802125803125804125805125806125807125808125809125810125811125812125813125814125815125816125817125818125819125820125821125822125823125824125825125826125827125828125829125830125831125832125833125834125835125836125837125838125839125840125841125842125843125844125845125846125847125848125849125850125851125852125853125854125855125856125857125858125859125860125861125862125863125864125865125866125867125868125869125870125871125872125873125874125875125876125877125878125879125880125881125882125883125884125885125886125887125888125889125890125891125892125893125894125895125896125897125898125899125900125901125902125903125904125905125906125907125908125909125910125911125912125913125914125915125916125917125918125919125920125921125922125923125924125925125926125927125928125929125930125931125932125933125934125935125936125937125938125939125940125941125942125943125944125945125946125947125948125949125950125951125952125953125954125955125956125957125958125959125960125961125962125963125964125965125966125967125968125969125970125971125972125973125974125975125976125977125978125979125980125981125982125983125984125985125986125987125988125989125990125991125992125993125994125995125996125997125998125999126000126001126002126003126004126005126006126007126008126009126010126011126012126013126014126015126016126017126018126019126020126021126022126023126024126025126026126027126028126029126030126031126032126033126034126035126036126037126038126039126040126041126042126043126044126045126046126047126048126049126050126051126052126053126054126055126056126057126058126059126060126061126062126063126064126065126066126067126068126069126070126071126072126073126074126075126076126077126078126079126080126081126082126083126084126085126086126087126088126089126090126091126092126093126094126095126096126097126098126099126100126101126102126103126104126105126106126107126108126109126110126111126112126113126114126115126116126117126118126119126120126121126122126123126124126125126126126127126128126129126130126131126132126133126134126135126136126137126138126139126140126141126142126143126144126145126146126147126148126149126150126151126152126153126154126155126156126157126158126159126160126161126162126163126164126165126166126167126168126169126170126171126172126173126174126175126176126177126178126179126180126181126182126183126184126185126186126187126188126189126190126191126192126193126194126195126196126197126198126199126200126201126202126203126204126205126206126207126208126209126210126211126212126213126214126215126216126217126218126219126220126221126222126223126224126225126226126227126228126229126230126231126232126233126234126235126236126237126238126239126240126241126242126243126244126245126246126247126248126249126250126251126252126253126254126255126256126257126258126259126260126261126262126263126264126265126266126267126268126269126270126271126272126273126274126275126276126277126278126279126280126281126282126283126284126285126286126287126288126289126290126291126292126293126294126295126296126297126298126299126300126301126302126303126304126305126306126307126308126309126310126311126312126313126314126315126316126317126318126319126320126321126322126323126324126325126326126327126328126329126330126331126332126333126334126335126336126337126338126339126340126341126342126343126344126345126346126347126348126349126350126351126352126353126354126355126356126357126358126359126360126361126362126363126364126365126366126367126368126369126370126371126372126373126374126375126376126377126378126379126380126381126382126383126384126385126386126387126388126389126390126391126392126393126394126395126396126397126398126399126400126401126402126403126404126405126406126407126408126409126410126411126412126413126414126415126416126417126418126419126420126421126422126423126424126425126426126427126428126429126430126431126432126433126434126435126436126437126438126439126440126441126442126443126444126445126446126447126448126449126450126451126452126453126454126455126456126457126458126459126460126461126462126463126464126465126466126467126468126469126470126471126472126473126474126475126476126477126478126479126480126481126482126483126484126485126486126487126488126489126490126491126492126493126494126495126496126497126498126499126500126501126502126503126504126505126506126507126508126509126510126511126512126513126514126515126516126517126518126519126520126521126522126523126524126525126526126527126528126529126530126531126532126533126534126535126536126537126538126539126540126541126542126543126544126545126546126547126548126549126550126551126552126553126554126555126556126557126558126559126560126561126562126563126564126565126566126567126568126569126570126571126572126573126574126575126576126577126578126579126580126581126582126583126584126585126586126587126588126589126590126591126592126593126594126595126596126597126598126599126600126601126602126603126604126605126606126607126608126609126610126611126612126613126614126615126616126617126618126619126620126621126622126623126624126625126626126627126628126629126630126631126632126633126634126635126636126637126638126639126640126641126642126643126644126645126646126647126648126649126650126651126652126653126654126655126656126657126658126659126660126661126662126663126664126665126666126667126668126669126670126671126672126673126674126675126676126677126678126679126680126681126682126683126684126685126686126687126688126689126690126691126692126693126694126695126696126697126698126699126700126701126702126703126704126705126706126707126708126709126710126711126712126713126714126715126716126717126718126719126720126721126722126723126724126725126726126727126728126729126730126731126732126733126734126735126736126737126738126739126740126741126742126743126744126745126746126747126748126749126750126751126752126753126754126755126756126757126758126759126760126761126762126763126764126765126766126767126768126769126770126771126772126773126774126775126776126777126778126779126780126781126782126783126784126785126786126787126788126789126790126791126792126793126794126795126796126797126798126799126800126801126802126803126804126805126806126807126808126809126810126811126812126813126814126815126816126817126818126819126820126821126822126823126824126825126826126827126828126829126830126831126832126833126834126835126836126837126838126839126840126841126842126843126844126845126846126847126848126849126850126851126852126853126854126855126856126857126858126859126860126861126862126863126864126865126866126867126868126869126870126871126872126873126874126875126876126877126878126879126880126881126882126883126884126885126886126887126888126889126890126891126892126893126894126895126896126897126898126899126900126901126902126903126904126905126906126907126908126909126910126911126912126913126914126915126916126917126918126919126920126921126922126923126924126925126926126927126928126929126930126931126932126933126934126935126936126937126938126939126940126941126942126943126944126945126946126947126948126949126950126951126952126953126954126955126956126957126958126959126960126961126962126963126964126965126966126967126968126969126970126971126972126973126974126975126976126977126978126979126980126981126982126983126984126985126986126987126988126989126990126991126992126993126994126995126996126997126998126999127000127001127002127003127004127005127006127007127008127009127010127011127012127013127014127015127016127017127018127019127020127021127022127023127024127025127026127027127028127029127030127031127032127033127034127035127036127037127038127039127040127041127042127043127044127045127046127047127048127049127050127051127052127053127054127055127056127057127058127059127060127061127062127063127064127065127066127067127068127069127070127071127072127073127074127075127076127077127078127079127080127081127082127083127084127085127086127087127088127089127090127091127092127093127094127095127096127097127098127099127100127101127102127103127104127105127106127107127108127109127110127111127112127113127114127115127116127117127118127119127120127121127122127123127124127125127126127127127128127129127130127131127132127133127134127135127136127137127138127139127140127141127142127143127144127145127146127147127148127149127150127151127152127153127154127155127156127157127158127159127160127161127162127163127164127165127166127167127168127169127170127171127172127173127174127175127176127177127178127179127180127181127182127183127184127185127186127187127188127189127190127191127192127193127194127195127196127197127198127199127200127201127202127203127204127205127206127207127208127209127210127211127212127213127214127215127216127217127218127219127220127221127222127223127224127225127226127227127228127229127230127231127232127233127234127235127236127237127238127239127240127241127242127243127244127245127246127247127248127249127250127251127252127253127254127255127256127257127258127259127260127261127262127263127264127265127266127267127268127269127270127271127272127273127274127275127276127277127278127279127280127281127282127283127284127285127286127287127288127289127290127291127292127293127294127295127296127297127298127299127300127301127302127303127304127305127306127307127308127309127310127311127312127313127314127315127316127317127318127319127320127321127322127323127324127325127326127327127328127329127330127331127332127333127334127335127336127337127338127339127340127341127342127343127344127345127346127347127348127349127350127351127352127353127354127355127356127357127358127359127360127361127362127363127364127365127366127367127368127369127370127371127372127373127374127375127376127377127378127379127380127381127382127383127384127385127386127387127388127389127390127391127392127393127394127395127396127397127398127399127400127401127402127403127404127405127406127407127408127409127410127411127412127413127414127415127416127417127418127419127420127421127422127423127424127425127426127427127428127429127430127431127432127433127434127435127436127437127438127439127440127441127442127443127444127445127446127447127448127449127450127451127452127453127454127455127456127457127458127459127460127461127462127463127464127465127466127467127468127469127470127471127472127473127474127475127476127477127478127479127480127481127482127483127484127485127486127487127488127489127490127491127492127493127494127495127496127497127498127499127500127501127502127503127504127505127506127507127508127509127510127511127512127513127514127515127516127517127518127519127520127521127522127523127524127525127526127527127528127529127530127531127532127533127534127535127536127537127538127539127540127541127542127543127544127545127546127547127548127549127550127551127552127553127554127555127556127557127558127559127560127561127562127563127564127565127566127567127568127569127570127571127572127573127574127575127576127577127578127579127580127581127582127583127584127585127586127587127588127589127590127591127592127593127594127595127596127597127598127599127600127601127602127603127604127605127606127607127608127609127610127611127612127613127614127615127616127617127618127619127620127621127622127623127624127625127626127627127628127629127630127631127632127633127634127635127636127637127638127639127640127641127642127643127644127645127646127647127648127649127650127651127652127653127654127655127656127657127658127659127660127661127662127663127664127665127666127667127668127669127670127671127672127673127674127675127676127677127678127679127680127681127682127683127684127685127686127687127688127689127690127691127692127693127694127695127696127697127698127699127700127701127702127703127704127705127706127707127708127709127710127711127712127713127714127715127716127717127718127719127720127721127722127723127724127725127726127727127728127729127730127731127732127733127734127735127736127737127738127739127740127741127742127743127744127745127746127747127748127749127750127751127752127753127754127755127756127757127758127759127760127761127762127763127764127765127766127767127768127769127770127771127772127773127774127775127776127777127778127779127780127781127782127783127784127785127786127787127788127789127790127791127792127793127794127795127796127797127798127799127800127801127802127803127804127805127806127807127808127809127810127811127812127813127814127815127816127817127818127819127820127821127822127823127824127825127826127827127828127829127830127831127832127833127834127835127836127837127838127839127840127841127842127843127844127845127846127847127848127849127850127851127852127853127854127855127856127857127858127859127860127861127862127863127864127865127866127867127868127869127870127871127872127873127874127875127876127877127878127879127880127881127882127883127884127885127886127887127888127889127890127891127892127893127894127895127896127897127898127899127900127901127902127903127904127905127906127907127908127909127910127911127912127913127914127915127916127917127918127919127920127921127922127923127924127925127926127927127928127929127930127931127932127933127934127935127936127937127938127939127940127941127942127943127944127945127946127947127948127949127950127951127952127953127954127955127956127957127958127959127960127961127962127963127964127965127966127967127968127969127970127971127972127973127974127975127976127977127978127979127980127981127982127983127984127985127986127987127988127989127990127991127992127993127994127995127996127997127998127999128000128001128002128003128004128005128006128007128008128009128010128011128012128013128014128015128016128017128018128019128020128021128022128023128024128025128026128027128028128029128030128031128032128033128034128035128036128037128038128039128040128041128042128043128044128045128046128047128048128049128050128051128052128053128054128055128056128057128058128059128060128061128062128063128064128065128066128067128068128069128070128071128072128073128074128075128076128077128078128079128080128081128082128083128084128085128086128087128088128089128090128091128092128093128094128095128096128097128098128099128100128101128102128103128104128105128106128107128108128109128110128111128112128113128114128115128116128117128118128119128120128121128122128123128124128125128126128127128128128129128130128131128132128133128134128135128136128137128138128139128140128141128142128143128144128145128146128147128148128149128150128151128152128153128154128155128156128157128158128159128160128161128162128163128164128165128166128167128168128169128170128171128172128173128174128175128176128177128178128179128180128181128182128183128184128185128186128187128188128189128190128191128192128193128194128195128196128197128198128199128200128201128202128203128204128205128206128207128208128209128210128211128212128213128214128215128216128217128218128219128220128221128222128223128224128225128226128227128228128229128230128231128232128233128234128235128236128237128238128239128240128241128242128243128244128245128246128247128248128249128250128251128252128253128254128255128256128257128258128259128260128261128262128263128264128265128266128267128268128269128270128271128272128273128274128275128276128277128278128279128280128281128282128283128284128285128286128287128288128289128290128291128292128293128294128295128296128297128298128299128300128301128302128303128304128305128306128307128308128309128310128311128312128313128314128315128316128317128318128319128320128321128322128323128324128325128326128327128328128329128330128331128332128333128334128335128336128337128338128339128340128341128342128343128344128345128346128347128348128349128350128351128352128353128354128355128356128357128358128359128360128361128362128363128364128365128366128367128368128369128370128371128372128373128374128375128376128377128378128379128380128381128382128383128384128385128386128387128388128389128390128391128392128393128394128395128396128397128398128399128400128401128402128403128404128405128406128407128408128409128410128411128412128413128414128415128416128417128418128419128420128421128422128423128424128425128426128427128428128429128430128431128432128433128434128435128436128437128438128439128440128441128442128443128444128445128446128447128448128449128450128451128452128453128454128455128456128457128458128459128460128461128462128463128464128465128466128467128468128469128470128471128472128473128474128475128476128477128478128479128480128481128482128483128484128485128486128487128488128489128490128491128492128493128494128495128496128497128498128499128500128501128502128503128504128505128506128507128508128509128510128511128512128513128514128515128516128517128518128519128520128521128522128523128524128525128526128527128528128529128530128531128532128533128534128535128536128537128538128539128540128541128542128543128544128545128546128547128548128549128550128551128552128553128554128555128556128557128558128559128560128561128562128563128564128565128566128567128568128569128570128571128572128573128574128575128576128577128578128579128580128581128582128583128584128585128586128587128588128589128590128591128592128593128594128595128596128597128598128599128600128601128602128603128604128605128606128607128608128609128610128611128612128613128614128615128616128617128618128619128620128621128622128623128624128625128626128627128628128629128630128631128632128633128634128635128636128637128638128639128640128641128642128643128644128645128646128647128648128649128650128651128652128653128654128655128656128657128658128659128660128661128662128663128664128665128666128667128668128669128670128671128672128673128674128675128676128677128678128679128680128681128682128683128684128685128686128687128688128689128690128691128692128693128694128695128696128697128698128699128700128701128702128703128704128705128706128707128708128709128710128711128712128713128714128715128716128717128718128719128720128721128722128723128724128725128726128727128728128729128730128731128732128733128734128735128736128737128738128739128740128741128742128743128744128745128746128747128748128749128750128751128752128753128754128755128756128757128758128759128760128761128762128763128764128765128766128767128768128769128770128771128772128773128774128775128776128777128778128779128780128781128782128783128784128785128786128787128788128789128790128791128792128793128794128795128796128797128798128799128800128801128802128803128804128805128806128807128808128809128810128811128812128813128814128815128816128817128818128819128820128821128822128823128824128825128826128827128828128829128830128831128832128833128834128835128836128837128838128839128840128841128842128843128844128845128846128847128848128849128850128851128852128853128854128855128856128857128858128859128860128861128862128863128864128865128866128867128868128869128870128871128872128873128874128875128876128877128878128879128880128881128882128883128884128885128886128887128888128889128890128891128892128893128894128895128896128897128898128899128900128901128902128903128904128905128906128907128908128909128910128911128912128913128914128915128916128917128918128919128920128921128922128923128924128925128926128927128928128929128930128931128932128933128934128935128936128937128938128939128940128941128942128943128944128945128946128947128948128949128950128951128952128953128954128955128956128957128958128959128960128961128962128963128964128965128966128967128968128969128970128971128972128973128974128975128976128977128978128979128980128981128982128983128984128985128986128987128988128989128990128991128992128993128994128995128996128997128998128999129000129001129002129003129004129005129006129007129008129009129010129011129012129013129014129015129016129017129018129019129020129021129022129023129024129025129026129027129028129029129030129031129032129033129034129035129036129037129038129039129040129041129042129043129044129045129046129047129048129049129050129051129052129053129054129055129056129057129058129059129060129061129062129063129064129065129066129067129068129069129070129071129072129073129074129075129076129077129078129079129080129081129082129083129084129085129086129087129088129089129090129091129092129093129094129095129096129097129098129099129100129101129102129103129104129105129106129107129108129109129110129111129112129113129114129115129116129117129118129119129120129121129122129123129124129125129126129127129128129129129130129131129132129133129134129135129136129137129138129139129140129141129142129143129144129145129146129147129148129149129150129151129152129153129154129155129156129157129158129159129160129161129162129163129164129165129166129167129168129169129170129171129172129173129174129175129176129177129178129179129180129181129182129183129184129185129186129187129188129189129190129191129192129193129194129195129196129197129198129199129200129201129202129203129204129205129206129207129208129209129210129211129212129213129214129215129216129217129218129219129220129221129222129223129224129225129226129227129228129229129230129231129232129233129234129235129236129237129238129239129240129241129242129243129244129245129246129247129248129249129250129251129252129253129254129255129256129257129258129259129260129261129262129263129264129265129266129267129268129269129270129271129272129273129274129275129276129277129278129279129280129281129282129283129284129285129286129287129288129289129290129291129292129293129294129295129296129297129298129299129300129301129302129303129304129305129306129307129308129309129310129311129312129313129314129315129316129317129318129319129320129321129322129323129324129325129326129327129328129329129330129331129332129333129334129335129336129337129338129339129340129341129342129343129344129345129346129347129348129349129350129351129352129353129354129355129356129357129358129359129360129361129362129363129364129365129366129367129368129369129370129371129372129373129374129375129376129377129378129379129380129381129382129383129384129385129386129387129388129389129390129391129392129393129394129395129396129397129398129399129400129401129402129403129404129405129406129407129408129409129410129411129412129413129414129415129416129417129418129419129420129421129422129423129424129425129426129427129428129429129430129431129432129433129434129435129436129437129438129439129440129441129442129443129444129445129446129447129448129449129450129451129452129453129454129455129456129457129458129459129460129461129462129463129464129465129466129467129468129469129470129471129472129473129474129475129476129477129478129479129480129481129482129483129484129485129486129487129488129489129490129491129492129493129494129495129496129497129498129499129500129501129502129503129504129505129506129507129508129509129510129511129512129513129514129515129516129517129518129519129520129521129522129523129524129525129526129527129528129529129530129531129532129533129534129535129536129537129538129539129540129541129542129543129544129545129546129547129548129549129550129551129552129553129554129555129556129557129558129559129560129561129562129563129564129565129566129567129568129569129570129571129572129573129574129575129576129577129578129579129580129581129582129583129584129585129586129587129588129589129590129591129592129593129594129595129596129597129598129599129600129601129602129603129604129605129606129607129608129609129610129611129612129613129614129615129616129617129618129619129620129621129622129623129624129625129626129627129628129629129630129631129632129633129634129635129636129637129638129639129640129641129642129643129644129645129646129647129648129649129650129651129652129653129654129655129656129657129658129659129660129661129662129663129664129665129666129667129668129669129670129671129672129673129674129675129676129677129678129679129680129681129682129683129684129685129686129687129688129689129690129691129692129693129694129695129696129697129698129699129700129701129702129703129704129705129706129707129708129709129710129711129712129713129714129715129716129717129718129719129720129721129722129723129724129725129726129727129728129729129730129731129732129733129734129735129736129737129738129739129740129741129742129743129744129745129746129747129748129749129750129751129752129753129754129755129756129757129758129759129760129761129762129763129764129765129766129767129768129769129770129771129772129773129774129775129776129777129778129779129780129781129782129783129784129785129786129787129788129789129790129791129792129793129794129795129796129797129798129799129800129801129802129803129804129805129806129807129808129809129810129811129812129813129814129815129816129817129818129819129820129821129822129823129824129825129826129827129828129829129830129831129832129833129834129835129836129837129838129839129840129841129842129843129844129845129846129847129848129849129850129851129852129853129854129855129856129857129858129859129860129861129862129863129864129865129866129867129868129869129870129871129872129873129874129875129876129877129878129879129880129881129882129883129884129885129886129887129888129889129890129891129892129893129894129895129896129897129898129899129900129901129902129903129904129905129906129907129908129909129910129911129912129913129914129915129916129917129918129919129920129921129922129923129924129925129926129927129928129929129930129931129932129933129934129935129936129937129938129939129940129941129942129943129944129945129946129947129948129949129950129951129952129953129954129955129956129957129958129959129960129961129962129963129964129965129966129967129968129969129970129971129972129973129974129975129976129977129978129979129980129981129982129983129984129985129986129987129988129989129990129991129992129993129994129995129996129997129998129999130000130001130002130003130004130005130006130007130008130009130010130011130012130013130014130015130016130017130018130019130020130021130022130023130024130025130026130027130028130029130030130031130032130033130034130035130036130037130038130039130040130041130042130043130044130045130046130047130048130049130050130051130052130053130054130055130056130057130058130059130060130061130062130063130064130065130066130067130068130069130070130071130072130073130074130075130076130077130078130079130080130081130082130083130084130085130086130087130088130089130090130091130092130093130094130095130096130097130098130099130100130101130102130103130104130105130106130107130108130109130110130111130112130113130114130115130116130117130118130119130120130121130122130123130124130125130126130127130128130129130130130131130132130133130134130135130136130137130138130139130140130141130142130143130144130145130146130147130148130149130150130151130152130153130154130155130156130157130158130159130160130161130162130163130164130165130166130167130168130169130170130171130172130173130174130175130176130177130178130179130180130181130182130183130184130185130186130187130188130189130190130191130192130193130194130195130196130197130198130199130200130201130202130203130204130205130206130207130208130209130210130211130212130213130214130215130216130217130218130219130220130221130222130223130224130225130226130227130228130229130230130231130232130233130234130235130236130237130238130239130240130241130242130243130244130245130246130247130248130249130250130251130252130253130254130255130256130257130258130259130260130261130262130263130264130265130266130267130268130269130270130271130272130273130274130275130276130277130278130279130280130281130282130283130284130285130286130287130288130289130290130291130292130293130294130295130296130297130298130299130300130301130302130303130304130305130306130307130308130309130310130311130312130313130314130315130316130317130318130319130320130321130322130323130324130325130326130327130328130329130330130331130332130333130334130335130336130337130338130339130340130341130342130343130344130345130346130347130348130349130350130351130352130353130354130355130356130357130358130359130360130361130362130363130364130365130366130367130368130369130370130371130372130373130374130375130376130377130378130379130380130381130382130383130384130385130386130387130388130389130390130391130392130393130394130395130396130397130398130399130400130401130402130403130404130405130406130407130408130409130410130411130412130413130414130415130416130417130418130419130420130421130422130423130424130425130426130427130428130429130430130431130432130433130434130435130436130437130438130439130440130441130442130443130444130445130446130447130448130449130450130451130452130453130454130455130456130457130458130459130460130461130462130463130464130465130466130467130468130469130470130471130472130473130474130475130476130477130478130479130480130481130482130483130484130485130486130487130488130489130490130491130492130493130494130495130496130497130498130499130500130501130502130503130504130505130506130507130508130509130510130511130512130513130514130515130516130517130518130519130520130521130522130523130524130525130526130527130528130529130530130531130532130533130534130535130536130537130538130539130540130541130542130543130544130545130546130547130548130549130550130551130552130553130554130555130556130557130558130559130560130561130562130563130564130565130566130567130568130569130570130571130572130573130574130575130576130577130578130579130580130581130582130583130584130585130586130587130588130589130590130591130592130593130594130595130596130597130598130599130600130601130602130603130604130605130606130607130608130609130610130611130612130613130614130615130616130617130618130619130620130621130622130623130624130625130626130627130628130629130630130631130632130633130634130635130636130637130638130639130640130641130642130643130644130645130646130647130648130649130650130651130652130653130654130655130656130657130658130659130660130661130662130663130664130665130666130667130668130669130670130671130672130673130674130675130676130677130678130679130680130681130682130683130684130685130686130687130688130689130690130691130692130693130694130695130696130697130698130699130700130701130702130703130704130705130706130707130708130709130710130711130712130713130714130715130716130717130718130719130720130721130722130723130724130725130726130727130728130729130730130731130732130733130734130735130736130737130738130739130740130741130742130743130744130745130746130747130748130749130750130751130752130753130754130755130756130757130758130759130760130761130762130763130764130765130766130767130768130769130770130771130772130773130774130775130776130777130778130779130780130781130782130783130784130785130786130787130788130789130790130791130792130793130794130795130796130797130798130799130800130801130802130803130804130805130806130807130808130809130810130811130812130813130814130815130816130817130818130819130820130821130822130823130824130825130826130827130828130829130830130831130832130833130834130835130836130837130838130839130840130841130842130843130844130845130846130847130848130849130850130851130852130853130854130855130856130857130858130859130860130861130862130863130864130865130866130867130868130869130870130871130872130873130874130875130876130877130878130879130880130881130882130883130884130885130886130887130888130889130890130891130892130893130894130895130896130897130898130899130900130901130902130903130904130905130906130907130908130909130910130911130912130913130914130915130916130917130918130919130920130921130922130923130924130925130926130927130928130929130930130931130932130933130934130935130936130937130938130939130940130941130942130943130944130945130946130947130948130949130950130951130952130953130954130955130956130957130958130959130960130961130962130963130964130965130966130967130968130969130970130971130972130973130974130975130976130977130978130979130980130981130982130983130984130985130986130987130988130989130990130991130992130993130994130995130996130997130998130999131000131001131002131003131004131005131006131007131008131009131010131011131012131013131014131015131016131017131018131019131020131021131022131023131024131025131026131027131028131029131030131031131032131033131034131035131036131037131038131039131040131041131042131043131044131045131046131047131048131049131050131051131052131053131054131055131056131057131058131059131060131061131062131063131064131065131066131067131068131069131070131071131072131073131074131075131076131077131078131079131080131081131082131083131084131085131086131087131088131089131090131091131092131093131094131095131096131097131098131099131100131101131102131103131104131105131106131107131108131109131110131111131112131113131114131115131116131117131118131119131120131121131122131123131124131125131126131127131128131129131130131131131132131133131134131135131136131137131138131139131140131141131142131143131144131145131146131147131148131149131150131151131152131153131154131155131156131157131158131159131160131161131162131163131164131165131166131167131168131169131170131171131172131173131174131175131176131177131178131179131180131181131182131183131184131185131186131187131188131189131190131191131192131193131194131195131196131197131198131199131200131201131202131203131204131205131206131207131208131209131210131211131212131213131214131215131216131217131218131219131220131221131222131223131224131225131226131227131228131229131230131231131232131233131234131235131236131237131238131239131240131241131242131243131244131245131246131247131248131249131250131251131252131253131254131255131256131257131258131259131260131261131262131263131264131265131266131267131268131269131270131271131272131273131274131275131276131277131278131279131280131281131282131283131284131285131286131287131288131289131290131291131292131293131294131295131296131297131298131299131300131301131302131303131304131305131306131307131308131309131310131311131312131313131314131315131316131317131318131319131320131321131322131323131324131325131326131327131328131329131330131331131332131333131334131335131336131337131338131339131340131341131342131343131344131345131346131347131348131349131350131351131352131353131354131355131356131357131358131359131360131361131362131363131364131365131366131367131368131369131370131371131372131373131374131375131376131377131378131379131380131381131382131383131384131385131386131387131388131389131390131391131392131393131394131395131396131397131398131399131400131401131402131403131404131405131406131407131408131409131410131411131412131413131414131415131416131417131418131419131420131421131422131423131424131425131426131427131428131429131430131431131432131433131434131435131436131437131438131439131440131441131442131443131444131445131446131447131448131449131450131451131452131453131454131455131456131457131458131459131460131461131462131463131464131465131466131467131468131469131470131471131472131473131474131475131476131477131478131479131480131481131482131483131484131485131486131487131488131489131490131491131492131493131494131495131496131497131498131499131500131501131502131503131504131505131506131507131508131509131510131511131512131513131514131515131516131517131518131519131520131521131522131523131524131525131526131527131528131529131530131531131532131533131534131535131536131537131538131539131540131541131542131543131544131545131546131547131548131549131550131551131552131553131554131555131556131557131558131559131560131561131562131563131564131565131566131567131568131569131570131571131572131573131574131575131576131577131578131579131580131581131582131583131584131585131586131587131588131589131590131591131592131593131594131595131596131597131598131599131600131601131602131603131604131605131606131607131608131609131610131611131612131613131614131615131616131617131618131619131620131621131622131623131624131625131626131627131628131629131630131631131632131633131634131635131636131637131638131639131640131641131642131643131644131645131646131647131648131649131650131651131652131653131654131655131656131657131658131659131660131661131662131663131664131665131666131667131668131669131670131671131672131673131674131675131676131677131678131679131680131681131682131683131684131685131686131687131688131689131690131691131692131693131694131695131696131697131698131699131700131701131702131703131704131705131706131707131708131709131710131711131712131713131714131715131716131717131718131719131720131721131722131723131724131725131726131727131728131729131730131731131732131733131734131735131736131737131738131739131740131741131742131743131744131745131746131747131748131749131750131751131752131753131754131755131756131757131758131759131760131761131762131763131764131765131766131767131768131769131770131771131772131773131774131775131776131777131778131779131780131781131782131783131784131785131786131787131788131789131790131791131792131793131794131795131796131797131798131799131800131801131802131803131804131805131806131807131808131809131810131811131812131813131814131815131816131817131818131819131820131821131822131823131824131825131826131827131828131829131830131831131832131833131834131835131836131837131838131839131840131841131842131843131844131845131846131847131848131849131850131851131852131853131854131855131856131857131858131859131860131861131862131863131864131865131866131867131868131869131870131871131872131873131874131875131876131877131878131879131880131881131882131883131884131885131886131887131888131889131890131891131892131893131894131895131896131897131898131899131900131901131902131903131904131905131906131907131908131909131910131911131912131913131914131915131916131917131918131919131920131921131922131923131924131925131926131927131928131929131930131931131932131933131934131935131936131937131938131939131940131941131942131943131944131945131946131947131948131949131950131951131952131953131954131955131956131957131958131959131960131961131962131963131964131965131966131967131968131969131970131971131972131973131974131975131976131977131978131979131980131981131982131983131984131985131986131987131988131989131990131991131992131993131994131995131996131997131998131999132000132001132002132003132004132005132006132007132008132009132010132011132012132013132014132015132016132017132018132019132020132021132022132023132024132025132026132027132028132029132030132031132032132033132034132035132036132037132038132039132040132041132042132043132044132045132046132047132048132049132050132051132052132053132054132055132056132057132058132059132060132061132062132063132064132065132066132067132068132069132070132071132072132073132074132075132076132077132078132079132080132081132082132083132084132085132086132087132088132089132090132091132092132093132094132095132096132097132098132099132100132101132102132103132104132105132106132107132108132109132110132111132112132113132114132115132116132117132118132119132120132121132122132123132124132125132126132127132128132129132130132131132132132133132134132135132136132137132138132139132140132141132142132143132144132145132146132147132148132149132150132151132152132153132154132155132156132157132158132159132160132161132162132163132164132165132166132167132168132169132170132171132172132173132174132175132176132177132178132179132180132181132182132183132184132185132186132187132188132189132190132191132192132193132194132195132196132197132198132199132200132201132202132203132204132205132206132207132208132209132210132211132212132213132214132215132216132217132218132219132220132221132222132223132224132225132226132227132228132229132230132231132232132233132234132235132236132237132238132239132240132241132242132243132244132245132246132247132248132249132250132251132252132253132254132255132256132257132258132259132260132261132262132263132264132265132266132267132268132269132270132271132272132273132274132275132276132277132278132279132280132281132282132283132284132285132286132287132288132289132290132291132292132293132294132295132296132297132298132299132300132301132302132303132304132305132306132307132308132309132310132311132312132313132314132315132316132317132318132319132320132321132322132323132324132325132326132327132328132329132330132331132332132333132334132335132336132337132338132339132340132341132342132343132344132345132346132347132348132349132350132351132352132353132354132355132356132357132358132359132360132361132362132363132364132365132366132367132368132369132370132371132372132373132374132375132376132377132378132379132380132381132382132383132384132385132386132387132388132389132390132391132392132393132394132395132396132397132398132399132400132401132402132403132404132405132406132407132408132409132410132411132412132413132414132415132416132417132418132419132420132421132422132423132424132425132426132427132428132429132430132431132432132433132434132435132436132437132438132439132440132441132442132443132444132445132446132447132448132449132450132451132452132453132454132455132456132457132458132459132460132461132462132463132464132465132466132467132468132469132470132471132472132473132474132475132476132477132478132479132480132481132482132483132484132485132486132487132488132489132490132491132492132493132494132495132496132497132498132499132500132501132502132503132504132505132506132507132508132509132510132511132512132513132514132515132516132517132518132519132520132521132522132523132524132525132526132527132528132529132530132531132532132533132534132535132536132537132538132539132540132541132542132543132544132545132546132547132548132549132550132551132552132553132554132555132556132557132558132559132560132561132562132563132564132565132566132567132568132569132570132571132572132573132574132575132576132577132578132579132580132581132582132583132584132585132586132587132588132589132590132591132592132593132594132595132596132597132598132599132600132601132602132603132604132605132606132607132608132609132610132611132612132613132614132615132616132617132618132619132620132621132622132623132624132625132626132627132628132629132630132631132632132633132634132635132636132637132638132639132640132641132642132643132644132645132646132647132648132649132650132651132652132653132654132655132656132657132658132659132660132661132662132663132664132665132666132667132668132669132670132671132672132673132674132675132676132677132678132679132680132681132682132683132684132685132686132687132688132689132690132691132692132693132694132695132696132697132698132699132700132701132702132703132704132705132706132707132708132709132710132711132712132713132714132715132716132717132718132719132720132721132722132723132724132725132726132727132728132729132730132731132732132733132734132735132736132737132738132739132740132741132742132743132744132745132746132747132748132749132750132751132752132753132754132755132756132757132758132759132760132761132762132763132764132765132766132767132768132769132770132771132772132773132774132775132776132777132778132779132780132781132782132783132784132785132786132787132788132789132790132791132792132793132794132795132796132797132798132799132800132801132802132803132804132805132806132807132808132809132810132811132812132813132814132815132816132817132818132819132820132821132822132823132824132825132826132827132828132829132830132831132832132833132834132835132836132837132838132839132840132841132842132843132844132845132846132847132848132849132850132851132852132853132854132855132856132857132858132859132860132861132862132863132864132865132866132867132868132869132870132871132872132873132874132875132876132877132878132879132880132881132882132883132884132885132886132887132888132889132890132891132892132893132894132895132896132897132898132899132900132901132902132903132904132905132906132907132908132909132910132911132912132913132914132915132916132917132918132919132920132921132922132923132924132925132926132927132928132929132930132931132932132933132934132935132936132937132938132939132940132941132942132943132944132945132946132947132948132949132950132951132952132953132954132955132956132957132958132959132960132961132962132963132964132965132966132967132968132969132970132971132972132973132974132975132976132977132978132979132980132981132982132983132984132985132986132987132988132989132990132991132992132993132994132995132996132997132998132999133000133001133002133003133004133005133006133007133008133009133010133011133012133013133014133015133016133017133018133019133020133021133022133023133024133025133026133027133028133029133030133031133032133033133034133035133036133037133038133039133040133041133042133043133044133045133046133047133048133049133050133051133052133053133054133055133056133057133058133059133060133061133062133063133064133065133066133067133068133069133070133071133072133073133074133075133076133077133078133079133080133081133082133083133084133085133086133087133088133089133090133091133092133093133094133095133096133097133098133099133100133101133102133103133104133105133106133107133108133109133110133111133112133113133114133115133116133117133118133119133120133121133122133123133124133125133126133127133128133129133130133131133132133133133134133135133136133137133138133139133140133141133142133143133144133145133146133147133148133149133150133151133152133153133154133155133156133157133158133159133160133161133162133163133164133165133166133167133168133169133170133171133172133173133174133175133176133177133178133179133180133181133182133183133184133185133186133187133188133189133190133191133192133193133194133195133196133197133198133199133200133201133202133203133204133205133206133207133208133209133210133211133212133213133214133215133216133217133218133219133220133221133222133223133224133225133226133227133228133229133230133231133232133233133234133235133236133237133238133239133240133241133242133243133244133245133246133247133248133249133250133251133252133253133254133255133256133257133258133259133260133261133262133263133264133265133266133267133268133269133270133271133272133273133274133275133276133277133278133279133280133281133282133283133284133285133286133287133288133289133290133291133292133293133294133295133296133297133298133299133300133301133302133303133304133305133306133307133308133309133310133311133312133313133314133315133316133317133318133319133320133321133322133323133324133325133326133327133328133329133330133331133332133333133334133335133336133337133338133339133340133341133342133343133344133345133346133347133348133349133350133351133352133353133354133355133356133357133358133359133360133361133362133363133364133365133366133367133368133369133370133371133372133373133374133375133376133377133378133379133380133381133382133383133384133385133386133387133388133389133390133391133392133393133394133395133396133397133398133399133400133401133402133403133404133405133406133407133408133409133410133411133412133413133414133415133416133417133418133419133420133421133422133423133424133425133426133427133428133429133430133431133432133433133434133435133436133437133438133439133440133441133442133443133444133445133446133447133448133449133450133451133452133453133454133455133456133457133458133459133460133461133462133463133464133465133466133467133468133469133470133471133472133473133474133475133476133477133478133479133480133481133482133483133484133485133486133487133488133489133490133491133492133493133494133495133496133497133498133499133500133501133502133503133504133505133506133507133508133509133510133511133512133513133514133515133516133517133518133519133520133521133522133523133524133525133526133527133528133529133530133531133532133533133534133535133536133537133538133539133540133541133542133543133544133545133546133547133548133549133550133551133552133553133554133555133556133557133558133559133560133561133562133563133564133565133566133567133568133569133570133571133572133573133574133575133576133577133578133579133580133581133582133583133584133585133586133587133588133589133590133591133592133593133594133595133596133597133598133599133600133601133602133603133604133605133606133607133608133609133610133611133612133613133614133615133616133617133618133619133620133621133622133623133624133625133626133627133628133629133630133631133632133633133634133635133636133637133638133639133640133641133642133643133644133645133646133647133648133649133650133651133652133653133654133655133656133657133658133659133660133661133662133663133664133665133666133667133668133669133670133671133672133673133674133675133676133677133678133679133680133681133682133683133684133685133686133687133688133689133690133691133692133693133694133695133696133697133698133699133700133701133702133703133704133705133706133707133708133709133710133711133712133713133714133715133716133717133718133719133720133721133722133723133724133725133726133727133728133729133730133731133732133733133734133735133736133737133738133739133740133741133742133743133744133745133746133747133748133749133750133751133752133753133754133755133756133757133758133759133760133761133762133763133764133765133766133767133768133769133770133771133772133773133774133775133776133777133778133779133780133781133782133783133784133785133786133787133788133789133790133791133792133793133794133795133796133797133798133799133800133801133802133803133804133805133806133807133808133809133810133811133812133813133814133815133816133817133818133819133820133821133822133823133824133825133826133827133828133829133830133831133832133833133834133835133836133837133838133839133840133841133842133843133844133845133846133847133848133849133850133851133852133853133854133855133856133857133858133859133860133861133862133863133864133865133866133867133868133869133870133871133872133873133874133875133876133877133878133879133880133881133882133883133884133885133886133887133888133889133890133891133892133893133894133895133896133897133898133899133900133901133902133903133904133905133906133907133908133909133910133911133912133913133914133915133916133917133918133919133920133921133922133923133924133925133926133927133928133929133930133931133932133933133934133935133936133937133938133939133940133941133942133943133944133945133946133947133948133949133950133951133952133953133954133955133956133957133958133959133960133961133962133963133964133965133966133967133968133969133970133971133972133973133974133975133976133977133978133979133980133981133982133983133984133985133986133987133988133989133990133991133992133993133994133995133996133997133998133999134000134001134002134003134004134005134006134007134008134009134010134011134012134013134014134015134016134017134018134019134020134021134022134023134024134025134026134027134028134029134030134031134032134033134034134035134036134037134038134039134040134041134042134043134044134045134046134047134048134049134050134051134052134053134054134055134056134057134058134059134060134061134062134063134064134065134066134067134068134069134070134071134072134073134074134075134076134077134078134079134080134081134082134083134084134085134086134087134088134089134090134091134092134093134094134095134096134097134098134099134100134101134102134103134104134105134106134107134108134109134110134111134112134113134114134115134116134117134118134119134120134121134122134123134124134125134126134127134128134129134130134131134132134133134134134135134136134137134138134139134140134141134142134143134144134145134146134147134148134149134150134151134152134153134154134155134156134157134158134159134160134161134162134163134164134165134166134167134168134169134170134171134172134173134174134175134176134177134178134179134180134181134182134183134184134185134186134187134188134189134190134191134192134193134194134195134196134197134198134199134200134201134202134203134204134205134206134207134208134209134210134211134212134213134214134215134216134217134218134219134220134221134222134223134224134225134226134227134228134229134230134231134232134233134234134235134236134237134238134239134240134241134242134243134244134245134246134247134248134249134250134251134252134253134254134255134256134257134258134259134260134261134262134263134264134265134266134267134268134269134270134271134272134273134274134275134276134277134278134279134280134281134282134283134284134285134286134287134288134289134290134291134292134293134294134295134296134297134298134299134300134301134302134303134304134305134306134307134308134309134310134311134312134313134314134315134316134317134318134319134320134321134322134323134324134325134326134327134328134329134330134331134332134333134334134335134336134337134338134339134340134341134342134343134344134345134346134347134348134349134350134351134352134353134354134355134356134357134358134359134360134361134362134363134364134365134366134367134368134369134370134371134372134373134374134375134376134377134378134379134380134381134382134383134384134385134386134387134388134389134390134391134392134393134394134395134396134397134398134399134400134401134402134403134404134405134406134407134408134409134410134411134412134413134414134415134416134417134418134419134420134421134422134423134424134425134426134427134428134429134430134431134432134433134434134435134436134437134438134439134440134441134442134443134444134445134446134447134448134449134450134451134452134453134454134455134456134457134458134459134460134461134462134463134464134465134466134467134468134469134470134471134472134473134474134475134476134477134478134479134480134481134482134483134484134485134486134487134488134489134490134491134492134493134494134495134496134497134498134499134500134501134502134503134504134505134506134507134508134509134510134511134512134513134514134515134516134517134518134519134520134521134522134523134524134525134526134527134528134529134530134531134532134533134534134535134536134537134538134539134540134541134542134543134544134545134546134547134548134549134550134551134552134553134554134555134556134557134558134559134560134561134562134563134564134565134566134567134568134569134570134571134572134573134574134575134576134577134578134579134580134581134582134583134584134585134586134587134588134589134590134591134592134593134594134595134596134597134598134599134600134601134602134603134604134605134606134607134608134609134610134611134612134613134614134615134616134617134618134619134620134621134622134623134624134625134626134627134628134629134630134631134632134633134634134635134636134637134638134639134640134641134642134643134644134645134646134647134648134649134650134651134652134653134654134655134656134657134658134659134660134661134662134663134664134665134666134667134668134669134670134671134672134673134674134675134676134677134678134679134680134681134682134683134684134685134686134687134688134689134690134691134692134693134694134695134696134697134698134699134700134701134702134703134704134705134706134707134708134709134710134711134712134713134714134715134716134717134718134719134720134721134722134723134724134725134726134727134728134729134730134731134732134733134734134735134736134737134738134739134740134741134742134743134744134745134746134747134748134749134750134751134752134753134754134755134756134757134758134759134760134761134762134763134764134765134766134767134768134769134770134771134772134773134774134775134776134777134778134779134780134781134782134783134784134785134786134787134788134789134790134791134792134793134794134795134796134797134798134799134800134801134802134803134804134805134806134807134808134809134810134811134812134813134814134815134816134817134818134819134820134821134822134823134824134825134826134827134828134829134830134831134832134833134834134835134836134837134838134839134840134841134842134843134844134845134846134847134848134849134850134851134852134853134854134855134856134857134858134859134860134861134862134863134864134865134866134867134868134869134870134871134872134873134874134875134876134877134878134879134880134881134882134883134884134885134886134887134888134889134890134891134892134893134894134895134896134897134898134899134900134901134902134903134904134905134906134907134908134909134910134911134912134913134914134915134916134917134918134919134920134921134922134923134924134925134926134927134928134929134930134931134932134933134934134935134936134937134938134939134940134941134942134943134944134945134946134947134948134949134950134951134952134953134954134955134956134957134958134959134960134961134962134963134964134965134966134967134968134969134970134971134972134973134974134975134976134977134978134979134980134981134982134983134984134985134986134987134988134989134990134991134992134993134994134995134996134997134998134999135000135001135002135003135004135005135006135007135008135009135010135011135012135013135014135015135016135017135018135019135020135021135022135023135024135025135026135027135028135029135030135031135032135033135034135035135036135037135038135039135040135041135042135043135044135045135046135047135048135049135050135051135052135053135054135055135056135057135058135059135060135061135062135063135064135065135066135067135068135069135070135071135072135073135074135075135076135077135078135079135080135081135082135083135084135085135086135087135088135089135090135091135092135093135094135095135096135097135098135099135100135101135102135103135104135105135106135107135108135109135110135111135112135113135114135115135116135117135118135119135120135121135122135123135124135125135126135127135128135129135130135131135132135133135134135135135136135137135138135139135140135141135142135143135144135145135146135147135148135149135150135151135152135153135154135155135156135157135158135159135160135161135162135163135164135165135166135167135168135169135170135171135172135173135174135175135176135177135178135179135180135181135182135183135184135185135186135187135188135189135190135191135192135193135194135195135196135197135198135199135200135201135202135203135204135205135206135207135208135209135210135211135212135213135214135215135216135217135218135219135220135221135222135223135224135225135226135227135228135229135230135231135232135233135234135235135236135237135238135239135240135241135242135243135244135245135246135247135248135249135250135251135252135253135254135255135256135257135258135259135260135261135262135263135264135265135266135267135268135269135270135271135272135273135274135275135276135277135278135279135280135281135282135283135284135285135286135287135288135289135290135291135292135293135294135295135296135297135298135299135300135301135302135303135304135305135306135307135308135309135310135311135312135313135314135315135316135317135318135319135320135321135322135323135324135325135326135327135328135329135330135331135332135333135334135335135336135337135338135339135340135341135342135343135344135345135346135347135348135349135350135351135352135353135354135355135356135357135358135359135360135361135362135363135364135365135366135367135368135369135370135371135372135373135374135375135376135377135378135379135380135381135382135383135384135385135386135387135388135389135390135391135392135393135394135395135396135397135398135399135400135401135402135403135404135405135406135407135408135409135410135411135412135413135414135415135416135417135418135419135420135421135422135423135424135425135426135427135428135429135430135431135432135433135434135435135436135437135438135439135440135441135442135443135444135445135446135447135448135449135450135451135452135453135454135455135456135457135458135459135460135461135462135463135464135465135466135467135468135469135470135471135472135473135474135475135476135477135478135479135480135481135482135483135484135485135486135487135488135489135490135491135492135493135494135495135496135497135498135499135500135501135502135503135504135505135506135507135508135509135510135511135512135513135514135515135516135517135518135519135520135521135522135523135524135525135526135527135528135529135530135531135532135533135534135535135536135537135538135539135540135541135542135543135544135545135546135547135548135549135550135551135552135553135554135555135556135557135558135559135560135561135562135563135564135565135566135567135568135569135570135571135572135573135574135575135576135577135578135579135580135581135582135583135584135585135586135587135588135589135590135591135592135593135594135595135596135597135598135599135600135601135602135603135604135605135606135607135608135609135610135611135612135613135614135615135616135617135618135619135620135621135622135623135624135625135626135627135628135629135630135631135632135633135634135635135636135637135638135639135640135641135642135643135644135645135646135647135648135649135650135651135652135653135654135655135656135657135658135659135660135661135662135663135664135665135666135667135668135669135670135671135672135673135674135675135676135677135678135679135680135681135682135683135684135685135686135687135688135689135690135691135692135693135694135695135696135697135698135699135700135701135702135703135704135705135706135707135708135709135710135711135712135713135714135715135716135717135718135719135720135721135722135723135724135725135726135727135728135729135730135731135732135733135734135735135736135737135738135739135740135741135742135743135744135745135746135747135748135749135750135751135752135753135754135755135756135757135758135759135760135761135762135763135764135765135766135767135768135769135770135771135772135773135774135775135776135777135778135779135780135781135782135783135784135785135786135787135788135789135790135791135792135793135794135795135796135797135798135799135800135801135802135803135804135805135806135807135808135809135810135811135812135813135814135815135816135817135818135819135820135821135822135823135824135825135826135827135828135829135830135831135832135833135834135835135836135837135838135839135840135841135842135843135844135845135846135847135848135849135850135851135852135853135854135855135856135857135858135859135860135861135862135863135864135865135866135867135868135869135870135871135872135873135874135875135876135877135878135879135880135881135882135883135884135885135886135887135888135889135890135891135892135893135894135895135896135897135898135899135900135901135902135903135904135905135906135907135908135909135910135911135912135913135914135915135916135917135918135919135920135921135922135923135924135925135926135927135928135929135930135931135932135933135934135935135936135937135938135939135940135941135942135943135944135945135946135947135948135949135950135951135952135953135954135955135956135957135958135959135960135961135962135963135964135965135966135967135968135969135970135971135972135973135974135975135976135977135978135979135980135981135982135983135984135985135986135987135988135989135990135991135992135993135994135995135996135997135998135999136000136001136002136003136004136005136006136007136008136009136010136011136012136013136014136015136016136017136018136019136020136021136022136023136024136025136026136027136028136029136030136031136032136033136034136035136036136037136038136039136040136041136042136043136044136045136046136047136048136049136050136051136052136053136054136055136056136057136058136059136060136061136062136063136064136065136066136067136068136069136070136071136072136073136074136075136076136077136078136079136080136081136082136083136084136085136086136087136088136089136090136091136092136093136094136095136096136097136098136099136100136101136102136103136104136105136106136107136108136109136110136111136112136113136114136115136116136117136118136119136120136121136122136123136124136125136126136127136128136129136130136131136132136133136134136135136136136137136138136139136140136141136142136143136144136145136146136147136148136149136150136151136152136153136154136155136156136157136158136159136160136161136162136163136164136165136166136167136168136169136170136171136172136173136174136175136176136177136178136179136180136181136182136183136184136185136186136187136188136189136190136191136192136193136194136195136196136197136198136199136200136201136202136203136204136205136206136207136208136209136210136211136212136213136214136215136216136217136218136219136220136221136222136223136224136225136226136227136228136229136230136231136232136233136234136235136236136237136238136239136240136241136242136243136244136245136246136247136248136249136250136251136252136253136254136255136256136257136258136259136260136261136262136263136264136265136266136267136268136269136270136271136272136273136274136275136276136277136278136279136280136281136282136283136284136285136286136287136288136289136290136291136292136293136294136295136296136297136298136299136300136301136302136303136304136305136306136307136308136309136310136311136312136313136314136315136316136317136318136319136320136321136322136323136324136325136326136327136328136329136330136331136332136333136334136335136336136337136338136339136340136341136342136343136344136345136346136347136348136349136350136351136352136353136354136355136356136357136358136359136360136361136362136363136364136365136366136367136368136369136370136371136372136373136374136375136376136377136378136379136380136381136382136383136384136385136386136387136388136389136390136391136392136393136394136395136396136397136398136399136400136401136402136403136404136405136406136407136408136409136410136411136412136413136414136415136416136417136418136419136420136421136422136423136424136425136426136427136428136429136430136431136432136433136434136435136436136437136438136439136440136441136442136443136444136445136446136447136448136449136450136451136452136453136454136455136456136457136458136459136460136461136462136463136464136465136466136467136468136469136470136471136472136473136474136475136476136477136478136479136480136481136482136483136484136485136486136487136488136489136490136491136492136493136494136495136496136497136498136499136500136501136502136503136504136505136506136507136508136509136510136511136512136513136514136515136516136517136518136519136520136521136522136523136524136525136526136527136528136529136530136531136532136533136534136535136536136537136538136539136540136541136542136543136544136545136546136547136548136549136550136551136552136553136554136555136556136557136558136559136560136561136562136563136564136565136566136567136568136569136570136571136572136573136574136575136576136577136578136579136580136581136582136583136584136585136586136587136588136589136590136591136592136593136594136595136596136597136598136599136600136601136602136603136604136605136606136607136608136609136610136611136612136613136614136615136616136617136618136619136620136621136622136623136624136625136626136627136628136629136630136631136632136633136634136635136636136637136638136639136640136641136642136643136644136645136646136647136648136649136650136651136652136653136654136655136656136657136658136659136660136661136662136663136664136665136666136667136668136669136670136671136672136673136674136675136676136677136678136679136680136681136682136683136684136685136686136687136688136689136690136691136692136693136694136695136696136697136698136699136700136701136702136703136704136705136706136707136708136709136710136711136712136713136714136715136716136717136718136719136720136721136722136723136724136725136726136727136728136729136730136731136732136733136734136735136736136737136738136739136740136741136742136743136744136745136746136747136748136749136750136751136752136753136754136755136756136757136758136759136760136761136762136763136764136765136766136767136768136769136770136771136772136773136774136775136776136777136778136779136780136781136782136783136784136785136786136787136788136789136790136791136792136793136794136795136796136797136798136799136800136801136802136803136804136805136806136807136808136809136810136811136812136813136814136815136816136817136818136819136820136821136822136823136824136825136826136827136828136829136830136831136832136833136834136835136836136837136838136839136840136841136842136843136844136845136846136847136848136849136850136851136852136853136854136855136856136857136858136859136860136861136862136863136864136865136866136867136868136869136870136871136872136873136874136875136876136877136878136879136880136881136882136883136884136885136886136887136888136889136890136891136892136893136894136895136896136897136898136899136900136901136902136903136904136905136906136907136908136909136910136911136912136913136914136915136916136917136918136919136920136921136922136923136924136925136926136927136928136929136930136931136932136933136934136935136936136937136938136939136940136941136942136943136944136945136946136947136948136949136950136951136952136953136954136955136956136957136958136959136960136961136962136963136964136965136966136967136968136969136970136971136972136973136974136975136976136977136978136979136980136981136982136983136984136985136986136987136988136989136990136991136992136993136994136995136996136997136998136999137000137001137002137003137004137005137006137007137008137009137010137011137012137013137014137015137016137017137018137019137020137021137022137023137024137025137026137027137028137029137030137031137032137033137034137035137036137037137038137039137040137041137042137043137044137045137046137047137048137049137050137051137052137053137054137055137056137057137058137059137060137061137062137063137064137065137066137067137068137069137070137071137072137073137074137075137076137077137078137079137080137081137082137083137084137085137086137087137088137089137090137091137092137093137094137095137096137097137098137099137100137101137102137103137104137105137106137107137108137109137110137111137112137113137114137115137116137117137118137119137120137121137122137123137124137125137126137127137128137129137130137131137132137133137134137135137136137137137138137139137140137141137142137143137144137145137146137147137148137149137150137151137152137153137154137155137156137157137158137159137160137161137162137163137164137165137166137167137168137169137170137171137172137173137174137175137176137177137178137179137180137181137182137183137184137185137186137187137188137189137190137191137192137193137194137195137196137197137198137199137200137201137202137203137204137205137206137207137208137209137210137211137212137213137214137215137216137217137218137219137220137221137222137223137224137225137226137227137228137229137230137231137232137233137234137235137236137237137238137239137240137241137242137243137244137245137246137247137248137249137250137251137252137253137254137255137256137257137258137259137260137261137262137263137264137265137266137267137268137269137270137271137272137273137274137275137276137277137278137279137280137281137282137283137284137285137286137287137288137289137290137291137292137293137294137295137296137297137298137299137300137301137302137303137304137305137306137307137308137309137310137311137312137313137314137315137316137317137318137319137320137321137322137323137324137325137326137327137328137329137330137331137332137333137334137335137336137337137338137339137340137341137342137343137344137345137346137347137348137349137350137351137352137353137354137355137356137357137358137359137360137361137362137363137364137365137366137367137368137369137370137371137372137373137374137375137376137377137378137379137380137381137382137383137384137385137386137387137388137389137390137391137392137393137394137395137396137397137398137399137400137401137402137403137404137405137406137407137408137409137410137411137412137413137414137415137416137417137418137419137420137421137422137423137424137425137426137427137428137429137430137431137432137433137434137435137436137437137438137439137440137441137442137443137444137445137446137447137448137449137450137451137452137453137454137455137456137457137458137459137460137461137462137463137464137465137466137467137468137469137470137471137472137473137474137475137476137477137478137479137480137481137482137483137484137485137486137487137488137489137490137491137492137493137494137495137496137497137498137499137500137501137502137503137504137505137506137507137508137509137510137511137512137513137514137515137516137517137518137519137520137521137522137523137524137525137526137527137528137529137530137531137532137533137534137535137536137537137538137539137540137541137542137543137544137545137546137547137548137549137550137551137552137553137554137555137556137557137558137559137560137561137562137563137564137565137566137567137568137569137570137571137572137573137574137575137576137577137578137579137580137581137582137583137584137585137586137587137588137589137590137591137592137593137594137595137596137597137598137599137600137601137602137603137604137605137606137607137608137609137610137611137612137613137614137615137616137617137618137619137620137621137622137623137624137625137626137627137628137629137630137631137632137633137634137635137636137637137638137639137640137641137642137643137644137645137646137647137648137649137650137651137652137653137654137655137656137657137658137659137660137661137662137663137664137665137666137667137668137669137670137671137672137673137674137675137676137677137678137679137680137681137682137683137684137685137686137687137688137689137690137691137692137693137694137695137696137697137698137699137700137701137702137703137704137705137706137707137708137709137710137711137712137713137714137715137716137717137718137719137720137721137722137723137724137725137726137727137728137729137730137731137732137733137734137735137736137737137738137739137740137741137742137743137744137745137746137747137748137749137750137751137752137753137754137755137756137757137758137759137760137761137762137763137764137765137766137767137768137769137770137771137772137773137774137775137776137777137778137779137780137781137782137783137784137785137786137787137788137789137790137791137792137793137794137795137796137797137798137799137800137801137802137803137804137805137806137807137808137809137810137811137812137813137814137815137816137817137818137819137820137821137822137823137824137825137826137827137828137829137830137831137832137833137834137835137836137837137838137839137840137841137842137843137844137845137846137847137848137849137850137851137852137853137854137855137856137857137858137859137860137861137862137863137864137865137866137867137868137869137870137871137872137873137874137875137876137877137878137879137880137881137882137883137884137885137886137887137888137889137890137891137892137893137894137895137896137897137898137899137900137901137902137903137904137905137906137907137908137909137910137911137912137913137914137915137916137917137918137919137920137921137922137923137924137925137926137927137928137929137930137931137932137933137934137935137936137937137938137939137940137941137942137943137944137945137946137947137948137949137950137951137952137953137954137955137956137957137958137959137960137961137962137963137964137965137966137967137968137969137970137971137972137973137974137975137976137977137978137979137980137981137982137983137984137985137986137987137988137989137990137991137992137993137994137995137996137997137998137999138000138001138002138003138004138005138006138007138008138009138010138011138012138013138014138015138016138017138018138019138020138021138022138023138024138025138026138027138028138029138030138031138032138033138034138035138036138037138038138039138040138041138042138043138044138045138046138047138048138049138050138051138052138053138054138055138056138057138058138059138060138061138062138063138064138065138066138067138068138069138070138071138072138073138074138075138076138077138078138079138080138081138082138083138084138085138086138087138088138089138090138091138092138093138094138095138096138097138098138099138100138101138102138103138104138105138106138107138108138109138110138111138112138113138114138115138116138117138118138119138120138121138122138123138124138125138126138127138128138129138130138131138132138133138134138135138136138137138138138139138140138141138142138143138144138145138146138147138148138149138150138151138152138153138154138155138156138157138158138159138160138161138162138163138164138165138166138167138168138169138170138171138172138173138174138175138176138177138178138179138180138181138182138183138184138185138186138187138188138189138190138191138192138193138194138195138196138197138198138199138200138201138202138203138204138205138206138207138208138209138210138211138212138213138214138215138216138217138218138219138220138221138222138223138224138225138226138227138228138229138230138231138232138233138234138235138236138237138238138239138240138241138242138243138244138245138246138247138248138249138250138251138252138253138254138255138256138257138258138259138260138261138262138263138264138265138266138267138268138269138270138271138272138273138274138275138276138277138278138279138280138281138282138283138284138285138286138287138288138289138290138291138292138293138294138295138296138297138298138299138300138301138302138303138304138305138306138307138308138309138310138311138312138313138314138315138316138317138318138319138320138321138322138323138324138325138326138327138328138329138330138331138332138333138334138335138336138337138338138339138340138341138342138343138344138345138346138347138348138349138350138351138352138353138354138355138356138357138358138359138360138361138362138363138364138365138366138367138368138369138370138371138372138373138374138375138376138377138378138379138380138381138382138383138384138385138386138387138388138389138390138391138392138393138394138395138396138397138398138399138400138401138402138403138404138405138406138407138408138409138410138411138412138413138414138415138416138417138418138419138420138421138422138423138424138425138426138427138428138429138430138431138432138433138434138435138436138437138438138439138440138441138442138443138444138445138446138447138448138449138450138451138452138453138454138455138456138457138458138459138460138461138462138463138464138465138466138467138468138469138470138471138472138473138474138475138476138477138478138479138480138481138482138483138484138485138486138487138488138489138490138491138492138493138494138495138496138497138498138499138500138501138502138503138504138505138506138507138508138509138510138511138512138513138514138515138516138517138518138519138520138521138522138523138524138525138526138527138528138529138530138531138532138533138534138535138536138537138538138539138540138541138542138543138544138545138546138547138548138549138550138551138552138553138554138555138556138557138558138559138560138561138562138563138564138565138566138567138568138569138570138571138572138573138574138575138576138577138578138579138580138581138582138583138584138585138586138587138588138589138590138591138592138593138594138595138596138597138598138599138600138601138602138603138604138605138606138607138608138609138610138611138612138613138614138615138616138617138618138619138620138621138622138623138624138625138626138627138628138629138630138631138632138633138634138635138636138637138638138639138640138641138642138643138644138645138646138647138648138649138650138651138652138653138654138655138656138657138658138659138660138661138662138663138664138665138666138667138668138669138670138671138672138673138674138675138676138677138678138679138680138681138682138683138684138685138686138687138688138689138690138691138692138693138694138695138696138697138698138699138700138701138702138703138704138705138706138707138708138709138710138711138712138713138714138715138716138717138718138719138720138721138722138723138724138725138726138727138728138729138730138731138732138733138734138735138736138737138738138739138740138741138742138743138744138745138746138747138748138749138750138751138752138753138754138755138756138757138758138759138760138761138762138763138764138765138766138767138768138769138770138771138772138773138774138775138776138777138778138779138780138781138782138783138784138785138786138787138788138789138790138791138792138793138794138795138796138797138798138799138800138801138802138803138804138805138806138807138808138809138810138811138812138813138814138815138816138817138818138819138820138821138822138823138824138825138826138827138828138829138830138831138832138833138834138835138836138837138838138839138840138841138842138843138844138845138846138847138848138849138850138851138852138853138854138855138856138857138858138859138860138861138862138863138864138865138866138867138868138869138870138871138872138873138874138875138876138877138878138879138880138881138882138883138884138885138886138887138888138889138890138891138892138893138894138895138896138897138898138899138900138901138902138903138904138905138906138907138908138909138910138911138912138913138914138915138916138917138918138919138920138921138922138923138924138925138926138927138928138929138930138931138932138933138934138935138936138937138938138939138940138941138942138943138944138945138946138947138948138949138950138951138952138953138954138955138956138957138958138959138960138961138962138963138964138965138966138967138968138969138970138971138972138973138974138975138976138977138978138979138980138981138982138983138984138985138986138987138988138989138990138991138992138993138994138995138996138997138998138999139000139001139002139003139004139005139006139007139008139009139010139011139012139013139014139015139016139017139018139019139020139021139022139023139024139025139026139027139028139029139030139031139032139033139034139035139036139037139038139039139040139041139042139043139044139045139046139047139048139049139050139051139052139053139054139055139056139057139058139059139060139061139062139063139064139065139066139067139068139069139070139071139072139073139074139075139076139077139078139079139080139081139082139083139084139085139086139087139088139089139090139091139092139093139094139095139096139097139098139099139100139101139102139103139104139105139106139107139108139109139110139111139112139113139114139115139116139117139118139119139120139121139122139123139124139125139126139127139128139129139130139131139132139133139134139135139136139137139138139139139140139141139142139143139144139145139146139147139148139149139150139151139152139153139154139155139156139157139158139159139160139161139162139163139164139165139166139167139168139169139170139171139172139173139174139175139176139177139178139179139180139181139182139183139184139185139186139187139188139189139190139191139192139193139194139195139196139197139198139199139200139201139202139203139204139205139206139207139208139209139210139211139212139213139214139215139216139217139218139219139220139221139222139223139224139225139226139227139228139229139230139231139232139233139234139235139236139237139238139239139240139241139242139243139244139245139246139247139248139249139250139251139252139253139254139255139256139257139258139259139260139261139262139263139264139265139266139267139268139269139270139271139272139273139274139275139276139277139278139279139280139281139282139283139284139285139286139287139288139289139290139291139292139293139294139295139296139297139298139299139300139301139302139303139304139305139306139307139308139309139310139311139312139313139314139315139316139317139318139319139320139321139322139323139324139325139326139327139328139329139330139331139332139333139334139335139336139337139338139339139340139341139342139343139344139345139346139347139348139349139350139351139352139353139354139355139356139357139358139359139360139361139362139363139364139365139366139367139368139369139370139371139372139373139374139375139376139377139378139379139380139381139382139383139384139385139386139387139388139389139390139391139392139393139394139395139396139397139398139399139400139401139402139403139404139405139406139407139408139409139410139411139412139413139414139415139416139417139418139419139420139421139422139423139424139425139426139427139428139429139430139431139432139433139434139435139436139437139438139439139440139441139442139443139444139445139446139447139448139449139450139451139452139453139454139455139456139457139458139459139460139461139462139463139464139465139466139467139468139469139470139471139472139473139474139475139476139477139478139479139480139481139482139483139484139485139486139487139488139489139490139491139492139493139494139495139496139497139498139499139500139501139502139503139504139505139506139507139508139509139510139511139512139513139514139515139516139517139518139519139520139521139522139523139524139525139526139527139528139529139530139531139532139533139534139535139536139537139538139539139540139541139542139543139544139545139546139547139548139549139550139551139552139553139554139555139556139557139558139559139560139561139562139563139564139565139566139567139568139569139570139571139572139573139574139575139576139577139578139579139580139581139582139583139584139585139586139587139588139589139590139591139592139593139594139595139596139597139598139599139600139601139602139603139604139605139606139607139608139609139610139611139612139613139614139615139616139617139618139619139620139621139622139623139624139625139626139627139628139629139630139631139632139633139634139635139636139637139638139639139640139641139642139643139644139645139646139647139648139649139650139651139652139653139654139655139656139657139658139659139660139661139662139663139664139665139666139667139668139669139670139671139672139673139674139675139676139677139678139679139680139681139682139683139684139685139686139687139688139689139690139691139692139693139694139695139696139697139698139699139700139701139702139703139704139705139706139707139708139709139710139711139712139713139714139715139716139717139718139719139720139721139722139723139724139725139726139727139728139729139730139731139732139733139734139735139736139737139738139739139740139741139742139743139744139745139746139747139748139749139750139751139752139753139754139755139756139757139758139759139760139761139762139763139764139765139766139767139768139769139770139771139772139773139774139775139776139777139778139779139780139781139782139783139784139785139786139787139788139789139790139791139792139793139794139795139796139797139798139799139800139801139802139803139804139805139806139807139808139809139810139811139812139813139814139815139816139817139818139819139820139821139822139823139824139825139826139827139828139829139830139831139832139833139834139835139836139837139838139839139840139841139842139843139844139845139846139847139848139849139850139851139852139853139854139855139856139857139858139859139860139861139862139863139864139865139866139867139868139869139870139871139872139873139874139875139876139877139878139879139880139881139882139883139884139885139886139887139888139889139890139891139892139893139894139895139896139897139898139899139900139901139902139903139904139905139906139907139908139909139910139911139912139913139914139915139916139917139918139919139920139921139922139923139924139925139926139927139928139929139930139931139932139933139934139935139936139937139938139939139940139941139942139943139944139945139946139947139948139949139950139951139952139953139954139955139956139957139958139959139960139961139962139963139964139965139966139967139968139969139970139971139972139973139974139975139976139977139978139979139980139981139982139983139984139985139986139987139988139989139990139991139992139993139994139995139996139997139998139999140000140001140002140003140004140005140006140007140008140009140010140011140012140013140014140015140016140017140018140019140020140021140022140023140024140025140026140027140028140029140030140031140032140033140034140035140036140037140038140039140040140041140042140043140044140045140046140047140048140049140050140051140052140053140054140055140056140057140058140059140060140061140062140063140064140065140066140067140068140069140070140071140072140073140074140075140076140077140078140079140080140081140082140083140084140085140086140087140088140089140090140091140092140093140094140095140096140097140098140099140100140101140102140103140104140105140106140107140108140109140110140111140112140113140114140115140116140117140118140119140120140121140122140123140124140125140126140127140128140129140130140131140132140133140134140135140136140137140138140139140140140141140142140143140144140145140146140147140148140149140150140151140152140153140154140155140156140157140158140159140160140161140162140163140164140165140166140167140168140169140170140171140172140173140174140175140176140177140178140179140180140181140182140183140184140185140186140187140188140189140190140191140192140193140194140195140196140197140198140199140200140201140202140203140204140205140206140207140208140209140210140211140212140213140214140215140216140217140218140219140220140221140222140223140224140225140226140227140228140229140230140231140232140233140234140235140236140237140238140239140240140241140242140243140244140245140246140247140248140249140250140251140252140253140254140255140256140257140258140259140260140261140262140263140264140265140266140267140268140269140270140271140272140273140274140275140276140277140278140279140280140281140282140283140284140285140286140287140288140289140290140291140292140293140294140295140296140297140298140299140300140301140302140303140304140305140306140307140308140309140310140311140312140313140314140315140316140317140318140319140320140321140322140323140324140325140326140327140328140329140330140331140332140333140334140335140336140337140338140339140340140341140342140343140344140345140346140347140348140349140350140351140352140353140354140355140356140357140358140359140360140361140362140363140364140365140366140367140368140369140370140371140372140373140374140375140376140377140378140379140380140381140382140383140384140385140386140387140388140389140390140391140392140393140394140395140396140397140398140399140400140401140402140403140404140405140406140407140408140409140410140411140412140413140414140415140416140417140418140419140420140421140422140423140424140425140426140427140428140429140430140431140432140433140434140435140436140437140438140439140440140441140442140443140444140445140446140447140448140449140450140451140452140453140454140455140456140457140458140459140460140461140462140463140464140465140466140467140468140469140470140471140472140473140474140475140476140477140478140479140480140481140482140483140484140485140486140487140488140489140490140491140492140493140494140495140496140497140498140499140500140501140502140503140504140505140506140507140508140509140510140511140512140513140514140515140516140517140518140519140520140521140522140523140524140525140526140527140528140529140530140531140532140533140534140535140536140537140538140539140540140541140542140543140544140545140546140547140548140549140550140551140552140553140554140555140556140557140558140559140560140561140562140563140564140565140566140567140568140569140570140571140572140573140574140575140576140577140578140579140580140581140582140583140584140585140586140587140588140589140590140591140592140593140594140595140596140597140598140599140600140601140602140603140604140605140606140607140608140609140610140611140612140613140614140615140616140617140618140619140620140621140622140623140624140625140626140627140628140629140630140631140632140633140634140635140636140637140638140639140640140641140642140643140644140645140646140647140648140649140650140651140652140653140654140655140656140657140658140659140660140661140662140663140664140665140666140667140668140669140670140671140672140673140674140675140676140677140678140679140680140681140682140683140684140685140686140687140688140689140690140691140692140693140694140695140696140697140698140699140700140701140702140703140704140705140706140707140708140709140710140711140712140713140714140715140716140717140718140719140720140721140722140723140724140725140726140727140728140729140730140731140732140733140734140735140736140737140738140739140740140741140742140743140744140745140746140747140748140749140750140751140752140753140754140755140756140757140758140759140760140761140762140763140764140765140766140767140768140769140770140771140772140773140774140775140776140777140778140779140780140781140782140783140784140785140786140787140788140789140790140791140792140793140794140795140796140797140798140799140800140801140802140803140804140805140806140807140808140809140810140811140812140813140814140815140816140817140818140819140820140821140822140823140824140825140826140827140828140829140830140831140832140833140834140835140836140837140838140839140840140841140842140843140844140845140846140847140848140849140850140851140852140853140854140855140856140857140858140859140860140861140862140863140864140865140866140867140868140869140870140871140872140873140874140875140876140877140878140879140880140881140882140883140884140885140886140887140888140889140890140891140892140893140894140895140896140897140898140899140900140901140902140903140904140905140906140907140908140909140910140911140912140913140914140915140916140917140918140919140920140921140922140923140924140925140926140927140928140929140930140931140932140933140934140935140936140937140938140939140940140941140942140943140944140945140946140947140948140949140950140951140952140953140954140955140956140957140958140959140960140961140962140963140964140965140966140967140968140969140970140971140972140973140974140975140976140977140978140979140980140981140982140983140984140985140986140987140988140989140990140991140992140993140994140995140996140997140998140999141000141001141002141003141004141005141006141007141008141009141010141011141012141013141014141015141016141017141018141019141020141021141022141023141024141025141026141027141028141029141030141031141032141033141034141035141036141037141038141039141040141041141042141043141044141045141046141047141048141049141050141051141052141053141054141055141056141057141058141059141060141061141062141063141064141065141066141067141068141069141070141071141072141073141074141075141076141077141078141079141080141081141082141083141084141085141086141087141088141089141090141091141092141093141094141095141096141097141098141099141100141101141102141103141104141105141106141107141108141109141110141111141112141113141114141115141116141117141118141119141120141121141122141123141124141125141126141127141128141129141130141131141132141133141134141135141136141137141138141139141140141141141142141143141144141145141146141147141148141149141150141151141152141153141154141155141156141157141158141159141160141161141162141163141164141165141166141167141168141169141170141171141172141173141174141175141176141177141178141179141180141181141182141183141184141185141186141187141188141189141190141191141192141193141194141195141196141197141198141199141200141201141202141203141204141205141206141207141208141209141210141211141212141213141214141215141216141217141218141219141220141221141222141223141224141225141226141227141228141229141230141231141232141233141234141235141236141237141238141239141240141241141242141243141244141245141246141247141248141249141250141251141252141253141254141255141256141257141258141259141260141261141262141263141264141265141266141267141268141269141270141271141272141273141274141275141276141277141278141279141280141281141282141283141284141285141286141287141288141289141290141291141292141293141294141295141296141297141298141299141300141301141302141303141304141305141306141307141308141309141310141311141312141313141314141315141316141317141318141319141320141321141322141323141324141325141326141327141328141329141330141331141332141333141334141335141336141337141338141339141340141341141342141343141344141345141346141347141348141349141350141351141352141353141354141355141356141357141358141359141360141361141362141363141364141365141366141367141368141369141370141371141372141373141374141375141376141377141378141379141380141381141382141383141384141385141386141387141388141389141390141391141392141393141394141395141396141397141398141399141400141401141402141403141404141405141406141407141408141409141410141411141412141413141414141415141416141417141418141419141420141421141422141423141424141425141426141427141428141429141430141431141432141433141434141435141436141437141438141439141440141441141442141443141444141445141446141447141448141449141450141451141452141453141454141455141456141457141458141459141460141461141462141463141464141465141466141467141468141469141470141471141472141473141474141475141476141477141478141479141480141481141482141483141484141485141486141487141488141489141490141491141492141493141494141495141496141497141498141499141500141501141502141503141504141505141506141507141508141509141510141511141512141513141514141515141516141517141518141519141520141521141522141523141524141525141526141527141528141529141530141531141532141533141534141535141536141537141538141539141540141541141542141543141544141545141546141547141548141549141550141551141552141553141554141555141556141557141558141559141560141561141562141563141564141565141566141567141568141569141570141571141572141573141574141575141576141577141578141579141580141581141582141583141584141585141586141587141588141589141590141591141592141593141594141595141596141597141598141599141600141601141602141603141604141605141606141607141608141609141610141611141612141613141614141615141616141617141618141619141620141621141622141623141624141625141626141627141628141629141630141631141632141633141634141635141636141637141638141639141640141641141642141643141644141645141646141647141648141649141650141651141652141653141654141655141656141657141658141659141660141661141662141663141664141665141666141667141668141669141670141671141672141673141674141675141676141677141678141679141680141681141682141683141684141685141686141687141688141689141690141691141692141693141694141695141696141697141698141699141700141701141702141703141704141705141706141707141708141709141710141711141712141713141714141715141716141717141718141719141720141721141722141723141724141725141726141727141728141729141730141731141732141733141734141735141736141737141738141739141740141741141742141743141744141745141746141747141748141749141750141751141752141753141754141755141756141757141758141759141760141761141762141763141764141765141766141767141768141769141770141771141772141773141774141775141776141777141778141779141780141781141782141783141784141785141786141787141788141789141790141791141792141793141794141795141796141797141798141799141800141801141802141803141804141805141806141807141808141809141810141811141812141813141814141815141816141817141818141819141820141821141822141823141824141825141826141827141828141829141830141831141832141833141834141835141836141837141838141839141840141841141842141843141844141845141846141847141848141849141850141851141852141853141854141855141856141857141858141859141860141861141862141863141864141865141866141867141868141869141870141871141872141873141874141875141876141877141878141879141880141881141882141883141884141885141886141887141888141889141890141891141892141893141894141895141896141897141898141899141900141901141902141903141904141905141906141907141908141909141910141911141912141913141914141915141916141917141918141919141920141921141922141923141924141925141926141927141928141929141930141931141932141933141934141935141936141937141938141939141940141941141942141943141944141945141946141947141948141949141950141951141952141953141954141955141956141957141958141959141960141961141962141963141964141965141966141967141968141969141970141971141972141973141974141975141976141977141978141979141980141981141982141983141984141985141986141987141988141989141990141991141992141993141994141995141996141997141998141999142000142001142002142003142004142005142006142007142008142009142010142011142012142013142014142015142016142017142018142019142020142021142022142023142024142025142026142027142028142029142030142031142032142033142034142035142036142037142038142039142040142041142042142043142044142045142046142047142048142049142050142051142052142053142054142055142056142057142058142059142060142061142062142063142064142065142066142067142068142069142070142071142072142073142074142075142076142077142078142079142080142081142082142083142084142085142086142087142088142089142090142091142092142093142094142095142096142097142098142099142100142101142102142103142104142105142106142107142108142109142110142111142112142113142114142115142116142117142118142119142120142121142122142123142124142125142126142127142128142129142130142131142132142133142134142135142136142137142138142139142140142141142142142143142144142145142146142147142148142149142150142151142152142153142154142155142156142157142158142159142160142161142162142163142164142165142166142167142168142169142170142171142172142173142174142175142176142177142178142179142180142181142182142183142184142185142186142187142188142189142190142191142192142193142194142195142196142197142198142199142200142201142202142203142204142205142206142207142208142209142210142211142212142213142214142215142216142217142218142219142220142221142222142223142224142225142226142227142228142229142230142231142232142233142234142235142236142237142238142239142240142241142242142243142244142245142246142247142248142249142250142251142252142253142254142255142256142257142258142259142260142261142262142263142264142265142266142267142268142269142270142271142272142273142274142275142276142277142278142279142280142281142282142283142284142285142286142287142288142289142290142291142292142293142294142295142296142297142298142299142300142301142302142303142304142305142306142307142308142309142310142311142312142313142314142315142316142317142318142319142320142321142322142323142324142325142326142327142328142329142330142331142332142333142334142335142336142337142338142339142340142341142342142343142344142345142346142347142348142349142350142351142352142353142354142355142356142357142358142359142360142361142362142363142364142365142366142367142368142369142370142371142372142373142374142375142376142377142378142379142380142381142382142383142384142385142386142387142388142389142390142391142392142393142394142395142396142397142398142399142400142401142402142403142404142405142406142407142408142409142410142411142412142413142414142415142416142417142418142419142420142421142422142423142424142425142426142427142428142429142430142431142432142433142434142435142436142437142438142439142440142441142442142443142444142445142446142447142448142449142450142451142452142453142454142455142456142457142458142459142460142461142462142463142464142465142466142467142468142469142470142471142472142473142474142475142476142477142478142479142480142481142482142483142484142485142486142487142488142489142490142491142492142493142494142495142496142497142498142499142500142501142502142503142504142505142506142507142508142509142510142511142512142513142514142515142516142517142518142519142520142521142522142523142524142525142526142527142528142529142530142531142532142533142534142535142536142537142538142539142540142541142542142543142544142545142546142547142548142549142550142551142552142553142554142555142556142557142558142559142560142561142562142563142564142565142566142567142568142569142570142571142572142573142574142575142576142577142578142579142580142581142582142583142584142585142586142587142588142589142590142591142592142593142594142595142596142597142598142599142600142601142602142603142604142605142606142607142608142609142610142611142612142613142614142615142616142617142618142619142620142621142622142623142624142625142626142627142628142629142630142631142632142633142634142635142636142637142638142639142640142641142642142643142644142645142646142647142648142649142650142651142652142653142654142655142656142657142658142659142660142661142662142663142664142665142666142667142668142669142670142671142672142673142674142675142676142677142678142679142680142681142682142683142684142685142686142687142688142689142690142691142692142693142694142695142696142697142698142699142700142701142702142703142704142705142706142707142708142709142710142711142712142713142714142715142716142717142718142719142720142721142722142723142724142725142726142727142728142729142730142731142732142733142734142735142736142737142738142739142740142741142742142743142744142745142746142747142748142749142750142751142752142753142754142755142756142757142758142759142760142761142762142763142764142765142766142767142768142769142770142771142772142773142774142775142776142777142778142779142780142781142782142783142784142785142786142787142788142789142790142791142792142793142794142795142796142797142798142799142800142801142802142803142804142805142806142807142808142809142810142811142812142813142814142815142816142817142818142819142820142821142822142823142824142825142826142827142828142829142830142831142832142833142834142835142836142837142838142839142840142841142842142843142844142845142846142847142848142849142850142851142852142853142854142855142856142857142858142859142860142861142862142863142864142865142866142867142868142869142870142871142872142873142874142875142876142877142878142879142880142881142882142883142884142885142886142887142888142889142890142891142892142893142894142895142896142897142898142899142900142901142902142903142904142905142906142907142908142909142910142911142912142913142914142915142916142917142918142919142920142921142922142923142924142925142926142927142928142929142930142931142932142933142934142935142936142937142938142939142940142941142942142943142944142945142946142947142948142949142950142951142952142953142954142955142956142957142958142959142960142961142962142963142964142965142966142967142968142969142970142971142972142973142974142975142976142977142978142979142980142981142982142983142984142985142986142987142988142989142990142991142992142993142994142995142996142997142998142999143000143001143002143003143004143005143006143007143008143009143010143011143012143013143014143015143016143017143018143019143020143021143022143023143024143025143026143027143028143029143030143031143032143033143034143035143036143037143038143039143040143041143042143043143044143045143046143047143048143049143050143051143052143053143054143055143056143057143058143059143060143061143062143063143064143065143066143067143068143069143070143071143072143073143074143075143076143077143078143079143080143081143082143083143084143085143086143087143088143089143090143091143092143093143094143095143096143097143098143099143100143101143102143103143104143105143106143107143108143109143110143111143112143113143114143115143116143117143118143119143120143121143122143123143124143125143126143127143128143129143130143131143132143133143134143135143136143137143138143139143140143141143142143143143144143145143146143147143148143149143150143151143152143153143154143155143156143157143158143159143160143161143162143163143164143165143166143167143168143169143170143171143172143173143174143175143176143177143178143179143180143181143182143183143184143185143186143187143188143189143190143191143192143193143194143195143196143197143198143199143200143201143202143203143204143205143206143207143208143209143210143211143212143213143214143215143216143217143218143219143220143221143222143223143224143225143226143227143228143229143230143231143232143233143234143235143236143237143238143239143240143241143242143243143244143245143246143247143248143249143250143251143252143253143254143255143256143257143258143259143260143261143262143263143264143265143266143267143268143269143270143271143272143273143274143275143276143277143278143279143280143281143282143283143284143285143286143287143288143289143290143291143292143293143294143295143296143297143298143299143300143301143302143303143304143305143306143307143308143309143310143311143312143313143314143315143316143317143318143319143320143321143322143323143324143325143326143327143328143329143330143331143332143333143334143335143336143337143338143339143340143341143342143343143344143345143346143347143348143349143350143351143352143353143354143355143356143357143358143359143360143361143362143363143364143365143366143367143368143369143370143371143372143373143374143375143376143377143378143379143380143381143382143383143384143385143386143387143388143389143390143391143392143393143394143395143396143397143398143399143400143401143402143403143404143405143406143407143408143409143410143411143412143413143414143415143416143417143418143419143420143421143422143423143424143425143426143427143428143429143430143431143432143433143434143435143436143437143438143439143440143441143442143443143444143445143446143447143448143449143450143451143452143453143454143455143456143457143458143459143460143461143462143463143464143465143466143467143468143469143470143471143472143473143474143475143476143477143478143479143480143481143482143483143484143485143486143487143488143489143490143491143492143493143494143495143496143497143498143499143500143501143502143503143504143505143506143507143508143509143510143511143512143513143514143515143516143517143518143519143520143521143522143523143524143525143526143527143528143529143530143531143532143533143534143535143536143537143538143539143540143541143542143543143544143545143546143547143548143549143550143551143552143553143554143555143556143557143558143559143560143561143562143563143564143565143566143567143568143569143570143571143572143573143574143575143576143577143578143579143580143581143582143583143584143585143586143587143588143589143590143591143592143593143594143595143596143597143598143599143600143601143602143603143604143605143606143607143608143609143610143611143612143613143614143615143616143617143618143619143620143621143622143623143624143625143626143627143628143629143630143631143632143633143634143635143636143637143638143639143640143641143642143643143644143645143646143647143648143649143650143651143652143653143654143655143656143657143658143659143660143661143662143663143664143665143666143667143668143669143670143671143672143673143674143675143676143677143678143679143680143681143682143683143684143685143686143687143688143689143690143691143692143693143694143695143696143697143698143699143700143701143702143703143704143705143706143707143708143709143710143711143712143713143714143715143716143717143718143719143720143721143722143723143724143725143726143727143728143729143730143731143732143733143734143735143736143737143738143739143740143741143742143743143744143745143746143747143748143749143750143751143752143753143754143755143756143757143758143759143760143761143762143763143764143765143766143767143768143769143770143771143772143773143774143775143776143777143778143779143780143781143782143783143784143785143786143787143788143789143790143791143792143793143794143795143796143797143798143799143800143801143802143803143804143805143806143807143808143809143810143811143812143813143814143815143816143817143818143819143820143821143822143823143824143825143826143827143828143829143830143831143832143833143834143835143836143837143838143839143840143841143842143843143844143845143846143847143848143849143850143851143852143853143854143855143856143857143858143859143860143861143862143863143864143865143866143867143868143869143870143871143872143873143874143875143876143877143878143879143880143881143882143883143884143885143886143887143888143889143890143891143892143893143894143895143896143897143898143899143900143901143902143903143904143905143906143907143908143909143910143911143912143913143914143915143916143917143918143919143920143921143922143923143924143925143926143927143928143929143930143931143932143933143934143935143936143937143938143939143940143941143942143943143944143945143946143947143948143949143950143951143952143953143954143955143956143957143958143959143960143961143962143963143964143965143966143967143968143969143970143971143972143973143974143975143976143977143978143979143980143981143982143983143984143985143986143987143988143989143990143991143992143993143994143995143996143997143998143999144000144001144002144003144004144005144006144007144008144009144010144011144012144013144014144015144016144017144018144019144020144021144022144023144024144025144026144027144028144029144030144031144032144033144034144035144036144037144038144039144040144041144042144043144044144045144046144047144048144049144050144051144052144053144054144055144056144057144058144059144060144061144062144063144064144065144066144067144068144069144070144071144072144073144074144075144076144077144078144079144080144081144082144083144084144085144086144087144088144089144090144091144092144093144094144095144096144097144098144099144100144101144102144103144104144105144106144107144108144109144110144111144112144113144114144115144116144117144118144119144120144121144122144123144124144125144126144127144128144129144130144131144132144133144134144135144136144137144138144139144140144141144142144143144144144145144146144147144148144149144150144151144152144153144154144155144156144157144158144159144160144161144162144163144164144165144166144167144168144169144170144171144172144173144174144175144176144177144178144179144180144181144182144183144184144185144186144187144188144189144190144191144192144193144194144195144196144197144198144199144200144201144202144203144204144205144206144207144208144209144210144211144212144213144214144215144216144217144218144219144220144221144222144223144224144225144226144227144228144229144230144231144232144233144234144235144236144237144238144239144240144241144242144243144244144245144246144247144248144249144250144251144252144253144254144255144256144257144258144259144260144261144262144263144264144265144266144267144268144269144270144271144272144273144274144275144276144277144278144279144280144281144282144283144284144285144286144287144288144289144290144291144292144293144294144295144296144297144298144299144300144301144302144303144304144305144306144307144308144309144310144311144312144313144314144315144316144317144318144319144320144321144322144323144324144325144326144327144328144329144330144331144332144333144334144335144336144337144338144339144340144341144342144343144344144345144346144347144348144349144350144351144352144353144354144355144356144357144358144359144360144361144362144363144364144365144366144367144368144369144370144371144372144373144374144375144376144377144378144379144380144381144382144383144384144385144386144387144388144389144390144391144392144393144394144395144396144397144398144399144400144401144402144403144404144405144406144407144408144409144410144411144412144413144414144415144416144417144418144419144420144421144422144423144424144425144426144427144428144429144430144431144432144433144434144435144436144437144438144439144440144441144442144443144444144445144446144447144448144449144450144451144452144453144454144455144456144457144458144459144460144461144462144463144464144465144466144467144468144469144470144471144472144473144474144475144476144477144478144479144480144481144482144483144484144485144486144487144488144489144490144491144492144493144494144495144496144497144498144499144500144501144502144503144504144505144506144507144508144509144510144511144512144513144514144515144516144517144518144519144520144521144522144523144524144525144526144527144528144529144530144531144532144533144534144535144536144537144538144539144540144541144542144543144544144545144546144547144548144549144550144551144552144553144554144555144556144557144558144559144560144561144562144563144564144565144566144567144568144569144570144571144572144573144574144575144576144577144578144579144580144581144582144583144584144585144586144587144588144589144590144591144592144593144594144595144596144597144598144599144600144601144602144603144604144605144606144607144608144609144610144611144612144613144614144615144616144617144618144619144620144621144622144623144624144625144626144627144628144629144630144631144632144633144634144635144636144637144638144639144640144641144642144643144644144645144646144647144648144649144650144651144652144653144654144655144656144657144658144659144660144661144662144663144664144665144666144667144668144669144670144671144672144673144674144675144676144677144678144679144680144681144682144683144684144685144686144687144688144689144690144691144692144693144694144695144696144697144698144699144700144701144702144703144704144705144706144707144708144709144710144711144712144713144714144715144716144717144718144719144720144721144722144723144724144725144726144727144728144729144730144731144732144733144734144735144736144737144738144739144740144741144742144743144744144745144746144747144748144749144750144751144752144753144754144755144756144757144758144759144760144761144762144763144764144765144766144767144768144769144770144771144772144773144774144775144776144777144778144779144780144781144782144783144784144785144786144787144788144789144790144791144792144793144794144795144796144797144798144799144800144801144802144803144804144805144806144807144808144809144810144811144812144813144814144815144816144817144818144819144820144821144822144823144824144825144826144827144828144829144830144831144832144833144834144835144836144837144838144839144840144841144842144843144844144845144846144847144848144849144850144851144852144853144854144855144856144857144858144859144860144861144862144863144864144865144866144867144868144869144870144871144872144873144874144875144876144877144878144879144880144881144882144883144884144885144886144887144888144889144890144891144892144893144894144895144896144897144898144899144900144901144902144903144904144905144906144907144908144909144910144911144912144913144914144915144916144917144918144919144920144921144922144923144924144925144926144927144928144929144930144931144932144933144934144935144936144937144938144939144940144941144942144943144944144945144946144947144948144949144950144951144952144953144954144955144956144957144958144959144960144961144962144963144964144965144966144967144968144969144970144971144972144973144974144975144976144977144978144979144980144981144982144983144984144985144986144987144988144989144990144991144992144993144994144995144996144997144998144999145000145001145002145003145004145005145006145007145008145009145010145011145012145013145014145015145016145017145018145019145020145021145022145023145024145025145026145027145028145029145030145031145032145033145034145035145036145037145038145039145040145041145042145043145044145045145046145047145048145049145050145051145052145053145054145055145056145057145058145059145060145061145062145063145064145065145066145067145068145069145070145071145072145073145074145075145076145077145078145079145080145081145082145083145084145085145086145087145088145089145090145091145092145093145094145095145096145097145098145099145100145101145102145103145104145105145106145107145108145109145110145111145112145113145114145115145116145117145118145119145120145121145122145123145124145125145126145127145128145129145130145131145132145133145134145135145136145137145138145139145140145141145142145143145144145145145146145147145148145149145150145151145152145153145154145155145156145157145158145159145160145161145162145163145164145165145166145167145168145169145170145171145172145173145174145175145176145177145178145179145180145181145182145183145184145185145186145187145188145189145190145191145192145193145194145195145196145197145198145199145200145201145202145203145204145205145206145207145208145209145210145211145212145213145214145215145216145217145218145219145220145221145222145223145224145225145226145227145228145229145230145231145232145233145234145235145236145237145238145239145240145241145242145243145244145245145246145247145248145249145250145251145252145253145254145255145256145257145258145259145260145261145262145263145264145265145266145267145268145269145270145271145272145273145274145275145276145277145278145279145280145281145282145283145284145285145286145287145288145289145290145291145292145293145294145295145296145297145298145299145300145301145302145303145304145305145306145307145308145309145310145311145312145313145314145315145316145317145318145319145320145321145322145323145324145325145326145327145328145329145330145331145332145333145334145335145336145337145338145339145340145341145342145343145344145345145346145347145348145349145350145351145352145353145354145355145356145357145358145359145360145361145362145363145364145365145366145367145368145369145370145371145372145373145374145375145376145377145378145379145380145381145382145383145384145385145386145387145388145389145390145391145392145393145394145395145396145397145398145399145400145401145402145403145404145405145406145407145408145409145410145411145412145413145414145415145416145417145418145419145420145421145422145423145424145425145426145427145428145429145430145431145432145433145434145435145436145437145438145439145440145441145442145443145444145445145446145447145448145449145450145451145452145453145454145455145456145457145458145459145460145461145462145463145464145465145466145467145468145469145470145471145472145473145474145475145476145477145478145479145480145481145482145483145484145485145486145487145488145489145490145491145492145493145494145495145496145497145498145499145500145501145502145503145504145505145506145507145508145509145510145511145512145513145514145515145516145517145518145519145520145521145522145523145524145525145526145527145528145529145530145531145532145533145534145535145536145537145538145539145540145541145542145543145544145545145546145547145548145549145550145551145552145553145554145555145556145557145558145559145560145561145562145563145564145565145566145567145568145569145570145571145572145573145574145575145576145577145578145579145580145581145582145583145584145585145586145587145588145589145590145591145592145593145594145595145596145597145598145599145600145601145602145603145604145605145606145607145608145609145610145611145612145613145614145615145616145617145618145619145620145621145622145623145624145625145626145627145628145629145630145631145632145633145634145635145636145637145638145639145640145641145642145643145644145645145646145647145648145649145650145651145652145653145654145655145656145657145658145659145660145661145662145663145664145665145666145667145668145669145670145671145672145673145674145675145676145677145678145679145680145681145682145683145684145685145686145687145688145689145690145691145692145693145694145695145696145697145698145699145700145701145702145703145704145705145706145707145708145709145710145711145712145713145714145715145716145717145718145719145720145721145722145723145724145725145726145727145728145729145730145731145732145733145734145735145736145737145738145739145740145741145742145743145744145745145746145747145748145749145750145751145752145753145754145755145756145757145758145759145760145761145762145763145764145765145766145767145768145769145770145771145772145773145774145775145776145777145778145779145780145781145782145783145784145785145786145787145788145789145790145791145792145793145794145795145796145797145798145799145800145801145802145803145804145805145806145807145808145809145810145811145812145813145814145815145816145817145818145819145820145821145822145823145824145825145826145827145828145829145830145831145832145833145834145835145836145837145838145839145840145841145842145843145844145845145846145847145848145849145850145851145852145853145854145855145856145857145858145859145860145861145862145863145864145865145866145867145868145869145870145871145872145873145874145875145876145877145878145879145880145881145882145883145884145885145886145887145888145889145890145891145892145893145894145895145896145897145898145899145900145901145902145903145904145905145906145907145908145909145910145911145912145913145914145915145916145917145918145919145920145921145922145923145924145925145926145927145928145929145930145931145932145933145934145935145936145937145938145939145940145941145942145943145944145945145946145947145948145949145950145951145952145953145954145955145956145957145958145959145960145961145962145963145964145965145966145967145968145969145970145971145972145973145974145975145976145977145978145979145980145981145982145983145984145985145986145987145988145989145990145991145992145993145994145995145996145997145998145999146000146001146002146003146004146005146006146007146008146009146010146011146012146013146014146015146016146017146018146019146020146021146022146023146024146025146026146027146028146029146030146031146032146033146034146035146036146037146038146039146040146041146042146043146044146045146046146047146048146049146050146051146052146053146054146055146056146057146058146059146060146061146062146063146064146065146066146067146068146069146070146071146072146073146074146075146076146077146078146079146080146081146082146083146084146085146086146087146088146089146090146091146092146093146094146095146096146097146098146099146100146101146102146103146104146105146106146107146108146109146110146111146112146113146114146115146116146117146118146119146120146121146122146123146124146125146126146127146128146129146130146131146132146133146134146135146136146137146138146139146140146141146142146143146144146145146146146147146148146149146150146151146152146153146154146155146156146157146158146159146160146161146162146163146164146165146166146167146168146169146170146171146172146173146174146175146176146177146178146179146180146181146182146183146184146185146186146187146188146189146190146191146192146193146194146195146196146197146198146199146200146201146202146203146204146205146206146207146208146209146210146211146212146213146214146215146216146217146218146219146220146221146222146223146224146225146226146227146228146229146230146231146232146233146234146235146236146237146238146239146240146241146242146243146244146245146246146247146248146249146250146251146252146253146254146255146256146257146258146259146260146261146262146263146264146265146266146267146268146269146270146271146272146273146274146275146276146277146278146279146280146281146282146283146284146285146286146287146288146289146290146291146292146293146294146295146296146297146298146299146300146301146302146303146304146305146306146307146308146309146310146311146312146313146314146315146316146317146318146319146320146321146322146323146324146325146326146327146328146329146330146331146332146333146334146335146336146337146338146339146340146341146342146343146344146345146346146347146348146349146350146351146352146353146354146355146356146357146358146359146360146361146362146363146364146365146366146367146368146369146370146371146372146373146374146375146376146377146378146379146380146381146382146383146384146385146386146387146388146389146390146391146392146393146394146395146396146397146398146399146400146401146402146403146404146405146406146407146408146409146410146411146412146413146414146415146416146417146418146419146420146421146422146423146424146425146426146427146428146429146430146431146432146433146434146435146436146437146438146439146440146441146442146443146444146445146446146447146448146449146450146451146452146453146454146455146456146457146458146459146460146461146462146463146464146465146466146467146468146469146470146471146472146473146474146475146476146477146478146479146480146481146482146483146484146485146486146487146488146489146490146491146492146493146494146495146496146497146498146499146500146501146502146503146504146505146506146507146508146509146510146511146512146513146514146515146516146517146518146519146520146521146522146523146524146525146526146527146528146529146530146531146532146533146534146535146536146537146538146539146540146541146542146543146544146545146546146547146548146549146550146551146552146553146554146555146556146557146558146559146560146561146562146563146564146565146566146567146568146569146570146571146572146573146574146575146576146577146578146579146580146581146582146583146584146585146586146587146588146589146590146591146592146593146594146595146596146597146598146599146600146601146602146603146604146605146606146607146608146609146610146611146612146613146614146615146616146617146618146619146620146621146622146623146624146625146626146627146628146629146630146631146632146633146634146635146636146637146638146639146640146641146642146643146644146645146646146647146648146649146650146651146652146653146654146655146656146657146658146659146660146661146662146663146664146665146666146667146668146669146670146671146672146673146674146675146676146677146678146679146680146681146682146683146684146685146686146687146688146689146690146691146692146693146694146695146696146697146698146699146700146701146702146703146704146705146706146707146708146709146710146711146712146713146714146715146716146717146718146719146720146721146722146723146724146725146726146727146728146729146730146731146732146733146734146735146736146737146738146739146740146741146742146743146744146745146746146747146748146749146750146751146752146753146754146755146756146757146758146759146760146761146762146763146764146765146766146767146768146769146770146771146772146773146774146775146776146777146778146779146780146781146782146783146784146785146786146787146788146789146790146791146792146793146794146795146796146797146798146799146800146801146802146803146804146805146806146807146808146809146810146811146812146813146814146815146816146817146818146819146820146821146822146823146824146825146826146827146828146829146830146831146832146833146834146835146836146837146838146839146840146841146842146843146844146845146846146847146848146849146850146851146852146853146854146855146856146857146858146859146860146861146862146863146864146865146866146867146868146869146870146871146872146873146874146875146876146877146878146879146880146881146882146883146884146885146886146887146888146889146890146891146892146893146894146895146896146897146898146899146900146901146902146903146904146905146906146907146908146909146910146911146912146913146914146915146916146917146918146919146920146921146922146923146924146925146926146927146928146929146930146931146932146933146934146935146936146937146938146939146940146941146942146943146944146945146946146947146948146949146950146951146952146953146954146955146956146957146958146959146960146961146962146963146964146965146966146967146968146969146970146971146972146973146974146975146976146977146978146979146980146981146982146983146984146985146986146987146988146989146990146991146992146993146994146995146996146997146998146999147000147001147002147003147004147005147006147007147008147009147010147011147012147013147014147015147016147017147018147019147020147021147022147023147024147025147026147027147028147029147030147031147032147033147034147035147036147037147038147039147040147041147042147043147044147045147046147047147048147049147050147051147052147053147054147055147056147057147058147059147060147061147062147063147064147065147066147067147068147069147070147071147072147073147074147075147076147077147078147079147080147081147082147083147084147085147086147087147088147089147090147091147092147093147094147095147096147097147098147099147100147101147102147103147104147105147106147107147108147109147110147111147112147113147114147115147116147117147118147119147120147121147122147123147124147125147126147127147128147129147130147131147132147133147134147135147136147137147138147139147140147141147142147143147144147145147146147147147148147149147150147151147152147153147154147155147156147157147158147159147160147161147162147163147164147165147166147167147168147169147170147171147172147173147174147175147176147177147178147179147180147181147182147183147184147185147186147187147188147189147190147191147192147193147194147195147196147197147198147199147200147201147202147203147204147205147206147207147208147209147210147211147212147213147214147215147216147217147218147219147220147221147222147223147224147225147226147227147228147229147230147231147232147233147234147235147236147237147238147239147240147241147242147243147244147245147246147247147248147249147250147251147252147253147254147255147256147257147258147259147260147261147262147263147264147265147266147267147268147269147270147271147272147273147274147275147276147277147278147279147280147281147282147283147284147285147286147287147288147289147290147291147292147293147294147295147296147297147298147299147300147301147302147303147304147305147306147307147308147309147310147311147312147313147314147315147316147317147318147319147320147321147322147323147324147325147326147327147328147329147330147331147332147333147334147335147336147337147338147339147340147341147342147343147344147345147346147347147348147349147350147351147352147353147354147355147356147357147358147359147360147361147362147363147364147365147366147367147368147369147370147371147372147373147374147375147376147377147378147379147380147381147382147383147384147385147386147387147388147389147390147391147392147393147394147395147396147397147398147399147400147401147402147403147404147405147406147407147408147409147410147411147412147413147414147415147416147417147418147419147420147421147422147423147424147425147426147427147428147429147430147431147432147433147434147435147436147437147438147439147440147441147442147443147444147445147446147447147448147449147450147451147452147453147454147455147456147457147458147459147460147461147462147463147464147465147466147467147468147469147470147471147472147473147474147475147476147477147478147479147480147481147482147483147484147485147486147487147488147489147490147491147492147493147494147495147496147497147498147499147500147501147502147503147504147505147506147507147508147509147510147511147512147513147514147515147516147517147518147519147520147521147522147523147524147525147526147527147528147529147530147531147532147533147534147535147536147537147538147539147540147541147542147543147544147545147546147547147548147549147550147551147552147553147554147555147556147557147558147559147560147561147562147563147564147565147566147567147568147569147570147571147572147573147574147575147576147577147578147579147580147581147582147583147584147585147586147587147588147589147590147591147592147593147594147595147596147597147598147599147600147601147602147603147604147605147606147607147608147609147610147611147612147613147614147615147616147617147618147619147620147621147622147623147624147625147626147627147628147629147630147631147632147633147634147635147636147637147638147639147640147641147642147643147644147645147646147647147648147649147650147651147652147653147654147655147656147657147658147659147660147661147662147663147664147665147666147667147668147669147670147671147672147673147674147675147676147677147678147679147680147681147682147683147684147685147686147687147688147689147690147691147692147693147694147695147696147697147698147699147700147701147702147703147704147705147706147707147708147709147710147711147712147713147714147715147716147717147718147719147720147721147722147723147724147725147726147727147728147729147730147731147732147733147734147735147736147737147738147739147740147741147742147743147744147745147746147747147748147749147750147751147752147753147754147755147756147757147758147759147760147761147762147763147764147765147766147767147768147769147770147771147772147773147774147775147776147777147778147779147780147781147782147783147784147785147786147787147788147789147790147791147792147793147794147795147796147797147798147799147800147801147802147803147804147805147806147807147808147809147810147811147812147813147814147815147816147817147818147819147820147821147822147823147824147825147826147827147828147829147830147831147832147833147834147835147836147837147838147839147840147841147842147843147844147845147846147847147848147849147850147851147852147853147854147855147856147857147858147859147860147861147862147863147864147865147866147867147868147869147870147871147872147873147874147875147876147877147878147879147880147881147882147883147884147885147886147887147888147889147890147891147892147893147894147895147896147897147898147899147900147901147902147903147904147905147906147907147908147909147910147911147912147913147914147915147916147917147918147919147920147921147922147923147924147925147926147927147928147929147930147931147932147933147934147935147936147937147938147939147940147941147942147943147944147945147946147947147948147949147950147951147952147953147954147955147956147957147958147959147960147961147962147963147964147965147966147967147968147969147970147971147972147973147974147975147976147977147978147979147980147981147982147983147984147985147986147987147988147989147990147991147992147993147994147995147996147997147998147999148000148001148002148003148004148005148006148007148008148009148010148011148012148013148014148015148016148017148018148019148020148021148022148023148024148025148026148027148028148029148030148031148032148033148034148035148036148037148038148039148040148041148042148043148044148045148046148047148048148049148050148051148052148053148054148055148056148057148058148059148060148061148062148063148064148065148066148067148068148069148070148071148072148073148074148075148076148077148078148079148080148081148082148083148084148085148086148087148088148089148090148091148092148093148094148095148096148097148098148099148100148101148102148103148104148105148106148107148108148109148110148111148112148113148114148115148116148117148118148119148120148121148122148123148124148125148126148127148128148129148130148131148132148133148134148135148136148137148138148139148140148141148142148143148144148145148146148147148148148149148150148151148152148153148154148155148156148157148158148159148160148161148162148163148164148165148166148167148168148169148170148171148172148173148174148175148176148177148178148179148180148181148182148183148184148185148186148187148188148189148190148191148192148193148194148195148196148197148198148199148200148201148202148203148204148205148206148207148208148209148210148211148212148213148214148215148216148217148218148219148220148221148222148223148224148225148226148227148228148229148230148231148232148233148234148235148236148237148238148239148240148241148242148243148244148245148246148247148248148249148250148251148252148253148254148255148256148257148258148259148260148261148262148263148264148265148266148267148268148269148270148271148272148273148274148275148276148277148278148279148280148281148282148283148284148285148286148287148288148289148290148291148292148293148294148295148296148297148298148299148300148301148302148303148304148305148306148307148308148309148310148311148312148313148314148315148316148317148318148319148320148321148322148323148324148325148326148327148328148329148330148331148332148333148334148335148336148337148338148339148340148341148342148343148344148345148346148347148348148349148350148351148352148353148354148355148356148357148358148359148360148361148362148363148364148365148366148367148368148369148370148371148372148373148374148375148376148377148378148379148380148381148382148383148384148385148386148387148388148389148390148391148392148393148394148395148396148397148398148399148400148401148402148403148404148405148406148407148408148409148410148411148412148413148414148415148416148417148418148419148420148421148422148423148424148425148426148427148428148429148430148431148432148433148434148435148436148437148438148439148440148441148442148443148444148445148446148447148448148449148450148451148452148453148454148455148456148457148458148459148460148461148462148463148464148465148466148467148468148469148470148471148472148473148474148475148476148477148478148479148480148481148482148483148484148485148486148487148488148489148490148491148492148493148494148495148496148497148498148499148500148501148502148503148504148505148506148507148508148509148510148511148512148513148514148515148516148517148518148519148520148521148522148523148524148525148526148527148528148529148530148531148532148533148534148535148536148537148538148539148540148541148542148543148544148545148546148547148548148549148550148551148552148553148554148555148556148557148558148559148560148561148562148563148564148565148566148567148568148569148570148571148572148573148574148575148576148577148578148579148580148581148582148583148584148585148586148587148588148589148590148591148592148593148594148595148596148597148598148599148600148601148602148603148604148605148606148607148608148609148610148611148612148613148614148615148616148617148618148619148620148621148622148623148624148625148626148627148628148629148630148631148632148633148634148635148636148637148638148639148640148641148642148643148644148645148646148647148648148649148650148651148652148653148654148655148656148657148658148659148660148661148662148663148664148665148666148667148668148669148670148671148672148673148674148675148676148677148678148679148680148681148682148683148684148685148686148687148688148689148690148691148692148693148694148695148696148697148698148699148700148701148702148703148704148705148706148707148708148709148710148711148712148713148714148715148716148717148718148719148720148721148722148723148724148725148726148727148728148729148730148731148732148733148734148735148736148737148738148739148740148741148742148743148744148745148746148747148748148749148750148751148752148753148754148755148756148757148758148759148760148761148762148763148764148765148766148767148768148769148770148771148772148773148774148775148776148777148778148779148780148781148782148783148784148785148786148787148788148789148790148791148792148793148794148795148796148797148798148799148800148801148802148803148804148805148806148807148808148809148810148811148812148813148814148815148816148817148818148819148820148821148822148823148824148825148826148827148828148829148830148831148832148833148834148835148836148837148838148839148840148841148842148843148844148845148846148847148848148849148850148851148852148853148854148855148856148857148858148859148860148861148862148863148864148865148866148867148868148869148870148871148872148873148874148875148876148877148878148879148880148881148882148883148884148885148886148887148888148889148890148891148892148893148894148895148896148897148898148899148900148901148902148903148904148905148906148907148908148909148910148911148912148913148914148915148916148917148918148919148920148921148922148923148924148925148926148927148928148929148930148931148932148933148934148935148936148937148938148939148940148941148942148943148944148945148946148947148948148949148950148951148952148953148954148955148956148957148958148959148960148961148962148963148964148965148966148967148968148969148970148971148972148973148974148975148976148977148978148979148980148981148982148983148984148985148986148987148988148989148990148991148992148993148994148995148996148997148998148999149000149001149002149003149004149005149006149007149008149009149010149011149012149013149014149015149016149017149018149019149020149021149022149023149024149025149026149027149028149029149030149031149032149033149034149035149036149037149038149039149040149041149042149043149044149045149046149047149048149049149050149051149052149053149054149055149056149057149058149059149060149061149062149063149064149065149066149067149068149069149070149071149072149073149074149075149076149077149078149079149080149081149082149083149084149085149086149087149088149089149090149091149092149093149094149095149096149097149098149099149100149101149102149103149104149105149106149107149108149109149110149111149112149113149114149115149116149117149118149119149120149121149122149123149124149125149126149127149128149129149130149131149132149133149134149135149136149137149138149139149140149141149142149143149144149145149146149147149148149149149150149151149152149153149154149155149156149157149158149159149160149161149162149163149164149165149166149167149168149169149170149171149172149173149174149175149176149177149178149179149180149181149182149183149184149185149186149187149188149189149190149191149192149193149194149195149196149197149198149199149200149201149202149203149204149205149206149207149208149209149210149211149212149213149214149215149216149217149218149219149220149221149222149223149224149225149226149227149228149229149230149231149232149233149234149235149236149237149238149239149240149241149242149243149244149245149246149247149248149249149250149251149252149253149254149255149256149257149258149259149260149261149262149263149264149265149266149267149268149269149270149271149272149273149274149275149276149277149278149279149280149281149282149283149284149285149286149287149288149289149290149291149292149293149294149295149296149297149298149299149300149301149302149303149304149305149306149307149308149309149310149311149312149313149314149315149316149317149318149319149320149321149322149323149324149325149326149327149328149329149330149331149332149333149334149335149336149337149338149339149340149341149342149343149344149345149346149347149348149349149350149351149352149353149354149355149356149357149358149359149360149361149362149363149364149365149366149367149368149369149370149371149372149373149374149375149376149377149378149379149380149381149382149383149384149385149386149387149388149389149390149391149392149393149394149395149396149397149398149399149400149401149402149403149404149405149406149407149408149409149410149411149412149413149414149415149416149417149418149419149420149421149422149423149424149425149426149427149428149429149430149431149432149433149434149435149436149437149438149439149440149441149442149443149444149445149446149447149448149449149450149451149452149453149454149455149456149457149458149459149460149461149462149463149464149465149466149467149468149469149470149471149472149473149474149475149476149477149478149479149480149481149482149483149484149485149486149487149488149489149490149491149492149493149494149495149496149497149498149499149500149501149502149503149504149505149506149507149508149509149510149511149512149513149514149515149516149517149518149519149520149521149522149523149524149525149526149527149528149529149530149531149532149533149534149535149536149537149538149539149540149541149542149543149544149545149546149547149548149549149550149551149552149553149554149555149556149557149558149559149560149561149562149563149564149565149566149567149568149569149570149571149572149573149574149575149576149577149578149579149580149581149582149583149584149585149586149587149588149589149590149591149592149593149594149595149596149597149598149599149600149601149602149603149604149605149606149607149608149609149610149611149612149613149614149615149616149617149618149619149620149621149622149623149624149625149626149627149628149629149630149631149632149633149634149635149636149637149638149639149640149641149642149643149644149645149646149647149648149649149650149651149652149653149654149655149656149657149658149659149660149661149662149663149664149665149666149667149668149669149670149671149672149673149674149675149676149677149678149679149680149681149682149683149684149685149686149687149688149689149690149691149692149693149694149695149696149697149698149699149700149701149702149703149704149705149706149707149708149709149710149711149712149713149714149715149716149717149718149719149720149721149722149723149724149725149726149727149728149729149730149731149732149733149734149735149736149737149738149739149740149741149742149743149744149745149746149747149748149749149750149751149752149753149754149755149756149757149758149759149760149761149762149763149764149765149766149767149768149769149770149771149772149773149774149775149776149777149778149779149780149781149782149783149784149785149786149787149788149789149790149791149792149793149794149795149796149797149798149799149800149801149802149803149804149805149806149807149808149809149810149811149812149813149814149815149816149817149818149819149820149821149822149823149824149825149826149827149828149829149830149831149832149833149834149835149836149837149838149839149840149841149842149843149844149845149846149847149848149849149850149851149852149853149854149855149856149857149858149859149860149861149862149863149864149865149866149867149868149869149870149871149872149873149874149875149876149877149878149879149880149881149882149883149884149885149886149887149888149889149890149891149892149893149894149895149896149897149898149899149900149901149902149903149904149905149906149907149908149909149910149911149912149913149914149915149916149917149918149919149920149921149922149923149924149925149926149927149928149929149930149931149932149933149934149935149936149937149938149939149940149941149942149943149944149945149946149947149948149949149950149951149952149953149954149955149956149957149958149959149960149961149962149963149964149965149966149967149968149969149970149971149972149973149974149975149976149977149978149979149980149981149982149983149984149985149986149987149988149989149990149991149992149993149994149995149996149997149998149999150000150001150002150003150004150005150006150007150008150009150010150011150012150013150014150015150016150017150018150019150020150021150022150023150024150025150026150027150028150029150030150031150032150033150034150035150036150037150038150039150040150041150042150043150044150045150046150047150048150049150050150051150052150053150054150055150056150057150058150059150060150061150062150063150064150065150066150067150068150069150070150071150072150073150074150075150076150077150078150079150080150081150082150083150084150085150086150087150088150089150090150091150092150093150094150095150096150097150098150099150100150101150102150103150104150105150106150107150108150109150110150111150112150113150114150115150116150117150118150119150120150121150122150123150124150125150126150127150128150129150130150131150132150133150134150135150136150137150138150139150140150141150142150143150144150145150146150147150148150149150150150151150152150153150154150155150156150157150158150159150160150161150162150163150164150165150166150167150168150169150170150171150172150173150174150175150176150177150178150179150180150181150182150183150184150185150186150187150188150189150190150191150192150193150194150195150196150197150198150199150200150201150202150203150204150205150206150207150208150209150210150211150212150213150214150215150216150217150218150219150220150221150222150223150224150225150226150227150228150229150230150231150232150233150234150235150236150237150238150239150240150241150242150243150244150245150246150247150248150249150250150251150252150253150254150255150256150257150258150259150260150261150262150263150264150265150266150267150268150269150270150271150272150273150274150275150276150277150278150279150280150281150282150283150284150285150286150287150288150289150290150291150292150293150294150295150296150297150298150299150300150301150302150303150304150305150306150307150308150309150310150311150312150313150314150315150316150317150318150319150320150321150322150323150324150325150326150327150328150329150330150331150332150333150334150335150336150337150338150339150340150341150342150343150344150345150346150347150348150349150350150351150352150353150354150355150356150357150358150359150360150361150362150363150364150365150366150367150368150369150370150371150372150373150374150375150376150377150378150379150380150381150382150383150384150385150386150387150388150389150390150391150392150393150394150395150396150397150398150399150400150401150402150403150404150405150406150407150408150409150410150411150412150413150414150415150416150417150418150419150420150421150422150423150424150425150426150427150428150429150430150431150432150433150434150435150436150437150438150439150440150441150442150443150444150445150446150447150448150449150450150451150452150453150454150455150456150457150458150459150460150461150462150463150464150465150466150467150468150469150470150471150472150473150474150475150476150477150478150479150480150481150482150483150484150485150486150487150488150489150490150491150492150493150494150495150496150497150498150499150500150501150502150503150504150505150506150507150508150509150510150511150512150513150514150515150516150517150518150519150520150521150522150523150524150525150526150527150528150529150530150531150532150533150534150535150536150537150538150539150540150541150542150543150544150545150546150547150548150549150550150551150552150553150554150555150556150557150558150559150560150561150562150563150564150565150566150567150568150569150570150571150572150573150574150575150576150577150578150579150580150581150582150583150584150585150586150587150588150589150590150591150592150593150594150595150596150597150598150599150600150601150602150603150604150605150606150607150608150609150610150611150612150613150614150615150616150617150618150619150620150621150622150623150624150625150626150627150628150629150630150631150632150633150634150635150636150637150638150639150640150641150642150643150644150645150646150647150648150649150650150651150652150653150654150655150656150657150658150659150660150661150662150663150664150665150666150667150668150669150670150671150672150673150674150675150676150677150678150679150680150681150682150683150684150685150686150687150688150689150690150691150692150693150694150695150696150697150698150699150700150701150702150703150704150705150706150707150708150709150710150711150712150713150714150715150716150717150718150719150720150721150722150723150724150725150726150727150728150729150730150731150732150733150734150735150736150737150738150739150740150741150742150743150744150745150746150747150748150749150750150751150752150753150754150755150756150757150758150759150760150761150762150763150764150765150766150767150768150769150770150771150772150773150774150775150776150777150778150779150780150781150782150783150784150785150786150787150788150789150790150791150792150793150794150795150796150797150798150799150800150801150802150803150804150805150806150807150808150809150810150811150812150813150814150815150816150817150818150819150820150821150822150823150824150825150826150827150828150829150830150831150832150833150834150835150836150837150838150839150840150841150842150843150844150845150846150847150848150849150850150851150852150853150854150855150856150857150858150859150860150861150862150863150864150865150866150867150868150869150870150871150872150873150874150875150876150877150878150879150880150881150882150883150884150885150886150887150888150889150890150891150892150893150894150895150896150897150898150899150900150901150902150903150904150905150906150907150908150909150910150911150912150913150914150915150916150917150918150919150920150921150922150923150924150925150926150927150928150929150930150931150932150933150934150935150936150937150938150939150940150941150942150943150944150945150946150947150948150949150950150951150952150953150954150955150956150957150958150959150960150961150962150963150964150965150966150967150968150969150970150971150972150973150974150975150976150977150978150979150980150981150982150983150984150985150986150987150988150989150990150991150992150993150994150995150996150997150998150999151000151001151002151003151004151005151006151007151008151009151010151011151012151013151014151015151016151017151018151019151020151021151022151023151024151025151026151027151028151029151030151031151032151033151034151035151036151037151038151039151040151041151042151043151044151045151046151047151048151049151050151051151052151053151054151055151056151057151058151059151060151061151062151063151064151065151066151067151068151069151070151071151072151073151074151075151076151077151078151079151080151081151082151083151084151085151086151087151088151089151090151091151092151093151094151095151096151097151098151099151100151101151102151103151104151105151106151107151108151109151110151111151112151113151114151115151116151117151118151119151120151121151122151123151124151125151126151127151128151129151130151131151132151133151134151135151136151137151138151139151140151141151142151143151144151145151146151147151148151149151150151151151152151153151154151155151156151157151158151159151160151161151162151163151164151165151166151167151168151169151170151171151172151173151174151175151176151177151178151179151180151181151182151183151184151185151186151187151188151189151190151191151192151193151194151195151196151197151198151199151200151201151202151203151204151205151206151207151208151209151210151211151212151213151214151215151216151217151218151219151220151221151222151223151224151225151226151227151228151229151230151231151232151233151234151235151236151237151238151239151240151241151242151243151244151245151246151247151248151249151250151251151252151253151254151255151256151257151258151259151260151261151262151263151264151265151266151267151268151269151270151271151272151273151274151275151276151277151278151279151280151281151282151283151284151285151286151287151288151289151290151291151292151293151294151295151296151297151298151299151300151301151302151303151304151305151306151307151308151309151310151311151312151313151314151315151316151317151318151319151320151321151322151323151324151325151326151327151328151329151330151331151332151333151334151335151336151337151338151339151340151341151342151343151344151345151346151347151348151349151350151351151352151353151354151355151356151357151358151359151360151361151362151363151364151365151366151367151368151369151370151371151372151373151374151375151376151377151378151379151380151381151382151383151384151385151386151387151388151389151390151391151392151393151394151395151396151397151398151399151400151401151402151403151404151405151406151407151408151409151410151411151412151413151414151415151416151417151418151419151420151421151422151423151424151425151426151427151428151429151430151431151432151433151434151435151436151437151438151439151440151441151442151443151444151445151446151447151448151449151450151451151452151453151454151455151456151457151458151459151460151461151462151463151464151465151466151467151468151469151470151471151472151473151474151475151476151477151478151479151480151481151482151483151484151485151486151487151488151489151490151491151492151493151494151495151496151497151498151499151500151501151502151503151504151505151506151507151508151509151510151511151512151513151514151515151516151517151518151519151520151521151522151523151524151525151526151527151528151529151530151531151532151533151534151535151536151537151538151539151540151541151542151543151544151545151546151547151548151549151550151551151552151553151554151555151556151557151558151559151560151561151562151563151564151565151566151567151568151569151570151571151572151573151574151575151576151577151578151579151580151581151582151583151584151585151586151587151588151589151590151591151592151593151594151595151596151597151598151599151600151601151602151603151604151605151606151607151608151609151610151611151612151613151614151615151616151617151618151619151620151621151622151623151624151625151626151627151628151629151630151631151632151633151634151635151636151637151638151639151640151641151642151643151644151645151646151647151648151649151650151651151652151653151654151655151656151657151658151659151660151661151662151663151664151665151666151667151668151669151670151671151672151673151674151675151676151677151678151679151680151681151682151683151684151685151686151687151688151689151690151691151692151693151694151695151696151697151698151699151700151701151702151703151704151705151706151707151708151709151710151711151712151713151714151715151716151717151718151719151720151721151722151723151724151725151726151727151728151729151730151731151732151733151734151735151736151737151738151739151740151741151742151743151744151745151746151747151748151749151750151751151752151753151754151755151756151757151758151759151760151761151762151763151764151765151766151767151768151769151770151771151772151773151774151775151776151777151778151779151780151781151782151783151784151785151786151787151788151789151790151791151792151793151794151795151796151797151798151799151800151801151802151803151804151805151806151807151808151809151810151811151812151813151814151815151816151817151818151819151820151821151822151823151824151825151826151827151828151829151830151831151832151833151834151835151836151837151838151839151840151841151842151843151844151845151846151847151848151849151850151851151852151853151854151855151856151857151858151859151860151861151862151863151864151865151866151867151868151869151870151871151872151873151874151875151876151877151878151879151880151881151882151883151884151885151886151887151888151889151890151891151892151893151894151895151896151897151898151899151900151901151902151903151904151905151906151907151908151909151910151911151912151913151914151915151916151917151918151919151920151921151922151923151924151925151926151927151928151929151930151931151932151933151934151935151936151937151938151939151940151941151942151943151944151945151946151947151948151949151950151951151952151953151954151955151956151957151958151959151960151961151962151963151964151965151966151967151968151969151970151971151972151973151974151975151976151977151978151979151980151981151982151983151984151985151986151987151988151989151990151991151992151993151994151995151996151997151998151999152000152001152002152003152004152005152006152007152008152009152010152011152012152013152014152015152016152017152018152019152020152021152022152023152024152025152026152027152028152029152030152031152032152033152034152035152036152037152038152039152040152041152042152043152044152045152046152047152048152049152050152051152052152053152054152055152056152057152058152059152060152061152062152063152064152065152066152067152068152069152070152071152072152073152074152075152076152077152078152079152080152081152082152083152084152085152086152087152088152089152090152091152092152093152094152095152096152097152098152099152100152101152102152103152104152105152106152107152108152109152110152111152112152113152114152115152116152117152118152119152120152121152122152123152124152125152126152127152128152129152130152131152132152133152134152135152136152137152138152139152140152141152142152143152144152145152146152147152148152149152150152151152152152153152154152155152156152157152158152159152160152161152162152163152164152165152166152167152168152169152170152171152172152173152174152175152176152177152178152179152180152181152182152183152184152185152186152187152188152189152190152191152192152193152194152195152196152197152198152199152200152201152202152203152204152205152206152207152208152209152210152211152212152213152214152215152216152217152218152219152220152221152222152223152224152225152226152227152228152229152230152231152232152233152234152235152236152237152238152239152240152241152242152243152244152245152246152247152248152249152250152251152252152253152254152255152256152257152258152259152260152261152262152263152264152265152266152267152268152269152270152271152272152273152274152275152276152277152278152279152280152281152282152283152284152285152286152287152288152289152290152291152292152293152294152295152296152297152298152299152300152301152302152303152304152305152306152307152308152309152310152311152312152313152314152315152316152317152318152319152320152321152322152323152324152325152326152327152328152329152330152331152332152333152334152335152336152337152338152339152340152341152342152343152344152345152346152347152348152349152350152351152352152353152354152355152356152357152358152359152360152361152362152363152364152365152366152367152368152369152370152371152372152373152374152375152376152377152378152379152380152381152382152383152384152385152386152387152388152389152390152391152392152393152394152395152396152397152398152399152400152401152402152403152404152405152406152407152408152409152410152411152412152413152414152415152416152417152418152419152420152421152422152423152424152425152426152427152428152429152430152431152432152433152434152435152436152437152438152439152440152441152442152443152444152445152446152447152448152449152450152451152452152453152454152455152456152457152458152459152460152461152462152463152464152465152466152467152468152469152470152471152472152473152474152475152476152477152478152479152480152481152482152483152484152485152486152487152488152489152490152491152492152493152494152495152496152497152498152499152500152501152502152503152504152505152506152507152508152509152510152511152512152513152514152515152516152517152518152519152520152521152522152523152524152525152526152527152528152529152530152531152532152533152534152535152536152537152538152539152540152541152542152543152544152545152546152547152548152549152550152551152552152553152554152555152556152557152558152559152560152561152562152563152564152565152566152567152568152569152570152571152572152573152574152575152576152577152578152579152580152581152582152583152584152585152586152587152588152589152590152591152592152593152594152595152596152597152598152599152600152601152602152603152604152605152606152607152608152609152610152611152612152613152614152615152616152617152618152619152620152621152622152623152624152625152626152627152628152629152630152631152632152633152634152635152636152637152638152639152640152641152642152643152644152645152646152647152648152649152650152651152652152653152654152655152656152657152658152659152660152661152662152663152664152665152666152667152668152669152670152671152672152673152674152675152676152677152678152679152680152681152682152683152684152685152686152687152688152689152690152691152692152693152694152695152696152697152698152699152700152701152702152703152704152705152706152707152708152709152710152711152712152713152714152715152716152717152718152719152720152721152722152723152724152725152726152727152728152729152730152731152732152733152734152735152736152737152738152739152740152741152742152743152744152745152746152747152748152749152750152751152752152753152754152755152756152757152758152759152760152761152762152763152764152765152766152767152768152769152770152771152772152773152774152775152776152777152778152779152780152781152782152783152784152785152786152787152788152789152790152791152792152793152794152795152796152797152798152799152800152801152802152803152804152805152806152807152808152809152810152811152812152813152814152815152816152817152818152819152820152821152822152823152824152825152826152827152828152829152830152831152832152833152834152835152836152837152838152839152840152841152842152843152844152845152846152847152848152849152850152851152852152853152854152855152856152857152858152859152860152861152862152863152864152865152866152867152868152869152870152871152872152873152874152875152876152877152878152879152880152881152882152883152884152885152886152887152888152889152890152891152892152893152894152895152896152897152898152899152900152901152902152903152904152905152906152907152908152909152910152911152912152913152914152915152916152917152918152919152920152921152922152923152924152925152926152927152928152929152930152931152932152933152934152935152936152937152938152939152940152941152942152943152944152945152946152947152948152949152950152951152952152953152954152955152956152957152958152959152960152961152962152963152964152965152966152967152968152969152970152971152972152973152974152975152976152977152978152979152980152981152982152983152984152985152986152987152988152989152990152991152992152993152994152995152996152997152998152999153000153001153002153003153004153005153006153007153008153009153010153011153012153013153014153015153016153017153018153019153020153021153022153023153024153025153026153027153028153029153030153031153032153033153034153035153036153037153038153039153040153041153042153043153044153045153046153047153048153049153050153051153052153053153054153055153056153057153058153059153060153061153062153063153064153065153066153067153068153069153070153071153072153073153074153075153076153077153078153079153080153081153082153083153084153085153086153087153088153089153090153091153092153093153094153095153096153097153098153099153100153101153102153103153104153105153106153107153108153109153110153111153112153113153114153115153116153117153118153119153120153121153122153123153124153125153126153127153128153129153130153131153132153133153134153135153136153137153138153139153140153141153142153143153144153145153146153147153148153149153150153151153152153153153154153155153156153157153158153159153160153161153162153163153164153165153166153167153168153169153170153171153172153173153174153175153176153177153178153179153180153181153182153183153184153185153186153187153188153189153190153191153192153193153194153195153196153197153198153199153200153201153202153203153204153205153206153207153208153209153210153211153212153213153214153215153216153217153218153219153220153221153222153223153224153225153226153227153228153229153230153231153232153233153234153235153236153237153238153239153240153241153242153243153244153245153246153247153248153249153250153251153252153253153254153255153256153257153258153259153260153261153262153263153264153265153266153267153268153269153270153271153272153273153274153275153276153277153278153279153280153281153282153283153284153285153286153287153288153289153290153291153292153293153294153295153296153297153298153299153300153301153302153303153304153305153306153307153308153309153310153311153312153313153314153315153316153317153318153319153320153321153322153323153324153325153326153327153328153329153330153331153332153333153334153335153336153337153338153339153340153341153342153343153344153345153346153347153348153349153350153351153352153353153354153355153356153357153358153359153360153361153362153363153364153365153366153367153368153369153370153371153372153373153374153375153376153377153378153379153380153381153382153383153384153385153386153387153388153389153390153391153392153393153394153395153396153397153398153399153400153401153402153403153404153405153406153407153408153409153410153411153412153413153414153415153416153417153418153419153420153421153422153423153424153425153426153427153428153429153430153431153432153433153434153435153436153437153438153439153440153441153442153443153444153445153446153447153448153449153450153451153452153453153454153455153456153457153458153459153460153461153462153463153464153465153466153467153468153469153470153471153472153473153474153475153476153477153478153479153480153481153482153483153484153485153486153487153488153489153490153491153492153493153494153495153496153497153498153499153500153501153502153503153504153505153506153507153508153509153510153511153512153513153514153515153516153517153518153519153520153521153522153523153524153525153526153527153528153529153530153531153532153533153534153535153536153537153538153539153540153541153542153543153544153545153546153547153548153549153550153551153552153553153554153555153556153557153558153559153560153561153562153563153564153565153566153567153568153569153570153571153572153573153574153575153576153577153578153579153580153581153582153583153584153585153586153587153588153589153590153591153592153593153594153595153596153597153598153599153600153601153602153603153604153605153606153607153608153609153610153611153612153613153614153615153616153617153618153619153620153621153622153623153624153625153626153627153628153629153630153631153632153633153634153635153636153637153638153639153640153641153642153643153644153645153646153647153648153649153650153651153652153653153654153655153656153657153658153659153660153661153662153663153664153665153666153667153668153669153670153671153672153673153674153675153676153677153678153679153680153681153682153683153684153685153686153687153688153689153690153691153692153693153694153695153696153697153698153699153700153701153702153703153704153705153706153707153708153709153710153711153712153713153714153715153716153717153718153719153720153721153722153723153724153725153726153727153728153729153730153731153732153733153734153735153736153737153738153739153740153741153742153743153744153745153746153747153748153749153750153751153752153753153754153755153756153757153758153759153760153761153762153763153764153765153766153767153768153769153770153771153772153773153774153775153776153777153778153779153780153781153782153783153784153785153786153787153788153789153790153791153792153793153794153795153796153797153798153799153800153801153802153803153804153805153806153807153808153809153810153811153812153813153814153815153816153817153818153819153820153821153822153823153824153825153826153827153828153829153830153831153832153833153834153835153836153837153838153839153840153841153842153843153844153845153846153847153848153849153850153851153852153853153854153855153856153857153858153859153860153861153862153863153864153865153866153867153868153869153870153871153872153873153874153875153876153877153878153879153880153881153882153883153884153885153886153887153888153889153890153891153892153893153894153895153896153897153898153899153900153901153902153903153904153905153906153907153908153909153910153911153912153913153914153915153916153917153918153919153920153921153922153923153924153925153926153927153928153929153930153931153932153933153934153935153936153937153938153939153940153941153942153943153944153945153946153947153948153949153950153951153952153953153954153955153956153957153958153959153960153961153962153963153964153965153966153967153968153969153970153971153972153973153974153975153976153977153978153979153980153981153982153983153984153985153986153987153988153989153990153991153992153993153994153995153996153997153998153999154000154001154002154003154004154005154006154007154008154009154010154011154012154013154014154015154016154017154018154019154020154021154022154023154024154025154026154027154028154029154030154031154032154033154034154035154036154037154038154039154040154041154042154043154044154045154046154047154048154049154050154051154052154053154054154055154056154057154058154059154060154061154062154063154064154065154066154067154068154069154070154071154072154073154074154075154076154077154078154079154080154081154082154083154084154085154086154087154088154089154090154091154092154093154094154095154096154097154098154099154100154101154102154103154104154105154106154107154108154109154110154111154112154113154114154115154116154117154118154119154120154121154122154123154124154125154126154127154128154129154130154131154132154133154134154135154136154137154138154139154140154141154142154143154144154145154146154147154148154149154150154151154152154153154154154155154156154157154158154159154160154161154162154163154164154165154166154167154168154169154170154171154172154173154174154175154176154177154178154179154180154181154182154183154184154185154186154187154188154189154190154191154192154193154194154195154196154197154198154199154200154201154202154203154204154205154206154207154208154209154210154211154212154213154214154215154216154217154218154219154220154221154222154223154224154225154226154227154228154229154230154231154232154233154234154235154236154237154238154239154240154241154242154243154244154245154246154247154248154249154250154251154252154253154254154255154256154257154258154259154260154261154262154263154264154265154266154267154268154269154270154271154272154273154274154275154276154277154278154279154280154281154282154283154284154285154286154287154288154289154290154291154292154293154294154295154296154297154298154299154300154301154302154303154304154305154306154307154308154309154310154311154312154313154314154315154316154317154318154319154320154321154322154323154324154325154326154327154328154329154330154331154332154333154334154335154336154337154338154339154340154341154342154343154344154345154346154347154348154349154350154351154352154353154354154355154356154357154358154359154360154361154362154363154364154365154366154367154368154369154370154371154372154373154374154375154376154377154378154379154380154381154382154383154384154385154386154387154388154389154390154391154392154393154394154395154396154397154398154399154400154401154402154403154404154405154406154407154408154409154410154411154412154413154414154415154416154417154418154419154420154421154422154423154424154425154426154427154428154429154430154431154432154433154434154435154436154437154438154439154440154441154442154443154444154445154446154447154448154449154450154451154452154453154454154455154456154457154458154459154460154461154462154463154464154465154466154467154468154469154470154471154472154473154474154475154476154477154478154479154480154481154482154483154484154485154486154487154488154489154490154491154492154493154494154495154496154497154498154499154500154501154502154503154504154505154506154507154508154509154510154511154512154513154514154515154516154517154518154519154520154521154522154523154524154525154526154527154528154529154530154531154532154533154534154535154536154537154538154539154540154541154542154543154544154545154546154547154548154549154550154551154552154553154554154555154556154557154558154559154560154561154562154563154564154565154566154567154568154569154570154571154572154573154574154575154576154577154578154579154580154581154582154583154584154585154586154587154588154589154590154591154592154593154594154595154596154597154598154599154600154601154602154603154604154605154606154607154608154609154610154611154612154613154614154615154616154617154618154619154620154621154622154623154624154625154626154627154628154629154630154631154632154633154634154635154636154637154638154639154640154641154642154643154644154645154646154647154648154649154650154651154652154653154654154655154656154657154658154659154660154661154662154663154664154665154666154667154668154669154670154671154672154673154674154675154676154677154678154679154680154681154682154683154684154685154686154687154688154689154690154691154692154693154694154695154696154697154698154699154700154701154702154703154704154705154706154707154708154709154710154711154712154713154714154715154716154717154718154719154720154721154722154723154724154725154726154727154728154729154730154731154732154733154734154735154736154737154738154739154740154741154742154743154744154745154746154747154748154749154750154751154752154753154754154755154756154757154758154759154760154761154762154763154764154765154766154767154768154769154770154771154772154773154774154775154776154777154778154779154780154781154782154783154784154785154786154787154788154789154790154791154792154793154794154795154796154797154798154799154800154801154802154803154804154805154806154807154808154809154810154811154812154813154814154815154816154817154818154819154820154821154822154823154824154825154826154827154828154829154830154831154832154833154834154835154836154837154838154839154840154841154842154843154844154845154846154847154848154849154850154851154852154853154854154855154856154857154858154859154860154861154862154863154864154865154866154867154868154869154870154871154872154873154874154875154876154877154878154879154880154881154882154883154884154885154886154887154888154889154890154891154892154893154894154895154896154897154898154899154900154901154902154903154904154905154906154907154908154909154910154911154912154913154914154915154916154917154918154919154920154921154922154923154924154925154926154927154928154929154930154931154932154933154934154935154936154937154938154939154940154941154942154943154944154945154946154947154948154949154950154951154952154953154954154955154956154957154958154959154960154961154962154963154964154965154966154967154968154969154970154971154972154973154974154975154976154977154978154979154980154981154982154983154984154985154986154987154988154989154990154991154992154993154994154995154996154997154998154999155000155001155002155003155004155005155006155007155008155009155010155011155012155013155014155015155016155017155018155019155020155021155022155023155024155025155026155027155028155029155030155031155032155033155034155035155036155037155038155039155040155041155042155043155044155045155046155047155048155049155050155051155052155053155054155055155056155057155058155059155060155061155062155063155064155065155066155067155068155069155070155071155072155073155074155075155076155077155078155079155080155081155082155083155084155085155086155087155088155089155090155091155092155093155094155095155096155097155098155099155100155101155102155103155104155105155106155107155108155109155110155111155112155113155114155115155116155117155118155119155120155121155122155123155124155125155126155127155128155129155130155131155132155133155134155135155136155137155138155139155140155141155142155143155144155145155146155147155148155149155150155151155152155153155154155155155156155157155158155159155160155161155162155163155164155165155166155167155168155169155170155171155172155173155174155175155176155177155178155179155180155181155182155183155184155185155186155187155188155189155190155191155192155193155194155195155196155197155198155199155200155201155202155203155204155205155206155207155208155209155210155211155212155213155214155215155216155217155218155219155220155221155222155223155224155225155226155227155228155229155230155231155232155233155234155235155236155237155238155239155240155241155242155243155244155245155246155247155248155249155250155251155252155253155254155255155256155257155258155259155260155261155262155263155264155265155266155267155268155269155270155271155272155273155274155275155276155277155278155279155280155281155282155283155284155285155286155287155288155289155290155291155292155293155294155295155296155297155298155299155300155301155302155303155304155305155306155307155308155309155310155311155312155313155314155315155316155317155318155319155320155321155322155323155324155325155326155327155328155329155330155331155332155333155334155335155336155337155338155339155340155341155342155343155344155345155346155347155348155349155350155351155352155353155354155355155356155357155358155359155360155361155362155363155364155365155366155367155368155369155370155371155372155373155374155375155376155377155378155379155380155381155382155383155384155385155386155387155388155389155390155391155392155393155394155395155396155397155398155399155400155401155402155403155404155405155406155407155408155409155410155411155412155413155414155415155416155417155418155419155420155421155422155423155424155425155426155427155428155429155430155431155432155433155434155435155436155437155438155439155440155441155442155443155444155445155446155447155448155449155450155451155452155453155454155455155456155457155458155459155460155461155462155463155464155465155466155467155468155469155470155471155472155473155474155475155476155477155478155479155480155481155482155483155484155485155486155487155488155489155490155491155492155493155494155495155496155497155498155499155500155501155502155503155504155505155506155507155508155509155510155511155512155513155514155515155516155517155518155519155520155521155522155523155524155525155526155527155528155529155530155531155532155533155534155535155536155537155538155539155540155541155542155543155544155545155546155547155548155549155550155551155552155553155554155555155556155557155558155559155560155561155562155563155564155565155566155567155568155569155570155571155572155573155574155575155576155577155578155579155580155581155582155583155584155585155586155587155588155589155590155591155592155593155594155595155596155597155598155599155600155601155602155603155604155605155606155607155608155609155610155611155612155613155614155615155616155617155618155619155620155621155622155623155624155625155626155627155628155629155630155631155632155633155634155635155636155637155638155639155640155641155642155643155644155645155646155647155648155649155650155651155652155653155654155655155656155657155658155659155660155661155662155663155664155665155666155667155668155669155670155671155672155673155674155675155676155677155678155679155680155681155682155683155684155685155686155687155688155689155690155691155692155693155694155695155696155697155698155699155700155701155702155703155704155705155706155707155708155709155710155711155712155713155714155715155716155717155718155719155720155721155722155723155724155725155726155727155728155729155730155731155732155733155734155735155736155737155738155739155740155741155742155743155744155745155746155747155748155749155750155751155752155753155754155755155756155757155758155759155760155761155762155763155764155765155766155767155768155769155770155771155772155773155774155775155776155777155778155779155780155781155782155783155784155785155786155787155788155789155790155791155792155793155794155795155796155797155798155799155800155801155802155803155804155805155806155807155808155809155810155811155812155813155814155815155816155817155818155819155820155821155822155823155824155825155826155827155828155829155830155831155832155833155834155835155836155837155838155839155840155841155842155843155844155845155846155847155848155849155850155851155852155853155854155855155856155857155858155859155860155861155862155863155864155865155866155867155868155869155870155871155872155873155874155875155876155877155878155879155880155881155882155883155884155885155886155887155888155889155890155891155892155893155894155895155896155897155898155899155900155901155902155903155904155905155906155907155908155909155910155911155912155913155914155915155916155917155918155919155920155921155922155923155924155925155926155927155928155929155930155931155932155933155934155935155936155937155938155939155940155941155942155943155944155945155946155947155948155949155950155951155952155953155954155955155956155957155958155959155960155961155962155963155964155965155966155967155968155969155970155971155972155973155974155975155976155977155978155979155980155981155982155983155984155985155986155987155988155989155990155991155992155993155994155995155996155997155998155999156000156001156002156003156004156005156006156007156008156009156010156011156012156013156014156015156016156017156018156019156020156021156022156023156024156025156026156027156028156029156030156031156032156033156034156035156036156037156038156039156040156041156042156043156044156045156046156047156048156049156050156051156052156053156054156055156056156057156058156059156060156061156062156063156064156065156066156067156068156069156070156071156072156073156074156075156076156077156078156079156080156081156082156083156084156085156086156087156088156089156090156091156092156093156094156095156096156097156098156099156100156101156102156103156104156105156106156107156108156109156110156111156112156113156114156115156116156117156118156119156120156121156122156123156124156125156126156127156128156129156130156131156132156133156134156135156136156137156138156139156140156141156142156143156144156145156146156147156148156149156150156151156152156153156154156155156156156157156158156159156160156161156162156163156164156165156166156167156168156169156170156171156172156173156174156175156176156177156178156179156180156181156182156183156184156185156186156187156188156189156190156191156192156193156194156195156196156197156198156199156200156201156202156203156204156205156206156207156208156209156210156211156212156213156214156215156216156217156218156219156220156221156222156223156224156225156226156227156228156229156230156231156232156233156234156235156236156237156238156239156240156241156242156243156244156245156246156247156248156249156250156251156252156253156254156255156256156257156258156259156260156261156262156263156264156265156266156267156268156269156270156271156272156273156274156275156276156277156278156279156280156281156282156283156284156285156286156287156288156289156290156291156292156293156294156295156296156297156298156299156300156301156302156303156304156305156306156307156308156309156310156311156312156313156314156315156316156317156318156319156320156321156322156323156324156325156326156327156328156329156330156331156332156333156334156335156336156337156338156339156340156341156342156343156344156345156346156347156348156349156350156351156352156353156354156355156356156357156358156359156360156361156362156363156364156365156366156367156368156369156370156371156372156373156374156375156376156377156378156379156380156381156382156383156384156385156386156387156388156389156390156391156392156393156394156395156396156397156398156399156400156401156402156403156404156405156406156407156408156409156410156411156412156413156414156415156416156417156418156419156420156421156422156423156424156425156426156427156428156429156430156431156432156433156434156435156436156437156438156439156440156441156442156443156444156445156446156447156448156449156450156451156452156453156454156455156456156457156458156459156460156461156462156463156464156465156466156467156468156469156470156471156472156473156474156475156476156477156478156479156480156481156482156483156484156485156486156487156488156489156490156491156492156493156494156495156496156497156498156499156500156501156502156503156504156505156506156507156508156509156510156511156512156513156514156515156516156517156518156519156520156521156522156523156524156525156526156527156528156529156530156531156532156533156534156535156536156537156538156539156540156541156542156543156544156545156546156547156548156549156550156551156552156553156554156555156556156557156558156559156560156561156562156563156564156565156566156567156568156569156570156571156572156573156574156575156576156577156578156579156580156581156582156583156584156585156586156587156588156589156590156591156592156593156594156595156596156597156598156599156600156601156602156603156604156605156606156607156608156609156610156611156612156613156614156615156616156617156618156619156620156621156622156623156624156625156626156627156628156629156630156631156632156633156634156635156636156637156638156639156640156641156642156643156644156645156646156647156648156649156650156651156652156653156654156655156656156657156658156659156660156661156662156663156664156665156666156667156668156669156670156671156672156673156674156675156676156677156678156679156680156681156682156683156684156685156686156687156688156689156690156691156692156693156694156695156696156697156698156699156700156701156702156703156704156705156706156707156708156709156710156711156712156713156714156715156716156717156718156719156720156721156722156723156724156725156726156727156728156729156730156731156732156733156734156735156736156737156738156739156740156741156742156743156744156745156746156747156748156749156750156751156752156753156754156755156756156757156758156759156760156761156762156763156764156765156766156767156768156769156770156771156772156773156774156775156776156777156778156779156780156781156782156783156784156785156786156787156788156789156790156791156792156793156794156795156796156797156798156799156800156801156802156803156804156805156806156807156808156809156810156811156812156813156814156815156816156817156818156819156820156821156822156823156824156825156826156827156828156829156830156831156832156833156834156835156836156837156838156839156840156841156842156843156844156845156846156847156848156849156850156851156852156853156854156855156856156857156858156859156860156861156862156863156864156865156866156867156868156869156870156871156872156873156874156875156876156877156878156879156880156881156882156883156884156885156886156887156888156889156890156891156892156893156894156895156896156897156898156899156900156901156902156903156904156905156906156907156908156909156910156911156912156913156914156915156916156917156918156919156920156921156922156923156924156925156926156927156928156929156930156931156932156933156934156935156936156937156938156939156940156941156942156943156944156945156946156947156948156949156950156951156952156953156954156955156956156957156958156959156960156961156962156963156964156965156966156967156968156969156970156971156972156973156974156975156976156977156978156979156980156981156982156983156984156985156986156987156988156989156990156991156992156993156994156995156996156997156998156999157000157001157002157003157004157005157006157007157008157009157010157011157012157013157014157015157016157017157018157019157020157021157022157023157024157025157026157027157028157029157030157031157032157033157034157035157036157037157038157039157040157041157042157043157044157045157046157047157048157049157050157051157052157053157054157055157056157057157058157059157060157061157062157063157064157065157066157067157068157069157070157071157072157073157074157075157076157077157078157079157080157081157082157083157084157085157086157087157088157089157090157091157092157093157094157095157096157097157098157099157100157101157102157103157104157105157106157107157108157109157110157111157112157113157114157115157116157117157118157119157120157121157122157123157124157125157126157127157128157129157130157131157132157133157134157135157136157137157138157139157140157141157142157143157144157145157146157147157148157149157150157151157152157153157154157155157156157157157158157159157160157161157162157163157164157165157166157167157168157169157170157171157172157173157174157175157176157177157178157179157180157181157182157183157184157185157186157187157188157189157190157191157192157193157194157195157196157197157198157199157200157201157202157203157204157205157206157207157208157209157210157211157212157213157214157215157216157217157218157219157220157221157222157223157224157225157226157227157228157229157230157231157232157233157234157235157236157237157238157239157240157241157242157243157244157245157246157247157248157249157250157251157252157253157254157255157256157257157258157259157260157261157262157263157264157265157266157267157268157269157270157271157272157273157274157275157276157277157278157279157280157281157282157283157284157285157286157287157288157289157290157291157292157293157294157295157296157297157298157299157300157301157302157303157304157305157306157307157308157309157310157311157312157313157314157315157316157317157318157319157320157321157322157323157324157325157326157327157328157329157330157331157332157333157334157335157336157337157338157339157340157341157342157343157344157345157346157347157348157349157350157351157352157353157354157355157356157357157358157359157360157361157362157363157364157365157366157367157368157369157370157371157372157373157374157375157376157377157378157379157380157381157382157383157384157385157386157387157388157389157390157391157392157393157394157395157396157397157398157399157400157401157402157403157404157405157406157407157408157409157410157411157412157413157414157415157416157417157418157419157420157421157422157423157424157425157426157427157428157429157430157431157432157433157434157435157436157437157438157439157440157441157442157443157444157445157446157447157448157449157450157451157452157453157454157455157456157457157458157459157460157461157462157463157464157465157466157467157468157469157470157471157472157473157474157475157476157477157478157479157480157481157482157483157484157485157486157487157488157489157490157491157492157493157494157495157496157497157498157499157500157501157502157503157504157505157506157507157508157509157510157511157512157513157514157515157516157517157518157519157520157521157522157523157524157525157526157527157528157529157530157531157532157533157534157535157536157537157538157539157540157541157542157543157544157545157546157547157548157549157550157551157552157553157554157555157556157557157558157559157560157561157562157563157564157565157566157567157568157569157570157571157572157573157574157575157576157577157578157579157580157581157582157583157584157585157586157587157588157589157590157591157592157593157594157595157596157597157598157599157600157601157602157603157604157605157606157607157608157609157610157611157612157613157614157615157616157617157618157619157620157621157622157623157624157625157626157627157628157629157630157631157632157633157634157635157636157637157638157639157640157641157642157643157644157645157646157647157648157649157650157651157652157653157654157655157656157657157658157659157660157661157662157663157664157665157666157667157668157669157670157671157672157673157674157675157676157677157678157679157680157681157682157683157684157685157686157687157688157689157690157691157692157693157694157695157696157697157698157699157700157701157702157703157704157705157706157707157708157709157710157711157712157713157714157715157716157717157718157719157720157721157722157723157724157725157726157727157728157729157730157731157732157733157734157735157736157737157738157739157740157741157742157743157744157745157746157747157748157749157750157751157752157753157754157755157756157757157758157759157760157761157762157763157764157765157766157767157768157769157770157771157772157773157774157775157776157777157778157779157780157781157782157783157784157785157786157787157788157789157790157791157792157793157794157795157796157797157798157799157800157801157802157803157804157805157806157807157808157809157810157811157812157813157814157815157816157817157818157819157820157821157822157823157824157825157826157827157828157829157830157831157832157833157834157835157836157837157838157839157840157841157842157843157844157845157846157847157848157849157850157851157852157853157854157855157856157857157858157859157860157861157862157863157864157865157866157867157868157869157870157871157872157873157874157875157876157877157878157879157880157881157882157883157884157885157886157887157888157889157890157891157892157893157894157895157896157897157898157899157900157901157902157903157904157905157906157907157908157909157910157911157912157913157914157915157916157917157918157919157920157921157922157923157924157925157926157927157928157929157930157931157932157933157934157935157936157937157938157939157940157941157942157943157944157945157946157947157948157949157950157951157952157953157954157955157956157957157958157959157960157961157962157963157964157965157966157967157968157969157970157971157972157973157974157975157976157977157978157979157980157981157982157983157984157985157986157987157988157989157990157991157992157993157994157995157996157997157998157999158000158001158002158003158004158005158006158007158008158009158010158011158012158013158014158015158016158017158018158019158020158021158022158023158024158025158026158027158028158029158030158031158032158033158034158035158036158037158038158039158040158041158042158043158044158045158046158047158048158049158050158051158052158053158054158055158056158057158058158059158060158061158062158063158064158065158066158067158068158069158070158071158072158073158074158075158076158077158078158079158080158081158082158083158084158085158086158087158088158089158090158091158092158093158094158095158096158097158098158099158100158101158102158103158104158105158106158107158108158109158110158111158112158113158114158115158116158117158118158119158120158121158122158123158124158125158126158127158128158129158130158131158132158133158134158135158136158137158138158139158140158141158142158143158144158145158146158147158148158149158150158151158152158153158154158155158156158157158158158159158160158161158162158163158164158165158166158167158168158169158170158171158172158173158174158175158176158177158178158179158180158181158182158183158184158185158186158187158188158189158190158191158192158193158194158195158196158197158198158199158200158201158202158203158204158205158206158207158208158209158210158211158212158213158214158215158216158217158218158219158220158221158222158223158224158225158226158227158228158229158230158231158232158233158234158235158236158237158238158239158240158241158242158243158244158245158246158247158248158249158250158251158252158253158254158255158256158257158258158259158260158261158262158263158264158265158266158267158268158269158270158271158272158273158274158275158276158277158278158279158280158281158282158283158284158285158286158287158288158289158290158291158292158293158294158295158296158297158298158299158300158301158302158303158304158305158306158307158308158309158310158311158312158313158314158315158316158317158318158319158320158321158322158323158324158325158326158327158328158329158330158331158332158333158334158335158336158337158338158339158340158341158342158343158344158345158346158347158348158349158350158351158352158353158354158355158356158357158358158359158360158361158362158363158364158365158366158367158368158369158370158371158372158373158374158375158376158377158378158379158380158381158382158383158384158385158386158387158388158389158390158391158392158393158394158395158396158397158398158399158400158401158402158403158404158405158406158407158408158409158410158411158412158413158414158415158416158417158418158419158420158421158422158423158424158425158426158427158428158429158430158431158432158433158434158435158436158437158438158439158440158441158442158443158444158445158446158447158448158449158450158451158452158453158454158455158456158457158458158459158460158461158462158463158464158465158466158467158468158469158470158471158472158473158474158475158476158477158478158479158480158481158482158483158484158485158486158487158488158489158490158491158492158493158494158495158496158497158498158499158500158501158502158503158504158505158506158507158508158509158510158511158512158513158514158515158516158517158518158519158520158521158522158523158524158525158526158527158528158529158530158531158532158533158534158535158536158537158538158539158540158541158542158543158544158545158546158547158548158549158550158551158552158553158554158555158556158557158558158559158560158561158562158563158564158565158566158567158568158569158570158571158572158573158574158575158576158577158578158579158580158581158582158583158584158585158586158587158588158589158590158591158592158593158594158595158596158597158598158599158600158601158602158603158604158605158606158607158608158609158610158611158612158613158614158615158616158617158618158619158620158621158622158623158624158625158626158627158628158629158630158631158632158633158634158635158636158637158638158639158640158641158642158643158644158645158646158647158648158649158650158651158652158653158654158655158656158657158658158659158660158661158662158663158664158665158666158667158668158669158670158671158672158673158674158675158676158677158678158679158680158681158682158683158684158685158686158687158688158689158690158691158692158693158694158695158696158697158698158699158700158701158702158703158704158705158706158707158708158709158710158711158712158713158714158715158716158717158718158719158720158721158722158723158724158725158726158727158728158729158730158731158732158733158734158735158736158737158738158739158740158741158742158743158744158745158746158747158748158749158750158751158752158753158754158755158756158757158758158759158760158761158762158763158764158765158766158767158768158769158770158771158772158773158774158775158776158777158778158779158780158781158782158783158784158785158786158787158788158789158790158791158792158793158794158795158796158797158798158799158800158801158802158803158804158805158806158807158808158809158810158811158812158813158814158815158816158817158818158819158820158821158822158823158824158825158826158827158828158829158830158831158832158833158834158835158836158837158838158839158840158841158842158843158844158845158846158847158848158849158850158851158852158853158854158855158856158857158858158859158860158861158862158863158864158865158866158867158868158869158870158871158872158873158874158875158876158877158878158879158880158881158882158883158884158885158886158887158888158889158890158891158892158893158894158895158896158897158898158899158900158901158902158903158904158905158906158907158908158909158910158911158912158913158914158915158916158917158918158919158920158921158922158923158924158925158926158927158928158929158930158931158932158933158934158935158936158937158938158939158940158941158942158943158944158945158946158947158948158949158950158951158952158953158954158955158956158957158958158959158960158961158962158963158964158965158966158967158968158969158970158971158972158973158974158975158976158977158978158979158980158981158982158983158984158985158986158987158988158989158990158991158992158993158994158995158996158997158998158999159000159001159002159003159004159005159006159007159008159009159010159011159012159013159014159015159016159017159018159019159020159021159022159023159024159025159026159027159028159029159030159031159032159033159034159035159036159037159038159039159040159041159042159043159044159045159046159047159048159049159050159051159052159053159054159055159056159057159058159059159060159061159062159063159064159065159066159067159068159069159070159071159072159073159074159075159076159077159078159079159080159081159082159083159084159085159086159087159088159089159090159091159092159093159094159095159096159097159098159099159100159101159102159103159104159105159106159107159108159109159110159111159112159113159114159115159116159117159118159119159120159121159122159123159124159125159126159127159128159129159130159131159132159133159134159135159136159137159138159139159140159141159142159143159144159145159146159147159148159149159150159151159152159153159154159155159156159157159158159159159160159161159162159163159164159165159166159167159168159169159170159171159172159173159174159175159176159177159178159179159180159181159182159183159184159185159186159187159188159189159190159191159192159193159194159195159196159197159198159199159200159201159202159203159204159205159206159207159208159209159210159211159212159213159214159215159216159217159218159219159220159221159222159223159224159225159226159227159228159229159230159231159232159233159234159235159236159237159238159239159240159241159242159243159244159245159246159247159248159249159250159251159252159253159254159255159256159257159258159259159260159261159262159263159264159265159266159267159268159269159270159271159272159273159274159275159276159277159278159279159280159281159282159283159284159285159286159287159288159289159290159291159292159293159294159295159296159297159298159299159300159301159302159303159304159305159306159307159308159309159310159311159312159313159314159315159316159317159318159319159320159321159322159323159324159325159326159327159328159329159330159331159332159333159334159335159336159337159338159339159340159341159342159343159344159345159346159347159348159349159350159351159352159353159354159355159356159357159358159359159360159361159362159363159364159365159366159367159368159369159370159371159372159373159374159375159376159377159378159379159380159381159382159383159384159385159386159387159388159389159390159391159392159393159394159395159396159397159398159399159400159401159402159403159404159405159406159407159408159409159410159411159412159413159414159415159416159417159418159419159420159421159422159423159424159425159426159427159428159429159430159431159432159433159434159435159436159437159438159439159440159441159442159443159444159445159446159447159448159449159450159451159452159453159454159455159456159457159458159459159460159461159462159463159464159465159466159467159468159469159470159471159472159473159474159475159476159477159478159479159480159481159482159483159484159485159486159487159488159489159490159491159492159493159494159495159496159497159498159499159500159501159502159503159504159505159506159507159508159509159510159511159512159513159514159515159516159517159518159519159520159521159522159523159524159525159526159527159528159529159530159531159532159533159534159535159536159537159538159539159540159541159542159543159544159545159546159547159548159549159550159551159552159553159554159555159556159557159558159559159560159561159562159563159564159565159566159567159568159569159570159571159572159573159574159575159576159577159578159579159580159581159582159583159584159585159586159587159588159589159590159591159592159593159594159595159596159597159598159599159600159601159602159603159604159605159606159607159608159609159610159611159612159613159614159615159616159617159618159619159620159621159622159623159624159625159626159627159628159629159630159631159632159633159634159635159636159637159638159639159640159641159642159643159644159645159646159647159648159649159650159651159652159653159654159655159656159657159658159659159660159661159662159663159664159665159666159667159668159669159670159671159672159673159674159675159676159677159678159679159680159681159682159683159684159685159686159687159688159689159690159691159692159693159694159695159696159697159698159699159700159701159702159703159704159705159706159707159708159709159710159711159712159713159714159715159716159717159718159719159720159721159722159723159724159725159726159727159728159729159730159731159732159733159734159735159736159737159738159739159740159741159742159743159744159745159746159747159748159749159750159751159752159753159754159755159756159757159758159759159760159761159762159763159764159765159766159767159768159769159770159771159772159773159774159775159776159777159778159779159780159781159782159783159784159785159786159787159788159789159790159791159792159793159794159795159796159797159798159799159800159801159802159803159804159805159806159807159808159809159810159811159812159813159814159815159816159817159818159819159820159821159822159823159824159825159826159827159828159829159830159831159832159833159834159835159836159837159838159839159840159841159842159843159844159845159846159847159848159849159850159851159852159853159854159855159856159857159858159859159860159861159862159863159864159865159866159867159868159869159870159871159872159873159874159875159876159877159878159879159880159881159882159883159884159885159886159887159888159889159890159891159892159893159894159895159896159897159898159899159900159901159902159903159904159905159906159907159908159909159910159911159912159913159914159915159916159917159918159919159920159921159922159923159924159925159926159927159928159929159930159931159932159933159934159935159936159937159938159939159940159941159942159943159944159945159946159947159948159949159950159951159952159953159954159955159956159957159958159959159960159961159962159963159964159965159966159967159968159969159970159971159972159973159974159975159976159977159978159979159980159981159982159983159984159985159986159987159988159989159990159991159992159993159994159995159996159997159998159999160000160001160002160003160004160005160006160007160008160009160010160011160012160013160014160015160016160017160018160019160020160021160022160023160024160025160026160027160028160029160030160031160032160033160034160035160036160037160038160039160040160041160042160043160044160045160046160047160048160049160050160051160052160053160054160055160056160057160058160059160060160061160062160063160064160065160066160067160068160069160070160071160072160073160074160075160076160077160078160079160080160081160082160083160084160085160086160087160088160089160090160091160092160093160094160095160096160097160098160099160100160101160102160103160104160105160106160107160108160109160110160111160112160113160114160115160116160117160118160119160120160121160122160123160124160125160126160127160128160129160130160131160132160133160134160135160136160137160138160139160140160141160142160143160144160145160146160147160148160149160150160151160152160153160154160155160156160157160158160159160160160161160162160163160164160165160166160167160168160169160170160171160172160173160174160175160176160177160178160179160180160181160182160183160184160185160186160187160188160189160190160191160192160193160194160195160196160197160198160199160200160201160202160203160204160205160206160207160208160209160210160211160212160213160214160215160216160217160218160219160220160221160222160223160224160225160226160227160228160229160230160231160232160233160234160235160236160237160238160239160240160241160242160243160244160245160246160247160248160249160250160251160252160253160254160255160256160257160258160259160260160261160262160263160264160265160266160267160268160269160270160271160272160273160274160275160276160277160278160279160280160281160282160283160284160285160286160287160288160289160290160291160292160293160294160295160296160297160298160299160300160301160302160303160304160305160306160307160308160309160310160311160312160313160314160315160316160317160318160319160320160321160322160323160324160325160326160327160328160329160330160331160332160333160334160335160336160337160338160339160340160341160342160343160344160345160346160347160348160349160350160351160352160353160354160355160356160357160358160359160360160361160362160363160364160365160366160367160368160369160370160371160372160373160374160375160376160377160378160379160380160381160382160383160384160385160386160387160388160389160390160391160392160393160394160395160396160397160398160399160400160401160402160403160404160405160406160407160408160409160410160411160412160413160414160415160416160417160418160419160420160421160422160423160424160425160426160427160428160429160430160431160432160433160434160435160436160437160438160439160440160441160442160443160444160445160446160447160448160449160450160451160452160453160454160455160456160457160458160459160460160461160462160463160464160465160466160467160468160469160470160471160472160473160474160475160476160477160478160479160480160481160482160483160484160485160486160487160488160489160490160491160492160493160494160495160496160497160498160499160500160501160502160503160504160505160506160507160508160509160510160511160512160513160514160515160516160517160518160519160520160521160522160523160524160525160526160527160528160529160530160531160532160533160534160535160536160537160538160539160540160541160542160543160544160545160546160547160548160549160550160551160552160553160554160555160556160557160558160559160560160561160562160563160564160565160566160567160568160569160570160571160572160573160574160575160576160577160578160579160580160581160582160583160584160585160586160587160588160589160590160591160592160593160594160595160596160597160598160599160600160601160602160603160604160605160606160607160608160609160610160611160612160613160614160615160616160617160618160619160620160621160622160623160624160625160626160627160628160629160630160631160632160633160634160635160636160637160638160639160640160641160642160643160644160645160646160647160648160649160650160651160652160653160654160655160656160657160658160659160660160661160662160663160664160665160666160667160668160669160670160671160672160673160674160675160676160677160678160679160680160681160682160683160684160685160686160687160688160689160690160691160692160693160694160695160696160697160698160699160700160701160702160703160704160705160706160707160708160709160710160711160712160713160714160715160716160717160718160719160720160721160722160723160724160725160726160727160728160729160730160731160732160733160734160735160736160737160738160739160740160741160742160743160744160745160746160747160748160749160750160751160752160753160754160755160756160757160758160759160760160761160762160763160764160765160766160767160768160769160770160771160772160773160774160775160776160777160778160779160780160781160782160783160784160785160786160787160788160789160790160791160792160793160794160795160796160797160798160799160800160801160802160803160804160805160806160807160808160809160810160811160812160813160814160815160816160817160818160819160820160821160822160823160824160825160826160827160828160829160830160831160832160833160834160835160836160837160838160839160840160841160842160843160844160845160846160847160848160849160850160851160852160853160854160855160856160857160858160859160860160861160862160863160864160865160866160867160868160869160870160871160872160873160874160875160876160877160878160879160880160881160882160883160884160885160886160887160888160889160890160891160892160893160894160895160896160897160898160899160900160901160902160903160904160905160906160907160908160909160910160911160912160913160914160915160916160917160918160919160920160921160922160923160924160925160926160927160928160929160930160931160932160933160934160935160936160937160938160939160940160941160942160943160944160945160946160947160948160949160950160951160952160953160954160955160956160957160958160959160960160961160962160963160964160965160966160967160968160969160970160971160972160973160974160975160976160977160978160979160980160981160982160983160984160985160986160987160988160989160990160991160992160993160994160995160996160997160998160999161000161001161002161003161004161005161006161007161008161009161010161011161012161013161014161015161016161017161018161019161020161021161022161023161024161025161026161027161028161029161030161031161032161033161034161035161036161037161038161039161040161041161042161043161044161045161046161047161048161049161050161051161052161053161054161055161056161057161058161059161060161061161062161063161064161065161066161067161068161069161070161071161072161073161074161075161076161077161078161079161080161081161082161083161084161085161086161087161088161089161090161091161092161093161094161095161096161097161098161099161100161101161102161103161104161105161106161107161108161109161110161111161112161113161114161115161116161117161118161119161120161121161122161123161124161125161126161127161128161129161130161131161132161133161134161135161136161137161138161139161140161141161142161143161144161145161146161147161148161149161150161151161152161153161154161155161156161157161158161159161160161161161162161163161164161165161166161167161168161169161170161171161172161173161174161175161176161177161178161179161180161181161182161183161184161185161186161187161188161189161190161191161192161193161194161195161196161197161198161199161200161201161202161203161204161205161206161207161208161209161210161211161212161213161214161215161216161217161218161219161220161221161222161223161224161225161226161227161228161229161230161231161232161233161234161235161236161237161238161239161240161241161242161243161244161245161246161247161248161249161250161251161252161253161254161255161256161257161258161259161260161261161262161263161264161265161266161267161268161269161270161271161272161273161274161275161276161277161278161279161280161281161282161283161284161285161286161287161288161289161290161291161292161293161294161295161296161297161298161299161300161301161302161303161304161305161306161307161308161309161310161311161312161313161314161315161316161317161318161319161320161321161322161323161324161325161326161327161328161329161330161331161332161333161334161335161336161337161338161339161340161341161342161343161344161345161346161347161348161349161350161351161352161353161354161355161356161357161358161359161360161361161362161363161364161365161366161367161368161369161370161371161372161373161374161375161376161377161378161379161380161381161382161383161384161385161386161387161388161389161390161391161392161393161394161395161396161397161398161399161400161401161402161403161404161405161406161407161408161409161410161411161412161413161414161415161416161417161418161419161420161421161422161423161424161425161426161427161428161429161430161431161432161433161434161435161436161437161438161439161440161441161442161443161444161445161446161447161448161449161450161451161452161453161454161455161456161457161458161459161460161461161462161463161464161465161466161467161468161469161470161471161472161473161474161475161476161477161478161479161480161481161482161483161484161485161486161487161488161489161490161491161492161493161494161495161496161497161498161499161500161501161502161503161504161505161506161507161508161509161510161511161512161513161514161515161516161517161518161519161520161521161522161523161524161525161526161527161528161529161530161531161532161533161534161535161536161537161538161539161540161541161542161543161544161545161546161547161548161549161550161551161552161553161554161555161556161557161558161559161560161561161562161563161564161565161566161567161568161569161570161571161572161573161574161575161576161577161578161579161580161581161582161583161584161585161586161587161588161589161590161591161592161593161594161595161596161597161598161599161600161601161602161603161604161605161606161607161608161609161610161611161612161613161614161615161616161617161618161619161620161621161622161623161624161625161626161627161628161629161630161631161632161633161634161635161636161637161638161639161640161641161642161643161644161645161646161647161648161649161650161651161652161653161654161655161656161657161658161659161660161661161662161663161664161665161666161667161668161669161670161671161672161673161674161675161676161677161678161679161680161681161682161683161684161685161686161687161688161689161690161691161692161693161694161695161696161697161698161699161700161701161702161703161704161705161706161707161708161709161710161711161712161713161714161715161716161717161718161719161720161721161722161723161724161725161726161727161728161729161730161731161732161733161734161735161736161737161738161739161740161741161742161743161744161745161746161747161748161749161750161751161752161753161754161755161756161757161758161759161760161761161762161763161764161765161766161767161768161769161770161771161772161773161774161775161776161777161778161779161780161781161782161783161784161785161786161787161788161789161790161791161792161793161794161795161796161797161798161799161800161801161802161803161804161805161806161807161808161809161810161811161812161813161814161815161816161817161818161819161820161821161822161823161824161825161826161827161828161829161830161831161832161833161834161835161836161837161838161839161840161841161842161843161844161845161846161847161848161849161850161851161852161853161854161855161856161857161858161859161860161861161862161863161864161865161866161867161868161869161870161871161872161873161874161875161876161877161878161879161880161881161882161883161884161885161886161887161888161889161890161891161892161893161894161895161896161897161898161899161900161901161902161903161904161905161906161907161908161909161910161911161912161913161914161915161916161917161918161919161920161921161922161923161924161925161926161927161928161929161930161931161932161933161934161935161936161937161938161939161940161941161942161943161944161945161946161947161948161949161950161951161952161953161954161955161956161957161958161959161960161961161962161963161964161965161966161967161968161969161970161971161972161973161974161975161976161977161978161979161980161981161982161983161984161985161986161987161988161989161990161991161992161993161994161995161996161997161998161999162000162001162002162003162004162005162006162007162008162009162010162011162012162013162014162015162016162017162018162019162020162021162022162023162024162025162026162027162028162029162030162031162032162033162034162035162036162037162038162039162040162041162042162043162044162045162046162047162048162049162050162051162052162053162054162055162056162057162058162059162060162061162062162063162064162065162066162067162068162069162070162071162072162073162074162075162076162077162078162079162080162081162082162083162084162085162086162087162088162089162090162091162092162093162094162095162096162097162098162099162100162101162102162103162104162105162106162107162108162109162110162111162112162113162114162115162116162117162118162119162120162121162122162123162124162125162126162127162128162129162130162131162132162133162134162135162136162137162138162139162140162141162142162143162144162145162146162147162148162149162150162151162152162153162154162155162156162157162158162159162160162161162162162163162164162165162166162167162168162169162170162171162172162173162174162175162176162177162178162179162180162181162182162183162184162185162186162187162188162189162190162191162192162193162194162195162196162197162198162199162200162201162202162203162204162205162206162207162208162209162210162211162212162213162214162215162216162217162218162219162220162221162222162223162224162225162226162227162228162229162230162231162232162233162234162235162236162237162238162239162240162241162242162243162244162245162246162247162248162249162250162251162252162253162254162255162256162257162258162259162260162261162262162263162264162265162266162267162268162269162270162271162272162273162274162275162276162277162278162279162280162281162282162283162284162285162286162287162288162289162290162291162292162293162294162295162296162297162298162299162300162301162302162303162304162305162306162307162308162309162310162311162312162313162314162315162316162317162318162319162320162321162322162323162324162325162326162327162328162329162330162331162332162333162334162335162336162337162338162339162340162341162342162343162344162345162346162347162348162349162350162351162352162353162354162355162356162357162358162359162360162361162362162363162364162365162366162367162368162369162370162371162372162373162374162375162376162377162378162379162380162381162382162383162384162385162386162387162388162389162390162391162392162393162394162395162396162397162398162399162400162401162402162403162404162405162406162407162408162409162410162411162412162413162414162415162416162417162418162419162420162421162422162423162424162425162426162427162428162429162430162431162432162433162434162435162436162437162438162439162440162441162442162443162444162445162446162447162448162449162450162451162452162453162454162455162456162457162458162459162460162461162462162463162464162465162466162467162468162469162470162471162472162473162474162475162476162477162478162479162480162481162482162483162484162485162486162487162488162489162490162491162492162493162494162495162496162497162498162499162500162501162502162503162504162505162506162507162508162509162510162511162512162513162514162515162516162517162518162519162520162521162522162523162524162525162526162527162528162529162530162531162532162533162534162535162536162537162538162539162540162541162542162543162544162545162546162547162548162549162550162551162552162553162554162555162556162557162558162559162560162561162562162563162564162565162566162567162568162569162570162571162572162573162574162575162576162577162578162579162580162581162582162583162584162585162586162587162588162589162590162591162592162593162594162595162596162597162598162599162600162601162602162603162604162605162606162607162608162609162610162611162612162613162614162615162616162617162618162619162620162621162622162623162624162625162626162627162628162629162630162631162632162633162634162635162636162637162638162639162640162641162642162643162644162645162646162647162648162649162650162651162652162653162654162655162656162657162658162659162660162661162662162663162664162665162666162667162668162669162670162671162672162673162674162675162676162677162678162679162680162681162682162683162684162685162686162687162688162689162690162691162692162693162694162695162696162697162698162699162700162701162702162703162704162705162706162707162708162709162710162711162712162713162714162715162716162717162718162719162720162721162722162723162724162725162726162727162728162729162730162731162732162733162734162735162736162737162738162739162740162741162742162743162744162745162746162747162748162749162750162751162752162753162754162755162756162757162758162759162760162761162762162763162764162765162766162767162768162769162770162771162772162773162774162775162776162777162778162779162780162781162782162783162784162785162786162787162788162789162790162791162792162793162794162795162796162797162798162799162800162801162802162803162804162805162806162807162808162809162810162811162812162813162814162815162816162817162818162819162820162821162822162823162824162825162826162827162828162829162830162831162832162833162834162835162836162837162838162839162840162841162842162843162844162845162846162847162848162849162850162851162852162853162854162855162856162857162858162859162860162861162862162863162864162865162866162867162868162869162870162871162872162873162874162875162876162877162878162879162880162881162882162883162884162885162886162887162888162889162890162891162892162893162894162895162896162897162898162899162900162901162902162903162904162905162906162907162908162909162910162911162912162913162914162915162916162917162918162919162920162921162922162923162924162925162926162927162928162929162930162931162932162933162934162935162936162937162938162939162940162941162942162943162944162945162946162947162948162949162950162951162952162953162954162955162956162957162958162959162960162961162962162963162964162965162966162967162968162969162970162971162972162973162974162975162976162977162978162979162980162981162982162983162984162985162986162987162988162989162990162991162992162993162994162995162996162997162998162999163000163001163002163003163004163005163006163007163008163009163010163011163012163013163014163015163016163017163018163019163020163021163022163023163024163025163026163027163028163029163030163031163032163033163034163035163036163037163038163039163040163041163042163043163044163045163046163047163048163049163050163051163052163053163054163055163056163057163058163059163060163061163062163063163064163065163066163067163068163069163070163071163072163073163074163075163076163077163078163079163080163081163082163083163084163085163086163087163088163089163090163091163092163093163094163095163096163097163098163099163100163101163102163103163104163105163106163107163108163109163110163111163112163113163114163115163116163117163118163119163120163121163122163123163124163125163126163127163128163129163130163131163132163133163134163135163136163137163138163139163140163141163142163143163144163145163146163147163148163149163150163151163152163153163154163155163156163157163158163159163160163161163162163163163164163165163166163167163168163169163170163171163172163173163174163175163176163177163178163179163180163181163182163183163184163185163186163187163188163189163190163191163192163193163194163195163196163197163198163199163200163201163202163203163204163205163206163207163208163209163210163211163212163213163214163215163216163217163218163219163220163221163222163223163224163225163226163227163228163229163230163231163232163233163234163235163236163237163238163239163240163241163242163243163244163245163246163247163248163249163250163251163252163253163254163255163256163257163258163259163260163261163262163263163264163265163266163267163268163269163270163271163272163273163274163275163276163277163278163279163280163281163282163283163284163285163286163287163288163289163290163291163292163293163294163295163296163297163298163299163300163301163302163303163304163305163306163307163308163309163310163311163312163313163314163315163316163317163318163319163320163321163322163323163324163325163326163327163328163329163330163331163332163333163334163335163336163337163338163339163340163341163342163343163344163345163346163347163348163349163350163351163352163353163354163355163356163357163358163359163360163361163362163363163364163365163366163367163368163369163370163371163372163373163374163375163376163377163378163379163380163381163382163383163384163385163386163387163388163389163390163391163392163393163394163395163396163397163398163399163400163401163402163403163404163405163406163407163408163409163410163411163412163413163414163415163416163417163418163419163420163421163422163423163424163425163426163427163428163429163430163431163432163433163434163435163436163437163438163439163440163441163442163443163444163445163446163447163448163449163450163451163452163453163454163455163456163457163458163459163460163461163462163463163464163465163466163467163468163469163470163471163472163473163474163475163476163477163478163479163480163481163482163483163484163485163486163487163488163489163490163491163492163493163494163495163496163497163498163499163500163501163502163503163504163505163506163507163508163509163510163511163512163513163514163515163516163517163518163519163520163521163522163523163524163525163526163527163528163529163530163531163532163533163534163535163536163537163538163539163540163541163542163543163544163545163546163547163548163549163550163551163552163553163554163555163556163557163558163559163560163561163562163563163564163565163566163567163568163569163570163571163572163573163574163575163576163577163578163579163580163581163582163583163584163585163586163587163588163589163590163591163592163593163594163595163596163597163598163599163600163601163602163603163604163605163606163607163608163609163610163611163612163613163614163615163616163617163618163619163620163621163622163623163624163625163626163627163628163629163630163631163632163633163634163635163636163637163638163639163640163641163642163643163644163645163646163647163648163649163650163651163652163653163654163655163656163657163658163659163660163661163662163663163664163665163666163667163668163669163670163671163672163673163674163675163676163677163678163679163680163681163682163683163684163685163686163687163688163689163690163691163692163693163694163695163696163697163698163699163700163701163702163703163704163705163706163707163708163709163710163711163712163713163714163715163716163717163718163719163720163721163722163723163724163725163726163727163728163729163730163731163732163733163734163735163736163737163738163739163740163741163742163743163744163745163746163747163748163749163750163751163752163753163754163755163756163757163758163759163760163761163762163763163764163765163766163767163768163769163770163771163772163773163774163775163776163777163778163779163780163781163782163783163784163785163786163787163788163789163790163791163792163793163794163795163796163797163798163799163800163801163802163803163804163805163806163807163808163809163810163811163812163813163814163815163816163817163818163819163820163821163822163823163824163825163826163827163828163829163830163831163832163833163834163835163836163837163838163839163840163841163842163843163844163845163846163847163848163849163850163851163852163853163854163855163856163857163858163859163860163861163862163863163864163865163866163867163868163869163870163871163872163873163874163875163876163877163878163879163880163881163882163883163884163885163886163887163888163889163890163891163892163893163894163895163896163897163898163899163900163901163902163903163904163905163906163907163908163909163910163911163912163913163914163915163916163917163918163919163920163921163922163923163924163925163926163927163928163929163930163931163932163933163934163935163936163937163938163939163940163941163942163943163944163945163946163947163948163949163950163951163952163953163954163955163956163957163958163959163960163961163962163963163964163965163966163967163968163969163970163971163972163973163974163975163976163977163978163979163980163981163982163983163984163985163986163987163988163989163990163991163992163993163994163995163996163997163998163999164000164001164002164003164004164005164006164007164008164009164010164011164012164013164014164015164016164017164018164019164020164021164022164023164024164025164026164027164028164029164030164031164032164033164034164035164036164037164038164039164040164041164042164043164044164045164046164047164048164049164050164051164052164053164054164055164056164057164058164059164060164061164062164063164064164065164066164067164068164069164070164071164072164073164074164075164076164077164078164079164080164081164082164083164084164085164086164087164088164089164090164091164092164093164094164095164096164097164098164099164100164101164102164103164104164105164106164107164108164109164110164111164112164113164114164115164116164117164118164119164120164121164122164123164124164125164126164127164128164129164130164131164132164133164134164135164136164137164138164139164140164141164142164143164144164145164146164147164148164149164150164151164152164153164154164155164156164157164158164159164160164161164162164163164164164165164166164167164168164169164170164171164172164173164174164175164176164177164178164179164180164181164182164183164184164185164186164187164188164189164190164191164192164193164194164195164196164197164198164199164200164201164202164203164204164205164206164207164208164209164210164211164212164213164214164215164216164217164218164219164220164221164222164223164224164225164226164227164228164229164230164231164232164233164234164235164236164237164238164239164240164241164242164243164244164245164246164247164248164249164250164251164252164253164254164255164256164257164258164259164260164261164262164263164264164265164266164267164268164269164270164271164272164273164274164275164276164277164278164279164280164281164282164283164284164285164286164287164288164289164290164291164292164293164294164295164296164297164298164299164300164301164302164303164304164305164306164307164308164309164310164311164312164313164314164315164316164317164318164319164320164321164322164323164324164325164326164327164328164329164330164331164332164333164334164335164336164337164338164339164340164341164342164343164344164345164346164347164348164349164350164351164352164353164354164355164356164357164358164359164360164361164362164363164364164365164366164367164368164369164370164371164372164373164374164375164376164377164378164379164380164381164382164383164384164385164386164387164388164389164390164391164392164393164394164395164396164397164398164399164400164401164402164403164404164405164406164407164408164409164410164411164412164413164414164415164416164417164418164419164420164421164422164423164424164425164426164427164428164429164430164431164432164433164434164435164436164437164438164439164440164441164442164443164444164445164446164447164448164449164450164451164452164453164454164455164456164457164458164459164460164461164462164463164464164465164466164467164468164469164470164471164472164473164474164475164476164477164478164479164480164481164482164483164484164485164486164487164488164489164490164491164492164493164494164495164496164497164498164499164500164501164502164503164504164505164506164507164508164509164510164511164512164513164514164515164516164517164518164519164520164521164522164523164524164525164526164527164528164529164530164531164532164533164534164535164536164537164538164539164540164541164542164543164544164545164546164547164548164549164550164551164552164553164554164555164556164557164558164559164560164561164562164563164564164565164566164567164568164569164570164571164572164573164574164575164576164577164578164579164580164581164582164583164584164585164586164587164588164589164590164591164592164593164594164595164596164597164598164599164600164601164602164603164604164605164606164607164608164609164610164611164612164613164614164615164616164617164618164619164620164621164622164623164624164625164626164627164628164629164630164631164632164633164634164635164636164637164638164639164640164641164642164643164644164645164646164647164648164649164650164651164652164653164654164655164656164657164658164659164660164661164662164663164664164665164666164667164668164669164670164671164672164673164674164675164676164677164678164679164680164681164682164683164684164685164686164687164688164689164690164691164692164693164694164695164696164697164698164699164700164701164702164703164704164705164706164707164708164709164710164711164712164713164714164715164716164717164718164719164720164721164722164723164724164725164726164727164728164729164730164731164732164733164734164735164736164737164738164739164740164741164742164743164744164745164746164747164748164749164750164751164752164753164754164755164756164757164758164759164760164761164762164763164764164765164766164767164768164769164770164771164772164773164774164775164776164777164778164779164780164781164782164783164784164785164786164787164788164789164790164791164792164793164794164795164796164797164798164799164800164801164802164803164804164805164806164807164808164809164810164811164812164813164814164815164816164817164818164819164820164821164822164823164824164825164826164827164828164829164830164831164832164833164834164835164836164837164838164839164840164841164842164843164844164845164846164847164848164849164850164851164852164853164854164855164856164857164858164859164860164861164862164863164864164865164866164867164868164869164870164871164872164873164874164875164876164877164878164879164880164881164882164883164884164885164886164887164888164889164890164891164892164893164894164895164896164897164898164899164900164901164902164903164904164905164906164907164908164909164910164911164912164913164914164915164916164917164918164919164920164921164922164923164924164925164926164927164928164929164930164931164932164933164934164935164936164937164938164939164940164941164942164943164944164945164946164947164948164949164950164951164952164953164954164955164956164957164958164959164960164961164962164963164964164965164966164967164968164969164970164971164972164973164974164975164976164977164978164979164980164981164982164983164984164985164986164987164988164989164990164991164992164993164994164995164996164997164998164999165000165001165002165003165004165005165006165007165008165009165010165011165012165013165014165015165016165017165018165019165020165021165022165023165024165025165026165027165028165029165030165031165032165033165034165035165036165037165038165039165040165041165042165043165044165045165046165047165048165049165050165051165052165053165054165055165056165057165058165059165060165061165062165063165064165065165066165067165068165069165070165071165072165073165074165075165076165077165078165079165080165081165082165083165084165085165086165087165088165089165090165091165092165093165094165095165096165097165098165099165100165101165102165103165104165105165106165107165108165109165110165111165112165113165114165115165116165117165118165119165120165121165122165123165124165125165126165127165128165129165130165131165132165133165134165135165136165137165138165139165140165141165142165143165144165145165146165147165148165149165150165151165152165153165154165155165156165157165158165159165160165161165162165163165164165165165166165167165168165169165170165171165172165173165174165175165176165177165178165179165180165181165182165183165184165185165186165187165188165189165190165191165192165193165194165195165196165197165198165199165200165201165202165203165204165205165206165207165208165209165210165211165212165213165214165215165216165217165218165219165220165221165222165223165224165225165226165227165228165229165230165231165232165233165234165235165236165237165238165239165240165241165242165243165244165245165246165247165248165249165250165251165252165253165254165255165256165257165258165259165260165261165262165263165264165265165266165267165268165269165270165271165272165273165274165275165276165277165278165279165280165281165282165283165284165285165286165287165288165289165290165291165292165293165294165295165296165297165298165299165300165301165302165303165304165305165306165307165308165309165310165311165312165313165314165315165316165317165318165319165320165321165322165323165324165325165326165327165328165329165330165331165332165333165334165335165336165337165338165339165340165341165342165343165344165345165346165347165348165349165350165351165352165353165354165355165356165357165358165359165360165361165362165363165364165365165366165367165368165369165370165371165372165373165374165375165376165377165378165379165380165381165382165383165384165385165386165387165388165389165390165391165392165393165394165395165396165397165398165399165400165401165402165403165404165405165406165407165408165409165410165411165412165413165414165415165416165417165418165419165420165421165422165423165424165425165426165427165428165429165430165431165432165433165434165435165436165437165438165439165440165441165442165443165444165445165446165447165448165449165450165451165452165453165454165455165456165457165458165459165460165461165462165463165464165465165466165467165468165469165470165471165472165473165474165475165476165477165478165479165480165481165482165483165484165485165486165487165488165489165490165491165492165493165494165495165496165497165498165499165500165501165502165503165504165505165506165507165508165509165510165511165512165513165514165515165516165517165518165519165520165521165522165523165524165525165526165527165528165529165530165531165532165533165534165535165536165537165538165539165540165541165542165543165544165545165546165547165548165549165550165551165552165553165554165555165556165557165558165559165560165561165562165563165564165565165566165567165568165569165570165571165572165573165574165575165576165577165578165579165580165581165582165583165584165585165586165587165588165589165590165591165592165593165594165595165596165597165598165599165600165601165602165603165604165605165606165607165608165609165610165611165612165613165614165615165616165617165618165619165620165621165622165623165624165625165626165627165628165629165630165631165632165633165634165635165636165637165638165639165640165641165642165643165644165645165646165647165648165649165650165651165652165653165654165655165656165657165658165659165660165661165662165663165664165665165666165667165668165669165670165671165672165673165674165675165676165677165678165679165680165681165682165683165684165685165686165687165688165689165690165691165692165693165694165695165696165697165698165699165700165701165702165703165704165705165706165707165708165709165710165711165712165713165714165715165716165717165718165719165720165721165722165723165724165725165726165727165728165729165730165731165732165733165734165735165736165737165738165739165740165741165742165743165744165745165746165747165748165749165750165751165752165753165754165755165756165757165758165759165760165761165762165763165764165765165766165767165768165769165770165771165772165773165774165775165776165777165778165779165780165781165782165783165784165785165786165787165788165789165790165791165792165793165794165795165796165797165798165799165800165801165802165803165804165805165806165807165808165809165810165811165812165813165814165815165816165817165818165819165820165821165822165823165824165825165826165827165828165829165830165831165832165833165834165835165836165837165838165839165840165841165842165843165844165845165846165847165848165849165850165851165852165853165854165855165856165857165858165859165860165861165862165863165864165865165866165867165868165869165870165871165872165873165874165875165876165877165878165879165880165881165882165883165884165885165886165887165888165889165890165891165892165893165894165895165896165897165898165899165900165901165902165903165904165905165906165907165908165909165910165911165912165913165914165915165916165917165918165919165920165921165922165923165924165925165926165927165928165929165930165931165932165933165934165935165936165937165938165939165940165941165942165943165944165945165946165947165948165949165950165951165952165953165954165955165956165957165958165959165960165961165962165963165964165965165966165967165968165969165970165971165972165973165974165975165976165977165978165979165980165981165982165983165984165985165986165987165988165989165990165991165992165993165994165995165996165997165998165999166000166001166002166003166004166005166006166007166008166009166010166011166012166013166014166015166016166017166018166019166020166021166022166023166024166025166026166027166028166029166030166031166032166033166034166035166036166037166038166039166040166041166042166043166044166045166046166047166048166049166050166051166052166053166054166055166056166057166058166059166060166061166062166063166064166065166066166067166068166069166070166071166072166073166074166075166076166077166078166079166080166081166082166083166084166085166086166087166088166089166090166091166092166093166094166095166096166097166098166099166100166101166102166103166104166105166106166107166108166109166110166111166112166113166114166115166116166117166118166119166120166121166122166123166124166125166126166127166128166129166130166131166132166133166134166135166136166137166138166139166140166141166142166143166144166145166146166147166148166149166150166151166152166153166154166155166156166157166158166159166160166161166162166163166164166165166166166167166168166169166170166171166172166173166174166175166176166177166178166179166180166181166182166183166184166185166186166187166188166189166190166191166192166193166194166195166196166197166198166199166200166201166202166203166204166205166206166207166208166209166210166211166212166213166214166215166216166217166218166219166220166221166222166223166224166225166226166227166228166229166230166231166232166233166234166235166236166237166238166239166240166241166242166243166244166245166246166247166248166249166250166251166252166253166254166255166256166257166258166259166260166261166262166263166264166265166266166267166268166269166270166271166272166273166274166275166276166277166278166279166280166281166282166283166284166285166286166287166288166289166290166291166292166293166294166295166296166297166298166299166300166301166302166303166304166305166306166307166308166309166310166311166312166313166314166315166316166317166318166319166320166321166322166323166324166325166326166327166328166329166330166331166332166333166334166335166336166337166338166339166340166341166342166343166344166345166346166347166348166349166350166351166352166353166354166355166356166357166358166359166360166361166362166363166364166365166366166367166368166369166370166371166372166373166374166375166376166377166378166379166380166381166382166383166384166385166386166387166388166389166390166391166392166393166394166395166396166397166398166399166400166401166402166403166404166405166406166407166408166409166410166411166412166413166414166415166416166417166418166419166420166421166422166423166424166425166426166427166428166429166430166431166432166433166434166435166436166437166438166439166440166441166442166443166444166445166446166447166448166449166450166451166452166453166454166455166456166457166458166459166460166461166462166463166464166465166466166467166468166469166470166471166472166473166474166475166476166477166478166479166480166481166482166483166484166485166486166487166488166489166490166491166492166493166494166495166496166497166498166499166500166501166502166503166504166505166506166507166508166509166510166511166512166513166514166515166516166517166518166519166520166521166522166523166524166525166526166527166528166529166530166531166532166533166534166535166536166537166538166539166540166541166542166543166544166545166546166547166548166549166550166551166552166553166554166555166556166557166558166559166560166561166562166563166564166565166566166567166568166569166570166571166572166573166574166575166576166577166578166579166580166581166582166583166584166585166586166587166588166589166590166591166592166593166594166595166596166597166598166599166600166601166602166603166604166605166606166607166608166609166610166611166612166613166614166615166616166617166618166619166620166621166622166623166624166625166626166627166628166629166630166631166632166633166634166635166636166637166638166639166640166641166642166643166644166645166646166647166648166649166650166651166652166653166654166655166656166657166658166659166660166661166662166663166664166665166666166667166668166669166670166671166672166673166674166675166676166677166678166679166680166681166682166683166684166685166686166687166688166689166690166691166692166693166694166695166696166697166698166699166700166701166702166703166704166705166706166707166708166709166710166711166712166713166714166715166716166717166718166719166720166721166722166723166724166725166726166727166728166729166730166731166732166733166734166735166736166737166738166739166740166741166742166743166744166745166746166747166748166749166750166751166752166753166754166755166756166757166758166759166760166761166762166763166764166765166766166767166768166769166770166771166772166773166774166775166776166777166778166779166780166781166782166783166784166785166786166787166788166789166790166791166792166793166794166795166796166797166798166799166800166801166802166803166804166805166806166807166808166809166810166811166812166813166814166815166816166817166818166819166820166821166822166823166824166825166826166827166828166829166830166831166832166833166834166835166836166837166838166839166840166841166842166843166844166845166846166847166848166849166850166851166852166853166854166855166856166857166858166859166860166861166862166863166864166865166866166867166868166869166870166871166872166873166874166875166876166877166878166879166880166881166882166883166884166885166886166887166888166889166890166891166892166893166894166895166896166897166898166899166900166901166902166903166904166905166906166907166908166909166910166911166912166913166914166915166916166917166918166919166920166921166922166923166924166925166926166927166928166929166930166931166932166933166934166935166936166937166938166939166940166941166942166943166944166945166946166947166948166949166950166951166952166953166954166955166956166957166958166959166960166961166962166963166964166965166966166967166968166969166970166971166972166973166974166975166976166977166978166979166980166981166982166983166984166985166986166987166988166989166990166991166992166993166994166995166996166997166998166999167000167001167002167003167004167005167006167007167008167009167010167011167012167013167014167015167016167017167018167019167020167021167022167023167024167025167026167027167028167029167030167031167032167033167034167035167036167037167038167039167040167041167042167043167044167045167046167047167048167049167050167051167052167053167054167055167056167057167058167059167060167061167062167063167064167065167066167067167068167069167070167071167072167073167074167075167076167077167078167079167080167081167082167083167084167085167086167087167088167089167090167091167092167093167094167095167096167097167098167099167100167101167102167103167104167105167106167107167108167109167110167111167112167113167114167115167116167117167118167119167120167121167122167123167124167125167126167127167128167129167130167131167132167133167134167135167136167137167138167139167140167141167142167143167144167145167146167147167148167149167150167151167152167153167154167155167156167157167158167159167160167161167162167163167164167165167166167167167168167169167170167171167172167173167174167175167176167177167178167179167180167181167182167183167184167185167186167187167188167189167190167191167192167193167194167195167196167197167198167199167200167201167202167203167204167205167206167207167208167209167210167211167212167213167214167215167216167217167218167219167220167221167222167223167224167225167226167227167228167229167230167231167232167233167234167235167236167237167238167239167240167241167242167243167244167245167246167247167248167249167250167251167252167253167254167255167256167257167258167259167260167261167262167263167264167265167266167267167268167269167270167271167272167273167274167275167276167277167278167279167280167281167282167283167284167285167286167287167288167289167290167291167292167293167294167295167296167297167298167299167300167301167302167303167304167305167306167307167308167309167310167311167312167313167314167315167316167317167318167319167320167321167322167323167324167325167326167327167328167329167330167331167332167333167334167335167336167337167338167339167340167341167342167343167344167345167346167347167348167349167350167351167352167353167354167355167356167357167358167359167360167361167362167363167364167365167366167367167368167369167370167371167372167373167374167375167376167377167378167379167380167381167382167383167384167385167386167387167388167389167390167391167392167393167394167395167396167397167398167399167400167401167402167403167404167405167406167407167408167409167410167411167412167413167414167415167416167417167418167419167420167421167422167423167424167425167426167427167428167429167430167431167432167433167434167435167436167437167438167439167440167441167442167443167444167445167446167447167448167449167450167451167452167453167454167455167456167457167458167459167460167461167462167463167464167465167466167467167468167469167470167471167472167473167474167475167476167477167478167479167480167481167482167483167484167485167486167487167488167489167490167491167492167493167494167495167496167497167498167499167500167501167502167503167504167505167506167507167508167509167510167511167512167513167514167515167516167517167518167519167520167521167522167523167524167525167526167527167528167529167530167531167532167533167534167535167536167537167538167539167540167541167542167543167544167545167546167547167548167549167550167551167552167553167554167555167556167557167558167559167560167561167562167563167564167565167566167567167568167569167570167571167572167573167574167575167576167577167578167579167580167581167582167583167584167585167586167587167588167589167590167591167592167593167594167595167596167597167598167599167600167601167602167603167604167605167606167607167608167609167610167611167612167613167614167615167616167617167618167619167620167621167622167623167624167625167626167627167628167629167630167631167632167633167634167635167636167637167638167639167640167641167642167643167644167645167646167647167648167649167650167651167652167653167654167655167656167657167658167659167660167661167662167663167664167665167666167667167668167669167670167671167672167673167674167675167676167677167678167679167680167681167682167683167684167685167686167687167688167689167690167691167692167693167694167695167696167697167698167699167700167701167702167703167704167705167706167707167708167709167710167711167712167713167714167715167716167717167718167719167720167721167722167723167724167725167726167727167728167729167730167731167732167733167734167735167736167737167738167739167740167741167742167743167744167745167746167747167748167749167750167751167752167753167754167755167756167757167758167759167760167761167762167763167764167765167766167767167768167769167770167771167772167773167774167775167776167777167778167779167780167781167782167783167784167785167786167787167788167789167790167791167792167793167794167795167796167797167798167799167800167801167802167803167804167805167806167807167808167809167810167811167812167813167814167815167816167817167818167819167820167821167822167823167824167825167826167827167828167829167830167831167832167833167834167835167836167837167838167839167840167841167842167843167844167845167846167847167848167849167850167851167852167853167854167855167856167857167858167859167860167861167862167863167864167865167866167867167868167869167870167871167872167873167874167875167876167877167878167879167880167881167882167883167884167885167886167887167888167889167890167891167892167893167894167895167896167897167898167899167900167901167902167903167904167905167906167907167908167909167910167911167912167913167914167915167916167917167918167919167920167921167922167923167924167925167926167927167928167929167930167931167932167933167934167935167936167937167938167939167940167941167942167943167944167945167946167947167948167949167950167951167952167953167954167955167956167957167958167959167960167961167962167963167964167965167966167967167968167969167970167971167972167973167974167975167976167977167978167979167980167981167982167983167984167985167986167987167988167989167990167991167992167993167994167995167996167997167998167999168000168001168002168003168004168005168006168007168008168009168010168011168012168013168014168015168016168017168018168019168020168021168022168023168024168025168026168027168028168029168030168031168032168033168034168035168036168037168038168039168040168041168042168043168044168045168046168047168048168049168050168051168052168053168054168055168056168057168058168059168060168061168062168063168064168065168066168067168068168069168070168071168072168073168074168075168076168077168078168079168080168081168082168083168084168085168086168087168088168089168090168091168092168093168094168095168096168097168098168099168100168101168102168103168104168105168106168107168108168109168110168111168112168113168114168115168116168117168118168119168120168121168122168123168124168125168126168127168128168129168130168131168132168133168134168135168136168137168138168139168140168141168142168143168144168145168146168147168148168149168150168151168152168153168154168155168156168157168158168159168160168161168162168163168164168165168166168167168168168169168170168171168172168173168174168175168176168177168178168179168180168181168182168183168184168185168186168187168188168189168190168191168192168193168194168195168196168197168198168199168200168201168202168203168204168205168206168207168208168209168210168211168212168213168214168215168216168217168218168219168220168221168222168223168224168225168226168227168228168229168230168231168232168233168234168235168236168237168238168239168240168241168242168243168244168245168246168247168248168249168250168251168252168253168254168255168256168257168258168259168260168261168262168263168264168265168266168267168268168269168270168271168272168273168274168275168276168277168278168279168280168281168282168283168284168285168286168287168288168289168290168291168292168293168294168295168296168297168298168299168300168301168302168303168304168305168306168307168308168309168310168311168312168313168314168315168316168317168318168319168320168321168322168323168324168325168326168327168328168329168330168331168332168333168334168335168336168337168338168339168340168341168342168343168344168345168346168347168348168349168350168351168352168353168354168355168356168357168358168359168360168361168362168363168364168365168366168367168368168369168370168371168372168373168374168375168376168377168378168379168380168381168382168383168384168385168386168387168388168389168390168391168392168393168394168395168396168397168398168399168400168401168402168403168404168405168406168407168408168409168410168411168412168413168414168415168416168417168418168419168420168421168422168423168424168425168426168427168428168429168430168431168432168433168434168435168436168437168438168439168440168441168442168443168444168445168446168447168448168449168450168451168452168453168454168455168456168457168458168459168460168461168462168463168464168465168466168467168468168469168470168471168472168473168474168475168476168477168478168479168480168481168482168483168484168485168486168487168488168489168490168491168492168493168494168495168496168497168498168499168500168501168502168503168504168505168506168507168508168509168510168511168512168513168514168515168516168517168518168519168520168521168522168523168524168525168526168527168528168529168530168531168532168533168534168535168536168537168538168539168540168541168542168543168544168545168546168547168548168549168550168551168552168553168554168555168556168557168558168559168560168561168562168563168564168565168566168567168568168569168570168571168572168573168574168575168576168577168578168579168580168581168582168583168584168585168586168587168588168589168590168591168592168593168594168595168596168597168598168599168600168601168602168603168604168605168606168607168608168609168610168611168612168613168614168615168616168617168618168619168620168621168622168623168624168625168626168627168628168629168630168631168632168633168634168635168636168637168638168639168640168641168642168643168644168645168646168647168648168649168650168651168652168653168654168655168656168657168658168659168660168661168662168663168664168665168666168667168668168669168670168671168672168673168674168675168676168677168678168679168680168681168682168683168684168685168686168687168688168689168690168691168692168693168694168695168696168697168698168699168700168701168702168703168704168705168706168707168708168709168710168711168712168713168714168715168716168717168718168719168720168721168722168723168724168725168726168727168728168729168730168731168732168733168734168735168736168737168738168739168740168741168742168743168744168745168746168747168748168749168750168751168752168753168754168755168756168757168758168759168760168761168762168763168764168765168766168767168768168769168770168771168772168773168774168775168776168777168778168779168780168781168782168783168784168785168786168787168788168789168790168791168792168793168794168795168796168797168798168799168800168801168802168803168804168805168806168807168808168809168810168811168812168813168814168815168816168817168818168819168820168821168822168823168824168825168826168827168828168829168830168831168832168833168834168835168836168837168838168839168840168841168842168843168844168845168846168847168848168849168850168851168852168853168854168855168856168857168858168859168860168861168862168863168864168865168866168867168868168869168870168871168872168873168874168875168876168877168878168879168880168881168882168883168884168885168886168887168888168889168890168891168892168893168894168895168896168897168898168899168900168901168902168903168904168905168906168907168908168909168910168911168912168913168914168915168916168917168918168919168920168921168922168923168924168925168926168927168928168929168930168931168932168933168934168935168936168937168938168939168940168941168942168943168944168945168946168947168948168949168950168951168952168953168954168955168956168957168958168959168960168961168962168963168964168965168966168967168968168969168970168971168972168973168974168975168976168977168978168979168980168981168982168983168984168985168986168987168988168989168990168991168992168993168994168995168996168997168998168999169000169001169002169003169004169005169006169007169008169009169010169011169012169013169014169015169016169017169018169019169020169021169022169023169024169025169026169027169028169029169030169031169032169033169034169035169036169037169038169039169040169041169042169043169044169045169046169047169048169049169050169051169052169053169054169055169056169057169058169059169060169061169062169063169064169065169066169067169068169069169070169071169072169073169074169075169076169077169078169079169080169081169082169083169084169085169086169087169088169089169090169091169092169093169094169095169096169097169098169099169100169101169102169103169104169105169106169107169108169109169110169111169112169113169114169115169116169117169118169119169120169121169122169123169124169125169126169127169128169129169130169131169132169133169134169135169136169137169138169139169140169141169142169143169144169145169146169147169148169149169150169151169152169153169154169155169156169157169158169159169160169161169162169163169164169165169166169167169168169169169170169171169172169173169174169175169176169177169178169179169180169181169182169183169184169185169186169187169188169189169190169191169192169193169194169195169196169197169198169199169200169201169202169203169204169205169206169207169208169209169210169211169212169213169214169215169216169217169218169219169220169221169222169223169224169225169226169227169228169229169230169231169232169233169234169235169236169237169238169239169240169241169242169243169244169245169246169247169248169249169250169251169252169253169254169255169256169257169258169259169260169261169262169263169264169265169266169267169268169269169270169271169272169273169274169275169276169277169278169279169280169281169282169283169284169285169286169287169288169289169290169291169292169293169294169295169296169297169298169299169300169301169302169303169304169305169306169307169308169309169310169311169312169313169314169315169316169317169318169319169320169321169322169323169324169325169326169327169328169329169330169331169332169333169334169335169336169337169338169339169340169341169342169343169344169345169346169347169348169349169350169351169352169353169354169355169356169357169358169359169360169361169362169363169364169365169366169367169368169369169370169371169372169373169374169375169376169377169378169379169380169381169382169383169384169385169386169387169388169389169390169391169392169393169394169395169396169397169398169399169400169401169402169403169404169405169406169407169408169409169410169411169412169413169414169415169416169417169418169419169420169421169422169423169424169425169426169427169428169429169430169431169432169433169434169435169436169437169438169439169440169441169442169443169444169445169446169447169448169449169450169451169452169453169454169455169456169457169458169459169460169461169462169463169464169465169466169467169468169469169470169471169472169473169474169475169476169477169478169479169480169481169482169483169484169485169486169487169488169489169490169491169492169493169494169495169496169497169498169499169500169501169502169503169504169505169506169507169508169509169510169511169512169513169514169515169516169517169518169519169520169521169522169523169524169525169526169527169528169529169530169531169532169533169534169535169536169537169538169539169540169541169542169543169544169545169546169547169548169549169550169551169552169553169554169555169556169557169558169559169560169561169562169563169564169565169566169567169568169569169570169571169572169573169574169575169576169577169578169579169580169581169582169583169584169585169586169587169588169589169590169591169592169593169594169595169596169597169598169599169600169601169602169603169604169605169606169607169608169609169610169611169612169613169614169615169616169617169618169619169620169621169622169623169624169625169626169627169628169629169630169631169632169633169634169635169636169637169638169639169640169641169642169643169644169645169646169647169648169649169650169651169652169653169654169655169656169657169658169659169660169661169662169663169664169665169666169667169668169669169670169671169672169673169674169675169676169677169678169679169680169681169682169683169684169685169686169687169688169689169690169691169692169693169694169695169696169697169698169699169700169701169702169703169704169705169706169707169708169709169710169711169712169713169714169715169716169717169718169719169720169721169722169723169724169725169726169727169728169729169730169731169732169733169734169735169736169737169738169739169740169741169742169743169744169745169746169747169748169749169750169751169752169753169754169755169756169757169758169759169760169761169762169763169764169765169766169767169768169769169770169771169772169773169774169775169776169777169778169779169780169781169782169783169784169785169786169787169788169789169790169791169792169793169794169795169796169797169798169799169800169801169802169803169804169805169806169807169808169809169810169811169812169813169814169815169816169817169818169819169820169821169822169823169824169825169826169827169828169829169830169831169832169833169834169835169836169837169838169839169840169841169842169843169844169845169846169847169848169849169850169851169852169853169854169855169856169857169858169859169860169861169862169863169864169865169866169867169868169869169870169871169872169873169874169875169876169877169878169879169880169881169882169883169884169885169886169887169888169889169890169891169892169893169894169895169896169897169898169899169900169901169902169903169904169905169906169907169908169909169910169911169912169913169914169915169916169917169918169919169920169921169922169923169924169925169926169927169928169929169930169931169932169933169934169935169936169937169938169939169940169941169942169943169944169945169946169947169948169949169950169951169952169953169954169955169956169957169958169959169960169961169962169963169964169965169966169967169968169969169970169971169972169973169974169975169976169977169978169979169980169981169982169983169984169985169986169987169988169989169990169991169992169993169994169995169996169997169998169999170000170001170002170003170004170005170006170007170008170009170010170011170012170013170014170015170016170017170018170019170020170021170022170023170024170025170026170027170028170029170030170031170032170033170034170035170036170037170038170039170040170041170042170043170044170045170046170047170048170049170050170051170052170053170054170055170056170057170058170059170060170061170062170063170064170065170066170067170068170069170070170071170072170073170074170075170076170077170078170079170080170081170082170083170084170085170086170087170088170089170090170091170092170093170094170095170096170097170098170099170100170101170102170103170104170105170106170107170108170109170110170111170112170113170114170115170116170117170118170119170120170121170122170123170124170125170126170127170128170129170130170131170132170133170134170135170136170137170138170139170140170141170142170143170144170145170146170147170148170149170150170151170152170153170154170155170156170157170158170159170160170161170162170163170164170165170166170167170168170169170170170171170172170173170174170175170176170177170178170179170180170181170182170183170184170185170186170187170188170189170190170191170192170193170194170195170196170197170198170199170200170201170202170203170204170205170206170207170208170209170210170211170212170213170214170215170216170217170218170219170220170221170222170223170224170225170226170227170228170229170230170231170232170233170234170235170236170237170238170239170240170241170242170243170244170245170246170247170248170249170250170251170252170253170254170255170256170257170258170259170260170261170262170263170264170265170266170267170268170269170270170271170272170273170274170275170276170277170278170279170280170281170282170283170284170285170286170287170288170289170290170291170292170293170294170295170296170297170298170299170300170301170302170303170304170305170306170307170308170309170310170311170312170313170314170315170316170317170318170319170320170321170322170323170324170325170326170327170328170329170330170331170332170333170334170335170336170337170338170339170340170341170342170343170344170345170346170347170348170349170350170351170352170353170354170355170356170357170358170359170360170361170362170363170364170365170366170367170368170369170370170371170372170373170374170375170376170377170378170379170380170381170382170383170384170385170386170387170388170389170390170391170392170393170394170395170396170397170398170399170400170401170402170403170404170405170406170407170408170409170410170411170412170413170414170415170416170417170418170419170420170421170422170423170424170425170426170427170428170429170430170431170432170433170434170435170436170437170438170439170440170441170442170443170444170445170446170447170448170449170450170451170452170453170454170455170456170457170458170459170460170461170462170463170464170465170466170467170468170469170470170471170472170473170474170475170476170477170478170479170480170481170482170483170484170485170486170487170488170489170490170491170492170493170494170495170496170497170498170499170500170501170502170503170504170505170506170507170508170509170510170511170512170513170514170515170516170517170518170519170520170521170522170523170524170525170526170527170528170529170530170531170532170533170534170535170536170537170538170539170540170541170542170543170544170545170546170547170548170549170550170551170552170553170554170555170556170557170558170559170560170561170562170563170564170565170566170567170568170569170570170571170572170573170574170575170576170577170578170579170580170581170582170583170584170585170586170587170588170589170590170591170592170593170594170595170596170597170598170599170600170601170602170603170604170605170606170607170608170609170610170611170612170613170614170615170616170617170618170619170620170621170622170623170624170625170626170627170628170629170630170631170632170633170634170635170636170637170638170639170640170641170642170643170644170645170646170647170648170649170650170651170652170653170654170655170656170657170658170659170660170661170662170663170664170665170666170667170668170669170670170671170672170673170674170675170676170677170678170679170680170681170682170683170684170685170686170687170688170689170690170691170692170693170694170695170696170697170698170699170700170701170702170703170704170705170706170707170708170709170710170711170712170713170714170715170716170717170718170719170720170721170722170723170724170725170726170727170728170729170730170731170732170733170734170735170736170737170738170739170740170741170742170743170744170745170746170747170748170749170750170751170752170753170754170755170756170757170758170759170760170761170762170763170764170765170766170767170768170769170770170771170772170773170774170775170776170777170778170779170780170781170782170783170784170785170786170787170788170789170790170791170792170793170794170795170796170797170798170799170800170801170802170803170804170805170806170807170808170809170810170811170812170813170814170815170816170817170818170819170820170821170822170823170824170825170826170827170828170829170830170831170832170833170834170835170836170837170838170839170840170841170842170843170844170845170846170847170848170849170850170851170852170853170854170855170856170857170858170859170860170861170862170863170864170865170866170867170868170869170870170871170872170873170874170875170876170877170878170879170880170881170882170883170884170885170886170887170888170889170890170891170892170893170894170895170896170897170898170899170900170901170902170903170904170905170906170907170908170909170910170911170912170913170914170915170916170917170918170919170920170921170922170923170924170925170926170927170928170929170930170931170932170933170934170935170936170937170938170939170940170941170942170943170944170945170946170947170948170949170950170951170952170953170954170955170956170957170958170959170960170961170962170963170964170965170966170967170968170969170970170971170972170973170974170975170976170977170978170979170980170981170982170983170984170985170986170987170988170989170990170991170992170993170994170995170996170997170998170999171000171001171002171003171004171005171006171007171008171009171010171011171012171013171014171015171016171017171018171019171020171021171022171023171024171025171026171027171028171029171030171031171032171033171034171035171036171037171038171039171040171041171042171043171044171045171046171047171048171049171050171051171052171053171054171055171056171057171058171059171060171061171062171063171064171065171066171067171068171069171070171071171072171073171074171075171076171077171078171079171080171081171082171083171084171085171086171087171088171089171090171091171092171093171094171095171096171097171098171099171100171101171102171103171104171105171106171107171108171109171110171111171112171113171114171115171116171117171118171119171120171121171122171123171124171125171126171127171128171129171130171131171132171133171134171135171136171137171138171139171140171141171142171143171144171145171146171147171148171149171150171151171152171153171154171155171156171157171158171159171160171161171162171163171164171165171166171167171168171169171170171171171172171173171174171175171176171177171178171179171180171181171182171183171184171185171186171187171188171189171190171191171192171193171194171195171196171197171198171199171200171201171202171203171204171205171206171207171208171209171210171211171212171213171214171215171216171217171218171219171220171221171222171223171224171225171226171227171228171229171230171231171232171233171234171235171236171237171238171239171240171241171242171243171244171245171246171247171248171249171250171251171252171253171254171255171256171257171258171259171260171261171262171263171264171265171266171267171268171269171270171271171272171273171274171275171276171277171278171279171280171281171282171283171284171285171286171287171288171289171290171291171292171293171294171295171296171297171298171299171300171301171302171303171304171305171306171307171308171309171310171311171312171313171314171315171316171317171318171319171320171321171322171323171324171325171326171327171328171329171330171331171332171333171334171335171336171337171338171339171340171341171342171343171344171345171346171347171348171349171350171351171352171353171354171355171356171357171358171359171360171361171362171363171364171365171366171367171368171369171370171371171372171373171374171375171376171377171378171379171380171381171382171383171384171385171386171387171388171389171390171391171392171393171394171395171396171397171398171399171400171401171402171403171404171405171406171407171408171409171410171411171412171413171414171415171416171417171418171419171420171421171422171423171424171425171426171427171428171429171430171431171432171433171434171435171436171437171438171439171440171441171442171443171444171445171446171447171448171449171450171451171452171453171454171455171456171457171458171459171460171461171462171463171464171465171466171467171468171469171470171471171472171473171474171475171476171477171478171479171480171481171482171483171484171485171486171487171488171489171490171491171492171493171494171495171496171497171498171499171500171501171502171503171504171505171506171507171508171509171510171511171512171513171514171515171516171517171518171519171520171521171522171523171524171525171526171527171528171529171530171531171532171533171534171535171536171537171538171539171540171541171542171543171544171545171546171547171548171549171550171551171552171553171554171555171556171557171558171559171560171561171562171563171564171565171566171567171568171569171570171571171572171573171574171575171576171577171578171579171580171581171582171583171584171585171586171587171588171589171590171591171592171593171594171595171596171597171598171599171600171601171602171603171604171605171606171607171608171609171610171611171612171613171614171615171616171617171618171619171620171621171622171623171624171625171626171627171628171629171630171631171632171633171634171635171636171637171638171639171640171641171642171643171644171645171646171647171648171649171650171651171652171653171654171655171656171657171658171659171660171661171662171663171664171665171666171667171668171669171670171671171672171673171674171675171676171677171678171679171680171681171682171683171684171685171686171687171688171689171690171691171692171693171694171695171696171697171698171699171700171701171702171703171704171705171706171707171708171709171710171711171712171713171714171715171716171717171718171719171720171721171722171723171724171725171726171727171728171729171730171731171732171733171734171735171736171737171738171739171740171741171742171743171744171745171746171747171748171749171750171751171752171753171754171755171756171757171758171759171760171761171762171763171764171765171766171767171768171769171770171771171772171773171774171775171776171777171778171779171780171781171782171783171784171785171786171787171788171789171790171791171792171793171794171795171796171797171798171799171800171801171802171803171804171805171806171807171808171809171810171811171812171813171814171815171816171817171818171819171820171821171822171823171824171825171826171827171828171829171830171831171832171833171834171835171836171837171838171839171840171841171842171843171844171845171846171847171848171849171850171851171852171853171854171855171856171857171858171859171860171861171862171863171864171865171866171867171868171869171870171871171872171873171874171875171876171877171878171879171880171881171882171883171884171885171886171887171888171889171890171891171892171893171894171895171896171897171898171899171900171901171902171903171904171905171906171907171908171909171910171911171912171913171914171915171916171917171918171919171920171921171922171923171924171925171926171927171928171929171930171931171932171933171934171935171936171937171938171939171940171941171942171943171944171945171946171947171948171949171950171951171952171953171954171955171956171957171958171959171960171961171962171963171964171965171966171967171968171969171970171971171972171973171974171975171976171977171978171979171980171981171982171983171984171985171986171987171988171989171990171991171992171993171994171995171996171997171998171999172000172001172002172003172004172005172006172007172008172009172010172011172012172013172014172015172016172017172018172019172020172021172022172023172024172025172026172027172028172029172030172031172032172033172034172035172036172037172038172039172040172041172042172043172044172045172046172047172048172049172050172051172052172053172054172055172056172057172058172059172060172061172062172063172064172065172066172067172068172069172070172071172072172073172074172075172076172077172078172079172080172081172082172083172084172085172086172087172088172089172090172091172092172093172094172095172096172097172098172099172100172101172102172103172104172105172106172107172108172109172110172111172112172113172114172115172116172117172118172119172120172121172122172123172124172125172126172127172128172129172130172131172132172133172134172135172136172137172138172139172140172141172142172143172144172145172146172147172148172149172150172151172152172153172154172155172156172157172158172159172160172161172162172163172164172165172166172167172168172169172170172171172172172173172174172175172176172177172178172179172180172181172182172183172184172185172186172187172188172189172190172191172192172193172194172195172196172197172198172199172200172201172202172203172204172205172206172207172208172209172210172211172212172213172214172215172216172217172218172219172220172221172222172223172224172225172226172227172228172229172230172231172232172233172234172235172236172237172238172239172240172241172242172243172244172245172246172247172248172249172250172251172252172253172254172255172256172257172258172259172260172261172262172263172264172265172266172267172268172269172270172271172272172273172274172275172276172277172278172279172280172281172282172283172284172285172286172287172288172289172290172291172292172293172294172295172296172297172298172299172300172301172302172303172304172305172306172307172308172309172310172311172312172313172314172315172316172317172318172319172320172321172322172323172324172325172326172327172328172329172330172331172332172333172334172335172336172337172338172339172340172341172342172343172344172345172346172347172348172349172350172351172352172353172354172355172356172357172358172359172360172361172362172363172364172365172366172367172368172369172370172371172372172373172374172375172376172377172378172379172380172381172382172383172384172385172386172387172388172389172390172391172392172393172394172395172396172397172398172399172400172401172402172403172404172405172406172407172408172409172410172411172412172413172414172415172416172417172418172419172420172421172422172423172424172425172426172427172428172429172430172431172432172433172434172435172436172437172438172439172440172441172442172443172444172445172446172447172448172449172450172451172452172453172454172455172456172457172458172459172460172461172462172463172464172465172466172467172468172469172470172471172472172473172474172475172476172477172478172479172480172481172482172483172484172485172486172487172488172489172490172491172492172493172494172495172496172497172498172499172500172501172502172503172504172505172506172507172508172509172510172511172512172513172514172515172516172517172518172519172520172521172522172523172524172525172526172527172528172529172530172531172532172533172534172535172536172537172538172539172540172541172542172543172544172545172546172547172548172549172550172551172552172553172554172555172556172557172558172559172560172561172562172563172564172565172566172567172568172569172570172571172572172573172574172575172576172577172578172579172580172581172582172583172584172585172586172587172588172589172590172591172592172593172594172595172596172597172598172599172600172601172602172603172604172605172606172607172608172609172610172611172612172613172614172615172616172617172618172619172620172621172622172623172624172625172626172627172628172629172630172631172632172633172634172635172636172637172638172639172640172641172642172643172644172645172646172647172648172649172650172651172652172653172654172655172656172657172658172659172660172661172662172663172664172665172666172667172668172669172670172671172672172673172674172675172676172677172678172679172680172681172682172683172684172685172686172687172688172689172690172691172692172693172694172695172696172697172698172699172700172701172702172703172704172705172706172707172708172709172710172711172712172713172714172715172716172717172718172719172720172721172722172723172724172725172726172727172728172729172730172731172732172733172734172735172736172737172738172739172740172741172742172743172744172745172746172747172748172749172750172751172752172753172754172755172756172757172758172759172760172761172762172763172764172765172766172767172768172769172770172771172772172773172774172775172776172777172778172779172780172781172782172783172784172785172786172787172788172789172790172791172792172793172794172795172796172797172798172799172800172801172802172803172804172805172806172807172808172809172810172811172812172813172814172815172816172817172818172819172820172821172822172823172824172825172826172827172828172829172830172831172832172833172834172835172836172837172838172839172840172841172842172843172844172845172846172847172848172849172850172851172852172853172854172855172856172857172858172859172860172861172862172863172864172865172866172867172868172869172870172871172872172873172874172875172876172877172878172879172880172881172882172883172884172885172886172887172888172889172890172891172892172893172894172895172896172897172898172899172900172901172902172903172904172905172906172907172908172909172910172911172912172913172914172915172916172917172918172919172920172921172922172923172924172925172926172927172928172929172930172931172932172933172934172935172936172937172938172939172940172941172942172943172944172945172946172947172948172949172950172951172952172953172954172955172956172957172958172959172960172961172962172963172964172965172966172967172968172969172970172971172972172973172974172975172976172977172978172979172980172981172982172983172984172985172986172987172988172989172990172991172992172993172994172995172996172997172998172999173000173001173002173003173004173005173006173007173008173009173010173011173012173013173014173015173016173017173018173019173020173021173022173023173024173025173026173027173028173029173030173031173032173033173034173035173036173037173038173039173040173041173042173043173044173045173046173047173048173049173050173051173052173053173054173055173056173057173058173059173060173061173062173063173064173065173066173067173068173069173070173071173072173073173074173075173076173077173078173079173080173081173082173083173084173085173086173087173088173089173090173091173092173093173094173095173096173097173098173099173100173101173102173103173104173105173106173107173108173109173110173111173112173113173114173115173116173117173118173119173120173121173122173123173124173125173126173127173128173129173130173131173132173133173134173135173136173137173138173139173140173141173142173143173144173145173146173147173148173149173150173151173152173153173154173155173156173157173158173159173160173161173162173163173164173165173166173167173168173169173170173171173172173173173174173175173176173177173178173179173180173181173182173183173184173185173186173187173188173189173190173191173192173193173194173195173196173197173198173199173200173201173202173203173204173205173206173207173208173209173210173211173212173213173214173215173216173217173218173219173220173221173222173223173224173225173226173227173228173229173230173231173232173233173234173235173236173237173238173239173240173241173242173243173244173245173246173247173248173249173250173251173252173253173254173255173256173257173258173259173260173261173262173263173264173265173266173267173268173269173270173271173272173273173274173275173276173277173278173279173280173281173282173283173284173285173286173287173288173289173290173291173292173293173294173295173296173297173298173299173300173301173302173303173304173305173306173307173308173309173310173311173312173313173314173315173316173317173318173319173320173321173322173323173324173325173326173327173328173329173330173331173332173333173334173335173336173337173338173339173340173341173342173343173344173345173346173347173348173349173350173351173352173353173354173355173356173357173358173359173360173361173362173363173364173365173366173367173368173369173370173371173372173373173374173375173376173377173378173379173380173381173382173383173384173385173386173387173388173389173390173391173392173393173394173395173396173397173398173399173400173401173402173403173404173405173406173407173408173409173410173411173412173413173414173415173416173417173418173419173420173421173422173423173424173425173426173427173428173429173430173431173432173433173434173435173436173437173438173439173440173441173442173443173444173445173446173447173448173449173450173451173452173453173454173455173456173457173458173459173460173461173462173463173464173465173466173467173468173469173470173471173472173473173474173475173476173477173478173479173480173481173482173483173484173485173486173487173488173489173490173491173492173493173494173495173496173497173498173499173500173501173502173503173504173505173506173507173508173509173510173511173512173513173514173515173516173517173518173519173520173521173522173523173524173525173526173527173528173529173530173531173532173533173534173535173536173537173538173539173540173541173542173543173544173545173546173547173548173549173550173551173552173553173554173555173556173557173558173559173560173561173562173563173564173565173566173567173568173569173570173571173572173573173574173575173576173577173578173579173580173581173582173583173584173585173586173587173588173589173590173591173592173593173594173595173596173597173598173599173600173601173602173603173604173605173606173607173608173609173610173611173612173613173614173615173616173617173618173619173620173621173622173623173624173625173626173627173628173629173630173631173632173633173634173635173636173637173638173639173640173641173642173643173644173645173646173647173648173649173650173651173652173653173654173655173656173657173658173659173660173661173662173663173664173665173666173667173668173669173670173671173672173673173674173675173676173677173678173679173680173681173682173683173684173685173686173687173688173689173690173691173692173693173694173695173696173697173698173699173700173701173702173703173704173705173706173707173708173709173710173711173712173713173714173715173716173717173718173719173720173721173722173723173724173725173726173727173728173729173730173731173732173733173734173735173736173737173738173739173740173741173742173743173744173745173746173747173748173749173750173751173752173753173754173755173756173757173758173759173760173761173762173763173764173765173766173767173768173769173770173771173772173773173774173775173776173777173778173779173780173781173782173783173784173785173786173787173788173789173790173791173792173793173794173795173796173797173798173799173800173801173802173803173804173805173806173807173808173809173810173811173812173813173814173815173816173817173818173819173820173821173822173823173824173825173826173827173828173829173830173831173832173833173834173835173836173837173838173839173840173841173842173843173844173845173846173847173848173849173850173851173852173853173854173855173856173857173858173859173860173861173862173863173864173865173866173867173868173869173870173871173872173873173874173875173876173877173878173879173880173881173882173883173884173885173886173887173888173889173890173891173892173893173894173895173896173897173898173899173900173901173902173903173904173905173906173907173908173909173910173911173912173913173914173915173916173917173918173919173920173921173922173923173924173925173926173927173928173929173930173931173932173933173934173935173936173937173938173939173940173941173942173943173944173945173946173947173948173949173950173951173952173953173954173955173956173957173958173959173960173961173962173963173964173965173966173967173968173969173970173971173972173973173974173975173976173977173978173979173980173981173982173983173984173985173986173987173988173989173990173991173992173993173994173995173996173997173998173999174000174001174002174003174004174005174006174007174008174009174010174011174012174013174014174015174016174017174018174019174020174021174022174023174024174025174026174027174028174029174030174031174032174033174034174035174036174037174038174039174040174041174042174043174044174045174046174047174048174049174050174051174052174053174054174055174056174057174058174059174060174061174062174063174064174065174066174067174068174069174070174071174072174073174074174075174076174077174078174079174080174081174082174083174084174085174086174087174088174089174090174091174092174093174094174095174096174097174098174099174100174101174102174103174104174105174106174107174108174109174110174111174112174113174114174115174116174117174118174119174120174121174122174123174124174125174126174127174128174129174130174131174132174133174134174135174136174137174138174139174140174141174142174143174144174145174146174147174148174149174150174151174152174153174154174155174156174157174158174159174160174161174162174163174164174165174166174167174168174169174170174171174172174173174174174175174176174177174178174179174180174181174182174183174184174185174186174187174188174189174190174191174192174193174194174195174196174197174198174199174200174201174202174203174204174205174206174207174208174209174210174211174212174213174214174215174216174217174218174219174220174221174222174223174224174225174226174227174228174229174230174231174232174233174234174235174236174237174238174239174240174241174242174243174244174245174246174247174248174249174250174251174252174253174254174255174256174257174258174259174260174261174262174263174264174265174266174267174268174269174270174271174272174273174274174275174276174277174278174279174280174281174282174283174284174285174286174287174288174289174290174291174292174293174294174295174296174297174298174299174300174301174302174303174304174305174306174307174308174309174310174311174312174313174314174315174316174317174318174319174320174321174322174323174324174325174326174327174328174329174330174331174332174333174334174335174336174337174338174339174340174341174342174343174344174345174346174347174348174349174350174351174352174353174354174355174356174357174358174359174360174361174362174363174364174365174366174367174368174369174370174371174372174373174374174375174376174377174378174379174380174381174382174383174384174385174386174387174388174389174390174391174392174393174394174395174396174397174398174399174400174401174402174403174404174405174406174407174408174409174410174411174412174413174414174415174416174417174418174419174420174421174422174423174424174425174426174427174428174429174430174431174432174433174434174435174436174437174438174439174440174441174442174443174444174445174446174447174448174449174450174451174452174453174454174455174456174457174458174459174460174461174462174463174464174465174466174467174468174469174470174471174472174473174474174475174476174477174478174479174480174481174482174483174484174485174486174487174488174489174490174491174492174493174494174495174496174497174498174499174500174501174502174503174504174505174506174507174508174509174510174511174512174513174514174515174516174517174518174519174520174521174522174523174524174525174526174527174528174529174530174531174532174533174534174535174536174537174538174539174540174541174542174543174544174545174546174547174548174549174550174551174552174553174554174555174556174557174558174559174560174561174562174563174564174565174566174567174568174569174570174571174572174573174574174575174576174577174578174579174580174581174582174583174584174585174586174587174588174589174590174591174592174593174594174595174596174597174598174599174600174601174602174603174604174605174606174607174608174609174610174611174612174613174614174615174616174617174618174619174620174621174622174623174624174625174626174627174628174629174630174631174632174633174634174635174636174637174638174639174640174641174642174643174644174645174646174647174648174649174650174651174652174653174654174655174656174657174658174659174660174661174662174663174664174665174666174667174668174669174670174671174672174673174674174675174676174677174678174679174680174681174682174683174684174685174686174687174688174689174690174691174692174693174694174695174696174697174698174699174700174701174702174703174704174705174706174707174708174709174710174711174712174713174714174715174716174717174718174719174720174721174722174723174724174725174726174727174728174729174730174731174732174733174734174735174736174737174738174739174740174741174742174743174744174745174746174747174748174749174750174751174752174753174754174755174756174757174758174759174760174761174762174763174764174765174766174767174768174769174770174771174772174773174774174775174776174777174778174779174780174781174782174783174784174785174786174787174788174789174790174791174792174793174794174795174796174797174798174799174800174801174802174803174804174805174806174807174808174809174810174811174812174813174814174815174816174817174818174819174820174821174822174823174824174825174826174827174828174829174830174831174832174833174834174835174836174837174838174839174840174841174842174843174844174845174846174847174848174849174850174851174852174853174854174855174856174857174858174859174860174861174862174863174864174865174866174867174868174869174870174871174872174873174874174875174876174877174878174879174880174881174882174883174884174885174886174887174888174889174890174891174892174893174894174895174896174897174898174899174900174901174902174903174904174905174906174907174908174909174910174911174912174913174914174915174916174917174918174919174920174921174922174923174924174925174926174927174928174929174930174931174932174933174934174935174936174937174938174939174940174941174942174943174944174945174946174947174948174949174950174951174952174953174954174955174956174957174958174959174960174961174962174963174964174965174966174967174968174969174970174971174972174973174974174975174976174977174978174979174980174981174982174983174984174985174986174987174988174989174990174991174992174993174994174995174996174997174998174999175000175001175002175003175004175005175006175007175008175009175010175011175012175013175014175015175016175017175018175019175020175021175022175023175024175025175026175027175028175029175030175031175032175033175034175035175036175037175038175039175040175041175042175043175044175045175046175047175048175049175050175051175052175053175054175055175056175057175058175059175060175061175062175063175064175065175066175067175068175069175070175071175072175073175074175075175076175077175078175079175080175081175082175083175084175085175086175087175088175089175090175091175092175093175094175095175096175097175098175099175100175101175102175103175104175105175106175107175108175109175110175111175112175113175114175115175116175117175118175119175120175121175122175123175124175125175126175127175128175129175130175131175132175133175134175135175136175137175138175139175140175141175142175143175144175145175146175147175148175149175150175151175152175153175154175155175156175157175158175159175160175161175162175163175164175165175166175167175168175169175170175171175172175173175174175175175176175177175178175179175180175181175182175183175184175185175186175187175188175189175190175191175192175193175194175195175196175197175198175199175200175201175202175203175204175205175206175207175208175209175210175211175212175213175214175215175216175217175218175219175220175221175222175223175224175225175226175227175228175229175230175231175232175233175234175235175236175237175238175239175240175241175242175243175244175245175246175247175248175249175250175251175252175253175254175255175256175257175258175259175260175261175262175263175264175265175266175267175268175269175270175271175272175273175274175275175276175277175278175279175280175281175282175283175284175285175286175287175288175289175290175291175292175293175294175295175296175297175298175299175300175301175302175303175304175305175306175307175308175309175310175311175312175313175314175315175316175317175318175319175320175321175322175323175324175325175326175327175328175329175330175331175332175333175334175335175336175337175338175339175340175341175342175343175344175345175346175347175348175349175350175351175352175353175354175355175356175357175358175359175360175361175362175363175364175365175366175367175368175369175370175371175372175373175374175375175376175377175378175379175380175381175382175383175384175385175386175387175388175389175390175391175392175393175394175395175396175397175398175399175400175401175402175403175404175405175406175407175408175409175410175411175412175413175414175415175416175417175418175419175420175421175422175423175424175425175426175427175428175429175430175431175432175433175434175435175436175437175438175439175440175441175442175443175444175445175446175447175448175449175450175451175452175453175454175455175456175457175458175459175460175461175462175463175464175465175466175467175468175469175470175471175472175473175474175475175476175477175478175479175480175481175482175483175484175485175486175487175488175489175490175491175492175493175494175495175496175497175498175499175500175501175502175503175504175505175506175507175508175509175510175511175512175513175514175515175516175517175518175519175520175521175522175523175524175525175526175527175528175529175530175531175532175533175534175535175536175537175538175539175540175541175542175543175544175545175546175547175548175549175550175551175552175553175554175555175556175557175558175559175560175561175562175563175564175565175566175567175568175569175570175571175572175573175574175575175576175577175578175579175580175581175582175583175584175585175586175587175588175589175590175591175592175593175594175595175596175597175598175599175600175601175602175603175604175605175606175607175608175609175610175611175612175613175614175615175616175617175618175619175620175621175622175623175624175625175626175627175628175629175630175631175632175633175634175635175636175637175638175639175640175641175642175643175644175645175646175647175648175649175650175651175652175653175654175655175656175657175658175659175660175661175662175663175664175665175666175667175668175669175670175671175672175673175674175675175676175677175678175679175680175681175682175683175684175685175686175687175688175689175690175691175692175693175694175695175696175697175698175699175700175701175702175703175704175705175706175707175708175709175710175711175712175713175714175715175716175717175718175719175720175721175722175723175724175725175726175727175728175729175730175731175732175733175734175735175736175737175738175739175740175741175742175743175744175745175746175747175748175749175750175751175752175753175754175755175756175757175758175759175760175761175762175763175764175765175766175767175768175769175770175771175772175773175774175775175776175777175778175779175780175781175782175783175784175785175786175787175788175789175790175791175792175793175794175795175796175797175798175799175800175801175802175803175804175805175806175807175808175809175810175811175812175813175814175815175816175817175818175819175820175821175822175823175824175825175826175827175828175829175830175831175832175833175834175835175836175837175838175839175840175841175842175843175844175845175846175847175848175849175850175851175852175853175854175855175856175857175858175859175860175861175862175863175864175865175866175867175868175869175870175871175872175873175874175875175876175877175878175879175880175881175882175883175884175885175886175887175888175889175890175891175892175893175894175895175896175897175898175899175900175901175902175903175904175905175906175907175908175909175910175911175912175913175914175915175916175917175918175919175920175921175922175923175924175925175926175927175928175929175930175931175932175933175934175935175936175937175938175939175940175941175942175943175944175945175946175947175948175949175950175951175952175953175954175955175956175957175958175959175960175961175962175963175964175965175966175967175968175969175970175971175972175973175974175975175976175977175978175979175980175981175982175983175984175985175986175987175988175989175990175991175992175993175994175995175996175997175998175999176000176001176002176003176004176005176006176007176008176009176010176011176012176013176014176015176016176017176018176019176020176021176022176023176024176025176026176027176028176029176030176031176032176033176034176035176036176037176038176039176040176041176042176043176044176045176046176047176048176049176050176051176052176053176054176055176056176057176058176059176060176061176062176063176064176065176066176067176068176069176070176071176072176073176074176075176076176077176078176079176080176081176082176083176084176085176086176087176088176089176090176091176092176093176094176095176096176097176098176099176100176101176102176103176104176105176106176107176108176109176110176111176112176113176114176115176116176117176118176119176120176121176122176123176124176125176126176127176128176129176130176131176132176133176134176135176136176137176138176139176140176141176142176143176144176145176146176147176148176149176150176151176152176153176154176155176156176157176158176159176160176161176162176163176164176165176166176167176168176169176170176171176172176173176174176175176176176177176178176179176180176181176182176183176184176185176186176187176188176189176190176191176192176193176194176195176196176197176198176199176200176201176202176203176204176205176206176207176208176209176210176211176212176213176214176215176216176217176218176219176220176221176222176223176224176225176226176227176228176229176230176231176232176233176234176235176236176237176238176239176240176241176242176243176244176245176246176247176248176249176250176251176252176253176254176255176256176257176258176259176260176261176262176263176264176265176266176267176268176269176270176271176272176273176274176275176276176277176278176279176280176281176282176283176284176285176286176287176288176289176290176291176292176293176294176295176296176297176298176299176300176301176302176303176304176305176306176307176308176309176310176311176312176313176314176315176316176317176318176319176320176321176322176323176324176325176326176327176328176329176330176331176332176333176334176335176336176337176338176339176340176341176342176343176344176345176346176347176348176349176350176351176352176353176354176355176356176357176358176359176360176361176362176363176364176365176366176367176368176369176370176371176372176373176374176375176376176377176378176379176380176381176382176383176384176385176386176387176388176389176390176391176392176393176394176395176396176397176398176399176400176401176402176403176404176405176406176407176408176409176410176411176412176413176414176415176416176417176418176419176420176421176422176423176424176425176426176427176428176429176430176431176432176433176434176435176436176437176438176439176440176441176442176443176444176445176446176447176448176449176450176451176452176453176454176455176456176457176458176459176460176461176462176463176464176465176466176467176468176469176470176471176472176473176474176475176476176477176478176479176480176481176482176483176484176485176486176487176488176489176490176491176492176493176494176495176496176497176498176499176500176501176502176503176504176505176506176507176508176509176510176511176512176513176514176515176516176517176518176519176520176521176522176523176524176525176526176527176528176529176530176531176532176533176534176535176536176537176538176539176540176541176542176543176544176545176546176547176548176549176550176551176552176553176554176555176556176557176558176559176560176561176562176563176564176565176566176567176568176569176570176571176572176573176574176575176576176577176578176579176580176581176582176583176584176585176586176587176588176589176590176591176592176593176594176595176596176597176598176599176600176601176602176603176604176605176606176607176608176609176610176611176612176613176614176615176616176617176618176619176620176621176622176623176624176625176626176627176628176629176630176631176632176633176634176635176636176637176638176639176640176641176642176643176644176645176646176647176648176649176650176651176652176653176654176655176656176657176658176659176660176661176662176663176664176665176666176667176668176669176670176671176672176673176674176675176676176677176678176679176680176681176682176683176684176685176686176687176688176689176690176691176692176693176694176695176696176697176698176699176700176701176702176703176704176705176706176707176708176709176710176711176712176713176714176715176716176717176718176719176720176721176722176723176724176725176726176727176728176729176730176731176732176733176734176735176736176737176738176739176740176741176742176743176744176745176746176747176748176749176750176751176752176753176754176755176756176757176758176759176760176761176762176763176764176765176766176767176768176769176770176771176772176773176774176775176776176777176778176779176780176781176782176783176784176785176786176787176788176789176790176791176792176793176794176795176796176797176798176799176800176801176802176803176804176805176806176807176808176809176810176811176812176813176814176815176816176817176818176819176820176821176822176823176824176825176826176827176828176829176830176831176832176833176834176835176836176837176838176839176840176841176842176843176844176845176846176847176848176849176850176851176852176853176854176855176856176857176858176859176860176861176862176863176864176865176866176867176868176869176870176871176872176873176874176875176876176877176878176879176880176881176882176883176884176885176886176887176888176889176890176891176892176893176894176895176896176897176898176899176900176901176902176903176904176905176906176907176908176909176910176911176912176913176914176915176916176917176918176919176920176921176922176923176924176925176926176927176928176929176930176931176932176933176934176935176936176937176938176939176940176941176942176943176944176945176946176947176948176949176950176951176952176953176954176955176956176957176958176959176960176961176962176963176964176965176966176967176968176969176970176971176972176973176974176975176976176977176978176979176980176981176982176983176984176985176986176987176988176989176990176991176992176993176994176995176996176997176998176999177000177001177002177003177004177005177006177007177008177009177010177011177012177013177014177015177016177017177018177019177020177021177022177023177024177025177026177027177028177029177030177031177032177033177034177035177036177037177038177039177040177041177042177043177044177045177046177047177048177049177050177051177052177053177054177055177056177057177058177059177060177061177062177063177064177065177066177067177068177069177070177071177072177073177074177075177076177077177078177079177080177081177082177083177084177085177086177087177088177089177090177091177092177093177094177095177096177097177098177099177100177101177102177103177104177105177106177107177108177109177110177111177112177113177114177115177116177117177118177119177120177121177122177123177124177125177126177127177128177129177130177131177132177133177134177135177136177137177138177139177140177141177142177143177144177145177146177147177148177149177150177151177152177153177154177155177156177157177158177159177160177161177162177163177164177165177166177167177168177169177170177171177172177173177174177175177176177177177178177179177180177181177182177183177184177185177186177187177188177189177190177191177192177193177194177195177196177197177198177199177200177201177202177203177204177205177206177207177208177209177210177211177212177213177214177215177216177217177218177219177220177221177222177223177224177225177226177227177228177229177230177231177232177233177234177235177236177237177238177239177240177241177242177243177244177245177246177247177248177249177250177251177252177253177254177255177256177257177258177259177260177261177262177263177264177265177266177267177268177269177270177271177272177273177274177275177276177277177278177279177280177281177282177283177284177285177286177287177288177289177290177291177292177293177294177295177296177297177298177299177300177301177302177303177304177305177306177307177308177309177310177311177312177313177314177315177316177317177318177319177320177321177322177323177324177325177326177327177328177329177330177331177332177333177334177335177336177337177338177339177340177341177342177343177344177345177346177347177348177349177350177351177352177353177354177355177356177357177358177359177360177361177362177363177364177365177366177367177368177369177370177371177372177373177374177375177376177377177378177379177380177381177382177383177384177385177386177387177388177389177390177391177392177393177394177395177396177397177398177399177400177401177402177403177404177405177406177407177408177409177410177411177412177413177414177415177416177417177418177419177420177421177422177423177424177425177426177427177428177429177430177431177432177433177434177435177436177437177438177439177440177441177442177443177444177445177446177447177448177449177450177451177452177453177454177455177456177457177458177459177460177461177462177463177464177465177466177467177468177469177470177471177472177473177474177475177476177477177478177479177480177481177482177483177484177485177486177487177488177489177490177491177492177493177494177495177496177497177498177499177500177501177502177503177504177505177506177507177508177509177510177511177512177513177514177515177516177517177518177519177520177521177522177523177524177525177526177527177528177529177530177531177532177533177534177535177536177537177538177539177540177541177542177543177544177545177546177547177548177549177550177551177552177553177554177555177556177557177558177559177560177561177562177563177564177565177566177567177568177569177570177571177572177573177574177575177576177577177578177579177580177581177582177583177584177585177586177587177588177589177590177591177592177593177594177595177596177597177598177599177600177601177602177603177604177605177606177607177608177609177610177611177612177613177614177615177616177617177618177619177620177621177622177623177624177625177626177627177628177629177630177631177632177633177634177635177636177637177638177639177640177641177642177643177644177645177646177647177648177649177650177651177652177653177654177655177656177657177658177659177660177661177662177663177664177665177666177667177668177669177670177671177672177673177674177675177676177677177678177679177680177681177682177683177684177685177686177687177688177689177690177691177692177693177694177695177696177697177698177699177700177701177702177703177704177705177706177707177708177709177710177711177712177713177714177715177716177717177718177719177720177721177722177723177724177725177726177727177728177729177730177731177732177733177734177735177736177737177738177739177740177741177742177743177744177745177746177747177748177749177750177751177752177753177754177755177756177757177758177759177760177761177762177763177764177765177766177767177768177769177770177771177772177773177774177775177776177777177778177779177780177781177782177783177784177785177786177787177788177789177790177791177792177793177794177795177796177797177798177799177800177801177802177803177804177805177806177807177808177809177810177811177812177813177814177815177816177817177818177819177820177821177822177823177824177825177826177827177828177829177830177831177832177833177834177835177836177837177838177839177840177841177842177843177844177845177846177847177848177849177850177851177852177853177854177855177856177857177858177859177860177861177862177863177864177865177866177867177868177869177870177871177872177873177874177875177876177877177878177879177880177881177882177883177884177885177886177887177888177889177890177891177892177893177894177895177896177897177898177899177900177901177902177903177904177905177906177907177908177909177910177911177912177913177914177915177916177917177918177919177920177921177922177923177924177925177926177927177928177929177930177931177932177933177934177935177936177937177938177939177940177941177942177943177944177945177946177947177948177949177950177951177952177953177954177955177956177957177958177959177960177961177962177963177964177965177966177967177968177969177970177971177972177973177974177975177976177977177978177979177980177981177982177983177984177985177986177987177988177989177990177991177992177993177994177995177996177997177998177999178000178001178002178003178004178005178006178007178008178009178010178011178012178013178014178015178016178017178018178019178020178021178022178023178024178025178026178027178028178029178030178031178032178033178034178035178036178037178038178039178040178041178042178043178044178045178046178047178048178049178050178051178052178053178054178055178056178057178058178059178060178061178062178063178064178065178066178067178068178069178070178071178072178073178074178075178076178077178078178079178080178081178082178083178084178085178086178087178088178089178090178091178092178093178094178095178096178097178098178099178100178101178102178103178104178105178106178107178108178109178110178111178112178113178114178115178116178117178118178119178120178121178122178123178124178125178126178127178128178129178130178131178132178133178134178135178136178137178138178139178140178141178142178143178144178145178146178147178148178149178150178151178152178153178154178155178156178157178158178159178160178161178162178163178164178165178166178167178168178169178170178171178172178173178174178175178176178177178178178179178180178181178182178183178184178185178186178187178188178189178190178191178192178193178194178195178196178197178198178199178200178201178202178203178204178205178206178207178208178209178210178211178212178213178214178215178216178217178218178219178220178221178222178223178224178225178226178227178228178229178230178231178232178233178234178235178236178237178238178239178240178241178242178243178244178245178246178247178248178249178250178251178252178253178254178255178256178257178258178259178260178261178262178263178264178265178266178267178268178269178270178271178272178273178274178275178276178277178278178279178280178281178282178283178284178285178286178287178288178289178290178291178292178293178294178295178296178297178298178299178300178301178302178303178304178305178306178307178308178309178310178311178312178313178314178315178316178317178318178319178320178321178322178323178324178325178326178327178328178329178330178331178332178333178334178335178336178337178338178339178340178341178342178343178344178345178346178347178348178349178350178351178352178353178354178355178356178357178358178359178360178361178362178363178364178365178366178367178368178369178370178371178372178373178374178375178376178377178378178379178380178381178382178383178384178385178386178387178388178389178390178391178392178393178394178395178396178397178398178399178400178401178402178403178404178405178406178407178408178409178410178411178412178413178414178415178416178417178418178419178420178421178422178423178424178425178426178427178428178429178430178431178432178433178434178435178436178437178438178439178440178441178442178443178444178445178446178447178448178449178450178451178452178453178454178455178456178457178458178459178460178461178462178463178464178465178466178467178468178469178470178471178472178473178474178475178476178477178478178479178480178481178482178483178484178485178486178487178488178489178490178491178492178493178494178495178496178497178498178499178500178501178502178503178504178505178506178507178508178509178510178511178512178513178514178515178516178517178518178519178520178521178522178523178524178525178526178527178528178529178530178531178532178533178534178535178536178537178538178539178540178541178542178543178544178545178546178547178548178549178550178551178552178553178554178555178556178557178558178559178560178561178562178563178564178565178566178567178568178569178570178571178572178573178574178575178576178577178578178579178580178581178582178583178584178585178586178587178588178589178590178591178592178593178594178595178596178597178598178599178600178601178602178603178604178605178606178607178608178609178610178611178612178613178614178615178616178617178618178619178620178621178622178623178624178625178626178627178628178629178630178631178632178633178634178635178636178637178638178639178640178641178642178643178644178645178646178647178648178649178650178651178652178653178654178655178656178657178658178659178660178661178662178663178664178665178666178667178668178669178670178671178672178673178674178675178676178677178678178679178680178681178682178683178684178685178686178687178688178689178690178691178692178693178694178695178696178697178698178699178700178701178702178703178704178705178706178707178708178709178710178711178712178713178714178715178716178717178718178719178720178721178722178723178724178725178726178727178728178729178730178731178732178733178734178735178736178737178738178739178740178741178742178743178744178745178746178747178748178749178750178751178752178753178754178755178756178757178758178759178760178761178762178763178764178765178766178767178768178769178770178771178772178773178774178775178776178777178778178779178780178781178782178783178784178785178786178787178788178789178790178791178792178793178794178795178796178797178798178799178800178801178802178803178804178805178806178807178808178809178810178811178812178813178814178815178816178817178818178819178820178821178822178823178824178825178826178827178828178829178830178831178832178833178834178835178836178837178838178839178840178841178842178843178844178845178846178847178848178849178850178851178852178853178854178855178856178857178858178859178860178861178862178863178864178865178866178867178868178869178870178871178872178873178874178875178876178877178878178879178880178881178882178883178884178885178886178887178888178889178890178891178892178893178894178895178896178897178898178899178900178901178902178903178904178905178906178907178908178909178910178911178912178913178914178915178916178917178918178919178920178921178922178923178924178925178926178927178928178929178930178931178932178933178934178935178936178937178938178939178940178941178942178943178944178945178946178947178948178949178950178951178952178953178954178955178956178957178958178959178960178961178962178963178964178965178966178967178968178969178970178971178972178973178974178975178976178977178978178979178980178981178982178983178984178985178986178987178988178989178990178991178992178993178994178995178996178997178998178999179000179001179002179003179004179005179006179007179008179009179010179011179012179013179014179015179016179017179018179019179020179021179022179023179024179025179026179027179028179029179030179031179032179033179034179035179036179037179038179039179040179041179042179043179044179045179046179047179048179049179050179051179052179053179054179055179056179057179058179059179060179061179062179063179064179065179066179067179068179069179070179071179072179073179074179075179076179077179078179079179080179081179082179083179084179085179086179087179088179089179090179091179092179093179094179095179096179097179098179099179100179101179102179103179104179105179106179107179108179109179110179111179112179113179114179115179116179117179118179119179120179121179122179123179124179125179126179127179128179129179130179131179132179133179134179135179136179137179138179139179140179141179142179143179144179145179146179147179148179149179150179151179152179153179154179155179156179157179158179159179160179161179162179163179164179165179166179167179168179169179170179171179172179173179174179175179176179177179178179179179180179181179182179183179184179185179186179187179188179189179190179191179192179193179194179195179196179197179198179199179200179201179202179203179204179205179206179207179208179209179210179211179212179213179214179215179216179217179218179219179220179221179222179223179224179225179226179227179228179229179230179231179232179233179234179235179236179237179238179239179240179241179242179243179244179245179246179247179248179249179250179251179252179253179254179255179256179257179258179259179260179261179262179263179264179265179266179267179268179269179270179271179272179273179274179275179276179277179278179279179280179281179282179283179284179285179286179287179288179289179290179291179292179293179294179295179296179297179298179299179300179301179302179303179304179305179306179307179308179309179310179311179312179313179314179315179316179317179318179319179320179321179322179323179324179325179326179327179328179329179330179331179332179333179334179335179336179337179338179339179340179341179342179343179344179345179346179347179348179349179350179351179352179353179354179355179356179357179358179359179360179361179362179363179364179365179366179367179368179369179370179371179372179373179374179375179376179377179378179379179380179381179382179383179384179385179386179387179388179389179390179391179392179393179394179395179396179397179398179399179400179401179402179403179404179405179406179407179408179409179410179411179412179413179414179415179416179417179418179419179420179421179422179423179424179425179426179427179428179429179430179431179432179433179434179435179436179437179438179439179440179441179442179443179444179445179446179447179448179449179450179451179452179453179454179455179456179457179458179459179460179461179462179463179464179465179466179467179468179469179470179471179472179473179474179475179476179477179478179479179480179481179482179483179484179485179486179487179488179489179490179491179492179493179494179495179496179497179498179499179500179501179502179503179504179505179506179507179508179509179510179511179512179513179514179515179516179517179518179519179520179521179522179523179524179525179526179527179528179529179530179531179532179533179534179535179536179537179538179539179540179541179542179543179544179545179546179547179548179549179550179551179552179553179554179555179556179557179558179559179560179561179562179563179564179565179566179567179568179569179570179571179572179573179574179575179576179577179578179579179580179581179582179583179584179585179586179587179588179589179590179591179592179593179594179595179596179597179598179599179600179601179602179603179604179605179606179607179608179609179610179611179612179613179614179615179616179617179618179619179620179621179622179623179624179625179626179627179628179629179630179631179632179633179634179635179636179637179638179639179640179641179642179643179644179645179646179647179648179649179650179651179652179653179654179655179656179657179658179659179660179661179662179663179664179665179666179667179668179669179670179671179672179673179674179675179676179677179678179679179680179681179682179683179684179685179686179687179688179689179690179691179692179693179694179695179696179697179698179699179700179701179702179703179704179705179706179707179708179709179710179711179712179713179714179715179716179717179718179719179720179721179722179723179724179725179726179727179728179729179730179731179732179733179734179735179736179737179738179739179740179741179742179743179744179745179746179747179748179749179750179751179752179753179754179755179756179757179758179759179760179761179762179763179764179765179766179767179768179769179770179771179772179773179774179775179776179777179778179779179780179781179782179783179784179785179786179787179788179789179790179791179792179793179794179795179796179797179798179799179800179801179802179803179804179805179806179807179808179809179810179811179812179813179814179815179816179817179818179819179820179821179822179823179824179825179826179827179828179829179830179831179832179833179834179835179836179837179838179839179840179841179842179843179844179845179846179847179848179849179850179851179852179853179854179855179856179857179858179859179860179861179862179863179864179865179866179867179868179869179870179871179872179873179874179875179876179877179878179879179880179881179882179883179884179885179886179887179888179889179890179891179892179893179894179895179896179897179898179899179900179901179902179903179904179905179906179907179908179909179910179911179912179913179914179915179916179917179918179919179920179921179922179923179924179925179926179927179928179929179930179931179932179933179934179935179936179937179938179939179940179941179942179943179944179945179946179947179948179949179950179951179952179953179954179955179956179957179958179959179960179961179962179963179964179965179966179967179968179969179970179971179972179973179974179975179976179977179978179979179980179981179982179983179984179985179986179987179988179989179990179991179992179993179994179995179996179997179998179999180000180001180002180003180004180005180006180007180008180009180010180011180012180013180014180015180016180017180018180019180020180021180022180023180024180025180026180027180028180029180030180031180032180033180034180035180036180037180038180039180040180041180042180043180044180045180046180047180048180049180050180051180052180053180054180055180056180057180058180059180060180061180062180063180064180065180066180067180068180069180070180071180072180073180074180075180076180077180078180079180080180081180082180083180084180085180086180087180088180089180090180091180092180093180094180095180096180097180098180099180100180101180102180103180104180105180106180107180108180109180110180111180112180113180114180115180116180117180118180119180120180121180122180123180124180125180126180127180128180129180130180131180132180133180134180135180136180137180138180139180140180141180142180143180144180145180146180147180148180149180150180151180152180153180154180155180156180157180158180159180160180161180162180163180164180165180166180167180168180169180170180171180172180173180174180175180176180177180178180179180180180181180182180183180184180185180186180187180188180189180190180191180192180193180194180195180196180197180198180199180200180201180202180203180204180205180206180207180208180209180210180211180212180213180214180215180216180217180218180219180220180221180222180223180224180225180226180227180228180229180230180231180232180233180234180235180236180237180238180239180240180241180242180243180244180245180246180247180248180249180250180251180252180253180254180255180256180257180258180259180260180261180262180263180264180265180266180267180268180269180270180271180272180273180274180275180276180277180278180279180280180281180282180283180284180285180286180287180288180289180290180291180292180293180294180295180296180297180298180299180300180301180302180303180304180305180306180307180308180309180310180311180312180313180314180315180316180317180318180319180320180321180322180323180324180325180326180327180328180329180330180331180332180333180334180335180336180337180338180339180340180341180342180343180344180345180346180347180348180349180350180351180352180353180354180355180356180357180358180359180360180361180362180363180364180365180366180367180368180369180370180371180372180373180374180375180376180377180378180379180380180381180382180383180384180385180386180387180388180389180390180391180392180393180394180395180396180397180398180399180400180401180402180403180404180405180406180407180408180409180410180411180412180413180414180415180416180417180418180419180420180421180422180423180424180425180426180427180428180429180430180431180432180433180434180435180436180437180438180439180440180441180442180443180444180445180446180447180448180449180450180451180452180453180454180455180456180457180458180459180460180461180462180463180464180465180466180467180468180469180470180471180472180473180474180475180476180477180478180479180480180481180482180483180484180485180486180487180488180489180490180491180492180493180494180495180496180497180498180499180500180501180502180503180504180505180506180507180508180509180510180511180512180513180514180515180516180517180518180519180520180521180522180523180524180525180526180527180528180529180530180531180532180533180534180535180536180537180538180539180540180541180542180543180544180545180546180547180548180549180550180551180552180553180554180555180556180557180558180559180560180561180562180563180564180565180566180567180568180569180570180571180572180573180574180575180576180577180578180579180580180581180582180583180584180585180586180587180588180589180590180591180592180593180594180595180596180597180598180599180600180601180602180603180604180605180606180607180608180609180610180611180612180613180614180615180616180617180618180619180620180621180622180623180624180625180626180627180628180629180630180631180632180633180634180635180636180637180638180639180640180641180642180643180644180645180646180647180648180649180650180651180652180653180654180655180656180657180658180659180660180661180662180663180664180665180666180667180668180669180670180671180672180673180674180675180676180677180678180679180680180681180682180683180684180685180686180687180688180689180690180691180692180693180694180695180696180697180698180699180700180701180702180703180704180705180706180707180708180709180710180711180712180713180714180715180716180717180718180719180720180721180722180723180724180725180726180727180728180729180730180731180732180733180734180735180736180737180738180739180740180741180742180743180744180745180746180747180748180749180750180751180752180753180754180755180756180757180758180759180760180761180762180763180764180765180766180767180768180769180770180771180772180773180774180775180776180777180778180779180780180781180782180783180784180785180786180787180788180789180790180791180792180793180794180795180796180797180798180799180800180801180802180803180804180805180806180807180808180809180810180811180812180813180814180815180816180817180818180819180820180821180822180823180824180825180826180827180828180829180830180831180832180833180834180835180836180837180838180839180840180841180842180843180844180845180846180847180848180849180850180851180852180853180854180855180856180857180858180859180860180861180862180863180864180865180866180867180868180869180870180871180872180873180874180875180876180877180878180879180880180881180882180883180884180885180886180887180888180889180890180891180892180893180894180895180896180897180898180899180900180901180902180903180904180905180906180907180908180909180910180911180912180913180914180915180916180917180918180919180920180921180922180923180924180925180926180927180928180929180930180931180932180933180934180935180936180937180938180939180940180941180942180943180944180945180946180947180948180949180950180951180952180953180954180955180956180957180958180959180960180961180962180963180964180965180966180967180968180969180970180971180972180973180974180975180976180977180978180979180980180981180982180983180984180985180986180987180988180989180990180991180992180993180994180995180996180997180998180999181000181001181002181003181004181005181006181007181008181009181010181011181012181013181014181015181016181017181018181019181020181021181022181023181024181025181026181027181028181029181030181031181032181033181034181035181036181037181038181039181040181041181042181043181044181045181046181047181048181049181050181051181052181053181054181055181056181057181058181059181060181061181062181063181064181065181066181067181068181069181070181071181072181073181074181075181076181077181078181079181080181081181082181083181084181085181086181087181088181089181090181091181092181093181094181095181096181097181098181099181100181101181102181103181104181105181106181107181108181109181110181111181112181113181114181115181116181117181118181119181120181121181122181123181124181125181126181127181128181129181130181131181132181133181134181135181136181137181138181139181140181141181142181143181144181145181146181147181148181149181150181151181152181153181154181155181156181157181158181159181160181161181162181163181164181165181166181167181168181169181170181171181172181173181174181175181176181177181178181179181180181181181182181183181184181185181186181187181188181189181190181191181192181193181194181195181196181197181198181199181200181201181202181203181204181205181206181207181208181209181210181211181212181213181214181215181216181217181218181219181220181221181222181223181224181225181226181227181228181229181230181231181232181233181234181235181236181237181238181239181240181241181242181243181244181245181246181247181248181249181250181251181252181253181254181255181256181257181258181259181260181261181262181263181264181265181266181267181268181269181270181271181272181273181274181275181276181277181278181279181280181281181282181283181284181285181286181287181288181289181290181291181292181293181294181295181296181297181298181299181300181301181302181303181304181305181306181307181308181309181310181311181312181313181314181315181316181317181318181319181320181321181322181323181324181325181326181327181328181329181330181331181332181333181334181335181336181337181338181339181340181341181342181343181344181345181346181347181348181349181350181351181352181353181354181355181356181357181358181359181360181361181362181363181364181365181366181367181368181369181370181371181372181373181374181375181376181377181378181379181380181381181382181383181384181385181386181387181388181389181390181391181392181393181394181395181396181397181398181399181400181401181402181403181404181405181406181407181408181409181410181411181412181413181414181415181416181417181418181419181420181421181422181423181424181425181426181427181428181429181430181431181432181433181434181435181436181437181438181439181440181441181442181443181444181445181446181447181448181449181450181451181452181453181454181455181456181457181458181459181460181461181462181463181464181465181466181467181468181469181470181471181472181473181474181475181476181477181478181479181480181481181482181483181484181485181486181487181488181489181490181491181492181493181494181495181496181497181498181499181500181501181502181503181504181505181506181507181508181509181510181511181512181513181514181515181516181517181518181519181520181521181522181523181524181525181526181527181528181529181530181531181532181533181534181535181536181537181538181539181540181541181542181543181544181545181546181547181548181549181550181551181552181553181554181555181556181557181558181559181560181561181562181563181564181565181566181567181568181569181570181571181572181573181574181575181576181577181578181579181580181581181582181583181584181585181586181587181588181589181590181591181592181593181594181595181596181597181598181599181600181601181602181603181604181605181606181607181608181609181610181611181612181613181614181615181616181617181618181619181620181621181622181623181624181625181626181627181628181629181630181631181632181633181634181635181636181637181638181639181640181641181642181643181644181645181646181647181648181649181650181651181652181653181654181655181656181657181658181659181660181661181662181663181664181665181666181667181668181669181670181671181672181673181674181675181676181677181678181679181680181681181682181683181684181685181686181687181688181689181690181691181692181693181694181695181696181697181698181699181700181701181702181703181704181705181706181707181708181709181710181711181712181713181714181715181716181717181718181719181720181721181722181723181724181725181726181727181728181729181730181731181732181733181734181735181736181737181738181739181740181741181742181743181744181745181746181747181748181749181750181751181752181753181754181755181756181757181758181759181760181761181762181763181764181765181766181767181768181769181770181771181772181773181774181775181776181777181778181779181780181781181782181783181784181785181786181787181788181789181790181791181792181793181794181795181796181797181798181799181800181801181802181803181804181805181806181807181808181809181810181811181812181813181814181815181816181817181818181819181820181821181822181823181824181825181826181827181828181829181830181831181832181833181834181835181836181837181838181839181840181841181842181843181844181845181846181847181848181849181850181851181852181853181854181855181856181857181858181859181860181861181862181863181864181865181866181867181868181869181870181871181872181873181874181875181876181877181878181879181880181881181882181883181884181885181886181887181888181889181890181891181892181893181894181895181896181897181898181899181900181901181902181903181904181905181906181907181908181909181910181911181912181913181914181915181916181917181918181919181920181921181922181923181924181925181926181927181928181929181930181931181932181933181934181935181936181937181938181939181940181941181942181943181944181945181946181947181948181949181950181951181952181953181954181955181956181957181958181959181960181961181962181963181964181965181966181967181968181969181970181971181972181973181974181975181976181977181978181979181980181981181982181983181984181985181986181987181988181989181990181991181992181993181994181995181996181997181998181999182000182001182002182003182004182005182006182007182008182009182010182011182012182013182014182015182016182017182018182019182020182021182022182023182024182025182026182027182028182029182030182031182032182033182034182035182036182037182038182039182040182041182042182043182044182045182046182047182048182049182050182051182052182053182054182055182056182057182058182059182060182061182062182063182064182065182066182067182068182069182070182071182072182073182074182075182076182077182078182079182080182081182082182083182084182085182086182087182088182089182090182091182092182093182094182095182096182097182098182099182100182101182102182103182104182105182106182107182108182109182110182111182112182113182114182115182116182117182118182119182120182121182122182123182124182125182126182127182128182129182130182131182132182133182134182135182136182137182138182139182140182141182142182143182144182145182146182147182148182149182150182151182152182153182154182155182156182157182158182159182160182161182162182163182164182165182166182167182168182169182170182171182172182173182174182175182176182177182178182179182180182181182182182183182184182185182186182187182188182189182190182191182192182193182194182195182196182197182198182199182200182201182202182203182204182205182206182207182208182209182210182211182212182213182214182215182216182217182218182219182220182221182222182223182224182225182226182227182228182229182230182231182232182233182234182235182236182237182238182239182240182241182242182243182244182245182246182247182248182249182250182251182252182253182254182255182256182257182258182259182260182261182262182263182264182265182266182267182268182269182270182271182272182273182274182275182276182277182278182279182280182281182282182283182284182285182286182287182288182289182290182291182292182293182294182295182296182297182298182299182300182301182302182303182304182305182306182307182308182309182310182311182312182313182314182315182316182317182318182319182320182321182322182323182324182325182326182327182328182329182330182331182332182333182334182335182336182337182338182339182340182341182342182343182344182345182346182347182348182349182350182351182352182353182354182355182356182357182358182359182360182361182362182363182364182365182366182367182368182369182370182371182372182373182374182375182376182377182378182379182380182381182382182383182384182385182386182387182388182389182390182391182392182393182394182395182396182397182398182399182400182401182402182403182404182405182406182407182408182409182410182411182412182413182414182415182416182417182418182419182420182421182422182423182424182425182426182427182428182429182430182431182432182433182434182435182436182437182438182439182440182441182442182443182444182445182446182447182448182449182450182451182452182453182454182455182456182457182458182459182460182461182462182463182464182465182466182467182468182469182470182471182472182473182474182475182476182477182478182479182480182481182482182483182484182485182486182487182488182489182490182491182492182493182494182495182496182497182498182499182500182501182502182503182504182505182506182507182508182509182510182511182512182513182514182515182516182517182518182519182520182521182522182523182524182525182526182527182528182529182530182531182532182533182534182535182536182537182538182539182540182541182542182543182544182545182546182547182548182549182550182551182552182553182554182555182556182557182558182559182560182561182562182563182564182565182566182567182568182569182570182571182572182573182574182575182576182577182578182579182580182581182582182583182584182585182586182587182588182589182590182591182592182593182594182595182596182597182598182599182600182601182602182603182604182605182606182607182608182609182610182611182612182613182614182615182616182617182618182619182620182621182622182623182624182625182626182627182628182629182630182631182632182633182634182635182636182637182638182639182640182641182642182643182644182645182646182647182648182649182650182651182652182653182654182655182656182657182658182659182660182661182662182663182664182665182666182667182668182669182670182671182672182673182674182675182676182677182678182679182680182681182682182683182684182685182686182687182688182689182690182691182692182693182694182695182696182697182698182699182700182701182702182703182704182705182706182707182708182709182710182711182712182713182714182715182716182717182718182719182720182721182722182723182724182725182726182727182728182729182730182731182732182733182734182735182736182737182738182739182740182741182742182743182744182745182746182747182748182749182750182751182752182753182754182755182756182757182758182759182760182761182762182763182764182765182766182767182768182769182770182771182772182773182774182775182776182777182778182779182780182781182782182783182784182785182786182787182788182789182790182791182792182793182794182795182796182797182798182799182800182801182802182803182804182805182806182807182808182809182810182811182812182813182814182815182816182817182818182819182820182821182822182823182824182825182826182827182828182829182830182831182832182833182834182835182836182837182838182839182840182841182842182843182844182845182846182847182848182849182850182851182852182853182854182855182856182857182858182859182860182861182862182863182864182865182866182867182868182869182870182871182872182873182874182875182876182877182878182879182880182881182882182883182884182885182886182887182888182889182890182891182892182893182894182895182896182897182898182899182900182901182902182903182904182905182906182907182908182909182910182911182912182913182914182915182916182917182918182919182920182921182922182923182924182925182926182927182928182929182930182931182932182933182934182935182936182937182938182939182940182941182942182943182944182945182946182947182948182949182950182951182952182953182954182955182956182957182958182959182960182961182962182963182964182965182966182967182968182969182970182971182972182973182974182975182976182977182978182979182980182981182982182983182984182985182986182987182988182989182990182991182992182993182994182995182996182997182998182999183000183001183002183003183004183005183006183007183008183009183010183011183012183013183014183015183016183017183018183019183020183021183022183023183024183025183026183027183028183029183030183031183032183033183034183035183036183037183038183039183040183041183042183043183044183045183046183047183048183049183050183051183052183053183054183055183056183057183058183059183060183061183062183063183064183065183066183067183068183069183070183071183072183073183074183075183076183077183078183079183080183081183082183083183084183085183086183087183088183089183090183091183092183093183094183095183096183097183098183099183100183101183102183103183104183105183106183107183108183109183110183111183112183113183114183115183116183117183118183119183120183121183122183123183124183125183126183127183128183129183130183131183132183133183134183135183136183137183138183139183140183141183142183143183144183145183146183147183148183149183150183151183152183153183154183155183156183157183158183159183160183161183162183163183164183165183166183167183168183169183170183171183172183173183174183175183176183177183178183179183180183181183182183183183184183185183186183187183188183189183190183191183192183193183194183195183196183197183198183199183200183201183202183203183204183205183206183207183208183209183210183211183212183213183214183215183216183217183218183219183220183221183222183223183224183225183226183227183228183229183230183231183232183233183234183235183236183237183238183239183240183241183242183243183244183245183246183247183248183249183250183251183252183253183254183255183256183257183258183259183260183261183262183263183264183265183266183267183268183269183270183271183272183273183274183275183276183277183278183279183280183281183282183283183284183285183286183287183288183289183290183291183292183293183294183295183296183297183298183299183300183301183302183303183304183305183306183307183308183309183310183311183312183313183314183315183316183317183318183319183320183321183322183323183324183325183326183327183328183329183330183331183332183333183334183335183336183337183338183339183340183341183342183343183344183345183346183347183348183349183350183351183352183353183354183355183356183357183358183359183360183361183362183363183364183365183366183367183368183369183370183371183372183373183374183375183376183377183378183379183380183381183382183383183384183385183386183387183388183389183390183391183392183393183394183395183396183397183398183399183400183401183402183403183404183405183406183407183408183409183410183411183412183413183414183415183416183417183418183419183420183421183422183423183424183425183426183427183428183429183430183431183432183433183434183435183436183437183438183439183440183441183442183443183444183445183446183447183448183449183450183451183452183453183454183455183456183457183458183459183460183461183462183463183464183465183466183467183468183469183470183471183472183473183474183475183476183477183478183479183480183481183482183483183484183485183486183487183488183489183490183491183492183493183494183495183496183497183498183499183500183501183502183503183504183505183506183507183508183509183510183511183512183513183514183515183516183517183518183519183520183521183522183523183524183525183526183527183528183529183530183531183532183533183534183535183536183537183538183539183540183541183542183543183544183545183546183547183548183549183550183551183552183553183554183555183556183557183558183559183560183561183562183563183564183565183566183567183568183569183570183571183572183573183574183575183576183577183578183579183580183581183582183583183584183585183586183587183588183589183590183591183592183593183594183595183596183597183598183599183600183601183602183603183604183605183606183607183608183609183610183611183612183613183614183615183616183617183618183619183620183621183622183623183624183625183626183627183628183629183630183631183632183633183634183635183636183637183638183639183640183641183642183643183644183645183646183647183648183649183650183651183652183653183654183655183656183657183658183659183660183661183662183663183664183665183666183667183668183669183670183671183672183673183674183675183676183677183678183679183680183681183682183683183684183685183686183687183688183689183690183691183692183693183694183695183696183697183698183699183700183701183702183703183704183705183706183707183708183709183710183711183712183713183714183715183716183717183718183719183720183721183722183723183724183725183726183727183728183729183730183731183732183733183734183735183736183737183738183739183740183741183742183743183744183745183746183747183748183749183750183751183752183753183754183755183756183757183758183759183760183761183762183763183764183765183766183767183768183769183770183771183772183773183774183775183776183777183778183779183780183781183782183783183784183785183786183787183788183789183790183791183792183793183794183795183796183797183798183799183800183801183802183803183804183805183806183807183808183809183810183811183812183813183814183815183816183817183818183819183820183821183822183823183824183825183826183827183828183829183830183831183832183833183834183835183836183837183838183839183840183841183842183843183844183845183846183847183848183849183850183851183852183853183854183855183856183857183858183859183860183861183862183863183864183865183866183867183868183869183870183871183872183873183874183875183876183877183878183879183880183881183882183883183884183885183886183887183888183889183890183891183892183893183894183895183896183897183898183899183900183901183902183903183904183905183906183907183908183909183910183911183912183913183914183915183916183917183918183919183920183921183922183923183924183925183926183927183928183929183930183931183932183933183934183935183936183937183938183939183940183941183942183943183944183945183946183947183948183949183950183951183952183953183954183955183956183957183958183959183960183961183962183963183964183965183966183967183968183969183970183971183972183973183974183975183976183977183978183979183980183981183982183983183984183985183986183987183988183989183990183991183992183993183994183995183996183997183998183999184000184001184002184003184004184005184006184007184008184009184010184011184012184013184014184015184016184017184018184019184020184021184022184023184024184025184026184027184028184029184030184031184032184033184034184035184036184037184038184039184040184041184042184043184044184045184046184047184048184049184050184051184052184053184054184055184056184057184058184059184060184061184062184063184064184065184066184067184068184069184070184071184072184073184074184075184076184077184078184079184080184081184082184083184084184085184086184087184088184089184090184091184092184093184094184095184096184097184098184099184100184101184102184103184104184105184106184107184108184109184110184111184112184113184114184115184116184117184118184119184120184121184122184123184124184125184126184127184128184129184130184131184132184133184134184135184136184137184138184139184140184141184142184143184144184145184146184147184148184149184150184151184152184153184154184155184156184157184158184159184160184161184162184163184164184165184166184167184168184169184170184171184172184173184174184175184176184177184178184179184180184181184182184183184184184185184186184187184188184189184190184191184192184193184194184195184196184197184198184199184200184201184202184203184204184205184206184207184208184209184210184211184212184213184214184215184216184217184218184219184220184221184222184223184224184225184226184227184228184229184230184231184232184233184234184235184236184237184238184239184240184241184242184243184244184245184246184247184248184249184250184251184252184253184254184255184256184257184258184259184260184261184262184263184264184265184266184267184268184269184270184271184272184273184274184275184276184277184278184279184280184281184282184283184284184285184286184287184288184289184290184291184292184293184294184295184296184297184298184299184300184301184302184303184304184305184306184307184308184309184310184311184312184313184314184315184316184317184318184319184320184321184322184323184324184325184326184327184328184329184330184331184332184333184334184335184336184337184338184339184340184341184342184343184344184345184346184347184348184349184350184351184352184353184354184355184356184357184358184359184360184361184362184363184364184365184366184367184368184369184370184371184372184373184374184375184376184377184378184379184380184381184382184383184384184385184386184387184388184389184390184391184392184393184394184395184396184397184398184399184400184401184402184403184404184405184406184407184408184409184410184411184412184413184414184415184416184417184418184419184420184421184422184423184424184425184426184427184428184429184430184431184432184433184434184435184436184437184438184439184440184441184442184443184444184445184446184447184448184449184450184451184452184453184454184455184456184457184458184459184460184461184462184463184464184465184466184467184468184469184470184471184472184473184474184475184476184477184478184479184480184481184482184483184484184485184486184487184488184489184490184491184492184493184494184495184496184497184498184499184500184501184502184503184504184505184506184507184508184509184510184511184512184513184514184515184516184517184518184519184520184521184522184523184524184525184526184527184528184529184530184531184532184533184534184535184536184537184538184539184540184541184542184543184544184545184546184547184548184549184550184551184552184553184554184555184556184557184558184559184560184561184562184563184564184565184566184567184568184569184570184571184572184573184574184575184576184577184578184579184580184581184582184583184584184585184586184587184588184589184590184591184592184593184594184595184596184597184598184599184600184601184602184603184604184605184606184607184608184609184610184611184612184613184614184615184616184617184618184619184620184621184622184623184624184625184626184627184628184629184630184631184632184633184634184635184636184637184638184639184640184641184642184643184644184645184646184647184648184649184650184651184652184653184654184655184656184657184658184659184660184661184662184663184664184665184666184667184668184669184670184671184672184673184674184675184676184677184678184679184680184681184682184683184684184685184686184687184688184689184690184691184692184693184694184695184696184697184698184699184700184701184702184703184704184705184706184707184708184709184710184711184712184713184714184715184716184717184718184719184720184721184722184723184724184725184726184727184728184729184730184731184732184733184734184735184736184737184738184739184740184741184742184743184744184745184746184747184748184749184750184751184752184753184754184755184756184757184758184759184760184761184762184763184764184765184766184767184768184769184770184771184772184773184774184775184776184777184778184779184780184781184782184783184784184785184786184787184788184789184790184791184792184793184794184795184796184797184798184799184800184801184802184803184804184805184806184807184808184809184810184811184812184813184814184815184816184817184818184819184820184821184822184823184824184825184826184827184828184829184830184831184832184833184834184835184836184837184838184839184840184841184842184843184844184845184846184847184848184849184850184851184852184853184854184855184856184857184858184859184860184861184862184863184864184865184866184867184868184869184870184871184872184873184874184875184876184877184878184879184880184881184882184883184884184885184886184887184888184889184890184891184892184893184894184895184896184897184898184899184900184901184902184903184904184905184906184907184908184909184910184911184912184913184914184915184916184917184918184919184920184921184922184923184924184925184926184927184928184929184930184931184932184933184934184935184936184937184938184939184940184941184942184943184944184945184946184947184948184949184950184951184952184953184954184955184956184957184958184959184960184961184962184963184964184965184966
  1. /**
  2. * Cesium - https://github.com/AnalyticalGraphicsInc/cesium
  3. *
  4. * Copyright 2011-2016 Cesium Contributors
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * Columbus View (Pat. Pend.)
  19. *
  20. * Portions licensed separately.
  21. * See https://github.com/AnalyticalGraphicsInc/cesium/blob/master/LICENSE.md for full licensing details.
  22. */
  23. (function () {
  24. /**
  25. * @license almond 0.3.3 Copyright jQuery Foundation and other contributors.
  26. * Released under MIT license, http://github.com/requirejs/almond/LICENSE
  27. */
  28. //Going sloppy to avoid 'use strict' string cost, but strict practices should
  29. //be followed.
  30. /*global setTimeout: false */
  31. var requirejs, require, define;
  32. (function (undef) {
  33. var main, req, makeMap, handlers,
  34. defined = {},
  35. waiting = {},
  36. config = {},
  37. defining = {},
  38. hasOwn = Object.prototype.hasOwnProperty,
  39. aps = [].slice,
  40. jsSuffixRegExp = /\.js$/;
  41. function hasProp(obj, prop) {
  42. return hasOwn.call(obj, prop);
  43. }
  44. /**
  45. * Given a relative module name, like ./something, normalize it to
  46. * a real name that can be mapped to a path.
  47. * @param {String} name the relative name
  48. * @param {String} baseName a real name that the name arg is relative
  49. * to.
  50. * @returns {String} normalized name
  51. */
  52. function normalize(name, baseName) {
  53. var nameParts, nameSegment, mapValue, foundMap, lastIndex,
  54. foundI, foundStarMap, starI, i, j, part, normalizedBaseParts,
  55. baseParts = baseName && baseName.split("/"),
  56. map = config.map,
  57. starMap = (map && map['*']) || {};
  58. //Adjust any relative paths.
  59. if (name) {
  60. name = name.split('/');
  61. lastIndex = name.length - 1;
  62. // If wanting node ID compatibility, strip .js from end
  63. // of IDs. Have to do this here, and not in nameToUrl
  64. // because node allows either .js or non .js to map
  65. // to same file.
  66. if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
  67. name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
  68. }
  69. // Starts with a '.' so need the baseName
  70. if (name[0].charAt(0) === '.' && baseParts) {
  71. //Convert baseName to array, and lop off the last part,
  72. //so that . matches that 'directory' and not name of the baseName's
  73. //module. For instance, baseName of 'one/two/three', maps to
  74. //'one/two/three.js', but we want the directory, 'one/two' for
  75. //this normalization.
  76. normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
  77. name = normalizedBaseParts.concat(name);
  78. }
  79. //start trimDots
  80. for (i = 0; i < name.length; i++) {
  81. part = name[i];
  82. if (part === '.') {
  83. name.splice(i, 1);
  84. i -= 1;
  85. } else if (part === '..') {
  86. // If at the start, or previous value is still ..,
  87. // keep them so that when converted to a path it may
  88. // still work when converted to a path, even though
  89. // as an ID it is less than ideal. In larger point
  90. // releases, may be better to just kick out an error.
  91. if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') {
  92. continue;
  93. } else if (i > 0) {
  94. name.splice(i - 1, 2);
  95. i -= 2;
  96. }
  97. }
  98. }
  99. //end trimDots
  100. name = name.join('/');
  101. }
  102. //Apply map config if available.
  103. if ((baseParts || starMap) && map) {
  104. nameParts = name.split('/');
  105. for (i = nameParts.length; i > 0; i -= 1) {
  106. nameSegment = nameParts.slice(0, i).join("/");
  107. if (baseParts) {
  108. //Find the longest baseName segment match in the config.
  109. //So, do joins on the biggest to smallest lengths of baseParts.
  110. for (j = baseParts.length; j > 0; j -= 1) {
  111. mapValue = map[baseParts.slice(0, j).join('/')];
  112. //baseName segment has config, find if it has one for
  113. //this name.
  114. if (mapValue) {
  115. mapValue = mapValue[nameSegment];
  116. if (mapValue) {
  117. //Match, update name to the new value.
  118. foundMap = mapValue;
  119. foundI = i;
  120. break;
  121. }
  122. }
  123. }
  124. }
  125. if (foundMap) {
  126. break;
  127. }
  128. //Check for a star map match, but just hold on to it,
  129. //if there is a shorter segment match later in a matching
  130. //config, then favor over this star map.
  131. if (!foundStarMap && starMap && starMap[nameSegment]) {
  132. foundStarMap = starMap[nameSegment];
  133. starI = i;
  134. }
  135. }
  136. if (!foundMap && foundStarMap) {
  137. foundMap = foundStarMap;
  138. foundI = starI;
  139. }
  140. if (foundMap) {
  141. nameParts.splice(0, foundI, foundMap);
  142. name = nameParts.join('/');
  143. }
  144. }
  145. return name;
  146. }
  147. function makeRequire(relName, forceSync) {
  148. return function () {
  149. //A version of a require function that passes a moduleName
  150. //value for items that may need to
  151. //look up paths relative to the moduleName
  152. var args = aps.call(arguments, 0);
  153. //If first arg is not require('string'), and there is only
  154. //one arg, it is the array form without a callback. Insert
  155. //a null so that the following concat is correct.
  156. if (typeof args[0] !== 'string' && args.length === 1) {
  157. args.push(null);
  158. }
  159. return req.apply(undef, args.concat([relName, forceSync]));
  160. };
  161. }
  162. function makeNormalize(relName) {
  163. return function (name) {
  164. return normalize(name, relName);
  165. };
  166. }
  167. function makeLoad(depName) {
  168. return function (value) {
  169. defined[depName] = value;
  170. };
  171. }
  172. function callDep(name) {
  173. if (hasProp(waiting, name)) {
  174. var args = waiting[name];
  175. delete waiting[name];
  176. defining[name] = true;
  177. main.apply(undef, args);
  178. }
  179. if (!hasProp(defined, name) && !hasProp(defining, name)) {
  180. throw new Error('No ' + name);
  181. }
  182. return defined[name];
  183. }
  184. //Turns a plugin!resource to [plugin, resource]
  185. //with the plugin being undefined if the name
  186. //did not have a plugin prefix.
  187. function splitPrefix(name) {
  188. var prefix,
  189. index = name ? name.indexOf('!') : -1;
  190. if (index > -1) {
  191. prefix = name.substring(0, index);
  192. name = name.substring(index + 1, name.length);
  193. }
  194. return [prefix, name];
  195. }
  196. //Creates a parts array for a relName where first part is plugin ID,
  197. //second part is resource ID. Assumes relName has already been normalized.
  198. function makeRelParts(relName) {
  199. return relName ? splitPrefix(relName) : [];
  200. }
  201. /**
  202. * Makes a name map, normalizing the name, and using a plugin
  203. * for normalization if necessary. Grabs a ref to plugin
  204. * too, as an optimization.
  205. */
  206. makeMap = function (name, relParts) {
  207. var plugin,
  208. parts = splitPrefix(name),
  209. prefix = parts[0],
  210. relResourceName = relParts[1];
  211. name = parts[1];
  212. if (prefix) {
  213. prefix = normalize(prefix, relResourceName);
  214. plugin = callDep(prefix);
  215. }
  216. //Normalize according
  217. if (prefix) {
  218. if (plugin && plugin.normalize) {
  219. name = plugin.normalize(name, makeNormalize(relResourceName));
  220. } else {
  221. name = normalize(name, relResourceName);
  222. }
  223. } else {
  224. name = normalize(name, relResourceName);
  225. parts = splitPrefix(name);
  226. prefix = parts[0];
  227. name = parts[1];
  228. if (prefix) {
  229. plugin = callDep(prefix);
  230. }
  231. }
  232. //Using ridiculous property names for space reasons
  233. return {
  234. f: prefix ? prefix + '!' + name : name, //fullName
  235. n: name,
  236. pr: prefix,
  237. p: plugin
  238. };
  239. };
  240. function makeConfig(name) {
  241. return function () {
  242. return (config && config.config && config.config[name]) || {};
  243. };
  244. }
  245. handlers = {
  246. require: function (name) {
  247. return makeRequire(name);
  248. },
  249. exports: function (name) {
  250. var e = defined[name];
  251. if (typeof e !== 'undefined') {
  252. return e;
  253. } else {
  254. return (defined[name] = {});
  255. }
  256. },
  257. module: function (name) {
  258. return {
  259. id: name,
  260. uri: '',
  261. exports: defined[name],
  262. config: makeConfig(name)
  263. };
  264. }
  265. };
  266. main = function (name, deps, callback, relName) {
  267. var cjsModule, depName, ret, map, i, relParts,
  268. args = [],
  269. callbackType = typeof callback,
  270. usingExports;
  271. //Use name if no relName
  272. relName = relName || name;
  273. relParts = makeRelParts(relName);
  274. //Call the callback to define the module, if necessary.
  275. if (callbackType === 'undefined' || callbackType === 'function') {
  276. //Pull out the defined dependencies and pass the ordered
  277. //values to the callback.
  278. //Default to [require, exports, module] if no deps
  279. deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
  280. for (i = 0; i < deps.length; i += 1) {
  281. map = makeMap(deps[i], relParts);
  282. depName = map.f;
  283. //Fast path CommonJS standard dependencies.
  284. if (depName === "require") {
  285. args[i] = handlers.require(name);
  286. } else if (depName === "exports") {
  287. //CommonJS module spec 1.1
  288. args[i] = handlers.exports(name);
  289. usingExports = true;
  290. } else if (depName === "module") {
  291. //CommonJS module spec 1.1
  292. cjsModule = args[i] = handlers.module(name);
  293. } else if (hasProp(defined, depName) ||
  294. hasProp(waiting, depName) ||
  295. hasProp(defining, depName)) {
  296. args[i] = callDep(depName);
  297. } else if (map.p) {
  298. map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
  299. args[i] = defined[depName];
  300. } else {
  301. throw new Error(name + ' missing ' + depName);
  302. }
  303. }
  304. ret = callback ? callback.apply(defined[name], args) : undefined;
  305. if (name) {
  306. //If setting exports via "module" is in play,
  307. //favor that over return value and exports. After that,
  308. //favor a non-undefined return value over exports use.
  309. if (cjsModule && cjsModule.exports !== undef &&
  310. cjsModule.exports !== defined[name]) {
  311. defined[name] = cjsModule.exports;
  312. } else if (ret !== undef || !usingExports) {
  313. //Use the return value from the function.
  314. defined[name] = ret;
  315. }
  316. }
  317. } else if (name) {
  318. //May just be an object definition for the module. Only
  319. //worry about defining if have a module name.
  320. defined[name] = callback;
  321. }
  322. };
  323. requirejs = require = req = function (deps, callback, relName, forceSync, alt) {
  324. if (typeof deps === "string") {
  325. if (handlers[deps]) {
  326. //callback in this case is really relName
  327. return handlers[deps](callback);
  328. }
  329. //Just return the module wanted. In this scenario, the
  330. //deps arg is the module name, and second arg (if passed)
  331. //is just the relName.
  332. //Normalize module name, if it contains . or ..
  333. return callDep(makeMap(deps, makeRelParts(callback)).f);
  334. } else if (!deps.splice) {
  335. //deps is a config object, not an array.
  336. config = deps;
  337. if (config.deps) {
  338. req(config.deps, config.callback);
  339. }
  340. if (!callback) {
  341. return;
  342. }
  343. if (callback.splice) {
  344. //callback is an array, which means it is a dependency list.
  345. //Adjust args if there are dependencies
  346. deps = callback;
  347. callback = relName;
  348. relName = null;
  349. } else {
  350. deps = undef;
  351. }
  352. }
  353. //Support require(['a'])
  354. callback = callback || function () {};
  355. //If relName is a function, it is an errback handler,
  356. //so remove it.
  357. if (typeof relName === 'function') {
  358. relName = forceSync;
  359. forceSync = alt;
  360. }
  361. //Simulate async callback;
  362. if (forceSync) {
  363. main(undef, deps, callback, relName);
  364. } else {
  365. //Using a non-zero value because of concern for what old browsers
  366. //do, and latest browsers "upgrade" to 4 if lower value is used:
  367. //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
  368. //If want a value immediately, use require('id') instead -- something
  369. //that works in almond on the global level, but not guaranteed and
  370. //unlikely to work in other AMD implementations.
  371. setTimeout(function () {
  372. main(undef, deps, callback, relName);
  373. }, 4);
  374. }
  375. return req;
  376. };
  377. /**
  378. * Just drops the config on the floor, but returns req in case
  379. * the config return value is used.
  380. */
  381. req.config = function (cfg) {
  382. return req(cfg);
  383. };
  384. /**
  385. * Expose module registry for debugging and tooling
  386. */
  387. requirejs._defined = defined;
  388. define = function (name, deps, callback) {
  389. if (typeof name !== 'string') {
  390. throw new Error('See almond README: incorrect module build, no module name');
  391. }
  392. //This module may not have dependencies
  393. if (!deps.splice) {
  394. //deps is not an array, so probably means
  395. //an object literal or factory function for
  396. //the value. Adjust args.
  397. callback = deps;
  398. deps = [];
  399. }
  400. if (!hasProp(defined, name) && !hasProp(waiting, name)) {
  401. waiting[name] = [name, deps, callback];
  402. }
  403. };
  404. define.amd = {
  405. jQuery: true
  406. };
  407. }());
  408. /*global define*/
  409. define('Core/appendForwardSlash',[],function() {
  410. 'use strict';
  411. /**
  412. * @private
  413. */
  414. function appendForwardSlash(url) {
  415. if (url.length === 0 || url[url.length - 1] !== '/') {
  416. url = url + '/';
  417. }
  418. return url;
  419. }
  420. return appendForwardSlash;
  421. });
  422. /**
  423. @license
  424. when.js - https://github.com/cujojs/when
  425. MIT License (c) copyright B Cavalier & J Hann
  426. * A lightweight CommonJS Promises/A and when() implementation
  427. * when is part of the cujo.js family of libraries (http://cujojs.com/)
  428. *
  429. * Licensed under the MIT License at:
  430. * http://www.opensource.org/licenses/mit-license.php
  431. *
  432. * @version 1.7.1
  433. */
  434. (function(define) { 'use strict';
  435. define('ThirdParty/when',[],function () {
  436. var reduceArray, slice, undef;
  437. //
  438. // Public API
  439. //
  440. when.defer = defer; // Create a deferred
  441. when.resolve = resolve; // Create a resolved promise
  442. when.reject = reject; // Create a rejected promise
  443. when.join = join; // Join 2 or more promises
  444. when.all = all; // Resolve a list of promises
  445. when.map = map; // Array.map() for promises
  446. when.reduce = reduce; // Array.reduce() for promises
  447. when.any = any; // One-winner race
  448. when.some = some; // Multi-winner race
  449. when.chain = chain; // Make a promise trigger another resolver
  450. when.isPromise = isPromise; // Determine if a thing is a promise
  451. /**
  452. * Register an observer for a promise or immediate value.
  453. *
  454. * @param {*} promiseOrValue
  455. * @param {function?} [onFulfilled] callback to be called when promiseOrValue is
  456. * successfully fulfilled. If promiseOrValue is an immediate value, callback
  457. * will be invoked immediately.
  458. * @param {function?} [onRejected] callback to be called when promiseOrValue is
  459. * rejected.
  460. * @param {function?} [onProgress] callback to be called when progress updates
  461. * are issued for promiseOrValue.
  462. * @returns {Promise} a new {@link Promise} that will complete with the return
  463. * value of callback or errback or the completion value of promiseOrValue if
  464. * callback and/or errback is not supplied.
  465. */
  466. function when(promiseOrValue, onFulfilled, onRejected, onProgress) {
  467. // Get a trusted promise for the input promiseOrValue, and then
  468. // register promise handlers
  469. return resolve(promiseOrValue).then(onFulfilled, onRejected, onProgress);
  470. }
  471. /**
  472. * Returns promiseOrValue if promiseOrValue is a {@link Promise}, a new Promise if
  473. * promiseOrValue is a foreign promise, or a new, already-fulfilled {@link Promise}
  474. * whose value is promiseOrValue if promiseOrValue is an immediate value.
  475. *
  476. * @param {*} promiseOrValue
  477. * @returns Guaranteed to return a trusted Promise. If promiseOrValue is a when.js {@link Promise}
  478. * returns promiseOrValue, otherwise, returns a new, already-resolved, when.js {@link Promise}
  479. * whose resolution value is:
  480. * * the resolution value of promiseOrValue if it's a foreign promise, or
  481. * * promiseOrValue if it's a value
  482. */
  483. function resolve(promiseOrValue) {
  484. var promise, deferred;
  485. if(promiseOrValue instanceof Promise) {
  486. // It's a when.js promise, so we trust it
  487. promise = promiseOrValue;
  488. } else {
  489. // It's not a when.js promise. See if it's a foreign promise or a value.
  490. if(isPromise(promiseOrValue)) {
  491. // It's a thenable, but we don't know where it came from, so don't trust
  492. // its implementation entirely. Introduce a trusted middleman when.js promise
  493. deferred = defer();
  494. // IMPORTANT: This is the only place when.js should ever call .then() on an
  495. // untrusted promise. Don't expose the return value to the untrusted promise
  496. promiseOrValue.then(
  497. function(value) { deferred.resolve(value); },
  498. function(reason) { deferred.reject(reason); },
  499. function(update) { deferred.progress(update); }
  500. );
  501. promise = deferred.promise;
  502. } else {
  503. // It's a value, not a promise. Create a resolved promise for it.
  504. promise = fulfilled(promiseOrValue);
  505. }
  506. }
  507. return promise;
  508. }
  509. /**
  510. * Returns a rejected promise for the supplied promiseOrValue. The returned
  511. * promise will be rejected with:
  512. * - promiseOrValue, if it is a value, or
  513. * - if promiseOrValue is a promise
  514. * - promiseOrValue's value after it is fulfilled
  515. * - promiseOrValue's reason after it is rejected
  516. * @param {*} promiseOrValue the rejected value of the returned {@link Promise}
  517. * @returns {Promise} rejected {@link Promise}
  518. */
  519. function reject(promiseOrValue) {
  520. return when(promiseOrValue, rejected);
  521. }
  522. /**
  523. * Trusted Promise constructor. A Promise created from this constructor is
  524. * a trusted when.js promise. Any other duck-typed promise is considered
  525. * untrusted.
  526. * @constructor
  527. * @name Promise
  528. */
  529. function Promise(then) {
  530. this.then = then;
  531. }
  532. Promise.prototype = {
  533. /**
  534. * Register a callback that will be called when a promise is
  535. * fulfilled or rejected. Optionally also register a progress handler.
  536. * Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress)
  537. * @param {function?} [onFulfilledOrRejected]
  538. * @param {function?} [onProgress]
  539. * @returns {Promise}
  540. */
  541. always: function(onFulfilledOrRejected, onProgress) {
  542. return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress);
  543. },
  544. /**
  545. * Register a rejection handler. Shortcut for .then(undefined, onRejected)
  546. * @param {function?} onRejected
  547. * @returns {Promise}
  548. */
  549. otherwise: function(onRejected) {
  550. return this.then(undef, onRejected);
  551. },
  552. /**
  553. * Shortcut for .then(function() { return value; })
  554. * @param {*} value
  555. * @returns {Promise} a promise that:
  556. * - is fulfilled if value is not a promise, or
  557. * - if value is a promise, will fulfill with its value, or reject
  558. * with its reason.
  559. */
  560. yield: function(value) {
  561. return this.then(function() {
  562. return value;
  563. });
  564. },
  565. /**
  566. * Assumes that this promise will fulfill with an array, and arranges
  567. * for the onFulfilled to be called with the array as its argument list
  568. * i.e. onFulfilled.spread(undefined, array).
  569. * @param {function} onFulfilled function to receive spread arguments
  570. * @returns {Promise}
  571. */
  572. spread: function(onFulfilled) {
  573. return this.then(function(array) {
  574. // array may contain promises, so resolve its contents.
  575. return all(array, function(array) {
  576. return onFulfilled.apply(undef, array);
  577. });
  578. });
  579. }
  580. };
  581. /**
  582. * Create an already-resolved promise for the supplied value
  583. * @private
  584. *
  585. * @param {*} value
  586. * @returns {Promise} fulfilled promise
  587. */
  588. function fulfilled(value) {
  589. var p = new Promise(function(onFulfilled) {
  590. // TODO: Promises/A+ check typeof onFulfilled
  591. try {
  592. return resolve(onFulfilled ? onFulfilled(value) : value);
  593. } catch(e) {
  594. return rejected(e);
  595. }
  596. });
  597. return p;
  598. }
  599. /**
  600. * Create an already-rejected {@link Promise} with the supplied
  601. * rejection reason.
  602. * @private
  603. *
  604. * @param {*} reason
  605. * @returns {Promise} rejected promise
  606. */
  607. function rejected(reason) {
  608. var p = new Promise(function(_, onRejected) {
  609. // TODO: Promises/A+ check typeof onRejected
  610. try {
  611. return onRejected ? resolve(onRejected(reason)) : rejected(reason);
  612. } catch(e) {
  613. return rejected(e);
  614. }
  615. });
  616. return p;
  617. }
  618. /**
  619. * Creates a new, Deferred with fully isolated resolver and promise parts,
  620. * either or both of which may be given out safely to consumers.
  621. * The Deferred itself has the full API: resolve, reject, progress, and
  622. * then. The resolver has resolve, reject, and progress. The promise
  623. * only has then.
  624. *
  625. * @returns {Deferred}
  626. */
  627. function defer() {
  628. var deferred, promise, handlers, progressHandlers,
  629. _then, _progress, _resolve;
  630. /**
  631. * The promise for the new deferred
  632. * @type {Promise}
  633. */
  634. promise = new Promise(then);
  635. /**
  636. * The full Deferred object, with {@link Promise} and {@link Resolver} parts
  637. * @class Deferred
  638. * @name Deferred
  639. */
  640. deferred = {
  641. then: then, // DEPRECATED: use deferred.promise.then
  642. resolve: promiseResolve,
  643. reject: promiseReject,
  644. // TODO: Consider renaming progress() to notify()
  645. progress: promiseProgress,
  646. promise: promise,
  647. resolver: {
  648. resolve: promiseResolve,
  649. reject: promiseReject,
  650. progress: promiseProgress
  651. }
  652. };
  653. handlers = [];
  654. progressHandlers = [];
  655. /**
  656. * Pre-resolution then() that adds the supplied callback, errback, and progback
  657. * functions to the registered listeners
  658. * @private
  659. *
  660. * @param {function?} [onFulfilled] resolution handler
  661. * @param {function?} [onRejected] rejection handler
  662. * @param {function?} [onProgress] progress handler
  663. */
  664. _then = function(onFulfilled, onRejected, onProgress) {
  665. // TODO: Promises/A+ check typeof onFulfilled, onRejected, onProgress
  666. var deferred, progressHandler;
  667. deferred = defer();
  668. progressHandler = typeof onProgress === 'function'
  669. ? function(update) {
  670. try {
  671. // Allow progress handler to transform progress event
  672. deferred.progress(onProgress(update));
  673. } catch(e) {
  674. // Use caught value as progress
  675. deferred.progress(e);
  676. }
  677. }
  678. : function(update) { deferred.progress(update); };
  679. handlers.push(function(promise) {
  680. promise.then(onFulfilled, onRejected)
  681. .then(deferred.resolve, deferred.reject, progressHandler);
  682. });
  683. progressHandlers.push(progressHandler);
  684. return deferred.promise;
  685. };
  686. /**
  687. * Issue a progress event, notifying all progress listeners
  688. * @private
  689. * @param {*} update progress event payload to pass to all listeners
  690. */
  691. _progress = function(update) {
  692. processQueue(progressHandlers, update);
  693. return update;
  694. };
  695. /**
  696. * Transition from pre-resolution state to post-resolution state, notifying
  697. * all listeners of the resolution or rejection
  698. * @private
  699. * @param {*} value the value of this deferred
  700. */
  701. _resolve = function(value) {
  702. value = resolve(value);
  703. // Replace _then with one that directly notifies with the result.
  704. _then = value.then;
  705. // Replace _resolve so that this Deferred can only be resolved once
  706. _resolve = resolve;
  707. // Make _progress a noop, to disallow progress for the resolved promise.
  708. _progress = noop;
  709. // Notify handlers
  710. processQueue(handlers, value);
  711. // Free progressHandlers array since we'll never issue progress events
  712. progressHandlers = handlers = undef;
  713. return value;
  714. };
  715. return deferred;
  716. /**
  717. * Wrapper to allow _then to be replaced safely
  718. * @param {function?} [onFulfilled] resolution handler
  719. * @param {function?} [onRejected] rejection handler
  720. * @param {function?} [onProgress] progress handler
  721. * @returns {Promise} new promise
  722. */
  723. function then(onFulfilled, onRejected, onProgress) {
  724. // TODO: Promises/A+ check typeof onFulfilled, onRejected, onProgress
  725. return _then(onFulfilled, onRejected, onProgress);
  726. }
  727. /**
  728. * Wrapper to allow _resolve to be replaced
  729. */
  730. function promiseResolve(val) {
  731. return _resolve(val);
  732. }
  733. /**
  734. * Wrapper to allow _reject to be replaced
  735. */
  736. function promiseReject(err) {
  737. return _resolve(rejected(err));
  738. }
  739. /**
  740. * Wrapper to allow _progress to be replaced
  741. */
  742. function promiseProgress(update) {
  743. return _progress(update);
  744. }
  745. }
  746. /**
  747. * Determines if promiseOrValue is a promise or not. Uses the feature
  748. * test from http://wiki.commonjs.org/wiki/Promises/A to determine if
  749. * promiseOrValue is a promise.
  750. *
  751. * @param {*} promiseOrValue anything
  752. * @returns {boolean} true if promiseOrValue is a {@link Promise}
  753. */
  754. function isPromise(promiseOrValue) {
  755. return promiseOrValue && typeof promiseOrValue.then === 'function';
  756. }
  757. /**
  758. * Initiates a competitive race, returning a promise that will resolve when
  759. * howMany of the supplied promisesOrValues have resolved, or will reject when
  760. * it becomes impossible for howMany to resolve, for example, when
  761. * (promisesOrValues.length - howMany) + 1 input promises reject.
  762. *
  763. * @param {Array} promisesOrValues array of anything, may contain a mix
  764. * of promises and values
  765. * @param howMany {number} number of promisesOrValues to resolve
  766. * @param {function?} [onFulfilled] resolution handler
  767. * @param {function?} [onRejected] rejection handler
  768. * @param {function?} [onProgress] progress handler
  769. * @returns {Promise} promise that will resolve to an array of howMany values that
  770. * resolved first, or will reject with an array of (promisesOrValues.length - howMany) + 1
  771. * rejection reasons.
  772. */
  773. function some(promisesOrValues, howMany, onFulfilled, onRejected, onProgress) {
  774. checkCallbacks(2, arguments);
  775. return when(promisesOrValues, function(promisesOrValues) {
  776. var toResolve, toReject, values, reasons, deferred, fulfillOne, rejectOne, progress, len, i;
  777. len = promisesOrValues.length >>> 0;
  778. toResolve = Math.max(0, Math.min(howMany, len));
  779. values = [];
  780. toReject = (len - toResolve) + 1;
  781. reasons = [];
  782. deferred = defer();
  783. // No items in the input, resolve immediately
  784. if (!toResolve) {
  785. deferred.resolve(values);
  786. } else {
  787. progress = deferred.progress;
  788. rejectOne = function(reason) {
  789. reasons.push(reason);
  790. if(!--toReject) {
  791. fulfillOne = rejectOne = noop;
  792. deferred.reject(reasons);
  793. }
  794. };
  795. fulfillOne = function(val) {
  796. // This orders the values based on promise resolution order
  797. // Another strategy would be to use the original position of
  798. // the corresponding promise.
  799. values.push(val);
  800. if (!--toResolve) {
  801. fulfillOne = rejectOne = noop;
  802. deferred.resolve(values);
  803. }
  804. };
  805. for(i = 0; i < len; ++i) {
  806. if(i in promisesOrValues) {
  807. when(promisesOrValues[i], fulfiller, rejecter, progress);
  808. }
  809. }
  810. }
  811. return deferred.then(onFulfilled, onRejected, onProgress);
  812. function rejecter(reason) {
  813. rejectOne(reason);
  814. }
  815. function fulfiller(val) {
  816. fulfillOne(val);
  817. }
  818. });
  819. }
  820. /**
  821. * Initiates a competitive race, returning a promise that will resolve when
  822. * any one of the supplied promisesOrValues has resolved or will reject when
  823. * *all* promisesOrValues have rejected.
  824. *
  825. * @param {Array|Promise} promisesOrValues array of anything, may contain a mix
  826. * of {@link Promise}s and values
  827. * @param {function?} [onFulfilled] resolution handler
  828. * @param {function?} [onRejected] rejection handler
  829. * @param {function?} [onProgress] progress handler
  830. * @returns {Promise} promise that will resolve to the value that resolved first, or
  831. * will reject with an array of all rejected inputs.
  832. */
  833. function any(promisesOrValues, onFulfilled, onRejected, onProgress) {
  834. function unwrapSingleResult(val) {
  835. return onFulfilled ? onFulfilled(val[0]) : val[0];
  836. }
  837. return some(promisesOrValues, 1, unwrapSingleResult, onRejected, onProgress);
  838. }
  839. /**
  840. * Return a promise that will resolve only once all the supplied promisesOrValues
  841. * have resolved. The resolution value of the returned promise will be an array
  842. * containing the resolution values of each of the promisesOrValues.
  843. * @memberOf when
  844. *
  845. * @param {Array|Promise} promisesOrValues array of anything, may contain a mix
  846. * of {@link Promise}s and values
  847. * @param {function?} [onFulfilled] resolution handler
  848. * @param {function?} [onRejected] rejection handler
  849. * @param {function?} [onProgress] progress handler
  850. * @returns {Promise}
  851. */
  852. function all(promisesOrValues, onFulfilled, onRejected, onProgress) {
  853. checkCallbacks(1, arguments);
  854. return map(promisesOrValues, identity).then(onFulfilled, onRejected, onProgress);
  855. }
  856. /**
  857. * Joins multiple promises into a single returned promise.
  858. * @returns {Promise} a promise that will fulfill when *all* the input promises
  859. * have fulfilled, or will reject when *any one* of the input promises rejects.
  860. */
  861. function join(/* ...promises */) {
  862. return map(arguments, identity);
  863. }
  864. /**
  865. * Traditional map function, similar to `Array.prototype.map()`, but allows
  866. * input to contain {@link Promise}s and/or values, and mapFunc may return
  867. * either a value or a {@link Promise}
  868. *
  869. * @param {Array|Promise} promise array of anything, may contain a mix
  870. * of {@link Promise}s and values
  871. * @param {function} mapFunc mapping function mapFunc(value) which may return
  872. * either a {@link Promise} or value
  873. * @returns {Promise} a {@link Promise} that will resolve to an array containing
  874. * the mapped output values.
  875. */
  876. function map(promise, mapFunc) {
  877. return when(promise, function(array) {
  878. var results, len, toResolve, resolve, i, d;
  879. // Since we know the resulting length, we can preallocate the results
  880. // array to avoid array expansions.
  881. toResolve = len = array.length >>> 0;
  882. results = [];
  883. d = defer();
  884. if(!toResolve) {
  885. d.resolve(results);
  886. } else {
  887. resolve = function resolveOne(item, i) {
  888. when(item, mapFunc).then(function(mapped) {
  889. results[i] = mapped;
  890. if(!--toResolve) {
  891. d.resolve(results);
  892. }
  893. }, d.reject);
  894. };
  895. // Since mapFunc may be async, get all invocations of it into flight
  896. for(i = 0; i < len; i++) {
  897. if(i in array) {
  898. resolve(array[i], i);
  899. } else {
  900. --toResolve;
  901. }
  902. }
  903. }
  904. return d.promise;
  905. });
  906. }
  907. /**
  908. * Traditional reduce function, similar to `Array.prototype.reduce()`, but
  909. * input may contain promises and/or values, and reduceFunc
  910. * may return either a value or a promise, *and* initialValue may
  911. * be a promise for the starting value.
  912. *
  913. * @param {Array|Promise} promise array or promise for an array of anything,
  914. * may contain a mix of promises and values.
  915. * @param {function} reduceFunc reduce function reduce(currentValue, nextValue, index, total),
  916. * where total is the total number of items being reduced, and will be the same
  917. * in each call to reduceFunc.
  918. * @returns {Promise} that will resolve to the final reduced value
  919. */
  920. function reduce(promise, reduceFunc /*, initialValue */) {
  921. var args = slice.call(arguments, 1);
  922. return when(promise, function(array) {
  923. var total;
  924. total = array.length;
  925. // Wrap the supplied reduceFunc with one that handles promises and then
  926. // delegates to the supplied.
  927. args[0] = function (current, val, i) {
  928. return when(current, function (c) {
  929. return when(val, function (value) {
  930. return reduceFunc(c, value, i, total);
  931. });
  932. });
  933. };
  934. return reduceArray.apply(array, args);
  935. });
  936. }
  937. /**
  938. * Ensure that resolution of promiseOrValue will trigger resolver with the
  939. * value or reason of promiseOrValue, or instead with resolveValue if it is provided.
  940. *
  941. * @param promiseOrValue
  942. * @param {Object} resolver
  943. * @param {function} resolver.resolve
  944. * @param {function} resolver.reject
  945. * @param {*} [resolveValue]
  946. * @returns {Promise}
  947. */
  948. function chain(promiseOrValue, resolver, resolveValue) {
  949. var useResolveValue = arguments.length > 2;
  950. return when(promiseOrValue,
  951. function(val) {
  952. val = useResolveValue ? resolveValue : val;
  953. resolver.resolve(val);
  954. return val;
  955. },
  956. function(reason) {
  957. resolver.reject(reason);
  958. return rejected(reason);
  959. },
  960. resolver.progress
  961. );
  962. }
  963. //
  964. // Utility functions
  965. //
  966. /**
  967. * Apply all functions in queue to value
  968. * @param {Array} queue array of functions to execute
  969. * @param {*} value argument passed to each function
  970. */
  971. function processQueue(queue, value) {
  972. var handler, i = 0;
  973. while (handler = queue[i++]) {
  974. handler(value);
  975. }
  976. }
  977. /**
  978. * Helper that checks arrayOfCallbacks to ensure that each element is either
  979. * a function, or null or undefined.
  980. * @private
  981. * @param {number} start index at which to start checking items in arrayOfCallbacks
  982. * @param {Array} arrayOfCallbacks array to check
  983. * @throws {Error} if any element of arrayOfCallbacks is something other than
  984. * a functions, null, or undefined.
  985. */
  986. function checkCallbacks(start, arrayOfCallbacks) {
  987. // TODO: Promises/A+ update type checking and docs
  988. var arg, i = arrayOfCallbacks.length;
  989. while(i > start) {
  990. arg = arrayOfCallbacks[--i];
  991. if (arg != null && typeof arg != 'function') {
  992. throw new Error('arg '+i+' must be a function');
  993. }
  994. }
  995. }
  996. /**
  997. * No-Op function used in method replacement
  998. * @private
  999. */
  1000. function noop() {}
  1001. slice = [].slice;
  1002. // ES5 reduce implementation if native not available
  1003. // See: http://es5.github.com/#x15.4.4.21 as there are many
  1004. // specifics and edge cases.
  1005. reduceArray = [].reduce ||
  1006. function(reduceFunc /*, initialValue */) {
  1007. /*jshint maxcomplexity: 7*/
  1008. // ES5 dictates that reduce.length === 1
  1009. // This implementation deviates from ES5 spec in the following ways:
  1010. // 1. It does not check if reduceFunc is a Callable
  1011. var arr, args, reduced, len, i;
  1012. i = 0;
  1013. // This generates a jshint warning, despite being valid
  1014. // "Missing 'new' prefix when invoking a constructor."
  1015. // See https://github.com/jshint/jshint/issues/392
  1016. arr = Object(this);
  1017. len = arr.length >>> 0;
  1018. args = arguments;
  1019. // If no initialValue, use first item of array (we know length !== 0 here)
  1020. // and adjust i to start at second item
  1021. if(args.length <= 1) {
  1022. // Skip to the first real element in the array
  1023. for(;;) {
  1024. if(i in arr) {
  1025. reduced = arr[i++];
  1026. break;
  1027. }
  1028. // If we reached the end of the array without finding any real
  1029. // elements, it's a TypeError
  1030. if(++i >= len) {
  1031. throw new TypeError();
  1032. }
  1033. }
  1034. } else {
  1035. // If initialValue provided, use it
  1036. reduced = args[1];
  1037. }
  1038. // Do the actual reduce
  1039. for(;i < len; ++i) {
  1040. // Skip holes
  1041. if(i in arr) {
  1042. reduced = reduceFunc(reduced, arr[i], i, arr);
  1043. }
  1044. }
  1045. return reduced;
  1046. };
  1047. function identity(x) {
  1048. return x;
  1049. }
  1050. return when;
  1051. });
  1052. })(typeof define == 'function' && define.amd
  1053. ? define
  1054. : function (factory) { typeof exports === 'object'
  1055. ? (module.exports = factory())
  1056. : (this.when = factory());
  1057. }
  1058. // Boilerplate for AMD, Node, and browser global
  1059. );
  1060. /*global define*/
  1061. define('Core/defined',[],function() {
  1062. 'use strict';
  1063. /**
  1064. * @exports defined
  1065. *
  1066. * @param {Object} value The object.
  1067. * @returns {Boolean} Returns true if the object is defined, returns false otherwise.
  1068. *
  1069. * @example
  1070. * if (Cesium.defined(positions)) {
  1071. * doSomething();
  1072. * } else {
  1073. * doSomethingElse();
  1074. * }
  1075. */
  1076. function defined(value) {
  1077. return value !== undefined && value !== null;
  1078. }
  1079. return defined;
  1080. });
  1081. /*global define*/
  1082. define('Core/defineProperties',[
  1083. './defined'
  1084. ], function(
  1085. defined) {
  1086. 'use strict';
  1087. var definePropertyWorks = (function() {
  1088. try {
  1089. return 'x' in Object.defineProperty({}, 'x', {});
  1090. } catch (e) {
  1091. return false;
  1092. }
  1093. })();
  1094. /**
  1095. * Defines properties on an object, using Object.defineProperties if available,
  1096. * otherwise returns the object unchanged. This function should be used in
  1097. * setup code to prevent errors from completely halting JavaScript execution
  1098. * in legacy browsers.
  1099. *
  1100. * @private
  1101. *
  1102. * @exports defineProperties
  1103. */
  1104. var defineProperties = Object.defineProperties;
  1105. if (!definePropertyWorks || !defined(defineProperties)) {
  1106. defineProperties = function(o) {
  1107. return o;
  1108. };
  1109. }
  1110. return defineProperties;
  1111. });
  1112. /*global define*/
  1113. define('Core/DeveloperError',[
  1114. './defined'
  1115. ], function(
  1116. defined) {
  1117. 'use strict';
  1118. /**
  1119. * Constructs an exception object that is thrown due to a developer error, e.g., invalid argument,
  1120. * argument out of range, etc. This exception should only be thrown during development;
  1121. * it usually indicates a bug in the calling code. This exception should never be
  1122. * caught; instead the calling code should strive not to generate it.
  1123. * <br /><br />
  1124. * On the other hand, a {@link RuntimeError} indicates an exception that may
  1125. * be thrown at runtime, e.g., out of memory, that the calling code should be prepared
  1126. * to catch.
  1127. *
  1128. * @alias DeveloperError
  1129. * @constructor
  1130. * @extends Error
  1131. *
  1132. * @param {String} [message] The error message for this exception.
  1133. *
  1134. * @see RuntimeError
  1135. */
  1136. function DeveloperError(message) {
  1137. /**
  1138. * 'DeveloperError' indicating that this exception was thrown due to a developer error.
  1139. * @type {String}
  1140. * @readonly
  1141. */
  1142. this.name = 'DeveloperError';
  1143. /**
  1144. * The explanation for why this exception was thrown.
  1145. * @type {String}
  1146. * @readonly
  1147. */
  1148. this.message = message;
  1149. //Browsers such as IE don't have a stack property until you actually throw the error.
  1150. var stack;
  1151. try {
  1152. throw new Error();
  1153. } catch (e) {
  1154. stack = e.stack;
  1155. }
  1156. /**
  1157. * The stack trace of this exception, if available.
  1158. * @type {String}
  1159. * @readonly
  1160. */
  1161. this.stack = stack;
  1162. }
  1163. if (defined(Object.create)) {
  1164. DeveloperError.prototype = Object.create(Error.prototype);
  1165. DeveloperError.prototype.constructor = DeveloperError;
  1166. }
  1167. DeveloperError.prototype.toString = function() {
  1168. var str = this.name + ': ' + this.message;
  1169. if (defined(this.stack)) {
  1170. str += '\n' + this.stack.toString();
  1171. }
  1172. return str;
  1173. };
  1174. /**
  1175. * @private
  1176. */
  1177. DeveloperError.throwInstantiationError = function() {
  1178. throw new DeveloperError('This function defines an interface and should not be called directly.');
  1179. };
  1180. return DeveloperError;
  1181. });
  1182. /*global define*/
  1183. define('Core/Credit',[
  1184. './defined',
  1185. './defineProperties',
  1186. './DeveloperError'
  1187. ], function(
  1188. defined,
  1189. defineProperties,
  1190. DeveloperError) {
  1191. 'use strict';
  1192. var nextCreditId = 0;
  1193. var creditToId = {};
  1194. /**
  1195. * A credit contains data pertaining to how to display attributions/credits for certain content on the screen.
  1196. *
  1197. * @param {String} [text] The text to be displayed on the screen if no imageUrl is specified.
  1198. * @param {String} [imageUrl] The source location for an image
  1199. * @param {String} [link] A URL location for which the credit will be hyperlinked
  1200. *
  1201. * @alias Credit
  1202. * @constructor
  1203. *
  1204. * @example
  1205. * //Create a credit with a tooltip, image and link
  1206. * var credit = new Cesium.Credit('Cesium', '/images/cesium_logo.png', 'http://cesiumjs.org/');
  1207. */
  1208. function Credit(text, imageUrl, link) {
  1209. var hasLink = (defined(link));
  1210. var hasImage = (defined(imageUrl));
  1211. var hasText = (defined(text));
  1212. if (!hasText && !hasImage && !hasLink) {
  1213. throw new DeveloperError('text, imageUrl or link is required');
  1214. }
  1215. if (!hasText && !hasImage) {
  1216. text = link;
  1217. }
  1218. this._text = text;
  1219. this._imageUrl = imageUrl;
  1220. this._link = link;
  1221. this._hasLink = hasLink;
  1222. this._hasImage = hasImage;
  1223. // Credits are immutable so generate an id to use to optimize equal()
  1224. var id;
  1225. var key = JSON.stringify([text, imageUrl, link]);
  1226. if (defined(creditToId[key])) {
  1227. id = creditToId[key];
  1228. } else {
  1229. id = nextCreditId++;
  1230. creditToId[key] = id;
  1231. }
  1232. this._id = id;
  1233. }
  1234. defineProperties(Credit.prototype, {
  1235. /**
  1236. * The credit text
  1237. * @memberof Credit.prototype
  1238. * @type {String}
  1239. * @readonly
  1240. */
  1241. text : {
  1242. get : function() {
  1243. return this._text;
  1244. }
  1245. },
  1246. /**
  1247. * The source location for the image.
  1248. * @memberof Credit.prototype
  1249. * @type {String}
  1250. * @readonly
  1251. */
  1252. imageUrl : {
  1253. get : function() {
  1254. return this._imageUrl;
  1255. }
  1256. },
  1257. /**
  1258. * A URL location for the credit hyperlink
  1259. * @memberof Credit.prototype
  1260. * @type {String}
  1261. * @readonly
  1262. */
  1263. link : {
  1264. get : function() {
  1265. return this._link;
  1266. }
  1267. },
  1268. /**
  1269. * @memberof Credit.prototype
  1270. * @type {Number}
  1271. * @readonly
  1272. *
  1273. * @private
  1274. */
  1275. id : {
  1276. get : function() {
  1277. return this._id;
  1278. }
  1279. }
  1280. });
  1281. /**
  1282. * Returns true if the credit has an imageUrl
  1283. *
  1284. * @returns {Boolean}
  1285. */
  1286. Credit.prototype.hasImage = function() {
  1287. return this._hasImage;
  1288. };
  1289. /**
  1290. * Returns true if the credit has a link
  1291. *
  1292. * @returns {Boolean}
  1293. */
  1294. Credit.prototype.hasLink = function() {
  1295. return this._hasLink;
  1296. };
  1297. /**
  1298. * Returns true if the credits are equal
  1299. *
  1300. * @param {Credit} left The first credit
  1301. * @param {Credit} right The second credit
  1302. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  1303. */
  1304. Credit.equals = function(left, right) {
  1305. return (left === right) ||
  1306. ((defined(left)) &&
  1307. (defined(right)) &&
  1308. (left._id === right._id));
  1309. };
  1310. /**
  1311. * Returns true if the credits are equal
  1312. *
  1313. * @param {Credit} credits The credit to compare to.
  1314. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  1315. */
  1316. Credit.prototype.equals = function(credit) {
  1317. return Credit.equals(this, credit);
  1318. };
  1319. return Credit;
  1320. });
  1321. /*global define*/
  1322. define('Core/freezeObject',[
  1323. './defined'
  1324. ], function(
  1325. defined) {
  1326. 'use strict';
  1327. /**
  1328. * Freezes an object, using Object.freeze if available, otherwise returns
  1329. * the object unchanged. This function should be used in setup code to prevent
  1330. * errors from completely halting JavaScript execution in legacy browsers.
  1331. *
  1332. * @private
  1333. *
  1334. * @exports freezeObject
  1335. */
  1336. var freezeObject = Object.freeze;
  1337. if (!defined(freezeObject)) {
  1338. freezeObject = function(o) {
  1339. return o;
  1340. };
  1341. }
  1342. return freezeObject;
  1343. });
  1344. /*global define*/
  1345. define('Core/defaultValue',[
  1346. './freezeObject'
  1347. ], function(
  1348. freezeObject) {
  1349. 'use strict';
  1350. /**
  1351. * Returns the first parameter if not undefined, otherwise the second parameter.
  1352. * Useful for setting a default value for a parameter.
  1353. *
  1354. * @exports defaultValue
  1355. *
  1356. * @param {*} a
  1357. * @param {*} b
  1358. * @returns {*} Returns the first parameter if not undefined, otherwise the second parameter.
  1359. *
  1360. * @example
  1361. * param = Cesium.defaultValue(param, 'default');
  1362. */
  1363. function defaultValue(a, b) {
  1364. if (a !== undefined) {
  1365. return a;
  1366. }
  1367. return b;
  1368. }
  1369. /**
  1370. * A frozen empty object that can be used as the default value for options passed as
  1371. * an object literal.
  1372. */
  1373. defaultValue.EMPTY_OBJECT = freezeObject({});
  1374. return defaultValue;
  1375. });
  1376. /*global define*/
  1377. define('Core/isArray',[
  1378. './defined'
  1379. ], function(
  1380. defined) {
  1381. 'use strict';
  1382. /**
  1383. * Tests an object to see if it is an array.
  1384. * @exports isArray
  1385. *
  1386. * @param {Object} value The value to test.
  1387. * @returns {Boolean} true if the value is an array, false otherwise.
  1388. */
  1389. var isArray = Array.isArray;
  1390. if (!defined(isArray)) {
  1391. isArray = function(value) {
  1392. return Object.prototype.toString.call(value) === '[object Array]';
  1393. };
  1394. }
  1395. return isArray;
  1396. });
  1397. /*global define*/
  1398. define('Core/Check',[
  1399. './defaultValue',
  1400. './defined',
  1401. './DeveloperError',
  1402. './isArray'
  1403. ], function(
  1404. defaultValue,
  1405. defined,
  1406. DeveloperError,
  1407. isArray) {
  1408. 'use strict';
  1409. /**
  1410. * Contains functions for checking that supplied arguments are of a specified type
  1411. * or meet specified conditions
  1412. * @private
  1413. */
  1414. var Check = {};
  1415. /**
  1416. * Contains type checking functions, all using the typeof operator
  1417. */
  1418. Check.typeOf = {};
  1419. /**
  1420. * Contains functions for checking numeric conditions such as minimum and maximum values
  1421. */
  1422. Check.numeric = {};
  1423. function getUndefinedErrorMessage(name) {
  1424. return name + ' was required but undefined.';
  1425. }
  1426. function getFailedTypeErrorMessage(actual, expected, name) {
  1427. return 'Expected ' + name + ' to be typeof ' + expected + ', got ' + actual;
  1428. }
  1429. /**
  1430. * Throws if test is not defined
  1431. *
  1432. * @param {*} test The value that is to be checked
  1433. * @param {String} name The name of the variable being tested
  1434. * @exception {DeveloperError} test must be defined
  1435. */
  1436. Check.defined = function (test, name) {
  1437. if (!defined(test)) {
  1438. throw new DeveloperError(getUndefinedErrorMessage(name));
  1439. }
  1440. };
  1441. /**
  1442. * Throws if test is greater than maximum
  1443. *
  1444. * @param {Number} test The value to test
  1445. * @param {Number} maximum The maximum allowed value
  1446. * @exception {DeveloperError} test must not be greater than maximum
  1447. * @exception {DeveloperError} Both test and maximum must be typeof 'number'
  1448. */
  1449. Check.numeric.maximum = function (test, maximum) {
  1450. Check.typeOf.number(test);
  1451. Check.typeOf.number(maximum);
  1452. if (test > maximum) {
  1453. throw new DeveloperError('Expected ' + test + ' to be at most ' + maximum);
  1454. }
  1455. };
  1456. /**
  1457. * Throws if test is less than minimum
  1458. *
  1459. * @param {Number} test The value to test
  1460. * @param {Number} minimum The minimum allowed value
  1461. * @exception {DeveloperError} test must not be less than mininum
  1462. * @exception {DeveloperError} Both test and maximum must be typeof 'number'
  1463. */
  1464. Check.numeric.minimum = function (test, minimum) {
  1465. Check.typeOf.number(test);
  1466. Check.typeOf.number(minimum);
  1467. if (test < minimum) {
  1468. throw new DeveloperError('Expected ' + test + ' to be at least ' + minimum);
  1469. }
  1470. };
  1471. /**
  1472. * Throws if test is not typeof 'function'
  1473. *
  1474. * @param {*} test The value to test
  1475. * @param {String} name The name of the variable being tested
  1476. * @exception {DeveloperError} test must be typeof 'function'
  1477. */
  1478. Check.typeOf.function = function (test, name) {
  1479. if (typeof test !== 'function') {
  1480. throw new DeveloperError(getFailedTypeErrorMessage(typeof test, 'function', name));
  1481. }
  1482. };
  1483. /**
  1484. * Throws if test is not typeof 'string'
  1485. *
  1486. * @param {*} test The value to test
  1487. * @param {String} name The name of the variable being tested
  1488. * @exception {DeveloperError} test must be typeof 'string'
  1489. */
  1490. Check.typeOf.string = function (test, name) {
  1491. if (typeof test !== 'string') {
  1492. throw new DeveloperError(getFailedTypeErrorMessage(typeof test, 'string', name));
  1493. }
  1494. };
  1495. /**
  1496. * Throws if test is not typeof 'number'
  1497. *
  1498. * @param {*} test The value to test
  1499. * @param {String} name The name of the variable being tested
  1500. * @exception {DeveloperError} test must be typeof 'number'
  1501. */
  1502. Check.typeOf.number = function (test, name) {
  1503. if (typeof test !== 'number') {
  1504. throw new DeveloperError(getFailedTypeErrorMessage(typeof test, 'number', name));
  1505. }
  1506. };
  1507. /**
  1508. * Throws if test is not typeof 'object'
  1509. *
  1510. * @param {*} test The value to test
  1511. * @param {String} name The name of the variable being tested
  1512. * @exception {DeveloperError} test must be typeof 'object'
  1513. */
  1514. Check.typeOf.object = function (test, name) {
  1515. if (typeof test !== 'object') {
  1516. throw new DeveloperError(getFailedTypeErrorMessage(typeof test, 'object', name));
  1517. }
  1518. };
  1519. /**
  1520. * Throws if test is not typeof 'boolean'
  1521. *
  1522. * @param {*} test The value to test
  1523. * @param {String} name The name of the variable being tested
  1524. * @exception {DeveloperError} test must be typeof 'boolean'
  1525. */
  1526. Check.typeOf.boolean = function (test, name) {
  1527. if (typeof test !== 'boolean') {
  1528. throw new DeveloperError(getFailedTypeErrorMessage(typeof test, 'boolean', name));
  1529. }
  1530. };
  1531. return Check;
  1532. });
  1533. /*
  1534. I've wrapped Makoto Matsumoto and Takuji Nishimura's code in a namespace
  1535. so it's better encapsulated. Now you can have multiple random number generators
  1536. and they won't stomp all over eachother's state.
  1537. If you want to use this as a substitute for Math.random(), use the random()
  1538. method like so:
  1539. var m = new MersenneTwister();
  1540. var randomNumber = m.random();
  1541. You can also call the other genrand_{foo}() methods on the instance.
  1542. If you want to use a specific seed in order to get a repeatable random
  1543. sequence, pass an integer into the constructor:
  1544. var m = new MersenneTwister(123);
  1545. and that will always produce the same random sequence.
  1546. Sean McCullough (banksean@gmail.com)
  1547. */
  1548. /*
  1549. A C-program for MT19937, with initialization improved 2002/1/26.
  1550. Coded by Takuji Nishimura and Makoto Matsumoto.
  1551. Before using, initialize the state by using init_genrand(seed)
  1552. or init_by_array(init_key, key_length).
  1553. */
  1554. /**
  1555. @license
  1556. mersenne-twister.js - https://gist.github.com/banksean/300494
  1557. Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
  1558. All rights reserved.
  1559. Redistribution and use in source and binary forms, with or without
  1560. modification, are permitted provided that the following conditions
  1561. are met:
  1562. 1. Redistributions of source code must retain the above copyright
  1563. notice, this list of conditions and the following disclaimer.
  1564. 2. Redistributions in binary form must reproduce the above copyright
  1565. notice, this list of conditions and the following disclaimer in the
  1566. documentation and/or other materials provided with the distribution.
  1567. 3. The names of its contributors may not be used to endorse or promote
  1568. products derived from this software without specific prior written
  1569. permission.
  1570. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  1571. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  1572. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  1573. A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  1574. CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  1575. EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  1576. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  1577. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  1578. LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  1579. NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  1580. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  1581. */
  1582. /*
  1583. Any feedback is very welcome.
  1584. http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
  1585. email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
  1586. */
  1587. define('ThirdParty/mersenne-twister',[],function() {
  1588. var MersenneTwister = function(seed) {
  1589. if (seed == undefined) {
  1590. seed = new Date().getTime();
  1591. }
  1592. /* Period parameters */
  1593. this.N = 624;
  1594. this.M = 397;
  1595. this.MATRIX_A = 0x9908b0df; /* constant vector a */
  1596. this.UPPER_MASK = 0x80000000; /* most significant w-r bits */
  1597. this.LOWER_MASK = 0x7fffffff; /* least significant r bits */
  1598. this.mt = new Array(this.N); /* the array for the state vector */
  1599. this.mti=this.N+1; /* mti==N+1 means mt[N] is not initialized */
  1600. this.init_genrand(seed);
  1601. }
  1602. /* initializes mt[N] with a seed */
  1603. MersenneTwister.prototype.init_genrand = function(s) {
  1604. this.mt[0] = s >>> 0;
  1605. for (this.mti=1; this.mti<this.N; this.mti++) {
  1606. var s = this.mt[this.mti-1] ^ (this.mt[this.mti-1] >>> 30);
  1607. this.mt[this.mti] = (((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253)
  1608. + this.mti;
  1609. /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
  1610. /* In the previous versions, MSBs of the seed affect */
  1611. /* only MSBs of the array mt[]. */
  1612. /* 2002/01/09 modified by Makoto Matsumoto */
  1613. this.mt[this.mti] >>>= 0;
  1614. /* for >32 bit machines */
  1615. }
  1616. }
  1617. /* initialize by an array with array-length */
  1618. /* init_key is the array for initializing keys */
  1619. /* key_length is its length */
  1620. /* slight change for C++, 2004/2/26 */
  1621. //MersenneTwister.prototype.init_by_array = function(init_key, key_length) {
  1622. // var i, j, k;
  1623. // this.init_genrand(19650218);
  1624. // i=1; j=0;
  1625. // k = (this.N>key_length ? this.N : key_length);
  1626. // for (; k; k--) {
  1627. // var s = this.mt[i-1] ^ (this.mt[i-1] >>> 30)
  1628. // this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1664525) << 16) + ((s & 0x0000ffff) * 1664525)))
  1629. // + init_key[j] + j; /* non linear */
  1630. // this.mt[i] >>>= 0; /* for WORDSIZE > 32 machines */
  1631. // i++; j++;
  1632. // if (i>=this.N) { this.mt[0] = this.mt[this.N-1]; i=1; }
  1633. // if (j>=key_length) j=0;
  1634. // }
  1635. // for (k=this.N-1; k; k--) {
  1636. // var s = this.mt[i-1] ^ (this.mt[i-1] >>> 30);
  1637. // this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1566083941) << 16) + (s & 0x0000ffff) * 1566083941))
  1638. // - i; /* non linear */
  1639. // this.mt[i] >>>= 0; /* for WORDSIZE > 32 machines */
  1640. // i++;
  1641. // if (i>=this.N) { this.mt[0] = this.mt[this.N-1]; i=1; }
  1642. // }
  1643. //
  1644. // this.mt[0] = 0x80000000; /* MSB is 1; assuring non-zero initial array */
  1645. //}
  1646. /* generates a random number on [0,0xffffffff]-interval */
  1647. MersenneTwister.prototype.genrand_int32 = function() {
  1648. var y;
  1649. var mag01 = new Array(0x0, this.MATRIX_A);
  1650. /* mag01[x] = x * MATRIX_A for x=0,1 */
  1651. if (this.mti >= this.N) { /* generate N words at one time */
  1652. var kk;
  1653. if (this.mti == this.N+1) /* if init_genrand() has not been called, */
  1654. this.init_genrand(5489); /* a default initial seed is used */
  1655. for (kk=0;kk<this.N-this.M;kk++) {
  1656. y = (this.mt[kk]&this.UPPER_MASK)|(this.mt[kk+1]&this.LOWER_MASK);
  1657. this.mt[kk] = this.mt[kk+this.M] ^ (y >>> 1) ^ mag01[y & 0x1];
  1658. }
  1659. for (;kk<this.N-1;kk++) {
  1660. y = (this.mt[kk]&this.UPPER_MASK)|(this.mt[kk+1]&this.LOWER_MASK);
  1661. this.mt[kk] = this.mt[kk+(this.M-this.N)] ^ (y >>> 1) ^ mag01[y & 0x1];
  1662. }
  1663. y = (this.mt[this.N-1]&this.UPPER_MASK)|(this.mt[0]&this.LOWER_MASK);
  1664. this.mt[this.N-1] = this.mt[this.M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
  1665. this.mti = 0;
  1666. }
  1667. y = this.mt[this.mti++];
  1668. /* Tempering */
  1669. y ^= (y >>> 11);
  1670. y ^= (y << 7) & 0x9d2c5680;
  1671. y ^= (y << 15) & 0xefc60000;
  1672. y ^= (y >>> 18);
  1673. return y >>> 0;
  1674. }
  1675. /* generates a random number on [0,0x7fffffff]-interval */
  1676. //MersenneTwister.prototype.genrand_int31 = function() {
  1677. // return (this.genrand_int32()>>>1);
  1678. //}
  1679. /* generates a random number on [0,1]-real-interval */
  1680. //MersenneTwister.prototype.genrand_real1 = function() {
  1681. // return this.genrand_int32()*(1.0/4294967295.0);
  1682. // /* divided by 2^32-1 */
  1683. //}
  1684. /* generates a random number on [0,1)-real-interval */
  1685. MersenneTwister.prototype.random = function() {
  1686. return this.genrand_int32()*(1.0/4294967296.0);
  1687. /* divided by 2^32 */
  1688. }
  1689. /* generates a random number on (0,1)-real-interval */
  1690. //MersenneTwister.prototype.genrand_real3 = function() {
  1691. // return (this.genrand_int32() + 0.5)*(1.0/4294967296.0);
  1692. // /* divided by 2^32 */
  1693. //}
  1694. /* generates a random number on [0,1) with 53-bit resolution*/
  1695. //MersenneTwister.prototype.genrand_res53 = function() {
  1696. // var a=this.genrand_int32()>>>5, b=this.genrand_int32()>>>6;
  1697. // return(a*67108864.0+b)*(1.0/9007199254740992.0);
  1698. //}
  1699. /* These real versions are due to Isaku Wada, 2002/01/09 added */
  1700. return MersenneTwister;
  1701. });
  1702. /*global define*/
  1703. define('Core/Math',[
  1704. '../ThirdParty/mersenne-twister',
  1705. './defaultValue',
  1706. './defined',
  1707. './DeveloperError'
  1708. ], function(
  1709. MersenneTwister,
  1710. defaultValue,
  1711. defined,
  1712. DeveloperError) {
  1713. 'use strict';
  1714. /**
  1715. * Math functions.
  1716. *
  1717. * @exports CesiumMath
  1718. */
  1719. var CesiumMath = {};
  1720. /**
  1721. * 0.1
  1722. * @type {Number}
  1723. * @constant
  1724. */
  1725. CesiumMath.EPSILON1 = 0.1;
  1726. /**
  1727. * 0.01
  1728. * @type {Number}
  1729. * @constant
  1730. */
  1731. CesiumMath.EPSILON2 = 0.01;
  1732. /**
  1733. * 0.001
  1734. * @type {Number}
  1735. * @constant
  1736. */
  1737. CesiumMath.EPSILON3 = 0.001;
  1738. /**
  1739. * 0.0001
  1740. * @type {Number}
  1741. * @constant
  1742. */
  1743. CesiumMath.EPSILON4 = 0.0001;
  1744. /**
  1745. * 0.00001
  1746. * @type {Number}
  1747. * @constant
  1748. */
  1749. CesiumMath.EPSILON5 = 0.00001;
  1750. /**
  1751. * 0.000001
  1752. * @type {Number}
  1753. * @constant
  1754. */
  1755. CesiumMath.EPSILON6 = 0.000001;
  1756. /**
  1757. * 0.0000001
  1758. * @type {Number}
  1759. * @constant
  1760. */
  1761. CesiumMath.EPSILON7 = 0.0000001;
  1762. /**
  1763. * 0.00000001
  1764. * @type {Number}
  1765. * @constant
  1766. */
  1767. CesiumMath.EPSILON8 = 0.00000001;
  1768. /**
  1769. * 0.000000001
  1770. * @type {Number}
  1771. * @constant
  1772. */
  1773. CesiumMath.EPSILON9 = 0.000000001;
  1774. /**
  1775. * 0.0000000001
  1776. * @type {Number}
  1777. * @constant
  1778. */
  1779. CesiumMath.EPSILON10 = 0.0000000001;
  1780. /**
  1781. * 0.00000000001
  1782. * @type {Number}
  1783. * @constant
  1784. */
  1785. CesiumMath.EPSILON11 = 0.00000000001;
  1786. /**
  1787. * 0.000000000001
  1788. * @type {Number}
  1789. * @constant
  1790. */
  1791. CesiumMath.EPSILON12 = 0.000000000001;
  1792. /**
  1793. * 0.0000000000001
  1794. * @type {Number}
  1795. * @constant
  1796. */
  1797. CesiumMath.EPSILON13 = 0.0000000000001;
  1798. /**
  1799. * 0.00000000000001
  1800. * @type {Number}
  1801. * @constant
  1802. */
  1803. CesiumMath.EPSILON14 = 0.00000000000001;
  1804. /**
  1805. * 0.000000000000001
  1806. * @type {Number}
  1807. * @constant
  1808. */
  1809. CesiumMath.EPSILON15 = 0.000000000000001;
  1810. /**
  1811. * 0.0000000000000001
  1812. * @type {Number}
  1813. * @constant
  1814. */
  1815. CesiumMath.EPSILON16 = 0.0000000000000001;
  1816. /**
  1817. * 0.00000000000000001
  1818. * @type {Number}
  1819. * @constant
  1820. */
  1821. CesiumMath.EPSILON17 = 0.00000000000000001;
  1822. /**
  1823. * 0.000000000000000001
  1824. * @type {Number}
  1825. * @constant
  1826. */
  1827. CesiumMath.EPSILON18 = 0.000000000000000001;
  1828. /**
  1829. * 0.0000000000000000001
  1830. * @type {Number}
  1831. * @constant
  1832. */
  1833. CesiumMath.EPSILON19 = 0.0000000000000000001;
  1834. /**
  1835. * 0.00000000000000000001
  1836. * @type {Number}
  1837. * @constant
  1838. */
  1839. CesiumMath.EPSILON20 = 0.00000000000000000001;
  1840. /**
  1841. * 3.986004418e14
  1842. * @type {Number}
  1843. * @constant
  1844. */
  1845. CesiumMath.GRAVITATIONALPARAMETER = 3.986004418e14;
  1846. /**
  1847. * Radius of the sun in meters: 6.955e8
  1848. * @type {Number}
  1849. * @constant
  1850. */
  1851. CesiumMath.SOLAR_RADIUS = 6.955e8;
  1852. /**
  1853. * The mean radius of the moon, according to the "Report of the IAU/IAG Working Group on
  1854. * Cartographic Coordinates and Rotational Elements of the Planets and satellites: 2000",
  1855. * Celestial Mechanics 82: 83-110, 2002.
  1856. * @type {Number}
  1857. * @constant
  1858. */
  1859. CesiumMath.LUNAR_RADIUS = 1737400.0;
  1860. /**
  1861. * 64 * 1024
  1862. * @type {Number}
  1863. * @constant
  1864. */
  1865. CesiumMath.SIXTY_FOUR_KILOBYTES = 64 * 1024;
  1866. /**
  1867. * Returns the sign of the value; 1 if the value is positive, -1 if the value is
  1868. * negative, or 0 if the value is 0.
  1869. *
  1870. * @param {Number} value The value to return the sign of.
  1871. * @returns {Number} The sign of value.
  1872. */
  1873. CesiumMath.sign = function(value) {
  1874. if (value > 0) {
  1875. return 1;
  1876. }
  1877. if (value < 0) {
  1878. return -1;
  1879. }
  1880. return 0;
  1881. };
  1882. /**
  1883. * Returns 1.0 if the given value is positive or zero, and -1.0 if it is negative.
  1884. * This is similar to {@link CesiumMath#sign} except that returns 1.0 instead of
  1885. * 0.0 when the input value is 0.0.
  1886. * @param {Number} value The value to return the sign of.
  1887. * @returns {Number} The sign of value.
  1888. */
  1889. CesiumMath.signNotZero = function(value) {
  1890. return value < 0.0 ? -1.0 : 1.0;
  1891. };
  1892. /**
  1893. * Converts a scalar value in the range [-1.0, 1.0] to a SNORM in the range [0, rangeMax]
  1894. * @param {Number} value The scalar value in the range [-1.0, 1.0]
  1895. * @param {Number} [rangeMax=255] The maximum value in the mapped range, 255 by default.
  1896. * @returns {Number} A SNORM value, where 0 maps to -1.0 and rangeMax maps to 1.0.
  1897. *
  1898. * @see CesiumMath.fromSNorm
  1899. */
  1900. CesiumMath.toSNorm = function(value, rangeMax) {
  1901. rangeMax = defaultValue(rangeMax, 255);
  1902. return Math.round((CesiumMath.clamp(value, -1.0, 1.0) * 0.5 + 0.5) * rangeMax);
  1903. };
  1904. /**
  1905. * Converts a SNORM value in the range [0, rangeMax] to a scalar in the range [-1.0, 1.0].
  1906. * @param {Number} value SNORM value in the range [0, 255]
  1907. * @param {Number} [rangeMax=255] The maximum value in the SNORM range, 255 by default.
  1908. * @returns {Number} Scalar in the range [-1.0, 1.0].
  1909. *
  1910. * @see CesiumMath.toSNorm
  1911. */
  1912. CesiumMath.fromSNorm = function(value, rangeMax) {
  1913. rangeMax = defaultValue(rangeMax, 255);
  1914. return CesiumMath.clamp(value, 0.0, rangeMax) / rangeMax * 2.0 - 1.0;
  1915. };
  1916. /**
  1917. * Returns the hyperbolic sine of a number.
  1918. * The hyperbolic sine of <em>value</em> is defined to be
  1919. * (<em>e<sup>x</sup>&nbsp;-&nbsp;e<sup>-x</sup></em>)/2.0
  1920. * where <i>e</i> is Euler's number, approximately 2.71828183.
  1921. *
  1922. * <p>Special cases:
  1923. * <ul>
  1924. * <li>If the argument is NaN, then the result is NaN.</li>
  1925. *
  1926. * <li>If the argument is infinite, then the result is an infinity
  1927. * with the same sign as the argument.</li>
  1928. *
  1929. * <li>If the argument is zero, then the result is a zero with the
  1930. * same sign as the argument.</li>
  1931. * </ul>
  1932. *</p>
  1933. *
  1934. * @param {Number} value The number whose hyperbolic sine is to be returned.
  1935. * @returns {Number} The hyperbolic sine of <code>value</code>.
  1936. */
  1937. CesiumMath.sinh = function(value) {
  1938. var part1 = Math.pow(Math.E, value);
  1939. var part2 = Math.pow(Math.E, -1.0 * value);
  1940. return (part1 - part2) * 0.5;
  1941. };
  1942. /**
  1943. * Returns the hyperbolic cosine of a number.
  1944. * The hyperbolic cosine of <strong>value</strong> is defined to be
  1945. * (<em>e<sup>x</sup>&nbsp;+&nbsp;e<sup>-x</sup></em>)/2.0
  1946. * where <i>e</i> is Euler's number, approximately 2.71828183.
  1947. *
  1948. * <p>Special cases:
  1949. * <ul>
  1950. * <li>If the argument is NaN, then the result is NaN.</li>
  1951. *
  1952. * <li>If the argument is infinite, then the result is positive infinity.</li>
  1953. *
  1954. * <li>If the argument is zero, then the result is 1.0.</li>
  1955. * </ul>
  1956. *</p>
  1957. *
  1958. * @param {Number} value The number whose hyperbolic cosine is to be returned.
  1959. * @returns {Number} The hyperbolic cosine of <code>value</code>.
  1960. */
  1961. CesiumMath.cosh = function(value) {
  1962. var part1 = Math.pow(Math.E, value);
  1963. var part2 = Math.pow(Math.E, -1.0 * value);
  1964. return (part1 + part2) * 0.5;
  1965. };
  1966. /**
  1967. * Computes the linear interpolation of two values.
  1968. *
  1969. * @param {Number} p The start value to interpolate.
  1970. * @param {Number} q The end value to interpolate.
  1971. * @param {Number} time The time of interpolation generally in the range <code>[0.0, 1.0]</code>.
  1972. * @returns {Number} The linearly interpolated value.
  1973. *
  1974. * @example
  1975. * var n = Cesium.Math.lerp(0.0, 2.0, 0.5); // returns 1.0
  1976. */
  1977. CesiumMath.lerp = function(p, q, time) {
  1978. return ((1.0 - time) * p) + (time * q);
  1979. };
  1980. /**
  1981. * pi
  1982. *
  1983. * @type {Number}
  1984. * @constant
  1985. */
  1986. CesiumMath.PI = Math.PI;
  1987. /**
  1988. * 1/pi
  1989. *
  1990. * @type {Number}
  1991. * @constant
  1992. */
  1993. CesiumMath.ONE_OVER_PI = 1.0 / Math.PI;
  1994. /**
  1995. * pi/2
  1996. *
  1997. * @type {Number}
  1998. * @constant
  1999. */
  2000. CesiumMath.PI_OVER_TWO = Math.PI * 0.5;
  2001. /**
  2002. * pi/3
  2003. *
  2004. * @type {Number}
  2005. * @constant
  2006. */
  2007. CesiumMath.PI_OVER_THREE = Math.PI / 3.0;
  2008. /**
  2009. * pi/4
  2010. *
  2011. * @type {Number}
  2012. * @constant
  2013. */
  2014. CesiumMath.PI_OVER_FOUR = Math.PI / 4.0;
  2015. /**
  2016. * pi/6
  2017. *
  2018. * @type {Number}
  2019. * @constant
  2020. */
  2021. CesiumMath.PI_OVER_SIX = Math.PI / 6.0;
  2022. /**
  2023. * 3pi/2
  2024. *
  2025. * @type {Number}
  2026. * @constant
  2027. */
  2028. CesiumMath.THREE_PI_OVER_TWO = (3.0 * Math.PI) * 0.5;
  2029. /**
  2030. * 2pi
  2031. *
  2032. * @type {Number}
  2033. * @constant
  2034. */
  2035. CesiumMath.TWO_PI = 2.0 * Math.PI;
  2036. /**
  2037. * 1/2pi
  2038. *
  2039. * @type {Number}
  2040. * @constant
  2041. */
  2042. CesiumMath.ONE_OVER_TWO_PI = 1.0 / (2.0 * Math.PI);
  2043. /**
  2044. * The number of radians in a degree.
  2045. *
  2046. * @type {Number}
  2047. * @constant
  2048. * @default Math.PI / 180.0
  2049. */
  2050. CesiumMath.RADIANS_PER_DEGREE = Math.PI / 180.0;
  2051. /**
  2052. * The number of degrees in a radian.
  2053. *
  2054. * @type {Number}
  2055. * @constant
  2056. * @default 180.0 / Math.PI
  2057. */
  2058. CesiumMath.DEGREES_PER_RADIAN = 180.0 / Math.PI;
  2059. /**
  2060. * The number of radians in an arc second.
  2061. *
  2062. * @type {Number}
  2063. * @constant
  2064. * @default {@link CesiumMath.RADIANS_PER_DEGREE} / 3600.0
  2065. */
  2066. CesiumMath.RADIANS_PER_ARCSECOND = CesiumMath.RADIANS_PER_DEGREE / 3600.0;
  2067. /**
  2068. * Converts degrees to radians.
  2069. * @param {Number} degrees The angle to convert in degrees.
  2070. * @returns {Number} The corresponding angle in radians.
  2071. */
  2072. CesiumMath.toRadians = function(degrees) {
  2073. if (!defined(degrees)) {
  2074. throw new DeveloperError('degrees is required.');
  2075. }
  2076. return degrees * CesiumMath.RADIANS_PER_DEGREE;
  2077. };
  2078. /**
  2079. * Converts radians to degrees.
  2080. * @param {Number} radians The angle to convert in radians.
  2081. * @returns {Number} The corresponding angle in degrees.
  2082. */
  2083. CesiumMath.toDegrees = function(radians) {
  2084. if (!defined(radians)) {
  2085. throw new DeveloperError('radians is required.');
  2086. }
  2087. return radians * CesiumMath.DEGREES_PER_RADIAN;
  2088. };
  2089. /**
  2090. * Converts a longitude value, in radians, to the range [<code>-Math.PI</code>, <code>Math.PI</code>).
  2091. *
  2092. * @param {Number} angle The longitude value, in radians, to convert to the range [<code>-Math.PI</code>, <code>Math.PI</code>).
  2093. * @returns {Number} The equivalent longitude value in the range [<code>-Math.PI</code>, <code>Math.PI</code>).
  2094. *
  2095. * @example
  2096. * // Convert 270 degrees to -90 degrees longitude
  2097. * var longitude = Cesium.Math.convertLongitudeRange(Cesium.Math.toRadians(270.0));
  2098. */
  2099. CesiumMath.convertLongitudeRange = function(angle) {
  2100. if (!defined(angle)) {
  2101. throw new DeveloperError('angle is required.');
  2102. }
  2103. var twoPi = CesiumMath.TWO_PI;
  2104. var simplified = angle - Math.floor(angle / twoPi) * twoPi;
  2105. if (simplified < -Math.PI) {
  2106. return simplified + twoPi;
  2107. }
  2108. if (simplified >= Math.PI) {
  2109. return simplified - twoPi;
  2110. }
  2111. return simplified;
  2112. };
  2113. /**
  2114. * Convenience function that clamps a latitude value, in radians, to the range [<code>-Math.PI/2</code>, <code>Math.PI/2</code>).
  2115. * Useful for sanitizing data before use in objects requiring correct range.
  2116. *
  2117. * @param {Number} angle The latitude value, in radians, to clamp to the range [<code>-Math.PI/2</code>, <code>Math.PI/2</code>).
  2118. * @returns {Number} The latitude value clamped to the range [<code>-Math.PI/2</code>, <code>Math.PI/2</code>).
  2119. *
  2120. * @example
  2121. * // Clamp 108 degrees latitude to 90 degrees latitude
  2122. * var latitude = Cesium.Math.clampToLatitudeRange(Cesium.Math.toRadians(108.0));
  2123. */
  2124. CesiumMath.clampToLatitudeRange = function(angle) {
  2125. if (!defined(angle)) {
  2126. throw new DeveloperError('angle is required.');
  2127. }
  2128. return CesiumMath.clamp(angle, -1*CesiumMath.PI_OVER_TWO, CesiumMath.PI_OVER_TWO);
  2129. };
  2130. /**
  2131. * Produces an angle in the range -Pi <= angle <= Pi which is equivalent to the provided angle.
  2132. *
  2133. * @param {Number} angle in radians
  2134. * @returns {Number} The angle in the range [<code>-CesiumMath.PI</code>, <code>CesiumMath.PI</code>].
  2135. */
  2136. CesiumMath.negativePiToPi = function(x) {
  2137. if (!defined(x)) {
  2138. throw new DeveloperError('x is required.');
  2139. }
  2140. return CesiumMath.zeroToTwoPi(x + CesiumMath.PI) - CesiumMath.PI;
  2141. };
  2142. /**
  2143. * Produces an angle in the range 0 <= angle <= 2Pi which is equivalent to the provided angle.
  2144. *
  2145. * @param {Number} angle in radians
  2146. * @returns {Number} The angle in the range [0, <code>CesiumMath.TWO_PI</code>].
  2147. */
  2148. CesiumMath.zeroToTwoPi = function(x) {
  2149. if (!defined(x)) {
  2150. throw new DeveloperError('x is required.');
  2151. }
  2152. var mod = CesiumMath.mod(x, CesiumMath.TWO_PI);
  2153. if (Math.abs(mod) < CesiumMath.EPSILON14 && Math.abs(x) > CesiumMath.EPSILON14) {
  2154. return CesiumMath.TWO_PI;
  2155. }
  2156. return mod;
  2157. };
  2158. /**
  2159. * The modulo operation that also works for negative dividends.
  2160. *
  2161. * @param {Number} m The dividend.
  2162. * @param {Number} n The divisor.
  2163. * @returns {Number} The remainder.
  2164. */
  2165. CesiumMath.mod = function(m, n) {
  2166. if (!defined(m)) {
  2167. throw new DeveloperError('m is required.');
  2168. }
  2169. if (!defined(n)) {
  2170. throw new DeveloperError('n is required.');
  2171. }
  2172. return ((m % n) + n) % n;
  2173. };
  2174. /**
  2175. * Determines if two values are equal using an absolute or relative tolerance test. This is useful
  2176. * to avoid problems due to roundoff error when comparing floating-point values directly. The values are
  2177. * first compared using an absolute tolerance test. If that fails, a relative tolerance test is performed.
  2178. * Use this test if you are unsure of the magnitudes of left and right.
  2179. *
  2180. * @param {Number} left The first value to compare.
  2181. * @param {Number} right The other value to compare.
  2182. * @param {Number} relativeEpsilon The maximum inclusive delta between <code>left</code> and <code>right</code> for the relative tolerance test.
  2183. * @param {Number} [absoluteEpsilon=relativeEpsilon] The maximum inclusive delta between <code>left</code> and <code>right</code> for the absolute tolerance test.
  2184. * @returns {Boolean} <code>true</code> if the values are equal within the epsilon; otherwise, <code>false</code>.
  2185. *
  2186. * @example
  2187. * var a = Cesium.Math.equalsEpsilon(0.0, 0.01, Cesium.Math.EPSILON2); // true
  2188. * var b = Cesium.Math.equalsEpsilon(0.0, 0.1, Cesium.Math.EPSILON2); // false
  2189. * var c = Cesium.Math.equalsEpsilon(3699175.1634344, 3699175.2, Cesium.Math.EPSILON7); // true
  2190. * var d = Cesium.Math.equalsEpsilon(3699175.1634344, 3699175.2, Cesium.Math.EPSILON9); // false
  2191. */
  2192. CesiumMath.equalsEpsilon = function(left, right, relativeEpsilon, absoluteEpsilon) {
  2193. if (!defined(left)) {
  2194. throw new DeveloperError('left is required.');
  2195. }
  2196. if (!defined(right)) {
  2197. throw new DeveloperError('right is required.');
  2198. }
  2199. if (!defined(relativeEpsilon)) {
  2200. throw new DeveloperError('relativeEpsilon is required.');
  2201. }
  2202. absoluteEpsilon = defaultValue(absoluteEpsilon, relativeEpsilon);
  2203. var absDiff = Math.abs(left - right);
  2204. return absDiff <= absoluteEpsilon || absDiff <= relativeEpsilon * Math.max(Math.abs(left), Math.abs(right));
  2205. };
  2206. var factorials = [1];
  2207. /**
  2208. * Computes the factorial of the provided number.
  2209. *
  2210. * @param {Number} n The number whose factorial is to be computed.
  2211. * @returns {Number} The factorial of the provided number or undefined if the number is less than 0.
  2212. *
  2213. * @exception {DeveloperError} A number greater than or equal to 0 is required.
  2214. *
  2215. *
  2216. * @example
  2217. * //Compute 7!, which is equal to 5040
  2218. * var computedFactorial = Cesium.Math.factorial(7);
  2219. *
  2220. * @see {@link http://en.wikipedia.org/wiki/Factorial|Factorial on Wikipedia}
  2221. */
  2222. CesiumMath.factorial = function(n) {
  2223. if (typeof n !== 'number' || n < 0) {
  2224. throw new DeveloperError('A number greater than or equal to 0 is required.');
  2225. }
  2226. var length = factorials.length;
  2227. if (n >= length) {
  2228. var sum = factorials[length - 1];
  2229. for (var i = length; i <= n; i++) {
  2230. factorials.push(sum * i);
  2231. }
  2232. }
  2233. return factorials[n];
  2234. };
  2235. /**
  2236. * Increments a number with a wrapping to a minimum value if the number exceeds the maximum value.
  2237. *
  2238. * @param {Number} [n] The number to be incremented.
  2239. * @param {Number} [maximumValue] The maximum incremented value before rolling over to the minimum value.
  2240. * @param {Number} [minimumValue=0.0] The number reset to after the maximum value has been exceeded.
  2241. * @returns {Number} The incremented number.
  2242. *
  2243. * @exception {DeveloperError} Maximum value must be greater than minimum value.
  2244. *
  2245. * @example
  2246. * var n = Cesium.Math.incrementWrap(5, 10, 0); // returns 6
  2247. * var n = Cesium.Math.incrementWrap(10, 10, 0); // returns 0
  2248. */
  2249. CesiumMath.incrementWrap = function(n, maximumValue, minimumValue) {
  2250. minimumValue = defaultValue(minimumValue, 0.0);
  2251. if (!defined(n)) {
  2252. throw new DeveloperError('n is required.');
  2253. }
  2254. if (maximumValue <= minimumValue) {
  2255. throw new DeveloperError('maximumValue must be greater than minimumValue.');
  2256. }
  2257. ++n;
  2258. if (n > maximumValue) {
  2259. n = minimumValue;
  2260. }
  2261. return n;
  2262. };
  2263. /**
  2264. * Determines if a positive integer is a power of two.
  2265. *
  2266. * @param {Number} n The positive integer to test.
  2267. * @returns {Boolean} <code>true</code> if the number if a power of two; otherwise, <code>false</code>.
  2268. *
  2269. * @exception {DeveloperError} A number greater than or equal to 0 is required.
  2270. *
  2271. * @example
  2272. * var t = Cesium.Math.isPowerOfTwo(16); // true
  2273. * var f = Cesium.Math.isPowerOfTwo(20); // false
  2274. */
  2275. CesiumMath.isPowerOfTwo = function(n) {
  2276. if (typeof n !== 'number' || n < 0) {
  2277. throw new DeveloperError('A number greater than or equal to 0 is required.');
  2278. }
  2279. return (n !== 0) && ((n & (n - 1)) === 0);
  2280. };
  2281. /**
  2282. * Computes the next power-of-two integer greater than or equal to the provided positive integer.
  2283. *
  2284. * @param {Number} n The positive integer to test.
  2285. * @returns {Number} The next power-of-two integer.
  2286. *
  2287. * @exception {DeveloperError} A number greater than or equal to 0 is required.
  2288. *
  2289. * @example
  2290. * var n = Cesium.Math.nextPowerOfTwo(29); // 32
  2291. * var m = Cesium.Math.nextPowerOfTwo(32); // 32
  2292. */
  2293. CesiumMath.nextPowerOfTwo = function(n) {
  2294. if (typeof n !== 'number' || n < 0) {
  2295. throw new DeveloperError('A number greater than or equal to 0 is required.');
  2296. }
  2297. // From http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
  2298. --n;
  2299. n |= n >> 1;
  2300. n |= n >> 2;
  2301. n |= n >> 4;
  2302. n |= n >> 8;
  2303. n |= n >> 16;
  2304. ++n;
  2305. return n;
  2306. };
  2307. /**
  2308. * Constraint a value to lie between two values.
  2309. *
  2310. * @param {Number} value The value to constrain.
  2311. * @param {Number} min The minimum value.
  2312. * @param {Number} max The maximum value.
  2313. * @returns {Number} The value clamped so that min <= value <= max.
  2314. */
  2315. CesiumMath.clamp = function(value, min, max) {
  2316. if (!defined(value)) {
  2317. throw new DeveloperError('value is required');
  2318. }
  2319. if (!defined(min)) {
  2320. throw new DeveloperError('min is required.');
  2321. }
  2322. if (!defined(max)) {
  2323. throw new DeveloperError('max is required.');
  2324. }
  2325. return value < min ? min : value > max ? max : value;
  2326. };
  2327. var randomNumberGenerator = new MersenneTwister();
  2328. /**
  2329. * Sets the seed used by the random number generator
  2330. * in {@link CesiumMath#nextRandomNumber}.
  2331. *
  2332. * @param {Number} seed An integer used as the seed.
  2333. */
  2334. CesiumMath.setRandomNumberSeed = function(seed) {
  2335. if (!defined(seed)) {
  2336. throw new DeveloperError('seed is required.');
  2337. }
  2338. randomNumberGenerator = new MersenneTwister(seed);
  2339. };
  2340. /**
  2341. * Generates a random number in the range of [0.0, 1.0)
  2342. * using a Mersenne twister.
  2343. *
  2344. * @returns {Number} A random number in the range of [0.0, 1.0).
  2345. *
  2346. * @see CesiumMath.setRandomNumberSeed
  2347. * @see {@link http://en.wikipedia.org/wiki/Mersenne_twister|Mersenne twister on Wikipedia}
  2348. */
  2349. CesiumMath.nextRandomNumber = function() {
  2350. return randomNumberGenerator.random();
  2351. };
  2352. /**
  2353. * Computes <code>Math.acos(value)</acode>, but first clamps <code>value</code> to the range [-1.0, 1.0]
  2354. * so that the function will never return NaN.
  2355. *
  2356. * @param {Number} value The value for which to compute acos.
  2357. * @returns {Number} The acos of the value if the value is in the range [-1.0, 1.0], or the acos of -1.0 or 1.0,
  2358. * whichever is closer, if the value is outside the range.
  2359. */
  2360. CesiumMath.acosClamped = function(value) {
  2361. if (!defined(value)) {
  2362. throw new DeveloperError('value is required.');
  2363. }
  2364. return Math.acos(CesiumMath.clamp(value, -1.0, 1.0));
  2365. };
  2366. /**
  2367. * Computes <code>Math.asin(value)</acode>, but first clamps <code>value</code> to the range [-1.0, 1.0]
  2368. * so that the function will never return NaN.
  2369. *
  2370. * @param {Number} value The value for which to compute asin.
  2371. * @returns {Number} The asin of the value if the value is in the range [-1.0, 1.0], or the asin of -1.0 or 1.0,
  2372. * whichever is closer, if the value is outside the range.
  2373. */
  2374. CesiumMath.asinClamped = function(value) {
  2375. if (!defined(value)) {
  2376. throw new DeveloperError('value is required.');
  2377. }
  2378. return Math.asin(CesiumMath.clamp(value, -1.0, 1.0));
  2379. };
  2380. /**
  2381. * Finds the chord length between two points given the circle's radius and the angle between the points.
  2382. *
  2383. * @param {Number} angle The angle between the two points.
  2384. * @param {Number} radius The radius of the circle.
  2385. * @returns {Number} The chord length.
  2386. */
  2387. CesiumMath.chordLength = function(angle, radius) {
  2388. if (!defined(angle)) {
  2389. throw new DeveloperError('angle is required.');
  2390. }
  2391. if (!defined(radius)) {
  2392. throw new DeveloperError('radius is required.');
  2393. }
  2394. return 2.0 * radius * Math.sin(angle * 0.5);
  2395. };
  2396. /**
  2397. * Finds the logarithm of a number to a base.
  2398. *
  2399. * @param {Number} number The number.
  2400. * @param {Number} base The base.
  2401. * @returns {Number} The result.
  2402. */
  2403. CesiumMath.logBase = function(number, base) {
  2404. if (!defined(number)) {
  2405. throw new DeveloperError('number is required.');
  2406. }
  2407. if (!defined(base)) {
  2408. throw new DeveloperError('base is required.');
  2409. }
  2410. return Math.log(number) / Math.log(base);
  2411. };
  2412. /**
  2413. * @private
  2414. */
  2415. CesiumMath.fog = function(distanceToCamera, density) {
  2416. var scalar = distanceToCamera * density;
  2417. return 1.0 - Math.exp(-(scalar * scalar));
  2418. };
  2419. return CesiumMath;
  2420. });
  2421. /*global define*/
  2422. define('Core/Cartesian3',[
  2423. './Check',
  2424. './defaultValue',
  2425. './defined',
  2426. './DeveloperError',
  2427. './freezeObject',
  2428. './Math'
  2429. ], function(
  2430. Check,
  2431. defaultValue,
  2432. defined,
  2433. DeveloperError,
  2434. freezeObject,
  2435. CesiumMath) {
  2436. 'use strict';
  2437. /**
  2438. * A 3D Cartesian point.
  2439. * @alias Cartesian3
  2440. * @constructor
  2441. *
  2442. * @param {Number} [x=0.0] The X component.
  2443. * @param {Number} [y=0.0] The Y component.
  2444. * @param {Number} [z=0.0] The Z component.
  2445. *
  2446. * @see Cartesian2
  2447. * @see Cartesian4
  2448. * @see Packable
  2449. */
  2450. function Cartesian3(x, y, z) {
  2451. /**
  2452. * The X component.
  2453. * @type {Number}
  2454. * @default 0.0
  2455. */
  2456. this.x = defaultValue(x, 0.0);
  2457. /**
  2458. * The Y component.
  2459. * @type {Number}
  2460. * @default 0.0
  2461. */
  2462. this.y = defaultValue(y, 0.0);
  2463. /**
  2464. * The Z component.
  2465. * @type {Number}
  2466. * @default 0.0
  2467. */
  2468. this.z = defaultValue(z, 0.0);
  2469. }
  2470. /**
  2471. * Converts the provided Spherical into Cartesian3 coordinates.
  2472. *
  2473. * @param {Spherical} spherical The Spherical to be converted to Cartesian3.
  2474. * @param {Cartesian3} [result] The object onto which to store the result.
  2475. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
  2476. */
  2477. Cartesian3.fromSpherical = function(spherical, result) {
  2478. Check.typeOf.object(spherical, 'spherical');
  2479. if (!defined(result)) {
  2480. result = new Cartesian3();
  2481. }
  2482. var clock = spherical.clock;
  2483. var cone = spherical.cone;
  2484. var magnitude = defaultValue(spherical.magnitude, 1.0);
  2485. var radial = magnitude * Math.sin(cone);
  2486. result.x = radial * Math.cos(clock);
  2487. result.y = radial * Math.sin(clock);
  2488. result.z = magnitude * Math.cos(cone);
  2489. return result;
  2490. };
  2491. /**
  2492. * Creates a Cartesian3 instance from x, y and z coordinates.
  2493. *
  2494. * @param {Number} x The x coordinate.
  2495. * @param {Number} y The y coordinate.
  2496. * @param {Number} z The z coordinate.
  2497. * @param {Cartesian3} [result] The object onto which to store the result.
  2498. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
  2499. */
  2500. Cartesian3.fromElements = function(x, y, z, result) {
  2501. if (!defined(result)) {
  2502. return new Cartesian3(x, y, z);
  2503. }
  2504. result.x = x;
  2505. result.y = y;
  2506. result.z = z;
  2507. return result;
  2508. };
  2509. /**
  2510. * Duplicates a Cartesian3 instance.
  2511. *
  2512. * @param {Cartesian3} cartesian The Cartesian to duplicate.
  2513. * @param {Cartesian3} [result] The object onto which to store the result.
  2514. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided. (Returns undefined if cartesian is undefined)
  2515. */
  2516. Cartesian3.clone = function(cartesian, result) {
  2517. if (!defined(cartesian)) {
  2518. return undefined;
  2519. }
  2520. if (!defined(result)) {
  2521. return new Cartesian3(cartesian.x, cartesian.y, cartesian.z);
  2522. }
  2523. result.x = cartesian.x;
  2524. result.y = cartesian.y;
  2525. result.z = cartesian.z;
  2526. return result;
  2527. };
  2528. /**
  2529. * Creates a Cartesian3 instance from an existing Cartesian4. This simply takes the
  2530. * x, y, and z properties of the Cartesian4 and drops w.
  2531. * @function
  2532. *
  2533. * @param {Cartesian4} cartesian The Cartesian4 instance to create a Cartesian3 instance from.
  2534. * @param {Cartesian3} [result] The object onto which to store the result.
  2535. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
  2536. */
  2537. Cartesian3.fromCartesian4 = Cartesian3.clone;
  2538. /**
  2539. * The number of elements used to pack the object into an array.
  2540. * @type {Number}
  2541. */
  2542. Cartesian3.packedLength = 3;
  2543. /**
  2544. * Stores the provided instance into the provided array.
  2545. *
  2546. * @param {Cartesian3} value The value to pack.
  2547. * @param {Number[]} array The array to pack into.
  2548. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  2549. *
  2550. * @returns {Number[]} The array that was packed into
  2551. */
  2552. Cartesian3.pack = function(value, array, startingIndex) {
  2553. Check.typeOf.object(value, 'value');
  2554. Check.defined(array, 'array');
  2555. startingIndex = defaultValue(startingIndex, 0);
  2556. array[startingIndex++] = value.x;
  2557. array[startingIndex++] = value.y;
  2558. array[startingIndex] = value.z;
  2559. return array;
  2560. };
  2561. /**
  2562. * Retrieves an instance from a packed array.
  2563. *
  2564. * @param {Number[]} array The packed array.
  2565. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  2566. * @param {Cartesian3} [result] The object into which to store the result.
  2567. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
  2568. */
  2569. Cartesian3.unpack = function(array, startingIndex, result) {
  2570. Check.defined(array, 'array');
  2571. startingIndex = defaultValue(startingIndex, 0);
  2572. if (!defined(result)) {
  2573. result = new Cartesian3();
  2574. }
  2575. result.x = array[startingIndex++];
  2576. result.y = array[startingIndex++];
  2577. result.z = array[startingIndex];
  2578. return result;
  2579. };
  2580. /**
  2581. * Flattens an array of Cartesian3s into an array of components.
  2582. *
  2583. * @param {Cartesian3[]} array The array of cartesians to pack.
  2584. * @param {Number[]} result The array onto which to store the result.
  2585. * @returns {Number[]} The packed array.
  2586. */
  2587. Cartesian3.packArray = function(array, result) {
  2588. Check.defined(array, 'array');
  2589. var length = array.length;
  2590. if (!defined(result)) {
  2591. result = new Array(length * 3);
  2592. } else {
  2593. result.length = length * 3;
  2594. }
  2595. for (var i = 0; i < length; ++i) {
  2596. Cartesian3.pack(array[i], result, i * 3);
  2597. }
  2598. return result;
  2599. };
  2600. /**
  2601. * Unpacks an array of cartesian components into an array of Cartesian3s.
  2602. *
  2603. * @param {Number[]} array The array of components to unpack.
  2604. * @param {Cartesian3[]} result The array onto which to store the result.
  2605. * @returns {Cartesian3[]} The unpacked array.
  2606. */
  2607. Cartesian3.unpackArray = function(array, result) {
  2608. Check.defined(array, 'array');
  2609. Check.numeric.minimum(array.length, 3);
  2610. if (array.length % 3 !== 0) {
  2611. throw new DeveloperError('array length must be a multiple of 3.');
  2612. }
  2613. var length = array.length;
  2614. if (!defined(result)) {
  2615. result = new Array(length / 3);
  2616. } else {
  2617. result.length = length / 3;
  2618. }
  2619. for (var i = 0; i < length; i += 3) {
  2620. var index = i / 3;
  2621. result[index] = Cartesian3.unpack(array, i, result[index]);
  2622. }
  2623. return result;
  2624. };
  2625. /**
  2626. * Creates a Cartesian3 from three consecutive elements in an array.
  2627. * @function
  2628. *
  2629. * @param {Number[]} array The array whose three consecutive elements correspond to the x, y, and z components, respectively.
  2630. * @param {Number} [startingIndex=0] The offset into the array of the first element, which corresponds to the x component.
  2631. * @param {Cartesian3} [result] The object onto which to store the result.
  2632. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
  2633. *
  2634. * @example
  2635. * // Create a Cartesian3 with (1.0, 2.0, 3.0)
  2636. * var v = [1.0, 2.0, 3.0];
  2637. * var p = Cesium.Cartesian3.fromArray(v);
  2638. *
  2639. * // Create a Cartesian3 with (1.0, 2.0, 3.0) using an offset into an array
  2640. * var v2 = [0.0, 0.0, 1.0, 2.0, 3.0];
  2641. * var p2 = Cesium.Cartesian3.fromArray(v2, 2);
  2642. */
  2643. Cartesian3.fromArray = Cartesian3.unpack;
  2644. /**
  2645. * Computes the value of the maximum component for the supplied Cartesian.
  2646. *
  2647. * @param {Cartesian3} cartesian The cartesian to use.
  2648. * @returns {Number} The value of the maximum component.
  2649. */
  2650. Cartesian3.maximumComponent = function(cartesian) {
  2651. Check.typeOf.object(cartesian, 'cartesian');
  2652. return Math.max(cartesian.x, cartesian.y, cartesian.z);
  2653. };
  2654. /**
  2655. * Computes the value of the minimum component for the supplied Cartesian.
  2656. *
  2657. * @param {Cartesian3} cartesian The cartesian to use.
  2658. * @returns {Number} The value of the minimum component.
  2659. */
  2660. Cartesian3.minimumComponent = function(cartesian) {
  2661. Check.typeOf.object(cartesian, 'cartesian');
  2662. return Math.min(cartesian.x, cartesian.y, cartesian.z);
  2663. };
  2664. /**
  2665. * Compares two Cartesians and computes a Cartesian which contains the minimum components of the supplied Cartesians.
  2666. *
  2667. * @param {Cartesian3} first A cartesian to compare.
  2668. * @param {Cartesian3} second A cartesian to compare.
  2669. * @param {Cartesian3} result The object into which to store the result.
  2670. * @returns {Cartesian3} A cartesian with the minimum components.
  2671. */
  2672. Cartesian3.minimumByComponent = function(first, second, result) {
  2673. Check.typeOf.object(first, 'first');
  2674. Check.typeOf.object(second, 'second');
  2675. Check.typeOf.object(result, 'result');
  2676. result.x = Math.min(first.x, second.x);
  2677. result.y = Math.min(first.y, second.y);
  2678. result.z = Math.min(first.z, second.z);
  2679. return result;
  2680. };
  2681. /**
  2682. * Compares two Cartesians and computes a Cartesian which contains the maximum components of the supplied Cartesians.
  2683. *
  2684. * @param {Cartesian3} first A cartesian to compare.
  2685. * @param {Cartesian3} second A cartesian to compare.
  2686. * @param {Cartesian3} result The object into which to store the result.
  2687. * @returns {Cartesian3} A cartesian with the maximum components.
  2688. */
  2689. Cartesian3.maximumByComponent = function(first, second, result) {
  2690. Check.typeOf.object(first, 'first');
  2691. Check.typeOf.object(second, 'second');
  2692. Check.typeOf.object(result, 'result');
  2693. result.x = Math.max(first.x, second.x);
  2694. result.y = Math.max(first.y, second.y);
  2695. result.z = Math.max(first.z, second.z);
  2696. return result;
  2697. };
  2698. /**
  2699. * Computes the provided Cartesian's squared magnitude.
  2700. *
  2701. * @param {Cartesian3} cartesian The Cartesian instance whose squared magnitude is to be computed.
  2702. * @returns {Number} The squared magnitude.
  2703. */
  2704. Cartesian3.magnitudeSquared = function(cartesian) {
  2705. Check.typeOf.object(cartesian, 'cartesian');
  2706. return cartesian.x * cartesian.x + cartesian.y * cartesian.y + cartesian.z * cartesian.z;
  2707. };
  2708. /**
  2709. * Computes the Cartesian's magnitude (length).
  2710. *
  2711. * @param {Cartesian3} cartesian The Cartesian instance whose magnitude is to be computed.
  2712. * @returns {Number} The magnitude.
  2713. */
  2714. Cartesian3.magnitude = function(cartesian) {
  2715. return Math.sqrt(Cartesian3.magnitudeSquared(cartesian));
  2716. };
  2717. var distanceScratch = new Cartesian3();
  2718. /**
  2719. * Computes the distance between two points.
  2720. *
  2721. * @param {Cartesian3} left The first point to compute the distance from.
  2722. * @param {Cartesian3} right The second point to compute the distance to.
  2723. * @returns {Number} The distance between two points.
  2724. *
  2725. * @example
  2726. * // Returns 1.0
  2727. * var d = Cesium.Cartesian3.distance(new Cesium.Cartesian3(1.0, 0.0, 0.0), new Cesium.Cartesian3(2.0, 0.0, 0.0));
  2728. */
  2729. Cartesian3.distance = function(left, right) {
  2730. Check.typeOf.object(left, 'left');
  2731. Check.typeOf.object(right, 'right');
  2732. Cartesian3.subtract(left, right, distanceScratch);
  2733. return Cartesian3.magnitude(distanceScratch);
  2734. };
  2735. /**
  2736. * Computes the squared distance between two points. Comparing squared distances
  2737. * using this function is more efficient than comparing distances using {@link Cartesian3#distance}.
  2738. *
  2739. * @param {Cartesian3} left The first point to compute the distance from.
  2740. * @param {Cartesian3} right The second point to compute the distance to.
  2741. * @returns {Number} The distance between two points.
  2742. *
  2743. * @example
  2744. * // Returns 4.0, not 2.0
  2745. * var d = Cesium.Cartesian3.distanceSquared(new Cesium.Cartesian3(1.0, 0.0, 0.0), new Cesium.Cartesian3(3.0, 0.0, 0.0));
  2746. */
  2747. Cartesian3.distanceSquared = function(left, right) {
  2748. Check.typeOf.object(left, 'left');
  2749. Check.typeOf.object(right, 'right');
  2750. Cartesian3.subtract(left, right, distanceScratch);
  2751. return Cartesian3.magnitudeSquared(distanceScratch);
  2752. };
  2753. /**
  2754. * Computes the normalized form of the supplied Cartesian.
  2755. *
  2756. * @param {Cartesian3} cartesian The Cartesian to be normalized.
  2757. * @param {Cartesian3} result The object onto which to store the result.
  2758. * @returns {Cartesian3} The modified result parameter.
  2759. */
  2760. Cartesian3.normalize = function(cartesian, result) {
  2761. Check.typeOf.object(cartesian, 'cartesian');
  2762. Check.typeOf.object(result, 'result');
  2763. var magnitude = Cartesian3.magnitude(cartesian);
  2764. result.x = cartesian.x / magnitude;
  2765. result.y = cartesian.y / magnitude;
  2766. result.z = cartesian.z / magnitude;
  2767. if (isNaN(result.x) || isNaN(result.y) || isNaN(result.z)) {
  2768. throw new DeveloperError('normalized result is not a number');
  2769. }
  2770. return result;
  2771. };
  2772. /**
  2773. * Computes the dot (scalar) product of two Cartesians.
  2774. *
  2775. * @param {Cartesian3} left The first Cartesian.
  2776. * @param {Cartesian3} right The second Cartesian.
  2777. * @returns {Number} The dot product.
  2778. */
  2779. Cartesian3.dot = function(left, right) {
  2780. Check.typeOf.object(left, 'left');
  2781. Check.typeOf.object(right, 'right');
  2782. return left.x * right.x + left.y * right.y + left.z * right.z;
  2783. };
  2784. /**
  2785. * Computes the componentwise product of two Cartesians.
  2786. *
  2787. * @param {Cartesian3} left The first Cartesian.
  2788. * @param {Cartesian3} right The second Cartesian.
  2789. * @param {Cartesian3} result The object onto which to store the result.
  2790. * @returns {Cartesian3} The modified result parameter.
  2791. */
  2792. Cartesian3.multiplyComponents = function(left, right, result) {
  2793. Check.typeOf.object(left, 'left');
  2794. Check.typeOf.object(right, 'right');
  2795. Check.typeOf.object(result, 'result');
  2796. result.x = left.x * right.x;
  2797. result.y = left.y * right.y;
  2798. result.z = left.z * right.z;
  2799. return result;
  2800. };
  2801. /**
  2802. * Computes the componentwise quotient of two Cartesians.
  2803. *
  2804. * @param {Cartesian3} left The first Cartesian.
  2805. * @param {Cartesian3} right The second Cartesian.
  2806. * @param {Cartesian3} result The object onto which to store the result.
  2807. * @returns {Cartesian3} The modified result parameter.
  2808. */
  2809. Cartesian3.divideComponents = function(left, right, result) {
  2810. if (!defined(left)) {
  2811. throw new DeveloperError('left is required');
  2812. }
  2813. if (!defined(right)) {
  2814. throw new DeveloperError('right is required');
  2815. }
  2816. if (!defined(result)) {
  2817. throw new DeveloperError('result is required');
  2818. }
  2819. result.x = left.x / right.x;
  2820. result.y = left.y / right.y;
  2821. result.z = left.z / right.z;
  2822. return result;
  2823. };
  2824. /**
  2825. * Computes the componentwise sum of two Cartesians.
  2826. *
  2827. * @param {Cartesian3} left The first Cartesian.
  2828. * @param {Cartesian3} right The second Cartesian.
  2829. * @param {Cartesian3} result The object onto which to store the result.
  2830. * @returns {Cartesian3} The modified result parameter.
  2831. */
  2832. Cartesian3.add = function(left, right, result) {
  2833. Check.typeOf.object(left, 'left');
  2834. Check.typeOf.object(right, 'right');
  2835. Check.typeOf.object(result, 'result');
  2836. result.x = left.x + right.x;
  2837. result.y = left.y + right.y;
  2838. result.z = left.z + right.z;
  2839. return result;
  2840. };
  2841. /**
  2842. * Computes the componentwise difference of two Cartesians.
  2843. *
  2844. * @param {Cartesian3} left The first Cartesian.
  2845. * @param {Cartesian3} right The second Cartesian.
  2846. * @param {Cartesian3} result The object onto which to store the result.
  2847. * @returns {Cartesian3} The modified result parameter.
  2848. */
  2849. Cartesian3.subtract = function(left, right, result) {
  2850. Check.typeOf.object(left, 'left');
  2851. Check.typeOf.object(right, 'right');
  2852. Check.typeOf.object(result, 'result');
  2853. result.x = left.x - right.x;
  2854. result.y = left.y - right.y;
  2855. result.z = left.z - right.z;
  2856. return result;
  2857. };
  2858. /**
  2859. * Multiplies the provided Cartesian componentwise by the provided scalar.
  2860. *
  2861. * @param {Cartesian3} cartesian The Cartesian to be scaled.
  2862. * @param {Number} scalar The scalar to multiply with.
  2863. * @param {Cartesian3} result The object onto which to store the result.
  2864. * @returns {Cartesian3} The modified result parameter.
  2865. */
  2866. Cartesian3.multiplyByScalar = function(cartesian, scalar, result) {
  2867. Check.typeOf.object(cartesian, 'cartesian');
  2868. Check.typeOf.number(scalar, 'scalar');
  2869. Check.typeOf.object(result, 'result');
  2870. result.x = cartesian.x * scalar;
  2871. result.y = cartesian.y * scalar;
  2872. result.z = cartesian.z * scalar;
  2873. return result;
  2874. };
  2875. /**
  2876. * Divides the provided Cartesian componentwise by the provided scalar.
  2877. *
  2878. * @param {Cartesian3} cartesian The Cartesian to be divided.
  2879. * @param {Number} scalar The scalar to divide by.
  2880. * @param {Cartesian3} result The object onto which to store the result.
  2881. * @returns {Cartesian3} The modified result parameter.
  2882. */
  2883. Cartesian3.divideByScalar = function(cartesian, scalar, result) {
  2884. Check.typeOf.object(cartesian, 'cartesian');
  2885. Check.typeOf.number(scalar, 'scalar');
  2886. Check.typeOf.object(result, 'result');
  2887. result.x = cartesian.x / scalar;
  2888. result.y = cartesian.y / scalar;
  2889. result.z = cartesian.z / scalar;
  2890. return result;
  2891. };
  2892. /**
  2893. * Negates the provided Cartesian.
  2894. *
  2895. * @param {Cartesian3} cartesian The Cartesian to be negated.
  2896. * @param {Cartesian3} result The object onto which to store the result.
  2897. * @returns {Cartesian3} The modified result parameter.
  2898. */
  2899. Cartesian3.negate = function(cartesian, result) {
  2900. Check.typeOf.object(cartesian, 'cartesian');
  2901. Check.typeOf.object(result, 'result');
  2902. result.x = -cartesian.x;
  2903. result.y = -cartesian.y;
  2904. result.z = -cartesian.z;
  2905. return result;
  2906. };
  2907. /**
  2908. * Computes the absolute value of the provided Cartesian.
  2909. *
  2910. * @param {Cartesian3} cartesian The Cartesian whose absolute value is to be computed.
  2911. * @param {Cartesian3} result The object onto which to store the result.
  2912. * @returns {Cartesian3} The modified result parameter.
  2913. */
  2914. Cartesian3.abs = function(cartesian, result) {
  2915. Check.typeOf.object(cartesian, 'cartesian');
  2916. Check.typeOf.object(result, 'result');
  2917. result.x = Math.abs(cartesian.x);
  2918. result.y = Math.abs(cartesian.y);
  2919. result.z = Math.abs(cartesian.z);
  2920. return result;
  2921. };
  2922. var lerpScratch = new Cartesian3();
  2923. /**
  2924. * Computes the linear interpolation or extrapolation at t using the provided cartesians.
  2925. *
  2926. * @param {Cartesian3} start The value corresponding to t at 0.0.
  2927. * @param {Cartesian3} end The value corresponding to t at 1.0.
  2928. * @param {Number} t The point along t at which to interpolate.
  2929. * @param {Cartesian3} result The object onto which to store the result.
  2930. * @returns {Cartesian3} The modified result parameter.
  2931. */
  2932. Cartesian3.lerp = function(start, end, t, result) {
  2933. Check.typeOf.object(start, 'start');
  2934. Check.typeOf.object(end, 'end');
  2935. Check.typeOf.number(t, 't');
  2936. Check.typeOf.object(result, 'result');
  2937. Cartesian3.multiplyByScalar(end, t, lerpScratch);
  2938. result = Cartesian3.multiplyByScalar(start, 1.0 - t, result);
  2939. return Cartesian3.add(lerpScratch, result, result);
  2940. };
  2941. var angleBetweenScratch = new Cartesian3();
  2942. var angleBetweenScratch2 = new Cartesian3();
  2943. /**
  2944. * Returns the angle, in radians, between the provided Cartesians.
  2945. *
  2946. * @param {Cartesian3} left The first Cartesian.
  2947. * @param {Cartesian3} right The second Cartesian.
  2948. * @returns {Number} The angle between the Cartesians.
  2949. */
  2950. Cartesian3.angleBetween = function(left, right) {
  2951. Check.typeOf.object(left, 'left');
  2952. Check.typeOf.object(right, 'right');
  2953. Cartesian3.normalize(left, angleBetweenScratch);
  2954. Cartesian3.normalize(right, angleBetweenScratch2);
  2955. var cosine = Cartesian3.dot(angleBetweenScratch, angleBetweenScratch2);
  2956. var sine = Cartesian3.magnitude(Cartesian3.cross(angleBetweenScratch, angleBetweenScratch2, angleBetweenScratch));
  2957. return Math.atan2(sine, cosine);
  2958. };
  2959. var mostOrthogonalAxisScratch = new Cartesian3();
  2960. /**
  2961. * Returns the axis that is most orthogonal to the provided Cartesian.
  2962. *
  2963. * @param {Cartesian3} cartesian The Cartesian on which to find the most orthogonal axis.
  2964. * @param {Cartesian3} result The object onto which to store the result.
  2965. * @returns {Cartesian3} The most orthogonal axis.
  2966. */
  2967. Cartesian3.mostOrthogonalAxis = function(cartesian, result) {
  2968. Check.typeOf.object(cartesian, 'cartesian');
  2969. Check.typeOf.object(result, 'result');
  2970. var f = Cartesian3.normalize(cartesian, mostOrthogonalAxisScratch);
  2971. Cartesian3.abs(f, f);
  2972. if (f.x <= f.y) {
  2973. if (f.x <= f.z) {
  2974. result = Cartesian3.clone(Cartesian3.UNIT_X, result);
  2975. } else {
  2976. result = Cartesian3.clone(Cartesian3.UNIT_Z, result);
  2977. }
  2978. } else {
  2979. if (f.y <= f.z) {
  2980. result = Cartesian3.clone(Cartesian3.UNIT_Y, result);
  2981. } else {
  2982. result = Cartesian3.clone(Cartesian3.UNIT_Z, result);
  2983. }
  2984. }
  2985. return result;
  2986. };
  2987. /**
  2988. * Compares the provided Cartesians componentwise and returns
  2989. * <code>true</code> if they are equal, <code>false</code> otherwise.
  2990. *
  2991. * @param {Cartesian3} [left] The first Cartesian.
  2992. * @param {Cartesian3} [right] The second Cartesian.
  2993. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  2994. */
  2995. Cartesian3.equals = function(left, right) {
  2996. return (left === right) ||
  2997. ((defined(left)) &&
  2998. (defined(right)) &&
  2999. (left.x === right.x) &&
  3000. (left.y === right.y) &&
  3001. (left.z === right.z));
  3002. };
  3003. /**
  3004. * @private
  3005. */
  3006. Cartesian3.equalsArray = function(cartesian, array, offset) {
  3007. return cartesian.x === array[offset] &&
  3008. cartesian.y === array[offset + 1] &&
  3009. cartesian.z === array[offset + 2];
  3010. };
  3011. /**
  3012. * Compares the provided Cartesians componentwise and returns
  3013. * <code>true</code> if they pass an absolute or relative tolerance test,
  3014. * <code>false</code> otherwise.
  3015. *
  3016. * @param {Cartesian3} [left] The first Cartesian.
  3017. * @param {Cartesian3} [right] The second Cartesian.
  3018. * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
  3019. * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
  3020. * @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
  3021. */
  3022. Cartesian3.equalsEpsilon = function(left, right, relativeEpsilon, absoluteEpsilon) {
  3023. return (left === right) ||
  3024. (defined(left) &&
  3025. defined(right) &&
  3026. CesiumMath.equalsEpsilon(left.x, right.x, relativeEpsilon, absoluteEpsilon) &&
  3027. CesiumMath.equalsEpsilon(left.y, right.y, relativeEpsilon, absoluteEpsilon) &&
  3028. CesiumMath.equalsEpsilon(left.z, right.z, relativeEpsilon, absoluteEpsilon));
  3029. };
  3030. /**
  3031. * Computes the cross (outer) product of two Cartesians.
  3032. *
  3033. * @param {Cartesian3} left The first Cartesian.
  3034. * @param {Cartesian3} right The second Cartesian.
  3035. * @param {Cartesian3} result The object onto which to store the result.
  3036. * @returns {Cartesian3} The cross product.
  3037. */
  3038. Cartesian3.cross = function(left, right, result) {
  3039. Check.typeOf.object(left, 'left');
  3040. Check.typeOf.object(right, 'right');
  3041. Check.typeOf.object(result, 'result');
  3042. var leftX = left.x;
  3043. var leftY = left.y;
  3044. var leftZ = left.z;
  3045. var rightX = right.x;
  3046. var rightY = right.y;
  3047. var rightZ = right.z;
  3048. var x = leftY * rightZ - leftZ * rightY;
  3049. var y = leftZ * rightX - leftX * rightZ;
  3050. var z = leftX * rightY - leftY * rightX;
  3051. result.x = x;
  3052. result.y = y;
  3053. result.z = z;
  3054. return result;
  3055. };
  3056. /**
  3057. * Returns a Cartesian3 position from longitude and latitude values given in degrees.
  3058. *
  3059. * @param {Number} longitude The longitude, in degrees
  3060. * @param {Number} latitude The latitude, in degrees
  3061. * @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
  3062. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
  3063. * @param {Cartesian3} [result] The object onto which to store the result.
  3064. * @returns {Cartesian3} The position
  3065. *
  3066. * @example
  3067. * var position = Cesium.Cartesian3.fromDegrees(-115.0, 37.0);
  3068. */
  3069. Cartesian3.fromDegrees = function(longitude, latitude, height, ellipsoid, result) {
  3070. Check.typeOf.number(longitude, 'longitude');
  3071. Check.typeOf.number(latitude, 'latitude');
  3072. longitude = CesiumMath.toRadians(longitude);
  3073. latitude = CesiumMath.toRadians(latitude);
  3074. return Cartesian3.fromRadians(longitude, latitude, height, ellipsoid, result);
  3075. };
  3076. var scratchN = new Cartesian3();
  3077. var scratchK = new Cartesian3();
  3078. var wgs84RadiiSquared = new Cartesian3(6378137.0 * 6378137.0, 6378137.0 * 6378137.0, 6356752.3142451793 * 6356752.3142451793);
  3079. /**
  3080. * Returns a Cartesian3 position from longitude and latitude values given in radians.
  3081. *
  3082. * @param {Number} longitude The longitude, in radians
  3083. * @param {Number} latitude The latitude, in radians
  3084. * @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
  3085. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
  3086. * @param {Cartesian3} [result] The object onto which to store the result.
  3087. * @returns {Cartesian3} The position
  3088. *
  3089. * @example
  3090. * var position = Cesium.Cartesian3.fromRadians(-2.007, 0.645);
  3091. */
  3092. Cartesian3.fromRadians = function(longitude, latitude, height, ellipsoid, result) {
  3093. Check.typeOf.number(longitude, 'longitude');
  3094. Check.typeOf.number(latitude, 'latitude');
  3095. height = defaultValue(height, 0.0);
  3096. var radiiSquared = defined(ellipsoid) ? ellipsoid.radiiSquared : wgs84RadiiSquared;
  3097. var cosLatitude = Math.cos(latitude);
  3098. scratchN.x = cosLatitude * Math.cos(longitude);
  3099. scratchN.y = cosLatitude * Math.sin(longitude);
  3100. scratchN.z = Math.sin(latitude);
  3101. scratchN = Cartesian3.normalize(scratchN, scratchN);
  3102. Cartesian3.multiplyComponents(radiiSquared, scratchN, scratchK);
  3103. var gamma = Math.sqrt(Cartesian3.dot(scratchN, scratchK));
  3104. scratchK = Cartesian3.divideByScalar(scratchK, gamma, scratchK);
  3105. scratchN = Cartesian3.multiplyByScalar(scratchN, height, scratchN);
  3106. if (!defined(result)) {
  3107. result = new Cartesian3();
  3108. }
  3109. return Cartesian3.add(scratchK, scratchN, result);
  3110. };
  3111. /**
  3112. * Returns an array of Cartesian3 positions given an array of longitude and latitude values given in degrees.
  3113. *
  3114. * @param {Number[]} coordinates A list of longitude and latitude values. Values alternate [longitude, latitude, longitude, latitude...].
  3115. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the coordinates lie.
  3116. * @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result.
  3117. * @returns {Cartesian3[]} The array of positions.
  3118. *
  3119. * @example
  3120. * var positions = Cesium.Cartesian3.fromDegreesArray([-115.0, 37.0, -107.0, 33.0]);
  3121. */
  3122. Cartesian3.fromDegreesArray = function(coordinates, ellipsoid, result) {
  3123. Check.defined(coordinates, 'coordinates');
  3124. if (coordinates.length < 2 || coordinates.length % 2 !== 0) {
  3125. throw new DeveloperError('the number of coordinates must be a multiple of 2 and at least 2');
  3126. }
  3127. var length = coordinates.length;
  3128. if (!defined(result)) {
  3129. result = new Array(length / 2);
  3130. } else {
  3131. result.length = length / 2;
  3132. }
  3133. for (var i = 0; i < length; i += 2) {
  3134. var longitude = coordinates[i];
  3135. var latitude = coordinates[i + 1];
  3136. var index = i / 2;
  3137. result[index] = Cartesian3.fromDegrees(longitude, latitude, 0, ellipsoid, result[index]);
  3138. }
  3139. return result;
  3140. };
  3141. /**
  3142. * Returns an array of Cartesian3 positions given an array of longitude and latitude values given in radians.
  3143. *
  3144. * @param {Number[]} coordinates A list of longitude and latitude values. Values alternate [longitude, latitude, longitude, latitude...].
  3145. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the coordinates lie.
  3146. * @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result.
  3147. * @returns {Cartesian3[]} The array of positions.
  3148. *
  3149. * @example
  3150. * var positions = Cesium.Cartesian3.fromRadiansArray([-2.007, 0.645, -1.867, .575]);
  3151. */
  3152. Cartesian3.fromRadiansArray = function(coordinates, ellipsoid, result) {
  3153. Check.defined(coordinates, 'coordinates');
  3154. if (coordinates.length < 2 || coordinates.length % 2 !== 0) {
  3155. throw new DeveloperError('the number of coordinates must be a multiple of 2 and at least 2');
  3156. }
  3157. var length = coordinates.length;
  3158. if (!defined(result)) {
  3159. result = new Array(length / 2);
  3160. } else {
  3161. result.length = length / 2;
  3162. }
  3163. for (var i = 0; i < length; i += 2) {
  3164. var longitude = coordinates[i];
  3165. var latitude = coordinates[i + 1];
  3166. var index = i / 2;
  3167. result[index] = Cartesian3.fromRadians(longitude, latitude, 0, ellipsoid, result[index]);
  3168. }
  3169. return result;
  3170. };
  3171. /**
  3172. * Returns an array of Cartesian3 positions given an array of longitude, latitude and height values where longitude and latitude are given in degrees.
  3173. *
  3174. * @param {Number[]} coordinates A list of longitude, latitude and height values. Values alternate [longitude, latitude, height, longitude, latitude, height...].
  3175. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
  3176. * @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result.
  3177. * @returns {Cartesian3[]} The array of positions.
  3178. *
  3179. * @example
  3180. * var positions = Cesium.Cartesian3.fromDegreesArrayHeights([-115.0, 37.0, 100000.0, -107.0, 33.0, 150000.0]);
  3181. */
  3182. Cartesian3.fromDegreesArrayHeights = function(coordinates, ellipsoid, result) {
  3183. Check.defined(coordinates, 'coordinates');
  3184. if (coordinates.length < 3 || coordinates.length % 3 !== 0) {
  3185. throw new DeveloperError('the number of coordinates must be a multiple of 3 and at least 3');
  3186. }
  3187. var length = coordinates.length;
  3188. if (!defined(result)) {
  3189. result = new Array(length / 3);
  3190. } else {
  3191. result.length = length / 3;
  3192. }
  3193. for (var i = 0; i < length; i += 3) {
  3194. var longitude = coordinates[i];
  3195. var latitude = coordinates[i + 1];
  3196. var height = coordinates[i + 2];
  3197. var index = i / 3;
  3198. result[index] = Cartesian3.fromDegrees(longitude, latitude, height, ellipsoid, result[index]);
  3199. }
  3200. return result;
  3201. };
  3202. /**
  3203. * Returns an array of Cartesian3 positions given an array of longitude, latitude and height values where longitude and latitude are given in radians.
  3204. *
  3205. * @param {Number[]} coordinates A list of longitude, latitude and height values. Values alternate [longitude, latitude, height, longitude, latitude, height...].
  3206. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
  3207. * @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result.
  3208. * @returns {Cartesian3[]} The array of positions.
  3209. *
  3210. * @example
  3211. * var positions = Cesium.Cartesian3.fromRadiansArrayHeights([-2.007, 0.645, 100000.0, -1.867, .575, 150000.0]);
  3212. */
  3213. Cartesian3.fromRadiansArrayHeights = function(coordinates, ellipsoid, result) {
  3214. Check.defined(coordinates, 'coordinates');
  3215. if (coordinates.length < 3 || coordinates.length % 3 !== 0) {
  3216. throw new DeveloperError('the number of coordinates must be a multiple of 3 and at least 3');
  3217. }
  3218. var length = coordinates.length;
  3219. if (!defined(result)) {
  3220. result = new Array(length / 3);
  3221. } else {
  3222. result.length = length / 3;
  3223. }
  3224. for (var i = 0; i < length; i += 3) {
  3225. var longitude = coordinates[i];
  3226. var latitude = coordinates[i + 1];
  3227. var height = coordinates[i + 2];
  3228. var index = i / 3;
  3229. result[index] = Cartesian3.fromRadians(longitude, latitude, height, ellipsoid, result[index]);
  3230. }
  3231. return result;
  3232. };
  3233. /**
  3234. * An immutable Cartesian3 instance initialized to (0.0, 0.0, 0.0).
  3235. *
  3236. * @type {Cartesian3}
  3237. * @constant
  3238. */
  3239. Cartesian3.ZERO = freezeObject(new Cartesian3(0.0, 0.0, 0.0));
  3240. /**
  3241. * An immutable Cartesian3 instance initialized to (1.0, 0.0, 0.0).
  3242. *
  3243. * @type {Cartesian3}
  3244. * @constant
  3245. */
  3246. Cartesian3.UNIT_X = freezeObject(new Cartesian3(1.0, 0.0, 0.0));
  3247. /**
  3248. * An immutable Cartesian3 instance initialized to (0.0, 1.0, 0.0).
  3249. *
  3250. * @type {Cartesian3}
  3251. * @constant
  3252. */
  3253. Cartesian3.UNIT_Y = freezeObject(new Cartesian3(0.0, 1.0, 0.0));
  3254. /**
  3255. * An immutable Cartesian3 instance initialized to (0.0, 0.0, 1.0).
  3256. *
  3257. * @type {Cartesian3}
  3258. * @constant
  3259. */
  3260. Cartesian3.UNIT_Z = freezeObject(new Cartesian3(0.0, 0.0, 1.0));
  3261. /**
  3262. * Duplicates this Cartesian3 instance.
  3263. *
  3264. * @param {Cartesian3} [result] The object onto which to store the result.
  3265. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
  3266. */
  3267. Cartesian3.prototype.clone = function(result) {
  3268. return Cartesian3.clone(this, result);
  3269. };
  3270. /**
  3271. * Compares this Cartesian against the provided Cartesian componentwise and returns
  3272. * <code>true</code> if they are equal, <code>false</code> otherwise.
  3273. *
  3274. * @param {Cartesian3} [right] The right hand side Cartesian.
  3275. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  3276. */
  3277. Cartesian3.prototype.equals = function(right) {
  3278. return Cartesian3.equals(this, right);
  3279. };
  3280. /**
  3281. * Compares this Cartesian against the provided Cartesian componentwise and returns
  3282. * <code>true</code> if they pass an absolute or relative tolerance test,
  3283. * <code>false</code> otherwise.
  3284. *
  3285. * @param {Cartesian3} [right] The right hand side Cartesian.
  3286. * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
  3287. * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
  3288. * @returns {Boolean} <code>true</code> if they are within the provided epsilon, <code>false</code> otherwise.
  3289. */
  3290. Cartesian3.prototype.equalsEpsilon = function(right, relativeEpsilon, absoluteEpsilon) {
  3291. return Cartesian3.equalsEpsilon(this, right, relativeEpsilon, absoluteEpsilon);
  3292. };
  3293. /**
  3294. * Creates a string representing this Cartesian in the format '(x, y, z)'.
  3295. *
  3296. * @returns {String} A string representing this Cartesian in the format '(x, y, z)'.
  3297. */
  3298. Cartesian3.prototype.toString = function() {
  3299. return '(' + this.x + ', ' + this.y + ', ' + this.z + ')';
  3300. };
  3301. return Cartesian3;
  3302. });
  3303. /*global define*/
  3304. define('Core/scaleToGeodeticSurface',[
  3305. './Cartesian3',
  3306. './defined',
  3307. './DeveloperError',
  3308. './Math'
  3309. ], function(
  3310. Cartesian3,
  3311. defined,
  3312. DeveloperError,
  3313. CesiumMath) {
  3314. 'use strict';
  3315. var scaleToGeodeticSurfaceIntersection = new Cartesian3();
  3316. var scaleToGeodeticSurfaceGradient = new Cartesian3();
  3317. /**
  3318. * Scales the provided Cartesian position along the geodetic surface normal
  3319. * so that it is on the surface of this ellipsoid. If the position is
  3320. * at the center of the ellipsoid, this function returns undefined.
  3321. *
  3322. * @param {Cartesian3} cartesian The Cartesian position to scale.
  3323. * @param {Cartesian3} oneOverRadii One over radii of the ellipsoid.
  3324. * @param {Cartesian3} oneOverRadiiSquared One over radii squared of the ellipsoid.
  3325. * @param {Number} centerToleranceSquared Tolerance for closeness to the center.
  3326. * @param {Cartesian3} [result] The object onto which to store the result.
  3327. * @returns {Cartesian3} The modified result parameter, a new Cartesian3 instance if none was provided, or undefined if the position is at the center.
  3328. *
  3329. * @exports scaleToGeodeticSurface
  3330. *
  3331. * @private
  3332. */
  3333. function scaleToGeodeticSurface(cartesian, oneOverRadii, oneOverRadiiSquared, centerToleranceSquared, result) {
  3334. if (!defined(cartesian)) {
  3335. throw new DeveloperError('cartesian is required.');
  3336. }
  3337. if (!defined(oneOverRadii)) {
  3338. throw new DeveloperError('oneOverRadii is required.');
  3339. }
  3340. if (!defined(oneOverRadiiSquared)) {
  3341. throw new DeveloperError('oneOverRadiiSquared is required.');
  3342. }
  3343. if (!defined(centerToleranceSquared)) {
  3344. throw new DeveloperError('centerToleranceSquared is required.');
  3345. }
  3346. var positionX = cartesian.x;
  3347. var positionY = cartesian.y;
  3348. var positionZ = cartesian.z;
  3349. var oneOverRadiiX = oneOverRadii.x;
  3350. var oneOverRadiiY = oneOverRadii.y;
  3351. var oneOverRadiiZ = oneOverRadii.z;
  3352. var x2 = positionX * positionX * oneOverRadiiX * oneOverRadiiX;
  3353. var y2 = positionY * positionY * oneOverRadiiY * oneOverRadiiY;
  3354. var z2 = positionZ * positionZ * oneOverRadiiZ * oneOverRadiiZ;
  3355. // Compute the squared ellipsoid norm.
  3356. var squaredNorm = x2 + y2 + z2;
  3357. var ratio = Math.sqrt(1.0 / squaredNorm);
  3358. // As an initial approximation, assume that the radial intersection is the projection point.
  3359. var intersection = Cartesian3.multiplyByScalar(cartesian, ratio, scaleToGeodeticSurfaceIntersection);
  3360. // If the position is near the center, the iteration will not converge.
  3361. if (squaredNorm < centerToleranceSquared) {
  3362. return !isFinite(ratio) ? undefined : Cartesian3.clone(intersection, result);
  3363. }
  3364. var oneOverRadiiSquaredX = oneOverRadiiSquared.x;
  3365. var oneOverRadiiSquaredY = oneOverRadiiSquared.y;
  3366. var oneOverRadiiSquaredZ = oneOverRadiiSquared.z;
  3367. // Use the gradient at the intersection point in place of the true unit normal.
  3368. // The difference in magnitude will be absorbed in the multiplier.
  3369. var gradient = scaleToGeodeticSurfaceGradient;
  3370. gradient.x = intersection.x * oneOverRadiiSquaredX * 2.0;
  3371. gradient.y = intersection.y * oneOverRadiiSquaredY * 2.0;
  3372. gradient.z = intersection.z * oneOverRadiiSquaredZ * 2.0;
  3373. // Compute the initial guess at the normal vector multiplier, lambda.
  3374. var lambda = (1.0 - ratio) * Cartesian3.magnitude(cartesian) / (0.5 * Cartesian3.magnitude(gradient));
  3375. var correction = 0.0;
  3376. var func;
  3377. var denominator;
  3378. var xMultiplier;
  3379. var yMultiplier;
  3380. var zMultiplier;
  3381. var xMultiplier2;
  3382. var yMultiplier2;
  3383. var zMultiplier2;
  3384. var xMultiplier3;
  3385. var yMultiplier3;
  3386. var zMultiplier3;
  3387. do {
  3388. lambda -= correction;
  3389. xMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquaredX);
  3390. yMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquaredY);
  3391. zMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquaredZ);
  3392. xMultiplier2 = xMultiplier * xMultiplier;
  3393. yMultiplier2 = yMultiplier * yMultiplier;
  3394. zMultiplier2 = zMultiplier * zMultiplier;
  3395. xMultiplier3 = xMultiplier2 * xMultiplier;
  3396. yMultiplier3 = yMultiplier2 * yMultiplier;
  3397. zMultiplier3 = zMultiplier2 * zMultiplier;
  3398. func = x2 * xMultiplier2 + y2 * yMultiplier2 + z2 * zMultiplier2 - 1.0;
  3399. // "denominator" here refers to the use of this expression in the velocity and acceleration
  3400. // computations in the sections to follow.
  3401. denominator = x2 * xMultiplier3 * oneOverRadiiSquaredX + y2 * yMultiplier3 * oneOverRadiiSquaredY + z2 * zMultiplier3 * oneOverRadiiSquaredZ;
  3402. var derivative = -2.0 * denominator;
  3403. correction = func / derivative;
  3404. } while (Math.abs(func) > CesiumMath.EPSILON12);
  3405. if (!defined(result)) {
  3406. return new Cartesian3(positionX * xMultiplier, positionY * yMultiplier, positionZ * zMultiplier);
  3407. }
  3408. result.x = positionX * xMultiplier;
  3409. result.y = positionY * yMultiplier;
  3410. result.z = positionZ * zMultiplier;
  3411. return result;
  3412. }
  3413. return scaleToGeodeticSurface;
  3414. });
  3415. /*global define*/
  3416. define('Core/Cartographic',[
  3417. './Cartesian3',
  3418. './defaultValue',
  3419. './defined',
  3420. './DeveloperError',
  3421. './freezeObject',
  3422. './Math',
  3423. './scaleToGeodeticSurface'
  3424. ], function(
  3425. Cartesian3,
  3426. defaultValue,
  3427. defined,
  3428. DeveloperError,
  3429. freezeObject,
  3430. CesiumMath,
  3431. scaleToGeodeticSurface) {
  3432. 'use strict';
  3433. /**
  3434. * A position defined by longitude, latitude, and height.
  3435. * @alias Cartographic
  3436. * @constructor
  3437. *
  3438. * @param {Number} [longitude=0.0] The longitude, in radians.
  3439. * @param {Number} [latitude=0.0] The latitude, in radians.
  3440. * @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
  3441. *
  3442. * @see Ellipsoid
  3443. */
  3444. function Cartographic(longitude, latitude, height) {
  3445. /**
  3446. * The longitude, in radians.
  3447. * @type {Number}
  3448. * @default 0.0
  3449. */
  3450. this.longitude = defaultValue(longitude, 0.0);
  3451. /**
  3452. * The latitude, in radians.
  3453. * @type {Number}
  3454. * @default 0.0
  3455. */
  3456. this.latitude = defaultValue(latitude, 0.0);
  3457. /**
  3458. * The height, in meters, above the ellipsoid.
  3459. * @type {Number}
  3460. * @default 0.0
  3461. */
  3462. this.height = defaultValue(height, 0.0);
  3463. }
  3464. /**
  3465. * Creates a new Cartographic instance from longitude and latitude
  3466. * specified in radians.
  3467. *
  3468. * @param {Number} longitude The longitude, in radians.
  3469. * @param {Number} latitude The latitude, in radians.
  3470. * @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
  3471. * @param {Cartographic} [result] The object onto which to store the result.
  3472. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided.
  3473. */
  3474. Cartographic.fromRadians = function(longitude, latitude, height, result) {
  3475. if (!defined(longitude)) {
  3476. throw new DeveloperError('longitude is required.');
  3477. }
  3478. if (!defined(latitude)) {
  3479. throw new DeveloperError('latitude is required.');
  3480. }
  3481. height = defaultValue(height, 0.0);
  3482. if (!defined(result)) {
  3483. return new Cartographic(longitude, latitude, height);
  3484. }
  3485. result.longitude = longitude;
  3486. result.latitude = latitude;
  3487. result.height = height;
  3488. return result;
  3489. };
  3490. /**
  3491. * Creates a new Cartographic instance from longitude and latitude
  3492. * specified in degrees. The values in the resulting object will
  3493. * be in radians.
  3494. *
  3495. * @param {Number} longitude The longitude, in degrees.
  3496. * @param {Number} latitude The latitude, in degrees.
  3497. * @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
  3498. * @param {Cartographic} [result] The object onto which to store the result.
  3499. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided.
  3500. */
  3501. Cartographic.fromDegrees = function(longitude, latitude, height, result) {
  3502. if (!defined(longitude)) {
  3503. throw new DeveloperError('longitude is required.');
  3504. }
  3505. if (!defined(latitude)) {
  3506. throw new DeveloperError('latitude is required.');
  3507. }
  3508. longitude = CesiumMath.toRadians(longitude);
  3509. latitude = CesiumMath.toRadians(latitude);
  3510. return Cartographic.fromRadians(longitude, latitude, height, result);
  3511. };
  3512. var cartesianToCartographicN = new Cartesian3();
  3513. var cartesianToCartographicP = new Cartesian3();
  3514. var cartesianToCartographicH = new Cartesian3();
  3515. var wgs84OneOverRadii = new Cartesian3(1.0 / 6378137.0, 1.0 / 6378137.0, 1.0 / 6356752.3142451793);
  3516. var wgs84OneOverRadiiSquared = new Cartesian3(1.0 / (6378137.0 * 6378137.0), 1.0 / (6378137.0 * 6378137.0), 1.0 / (6356752.3142451793 * 6356752.3142451793));
  3517. var wgs84CenterToleranceSquared = CesiumMath.EPSILON1;
  3518. /**
  3519. * Creates a new Cartographic instance from a Cartesian position. The values in the
  3520. * resulting object will be in radians.
  3521. *
  3522. * @param {Cartesian3} cartesian The Cartesian position to convert to cartographic representation.
  3523. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
  3524. * @param {Cartographic} [result] The object onto which to store the result.
  3525. * @returns {Cartographic} The modified result parameter, new Cartographic instance if none was provided, or undefined if the cartesian is at the center of the ellipsoid.
  3526. */
  3527. Cartographic.fromCartesian = function(cartesian, ellipsoid, result) {
  3528. var oneOverRadii = defined(ellipsoid) ? ellipsoid.oneOverRadii : wgs84OneOverRadii;
  3529. var oneOverRadiiSquared = defined(ellipsoid) ? ellipsoid.oneOverRadiiSquared : wgs84OneOverRadiiSquared;
  3530. var centerToleranceSquared = defined(ellipsoid) ? ellipsoid._centerToleranceSquared : wgs84CenterToleranceSquared;
  3531. //`cartesian is required.` is thrown from scaleToGeodeticSurface
  3532. var p = scaleToGeodeticSurface(cartesian, oneOverRadii, oneOverRadiiSquared, centerToleranceSquared, cartesianToCartographicP);
  3533. if (!defined(p)) {
  3534. return undefined;
  3535. }
  3536. var n = Cartesian3.multiplyComponents(p, oneOverRadiiSquared, cartesianToCartographicN);
  3537. n = Cartesian3.normalize(n, n);
  3538. var h = Cartesian3.subtract(cartesian, p, cartesianToCartographicH);
  3539. var longitude = Math.atan2(n.y, n.x);
  3540. var latitude = Math.asin(n.z);
  3541. var height = CesiumMath.sign(Cartesian3.dot(h, cartesian)) * Cartesian3.magnitude(h);
  3542. if (!defined(result)) {
  3543. return new Cartographic(longitude, latitude, height);
  3544. }
  3545. result.longitude = longitude;
  3546. result.latitude = latitude;
  3547. result.height = height;
  3548. return result;
  3549. };
  3550. /**
  3551. * Duplicates a Cartographic instance.
  3552. *
  3553. * @param {Cartographic} cartographic The cartographic to duplicate.
  3554. * @param {Cartographic} [result] The object onto which to store the result.
  3555. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided. (Returns undefined if cartographic is undefined)
  3556. */
  3557. Cartographic.clone = function(cartographic, result) {
  3558. if (!defined(cartographic)) {
  3559. return undefined;
  3560. }
  3561. if (!defined(result)) {
  3562. return new Cartographic(cartographic.longitude, cartographic.latitude, cartographic.height);
  3563. }
  3564. result.longitude = cartographic.longitude;
  3565. result.latitude = cartographic.latitude;
  3566. result.height = cartographic.height;
  3567. return result;
  3568. };
  3569. /**
  3570. * Compares the provided cartographics componentwise and returns
  3571. * <code>true</code> if they are equal, <code>false</code> otherwise.
  3572. *
  3573. * @param {Cartographic} [left] The first cartographic.
  3574. * @param {Cartographic} [right] The second cartographic.
  3575. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  3576. */
  3577. Cartographic.equals = function(left, right) {
  3578. return (left === right) ||
  3579. ((defined(left)) &&
  3580. (defined(right)) &&
  3581. (left.longitude === right.longitude) &&
  3582. (left.latitude === right.latitude) &&
  3583. (left.height === right.height));
  3584. };
  3585. /**
  3586. * Compares the provided cartographics componentwise and returns
  3587. * <code>true</code> if they are within the provided epsilon,
  3588. * <code>false</code> otherwise.
  3589. *
  3590. * @param {Cartographic} [left] The first cartographic.
  3591. * @param {Cartographic} [right] The second cartographic.
  3592. * @param {Number} epsilon The epsilon to use for equality testing.
  3593. * @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
  3594. */
  3595. Cartographic.equalsEpsilon = function(left, right, epsilon) {
  3596. if (typeof epsilon !== 'number') {
  3597. throw new DeveloperError('epsilon is required and must be a number.');
  3598. }
  3599. return (left === right) ||
  3600. ((defined(left)) &&
  3601. (defined(right)) &&
  3602. (Math.abs(left.longitude - right.longitude) <= epsilon) &&
  3603. (Math.abs(left.latitude - right.latitude) <= epsilon) &&
  3604. (Math.abs(left.height - right.height) <= epsilon));
  3605. };
  3606. /**
  3607. * An immutable Cartographic instance initialized to (0.0, 0.0, 0.0).
  3608. *
  3609. * @type {Cartographic}
  3610. * @constant
  3611. */
  3612. Cartographic.ZERO = freezeObject(new Cartographic(0.0, 0.0, 0.0));
  3613. /**
  3614. * Duplicates this instance.
  3615. *
  3616. * @param {Cartographic} [result] The object onto which to store the result.
  3617. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided.
  3618. */
  3619. Cartographic.prototype.clone = function(result) {
  3620. return Cartographic.clone(this, result);
  3621. };
  3622. /**
  3623. * Compares the provided against this cartographic componentwise and returns
  3624. * <code>true</code> if they are equal, <code>false</code> otherwise.
  3625. *
  3626. * @param {Cartographic} [right] The second cartographic.
  3627. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  3628. */
  3629. Cartographic.prototype.equals = function(right) {
  3630. return Cartographic.equals(this, right);
  3631. };
  3632. /**
  3633. * Compares the provided against this cartographic componentwise and returns
  3634. * <code>true</code> if they are within the provided epsilon,
  3635. * <code>false</code> otherwise.
  3636. *
  3637. * @param {Cartographic} [right] The second cartographic.
  3638. * @param {Number} epsilon The epsilon to use for equality testing.
  3639. * @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
  3640. */
  3641. Cartographic.prototype.equalsEpsilon = function(right, epsilon) {
  3642. return Cartographic.equalsEpsilon(this, right, epsilon);
  3643. };
  3644. /**
  3645. * Creates a string representing this cartographic in the format '(longitude, latitude, height)'.
  3646. *
  3647. * @returns {String} A string representing the provided cartographic in the format '(longitude, latitude, height)'.
  3648. */
  3649. Cartographic.prototype.toString = function() {
  3650. return '(' + this.longitude + ', ' + this.latitude + ', ' + this.height + ')';
  3651. };
  3652. return Cartographic;
  3653. });
  3654. /*global define*/
  3655. define('Core/Ellipsoid',[
  3656. './Cartesian3',
  3657. './Cartographic',
  3658. './defaultValue',
  3659. './defined',
  3660. './defineProperties',
  3661. './DeveloperError',
  3662. './freezeObject',
  3663. './Math',
  3664. './scaleToGeodeticSurface'
  3665. ], function(
  3666. Cartesian3,
  3667. Cartographic,
  3668. defaultValue,
  3669. defined,
  3670. defineProperties,
  3671. DeveloperError,
  3672. freezeObject,
  3673. CesiumMath,
  3674. scaleToGeodeticSurface) {
  3675. 'use strict';
  3676. function initialize(ellipsoid, x, y, z) {
  3677. x = defaultValue(x, 0.0);
  3678. y = defaultValue(y, 0.0);
  3679. z = defaultValue(z, 0.0);
  3680. if (x < 0.0 || y < 0.0 || z < 0.0) {
  3681. throw new DeveloperError('All radii components must be greater than or equal to zero.');
  3682. }
  3683. ellipsoid._radii = new Cartesian3(x, y, z);
  3684. ellipsoid._radiiSquared = new Cartesian3(x * x,
  3685. y * y,
  3686. z * z);
  3687. ellipsoid._radiiToTheFourth = new Cartesian3(x * x * x * x,
  3688. y * y * y * y,
  3689. z * z * z * z);
  3690. ellipsoid._oneOverRadii = new Cartesian3(x === 0.0 ? 0.0 : 1.0 / x,
  3691. y === 0.0 ? 0.0 : 1.0 / y,
  3692. z === 0.0 ? 0.0 : 1.0 / z);
  3693. ellipsoid._oneOverRadiiSquared = new Cartesian3(x === 0.0 ? 0.0 : 1.0 / (x * x),
  3694. y === 0.0 ? 0.0 : 1.0 / (y * y),
  3695. z === 0.0 ? 0.0 : 1.0 / (z * z));
  3696. ellipsoid._minimumRadius = Math.min(x, y, z);
  3697. ellipsoid._maximumRadius = Math.max(x, y, z);
  3698. ellipsoid._centerToleranceSquared = CesiumMath.EPSILON1;
  3699. if (ellipsoid._radiiSquared.z !== 0) {
  3700. ellipsoid._sqauredXOverSquaredZ = ellipsoid._radiiSquared.x / ellipsoid._radiiSquared.z;
  3701. }
  3702. }
  3703. /**
  3704. * A quadratic surface defined in Cartesian coordinates by the equation
  3705. * <code>(x / a)^2 + (y / b)^2 + (z / c)^2 = 1</code>. Primarily used
  3706. * by Cesium to represent the shape of planetary bodies.
  3707. *
  3708. * Rather than constructing this object directly, one of the provided
  3709. * constants is normally used.
  3710. * @alias Ellipsoid
  3711. * @constructor
  3712. *
  3713. * @param {Number} [x=0] The radius in the x direction.
  3714. * @param {Number} [y=0] The radius in the y direction.
  3715. * @param {Number} [z=0] The radius in the z direction.
  3716. *
  3717. * @exception {DeveloperError} All radii components must be greater than or equal to zero.
  3718. *
  3719. * @see Ellipsoid.fromCartesian3
  3720. * @see Ellipsoid.WGS84
  3721. * @see Ellipsoid.UNIT_SPHERE
  3722. */
  3723. function Ellipsoid(x, y, z) {
  3724. this._radii = undefined;
  3725. this._radiiSquared = undefined;
  3726. this._radiiToTheFourth = undefined;
  3727. this._oneOverRadii = undefined;
  3728. this._oneOverRadiiSquared = undefined;
  3729. this._minimumRadius = undefined;
  3730. this._maximumRadius = undefined;
  3731. this._centerToleranceSquared = undefined;
  3732. this._sqauredXOverSquaredZ = undefined;
  3733. initialize(this, x, y, z);
  3734. }
  3735. defineProperties(Ellipsoid.prototype, {
  3736. /**
  3737. * Gets the radii of the ellipsoid.
  3738. * @memberof Ellipsoid.prototype
  3739. * @type {Cartesian3}
  3740. * @readonly
  3741. */
  3742. radii : {
  3743. get: function() {
  3744. return this._radii;
  3745. }
  3746. },
  3747. /**
  3748. * Gets the squared radii of the ellipsoid.
  3749. * @memberof Ellipsoid.prototype
  3750. * @type {Cartesian3}
  3751. * @readonly
  3752. */
  3753. radiiSquared : {
  3754. get : function() {
  3755. return this._radiiSquared;
  3756. }
  3757. },
  3758. /**
  3759. * Gets the radii of the ellipsoid raise to the fourth power.
  3760. * @memberof Ellipsoid.prototype
  3761. * @type {Cartesian3}
  3762. * @readonly
  3763. */
  3764. radiiToTheFourth : {
  3765. get : function() {
  3766. return this._radiiToTheFourth;
  3767. }
  3768. },
  3769. /**
  3770. * Gets one over the radii of the ellipsoid.
  3771. * @memberof Ellipsoid.prototype
  3772. * @type {Cartesian3}
  3773. * @readonly
  3774. */
  3775. oneOverRadii : {
  3776. get : function() {
  3777. return this._oneOverRadii;
  3778. }
  3779. },
  3780. /**
  3781. * Gets one over the squared radii of the ellipsoid.
  3782. * @memberof Ellipsoid.prototype
  3783. * @type {Cartesian3}
  3784. * @readonly
  3785. */
  3786. oneOverRadiiSquared : {
  3787. get : function() {
  3788. return this._oneOverRadiiSquared;
  3789. }
  3790. },
  3791. /**
  3792. * Gets the minimum radius of the ellipsoid.
  3793. * @memberof Ellipsoid.prototype
  3794. * @type {Number}
  3795. * @readonly
  3796. */
  3797. minimumRadius : {
  3798. get : function() {
  3799. return this._minimumRadius;
  3800. }
  3801. },
  3802. /**
  3803. * Gets the maximum radius of the ellipsoid.
  3804. * @memberof Ellipsoid.prototype
  3805. * @type {Number}
  3806. * @readonly
  3807. */
  3808. maximumRadius : {
  3809. get : function() {
  3810. return this._maximumRadius;
  3811. }
  3812. }
  3813. });
  3814. /**
  3815. * Duplicates an Ellipsoid instance.
  3816. *
  3817. * @param {Ellipsoid} ellipsoid The ellipsoid to duplicate.
  3818. * @param {Ellipsoid} [result] The object onto which to store the result, or undefined if a new
  3819. * instance should be created.
  3820. * @returns {Ellipsoid} The cloned Ellipsoid. (Returns undefined if ellipsoid is undefined)
  3821. */
  3822. Ellipsoid.clone = function(ellipsoid, result) {
  3823. if (!defined(ellipsoid)) {
  3824. return undefined;
  3825. }
  3826. var radii = ellipsoid._radii;
  3827. if (!defined(result)) {
  3828. return new Ellipsoid(radii.x, radii.y, radii.z);
  3829. }
  3830. Cartesian3.clone(radii, result._radii);
  3831. Cartesian3.clone(ellipsoid._radiiSquared, result._radiiSquared);
  3832. Cartesian3.clone(ellipsoid._radiiToTheFourth, result._radiiToTheFourth);
  3833. Cartesian3.clone(ellipsoid._oneOverRadii, result._oneOverRadii);
  3834. Cartesian3.clone(ellipsoid._oneOverRadiiSquared, result._oneOverRadiiSquared);
  3835. result._minimumRadius = ellipsoid._minimumRadius;
  3836. result._maximumRadius = ellipsoid._maximumRadius;
  3837. result._centerToleranceSquared = ellipsoid._centerToleranceSquared;
  3838. return result;
  3839. };
  3840. /**
  3841. * Computes an Ellipsoid from a Cartesian specifying the radii in x, y, and z directions.
  3842. *
  3843. * @param {Cartesian3} [radii=Cartesian3.ZERO] The ellipsoid's radius in the x, y, and z directions.
  3844. * @returns {Ellipsoid} A new Ellipsoid instance.
  3845. *
  3846. * @exception {DeveloperError} All radii components must be greater than or equal to zero.
  3847. *
  3848. * @see Ellipsoid.WGS84
  3849. * @see Ellipsoid.UNIT_SPHERE
  3850. */
  3851. Ellipsoid.fromCartesian3 = function(cartesian, result) {
  3852. if (!defined(result)) {
  3853. result = new Ellipsoid();
  3854. }
  3855. if (!defined(cartesian)) {
  3856. return result;
  3857. }
  3858. initialize(result, cartesian.x, cartesian.y, cartesian.z);
  3859. return result;
  3860. };
  3861. /**
  3862. * An Ellipsoid instance initialized to the WGS84 standard.
  3863. *
  3864. * @type {Ellipsoid}
  3865. * @constant
  3866. */
  3867. Ellipsoid.WGS84 = freezeObject(new Ellipsoid(6378137.0, 6378137.0, 6356752.3142451793));
  3868. /**
  3869. * An Ellipsoid instance initialized to radii of (1.0, 1.0, 1.0).
  3870. *
  3871. * @type {Ellipsoid}
  3872. * @constant
  3873. */
  3874. Ellipsoid.UNIT_SPHERE = freezeObject(new Ellipsoid(1.0, 1.0, 1.0));
  3875. /**
  3876. * An Ellipsoid instance initialized to a sphere with the lunar radius.
  3877. *
  3878. * @type {Ellipsoid}
  3879. * @constant
  3880. */
  3881. Ellipsoid.MOON = freezeObject(new Ellipsoid(CesiumMath.LUNAR_RADIUS, CesiumMath.LUNAR_RADIUS, CesiumMath.LUNAR_RADIUS));
  3882. /**
  3883. * Duplicates an Ellipsoid instance.
  3884. *
  3885. * @param {Ellipsoid} [result] The object onto which to store the result, or undefined if a new
  3886. * instance should be created.
  3887. * @returns {Ellipsoid} The cloned Ellipsoid.
  3888. */
  3889. Ellipsoid.prototype.clone = function(result) {
  3890. return Ellipsoid.clone(this, result);
  3891. };
  3892. /**
  3893. * The number of elements used to pack the object into an array.
  3894. * @type {Number}
  3895. */
  3896. Ellipsoid.packedLength = Cartesian3.packedLength;
  3897. /**
  3898. * Stores the provided instance into the provided array.
  3899. *
  3900. * @param {Ellipsoid} value The value to pack.
  3901. * @param {Number[]} array The array to pack into.
  3902. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  3903. *
  3904. * @returns {Number[]} The array that was packed into
  3905. */
  3906. Ellipsoid.pack = function(value, array, startingIndex) {
  3907. if (!defined(value)) {
  3908. throw new DeveloperError('value is required');
  3909. }
  3910. if (!defined(array)) {
  3911. throw new DeveloperError('array is required');
  3912. }
  3913. startingIndex = defaultValue(startingIndex, 0);
  3914. Cartesian3.pack(value._radii, array, startingIndex);
  3915. return array;
  3916. };
  3917. /**
  3918. * Retrieves an instance from a packed array.
  3919. *
  3920. * @param {Number[]} array The packed array.
  3921. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  3922. * @param {Ellipsoid} [result] The object into which to store the result.
  3923. * @returns {Ellipsoid} The modified result parameter or a new Ellipsoid instance if one was not provided.
  3924. */
  3925. Ellipsoid.unpack = function(array, startingIndex, result) {
  3926. if (!defined(array)) {
  3927. throw new DeveloperError('array is required');
  3928. }
  3929. startingIndex = defaultValue(startingIndex, 0);
  3930. var radii = Cartesian3.unpack(array, startingIndex);
  3931. return Ellipsoid.fromCartesian3(radii, result);
  3932. };
  3933. /**
  3934. * Computes the unit vector directed from the center of this ellipsoid toward the provided Cartesian position.
  3935. * @function
  3936. *
  3937. * @param {Cartesian3} cartesian The Cartesian for which to to determine the geocentric normal.
  3938. * @param {Cartesian3} [result] The object onto which to store the result.
  3939. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
  3940. */
  3941. Ellipsoid.prototype.geocentricSurfaceNormal = Cartesian3.normalize;
  3942. /**
  3943. * Computes the normal of the plane tangent to the surface of the ellipsoid at the provided position.
  3944. *
  3945. * @param {Cartographic} cartographic The cartographic position for which to to determine the geodetic normal.
  3946. * @param {Cartesian3} [result] The object onto which to store the result.
  3947. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
  3948. */
  3949. Ellipsoid.prototype.geodeticSurfaceNormalCartographic = function(cartographic, result) {
  3950. if (!defined(cartographic)) {
  3951. throw new DeveloperError('cartographic is required.');
  3952. }
  3953. var longitude = cartographic.longitude;
  3954. var latitude = cartographic.latitude;
  3955. var cosLatitude = Math.cos(latitude);
  3956. var x = cosLatitude * Math.cos(longitude);
  3957. var y = cosLatitude * Math.sin(longitude);
  3958. var z = Math.sin(latitude);
  3959. if (!defined(result)) {
  3960. result = new Cartesian3();
  3961. }
  3962. result.x = x;
  3963. result.y = y;
  3964. result.z = z;
  3965. return Cartesian3.normalize(result, result);
  3966. };
  3967. /**
  3968. * Computes the normal of the plane tangent to the surface of the ellipsoid at the provided position.
  3969. *
  3970. * @param {Cartesian3} cartesian The Cartesian position for which to to determine the surface normal.
  3971. * @param {Cartesian3} [result] The object onto which to store the result.
  3972. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
  3973. */
  3974. Ellipsoid.prototype.geodeticSurfaceNormal = function(cartesian, result) {
  3975. if (!defined(result)) {
  3976. result = new Cartesian3();
  3977. }
  3978. result = Cartesian3.multiplyComponents(cartesian, this._oneOverRadiiSquared, result);
  3979. return Cartesian3.normalize(result, result);
  3980. };
  3981. var cartographicToCartesianNormal = new Cartesian3();
  3982. var cartographicToCartesianK = new Cartesian3();
  3983. /**
  3984. * Converts the provided cartographic to Cartesian representation.
  3985. *
  3986. * @param {Cartographic} cartographic The cartographic position.
  3987. * @param {Cartesian3} [result] The object onto which to store the result.
  3988. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
  3989. *
  3990. * @example
  3991. * //Create a Cartographic and determine it's Cartesian representation on a WGS84 ellipsoid.
  3992. * var position = new Cesium.Cartographic(Cesium.Math.toRadians(21), Cesium.Math.toRadians(78), 5000);
  3993. * var cartesianPosition = Cesium.Ellipsoid.WGS84.cartographicToCartesian(position);
  3994. */
  3995. Ellipsoid.prototype.cartographicToCartesian = function(cartographic, result) {
  3996. //`cartographic is required` is thrown from geodeticSurfaceNormalCartographic.
  3997. var n = cartographicToCartesianNormal;
  3998. var k = cartographicToCartesianK;
  3999. this.geodeticSurfaceNormalCartographic(cartographic, n);
  4000. Cartesian3.multiplyComponents(this._radiiSquared, n, k);
  4001. var gamma = Math.sqrt(Cartesian3.dot(n, k));
  4002. Cartesian3.divideByScalar(k, gamma, k);
  4003. Cartesian3.multiplyByScalar(n, cartographic.height, n);
  4004. if (!defined(result)) {
  4005. result = new Cartesian3();
  4006. }
  4007. return Cartesian3.add(k, n, result);
  4008. };
  4009. /**
  4010. * Converts the provided array of cartographics to an array of Cartesians.
  4011. *
  4012. * @param {Cartographic[]} cartographics An array of cartographic positions.
  4013. * @param {Cartesian3[]} [result] The object onto which to store the result.
  4014. * @returns {Cartesian3[]} The modified result parameter or a new Array instance if none was provided.
  4015. *
  4016. * @example
  4017. * //Convert an array of Cartographics and determine their Cartesian representation on a WGS84 ellipsoid.
  4018. * var positions = [new Cesium.Cartographic(Cesium.Math.toRadians(21), Cesium.Math.toRadians(78), 0),
  4019. * new Cesium.Cartographic(Cesium.Math.toRadians(21.321), Cesium.Math.toRadians(78.123), 100),
  4020. * new Cesium.Cartographic(Cesium.Math.toRadians(21.645), Cesium.Math.toRadians(78.456), 250)];
  4021. * var cartesianPositions = Cesium.Ellipsoid.WGS84.cartographicArrayToCartesianArray(positions);
  4022. */
  4023. Ellipsoid.prototype.cartographicArrayToCartesianArray = function(cartographics, result) {
  4024. if (!defined(cartographics)) {
  4025. throw new DeveloperError('cartographics is required.');
  4026. }
  4027. var length = cartographics.length;
  4028. if (!defined(result)) {
  4029. result = new Array(length);
  4030. } else {
  4031. result.length = length;
  4032. }
  4033. for ( var i = 0; i < length; i++) {
  4034. result[i] = this.cartographicToCartesian(cartographics[i], result[i]);
  4035. }
  4036. return result;
  4037. };
  4038. var cartesianToCartographicN = new Cartesian3();
  4039. var cartesianToCartographicP = new Cartesian3();
  4040. var cartesianToCartographicH = new Cartesian3();
  4041. /**
  4042. * Converts the provided cartesian to cartographic representation.
  4043. * The cartesian is undefined at the center of the ellipsoid.
  4044. *
  4045. * @param {Cartesian3} cartesian The Cartesian position to convert to cartographic representation.
  4046. * @param {Cartographic} [result] The object onto which to store the result.
  4047. * @returns {Cartographic} The modified result parameter, new Cartographic instance if none was provided, or undefined if the cartesian is at the center of the ellipsoid.
  4048. *
  4049. * @example
  4050. * //Create a Cartesian and determine it's Cartographic representation on a WGS84 ellipsoid.
  4051. * var position = new Cesium.Cartesian3(17832.12, 83234.52, 952313.73);
  4052. * var cartographicPosition = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
  4053. */
  4054. Ellipsoid.prototype.cartesianToCartographic = function(cartesian, result) {
  4055. //`cartesian is required.` is thrown from scaleToGeodeticSurface
  4056. var p = this.scaleToGeodeticSurface(cartesian, cartesianToCartographicP);
  4057. if (!defined(p)) {
  4058. return undefined;
  4059. }
  4060. var n = this.geodeticSurfaceNormal(p, cartesianToCartographicN);
  4061. var h = Cartesian3.subtract(cartesian, p, cartesianToCartographicH);
  4062. var longitude = Math.atan2(n.y, n.x);
  4063. var latitude = Math.asin(n.z);
  4064. var height = CesiumMath.sign(Cartesian3.dot(h, cartesian)) * Cartesian3.magnitude(h);
  4065. if (!defined(result)) {
  4066. return new Cartographic(longitude, latitude, height);
  4067. }
  4068. result.longitude = longitude;
  4069. result.latitude = latitude;
  4070. result.height = height;
  4071. return result;
  4072. };
  4073. /**
  4074. * Converts the provided array of cartesians to an array of cartographics.
  4075. *
  4076. * @param {Cartesian3[]} cartesians An array of Cartesian positions.
  4077. * @param {Cartographic[]} [result] The object onto which to store the result.
  4078. * @returns {Cartographic[]} The modified result parameter or a new Array instance if none was provided.
  4079. *
  4080. * @example
  4081. * //Create an array of Cartesians and determine their Cartographic representation on a WGS84 ellipsoid.
  4082. * var positions = [new Cesium.Cartesian3(17832.12, 83234.52, 952313.73),
  4083. * new Cesium.Cartesian3(17832.13, 83234.53, 952313.73),
  4084. * new Cesium.Cartesian3(17832.14, 83234.54, 952313.73)]
  4085. * var cartographicPositions = Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray(positions);
  4086. */
  4087. Ellipsoid.prototype.cartesianArrayToCartographicArray = function(cartesians, result) {
  4088. if (!defined(cartesians)) {
  4089. throw new DeveloperError('cartesians is required.');
  4090. }
  4091. var length = cartesians.length;
  4092. if (!defined(result)) {
  4093. result = new Array(length);
  4094. } else {
  4095. result.length = length;
  4096. }
  4097. for ( var i = 0; i < length; ++i) {
  4098. result[i] = this.cartesianToCartographic(cartesians[i], result[i]);
  4099. }
  4100. return result;
  4101. };
  4102. /**
  4103. * Scales the provided Cartesian position along the geodetic surface normal
  4104. * so that it is on the surface of this ellipsoid. If the position is
  4105. * at the center of the ellipsoid, this function returns undefined.
  4106. *
  4107. * @param {Cartesian3} cartesian The Cartesian position to scale.
  4108. * @param {Cartesian3} [result] The object onto which to store the result.
  4109. * @returns {Cartesian3} The modified result parameter, a new Cartesian3 instance if none was provided, or undefined if the position is at the center.
  4110. */
  4111. Ellipsoid.prototype.scaleToGeodeticSurface = function(cartesian, result) {
  4112. return scaleToGeodeticSurface(cartesian, this._oneOverRadii, this._oneOverRadiiSquared, this._centerToleranceSquared, result);
  4113. };
  4114. /**
  4115. * Scales the provided Cartesian position along the geocentric surface normal
  4116. * so that it is on the surface of this ellipsoid.
  4117. *
  4118. * @param {Cartesian3} cartesian The Cartesian position to scale.
  4119. * @param {Cartesian3} [result] The object onto which to store the result.
  4120. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
  4121. */
  4122. Ellipsoid.prototype.scaleToGeocentricSurface = function(cartesian, result) {
  4123. if (!defined(cartesian)) {
  4124. throw new DeveloperError('cartesian is required.');
  4125. }
  4126. if (!defined(result)) {
  4127. result = new Cartesian3();
  4128. }
  4129. var positionX = cartesian.x;
  4130. var positionY = cartesian.y;
  4131. var positionZ = cartesian.z;
  4132. var oneOverRadiiSquared = this._oneOverRadiiSquared;
  4133. var beta = 1.0 / Math.sqrt((positionX * positionX) * oneOverRadiiSquared.x +
  4134. (positionY * positionY) * oneOverRadiiSquared.y +
  4135. (positionZ * positionZ) * oneOverRadiiSquared.z);
  4136. return Cartesian3.multiplyByScalar(cartesian, beta, result);
  4137. };
  4138. /**
  4139. * Transforms a Cartesian X, Y, Z position to the ellipsoid-scaled space by multiplying
  4140. * its components by the result of {@link Ellipsoid#oneOverRadii}.
  4141. *
  4142. * @param {Cartesian3} position The position to transform.
  4143. * @param {Cartesian3} [result] The position to which to copy the result, or undefined to create and
  4144. * return a new instance.
  4145. * @returns {Cartesian3} The position expressed in the scaled space. The returned instance is the
  4146. * one passed as the result parameter if it is not undefined, or a new instance of it is.
  4147. */
  4148. Ellipsoid.prototype.transformPositionToScaledSpace = function(position, result) {
  4149. if (!defined(result)) {
  4150. result = new Cartesian3();
  4151. }
  4152. return Cartesian3.multiplyComponents(position, this._oneOverRadii, result);
  4153. };
  4154. /**
  4155. * Transforms a Cartesian X, Y, Z position from the ellipsoid-scaled space by multiplying
  4156. * its components by the result of {@link Ellipsoid#radii}.
  4157. *
  4158. * @param {Cartesian3} position The position to transform.
  4159. * @param {Cartesian3} [result] The position to which to copy the result, or undefined to create and
  4160. * return a new instance.
  4161. * @returns {Cartesian3} The position expressed in the unscaled space. The returned instance is the
  4162. * one passed as the result parameter if it is not undefined, or a new instance of it is.
  4163. */
  4164. Ellipsoid.prototype.transformPositionFromScaledSpace = function(position, result) {
  4165. if (!defined(result)) {
  4166. result = new Cartesian3();
  4167. }
  4168. return Cartesian3.multiplyComponents(position, this._radii, result);
  4169. };
  4170. /**
  4171. * Compares this Ellipsoid against the provided Ellipsoid componentwise and returns
  4172. * <code>true</code> if they are equal, <code>false</code> otherwise.
  4173. *
  4174. * @param {Ellipsoid} [right] The other Ellipsoid.
  4175. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  4176. */
  4177. Ellipsoid.prototype.equals = function(right) {
  4178. return (this === right) ||
  4179. (defined(right) &&
  4180. Cartesian3.equals(this._radii, right._radii));
  4181. };
  4182. /**
  4183. * Creates a string representing this Ellipsoid in the format '(radii.x, radii.y, radii.z)'.
  4184. *
  4185. * @returns {String} A string representing this ellipsoid in the format '(radii.x, radii.y, radii.z)'.
  4186. */
  4187. Ellipsoid.prototype.toString = function() {
  4188. return this._radii.toString();
  4189. };
  4190. /**
  4191. * Computes a point which is the intersection of the surface normal with the z-axis.
  4192. *
  4193. * @param {Cartesian3} position the position. must be on the surface of the ellipsoid.
  4194. * @param {Number} [buffer = 0.0] A buffer to subtract from the ellipsoid size when checking if the point is inside the ellipsoid.
  4195. * In earth case, with common earth datums, there is no need for this buffer since the intersection point is always (relatively) very close to the center.
  4196. * In WGS84 datum, intersection point is at max z = +-42841.31151331382 (0.673% of z-axis).
  4197. * Intersection point could be outside the ellipsoid if the ratio of MajorAxis / AxisOfRotation is bigger than the square root of 2
  4198. * @param {Cartesian} [result] The cartesian to which to copy the result, or undefined to create and
  4199. * return a new instance.
  4200. * @returns {Cartesian | undefined} the intersection point if it's inside the ellipsoid, undefined otherwise
  4201. *
  4202. * @exception {DeveloperError} position is required.
  4203. * @exception {DeveloperError} Ellipsoid must be an ellipsoid of revolution (radii.x == radii.y).
  4204. * @exception {DeveloperError} Ellipsoid.radii.z must be greater than 0.
  4205. */
  4206. Ellipsoid.prototype.getSurfaceNormalIntersectionWithZAxis = function(position, buffer, result) {
  4207. if (!defined(position)) {
  4208. throw new DeveloperError('position is required.');
  4209. }
  4210. if (!CesiumMath.equalsEpsilon(this._radii.x, this._radii.y, CesiumMath.EPSILON15)) {
  4211. throw new DeveloperError('Ellipsoid must be an ellipsoid of revolution (radii.x == radii.y)');
  4212. }
  4213. if (this._radii.z === 0) {
  4214. throw new DeveloperError('Ellipsoid.radii.z must be greater than 0');
  4215. }
  4216. buffer = defaultValue(buffer, 0.0);
  4217. var sqauredXOverSquaredZ = this._sqauredXOverSquaredZ;
  4218. if (!defined(result)) {
  4219. result = new Cartesian3();
  4220. }
  4221. result.x = 0.0;
  4222. result.y = 0.0;
  4223. result.z = position.z * (1 - sqauredXOverSquaredZ);
  4224. if (Math.abs(result.z) >= this._radii.z - buffer) {
  4225. return undefined;
  4226. }
  4227. return result;
  4228. };
  4229. return Ellipsoid;
  4230. });
  4231. /*global define*/
  4232. define('Core/Event',[
  4233. './defined',
  4234. './defineProperties',
  4235. './DeveloperError'
  4236. ], function(
  4237. defined,
  4238. defineProperties,
  4239. DeveloperError) {
  4240. 'use strict';
  4241. /**
  4242. * A generic utility class for managing subscribers for a particular event.
  4243. * This class is usually instantiated inside of a container class and
  4244. * exposed as a property for others to subscribe to.
  4245. *
  4246. * @alias Event
  4247. * @constructor
  4248. *
  4249. * @example
  4250. * MyObject.prototype.myListener = function(arg1, arg2) {
  4251. * this.myArg1Copy = arg1;
  4252. * this.myArg2Copy = arg2;
  4253. * }
  4254. *
  4255. * var myObjectInstance = new MyObject();
  4256. * var evt = new Cesium.Event();
  4257. * evt.addEventListener(MyObject.prototype.myListener, myObjectInstance);
  4258. * evt.raiseEvent('1', '2');
  4259. * evt.removeEventListener(MyObject.prototype.myListener);
  4260. */
  4261. function Event() {
  4262. this._listeners = [];
  4263. this._scopes = [];
  4264. this._toRemove = [];
  4265. this._insideRaiseEvent = false;
  4266. }
  4267. defineProperties(Event.prototype, {
  4268. /**
  4269. * The number of listeners currently subscribed to the event.
  4270. * @memberof Event.prototype
  4271. * @type {Number}
  4272. * @readonly
  4273. */
  4274. numberOfListeners : {
  4275. get : function() {
  4276. return this._listeners.length - this._toRemove.length;
  4277. }
  4278. }
  4279. });
  4280. /**
  4281. * Registers a callback function to be executed whenever the event is raised.
  4282. * An optional scope can be provided to serve as the <code>this</code> pointer
  4283. * in which the function will execute.
  4284. *
  4285. * @param {Function} listener The function to be executed when the event is raised.
  4286. * @param {Object} [scope] An optional object scope to serve as the <code>this</code>
  4287. * pointer in which the listener function will execute.
  4288. * @returns {Event~RemoveCallback} A function that will remove this event listener when invoked.
  4289. *
  4290. * @see Event#raiseEvent
  4291. * @see Event#removeEventListener
  4292. */
  4293. Event.prototype.addEventListener = function(listener, scope) {
  4294. if (typeof listener !== 'function') {
  4295. throw new DeveloperError('listener is required and must be a function.');
  4296. }
  4297. this._listeners.push(listener);
  4298. this._scopes.push(scope);
  4299. var event = this;
  4300. return function() {
  4301. event.removeEventListener(listener, scope);
  4302. };
  4303. };
  4304. /**
  4305. * Unregisters a previously registered callback.
  4306. *
  4307. * @param {Function} listener The function to be unregistered.
  4308. * @param {Object} [scope] The scope that was originally passed to addEventListener.
  4309. * @returns {Boolean} <code>true</code> if the listener was removed; <code>false</code> if the listener and scope are not registered with the event.
  4310. *
  4311. * @see Event#addEventListener
  4312. * @see Event#raiseEvent
  4313. */
  4314. Event.prototype.removeEventListener = function(listener, scope) {
  4315. if (typeof listener !== 'function') {
  4316. throw new DeveloperError('listener is required and must be a function.');
  4317. }
  4318. var listeners = this._listeners;
  4319. var scopes = this._scopes;
  4320. var index = -1;
  4321. for (var i = 0; i < listeners.length; i++) {
  4322. if (listeners[i] === listener && scopes[i] === scope) {
  4323. index = i;
  4324. break;
  4325. }
  4326. }
  4327. if (index !== -1) {
  4328. if (this._insideRaiseEvent) {
  4329. //In order to allow removing an event subscription from within
  4330. //a callback, we don't actually remove the items here. Instead
  4331. //remember the index they are at and undefined their value.
  4332. this._toRemove.push(index);
  4333. listeners[index] = undefined;
  4334. scopes[index] = undefined;
  4335. } else {
  4336. listeners.splice(index, 1);
  4337. scopes.splice(index, 1);
  4338. }
  4339. return true;
  4340. }
  4341. return false;
  4342. };
  4343. /**
  4344. * Raises the event by calling each registered listener with all supplied arguments.
  4345. *
  4346. * @param {*} arguments This method takes any number of parameters and passes them through to the listener functions.
  4347. *
  4348. * @see Event#addEventListener
  4349. * @see Event#removeEventListener
  4350. */
  4351. Event.prototype.raiseEvent = function() {
  4352. this._insideRaiseEvent = true;
  4353. var i;
  4354. var listeners = this._listeners;
  4355. var scopes = this._scopes;
  4356. var length = listeners.length;
  4357. for (i = 0; i < length; i++) {
  4358. var listener = listeners[i];
  4359. if (defined(listener)) {
  4360. listeners[i].apply(scopes[i], arguments);
  4361. }
  4362. }
  4363. //Actually remove items removed in removeEventListener.
  4364. var toRemove = this._toRemove;
  4365. length = toRemove.length;
  4366. for (i = 0; i < length; i++) {
  4367. var index = toRemove[i];
  4368. listeners.splice(index, 1);
  4369. scopes.splice(index, 1);
  4370. }
  4371. toRemove.length = 0;
  4372. this._insideRaiseEvent = false;
  4373. };
  4374. /**
  4375. * A function that removes a listener.
  4376. * @callback Event~RemoveCallback
  4377. */
  4378. return Event;
  4379. });
  4380. /*global define*/
  4381. define('Core/Cartesian2',[
  4382. './defaultValue',
  4383. './defined',
  4384. './DeveloperError',
  4385. './freezeObject',
  4386. './Math'
  4387. ], function(
  4388. defaultValue,
  4389. defined,
  4390. DeveloperError,
  4391. freezeObject,
  4392. CesiumMath) {
  4393. 'use strict';
  4394. /**
  4395. * A 2D Cartesian point.
  4396. * @alias Cartesian2
  4397. * @constructor
  4398. *
  4399. * @param {Number} [x=0.0] The X component.
  4400. * @param {Number} [y=0.0] The Y component.
  4401. *
  4402. * @see Cartesian3
  4403. * @see Cartesian4
  4404. * @see Packable
  4405. */
  4406. function Cartesian2(x, y) {
  4407. /**
  4408. * The X component.
  4409. * @type {Number}
  4410. * @default 0.0
  4411. */
  4412. this.x = defaultValue(x, 0.0);
  4413. /**
  4414. * The Y component.
  4415. * @type {Number}
  4416. * @default 0.0
  4417. */
  4418. this.y = defaultValue(y, 0.0);
  4419. }
  4420. /**
  4421. * Creates a Cartesian2 instance from x and y coordinates.
  4422. *
  4423. * @param {Number} x The x coordinate.
  4424. * @param {Number} y The y coordinate.
  4425. * @param {Cartesian2} [result] The object onto which to store the result.
  4426. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
  4427. */
  4428. Cartesian2.fromElements = function(x, y, result) {
  4429. if (!defined(result)) {
  4430. return new Cartesian2(x, y);
  4431. }
  4432. result.x = x;
  4433. result.y = y;
  4434. return result;
  4435. };
  4436. /**
  4437. * Duplicates a Cartesian2 instance.
  4438. *
  4439. * @param {Cartesian2} cartesian The Cartesian to duplicate.
  4440. * @param {Cartesian2} [result] The object onto which to store the result.
  4441. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided. (Returns undefined if cartesian is undefined)
  4442. */
  4443. Cartesian2.clone = function(cartesian, result) {
  4444. if (!defined(cartesian)) {
  4445. return undefined;
  4446. }
  4447. if (!defined(result)) {
  4448. return new Cartesian2(cartesian.x, cartesian.y);
  4449. }
  4450. result.x = cartesian.x;
  4451. result.y = cartesian.y;
  4452. return result;
  4453. };
  4454. /**
  4455. * Creates a Cartesian2 instance from an existing Cartesian3. This simply takes the
  4456. * x and y properties of the Cartesian3 and drops z.
  4457. * @function
  4458. *
  4459. * @param {Cartesian3} cartesian The Cartesian3 instance to create a Cartesian2 instance from.
  4460. * @param {Cartesian2} [result] The object onto which to store the result.
  4461. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
  4462. */
  4463. Cartesian2.fromCartesian3 = Cartesian2.clone;
  4464. /**
  4465. * Creates a Cartesian2 instance from an existing Cartesian4. This simply takes the
  4466. * x and y properties of the Cartesian4 and drops z and w.
  4467. * @function
  4468. *
  4469. * @param {Cartesian4} cartesian The Cartesian4 instance to create a Cartesian2 instance from.
  4470. * @param {Cartesian2} [result] The object onto which to store the result.
  4471. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
  4472. */
  4473. Cartesian2.fromCartesian4 = Cartesian2.clone;
  4474. /**
  4475. * The number of elements used to pack the object into an array.
  4476. * @type {Number}
  4477. */
  4478. Cartesian2.packedLength = 2;
  4479. /**
  4480. * Stores the provided instance into the provided array.
  4481. *
  4482. * @param {Cartesian2} value The value to pack.
  4483. * @param {Number[]} array The array to pack into.
  4484. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  4485. *
  4486. * @returns {Number[]} The array that was packed into
  4487. */
  4488. Cartesian2.pack = function(value, array, startingIndex) {
  4489. if (!defined(value)) {
  4490. throw new DeveloperError('value is required');
  4491. }
  4492. if (!defined(array)) {
  4493. throw new DeveloperError('array is required');
  4494. }
  4495. startingIndex = defaultValue(startingIndex, 0);
  4496. array[startingIndex++] = value.x;
  4497. array[startingIndex] = value.y;
  4498. return array;
  4499. };
  4500. /**
  4501. * Retrieves an instance from a packed array.
  4502. *
  4503. * @param {Number[]} array The packed array.
  4504. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  4505. * @param {Cartesian2} [result] The object into which to store the result.
  4506. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
  4507. */
  4508. Cartesian2.unpack = function(array, startingIndex, result) {
  4509. if (!defined(array)) {
  4510. throw new DeveloperError('array is required');
  4511. }
  4512. startingIndex = defaultValue(startingIndex, 0);
  4513. if (!defined(result)) {
  4514. result = new Cartesian2();
  4515. }
  4516. result.x = array[startingIndex++];
  4517. result.y = array[startingIndex];
  4518. return result;
  4519. };
  4520. /**
  4521. * Flattens an array of Cartesian2s into and array of components.
  4522. *
  4523. * @param {Cartesian2[]} array The array of cartesians to pack.
  4524. * @param {Number[]} result The array onto which to store the result.
  4525. * @returns {Number[]} The packed array.
  4526. */
  4527. Cartesian2.packArray = function(array, result) {
  4528. if (!defined(array)) {
  4529. throw new DeveloperError('array is required');
  4530. }
  4531. var length = array.length;
  4532. if (!defined(result)) {
  4533. result = new Array(length * 2);
  4534. } else {
  4535. result.length = length * 2;
  4536. }
  4537. for (var i = 0; i < length; ++i) {
  4538. Cartesian2.pack(array[i], result, i * 2);
  4539. }
  4540. return result;
  4541. };
  4542. /**
  4543. * Unpacks an array of cartesian components into and array of Cartesian2s.
  4544. *
  4545. * @param {Number[]} array The array of components to unpack.
  4546. * @param {Cartesian2[]} result The array onto which to store the result.
  4547. * @returns {Cartesian2[]} The unpacked array.
  4548. */
  4549. Cartesian2.unpackArray = function(array, result) {
  4550. if (!defined(array)) {
  4551. throw new DeveloperError('array is required');
  4552. }
  4553. var length = array.length;
  4554. if (!defined(result)) {
  4555. result = new Array(length / 2);
  4556. } else {
  4557. result.length = length / 2;
  4558. }
  4559. for (var i = 0; i < length; i += 2) {
  4560. var index = i / 2;
  4561. result[index] = Cartesian2.unpack(array, i, result[index]);
  4562. }
  4563. return result;
  4564. };
  4565. /**
  4566. * Creates a Cartesian2 from two consecutive elements in an array.
  4567. * @function
  4568. *
  4569. * @param {Number[]} array The array whose two consecutive elements correspond to the x and y components, respectively.
  4570. * @param {Number} [startingIndex=0] The offset into the array of the first element, which corresponds to the x component.
  4571. * @param {Cartesian2} [result] The object onto which to store the result.
  4572. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
  4573. *
  4574. * @example
  4575. * // Create a Cartesian2 with (1.0, 2.0)
  4576. * var v = [1.0, 2.0];
  4577. * var p = Cesium.Cartesian2.fromArray(v);
  4578. *
  4579. * // Create a Cartesian2 with (1.0, 2.0) using an offset into an array
  4580. * var v2 = [0.0, 0.0, 1.0, 2.0];
  4581. * var p2 = Cesium.Cartesian2.fromArray(v2, 2);
  4582. */
  4583. Cartesian2.fromArray = Cartesian2.unpack;
  4584. /**
  4585. * Computes the value of the maximum component for the supplied Cartesian.
  4586. *
  4587. * @param {Cartesian2} cartesian The cartesian to use.
  4588. * @returns {Number} The value of the maximum component.
  4589. */
  4590. Cartesian2.maximumComponent = function(cartesian) {
  4591. if (!defined(cartesian)) {
  4592. throw new DeveloperError('cartesian is required');
  4593. }
  4594. return Math.max(cartesian.x, cartesian.y);
  4595. };
  4596. /**
  4597. * Computes the value of the minimum component for the supplied Cartesian.
  4598. *
  4599. * @param {Cartesian2} cartesian The cartesian to use.
  4600. * @returns {Number} The value of the minimum component.
  4601. */
  4602. Cartesian2.minimumComponent = function(cartesian) {
  4603. if (!defined(cartesian)) {
  4604. throw new DeveloperError('cartesian is required');
  4605. }
  4606. return Math.min(cartesian.x, cartesian.y);
  4607. };
  4608. /**
  4609. * Compares two Cartesians and computes a Cartesian which contains the minimum components of the supplied Cartesians.
  4610. *
  4611. * @param {Cartesian2} first A cartesian to compare.
  4612. * @param {Cartesian2} second A cartesian to compare.
  4613. * @param {Cartesian2} result The object into which to store the result.
  4614. * @returns {Cartesian2} A cartesian with the minimum components.
  4615. */
  4616. Cartesian2.minimumByComponent = function(first, second, result) {
  4617. if (!defined(first)) {
  4618. throw new DeveloperError('first is required.');
  4619. }
  4620. if (!defined(second)) {
  4621. throw new DeveloperError('second is required.');
  4622. }
  4623. if (!defined(result)) {
  4624. throw new DeveloperError('result is required.');
  4625. }
  4626. result.x = Math.min(first.x, second.x);
  4627. result.y = Math.min(first.y, second.y);
  4628. return result;
  4629. };
  4630. /**
  4631. * Compares two Cartesians and computes a Cartesian which contains the maximum components of the supplied Cartesians.
  4632. *
  4633. * @param {Cartesian2} first A cartesian to compare.
  4634. * @param {Cartesian2} second A cartesian to compare.
  4635. * @param {Cartesian2} result The object into which to store the result.
  4636. * @returns {Cartesian2} A cartesian with the maximum components.
  4637. */
  4638. Cartesian2.maximumByComponent = function(first, second, result) {
  4639. if (!defined(first)) {
  4640. throw new DeveloperError('first is required.');
  4641. }
  4642. if (!defined(second)) {
  4643. throw new DeveloperError('second is required.');
  4644. }
  4645. if (!defined(result)) {
  4646. throw new DeveloperError('result is required.');
  4647. }
  4648. result.x = Math.max(first.x, second.x);
  4649. result.y = Math.max(first.y, second.y);
  4650. return result;
  4651. };
  4652. /**
  4653. * Computes the provided Cartesian's squared magnitude.
  4654. *
  4655. * @param {Cartesian2} cartesian The Cartesian instance whose squared magnitude is to be computed.
  4656. * @returns {Number} The squared magnitude.
  4657. */
  4658. Cartesian2.magnitudeSquared = function(cartesian) {
  4659. if (!defined(cartesian)) {
  4660. throw new DeveloperError('cartesian is required');
  4661. }
  4662. return cartesian.x * cartesian.x + cartesian.y * cartesian.y;
  4663. };
  4664. /**
  4665. * Computes the Cartesian's magnitude (length).
  4666. *
  4667. * @param {Cartesian2} cartesian The Cartesian instance whose magnitude is to be computed.
  4668. * @returns {Number} The magnitude.
  4669. */
  4670. Cartesian2.magnitude = function(cartesian) {
  4671. return Math.sqrt(Cartesian2.magnitudeSquared(cartesian));
  4672. };
  4673. var distanceScratch = new Cartesian2();
  4674. /**
  4675. * Computes the distance between two points.
  4676. *
  4677. * @param {Cartesian2} left The first point to compute the distance from.
  4678. * @param {Cartesian2} right The second point to compute the distance to.
  4679. * @returns {Number} The distance between two points.
  4680. *
  4681. * @example
  4682. * // Returns 1.0
  4683. * var d = Cesium.Cartesian2.distance(new Cesium.Cartesian2(1.0, 0.0), new Cesium.Cartesian2(2.0, 0.0));
  4684. */
  4685. Cartesian2.distance = function(left, right) {
  4686. if (!defined(left) || !defined(right)) {
  4687. throw new DeveloperError('left and right are required.');
  4688. }
  4689. Cartesian2.subtract(left, right, distanceScratch);
  4690. return Cartesian2.magnitude(distanceScratch);
  4691. };
  4692. /**
  4693. * Computes the squared distance between two points. Comparing squared distances
  4694. * using this function is more efficient than comparing distances using {@link Cartesian2#distance}.
  4695. *
  4696. * @param {Cartesian2} left The first point to compute the distance from.
  4697. * @param {Cartesian2} right The second point to compute the distance to.
  4698. * @returns {Number} The distance between two points.
  4699. *
  4700. * @example
  4701. * // Returns 4.0, not 2.0
  4702. * var d = Cesium.Cartesian2.distance(new Cesium.Cartesian2(1.0, 0.0), new Cesium.Cartesian2(3.0, 0.0));
  4703. */
  4704. Cartesian2.distanceSquared = function(left, right) {
  4705. if (!defined(left) || !defined(right)) {
  4706. throw new DeveloperError('left and right are required.');
  4707. }
  4708. Cartesian2.subtract(left, right, distanceScratch);
  4709. return Cartesian2.magnitudeSquared(distanceScratch);
  4710. };
  4711. /**
  4712. * Computes the normalized form of the supplied Cartesian.
  4713. *
  4714. * @param {Cartesian2} cartesian The Cartesian to be normalized.
  4715. * @param {Cartesian2} result The object onto which to store the result.
  4716. * @returns {Cartesian2} The modified result parameter.
  4717. */
  4718. Cartesian2.normalize = function(cartesian, result) {
  4719. if (!defined(cartesian)) {
  4720. throw new DeveloperError('cartesian is required');
  4721. }
  4722. if (!defined(result)) {
  4723. throw new DeveloperError('result is required');
  4724. }
  4725. var magnitude = Cartesian2.magnitude(cartesian);
  4726. result.x = cartesian.x / magnitude;
  4727. result.y = cartesian.y / magnitude;
  4728. if (isNaN(result.x) || isNaN(result.y)) {
  4729. throw new DeveloperError('normalized result is not a number');
  4730. }
  4731. return result;
  4732. };
  4733. /**
  4734. * Computes the dot (scalar) product of two Cartesians.
  4735. *
  4736. * @param {Cartesian2} left The first Cartesian.
  4737. * @param {Cartesian2} right The second Cartesian.
  4738. * @returns {Number} The dot product.
  4739. */
  4740. Cartesian2.dot = function(left, right) {
  4741. if (!defined(left)) {
  4742. throw new DeveloperError('left is required');
  4743. }
  4744. if (!defined(right)) {
  4745. throw new DeveloperError('right is required');
  4746. }
  4747. return left.x * right.x + left.y * right.y;
  4748. };
  4749. /**
  4750. * Computes the componentwise product of two Cartesians.
  4751. *
  4752. * @param {Cartesian2} left The first Cartesian.
  4753. * @param {Cartesian2} right The second Cartesian.
  4754. * @param {Cartesian2} result The object onto which to store the result.
  4755. * @returns {Cartesian2} The modified result parameter.
  4756. */
  4757. Cartesian2.multiplyComponents = function(left, right, result) {
  4758. if (!defined(left)) {
  4759. throw new DeveloperError('left is required');
  4760. }
  4761. if (!defined(right)) {
  4762. throw new DeveloperError('right is required');
  4763. }
  4764. if (!defined(result)) {
  4765. throw new DeveloperError('result is required');
  4766. }
  4767. result.x = left.x * right.x;
  4768. result.y = left.y * right.y;
  4769. return result;
  4770. };
  4771. /**
  4772. * Computes the componentwise quotient of two Cartesians.
  4773. *
  4774. * @param {Cartesian2} left The first Cartesian.
  4775. * @param {Cartesian2} right The second Cartesian.
  4776. * @param {Cartesian2} result The object onto which to store the result.
  4777. * @returns {Cartesian2} The modified result parameter.
  4778. */
  4779. Cartesian2.divideComponents = function(left, right, result) {
  4780. if (!defined(left)) {
  4781. throw new DeveloperError('left is required');
  4782. }
  4783. if (!defined(right)) {
  4784. throw new DeveloperError('right is required');
  4785. }
  4786. if (!defined(result)) {
  4787. throw new DeveloperError('result is required');
  4788. }
  4789. result.x = left.x / right.x;
  4790. result.y = left.y / right.y;
  4791. return result;
  4792. };
  4793. /**
  4794. * Computes the componentwise sum of two Cartesians.
  4795. *
  4796. * @param {Cartesian2} left The first Cartesian.
  4797. * @param {Cartesian2} right The second Cartesian.
  4798. * @param {Cartesian2} result The object onto which to store the result.
  4799. * @returns {Cartesian2} The modified result parameter.
  4800. */
  4801. Cartesian2.add = function(left, right, result) {
  4802. if (!defined(left)) {
  4803. throw new DeveloperError('left is required');
  4804. }
  4805. if (!defined(right)) {
  4806. throw new DeveloperError('right is required');
  4807. }
  4808. if (!defined(result)) {
  4809. throw new DeveloperError('result is required');
  4810. }
  4811. result.x = left.x + right.x;
  4812. result.y = left.y + right.y;
  4813. return result;
  4814. };
  4815. /**
  4816. * Computes the componentwise difference of two Cartesians.
  4817. *
  4818. * @param {Cartesian2} left The first Cartesian.
  4819. * @param {Cartesian2} right The second Cartesian.
  4820. * @param {Cartesian2} result The object onto which to store the result.
  4821. * @returns {Cartesian2} The modified result parameter.
  4822. */
  4823. Cartesian2.subtract = function(left, right, result) {
  4824. if (!defined(left)) {
  4825. throw new DeveloperError('left is required');
  4826. }
  4827. if (!defined(right)) {
  4828. throw new DeveloperError('right is required');
  4829. }
  4830. if (!defined(result)) {
  4831. throw new DeveloperError('result is required');
  4832. }
  4833. result.x = left.x - right.x;
  4834. result.y = left.y - right.y;
  4835. return result;
  4836. };
  4837. /**
  4838. * Multiplies the provided Cartesian componentwise by the provided scalar.
  4839. *
  4840. * @param {Cartesian2} cartesian The Cartesian to be scaled.
  4841. * @param {Number} scalar The scalar to multiply with.
  4842. * @param {Cartesian2} result The object onto which to store the result.
  4843. * @returns {Cartesian2} The modified result parameter.
  4844. */
  4845. Cartesian2.multiplyByScalar = function(cartesian, scalar, result) {
  4846. if (!defined(cartesian)) {
  4847. throw new DeveloperError('cartesian is required');
  4848. }
  4849. if (typeof scalar !== 'number') {
  4850. throw new DeveloperError('scalar is required and must be a number.');
  4851. }
  4852. if (!defined(result)) {
  4853. throw new DeveloperError('result is required');
  4854. }
  4855. result.x = cartesian.x * scalar;
  4856. result.y = cartesian.y * scalar;
  4857. return result;
  4858. };
  4859. /**
  4860. * Divides the provided Cartesian componentwise by the provided scalar.
  4861. *
  4862. * @param {Cartesian2} cartesian The Cartesian to be divided.
  4863. * @param {Number} scalar The scalar to divide by.
  4864. * @param {Cartesian2} result The object onto which to store the result.
  4865. * @returns {Cartesian2} The modified result parameter.
  4866. */
  4867. Cartesian2.divideByScalar = function(cartesian, scalar, result) {
  4868. if (!defined(cartesian)) {
  4869. throw new DeveloperError('cartesian is required');
  4870. }
  4871. if (typeof scalar !== 'number') {
  4872. throw new DeveloperError('scalar is required and must be a number.');
  4873. }
  4874. if (!defined(result)) {
  4875. throw new DeveloperError('result is required');
  4876. }
  4877. result.x = cartesian.x / scalar;
  4878. result.y = cartesian.y / scalar;
  4879. return result;
  4880. };
  4881. /**
  4882. * Negates the provided Cartesian.
  4883. *
  4884. * @param {Cartesian2} cartesian The Cartesian to be negated.
  4885. * @param {Cartesian2} result The object onto which to store the result.
  4886. * @returns {Cartesian2} The modified result parameter.
  4887. */
  4888. Cartesian2.negate = function(cartesian, result) {
  4889. if (!defined(cartesian)) {
  4890. throw new DeveloperError('cartesian is required');
  4891. }
  4892. if (!defined(result)) {
  4893. throw new DeveloperError('result is required');
  4894. }
  4895. result.x = -cartesian.x;
  4896. result.y = -cartesian.y;
  4897. return result;
  4898. };
  4899. /**
  4900. * Computes the absolute value of the provided Cartesian.
  4901. *
  4902. * @param {Cartesian2} cartesian The Cartesian whose absolute value is to be computed.
  4903. * @param {Cartesian2} result The object onto which to store the result.
  4904. * @returns {Cartesian2} The modified result parameter.
  4905. */
  4906. Cartesian2.abs = function(cartesian, result) {
  4907. if (!defined(cartesian)) {
  4908. throw new DeveloperError('cartesian is required');
  4909. }
  4910. if (!defined(result)) {
  4911. throw new DeveloperError('result is required');
  4912. }
  4913. result.x = Math.abs(cartesian.x);
  4914. result.y = Math.abs(cartesian.y);
  4915. return result;
  4916. };
  4917. var lerpScratch = new Cartesian2();
  4918. /**
  4919. * Computes the linear interpolation or extrapolation at t using the provided cartesians.
  4920. *
  4921. * @param {Cartesian2} start The value corresponding to t at 0.0.
  4922. * @param {Cartesian2} end The value corresponding to t at 1.0.
  4923. * @param {Number} t The point along t at which to interpolate.
  4924. * @param {Cartesian2} result The object onto which to store the result.
  4925. * @returns {Cartesian2} The modified result parameter.
  4926. */
  4927. Cartesian2.lerp = function(start, end, t, result) {
  4928. if (!defined(start)) {
  4929. throw new DeveloperError('start is required.');
  4930. }
  4931. if (!defined(end)) {
  4932. throw new DeveloperError('end is required.');
  4933. }
  4934. if (typeof t !== 'number') {
  4935. throw new DeveloperError('t is required and must be a number.');
  4936. }
  4937. if (!defined(result)) {
  4938. throw new DeveloperError('result is required.');
  4939. }
  4940. Cartesian2.multiplyByScalar(end, t, lerpScratch);
  4941. result = Cartesian2.multiplyByScalar(start, 1.0 - t, result);
  4942. return Cartesian2.add(lerpScratch, result, result);
  4943. };
  4944. var angleBetweenScratch = new Cartesian2();
  4945. var angleBetweenScratch2 = new Cartesian2();
  4946. /**
  4947. * Returns the angle, in radians, between the provided Cartesians.
  4948. *
  4949. * @param {Cartesian2} left The first Cartesian.
  4950. * @param {Cartesian2} right The second Cartesian.
  4951. * @returns {Number} The angle between the Cartesians.
  4952. */
  4953. Cartesian2.angleBetween = function(left, right) {
  4954. if (!defined(left)) {
  4955. throw new DeveloperError('left is required');
  4956. }
  4957. if (!defined(right)) {
  4958. throw new DeveloperError('right is required');
  4959. }
  4960. Cartesian2.normalize(left, angleBetweenScratch);
  4961. Cartesian2.normalize(right, angleBetweenScratch2);
  4962. return CesiumMath.acosClamped(Cartesian2.dot(angleBetweenScratch, angleBetweenScratch2));
  4963. };
  4964. var mostOrthogonalAxisScratch = new Cartesian2();
  4965. /**
  4966. * Returns the axis that is most orthogonal to the provided Cartesian.
  4967. *
  4968. * @param {Cartesian2} cartesian The Cartesian on which to find the most orthogonal axis.
  4969. * @param {Cartesian2} result The object onto which to store the result.
  4970. * @returns {Cartesian2} The most orthogonal axis.
  4971. */
  4972. Cartesian2.mostOrthogonalAxis = function(cartesian, result) {
  4973. if (!defined(cartesian)) {
  4974. throw new DeveloperError('cartesian is required.');
  4975. }
  4976. if (!defined(result)) {
  4977. throw new DeveloperError('result is required.');
  4978. }
  4979. var f = Cartesian2.normalize(cartesian, mostOrthogonalAxisScratch);
  4980. Cartesian2.abs(f, f);
  4981. if (f.x <= f.y) {
  4982. result = Cartesian2.clone(Cartesian2.UNIT_X, result);
  4983. } else {
  4984. result = Cartesian2.clone(Cartesian2.UNIT_Y, result);
  4985. }
  4986. return result;
  4987. };
  4988. /**
  4989. * Compares the provided Cartesians componentwise and returns
  4990. * <code>true</code> if they are equal, <code>false</code> otherwise.
  4991. *
  4992. * @param {Cartesian2} [left] The first Cartesian.
  4993. * @param {Cartesian2} [right] The second Cartesian.
  4994. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  4995. */
  4996. Cartesian2.equals = function(left, right) {
  4997. return (left === right) ||
  4998. ((defined(left)) &&
  4999. (defined(right)) &&
  5000. (left.x === right.x) &&
  5001. (left.y === right.y));
  5002. };
  5003. /**
  5004. * @private
  5005. */
  5006. Cartesian2.equalsArray = function(cartesian, array, offset) {
  5007. return cartesian.x === array[offset] &&
  5008. cartesian.y === array[offset + 1];
  5009. };
  5010. /**
  5011. * Compares the provided Cartesians componentwise and returns
  5012. * <code>true</code> if they pass an absolute or relative tolerance test,
  5013. * <code>false</code> otherwise.
  5014. *
  5015. * @param {Cartesian2} [left] The first Cartesian.
  5016. * @param {Cartesian2} [right] The second Cartesian.
  5017. * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
  5018. * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
  5019. * @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
  5020. */
  5021. Cartesian2.equalsEpsilon = function(left, right, relativeEpsilon, absoluteEpsilon) {
  5022. return (left === right) ||
  5023. (defined(left) &&
  5024. defined(right) &&
  5025. CesiumMath.equalsEpsilon(left.x, right.x, relativeEpsilon, absoluteEpsilon) &&
  5026. CesiumMath.equalsEpsilon(left.y, right.y, relativeEpsilon, absoluteEpsilon));
  5027. };
  5028. /**
  5029. * An immutable Cartesian2 instance initialized to (0.0, 0.0).
  5030. *
  5031. * @type {Cartesian2}
  5032. * @constant
  5033. */
  5034. Cartesian2.ZERO = freezeObject(new Cartesian2(0.0, 0.0));
  5035. /**
  5036. * An immutable Cartesian2 instance initialized to (1.0, 0.0).
  5037. *
  5038. * @type {Cartesian2}
  5039. * @constant
  5040. */
  5041. Cartesian2.UNIT_X = freezeObject(new Cartesian2(1.0, 0.0));
  5042. /**
  5043. * An immutable Cartesian2 instance initialized to (0.0, 1.0).
  5044. *
  5045. * @type {Cartesian2}
  5046. * @constant
  5047. */
  5048. Cartesian2.UNIT_Y = freezeObject(new Cartesian2(0.0, 1.0));
  5049. /**
  5050. * Duplicates this Cartesian2 instance.
  5051. *
  5052. * @param {Cartesian2} [result] The object onto which to store the result.
  5053. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
  5054. */
  5055. Cartesian2.prototype.clone = function(result) {
  5056. return Cartesian2.clone(this, result);
  5057. };
  5058. /**
  5059. * Compares this Cartesian against the provided Cartesian componentwise and returns
  5060. * <code>true</code> if they are equal, <code>false</code> otherwise.
  5061. *
  5062. * @param {Cartesian2} [right] The right hand side Cartesian.
  5063. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  5064. */
  5065. Cartesian2.prototype.equals = function(right) {
  5066. return Cartesian2.equals(this, right);
  5067. };
  5068. /**
  5069. * Compares this Cartesian against the provided Cartesian componentwise and returns
  5070. * <code>true</code> if they pass an absolute or relative tolerance test,
  5071. * <code>false</code> otherwise.
  5072. *
  5073. * @param {Cartesian2} [right] The right hand side Cartesian.
  5074. * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
  5075. * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
  5076. * @returns {Boolean} <code>true</code> if they are within the provided epsilon, <code>false</code> otherwise.
  5077. */
  5078. Cartesian2.prototype.equalsEpsilon = function(right, relativeEpsilon, absoluteEpsilon) {
  5079. return Cartesian2.equalsEpsilon(this, right, relativeEpsilon, absoluteEpsilon);
  5080. };
  5081. /**
  5082. * Creates a string representing this Cartesian in the format '(x, y)'.
  5083. *
  5084. * @returns {String} A string representing the provided Cartesian in the format '(x, y)'.
  5085. */
  5086. Cartesian2.prototype.toString = function() {
  5087. return '(' + this.x + ', ' + this.y + ')';
  5088. };
  5089. return Cartesian2;
  5090. });
  5091. /*global define*/
  5092. define('Core/GeographicProjection',[
  5093. './Cartesian3',
  5094. './Cartographic',
  5095. './defaultValue',
  5096. './defined',
  5097. './defineProperties',
  5098. './DeveloperError',
  5099. './Ellipsoid'
  5100. ], function(
  5101. Cartesian3,
  5102. Cartographic,
  5103. defaultValue,
  5104. defined,
  5105. defineProperties,
  5106. DeveloperError,
  5107. Ellipsoid) {
  5108. 'use strict';
  5109. /**
  5110. * A simple map projection where longitude and latitude are linearly mapped to X and Y by multiplying
  5111. * them by the {@link Ellipsoid#maximumRadius}. This projection
  5112. * is commonly known as geographic, equirectangular, equidistant cylindrical, or plate carrée. It
  5113. * is also known as EPSG:4326.
  5114. *
  5115. * @alias GeographicProjection
  5116. * @constructor
  5117. *
  5118. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid.
  5119. *
  5120. * @see WebMercatorProjection
  5121. */
  5122. function GeographicProjection(ellipsoid) {
  5123. this._ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  5124. this._semimajorAxis = this._ellipsoid.maximumRadius;
  5125. this._oneOverSemimajorAxis = 1.0 / this._semimajorAxis;
  5126. }
  5127. defineProperties(GeographicProjection.prototype, {
  5128. /**
  5129. * Gets the {@link Ellipsoid}.
  5130. *
  5131. * @memberof GeographicProjection.prototype
  5132. *
  5133. * @type {Ellipsoid}
  5134. * @readonly
  5135. */
  5136. ellipsoid : {
  5137. get : function() {
  5138. return this._ellipsoid;
  5139. }
  5140. }
  5141. });
  5142. /**
  5143. * Projects a set of {@link Cartographic} coordinates, in radians, to map coordinates, in meters.
  5144. * X and Y are the longitude and latitude, respectively, multiplied by the maximum radius of the
  5145. * ellipsoid. Z is the unmodified height.
  5146. *
  5147. * @param {Cartographic} cartographic The coordinates to project.
  5148. * @param {Cartesian3} [result] An instance into which to copy the result. If this parameter is
  5149. * undefined, a new instance is created and returned.
  5150. * @returns {Cartesian3} The projected coordinates. If the result parameter is not undefined, the
  5151. * coordinates are copied there and that instance is returned. Otherwise, a new instance is
  5152. * created and returned.
  5153. */
  5154. GeographicProjection.prototype.project = function(cartographic, result) {
  5155. // Actually this is the special case of equidistant cylindrical called the plate carree
  5156. var semimajorAxis = this._semimajorAxis;
  5157. var x = cartographic.longitude * semimajorAxis;
  5158. var y = cartographic.latitude * semimajorAxis;
  5159. var z = cartographic.height;
  5160. if (!defined(result)) {
  5161. return new Cartesian3(x, y, z);
  5162. }
  5163. result.x = x;
  5164. result.y = y;
  5165. result.z = z;
  5166. return result;
  5167. };
  5168. /**
  5169. * Unprojects a set of projected {@link Cartesian3} coordinates, in meters, to {@link Cartographic}
  5170. * coordinates, in radians. Longitude and Latitude are the X and Y coordinates, respectively,
  5171. * divided by the maximum radius of the ellipsoid. Height is the unmodified Z coordinate.
  5172. *
  5173. * @param {Cartesian3} cartesian The Cartesian position to unproject with height (z) in meters.
  5174. * @param {Cartographic} [result] An instance into which to copy the result. If this parameter is
  5175. * undefined, a new instance is created and returned.
  5176. * @returns {Cartographic} The unprojected coordinates. If the result parameter is not undefined, the
  5177. * coordinates are copied there and that instance is returned. Otherwise, a new instance is
  5178. * created and returned.
  5179. */
  5180. GeographicProjection.prototype.unproject = function(cartesian, result) {
  5181. if (!defined(cartesian)) {
  5182. throw new DeveloperError('cartesian is required');
  5183. }
  5184. var oneOverEarthSemimajorAxis = this._oneOverSemimajorAxis;
  5185. var longitude = cartesian.x * oneOverEarthSemimajorAxis;
  5186. var latitude = cartesian.y * oneOverEarthSemimajorAxis;
  5187. var height = cartesian.z;
  5188. if (!defined(result)) {
  5189. return new Cartographic(longitude, latitude, height);
  5190. }
  5191. result.longitude = longitude;
  5192. result.latitude = latitude;
  5193. result.height = height;
  5194. return result;
  5195. };
  5196. return GeographicProjection;
  5197. });
  5198. /*global define*/
  5199. define('Core/Rectangle',[
  5200. './Cartographic',
  5201. './defaultValue',
  5202. './defined',
  5203. './defineProperties',
  5204. './DeveloperError',
  5205. './Ellipsoid',
  5206. './freezeObject',
  5207. './Math'
  5208. ], function(
  5209. Cartographic,
  5210. defaultValue,
  5211. defined,
  5212. defineProperties,
  5213. DeveloperError,
  5214. Ellipsoid,
  5215. freezeObject,
  5216. CesiumMath) {
  5217. 'use strict';
  5218. /**
  5219. * A two dimensional region specified as longitude and latitude coordinates.
  5220. *
  5221. * @alias Rectangle
  5222. * @constructor
  5223. *
  5224. * @param {Number} [west=0.0] The westernmost longitude, in radians, in the range [-Pi, Pi].
  5225. * @param {Number} [south=0.0] The southernmost latitude, in radians, in the range [-Pi/2, Pi/2].
  5226. * @param {Number} [east=0.0] The easternmost longitude, in radians, in the range [-Pi, Pi].
  5227. * @param {Number} [north=0.0] The northernmost latitude, in radians, in the range [-Pi/2, Pi/2].
  5228. *
  5229. * @see Packable
  5230. */
  5231. function Rectangle(west, south, east, north) {
  5232. /**
  5233. * The westernmost longitude in radians in the range [-Pi, Pi].
  5234. *
  5235. * @type {Number}
  5236. * @default 0.0
  5237. */
  5238. this.west = defaultValue(west, 0.0);
  5239. /**
  5240. * The southernmost latitude in radians in the range [-Pi/2, Pi/2].
  5241. *
  5242. * @type {Number}
  5243. * @default 0.0
  5244. */
  5245. this.south = defaultValue(south, 0.0);
  5246. /**
  5247. * The easternmost longitude in radians in the range [-Pi, Pi].
  5248. *
  5249. * @type {Number}
  5250. * @default 0.0
  5251. */
  5252. this.east = defaultValue(east, 0.0);
  5253. /**
  5254. * The northernmost latitude in radians in the range [-Pi/2, Pi/2].
  5255. *
  5256. * @type {Number}
  5257. * @default 0.0
  5258. */
  5259. this.north = defaultValue(north, 0.0);
  5260. }
  5261. defineProperties(Rectangle.prototype, {
  5262. /**
  5263. * Gets the width of the rectangle in radians.
  5264. * @memberof Rectangle.prototype
  5265. * @type {Number}
  5266. */
  5267. width : {
  5268. get : function() {
  5269. return Rectangle.computeWidth(this);
  5270. }
  5271. },
  5272. /**
  5273. * Gets the height of the rectangle in radians.
  5274. * @memberof Rectangle.prototype
  5275. * @type {Number}
  5276. */
  5277. height : {
  5278. get : function() {
  5279. return Rectangle.computeHeight(this);
  5280. }
  5281. }
  5282. });
  5283. /**
  5284. * The number of elements used to pack the object into an array.
  5285. * @type {Number}
  5286. */
  5287. Rectangle.packedLength = 4;
  5288. /**
  5289. * Stores the provided instance into the provided array.
  5290. *
  5291. * @param {Rectangle} value The value to pack.
  5292. * @param {Number[]} array The array to pack into.
  5293. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  5294. *
  5295. * @returns {Number[]} The array that was packed into
  5296. */
  5297. Rectangle.pack = function(value, array, startingIndex) {
  5298. if (!defined(value)) {
  5299. throw new DeveloperError('value is required');
  5300. }
  5301. if (!defined(array)) {
  5302. throw new DeveloperError('array is required');
  5303. }
  5304. startingIndex = defaultValue(startingIndex, 0);
  5305. array[startingIndex++] = value.west;
  5306. array[startingIndex++] = value.south;
  5307. array[startingIndex++] = value.east;
  5308. array[startingIndex] = value.north;
  5309. return array;
  5310. };
  5311. /**
  5312. * Retrieves an instance from a packed array.
  5313. *
  5314. * @param {Number[]} array The packed array.
  5315. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  5316. * @param {Rectangle} [result] The object into which to store the result.
  5317. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if one was not provided.
  5318. */
  5319. Rectangle.unpack = function(array, startingIndex, result) {
  5320. if (!defined(array)) {
  5321. throw new DeveloperError('array is required');
  5322. }
  5323. startingIndex = defaultValue(startingIndex, 0);
  5324. if (!defined(result)) {
  5325. result = new Rectangle();
  5326. }
  5327. result.west = array[startingIndex++];
  5328. result.south = array[startingIndex++];
  5329. result.east = array[startingIndex++];
  5330. result.north = array[startingIndex];
  5331. return result;
  5332. };
  5333. /**
  5334. * Computes the width of a rectangle in radians.
  5335. * @param {Rectangle} rectangle The rectangle to compute the width of.
  5336. * @returns {Number} The width.
  5337. */
  5338. Rectangle.computeWidth = function(rectangle) {
  5339. if (!defined(rectangle)) {
  5340. throw new DeveloperError('rectangle is required.');
  5341. }
  5342. var east = rectangle.east;
  5343. var west = rectangle.west;
  5344. if (east < west) {
  5345. east += CesiumMath.TWO_PI;
  5346. }
  5347. return east - west;
  5348. };
  5349. /**
  5350. * Computes the height of a rectangle in radians.
  5351. * @param {Rectangle} rectangle The rectangle to compute the height of.
  5352. * @returns {Number} The height.
  5353. */
  5354. Rectangle.computeHeight = function(rectangle) {
  5355. if (!defined(rectangle)) {
  5356. throw new DeveloperError('rectangle is required.');
  5357. }
  5358. return rectangle.north - rectangle.south;
  5359. };
  5360. /**
  5361. * Creates an rectangle given the boundary longitude and latitude in degrees.
  5362. *
  5363. * @param {Number} [west=0.0] The westernmost longitude in degrees in the range [-180.0, 180.0].
  5364. * @param {Number} [south=0.0] The southernmost latitude in degrees in the range [-90.0, 90.0].
  5365. * @param {Number} [east=0.0] The easternmost longitude in degrees in the range [-180.0, 180.0].
  5366. * @param {Number} [north=0.0] The northernmost latitude in degrees in the range [-90.0, 90.0].
  5367. * @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created.
  5368. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
  5369. *
  5370. * @example
  5371. * var rectangle = Cesium.Rectangle.fromDegrees(0.0, 20.0, 10.0, 30.0);
  5372. */
  5373. Rectangle.fromDegrees = function(west, south, east, north, result) {
  5374. west = CesiumMath.toRadians(defaultValue(west, 0.0));
  5375. south = CesiumMath.toRadians(defaultValue(south, 0.0));
  5376. east = CesiumMath.toRadians(defaultValue(east, 0.0));
  5377. north = CesiumMath.toRadians(defaultValue(north, 0.0));
  5378. if (!defined(result)) {
  5379. return new Rectangle(west, south, east, north);
  5380. }
  5381. result.west = west;
  5382. result.south = south;
  5383. result.east = east;
  5384. result.north = north;
  5385. return result;
  5386. };
  5387. /**
  5388. * Creates the smallest possible Rectangle that encloses all positions in the provided array.
  5389. *
  5390. * @param {Cartographic[]} cartographics The list of Cartographic instances.
  5391. * @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created.
  5392. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
  5393. */
  5394. Rectangle.fromCartographicArray = function(cartographics, result) {
  5395. if (!defined(cartographics)) {
  5396. throw new DeveloperError('cartographics is required.');
  5397. }
  5398. var west = Number.MAX_VALUE;
  5399. var east = -Number.MAX_VALUE;
  5400. var westOverIDL = Number.MAX_VALUE;
  5401. var eastOverIDL = -Number.MAX_VALUE;
  5402. var south = Number.MAX_VALUE;
  5403. var north = -Number.MAX_VALUE;
  5404. for ( var i = 0, len = cartographics.length; i < len; i++) {
  5405. var position = cartographics[i];
  5406. west = Math.min(west, position.longitude);
  5407. east = Math.max(east, position.longitude);
  5408. south = Math.min(south, position.latitude);
  5409. north = Math.max(north, position.latitude);
  5410. var lonAdjusted = position.longitude >= 0 ? position.longitude : position.longitude + CesiumMath.TWO_PI;
  5411. westOverIDL = Math.min(westOverIDL, lonAdjusted);
  5412. eastOverIDL = Math.max(eastOverIDL, lonAdjusted);
  5413. }
  5414. if(east - west > eastOverIDL - westOverIDL) {
  5415. west = westOverIDL;
  5416. east = eastOverIDL;
  5417. if (east > CesiumMath.PI) {
  5418. east = east - CesiumMath.TWO_PI;
  5419. }
  5420. if (west > CesiumMath.PI) {
  5421. west = west - CesiumMath.TWO_PI;
  5422. }
  5423. }
  5424. if (!defined(result)) {
  5425. return new Rectangle(west, south, east, north);
  5426. }
  5427. result.west = west;
  5428. result.south = south;
  5429. result.east = east;
  5430. result.north = north;
  5431. return result;
  5432. };
  5433. /**
  5434. * Creates the smallest possible Rectangle that encloses all positions in the provided array.
  5435. *
  5436. * @param {Cartesian[]} cartesians The list of Cartesian instances.
  5437. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid the cartesians are on.
  5438. * @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created.
  5439. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
  5440. */
  5441. Rectangle.fromCartesianArray = function(cartesians, ellipsoid, result) {
  5442. if (!defined(cartesians)) {
  5443. throw new DeveloperError('cartesians is required.');
  5444. }
  5445. var west = Number.MAX_VALUE;
  5446. var east = -Number.MAX_VALUE;
  5447. var westOverIDL = Number.MAX_VALUE;
  5448. var eastOverIDL = -Number.MAX_VALUE;
  5449. var south = Number.MAX_VALUE;
  5450. var north = -Number.MAX_VALUE;
  5451. for ( var i = 0, len = cartesians.length; i < len; i++) {
  5452. var position = ellipsoid.cartesianToCartographic(cartesians[i]);
  5453. west = Math.min(west, position.longitude);
  5454. east = Math.max(east, position.longitude);
  5455. south = Math.min(south, position.latitude);
  5456. north = Math.max(north, position.latitude);
  5457. var lonAdjusted = position.longitude >= 0 ? position.longitude : position.longitude + CesiumMath.TWO_PI;
  5458. westOverIDL = Math.min(westOverIDL, lonAdjusted);
  5459. eastOverIDL = Math.max(eastOverIDL, lonAdjusted);
  5460. }
  5461. if(east - west > eastOverIDL - westOverIDL) {
  5462. west = westOverIDL;
  5463. east = eastOverIDL;
  5464. if (east > CesiumMath.PI) {
  5465. east = east - CesiumMath.TWO_PI;
  5466. }
  5467. if (west > CesiumMath.PI) {
  5468. west = west - CesiumMath.TWO_PI;
  5469. }
  5470. }
  5471. if (!defined(result)) {
  5472. return new Rectangle(west, south, east, north);
  5473. }
  5474. result.west = west;
  5475. result.south = south;
  5476. result.east = east;
  5477. result.north = north;
  5478. return result;
  5479. };
  5480. /**
  5481. * Duplicates an Rectangle.
  5482. *
  5483. * @param {Rectangle} rectangle The rectangle to clone.
  5484. * @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created.
  5485. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided. (Returns undefined if rectangle is undefined)
  5486. */
  5487. Rectangle.clone = function(rectangle, result) {
  5488. if (!defined(rectangle)) {
  5489. return undefined;
  5490. }
  5491. if (!defined(result)) {
  5492. return new Rectangle(rectangle.west, rectangle.south, rectangle.east, rectangle.north);
  5493. }
  5494. result.west = rectangle.west;
  5495. result.south = rectangle.south;
  5496. result.east = rectangle.east;
  5497. result.north = rectangle.north;
  5498. return result;
  5499. };
  5500. /**
  5501. * Duplicates this Rectangle.
  5502. *
  5503. * @param {Rectangle} [result] The object onto which to store the result.
  5504. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
  5505. */
  5506. Rectangle.prototype.clone = function(result) {
  5507. return Rectangle.clone(this, result);
  5508. };
  5509. /**
  5510. * Compares the provided Rectangle with this Rectangle componentwise and returns
  5511. * <code>true</code> if they are equal, <code>false</code> otherwise.
  5512. *
  5513. * @param {Rectangle} [other] The Rectangle to compare.
  5514. * @returns {Boolean} <code>true</code> if the Rectangles are equal, <code>false</code> otherwise.
  5515. */
  5516. Rectangle.prototype.equals = function(other) {
  5517. return Rectangle.equals(this, other);
  5518. };
  5519. /**
  5520. * Compares the provided rectangles and returns <code>true</code> if they are equal,
  5521. * <code>false</code> otherwise.
  5522. *
  5523. * @param {Rectangle} [left] The first Rectangle.
  5524. * @param {Rectangle} [right] The second Rectangle.
  5525. * @returns {Boolean} <code>true</code> if left and right are equal; otherwise <code>false</code>.
  5526. */
  5527. Rectangle.equals = function(left, right) {
  5528. return (left === right) ||
  5529. ((defined(left)) &&
  5530. (defined(right)) &&
  5531. (left.west === right.west) &&
  5532. (left.south === right.south) &&
  5533. (left.east === right.east) &&
  5534. (left.north === right.north));
  5535. };
  5536. /**
  5537. * Compares the provided Rectangle with this Rectangle componentwise and returns
  5538. * <code>true</code> if they are within the provided epsilon,
  5539. * <code>false</code> otherwise.
  5540. *
  5541. * @param {Rectangle} [other] The Rectangle to compare.
  5542. * @param {Number} epsilon The epsilon to use for equality testing.
  5543. * @returns {Boolean} <code>true</code> if the Rectangles are within the provided epsilon, <code>false</code> otherwise.
  5544. */
  5545. Rectangle.prototype.equalsEpsilon = function(other, epsilon) {
  5546. if (typeof epsilon !== 'number') {
  5547. throw new DeveloperError('epsilon is required and must be a number.');
  5548. }
  5549. return defined(other) &&
  5550. (Math.abs(this.west - other.west) <= epsilon) &&
  5551. (Math.abs(this.south - other.south) <= epsilon) &&
  5552. (Math.abs(this.east - other.east) <= epsilon) &&
  5553. (Math.abs(this.north - other.north) <= epsilon);
  5554. };
  5555. /**
  5556. * Checks an Rectangle's properties and throws if they are not in valid ranges.
  5557. *
  5558. * @param {Rectangle} rectangle The rectangle to validate
  5559. *
  5560. * @exception {DeveloperError} <code>north</code> must be in the interval [<code>-Pi/2</code>, <code>Pi/2</code>].
  5561. * @exception {DeveloperError} <code>south</code> must be in the interval [<code>-Pi/2</code>, <code>Pi/2</code>].
  5562. * @exception {DeveloperError} <code>east</code> must be in the interval [<code>-Pi</code>, <code>Pi</code>].
  5563. * @exception {DeveloperError} <code>west</code> must be in the interval [<code>-Pi</code>, <code>Pi</code>].
  5564. */
  5565. Rectangle.validate = function(rectangle) {
  5566. if (!defined(rectangle)) {
  5567. throw new DeveloperError('rectangle is required');
  5568. }
  5569. var north = rectangle.north;
  5570. if (typeof north !== 'number') {
  5571. throw new DeveloperError('north is required to be a number.');
  5572. }
  5573. if (north < -CesiumMath.PI_OVER_TWO || north > CesiumMath.PI_OVER_TWO) {
  5574. throw new DeveloperError('north must be in the interval [-Pi/2, Pi/2].');
  5575. }
  5576. var south = rectangle.south;
  5577. if (typeof south !== 'number') {
  5578. throw new DeveloperError('south is required to be a number.');
  5579. }
  5580. if (south < -CesiumMath.PI_OVER_TWO || south > CesiumMath.PI_OVER_TWO) {
  5581. throw new DeveloperError('south must be in the interval [-Pi/2, Pi/2].');
  5582. }
  5583. var west = rectangle.west;
  5584. if (typeof west !== 'number') {
  5585. throw new DeveloperError('west is required to be a number.');
  5586. }
  5587. if (west < -Math.PI || west > Math.PI) {
  5588. throw new DeveloperError('west must be in the interval [-Pi, Pi].');
  5589. }
  5590. var east = rectangle.east;
  5591. if (typeof east !== 'number') {
  5592. throw new DeveloperError('east is required to be a number.');
  5593. }
  5594. if (east < -Math.PI || east > Math.PI) {
  5595. throw new DeveloperError('east must be in the interval [-Pi, Pi].');
  5596. }
  5597. };
  5598. /**
  5599. * Computes the southwest corner of an rectangle.
  5600. *
  5601. * @param {Rectangle} rectangle The rectangle for which to find the corner
  5602. * @param {Cartographic} [result] The object onto which to store the result.
  5603. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided.
  5604. */
  5605. Rectangle.southwest = function(rectangle, result) {
  5606. if (!defined(rectangle)) {
  5607. throw new DeveloperError('rectangle is required');
  5608. }
  5609. if (!defined(result)) {
  5610. return new Cartographic(rectangle.west, rectangle.south);
  5611. }
  5612. result.longitude = rectangle.west;
  5613. result.latitude = rectangle.south;
  5614. result.height = 0.0;
  5615. return result;
  5616. };
  5617. /**
  5618. * Computes the northwest corner of an rectangle.
  5619. *
  5620. * @param {Rectangle} rectangle The rectangle for which to find the corner
  5621. * @param {Cartographic} [result] The object onto which to store the result.
  5622. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided.
  5623. */
  5624. Rectangle.northwest = function(rectangle, result) {
  5625. if (!defined(rectangle)) {
  5626. throw new DeveloperError('rectangle is required');
  5627. }
  5628. if (!defined(result)) {
  5629. return new Cartographic(rectangle.west, rectangle.north);
  5630. }
  5631. result.longitude = rectangle.west;
  5632. result.latitude = rectangle.north;
  5633. result.height = 0.0;
  5634. return result;
  5635. };
  5636. /**
  5637. * Computes the northeast corner of an rectangle.
  5638. *
  5639. * @param {Rectangle} rectangle The rectangle for which to find the corner
  5640. * @param {Cartographic} [result] The object onto which to store the result.
  5641. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided.
  5642. */
  5643. Rectangle.northeast = function(rectangle, result) {
  5644. if (!defined(rectangle)) {
  5645. throw new DeveloperError('rectangle is required');
  5646. }
  5647. if (!defined(result)) {
  5648. return new Cartographic(rectangle.east, rectangle.north);
  5649. }
  5650. result.longitude = rectangle.east;
  5651. result.latitude = rectangle.north;
  5652. result.height = 0.0;
  5653. return result;
  5654. };
  5655. /**
  5656. * Computes the southeast corner of an rectangle.
  5657. *
  5658. * @param {Rectangle} rectangle The rectangle for which to find the corner
  5659. * @param {Cartographic} [result] The object onto which to store the result.
  5660. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided.
  5661. */
  5662. Rectangle.southeast = function(rectangle, result) {
  5663. if (!defined(rectangle)) {
  5664. throw new DeveloperError('rectangle is required');
  5665. }
  5666. if (!defined(result)) {
  5667. return new Cartographic(rectangle.east, rectangle.south);
  5668. }
  5669. result.longitude = rectangle.east;
  5670. result.latitude = rectangle.south;
  5671. result.height = 0.0;
  5672. return result;
  5673. };
  5674. /**
  5675. * Computes the center of an rectangle.
  5676. *
  5677. * @param {Rectangle} rectangle The rectangle for which to find the center
  5678. * @param {Cartographic} [result] The object onto which to store the result.
  5679. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided.
  5680. */
  5681. Rectangle.center = function(rectangle, result) {
  5682. if (!defined(rectangle)) {
  5683. throw new DeveloperError('rectangle is required');
  5684. }
  5685. var east = rectangle.east;
  5686. var west = rectangle.west;
  5687. if (east < west) {
  5688. east += CesiumMath.TWO_PI;
  5689. }
  5690. var longitude = CesiumMath.negativePiToPi((west + east) * 0.5);
  5691. var latitude = (rectangle.south + rectangle.north) * 0.5;
  5692. if (!defined(result)) {
  5693. return new Cartographic(longitude, latitude);
  5694. }
  5695. result.longitude = longitude;
  5696. result.latitude = latitude;
  5697. result.height = 0.0;
  5698. return result;
  5699. };
  5700. /**
  5701. * Computes the intersection of two rectangles. This function assumes that the rectangle's coordinates are
  5702. * latitude and longitude in radians and produces a correct intersection, taking into account the fact that
  5703. * the same angle can be represented with multiple values as well as the wrapping of longitude at the
  5704. * anti-meridian. For a simple intersection that ignores these factors and can be used with projected
  5705. * coordinates, see {@link Rectangle.simpleIntersection}.
  5706. *
  5707. * @param {Rectangle} rectangle On rectangle to find an intersection
  5708. * @param {Rectangle} otherRectangle Another rectangle to find an intersection
  5709. * @param {Rectangle} [result] The object onto which to store the result.
  5710. * @returns {Rectangle|undefined} The modified result parameter, a new Rectangle instance if none was provided or undefined if there is no intersection.
  5711. */
  5712. Rectangle.intersection = function(rectangle, otherRectangle, result) {
  5713. if (!defined(rectangle)) {
  5714. throw new DeveloperError('rectangle is required');
  5715. }
  5716. if (!defined(otherRectangle)) {
  5717. throw new DeveloperError('otherRectangle is required.');
  5718. }
  5719. var rectangleEast = rectangle.east;
  5720. var rectangleWest = rectangle.west;
  5721. var otherRectangleEast = otherRectangle.east;
  5722. var otherRectangleWest = otherRectangle.west;
  5723. if (rectangleEast < rectangleWest && otherRectangleEast > 0.0) {
  5724. rectangleEast += CesiumMath.TWO_PI;
  5725. } else if (otherRectangleEast < otherRectangleWest && rectangleEast > 0.0) {
  5726. otherRectangleEast += CesiumMath.TWO_PI;
  5727. }
  5728. if (rectangleEast < rectangleWest && otherRectangleWest < 0.0) {
  5729. otherRectangleWest += CesiumMath.TWO_PI;
  5730. } else if (otherRectangleEast < otherRectangleWest && rectangleWest < 0.0) {
  5731. rectangleWest += CesiumMath.TWO_PI;
  5732. }
  5733. var west = CesiumMath.negativePiToPi(Math.max(rectangleWest, otherRectangleWest));
  5734. var east = CesiumMath.negativePiToPi(Math.min(rectangleEast, otherRectangleEast));
  5735. if ((rectangle.west < rectangle.east || otherRectangle.west < otherRectangle.east) && east <= west) {
  5736. return undefined;
  5737. }
  5738. var south = Math.max(rectangle.south, otherRectangle.south);
  5739. var north = Math.min(rectangle.north, otherRectangle.north);
  5740. if (south >= north) {
  5741. return undefined;
  5742. }
  5743. if (!defined(result)) {
  5744. return new Rectangle(west, south, east, north);
  5745. }
  5746. result.west = west;
  5747. result.south = south;
  5748. result.east = east;
  5749. result.north = north;
  5750. return result;
  5751. };
  5752. /**
  5753. * Computes a simple intersection of two rectangles. Unlike {@link Rectangle.intersection}, this function
  5754. * does not attempt to put the angular coordinates into a consistent range or to account for crossing the
  5755. * anti-meridian. As such, it can be used for rectangles where the coordinates are not simply latitude
  5756. * and longitude (i.e. projected coordinates).
  5757. *
  5758. * @param {Rectangle} rectangle On rectangle to find an intersection
  5759. * @param {Rectangle} otherRectangle Another rectangle to find an intersection
  5760. * @param {Rectangle} [result] The object onto which to store the result.
  5761. * @returns {Rectangle|undefined} The modified result parameter, a new Rectangle instance if none was provided or undefined if there is no intersection.
  5762. */
  5763. Rectangle.simpleIntersection = function(rectangle, otherRectangle, result) {
  5764. if (!defined(rectangle)) {
  5765. throw new DeveloperError('rectangle is required');
  5766. }
  5767. if (!defined(otherRectangle)) {
  5768. throw new DeveloperError('otherRectangle is required.');
  5769. }
  5770. var west = Math.max(rectangle.west, otherRectangle.west);
  5771. var south = Math.max(rectangle.south, otherRectangle.south);
  5772. var east = Math.min(rectangle.east, otherRectangle.east);
  5773. var north = Math.min(rectangle.north, otherRectangle.north);
  5774. if (south >= north || west >= east) {
  5775. return undefined;
  5776. }
  5777. if (!defined(result)) {
  5778. return new Rectangle(west, south, east, north);
  5779. }
  5780. result.west = west;
  5781. result.south = south;
  5782. result.east = east;
  5783. result.north = north;
  5784. return result;
  5785. };
  5786. /**
  5787. * Computes a rectangle that is the union of two rectangles.
  5788. *
  5789. * @param {Rectangle} rectangle A rectangle to enclose in rectangle.
  5790. * @param {Rectangle} otherRectangle A rectangle to enclose in a rectangle.
  5791. * @param {Rectangle} [result] The object onto which to store the result.
  5792. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
  5793. */
  5794. Rectangle.union = function(rectangle, otherRectangle, result) {
  5795. if (!defined(rectangle)) {
  5796. throw new DeveloperError('rectangle is required');
  5797. }
  5798. if (!defined(otherRectangle)) {
  5799. throw new DeveloperError('otherRectangle is required.');
  5800. }
  5801. if (!defined(result)) {
  5802. result = new Rectangle();
  5803. }
  5804. var rectangleEast = rectangle.east;
  5805. var rectangleWest = rectangle.west;
  5806. var otherRectangleEast = otherRectangle.east;
  5807. var otherRectangleWest = otherRectangle.west;
  5808. if (rectangleEast < rectangleWest && otherRectangleEast > 0.0) {
  5809. rectangleEast += CesiumMath.TWO_PI;
  5810. } else if (otherRectangleEast < otherRectangleWest && rectangleEast > 0.0) {
  5811. otherRectangleEast += CesiumMath.TWO_PI;
  5812. }
  5813. if (rectangleEast < rectangleWest && otherRectangleWest < 0.0) {
  5814. otherRectangleWest += CesiumMath.TWO_PI;
  5815. } else if (otherRectangleEast < otherRectangleWest && rectangleWest < 0.0) {
  5816. rectangleWest += CesiumMath.TWO_PI;
  5817. }
  5818. var west = CesiumMath.convertLongitudeRange(Math.min(rectangleWest, otherRectangleWest));
  5819. var east = CesiumMath.convertLongitudeRange(Math.max(rectangleEast, otherRectangleEast));
  5820. result.west = west;
  5821. result.south = Math.min(rectangle.south, otherRectangle.south);
  5822. result.east = east;
  5823. result.north = Math.max(rectangle.north, otherRectangle.north);
  5824. return result;
  5825. };
  5826. /**
  5827. * Computes a rectangle by enlarging the provided rectangle until it contains the provided cartographic.
  5828. *
  5829. * @param {Rectangle} rectangle A rectangle to expand.
  5830. * @param {Cartographic} cartographic A cartographic to enclose in a rectangle.
  5831. * @param {Rectangle} [result] The object onto which to store the result.
  5832. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if one was not provided.
  5833. */
  5834. Rectangle.expand = function(rectangle, cartographic, result) {
  5835. if (!defined(rectangle)) {
  5836. throw new DeveloperError('rectangle is required.');
  5837. }
  5838. if (!defined(cartographic)) {
  5839. throw new DeveloperError('cartographic is required.');
  5840. }
  5841. if (!defined(result)) {
  5842. result = new Rectangle();
  5843. }
  5844. result.west = Math.min(rectangle.west, cartographic.longitude);
  5845. result.south = Math.min(rectangle.south, cartographic.latitude);
  5846. result.east = Math.max(rectangle.east, cartographic.longitude);
  5847. result.north = Math.max(rectangle.north, cartographic.latitude);
  5848. return result;
  5849. };
  5850. /**
  5851. * Returns true if the cartographic is on or inside the rectangle, false otherwise.
  5852. *
  5853. * @param {Rectangle} rectangle The rectangle
  5854. * @param {Cartographic} cartographic The cartographic to test.
  5855. * @returns {Boolean} true if the provided cartographic is inside the rectangle, false otherwise.
  5856. */
  5857. Rectangle.contains = function(rectangle, cartographic) {
  5858. if (!defined(rectangle)) {
  5859. throw new DeveloperError('rectangle is required');
  5860. }
  5861. if (!defined(cartographic)) {
  5862. throw new DeveloperError('cartographic is required.');
  5863. }
  5864. var longitude = cartographic.longitude;
  5865. var latitude = cartographic.latitude;
  5866. var west = rectangle.west;
  5867. var east = rectangle.east;
  5868. if (east < west) {
  5869. east += CesiumMath.TWO_PI;
  5870. if (longitude < 0.0) {
  5871. longitude += CesiumMath.TWO_PI;
  5872. }
  5873. }
  5874. return (longitude > west || CesiumMath.equalsEpsilon(longitude, west, CesiumMath.EPSILON14)) &&
  5875. (longitude < east || CesiumMath.equalsEpsilon(longitude, east, CesiumMath.EPSILON14)) &&
  5876. latitude >= rectangle.south &&
  5877. latitude <= rectangle.north;
  5878. };
  5879. var subsampleLlaScratch = new Cartographic();
  5880. /**
  5881. * Samples an rectangle so that it includes a list of Cartesian points suitable for passing to
  5882. * {@link BoundingSphere#fromPoints}. Sampling is necessary to account
  5883. * for rectangles that cover the poles or cross the equator.
  5884. *
  5885. * @param {Rectangle} rectangle The rectangle to subsample.
  5886. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid to use.
  5887. * @param {Number} [surfaceHeight=0.0] The height of the rectangle above the ellipsoid.
  5888. * @param {Cartesian3[]} [result] The array of Cartesians onto which to store the result.
  5889. * @returns {Cartesian3[]} The modified result parameter or a new Array of Cartesians instances if none was provided.
  5890. */
  5891. Rectangle.subsample = function(rectangle, ellipsoid, surfaceHeight, result) {
  5892. if (!defined(rectangle)) {
  5893. throw new DeveloperError('rectangle is required');
  5894. }
  5895. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  5896. surfaceHeight = defaultValue(surfaceHeight, 0.0);
  5897. if (!defined(result)) {
  5898. result = [];
  5899. }
  5900. var length = 0;
  5901. var north = rectangle.north;
  5902. var south = rectangle.south;
  5903. var east = rectangle.east;
  5904. var west = rectangle.west;
  5905. var lla = subsampleLlaScratch;
  5906. lla.height = surfaceHeight;
  5907. lla.longitude = west;
  5908. lla.latitude = north;
  5909. result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
  5910. length++;
  5911. lla.longitude = east;
  5912. result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
  5913. length++;
  5914. lla.latitude = south;
  5915. result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
  5916. length++;
  5917. lla.longitude = west;
  5918. result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
  5919. length++;
  5920. if (north < 0.0) {
  5921. lla.latitude = north;
  5922. } else if (south > 0.0) {
  5923. lla.latitude = south;
  5924. } else {
  5925. lla.latitude = 0.0;
  5926. }
  5927. for ( var i = 1; i < 8; ++i) {
  5928. lla.longitude = -Math.PI + i * CesiumMath.PI_OVER_TWO;
  5929. if (Rectangle.contains(rectangle, lla)) {
  5930. result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
  5931. length++;
  5932. }
  5933. }
  5934. if (lla.latitude === 0.0) {
  5935. lla.longitude = west;
  5936. result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
  5937. length++;
  5938. lla.longitude = east;
  5939. result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
  5940. length++;
  5941. }
  5942. result.length = length;
  5943. return result;
  5944. };
  5945. /**
  5946. * The largest possible rectangle.
  5947. *
  5948. * @type {Rectangle}
  5949. * @constant
  5950. */
  5951. Rectangle.MAX_VALUE = freezeObject(new Rectangle(-Math.PI, -CesiumMath.PI_OVER_TWO, Math.PI, CesiumMath.PI_OVER_TWO));
  5952. return Rectangle;
  5953. });
  5954. /*global define*/
  5955. define('Core/GeographicTilingScheme',[
  5956. './Cartesian2',
  5957. './defaultValue',
  5958. './defined',
  5959. './defineProperties',
  5960. './DeveloperError',
  5961. './Ellipsoid',
  5962. './GeographicProjection',
  5963. './Math',
  5964. './Rectangle'
  5965. ], function(
  5966. Cartesian2,
  5967. defaultValue,
  5968. defined,
  5969. defineProperties,
  5970. DeveloperError,
  5971. Ellipsoid,
  5972. GeographicProjection,
  5973. CesiumMath,
  5974. Rectangle) {
  5975. 'use strict';
  5976. /**
  5977. * A tiling scheme for geometry referenced to a simple {@link GeographicProjection} where
  5978. * longitude and latitude are directly mapped to X and Y. This projection is commonly
  5979. * known as geographic, equirectangular, equidistant cylindrical, or plate carrée.
  5980. *
  5981. * @alias GeographicTilingScheme
  5982. * @constructor
  5983. *
  5984. * @param {Object} [options] Object with the following properties:
  5985. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid whose surface is being tiled. Defaults to
  5986. * the WGS84 ellipsoid.
  5987. * @param {Rectangle} [options.rectangle=Rectangle.MAX_VALUE] The rectangle, in radians, covered by the tiling scheme.
  5988. * @param {Number} [options.numberOfLevelZeroTilesX=2] The number of tiles in the X direction at level zero of
  5989. * the tile tree.
  5990. * @param {Number} [options.numberOfLevelZeroTilesY=1] The number of tiles in the Y direction at level zero of
  5991. * the tile tree.
  5992. */
  5993. function GeographicTilingScheme(options) {
  5994. options = defaultValue(options, {});
  5995. this._ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  5996. this._rectangle = defaultValue(options.rectangle, Rectangle.MAX_VALUE);
  5997. this._projection = new GeographicProjection(this._ellipsoid);
  5998. this._numberOfLevelZeroTilesX = defaultValue(options.numberOfLevelZeroTilesX, 2);
  5999. this._numberOfLevelZeroTilesY = defaultValue(options.numberOfLevelZeroTilesY, 1);
  6000. }
  6001. defineProperties(GeographicTilingScheme.prototype, {
  6002. /**
  6003. * Gets the ellipsoid that is tiled by this tiling scheme.
  6004. * @memberof GeographicTilingScheme.prototype
  6005. * @type {Ellipsoid}
  6006. */
  6007. ellipsoid : {
  6008. get : function() {
  6009. return this._ellipsoid;
  6010. }
  6011. },
  6012. /**
  6013. * Gets the rectangle, in radians, covered by this tiling scheme.
  6014. * @memberof GeographicTilingScheme.prototype
  6015. * @type {Rectangle}
  6016. */
  6017. rectangle : {
  6018. get : function() {
  6019. return this._rectangle;
  6020. }
  6021. },
  6022. /**
  6023. * Gets the map projection used by this tiling scheme.
  6024. * @memberof GeographicTilingScheme.prototype
  6025. * @type {MapProjection}
  6026. */
  6027. projection : {
  6028. get : function() {
  6029. return this._projection;
  6030. }
  6031. }
  6032. });
  6033. /**
  6034. * Gets the total number of tiles in the X direction at a specified level-of-detail.
  6035. *
  6036. * @param {Number} level The level-of-detail.
  6037. * @returns {Number} The number of tiles in the X direction at the given level.
  6038. */
  6039. GeographicTilingScheme.prototype.getNumberOfXTilesAtLevel = function(level) {
  6040. return this._numberOfLevelZeroTilesX << level;
  6041. };
  6042. /**
  6043. * Gets the total number of tiles in the Y direction at a specified level-of-detail.
  6044. *
  6045. * @param {Number} level The level-of-detail.
  6046. * @returns {Number} The number of tiles in the Y direction at the given level.
  6047. */
  6048. GeographicTilingScheme.prototype.getNumberOfYTilesAtLevel = function(level) {
  6049. return this._numberOfLevelZeroTilesY << level;
  6050. };
  6051. /**
  6052. * Transforms an rectangle specified in geodetic radians to the native coordinate system
  6053. * of this tiling scheme.
  6054. *
  6055. * @param {Rectangle} rectangle The rectangle to transform.
  6056. * @param {Rectangle} [result] The instance to which to copy the result, or undefined if a new instance
  6057. * should be created.
  6058. * @returns {Rectangle} The specified 'result', or a new object containing the native rectangle if 'result'
  6059. * is undefined.
  6060. */
  6061. GeographicTilingScheme.prototype.rectangleToNativeRectangle = function(rectangle, result) {
  6062. if (!defined(rectangle)) {
  6063. throw new DeveloperError('rectangle is required.');
  6064. }
  6065. var west = CesiumMath.toDegrees(rectangle.west);
  6066. var south = CesiumMath.toDegrees(rectangle.south);
  6067. var east = CesiumMath.toDegrees(rectangle.east);
  6068. var north = CesiumMath.toDegrees(rectangle.north);
  6069. if (!defined(result)) {
  6070. return new Rectangle(west, south, east, north);
  6071. }
  6072. result.west = west;
  6073. result.south = south;
  6074. result.east = east;
  6075. result.north = north;
  6076. return result;
  6077. };
  6078. /**
  6079. * Converts tile x, y coordinates and level to an rectangle expressed in the native coordinates
  6080. * of the tiling scheme.
  6081. *
  6082. * @param {Number} x The integer x coordinate of the tile.
  6083. * @param {Number} y The integer y coordinate of the tile.
  6084. * @param {Number} level The tile level-of-detail. Zero is the least detailed.
  6085. * @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
  6086. * should be created.
  6087. * @returns {Rectangle} The specified 'result', or a new object containing the rectangle
  6088. * if 'result' is undefined.
  6089. */
  6090. GeographicTilingScheme.prototype.tileXYToNativeRectangle = function(x, y, level, result) {
  6091. var rectangleRadians = this.tileXYToRectangle(x, y, level, result);
  6092. rectangleRadians.west = CesiumMath.toDegrees(rectangleRadians.west);
  6093. rectangleRadians.south = CesiumMath.toDegrees(rectangleRadians.south);
  6094. rectangleRadians.east = CesiumMath.toDegrees(rectangleRadians.east);
  6095. rectangleRadians.north = CesiumMath.toDegrees(rectangleRadians.north);
  6096. return rectangleRadians;
  6097. };
  6098. /**
  6099. * Converts tile x, y coordinates and level to a cartographic rectangle in radians.
  6100. *
  6101. * @param {Number} x The integer x coordinate of the tile.
  6102. * @param {Number} y The integer y coordinate of the tile.
  6103. * @param {Number} level The tile level-of-detail. Zero is the least detailed.
  6104. * @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
  6105. * should be created.
  6106. * @returns {Rectangle} The specified 'result', or a new object containing the rectangle
  6107. * if 'result' is undefined.
  6108. */
  6109. GeographicTilingScheme.prototype.tileXYToRectangle = function(x, y, level, result) {
  6110. var rectangle = this._rectangle;
  6111. var xTiles = this.getNumberOfXTilesAtLevel(level);
  6112. var yTiles = this.getNumberOfYTilesAtLevel(level);
  6113. var xTileWidth = rectangle.width / xTiles;
  6114. var west = x * xTileWidth + rectangle.west;
  6115. var east = (x + 1) * xTileWidth + rectangle.west;
  6116. var yTileHeight = rectangle.height / yTiles;
  6117. var north = rectangle.north - y * yTileHeight;
  6118. var south = rectangle.north - (y + 1) * yTileHeight;
  6119. if (!defined(result)) {
  6120. result = new Rectangle(west, south, east, north);
  6121. }
  6122. result.west = west;
  6123. result.south = south;
  6124. result.east = east;
  6125. result.north = north;
  6126. return result;
  6127. };
  6128. /**
  6129. * Calculates the tile x, y coordinates of the tile containing
  6130. * a given cartographic position.
  6131. *
  6132. * @param {Cartographic} position The position.
  6133. * @param {Number} level The tile level-of-detail. Zero is the least detailed.
  6134. * @param {Cartesian2} [result] The instance to which to copy the result, or undefined if a new instance
  6135. * should be created.
  6136. * @returns {Cartesian2} The specified 'result', or a new object containing the tile x, y coordinates
  6137. * if 'result' is undefined.
  6138. */
  6139. GeographicTilingScheme.prototype.positionToTileXY = function(position, level, result) {
  6140. var rectangle = this._rectangle;
  6141. if (!Rectangle.contains(rectangle, position)) {
  6142. // outside the bounds of the tiling scheme
  6143. return undefined;
  6144. }
  6145. var xTiles = this.getNumberOfXTilesAtLevel(level);
  6146. var yTiles = this.getNumberOfYTilesAtLevel(level);
  6147. var xTileWidth = rectangle.width / xTiles;
  6148. var yTileHeight = rectangle.height / yTiles;
  6149. var longitude = position.longitude;
  6150. if (rectangle.east < rectangle.west) {
  6151. longitude += CesiumMath.TWO_PI;
  6152. }
  6153. var xTileCoordinate = (longitude - rectangle.west) / xTileWidth | 0;
  6154. if (xTileCoordinate >= xTiles) {
  6155. xTileCoordinate = xTiles - 1;
  6156. }
  6157. var yTileCoordinate = (rectangle.north - position.latitude) / yTileHeight | 0;
  6158. if (yTileCoordinate >= yTiles) {
  6159. yTileCoordinate = yTiles - 1;
  6160. }
  6161. if (!defined(result)) {
  6162. return new Cartesian2(xTileCoordinate, yTileCoordinate);
  6163. }
  6164. result.x = xTileCoordinate;
  6165. result.y = yTileCoordinate;
  6166. return result;
  6167. };
  6168. return GeographicTilingScheme;
  6169. });
  6170. /*global define*/
  6171. define('Core/getImagePixels',[
  6172. './defined'
  6173. ], function(
  6174. defined) {
  6175. 'use strict';
  6176. var context2DsByWidthAndHeight = {};
  6177. /**
  6178. * Extract a pixel array from a loaded image. Draws the image
  6179. * into a canvas so it can read the pixels back.
  6180. *
  6181. * @exports getImagePixels
  6182. *
  6183. * @param {Image} image The image to extract pixels from.
  6184. * @returns {CanvasPixelArray} The pixels of the image.
  6185. */
  6186. function getImagePixels(image, width, height) {
  6187. if (!defined(width)) {
  6188. width = image.width;
  6189. }
  6190. if (!defined(height)) {
  6191. height = image.height;
  6192. }
  6193. var context2DsByHeight = context2DsByWidthAndHeight[width];
  6194. if (!defined(context2DsByHeight)) {
  6195. context2DsByHeight = {};
  6196. context2DsByWidthAndHeight[width] = context2DsByHeight;
  6197. }
  6198. var context2d = context2DsByHeight[height];
  6199. if (!defined(context2d)) {
  6200. var canvas = document.createElement('canvas');
  6201. canvas.width = width;
  6202. canvas.height = height;
  6203. context2d = canvas.getContext('2d');
  6204. context2d.globalCompositeOperation = 'copy';
  6205. context2DsByHeight[height] = context2d;
  6206. }
  6207. context2d.drawImage(image, 0, 0, width, height);
  6208. return context2d.getImageData(0, 0, width, height).data;
  6209. }
  6210. return getImagePixels;
  6211. });
  6212. /*global define*/
  6213. define('Core/Intersect',[
  6214. './freezeObject'
  6215. ], function(
  6216. freezeObject) {
  6217. 'use strict';
  6218. /**
  6219. * This enumerated type is used in determining where, relative to the frustum, an
  6220. * object is located. The object can either be fully contained within the frustum (INSIDE),
  6221. * partially inside the frustum and partially outside (INTERSECTING), or somwhere entirely
  6222. * outside of the frustum's 6 planes (OUTSIDE).
  6223. *
  6224. * @exports Intersect
  6225. */
  6226. var Intersect = {
  6227. /**
  6228. * Represents that an object is not contained within the frustum.
  6229. *
  6230. * @type {Number}
  6231. * @constant
  6232. */
  6233. OUTSIDE : -1,
  6234. /**
  6235. * Represents that an object intersects one of the frustum's planes.
  6236. *
  6237. * @type {Number}
  6238. * @constant
  6239. */
  6240. INTERSECTING : 0,
  6241. /**
  6242. * Represents that an object is fully within the frustum.
  6243. *
  6244. * @type {Number}
  6245. * @constant
  6246. */
  6247. INSIDE : 1
  6248. };
  6249. return freezeObject(Intersect);
  6250. });
  6251. /*global define*/
  6252. define('Core/AxisAlignedBoundingBox',[
  6253. './Cartesian3',
  6254. './defaultValue',
  6255. './defined',
  6256. './DeveloperError',
  6257. './Intersect'
  6258. ], function(
  6259. Cartesian3,
  6260. defaultValue,
  6261. defined,
  6262. DeveloperError,
  6263. Intersect) {
  6264. 'use strict';
  6265. /**
  6266. * Creates an instance of an AxisAlignedBoundingBox from the minimum and maximum points along the x, y, and z axes.
  6267. * @alias AxisAlignedBoundingBox
  6268. * @constructor
  6269. *
  6270. * @param {Cartesian3} [minimum=Cartesian3.ZERO] The minimum point along the x, y, and z axes.
  6271. * @param {Cartesian3} [maximum=Cartesian3.ZERO] The maximum point along the x, y, and z axes.
  6272. * @param {Cartesian3} [center] The center of the box; automatically computed if not supplied.
  6273. *
  6274. * @see BoundingSphere
  6275. * @see BoundingRectangle
  6276. */
  6277. function AxisAlignedBoundingBox(minimum, maximum, center) {
  6278. /**
  6279. * The minimum point defining the bounding box.
  6280. * @type {Cartesian3}
  6281. * @default {@link Cartesian3.ZERO}
  6282. */
  6283. this.minimum = Cartesian3.clone(defaultValue(minimum, Cartesian3.ZERO));
  6284. /**
  6285. * The maximum point defining the bounding box.
  6286. * @type {Cartesian3}
  6287. * @default {@link Cartesian3.ZERO}
  6288. */
  6289. this.maximum = Cartesian3.clone(defaultValue(maximum, Cartesian3.ZERO));
  6290. //If center was not defined, compute it.
  6291. if (!defined(center)) {
  6292. center = Cartesian3.add(this.minimum, this.maximum, new Cartesian3());
  6293. Cartesian3.multiplyByScalar(center, 0.5, center);
  6294. } else {
  6295. center = Cartesian3.clone(center);
  6296. }
  6297. /**
  6298. * The center point of the bounding box.
  6299. * @type {Cartesian3}
  6300. */
  6301. this.center = center;
  6302. }
  6303. /**
  6304. * Computes an instance of an AxisAlignedBoundingBox. The box is determined by
  6305. * finding the points spaced the farthest apart on the x, y, and z axes.
  6306. *
  6307. * @param {Cartesian3[]} positions List of points that the bounding box will enclose. Each point must have a <code>x</code>, <code>y</code>, and <code>z</code> properties.
  6308. * @param {AxisAlignedBoundingBox} [result] The object onto which to store the result.
  6309. * @returns {AxisAlignedBoundingBox} The modified result parameter or a new AxisAlignedBoundingBox instance if one was not provided.
  6310. *
  6311. * @example
  6312. * // Compute an axis aligned bounding box enclosing two points.
  6313. * var box = Cesium.AxisAlignedBoundingBox.fromPoints([new Cesium.Cartesian3(2, 0, 0), new Cesium.Cartesian3(-2, 0, 0)]);
  6314. */
  6315. AxisAlignedBoundingBox.fromPoints = function(positions, result) {
  6316. if (!defined(result)) {
  6317. result = new AxisAlignedBoundingBox();
  6318. }
  6319. if (!defined(positions) || positions.length === 0) {
  6320. result.minimum = Cartesian3.clone(Cartesian3.ZERO, result.minimum);
  6321. result.maximum = Cartesian3.clone(Cartesian3.ZERO, result.maximum);
  6322. result.center = Cartesian3.clone(Cartesian3.ZERO, result.center);
  6323. return result;
  6324. }
  6325. var minimumX = positions[0].x;
  6326. var minimumY = positions[0].y;
  6327. var minimumZ = positions[0].z;
  6328. var maximumX = positions[0].x;
  6329. var maximumY = positions[0].y;
  6330. var maximumZ = positions[0].z;
  6331. var length = positions.length;
  6332. for ( var i = 1; i < length; i++) {
  6333. var p = positions[i];
  6334. var x = p.x;
  6335. var y = p.y;
  6336. var z = p.z;
  6337. minimumX = Math.min(x, minimumX);
  6338. maximumX = Math.max(x, maximumX);
  6339. minimumY = Math.min(y, minimumY);
  6340. maximumY = Math.max(y, maximumY);
  6341. minimumZ = Math.min(z, minimumZ);
  6342. maximumZ = Math.max(z, maximumZ);
  6343. }
  6344. var minimum = result.minimum;
  6345. minimum.x = minimumX;
  6346. minimum.y = minimumY;
  6347. minimum.z = minimumZ;
  6348. var maximum = result.maximum;
  6349. maximum.x = maximumX;
  6350. maximum.y = maximumY;
  6351. maximum.z = maximumZ;
  6352. var center = Cartesian3.add(minimum, maximum, result.center);
  6353. Cartesian3.multiplyByScalar(center, 0.5, center);
  6354. return result;
  6355. };
  6356. /**
  6357. * Duplicates a AxisAlignedBoundingBox instance.
  6358. *
  6359. * @param {AxisAlignedBoundingBox} box The bounding box to duplicate.
  6360. * @param {AxisAlignedBoundingBox} [result] The object onto which to store the result.
  6361. * @returns {AxisAlignedBoundingBox} The modified result parameter or a new AxisAlignedBoundingBox instance if none was provided. (Returns undefined if box is undefined)
  6362. */
  6363. AxisAlignedBoundingBox.clone = function(box, result) {
  6364. if (!defined(box)) {
  6365. return undefined;
  6366. }
  6367. if (!defined(result)) {
  6368. return new AxisAlignedBoundingBox(box.minimum, box.maximum);
  6369. }
  6370. result.minimum = Cartesian3.clone(box.minimum, result.minimum);
  6371. result.maximum = Cartesian3.clone(box.maximum, result.maximum);
  6372. result.center = Cartesian3.clone(box.center, result.center);
  6373. return result;
  6374. };
  6375. /**
  6376. * Compares the provided AxisAlignedBoundingBox componentwise and returns
  6377. * <code>true</code> if they are equal, <code>false</code> otherwise.
  6378. *
  6379. * @param {AxisAlignedBoundingBox} [left] The first AxisAlignedBoundingBox.
  6380. * @param {AxisAlignedBoundingBox} [right] The second AxisAlignedBoundingBox.
  6381. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  6382. */
  6383. AxisAlignedBoundingBox.equals = function(left, right) {
  6384. return (left === right) ||
  6385. ((defined(left)) &&
  6386. (defined(right)) &&
  6387. Cartesian3.equals(left.center, right.center) &&
  6388. Cartesian3.equals(left.minimum, right.minimum) &&
  6389. Cartesian3.equals(left.maximum, right.maximum));
  6390. };
  6391. var intersectScratch = new Cartesian3();
  6392. /**
  6393. * Determines which side of a plane a box is located.
  6394. *
  6395. * @param {AxisAlignedBoundingBox} box The bounding box to test.
  6396. * @param {Plane} plane The plane to test against.
  6397. * @returns {Intersect} {@link Intersect.INSIDE} if the entire box is on the side of the plane
  6398. * the normal is pointing, {@link Intersect.OUTSIDE} if the entire box is
  6399. * on the opposite side, and {@link Intersect.INTERSECTING} if the box
  6400. * intersects the plane.
  6401. */
  6402. AxisAlignedBoundingBox.intersectPlane = function(box, plane) {
  6403. if (!defined(box)) {
  6404. throw new DeveloperError('box is required.');
  6405. }
  6406. if (!defined(plane)) {
  6407. throw new DeveloperError('plane is required.');
  6408. }
  6409. intersectScratch = Cartesian3.subtract(box.maximum, box.minimum, intersectScratch);
  6410. var h = Cartesian3.multiplyByScalar(intersectScratch, 0.5, intersectScratch); //The positive half diagonal
  6411. var normal = plane.normal;
  6412. var e = h.x * Math.abs(normal.x) + h.y * Math.abs(normal.y) + h.z * Math.abs(normal.z);
  6413. var s = Cartesian3.dot(box.center, normal) + plane.distance; //signed distance from center
  6414. if (s - e > 0) {
  6415. return Intersect.INSIDE;
  6416. }
  6417. if (s + e < 0) {
  6418. //Not in front because normals point inward
  6419. return Intersect.OUTSIDE;
  6420. }
  6421. return Intersect.INTERSECTING;
  6422. };
  6423. /**
  6424. * Duplicates this AxisAlignedBoundingBox instance.
  6425. *
  6426. * @param {AxisAlignedBoundingBox} [result] The object onto which to store the result.
  6427. * @returns {AxisAlignedBoundingBox} The modified result parameter or a new AxisAlignedBoundingBox instance if one was not provided.
  6428. */
  6429. AxisAlignedBoundingBox.prototype.clone = function(result) {
  6430. return AxisAlignedBoundingBox.clone(this, result);
  6431. };
  6432. /**
  6433. * Determines which side of a plane this box is located.
  6434. *
  6435. * @param {Plane} plane The plane to test against.
  6436. * @returns {Intersect} {@link Intersect.INSIDE} if the entire box is on the side of the plane
  6437. * the normal is pointing, {@link Intersect.OUTSIDE} if the entire box is
  6438. * on the opposite side, and {@link Intersect.INTERSECTING} if the box
  6439. * intersects the plane.
  6440. */
  6441. AxisAlignedBoundingBox.prototype.intersectPlane = function(plane) {
  6442. return AxisAlignedBoundingBox.intersectPlane(this, plane);
  6443. };
  6444. /**
  6445. * Compares this AxisAlignedBoundingBox against the provided AxisAlignedBoundingBox componentwise and returns
  6446. * <code>true</code> if they are equal, <code>false</code> otherwise.
  6447. *
  6448. * @param {AxisAlignedBoundingBox} [right] The right hand side AxisAlignedBoundingBox.
  6449. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  6450. */
  6451. AxisAlignedBoundingBox.prototype.equals = function(right) {
  6452. return AxisAlignedBoundingBox.equals(this, right);
  6453. };
  6454. return AxisAlignedBoundingBox;
  6455. });
  6456. /*global define*/
  6457. define('Core/Interval',[
  6458. './defaultValue'
  6459. ], function(
  6460. defaultValue) {
  6461. 'use strict';
  6462. /**
  6463. * Represents the closed interval [start, stop].
  6464. * @alias Interval
  6465. * @constructor
  6466. *
  6467. * @param {Number} [start=0.0] The beginning of the interval.
  6468. * @param {Number} [stop=0.0] The end of the interval.
  6469. */
  6470. function Interval(start, stop) {
  6471. /**
  6472. * The beginning of the interval.
  6473. * @type {Number}
  6474. * @default 0.0
  6475. */
  6476. this.start = defaultValue(start, 0.0);
  6477. /**
  6478. * The end of the interval.
  6479. * @type {Number}
  6480. * @default 0.0
  6481. */
  6482. this.stop = defaultValue(stop, 0.0);
  6483. }
  6484. return Interval;
  6485. });
  6486. /*global define*/
  6487. define('Core/Matrix3',[
  6488. './Cartesian3',
  6489. './defaultValue',
  6490. './defined',
  6491. './defineProperties',
  6492. './DeveloperError',
  6493. './freezeObject',
  6494. './Math'
  6495. ], function(
  6496. Cartesian3,
  6497. defaultValue,
  6498. defined,
  6499. defineProperties,
  6500. DeveloperError,
  6501. freezeObject,
  6502. CesiumMath) {
  6503. 'use strict';
  6504. /**
  6505. * A 3x3 matrix, indexable as a column-major order array.
  6506. * Constructor parameters are in row-major order for code readability.
  6507. * @alias Matrix3
  6508. * @constructor
  6509. *
  6510. * @param {Number} [column0Row0=0.0] The value for column 0, row 0.
  6511. * @param {Number} [column1Row0=0.0] The value for column 1, row 0.
  6512. * @param {Number} [column2Row0=0.0] The value for column 2, row 0.
  6513. * @param {Number} [column0Row1=0.0] The value for column 0, row 1.
  6514. * @param {Number} [column1Row1=0.0] The value for column 1, row 1.
  6515. * @param {Number} [column2Row1=0.0] The value for column 2, row 1.
  6516. * @param {Number} [column0Row2=0.0] The value for column 0, row 2.
  6517. * @param {Number} [column1Row2=0.0] The value for column 1, row 2.
  6518. * @param {Number} [column2Row2=0.0] The value for column 2, row 2.
  6519. *
  6520. * @see Matrix3.fromColumnMajorArray
  6521. * @see Matrix3.fromRowMajorArray
  6522. * @see Matrix3.fromQuaternion
  6523. * @see Matrix3.fromScale
  6524. * @see Matrix3.fromUniformScale
  6525. * @see Matrix2
  6526. * @see Matrix4
  6527. */
  6528. function Matrix3(column0Row0, column1Row0, column2Row0,
  6529. column0Row1, column1Row1, column2Row1,
  6530. column0Row2, column1Row2, column2Row2) {
  6531. this[0] = defaultValue(column0Row0, 0.0);
  6532. this[1] = defaultValue(column0Row1, 0.0);
  6533. this[2] = defaultValue(column0Row2, 0.0);
  6534. this[3] = defaultValue(column1Row0, 0.0);
  6535. this[4] = defaultValue(column1Row1, 0.0);
  6536. this[5] = defaultValue(column1Row2, 0.0);
  6537. this[6] = defaultValue(column2Row0, 0.0);
  6538. this[7] = defaultValue(column2Row1, 0.0);
  6539. this[8] = defaultValue(column2Row2, 0.0);
  6540. }
  6541. /**
  6542. * The number of elements used to pack the object into an array.
  6543. * @type {Number}
  6544. */
  6545. Matrix3.packedLength = 9;
  6546. /**
  6547. * Stores the provided instance into the provided array.
  6548. *
  6549. * @param {Matrix3} value The value to pack.
  6550. * @param {Number[]} array The array to pack into.
  6551. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  6552. *
  6553. * @returns {Number[]} The array that was packed into
  6554. */
  6555. Matrix3.pack = function(value, array, startingIndex) {
  6556. if (!defined(value)) {
  6557. throw new DeveloperError('value is required');
  6558. }
  6559. if (!defined(array)) {
  6560. throw new DeveloperError('array is required');
  6561. }
  6562. startingIndex = defaultValue(startingIndex, 0);
  6563. array[startingIndex++] = value[0];
  6564. array[startingIndex++] = value[1];
  6565. array[startingIndex++] = value[2];
  6566. array[startingIndex++] = value[3];
  6567. array[startingIndex++] = value[4];
  6568. array[startingIndex++] = value[5];
  6569. array[startingIndex++] = value[6];
  6570. array[startingIndex++] = value[7];
  6571. array[startingIndex++] = value[8];
  6572. return array;
  6573. };
  6574. /**
  6575. * Retrieves an instance from a packed array.
  6576. *
  6577. * @param {Number[]} array The packed array.
  6578. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  6579. * @param {Matrix3} [result] The object into which to store the result.
  6580. * @returns {Matrix3} The modified result parameter or a new Matrix3 instance if one was not provided.
  6581. */
  6582. Matrix3.unpack = function(array, startingIndex, result) {
  6583. if (!defined(array)) {
  6584. throw new DeveloperError('array is required');
  6585. }
  6586. startingIndex = defaultValue(startingIndex, 0);
  6587. if (!defined(result)) {
  6588. result = new Matrix3();
  6589. }
  6590. result[0] = array[startingIndex++];
  6591. result[1] = array[startingIndex++];
  6592. result[2] = array[startingIndex++];
  6593. result[3] = array[startingIndex++];
  6594. result[4] = array[startingIndex++];
  6595. result[5] = array[startingIndex++];
  6596. result[6] = array[startingIndex++];
  6597. result[7] = array[startingIndex++];
  6598. result[8] = array[startingIndex++];
  6599. return result;
  6600. };
  6601. /**
  6602. * Duplicates a Matrix3 instance.
  6603. *
  6604. * @param {Matrix3} matrix The matrix to duplicate.
  6605. * @param {Matrix3} [result] The object onto which to store the result.
  6606. * @returns {Matrix3} The modified result parameter or a new Matrix3 instance if one was not provided. (Returns undefined if matrix is undefined)
  6607. */
  6608. Matrix3.clone = function(values, result) {
  6609. if (!defined(values)) {
  6610. return undefined;
  6611. }
  6612. if (!defined(result)) {
  6613. return new Matrix3(values[0], values[3], values[6],
  6614. values[1], values[4], values[7],
  6615. values[2], values[5], values[8]);
  6616. }
  6617. result[0] = values[0];
  6618. result[1] = values[1];
  6619. result[2] = values[2];
  6620. result[3] = values[3];
  6621. result[4] = values[4];
  6622. result[5] = values[5];
  6623. result[6] = values[6];
  6624. result[7] = values[7];
  6625. result[8] = values[8];
  6626. return result;
  6627. };
  6628. /**
  6629. * Creates a Matrix3 from 9 consecutive elements in an array.
  6630. *
  6631. * @param {Number[]} array The array whose 9 consecutive elements correspond to the positions of the matrix. Assumes column-major order.
  6632. * @param {Number} [startingIndex=0] The offset into the array of the first element, which corresponds to first column first row position in the matrix.
  6633. * @param {Matrix3} [result] The object onto which to store the result.
  6634. * @returns {Matrix3} The modified result parameter or a new Matrix3 instance if one was not provided.
  6635. *
  6636. * @example
  6637. * // Create the Matrix3:
  6638. * // [1.0, 2.0, 3.0]
  6639. * // [1.0, 2.0, 3.0]
  6640. * // [1.0, 2.0, 3.0]
  6641. *
  6642. * var v = [1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0];
  6643. * var m = Cesium.Matrix3.fromArray(v);
  6644. *
  6645. * // Create same Matrix3 with using an offset into an array
  6646. * var v2 = [0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0];
  6647. * var m2 = Cesium.Matrix3.fromArray(v2, 2);
  6648. */
  6649. Matrix3.fromArray = function(array, startingIndex, result) {
  6650. if (!defined(array)) {
  6651. throw new DeveloperError('array is required');
  6652. }
  6653. startingIndex = defaultValue(startingIndex, 0);
  6654. if (!defined(result)) {
  6655. result = new Matrix3();
  6656. }
  6657. result[0] = array[startingIndex];
  6658. result[1] = array[startingIndex + 1];
  6659. result[2] = array[startingIndex + 2];
  6660. result[3] = array[startingIndex + 3];
  6661. result[4] = array[startingIndex + 4];
  6662. result[5] = array[startingIndex + 5];
  6663. result[6] = array[startingIndex + 6];
  6664. result[7] = array[startingIndex + 7];
  6665. result[8] = array[startingIndex + 8];
  6666. return result;
  6667. };
  6668. /**
  6669. * Creates a Matrix3 instance from a column-major order array.
  6670. *
  6671. * @param {Number[]} values The column-major order array.
  6672. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
  6673. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
  6674. */
  6675. Matrix3.fromColumnMajorArray = function(values, result) {
  6676. if (!defined(values)) {
  6677. throw new DeveloperError('values parameter is required');
  6678. }
  6679. return Matrix3.clone(values, result);
  6680. };
  6681. /**
  6682. * Creates a Matrix3 instance from a row-major order array.
  6683. * The resulting matrix will be in column-major order.
  6684. *
  6685. * @param {Number[]} values The row-major order array.
  6686. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
  6687. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
  6688. */
  6689. Matrix3.fromRowMajorArray = function(values, result) {
  6690. if (!defined(values)) {
  6691. throw new DeveloperError('values is required.');
  6692. }
  6693. if (!defined(result)) {
  6694. return new Matrix3(values[0], values[1], values[2],
  6695. values[3], values[4], values[5],
  6696. values[6], values[7], values[8]);
  6697. }
  6698. result[0] = values[0];
  6699. result[1] = values[3];
  6700. result[2] = values[6];
  6701. result[3] = values[1];
  6702. result[4] = values[4];
  6703. result[5] = values[7];
  6704. result[6] = values[2];
  6705. result[7] = values[5];
  6706. result[8] = values[8];
  6707. return result;
  6708. };
  6709. /**
  6710. * Computes a 3x3 rotation matrix from the provided quaternion.
  6711. *
  6712. * @param {Quaternion} quaternion the quaternion to use.
  6713. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
  6714. * @returns {Matrix3} The 3x3 rotation matrix from this quaternion.
  6715. */
  6716. Matrix3.fromQuaternion = function(quaternion, result) {
  6717. if (!defined(quaternion)) {
  6718. throw new DeveloperError('quaternion is required');
  6719. }
  6720. var x2 = quaternion.x * quaternion.x;
  6721. var xy = quaternion.x * quaternion.y;
  6722. var xz = quaternion.x * quaternion.z;
  6723. var xw = quaternion.x * quaternion.w;
  6724. var y2 = quaternion.y * quaternion.y;
  6725. var yz = quaternion.y * quaternion.z;
  6726. var yw = quaternion.y * quaternion.w;
  6727. var z2 = quaternion.z * quaternion.z;
  6728. var zw = quaternion.z * quaternion.w;
  6729. var w2 = quaternion.w * quaternion.w;
  6730. var m00 = x2 - y2 - z2 + w2;
  6731. var m01 = 2.0 * (xy - zw);
  6732. var m02 = 2.0 * (xz + yw);
  6733. var m10 = 2.0 * (xy + zw);
  6734. var m11 = -x2 + y2 - z2 + w2;
  6735. var m12 = 2.0 * (yz - xw);
  6736. var m20 = 2.0 * (xz - yw);
  6737. var m21 = 2.0 * (yz + xw);
  6738. var m22 = -x2 - y2 + z2 + w2;
  6739. if (!defined(result)) {
  6740. return new Matrix3(m00, m01, m02,
  6741. m10, m11, m12,
  6742. m20, m21, m22);
  6743. }
  6744. result[0] = m00;
  6745. result[1] = m10;
  6746. result[2] = m20;
  6747. result[3] = m01;
  6748. result[4] = m11;
  6749. result[5] = m21;
  6750. result[6] = m02;
  6751. result[7] = m12;
  6752. result[8] = m22;
  6753. return result;
  6754. };
  6755. /**
  6756. * Computes a 3x3 rotation matrix from the provided headingPitchRoll. (see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles )
  6757. *
  6758. * @param {HeadingPitchRoll} headingPitchRoll the headingPitchRoll to use.
  6759. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
  6760. * @returns {Matrix3} The 3x3 rotation matrix from this headingPitchRoll.
  6761. */
  6762. Matrix3.fromHeadingPitchRoll = function(headingPitchRoll, result) {
  6763. if (!defined(headingPitchRoll)) {
  6764. throw new DeveloperError('headingPitchRoll is required');
  6765. }
  6766. var cosTheta = Math.cos(-headingPitchRoll.pitch);
  6767. var cosPsi = Math.cos(-headingPitchRoll.heading);
  6768. var cosPhi = Math.cos(headingPitchRoll.roll);
  6769. var sinTheta = Math.sin(-headingPitchRoll.pitch);
  6770. var sinPsi = Math.sin(-headingPitchRoll.heading);
  6771. var sinPhi = Math.sin(headingPitchRoll.roll);
  6772. var m00 = cosTheta * cosPsi;
  6773. var m01 = -cosPhi * sinPsi + sinPhi * sinTheta * cosPsi;
  6774. var m02 = sinPhi * sinPsi + cosPhi * sinTheta * cosPsi;
  6775. var m10 = cosTheta * sinPsi;
  6776. var m11 = cosPhi * cosPsi + sinPhi * sinTheta * sinPsi;
  6777. var m12 = -sinTheta * cosPhi + cosPhi * sinTheta * sinPsi;
  6778. var m20 = -sinTheta;
  6779. var m21 = sinPhi * cosTheta;
  6780. var m22 = cosPhi * cosTheta;
  6781. if (!defined(result)) {
  6782. return new Matrix3(m00, m01, m02,
  6783. m10, m11, m12,
  6784. m20, m21, m22);
  6785. }
  6786. result[0] = m00;
  6787. result[1] = m10;
  6788. result[2] = m20;
  6789. result[3] = m01;
  6790. result[4] = m11;
  6791. result[5] = m21;
  6792. result[6] = m02;
  6793. result[7] = m12;
  6794. result[8] = m22;
  6795. return result;
  6796. };
  6797. /**
  6798. * Computes a Matrix3 instance representing a non-uniform scale.
  6799. *
  6800. * @param {Cartesian3} scale The x, y, and z scale factors.
  6801. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
  6802. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
  6803. *
  6804. * @example
  6805. * // Creates
  6806. * // [7.0, 0.0, 0.0]
  6807. * // [0.0, 8.0, 0.0]
  6808. * // [0.0, 0.0, 9.0]
  6809. * var m = Cesium.Matrix3.fromScale(new Cesium.Cartesian3(7.0, 8.0, 9.0));
  6810. */
  6811. Matrix3.fromScale = function(scale, result) {
  6812. if (!defined(scale)) {
  6813. throw new DeveloperError('scale is required.');
  6814. }
  6815. if (!defined(result)) {
  6816. return new Matrix3(
  6817. scale.x, 0.0, 0.0,
  6818. 0.0, scale.y, 0.0,
  6819. 0.0, 0.0, scale.z);
  6820. }
  6821. result[0] = scale.x;
  6822. result[1] = 0.0;
  6823. result[2] = 0.0;
  6824. result[3] = 0.0;
  6825. result[4] = scale.y;
  6826. result[5] = 0.0;
  6827. result[6] = 0.0;
  6828. result[7] = 0.0;
  6829. result[8] = scale.z;
  6830. return result;
  6831. };
  6832. /**
  6833. * Computes a Matrix3 instance representing a uniform scale.
  6834. *
  6835. * @param {Number} scale The uniform scale factor.
  6836. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
  6837. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
  6838. *
  6839. * @example
  6840. * // Creates
  6841. * // [2.0, 0.0, 0.0]
  6842. * // [0.0, 2.0, 0.0]
  6843. * // [0.0, 0.0, 2.0]
  6844. * var m = Cesium.Matrix3.fromUniformScale(2.0);
  6845. */
  6846. Matrix3.fromUniformScale = function(scale, result) {
  6847. if (typeof scale !== 'number') {
  6848. throw new DeveloperError('scale is required.');
  6849. }
  6850. if (!defined(result)) {
  6851. return new Matrix3(
  6852. scale, 0.0, 0.0,
  6853. 0.0, scale, 0.0,
  6854. 0.0, 0.0, scale);
  6855. }
  6856. result[0] = scale;
  6857. result[1] = 0.0;
  6858. result[2] = 0.0;
  6859. result[3] = 0.0;
  6860. result[4] = scale;
  6861. result[5] = 0.0;
  6862. result[6] = 0.0;
  6863. result[7] = 0.0;
  6864. result[8] = scale;
  6865. return result;
  6866. };
  6867. /**
  6868. * Computes a Matrix3 instance representing the cross product equivalent matrix of a Cartesian3 vector.
  6869. *
  6870. * @param {Cartesian3} the vector on the left hand side of the cross product operation.
  6871. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
  6872. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
  6873. *
  6874. * @example
  6875. * // Creates
  6876. * // [0.0, -9.0, 8.0]
  6877. * // [9.0, 0.0, -7.0]
  6878. * // [-8.0, 7.0, 0.0]
  6879. * var m = Cesium.Matrix3.fromCrossProduct(new Cesium.Cartesian3(7.0, 8.0, 9.0));
  6880. */
  6881. Matrix3.fromCrossProduct = function(vector, result) {
  6882. if (!defined(vector)) {
  6883. throw new DeveloperError('vector is required.');
  6884. }
  6885. if (!defined(result)) {
  6886. return new Matrix3(
  6887. 0.0, -vector.z, vector.y,
  6888. vector.z, 0.0, -vector.x,
  6889. -vector.y, vector.x, 0.0);
  6890. }
  6891. result[0] = 0.0;
  6892. result[1] = vector.z;
  6893. result[2] = -vector.y;
  6894. result[3] = -vector.z;
  6895. result[4] = 0.0;
  6896. result[5] = vector.x;
  6897. result[6] = vector.y;
  6898. result[7] = -vector.x;
  6899. result[8] = 0.0;
  6900. return result;
  6901. };
  6902. /**
  6903. * Creates a rotation matrix around the x-axis.
  6904. *
  6905. * @param {Number} angle The angle, in radians, of the rotation. Positive angles are counterclockwise.
  6906. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
  6907. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
  6908. *
  6909. * @example
  6910. * // Rotate a point 45 degrees counterclockwise around the x-axis.
  6911. * var p = new Cesium.Cartesian3(5, 6, 7);
  6912. * var m = Cesium.Matrix3.fromRotationX(Cesium.Math.toRadians(45.0));
  6913. * var rotated = Cesium.Matrix3.multiplyByVector(m, p, new Cesium.Cartesian3());
  6914. */
  6915. Matrix3.fromRotationX = function(angle, result) {
  6916. if (!defined(angle)) {
  6917. throw new DeveloperError('angle is required.');
  6918. }
  6919. var cosAngle = Math.cos(angle);
  6920. var sinAngle = Math.sin(angle);
  6921. if (!defined(result)) {
  6922. return new Matrix3(
  6923. 1.0, 0.0, 0.0,
  6924. 0.0, cosAngle, -sinAngle,
  6925. 0.0, sinAngle, cosAngle);
  6926. }
  6927. result[0] = 1.0;
  6928. result[1] = 0.0;
  6929. result[2] = 0.0;
  6930. result[3] = 0.0;
  6931. result[4] = cosAngle;
  6932. result[5] = sinAngle;
  6933. result[6] = 0.0;
  6934. result[7] = -sinAngle;
  6935. result[8] = cosAngle;
  6936. return result;
  6937. };
  6938. /**
  6939. * Creates a rotation matrix around the y-axis.
  6940. *
  6941. * @param {Number} angle The angle, in radians, of the rotation. Positive angles are counterclockwise.
  6942. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
  6943. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
  6944. *
  6945. * @example
  6946. * // Rotate a point 45 degrees counterclockwise around the y-axis.
  6947. * var p = new Cesium.Cartesian3(5, 6, 7);
  6948. * var m = Cesium.Matrix3.fromRotationY(Cesium.Math.toRadians(45.0));
  6949. * var rotated = Cesium.Matrix3.multiplyByVector(m, p, new Cesium.Cartesian3());
  6950. */
  6951. Matrix3.fromRotationY = function(angle, result) {
  6952. if (!defined(angle)) {
  6953. throw new DeveloperError('angle is required.');
  6954. }
  6955. var cosAngle = Math.cos(angle);
  6956. var sinAngle = Math.sin(angle);
  6957. if (!defined(result)) {
  6958. return new Matrix3(
  6959. cosAngle, 0.0, sinAngle,
  6960. 0.0, 1.0, 0.0,
  6961. -sinAngle, 0.0, cosAngle);
  6962. }
  6963. result[0] = cosAngle;
  6964. result[1] = 0.0;
  6965. result[2] = -sinAngle;
  6966. result[3] = 0.0;
  6967. result[4] = 1.0;
  6968. result[5] = 0.0;
  6969. result[6] = sinAngle;
  6970. result[7] = 0.0;
  6971. result[8] = cosAngle;
  6972. return result;
  6973. };
  6974. /**
  6975. * Creates a rotation matrix around the z-axis.
  6976. *
  6977. * @param {Number} angle The angle, in radians, of the rotation. Positive angles are counterclockwise.
  6978. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
  6979. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
  6980. *
  6981. * @example
  6982. * // Rotate a point 45 degrees counterclockwise around the z-axis.
  6983. * var p = new Cesium.Cartesian3(5, 6, 7);
  6984. * var m = Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(45.0));
  6985. * var rotated = Cesium.Matrix3.multiplyByVector(m, p, new Cesium.Cartesian3());
  6986. */
  6987. Matrix3.fromRotationZ = function(angle, result) {
  6988. if (!defined(angle)) {
  6989. throw new DeveloperError('angle is required.');
  6990. }
  6991. var cosAngle = Math.cos(angle);
  6992. var sinAngle = Math.sin(angle);
  6993. if (!defined(result)) {
  6994. return new Matrix3(
  6995. cosAngle, -sinAngle, 0.0,
  6996. sinAngle, cosAngle, 0.0,
  6997. 0.0, 0.0, 1.0);
  6998. }
  6999. result[0] = cosAngle;
  7000. result[1] = sinAngle;
  7001. result[2] = 0.0;
  7002. result[3] = -sinAngle;
  7003. result[4] = cosAngle;
  7004. result[5] = 0.0;
  7005. result[6] = 0.0;
  7006. result[7] = 0.0;
  7007. result[8] = 1.0;
  7008. return result;
  7009. };
  7010. /**
  7011. * Creates an Array from the provided Matrix3 instance.
  7012. * The array will be in column-major order.
  7013. *
  7014. * @param {Matrix3} matrix The matrix to use..
  7015. * @param {Number[]} [result] The Array onto which to store the result.
  7016. * @returns {Number[]} The modified Array parameter or a new Array instance if one was not provided.
  7017. */
  7018. Matrix3.toArray = function(matrix, result) {
  7019. if (!defined(matrix)) {
  7020. throw new DeveloperError('matrix is required');
  7021. }
  7022. if (!defined(result)) {
  7023. return [matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6], matrix[7], matrix[8]];
  7024. }
  7025. result[0] = matrix[0];
  7026. result[1] = matrix[1];
  7027. result[2] = matrix[2];
  7028. result[3] = matrix[3];
  7029. result[4] = matrix[4];
  7030. result[5] = matrix[5];
  7031. result[6] = matrix[6];
  7032. result[7] = matrix[7];
  7033. result[8] = matrix[8];
  7034. return result;
  7035. };
  7036. /**
  7037. * Computes the array index of the element at the provided row and column.
  7038. *
  7039. * @param {Number} row The zero-based index of the row.
  7040. * @param {Number} column The zero-based index of the column.
  7041. * @returns {Number} The index of the element at the provided row and column.
  7042. *
  7043. * @exception {DeveloperError} row must be 0, 1, or 2.
  7044. * @exception {DeveloperError} column must be 0, 1, or 2.
  7045. *
  7046. * @example
  7047. * var myMatrix = new Cesium.Matrix3();
  7048. * var column1Row0Index = Cesium.Matrix3.getElementIndex(1, 0);
  7049. * var column1Row0 = myMatrix[column1Row0Index]
  7050. * myMatrix[column1Row0Index] = 10.0;
  7051. */
  7052. Matrix3.getElementIndex = function(column, row) {
  7053. if (typeof row !== 'number' || row < 0 || row > 2) {
  7054. throw new DeveloperError('row must be 0, 1, or 2.');
  7055. }
  7056. if (typeof column !== 'number' || column < 0 || column > 2) {
  7057. throw new DeveloperError('column must be 0, 1, or 2.');
  7058. }
  7059. return column * 3 + row;
  7060. };
  7061. /**
  7062. * Retrieves a copy of the matrix column at the provided index as a Cartesian3 instance.
  7063. *
  7064. * @param {Matrix3} matrix The matrix to use.
  7065. * @param {Number} index The zero-based index of the column to retrieve.
  7066. * @param {Cartesian3} result The object onto which to store the result.
  7067. * @returns {Cartesian3} The modified result parameter.
  7068. *
  7069. * @exception {DeveloperError} index must be 0, 1, or 2.
  7070. */
  7071. Matrix3.getColumn = function(matrix, index, result) {
  7072. if (!defined(matrix)) {
  7073. throw new DeveloperError('matrix is required.');
  7074. }
  7075. if (typeof index !== 'number' || index < 0 || index > 2) {
  7076. throw new DeveloperError('index must be 0, 1, or 2.');
  7077. }
  7078. if (!defined(result)) {
  7079. throw new DeveloperError('result is required');
  7080. }
  7081. var startIndex = index * 3;
  7082. var x = matrix[startIndex];
  7083. var y = matrix[startIndex + 1];
  7084. var z = matrix[startIndex + 2];
  7085. result.x = x;
  7086. result.y = y;
  7087. result.z = z;
  7088. return result;
  7089. };
  7090. /**
  7091. * Computes a new matrix that replaces the specified column in the provided matrix with the provided Cartesian3 instance.
  7092. *
  7093. * @param {Matrix3} matrix The matrix to use.
  7094. * @param {Number} index The zero-based index of the column to set.
  7095. * @param {Cartesian3} cartesian The Cartesian whose values will be assigned to the specified column.
  7096. * @param {Matrix3} result The object onto which to store the result.
  7097. * @returns {Matrix3} The modified result parameter.
  7098. *
  7099. * @exception {DeveloperError} index must be 0, 1, or 2.
  7100. */
  7101. Matrix3.setColumn = function(matrix, index, cartesian, result) {
  7102. if (!defined(matrix)) {
  7103. throw new DeveloperError('matrix is required');
  7104. }
  7105. if (!defined(cartesian)) {
  7106. throw new DeveloperError('cartesian is required');
  7107. }
  7108. if (typeof index !== 'number' || index < 0 || index > 2) {
  7109. throw new DeveloperError('index must be 0, 1, or 2.');
  7110. }
  7111. if (!defined(result)) {
  7112. throw new DeveloperError('result is required');
  7113. }
  7114. result = Matrix3.clone(matrix, result);
  7115. var startIndex = index * 3;
  7116. result[startIndex] = cartesian.x;
  7117. result[startIndex + 1] = cartesian.y;
  7118. result[startIndex + 2] = cartesian.z;
  7119. return result;
  7120. };
  7121. /**
  7122. * Retrieves a copy of the matrix row at the provided index as a Cartesian3 instance.
  7123. *
  7124. * @param {Matrix3} matrix The matrix to use.
  7125. * @param {Number} index The zero-based index of the row to retrieve.
  7126. * @param {Cartesian3} result The object onto which to store the result.
  7127. * @returns {Cartesian3} The modified result parameter.
  7128. *
  7129. * @exception {DeveloperError} index must be 0, 1, or 2.
  7130. */
  7131. Matrix3.getRow = function(matrix, index, result) {
  7132. if (!defined(matrix)) {
  7133. throw new DeveloperError('matrix is required.');
  7134. }
  7135. if (typeof index !== 'number' || index < 0 || index > 2) {
  7136. throw new DeveloperError('index must be 0, 1, or 2.');
  7137. }
  7138. if (!defined(result)) {
  7139. throw new DeveloperError('result is required');
  7140. }
  7141. var x = matrix[index];
  7142. var y = matrix[index + 3];
  7143. var z = matrix[index + 6];
  7144. result.x = x;
  7145. result.y = y;
  7146. result.z = z;
  7147. return result;
  7148. };
  7149. /**
  7150. * Computes a new matrix that replaces the specified row in the provided matrix with the provided Cartesian3 instance.
  7151. *
  7152. * @param {Matrix3} matrix The matrix to use.
  7153. * @param {Number} index The zero-based index of the row to set.
  7154. * @param {Cartesian3} cartesian The Cartesian whose values will be assigned to the specified row.
  7155. * @param {Matrix3} result The object onto which to store the result.
  7156. * @returns {Matrix3} The modified result parameter.
  7157. *
  7158. * @exception {DeveloperError} index must be 0, 1, or 2.
  7159. */
  7160. Matrix3.setRow = function(matrix, index, cartesian, result) {
  7161. if (!defined(matrix)) {
  7162. throw new DeveloperError('matrix is required');
  7163. }
  7164. if (!defined(cartesian)) {
  7165. throw new DeveloperError('cartesian is required');
  7166. }
  7167. if (typeof index !== 'number' || index < 0 || index > 2) {
  7168. throw new DeveloperError('index must be 0, 1, or 2.');
  7169. }
  7170. if (!defined(result)) {
  7171. throw new DeveloperError('result is required');
  7172. }
  7173. result = Matrix3.clone(matrix, result);
  7174. result[index] = cartesian.x;
  7175. result[index + 3] = cartesian.y;
  7176. result[index + 6] = cartesian.z;
  7177. return result;
  7178. };
  7179. var scratchColumn = new Cartesian3();
  7180. /**
  7181. * Extracts the non-uniform scale assuming the matrix is an affine transformation.
  7182. *
  7183. * @param {Matrix3} matrix The matrix.
  7184. * @param {Cartesian3} result The object onto which to store the result.
  7185. * @returns {Cartesian3} The modified result parameter.
  7186. */
  7187. Matrix3.getScale = function(matrix, result) {
  7188. if (!defined(matrix)) {
  7189. throw new DeveloperError('matrix is required.');
  7190. }
  7191. if (!defined(result)) {
  7192. throw new DeveloperError('result is required');
  7193. }
  7194. result.x = Cartesian3.magnitude(Cartesian3.fromElements(matrix[0], matrix[1], matrix[2], scratchColumn));
  7195. result.y = Cartesian3.magnitude(Cartesian3.fromElements(matrix[3], matrix[4], matrix[5], scratchColumn));
  7196. result.z = Cartesian3.magnitude(Cartesian3.fromElements(matrix[6], matrix[7], matrix[8], scratchColumn));
  7197. return result;
  7198. };
  7199. var scratchScale = new Cartesian3();
  7200. /**
  7201. * Computes the maximum scale assuming the matrix is an affine transformation.
  7202. * The maximum scale is the maximum length of the column vectors.
  7203. *
  7204. * @param {Matrix3} matrix The matrix.
  7205. * @returns {Number} The maximum scale.
  7206. */
  7207. Matrix3.getMaximumScale = function(matrix) {
  7208. Matrix3.getScale(matrix, scratchScale);
  7209. return Cartesian3.maximumComponent(scratchScale);
  7210. };
  7211. /**
  7212. * Computes the product of two matrices.
  7213. *
  7214. * @param {Matrix3} left The first matrix.
  7215. * @param {Matrix3} right The second matrix.
  7216. * @param {Matrix3} result The object onto which to store the result.
  7217. * @returns {Matrix3} The modified result parameter.
  7218. */
  7219. Matrix3.multiply = function(left, right, result) {
  7220. if (!defined(left)) {
  7221. throw new DeveloperError('left is required');
  7222. }
  7223. if (!defined(right)) {
  7224. throw new DeveloperError('right is required');
  7225. }
  7226. if (!defined(result)) {
  7227. throw new DeveloperError('result is required');
  7228. }
  7229. var column0Row0 = left[0] * right[0] + left[3] * right[1] + left[6] * right[2];
  7230. var column0Row1 = left[1] * right[0] + left[4] * right[1] + left[7] * right[2];
  7231. var column0Row2 = left[2] * right[0] + left[5] * right[1] + left[8] * right[2];
  7232. var column1Row0 = left[0] * right[3] + left[3] * right[4] + left[6] * right[5];
  7233. var column1Row1 = left[1] * right[3] + left[4] * right[4] + left[7] * right[5];
  7234. var column1Row2 = left[2] * right[3] + left[5] * right[4] + left[8] * right[5];
  7235. var column2Row0 = left[0] * right[6] + left[3] * right[7] + left[6] * right[8];
  7236. var column2Row1 = left[1] * right[6] + left[4] * right[7] + left[7] * right[8];
  7237. var column2Row2 = left[2] * right[6] + left[5] * right[7] + left[8] * right[8];
  7238. result[0] = column0Row0;
  7239. result[1] = column0Row1;
  7240. result[2] = column0Row2;
  7241. result[3] = column1Row0;
  7242. result[4] = column1Row1;
  7243. result[5] = column1Row2;
  7244. result[6] = column2Row0;
  7245. result[7] = column2Row1;
  7246. result[8] = column2Row2;
  7247. return result;
  7248. };
  7249. /**
  7250. * Computes the sum of two matrices.
  7251. *
  7252. * @param {Matrix3} left The first matrix.
  7253. * @param {Matrix3} right The second matrix.
  7254. * @param {Matrix3} result The object onto which to store the result.
  7255. * @returns {Matrix3} The modified result parameter.
  7256. */
  7257. Matrix3.add = function(left, right, result) {
  7258. if (!defined(left)) {
  7259. throw new DeveloperError('left is required');
  7260. }
  7261. if (!defined(right)) {
  7262. throw new DeveloperError('right is required');
  7263. }
  7264. if (!defined(result)) {
  7265. throw new DeveloperError('result is required');
  7266. }
  7267. result[0] = left[0] + right[0];
  7268. result[1] = left[1] + right[1];
  7269. result[2] = left[2] + right[2];
  7270. result[3] = left[3] + right[3];
  7271. result[4] = left[4] + right[4];
  7272. result[5] = left[5] + right[5];
  7273. result[6] = left[6] + right[6];
  7274. result[7] = left[7] + right[7];
  7275. result[8] = left[8] + right[8];
  7276. return result;
  7277. };
  7278. /**
  7279. * Computes the difference of two matrices.
  7280. *
  7281. * @param {Matrix3} left The first matrix.
  7282. * @param {Matrix3} right The second matrix.
  7283. * @param {Matrix3} result The object onto which to store the result.
  7284. * @returns {Matrix3} The modified result parameter.
  7285. */
  7286. Matrix3.subtract = function(left, right, result) {
  7287. if (!defined(left)) {
  7288. throw new DeveloperError('left is required');
  7289. }
  7290. if (!defined(right)) {
  7291. throw new DeveloperError('right is required');
  7292. }
  7293. if (!defined(result)) {
  7294. throw new DeveloperError('result is required');
  7295. }
  7296. result[0] = left[0] - right[0];
  7297. result[1] = left[1] - right[1];
  7298. result[2] = left[2] - right[2];
  7299. result[3] = left[3] - right[3];
  7300. result[4] = left[4] - right[4];
  7301. result[5] = left[5] - right[5];
  7302. result[6] = left[6] - right[6];
  7303. result[7] = left[7] - right[7];
  7304. result[8] = left[8] - right[8];
  7305. return result;
  7306. };
  7307. /**
  7308. * Computes the product of a matrix and a column vector.
  7309. *
  7310. * @param {Matrix3} matrix The matrix.
  7311. * @param {Cartesian3} cartesian The column.
  7312. * @param {Cartesian3} result The object onto which to store the result.
  7313. * @returns {Cartesian3} The modified result parameter.
  7314. */
  7315. Matrix3.multiplyByVector = function(matrix, cartesian, result) {
  7316. if (!defined(matrix)) {
  7317. throw new DeveloperError('matrix is required');
  7318. }
  7319. if (!defined(cartesian)) {
  7320. throw new DeveloperError('cartesian is required');
  7321. }
  7322. if (!defined(result)) {
  7323. throw new DeveloperError('result is required');
  7324. }
  7325. var vX = cartesian.x;
  7326. var vY = cartesian.y;
  7327. var vZ = cartesian.z;
  7328. var x = matrix[0] * vX + matrix[3] * vY + matrix[6] * vZ;
  7329. var y = matrix[1] * vX + matrix[4] * vY + matrix[7] * vZ;
  7330. var z = matrix[2] * vX + matrix[5] * vY + matrix[8] * vZ;
  7331. result.x = x;
  7332. result.y = y;
  7333. result.z = z;
  7334. return result;
  7335. };
  7336. /**
  7337. * Computes the product of a matrix and a scalar.
  7338. *
  7339. * @param {Matrix3} matrix The matrix.
  7340. * @param {Number} scalar The number to multiply by.
  7341. * @param {Matrix3} result The object onto which to store the result.
  7342. * @returns {Matrix3} The modified result parameter.
  7343. */
  7344. Matrix3.multiplyByScalar = function(matrix, scalar, result) {
  7345. if (!defined(matrix)) {
  7346. throw new DeveloperError('matrix is required');
  7347. }
  7348. if (typeof scalar !== 'number') {
  7349. throw new DeveloperError('scalar must be a number');
  7350. }
  7351. if (!defined(result)) {
  7352. throw new DeveloperError('result is required');
  7353. }
  7354. result[0] = matrix[0] * scalar;
  7355. result[1] = matrix[1] * scalar;
  7356. result[2] = matrix[2] * scalar;
  7357. result[3] = matrix[3] * scalar;
  7358. result[4] = matrix[4] * scalar;
  7359. result[5] = matrix[5] * scalar;
  7360. result[6] = matrix[6] * scalar;
  7361. result[7] = matrix[7] * scalar;
  7362. result[8] = matrix[8] * scalar;
  7363. return result;
  7364. };
  7365. /**
  7366. * Computes the product of a matrix times a (non-uniform) scale, as if the scale were a scale matrix.
  7367. *
  7368. * @param {Matrix3} matrix The matrix on the left-hand side.
  7369. * @param {Cartesian3} scale The non-uniform scale on the right-hand side.
  7370. * @param {Matrix3} result The object onto which to store the result.
  7371. * @returns {Matrix3} The modified result parameter.
  7372. *
  7373. *
  7374. * @example
  7375. * // Instead of Cesium.Matrix3.multiply(m, Cesium.Matrix3.fromScale(scale), m);
  7376. * Cesium.Matrix3.multiplyByScale(m, scale, m);
  7377. *
  7378. * @see Matrix3.fromScale
  7379. * @see Matrix3.multiplyByUniformScale
  7380. */
  7381. Matrix3.multiplyByScale = function(matrix, scale, result) {
  7382. if (!defined(matrix)) {
  7383. throw new DeveloperError('matrix is required');
  7384. }
  7385. if (!defined(scale)) {
  7386. throw new DeveloperError('scale is required');
  7387. }
  7388. if (!defined(result)) {
  7389. throw new DeveloperError('result is required');
  7390. }
  7391. result[0] = matrix[0] * scale.x;
  7392. result[1] = matrix[1] * scale.x;
  7393. result[2] = matrix[2] * scale.x;
  7394. result[3] = matrix[3] * scale.y;
  7395. result[4] = matrix[4] * scale.y;
  7396. result[5] = matrix[5] * scale.y;
  7397. result[6] = matrix[6] * scale.z;
  7398. result[7] = matrix[7] * scale.z;
  7399. result[8] = matrix[8] * scale.z;
  7400. return result;
  7401. };
  7402. /**
  7403. * Creates a negated copy of the provided matrix.
  7404. *
  7405. * @param {Matrix3} matrix The matrix to negate.
  7406. * @param {Matrix3} result The object onto which to store the result.
  7407. * @returns {Matrix3} The modified result parameter.
  7408. */
  7409. Matrix3.negate = function(matrix, result) {
  7410. if (!defined(matrix)) {
  7411. throw new DeveloperError('matrix is required');
  7412. }
  7413. if (!defined(result)) {
  7414. throw new DeveloperError('result is required');
  7415. }
  7416. result[0] = -matrix[0];
  7417. result[1] = -matrix[1];
  7418. result[2] = -matrix[2];
  7419. result[3] = -matrix[3];
  7420. result[4] = -matrix[4];
  7421. result[5] = -matrix[5];
  7422. result[6] = -matrix[6];
  7423. result[7] = -matrix[7];
  7424. result[8] = -matrix[8];
  7425. return result;
  7426. };
  7427. /**
  7428. * Computes the transpose of the provided matrix.
  7429. *
  7430. * @param {Matrix3} matrix The matrix to transpose.
  7431. * @param {Matrix3} result The object onto which to store the result.
  7432. * @returns {Matrix3} The modified result parameter.
  7433. */
  7434. Matrix3.transpose = function(matrix, result) {
  7435. if (!defined(matrix)) {
  7436. throw new DeveloperError('matrix is required');
  7437. }
  7438. if (!defined(result)) {
  7439. throw new DeveloperError('result is required');
  7440. }
  7441. var column0Row0 = matrix[0];
  7442. var column0Row1 = matrix[3];
  7443. var column0Row2 = matrix[6];
  7444. var column1Row0 = matrix[1];
  7445. var column1Row1 = matrix[4];
  7446. var column1Row2 = matrix[7];
  7447. var column2Row0 = matrix[2];
  7448. var column2Row1 = matrix[5];
  7449. var column2Row2 = matrix[8];
  7450. result[0] = column0Row0;
  7451. result[1] = column0Row1;
  7452. result[2] = column0Row2;
  7453. result[3] = column1Row0;
  7454. result[4] = column1Row1;
  7455. result[5] = column1Row2;
  7456. result[6] = column2Row0;
  7457. result[7] = column2Row1;
  7458. result[8] = column2Row2;
  7459. return result;
  7460. };
  7461. function computeFrobeniusNorm(matrix) {
  7462. var norm = 0.0;
  7463. for (var i = 0; i < 9; ++i) {
  7464. var temp = matrix[i];
  7465. norm += temp * temp;
  7466. }
  7467. return Math.sqrt(norm);
  7468. }
  7469. var rowVal = [1, 0, 0];
  7470. var colVal = [2, 2, 1];
  7471. function offDiagonalFrobeniusNorm(matrix) {
  7472. // Computes the "off-diagonal" Frobenius norm.
  7473. // Assumes matrix is symmetric.
  7474. var norm = 0.0;
  7475. for (var i = 0; i < 3; ++i) {
  7476. var temp = matrix[Matrix3.getElementIndex(colVal[i], rowVal[i])];
  7477. norm += 2.0 * temp * temp;
  7478. }
  7479. return Math.sqrt(norm);
  7480. }
  7481. function shurDecomposition(matrix, result) {
  7482. // This routine was created based upon Matrix Computations, 3rd ed., by Golub and Van Loan,
  7483. // section 8.4.2 The 2by2 Symmetric Schur Decomposition.
  7484. //
  7485. // The routine takes a matrix, which is assumed to be symmetric, and
  7486. // finds the largest off-diagonal term, and then creates
  7487. // a matrix (result) which can be used to help reduce it
  7488. var tolerance = CesiumMath.EPSILON15;
  7489. var maxDiagonal = 0.0;
  7490. var rotAxis = 1;
  7491. // find pivot (rotAxis) based on max diagonal of matrix
  7492. for (var i = 0; i < 3; ++i) {
  7493. var temp = Math.abs(matrix[Matrix3.getElementIndex(colVal[i], rowVal[i])]);
  7494. if (temp > maxDiagonal) {
  7495. rotAxis = i;
  7496. maxDiagonal = temp;
  7497. }
  7498. }
  7499. var c = 1.0;
  7500. var s = 0.0;
  7501. var p = rowVal[rotAxis];
  7502. var q = colVal[rotAxis];
  7503. if (Math.abs(matrix[Matrix3.getElementIndex(q, p)]) > tolerance) {
  7504. var qq = matrix[Matrix3.getElementIndex(q, q)];
  7505. var pp = matrix[Matrix3.getElementIndex(p, p)];
  7506. var qp = matrix[Matrix3.getElementIndex(q, p)];
  7507. var tau = (qq - pp) / 2.0 / qp;
  7508. var t;
  7509. if (tau < 0.0) {
  7510. t = -1.0 / (-tau + Math.sqrt(1.0 + tau * tau));
  7511. } else {
  7512. t = 1.0 / (tau + Math.sqrt(1.0 + tau * tau));
  7513. }
  7514. c = 1.0 / Math.sqrt(1.0 + t * t);
  7515. s = t * c;
  7516. }
  7517. result = Matrix3.clone(Matrix3.IDENTITY, result);
  7518. result[Matrix3.getElementIndex(p, p)] = result[Matrix3.getElementIndex(q, q)] = c;
  7519. result[Matrix3.getElementIndex(q, p)] = s;
  7520. result[Matrix3.getElementIndex(p, q)] = -s;
  7521. return result;
  7522. }
  7523. var jMatrix = new Matrix3();
  7524. var jMatrixTranspose = new Matrix3();
  7525. /**
  7526. * Computes the eigenvectors and eigenvalues of a symmetric matrix.
  7527. * <p>
  7528. * Returns a diagonal matrix and unitary matrix such that:
  7529. * <code>matrix = unitary matrix * diagonal matrix * transpose(unitary matrix)</code>
  7530. * </p>
  7531. * <p>
  7532. * The values along the diagonal of the diagonal matrix are the eigenvalues. The columns
  7533. * of the unitary matrix are the corresponding eigenvectors.
  7534. * </p>
  7535. *
  7536. * @param {Matrix3} matrix The matrix to decompose into diagonal and unitary matrix. Expected to be symmetric.
  7537. * @param {Object} [result] An object with unitary and diagonal properties which are matrices onto which to store the result.
  7538. * @returns {Object} An object with unitary and diagonal properties which are the unitary and diagonal matrices, respectively.
  7539. *
  7540. * @example
  7541. * var a = //... symetric matrix
  7542. * var result = {
  7543. * unitary : new Cesium.Matrix3(),
  7544. * diagonal : new Cesium.Matrix3()
  7545. * };
  7546. * Cesium.Matrix3.computeEigenDecomposition(a, result);
  7547. *
  7548. * var unitaryTranspose = Cesium.Matrix3.transpose(result.unitary, new Cesium.Matrix3());
  7549. * var b = Cesium.Matrix3.multiply(result.unitary, result.diagonal, new Cesium.Matrix3());
  7550. * Cesium.Matrix3.multiply(b, unitaryTranspose, b); // b is now equal to a
  7551. *
  7552. * var lambda = Cesium.Matrix3.getColumn(result.diagonal, 0, new Cesium.Cartesian3()).x; // first eigenvalue
  7553. * var v = Cesium.Matrix3.getColumn(result.unitary, 0, new Cesium.Cartesian3()); // first eigenvector
  7554. * var c = Cesium.Cartesian3.multiplyByScalar(v, lambda, new Cesium.Cartesian3()); // equal to Cesium.Matrix3.multiplyByVector(a, v)
  7555. */
  7556. Matrix3.computeEigenDecomposition = function(matrix, result) {
  7557. if (!defined(matrix)) {
  7558. throw new DeveloperError('matrix is required.');
  7559. }
  7560. // This routine was created based upon Matrix Computations, 3rd ed., by Golub and Van Loan,
  7561. // section 8.4.3 The Classical Jacobi Algorithm
  7562. var tolerance = CesiumMath.EPSILON20;
  7563. var maxSweeps = 10;
  7564. var count = 0;
  7565. var sweep = 0;
  7566. if (!defined(result)) {
  7567. result = {};
  7568. }
  7569. var unitaryMatrix = result.unitary = Matrix3.clone(Matrix3.IDENTITY, result.unitary);
  7570. var diagMatrix = result.diagonal = Matrix3.clone(matrix, result.diagonal);
  7571. var epsilon = tolerance * computeFrobeniusNorm(diagMatrix);
  7572. while (sweep < maxSweeps && offDiagonalFrobeniusNorm(diagMatrix) > epsilon) {
  7573. shurDecomposition(diagMatrix, jMatrix);
  7574. Matrix3.transpose(jMatrix, jMatrixTranspose);
  7575. Matrix3.multiply(diagMatrix, jMatrix, diagMatrix);
  7576. Matrix3.multiply(jMatrixTranspose, diagMatrix, diagMatrix);
  7577. Matrix3.multiply(unitaryMatrix, jMatrix, unitaryMatrix);
  7578. if (++count > 2) {
  7579. ++sweep;
  7580. count = 0;
  7581. }
  7582. }
  7583. return result;
  7584. };
  7585. /**
  7586. * Computes a matrix, which contains the absolute (unsigned) values of the provided matrix's elements.
  7587. *
  7588. * @param {Matrix3} matrix The matrix with signed elements.
  7589. * @param {Matrix3} result The object onto which to store the result.
  7590. * @returns {Matrix3} The modified result parameter.
  7591. */
  7592. Matrix3.abs = function(matrix, result) {
  7593. if (!defined(matrix)) {
  7594. throw new DeveloperError('matrix is required');
  7595. }
  7596. if (!defined(result)) {
  7597. throw new DeveloperError('result is required');
  7598. }
  7599. result[0] = Math.abs(matrix[0]);
  7600. result[1] = Math.abs(matrix[1]);
  7601. result[2] = Math.abs(matrix[2]);
  7602. result[3] = Math.abs(matrix[3]);
  7603. result[4] = Math.abs(matrix[4]);
  7604. result[5] = Math.abs(matrix[5]);
  7605. result[6] = Math.abs(matrix[6]);
  7606. result[7] = Math.abs(matrix[7]);
  7607. result[8] = Math.abs(matrix[8]);
  7608. return result;
  7609. };
  7610. /**
  7611. * Computes the determinant of the provided matrix.
  7612. *
  7613. * @param {Matrix3} matrix The matrix to use.
  7614. * @returns {Number} The value of the determinant of the matrix.
  7615. */
  7616. Matrix3.determinant = function(matrix) {
  7617. if (!defined(matrix)) {
  7618. throw new DeveloperError('matrix is required');
  7619. }
  7620. var m11 = matrix[0];
  7621. var m21 = matrix[3];
  7622. var m31 = matrix[6];
  7623. var m12 = matrix[1];
  7624. var m22 = matrix[4];
  7625. var m32 = matrix[7];
  7626. var m13 = matrix[2];
  7627. var m23 = matrix[5];
  7628. var m33 = matrix[8];
  7629. return m11 * (m22 * m33 - m23 * m32) + m12 * (m23 * m31 - m21 * m33) + m13 * (m21 * m32 - m22 * m31);
  7630. };
  7631. /**
  7632. * Computes the inverse of the provided matrix.
  7633. *
  7634. * @param {Matrix3} matrix The matrix to invert.
  7635. * @param {Matrix3} result The object onto which to store the result.
  7636. * @returns {Matrix3} The modified result parameter.
  7637. *
  7638. * @exception {DeveloperError} matrix is not invertible.
  7639. */
  7640. Matrix3.inverse = function(matrix, result) {
  7641. if (!defined(matrix)) {
  7642. throw new DeveloperError('matrix is required');
  7643. }
  7644. if (!defined(result)) {
  7645. throw new DeveloperError('result is required');
  7646. }
  7647. var m11 = matrix[0];
  7648. var m21 = matrix[1];
  7649. var m31 = matrix[2];
  7650. var m12 = matrix[3];
  7651. var m22 = matrix[4];
  7652. var m32 = matrix[5];
  7653. var m13 = matrix[6];
  7654. var m23 = matrix[7];
  7655. var m33 = matrix[8];
  7656. var determinant = Matrix3.determinant(matrix);
  7657. if (Math.abs(determinant) <= CesiumMath.EPSILON15) {
  7658. throw new DeveloperError('matrix is not invertible');
  7659. }
  7660. result[0] = m22 * m33 - m23 * m32;
  7661. result[1] = m23 * m31 - m21 * m33;
  7662. result[2] = m21 * m32 - m22 * m31;
  7663. result[3] = m13 * m32 - m12 * m33;
  7664. result[4] = m11 * m33 - m13 * m31;
  7665. result[5] = m12 * m31 - m11 * m32;
  7666. result[6] = m12 * m23 - m13 * m22;
  7667. result[7] = m13 * m21 - m11 * m23;
  7668. result[8] = m11 * m22 - m12 * m21;
  7669. var scale = 1.0 / determinant;
  7670. return Matrix3.multiplyByScalar(result, scale, result);
  7671. };
  7672. /**
  7673. * Compares the provided matrices componentwise and returns
  7674. * <code>true</code> if they are equal, <code>false</code> otherwise.
  7675. *
  7676. * @param {Matrix3} [left] The first matrix.
  7677. * @param {Matrix3} [right] The second matrix.
  7678. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  7679. */
  7680. Matrix3.equals = function(left, right) {
  7681. return (left === right) ||
  7682. (defined(left) &&
  7683. defined(right) &&
  7684. left[0] === right[0] &&
  7685. left[1] === right[1] &&
  7686. left[2] === right[2] &&
  7687. left[3] === right[3] &&
  7688. left[4] === right[4] &&
  7689. left[5] === right[5] &&
  7690. left[6] === right[6] &&
  7691. left[7] === right[7] &&
  7692. left[8] === right[8]);
  7693. };
  7694. /**
  7695. * Compares the provided matrices componentwise and returns
  7696. * <code>true</code> if they are within the provided epsilon,
  7697. * <code>false</code> otherwise.
  7698. *
  7699. * @param {Matrix3} [left] The first matrix.
  7700. * @param {Matrix3} [right] The second matrix.
  7701. * @param {Number} epsilon The epsilon to use for equality testing.
  7702. * @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
  7703. */
  7704. Matrix3.equalsEpsilon = function(left, right, epsilon) {
  7705. if (typeof epsilon !== 'number') {
  7706. throw new DeveloperError('epsilon must be a number');
  7707. }
  7708. return (left === right) ||
  7709. (defined(left) &&
  7710. defined(right) &&
  7711. Math.abs(left[0] - right[0]) <= epsilon &&
  7712. Math.abs(left[1] - right[1]) <= epsilon &&
  7713. Math.abs(left[2] - right[2]) <= epsilon &&
  7714. Math.abs(left[3] - right[3]) <= epsilon &&
  7715. Math.abs(left[4] - right[4]) <= epsilon &&
  7716. Math.abs(left[5] - right[5]) <= epsilon &&
  7717. Math.abs(left[6] - right[6]) <= epsilon &&
  7718. Math.abs(left[7] - right[7]) <= epsilon &&
  7719. Math.abs(left[8] - right[8]) <= epsilon);
  7720. };
  7721. /**
  7722. * An immutable Matrix3 instance initialized to the identity matrix.
  7723. *
  7724. * @type {Matrix3}
  7725. * @constant
  7726. */
  7727. Matrix3.IDENTITY = freezeObject(new Matrix3(1.0, 0.0, 0.0,
  7728. 0.0, 1.0, 0.0,
  7729. 0.0, 0.0, 1.0));
  7730. /**
  7731. * An immutable Matrix3 instance initialized to the zero matrix.
  7732. *
  7733. * @type {Matrix3}
  7734. * @constant
  7735. */
  7736. Matrix3.ZERO = freezeObject(new Matrix3(0.0, 0.0, 0.0,
  7737. 0.0, 0.0, 0.0,
  7738. 0.0, 0.0, 0.0));
  7739. /**
  7740. * The index into Matrix3 for column 0, row 0.
  7741. *
  7742. * @type {Number}
  7743. * @constant
  7744. */
  7745. Matrix3.COLUMN0ROW0 = 0;
  7746. /**
  7747. * The index into Matrix3 for column 0, row 1.
  7748. *
  7749. * @type {Number}
  7750. * @constant
  7751. */
  7752. Matrix3.COLUMN0ROW1 = 1;
  7753. /**
  7754. * The index into Matrix3 for column 0, row 2.
  7755. *
  7756. * @type {Number}
  7757. * @constant
  7758. */
  7759. Matrix3.COLUMN0ROW2 = 2;
  7760. /**
  7761. * The index into Matrix3 for column 1, row 0.
  7762. *
  7763. * @type {Number}
  7764. * @constant
  7765. */
  7766. Matrix3.COLUMN1ROW0 = 3;
  7767. /**
  7768. * The index into Matrix3 for column 1, row 1.
  7769. *
  7770. * @type {Number}
  7771. * @constant
  7772. */
  7773. Matrix3.COLUMN1ROW1 = 4;
  7774. /**
  7775. * The index into Matrix3 for column 1, row 2.
  7776. *
  7777. * @type {Number}
  7778. * @constant
  7779. */
  7780. Matrix3.COLUMN1ROW2 = 5;
  7781. /**
  7782. * The index into Matrix3 for column 2, row 0.
  7783. *
  7784. * @type {Number}
  7785. * @constant
  7786. */
  7787. Matrix3.COLUMN2ROW0 = 6;
  7788. /**
  7789. * The index into Matrix3 for column 2, row 1.
  7790. *
  7791. * @type {Number}
  7792. * @constant
  7793. */
  7794. Matrix3.COLUMN2ROW1 = 7;
  7795. /**
  7796. * The index into Matrix3 for column 2, row 2.
  7797. *
  7798. * @type {Number}
  7799. * @constant
  7800. */
  7801. Matrix3.COLUMN2ROW2 = 8;
  7802. defineProperties(Matrix3.prototype, {
  7803. /**
  7804. * Gets the number of items in the collection.
  7805. * @memberof Matrix3.prototype
  7806. *
  7807. * @type {Number}
  7808. */
  7809. length : {
  7810. get : function() {
  7811. return Matrix3.packedLength;
  7812. }
  7813. }
  7814. });
  7815. /**
  7816. * Duplicates the provided Matrix3 instance.
  7817. *
  7818. * @param {Matrix3} [result] The object onto which to store the result.
  7819. * @returns {Matrix3} The modified result parameter or a new Matrix3 instance if one was not provided.
  7820. */
  7821. Matrix3.prototype.clone = function(result) {
  7822. return Matrix3.clone(this, result);
  7823. };
  7824. /**
  7825. * Compares this matrix to the provided matrix componentwise and returns
  7826. * <code>true</code> if they are equal, <code>false</code> otherwise.
  7827. *
  7828. * @param {Matrix3} [right] The right hand side matrix.
  7829. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  7830. */
  7831. Matrix3.prototype.equals = function(right) {
  7832. return Matrix3.equals(this, right);
  7833. };
  7834. /**
  7835. * @private
  7836. */
  7837. Matrix3.equalsArray = function(matrix, array, offset) {
  7838. return matrix[0] === array[offset] &&
  7839. matrix[1] === array[offset + 1] &&
  7840. matrix[2] === array[offset + 2] &&
  7841. matrix[3] === array[offset + 3] &&
  7842. matrix[4] === array[offset + 4] &&
  7843. matrix[5] === array[offset + 5] &&
  7844. matrix[6] === array[offset + 6] &&
  7845. matrix[7] === array[offset + 7] &&
  7846. matrix[8] === array[offset + 8];
  7847. };
  7848. /**
  7849. * Compares this matrix to the provided matrix componentwise and returns
  7850. * <code>true</code> if they are within the provided epsilon,
  7851. * <code>false</code> otherwise.
  7852. *
  7853. * @param {Matrix3} [right] The right hand side matrix.
  7854. * @param {Number} epsilon The epsilon to use for equality testing.
  7855. * @returns {Boolean} <code>true</code> if they are within the provided epsilon, <code>false</code> otherwise.
  7856. */
  7857. Matrix3.prototype.equalsEpsilon = function(right, epsilon) {
  7858. return Matrix3.equalsEpsilon(this, right, epsilon);
  7859. };
  7860. /**
  7861. * Creates a string representing this Matrix with each row being
  7862. * on a separate line and in the format '(column0, column1, column2)'.
  7863. *
  7864. * @returns {String} A string representing the provided Matrix with each row being on a separate line and in the format '(column0, column1, column2)'.
  7865. */
  7866. Matrix3.prototype.toString = function() {
  7867. return '(' + this[0] + ', ' + this[3] + ', ' + this[6] + ')\n' +
  7868. '(' + this[1] + ', ' + this[4] + ', ' + this[7] + ')\n' +
  7869. '(' + this[2] + ', ' + this[5] + ', ' + this[8] + ')';
  7870. };
  7871. return Matrix3;
  7872. });
  7873. /*global define*/
  7874. define('Core/Cartesian4',[
  7875. './defaultValue',
  7876. './defined',
  7877. './DeveloperError',
  7878. './freezeObject',
  7879. './Math'
  7880. ], function(
  7881. defaultValue,
  7882. defined,
  7883. DeveloperError,
  7884. freezeObject,
  7885. CesiumMath) {
  7886. 'use strict';
  7887. /**
  7888. * A 4D Cartesian point.
  7889. * @alias Cartesian4
  7890. * @constructor
  7891. *
  7892. * @param {Number} [x=0.0] The X component.
  7893. * @param {Number} [y=0.0] The Y component.
  7894. * @param {Number} [z=0.0] The Z component.
  7895. * @param {Number} [w=0.0] The W component.
  7896. *
  7897. * @see Cartesian2
  7898. * @see Cartesian3
  7899. * @see Packable
  7900. */
  7901. function Cartesian4(x, y, z, w) {
  7902. /**
  7903. * The X component.
  7904. * @type {Number}
  7905. * @default 0.0
  7906. */
  7907. this.x = defaultValue(x, 0.0);
  7908. /**
  7909. * The Y component.
  7910. * @type {Number}
  7911. * @default 0.0
  7912. */
  7913. this.y = defaultValue(y, 0.0);
  7914. /**
  7915. * The Z component.
  7916. * @type {Number}
  7917. * @default 0.0
  7918. */
  7919. this.z = defaultValue(z, 0.0);
  7920. /**
  7921. * The W component.
  7922. * @type {Number}
  7923. * @default 0.0
  7924. */
  7925. this.w = defaultValue(w, 0.0);
  7926. }
  7927. /**
  7928. * Creates a Cartesian4 instance from x, y, z and w coordinates.
  7929. *
  7930. * @param {Number} x The x coordinate.
  7931. * @param {Number} y The y coordinate.
  7932. * @param {Number} z The z coordinate.
  7933. * @param {Number} w The w coordinate.
  7934. * @param {Cartesian4} [result] The object onto which to store the result.
  7935. * @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
  7936. */
  7937. Cartesian4.fromElements = function(x, y, z, w, result) {
  7938. if (!defined(result)) {
  7939. return new Cartesian4(x, y, z, w);
  7940. }
  7941. result.x = x;
  7942. result.y = y;
  7943. result.z = z;
  7944. result.w = w;
  7945. return result;
  7946. };
  7947. /**
  7948. * Creates a Cartesian4 instance from a {@link Color}. <code>red</code>, <code>green</code>, <code>blue</code>,
  7949. * and <code>alpha</code> map to <code>x</code>, <code>y</code>, <code>z</code>, and <code>w</code>, respectively.
  7950. *
  7951. * @param {Color} color The source color.
  7952. * @param {Cartesian4} [result] The object onto which to store the result.
  7953. * @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
  7954. */
  7955. Cartesian4.fromColor = function(color, result) {
  7956. if (!defined(color)) {
  7957. throw new DeveloperError('color is required');
  7958. }
  7959. if (!defined(result)) {
  7960. return new Cartesian4(color.red, color.green, color.blue, color.alpha);
  7961. }
  7962. result.x = color.red;
  7963. result.y = color.green;
  7964. result.z = color.blue;
  7965. result.w = color.alpha;
  7966. return result;
  7967. };
  7968. /**
  7969. * Duplicates a Cartesian4 instance.
  7970. *
  7971. * @param {Cartesian4} cartesian The Cartesian to duplicate.
  7972. * @param {Cartesian4} [result] The object onto which to store the result.
  7973. * @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided. (Returns undefined if cartesian is undefined)
  7974. */
  7975. Cartesian4.clone = function(cartesian, result) {
  7976. if (!defined(cartesian)) {
  7977. return undefined;
  7978. }
  7979. if (!defined(result)) {
  7980. return new Cartesian4(cartesian.x, cartesian.y, cartesian.z, cartesian.w);
  7981. }
  7982. result.x = cartesian.x;
  7983. result.y = cartesian.y;
  7984. result.z = cartesian.z;
  7985. result.w = cartesian.w;
  7986. return result;
  7987. };
  7988. /**
  7989. * The number of elements used to pack the object into an array.
  7990. * @type {Number}
  7991. */
  7992. Cartesian4.packedLength = 4;
  7993. /**
  7994. * Stores the provided instance into the provided array.
  7995. *
  7996. * @param {Cartesian4} value The value to pack.
  7997. * @param {Number[]} array The array to pack into.
  7998. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  7999. *
  8000. * @returns {Number[]} The array that was packed into
  8001. */
  8002. Cartesian4.pack = function(value, array, startingIndex) {
  8003. if (!defined(value)) {
  8004. throw new DeveloperError('value is required');
  8005. }
  8006. if (!defined(array)) {
  8007. throw new DeveloperError('array is required');
  8008. }
  8009. startingIndex = defaultValue(startingIndex, 0);
  8010. array[startingIndex++] = value.x;
  8011. array[startingIndex++] = value.y;
  8012. array[startingIndex++] = value.z;
  8013. array[startingIndex] = value.w;
  8014. return array;
  8015. };
  8016. /**
  8017. * Retrieves an instance from a packed array.
  8018. *
  8019. * @param {Number[]} array The packed array.
  8020. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  8021. * @param {Cartesian4} [result] The object into which to store the result.
  8022. * @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
  8023. */
  8024. Cartesian4.unpack = function(array, startingIndex, result) {
  8025. if (!defined(array)) {
  8026. throw new DeveloperError('array is required');
  8027. }
  8028. startingIndex = defaultValue(startingIndex, 0);
  8029. if (!defined(result)) {
  8030. result = new Cartesian4();
  8031. }
  8032. result.x = array[startingIndex++];
  8033. result.y = array[startingIndex++];
  8034. result.z = array[startingIndex++];
  8035. result.w = array[startingIndex];
  8036. return result;
  8037. };
  8038. /**
  8039. * Flattens an array of Cartesian4s into and array of components.
  8040. *
  8041. * @param {Cartesian4[]} array The array of cartesians to pack.
  8042. * @param {Number[]} result The array onto which to store the result.
  8043. * @returns {Number[]} The packed array.
  8044. */
  8045. Cartesian4.packArray = function(array, result) {
  8046. if (!defined(array)) {
  8047. throw new DeveloperError('array is required');
  8048. }
  8049. var length = array.length;
  8050. if (!defined(result)) {
  8051. result = new Array(length * 4);
  8052. } else {
  8053. result.length = length * 4;
  8054. }
  8055. for (var i = 0; i < length; ++i) {
  8056. Cartesian4.pack(array[i], result, i * 4);
  8057. }
  8058. return result;
  8059. };
  8060. /**
  8061. * Unpacks an array of cartesian components into and array of Cartesian4s.
  8062. *
  8063. * @param {Number[]} array The array of components to unpack.
  8064. * @param {Cartesian4[]} result The array onto which to store the result.
  8065. * @returns {Cartesian4[]} The unpacked array.
  8066. */
  8067. Cartesian4.unpackArray = function(array, result) {
  8068. if (!defined(array)) {
  8069. throw new DeveloperError('array is required');
  8070. }
  8071. var length = array.length;
  8072. if (!defined(result)) {
  8073. result = new Array(length / 4);
  8074. } else {
  8075. result.length = length / 4;
  8076. }
  8077. for (var i = 0; i < length; i += 4) {
  8078. var index = i / 4;
  8079. result[index] = Cartesian4.unpack(array, i, result[index]);
  8080. }
  8081. return result;
  8082. };
  8083. /**
  8084. * Creates a Cartesian4 from four consecutive elements in an array.
  8085. * @function
  8086. *
  8087. * @param {Number[]} array The array whose four consecutive elements correspond to the x, y, z, and w components, respectively.
  8088. * @param {Number} [startingIndex=0] The offset into the array of the first element, which corresponds to the x component.
  8089. * @param {Cartesian4} [result] The object onto which to store the result.
  8090. * @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
  8091. *
  8092. * @example
  8093. * // Create a Cartesian4 with (1.0, 2.0, 3.0, 4.0)
  8094. * var v = [1.0, 2.0, 3.0, 4.0];
  8095. * var p = Cesium.Cartesian4.fromArray(v);
  8096. *
  8097. * // Create a Cartesian4 with (1.0, 2.0, 3.0, 4.0) using an offset into an array
  8098. * var v2 = [0.0, 0.0, 1.0, 2.0, 3.0, 4.0];
  8099. * var p2 = Cesium.Cartesian4.fromArray(v2, 2);
  8100. */
  8101. Cartesian4.fromArray = Cartesian4.unpack;
  8102. /**
  8103. * Computes the value of the maximum component for the supplied Cartesian.
  8104. *
  8105. * @param {Cartesian4} cartesian The cartesian to use.
  8106. * @returns {Number} The value of the maximum component.
  8107. */
  8108. Cartesian4.maximumComponent = function(cartesian) {
  8109. if (!defined(cartesian)) {
  8110. throw new DeveloperError('cartesian is required');
  8111. }
  8112. return Math.max(cartesian.x, cartesian.y, cartesian.z, cartesian.w);
  8113. };
  8114. /**
  8115. * Computes the value of the minimum component for the supplied Cartesian.
  8116. *
  8117. * @param {Cartesian4} cartesian The cartesian to use.
  8118. * @returns {Number} The value of the minimum component.
  8119. */
  8120. Cartesian4.minimumComponent = function(cartesian) {
  8121. if (!defined(cartesian)) {
  8122. throw new DeveloperError('cartesian is required');
  8123. }
  8124. return Math.min(cartesian.x, cartesian.y, cartesian.z, cartesian.w);
  8125. };
  8126. /**
  8127. * Compares two Cartesians and computes a Cartesian which contains the minimum components of the supplied Cartesians.
  8128. *
  8129. * @param {Cartesian4} first A cartesian to compare.
  8130. * @param {Cartesian4} second A cartesian to compare.
  8131. * @param {Cartesian4} result The object into which to store the result.
  8132. * @returns {Cartesian4} A cartesian with the minimum components.
  8133. */
  8134. Cartesian4.minimumByComponent = function(first, second, result) {
  8135. if (!defined(first)) {
  8136. throw new DeveloperError('first is required.');
  8137. }
  8138. if (!defined(second)) {
  8139. throw new DeveloperError('second is required.');
  8140. }
  8141. if (!defined(result)) {
  8142. throw new DeveloperError('result is required.');
  8143. }
  8144. result.x = Math.min(first.x, second.x);
  8145. result.y = Math.min(first.y, second.y);
  8146. result.z = Math.min(first.z, second.z);
  8147. result.w = Math.min(first.w, second.w);
  8148. return result;
  8149. };
  8150. /**
  8151. * Compares two Cartesians and computes a Cartesian which contains the maximum components of the supplied Cartesians.
  8152. *
  8153. * @param {Cartesian4} first A cartesian to compare.
  8154. * @param {Cartesian4} second A cartesian to compare.
  8155. * @param {Cartesian4} result The object into which to store the result.
  8156. * @returns {Cartesian4} A cartesian with the maximum components.
  8157. */
  8158. Cartesian4.maximumByComponent = function(first, second, result) {
  8159. if (!defined(first)) {
  8160. throw new DeveloperError('first is required.');
  8161. }
  8162. if (!defined(second)) {
  8163. throw new DeveloperError('second is required.');
  8164. }
  8165. if (!defined(result)) {
  8166. throw new DeveloperError('result is required.');
  8167. }
  8168. result.x = Math.max(first.x, second.x);
  8169. result.y = Math.max(first.y, second.y);
  8170. result.z = Math.max(first.z, second.z);
  8171. result.w = Math.max(first.w, second.w);
  8172. return result;
  8173. };
  8174. /**
  8175. * Computes the provided Cartesian's squared magnitude.
  8176. *
  8177. * @param {Cartesian4} cartesian The Cartesian instance whose squared magnitude is to be computed.
  8178. * @returns {Number} The squared magnitude.
  8179. */
  8180. Cartesian4.magnitudeSquared = function(cartesian) {
  8181. if (!defined(cartesian)) {
  8182. throw new DeveloperError('cartesian is required');
  8183. }
  8184. return cartesian.x * cartesian.x + cartesian.y * cartesian.y + cartesian.z * cartesian.z + cartesian.w * cartesian.w;
  8185. };
  8186. /**
  8187. * Computes the Cartesian's magnitude (length).
  8188. *
  8189. * @param {Cartesian4} cartesian The Cartesian instance whose magnitude is to be computed.
  8190. * @returns {Number} The magnitude.
  8191. */
  8192. Cartesian4.magnitude = function(cartesian) {
  8193. return Math.sqrt(Cartesian4.magnitudeSquared(cartesian));
  8194. };
  8195. var distanceScratch = new Cartesian4();
  8196. /**
  8197. * Computes the 4-space distance between two points.
  8198. *
  8199. * @param {Cartesian4} left The first point to compute the distance from.
  8200. * @param {Cartesian4} right The second point to compute the distance to.
  8201. * @returns {Number} The distance between two points.
  8202. *
  8203. * @example
  8204. * // Returns 1.0
  8205. * var d = Cesium.Cartesian4.distance(
  8206. * new Cesium.Cartesian4(1.0, 0.0, 0.0, 0.0),
  8207. * new Cesium.Cartesian4(2.0, 0.0, 0.0, 0.0));
  8208. */
  8209. Cartesian4.distance = function(left, right) {
  8210. if (!defined(left) || !defined(right)) {
  8211. throw new DeveloperError('left and right are required.');
  8212. }
  8213. Cartesian4.subtract(left, right, distanceScratch);
  8214. return Cartesian4.magnitude(distanceScratch);
  8215. };
  8216. /**
  8217. * Computes the squared distance between two points. Comparing squared distances
  8218. * using this function is more efficient than comparing distances using {@link Cartesian4#distance}.
  8219. *
  8220. * @param {Cartesian4} left The first point to compute the distance from.
  8221. * @param {Cartesian4} right The second point to compute the distance to.
  8222. * @returns {Number} The distance between two points.
  8223. *
  8224. * @example
  8225. * // Returns 4.0, not 2.0
  8226. * var d = Cesium.Cartesian4.distance(
  8227. * new Cesium.Cartesian4(1.0, 0.0, 0.0, 0.0),
  8228. * new Cesium.Cartesian4(3.0, 0.0, 0.0, 0.0));
  8229. */
  8230. Cartesian4.distanceSquared = function(left, right) {
  8231. if (!defined(left) || !defined(right)) {
  8232. throw new DeveloperError('left and right are required.');
  8233. }
  8234. Cartesian4.subtract(left, right, distanceScratch);
  8235. return Cartesian4.magnitudeSquared(distanceScratch);
  8236. };
  8237. /**
  8238. * Computes the normalized form of the supplied Cartesian.
  8239. *
  8240. * @param {Cartesian4} cartesian The Cartesian to be normalized.
  8241. * @param {Cartesian4} result The object onto which to store the result.
  8242. * @returns {Cartesian4} The modified result parameter.
  8243. */
  8244. Cartesian4.normalize = function(cartesian, result) {
  8245. if (!defined(cartesian)) {
  8246. throw new DeveloperError('cartesian is required');
  8247. }
  8248. if (!defined(result)) {
  8249. throw new DeveloperError('result is required');
  8250. }
  8251. var magnitude = Cartesian4.magnitude(cartesian);
  8252. result.x = cartesian.x / magnitude;
  8253. result.y = cartesian.y / magnitude;
  8254. result.z = cartesian.z / magnitude;
  8255. result.w = cartesian.w / magnitude;
  8256. if (isNaN(result.x) || isNaN(result.y) || isNaN(result.z) || isNaN(result.w)) {
  8257. throw new DeveloperError('normalized result is not a number');
  8258. }
  8259. return result;
  8260. };
  8261. /**
  8262. * Computes the dot (scalar) product of two Cartesians.
  8263. *
  8264. * @param {Cartesian4} left The first Cartesian.
  8265. * @param {Cartesian4} right The second Cartesian.
  8266. * @returns {Number} The dot product.
  8267. */
  8268. Cartesian4.dot = function(left, right) {
  8269. if (!defined(left)) {
  8270. throw new DeveloperError('left is required');
  8271. }
  8272. if (!defined(right)) {
  8273. throw new DeveloperError('right is required');
  8274. }
  8275. return left.x * right.x + left.y * right.y + left.z * right.z + left.w * right.w;
  8276. };
  8277. /**
  8278. * Computes the componentwise product of two Cartesians.
  8279. *
  8280. * @param {Cartesian4} left The first Cartesian.
  8281. * @param {Cartesian4} right The second Cartesian.
  8282. * @param {Cartesian4} result The object onto which to store the result.
  8283. * @returns {Cartesian4} The modified result parameter.
  8284. */
  8285. Cartesian4.multiplyComponents = function(left, right, result) {
  8286. if (!defined(left)) {
  8287. throw new DeveloperError('left is required');
  8288. }
  8289. if (!defined(right)) {
  8290. throw new DeveloperError('right is required');
  8291. }
  8292. if (!defined(result)) {
  8293. throw new DeveloperError('result is required');
  8294. }
  8295. result.x = left.x * right.x;
  8296. result.y = left.y * right.y;
  8297. result.z = left.z * right.z;
  8298. result.w = left.w * right.w;
  8299. return result;
  8300. };
  8301. /**
  8302. * Computes the componentwise quotient of two Cartesians.
  8303. *
  8304. * @param {Cartesian4} left The first Cartesian.
  8305. * @param {Cartesian4} right The second Cartesian.
  8306. * @param {Cartesian4} result The object onto which to store the result.
  8307. * @returns {Cartesian4} The modified result parameter.
  8308. */
  8309. Cartesian4.divideComponents = function(left, right, result) {
  8310. if (!defined(left)) {
  8311. throw new DeveloperError('left is required');
  8312. }
  8313. if (!defined(right)) {
  8314. throw new DeveloperError('right is required');
  8315. }
  8316. if (!defined(result)) {
  8317. throw new DeveloperError('result is required');
  8318. }
  8319. result.x = left.x / right.x;
  8320. result.y = left.y / right.y;
  8321. result.z = left.z / right.z;
  8322. result.w = left.w / right.w;
  8323. return result;
  8324. };
  8325. /**
  8326. * Computes the componentwise sum of two Cartesians.
  8327. *
  8328. * @param {Cartesian4} left The first Cartesian.
  8329. * @param {Cartesian4} right The second Cartesian.
  8330. * @param {Cartesian4} result The object onto which to store the result.
  8331. * @returns {Cartesian4} The modified result parameter.
  8332. */
  8333. Cartesian4.add = function(left, right, result) {
  8334. if (!defined(left)) {
  8335. throw new DeveloperError('left is required');
  8336. }
  8337. if (!defined(right)) {
  8338. throw new DeveloperError('right is required');
  8339. }
  8340. if (!defined(result)) {
  8341. throw new DeveloperError('result is required');
  8342. }
  8343. result.x = left.x + right.x;
  8344. result.y = left.y + right.y;
  8345. result.z = left.z + right.z;
  8346. result.w = left.w + right.w;
  8347. return result;
  8348. };
  8349. /**
  8350. * Computes the componentwise difference of two Cartesians.
  8351. *
  8352. * @param {Cartesian4} left The first Cartesian.
  8353. * @param {Cartesian4} right The second Cartesian.
  8354. * @param {Cartesian4} result The object onto which to store the result.
  8355. * @returns {Cartesian4} The modified result parameter.
  8356. */
  8357. Cartesian4.subtract = function(left, right, result) {
  8358. if (!defined(left)) {
  8359. throw new DeveloperError('left is required');
  8360. }
  8361. if (!defined(right)) {
  8362. throw new DeveloperError('right is required');
  8363. }
  8364. if (!defined(result)) {
  8365. throw new DeveloperError('result is required');
  8366. }
  8367. result.x = left.x - right.x;
  8368. result.y = left.y - right.y;
  8369. result.z = left.z - right.z;
  8370. result.w = left.w - right.w;
  8371. return result;
  8372. };
  8373. /**
  8374. * Multiplies the provided Cartesian componentwise by the provided scalar.
  8375. *
  8376. * @param {Cartesian4} cartesian The Cartesian to be scaled.
  8377. * @param {Number} scalar The scalar to multiply with.
  8378. * @param {Cartesian4} result The object onto which to store the result.
  8379. * @returns {Cartesian4} The modified result parameter.
  8380. */
  8381. Cartesian4.multiplyByScalar = function(cartesian, scalar, result) {
  8382. if (!defined(cartesian)) {
  8383. throw new DeveloperError('cartesian is required');
  8384. }
  8385. if (typeof scalar !== 'number') {
  8386. throw new DeveloperError('scalar is required and must be a number.');
  8387. }
  8388. if (!defined(result)) {
  8389. throw new DeveloperError('result is required');
  8390. }
  8391. result.x = cartesian.x * scalar;
  8392. result.y = cartesian.y * scalar;
  8393. result.z = cartesian.z * scalar;
  8394. result.w = cartesian.w * scalar;
  8395. return result;
  8396. };
  8397. /**
  8398. * Divides the provided Cartesian componentwise by the provided scalar.
  8399. *
  8400. * @param {Cartesian4} cartesian The Cartesian to be divided.
  8401. * @param {Number} scalar The scalar to divide by.
  8402. * @param {Cartesian4} result The object onto which to store the result.
  8403. * @returns {Cartesian4} The modified result parameter.
  8404. */
  8405. Cartesian4.divideByScalar = function(cartesian, scalar, result) {
  8406. if (!defined(cartesian)) {
  8407. throw new DeveloperError('cartesian is required');
  8408. }
  8409. if (typeof scalar !== 'number') {
  8410. throw new DeveloperError('scalar is required and must be a number.');
  8411. }
  8412. if (!defined(result)) {
  8413. throw new DeveloperError('result is required');
  8414. }
  8415. result.x = cartesian.x / scalar;
  8416. result.y = cartesian.y / scalar;
  8417. result.z = cartesian.z / scalar;
  8418. result.w = cartesian.w / scalar;
  8419. return result;
  8420. };
  8421. /**
  8422. * Negates the provided Cartesian.
  8423. *
  8424. * @param {Cartesian4} cartesian The Cartesian to be negated.
  8425. * @param {Cartesian4} result The object onto which to store the result.
  8426. * @returns {Cartesian4} The modified result parameter.
  8427. */
  8428. Cartesian4.negate = function(cartesian, result) {
  8429. if (!defined(cartesian)) {
  8430. throw new DeveloperError('cartesian is required');
  8431. }
  8432. if (!defined(result)) {
  8433. throw new DeveloperError('result is required');
  8434. }
  8435. result.x = -cartesian.x;
  8436. result.y = -cartesian.y;
  8437. result.z = -cartesian.z;
  8438. result.w = -cartesian.w;
  8439. return result;
  8440. };
  8441. /**
  8442. * Computes the absolute value of the provided Cartesian.
  8443. *
  8444. * @param {Cartesian4} cartesian The Cartesian whose absolute value is to be computed.
  8445. * @param {Cartesian4} result The object onto which to store the result.
  8446. * @returns {Cartesian4} The modified result parameter.
  8447. */
  8448. Cartesian4.abs = function(cartesian, result) {
  8449. if (!defined(cartesian)) {
  8450. throw new DeveloperError('cartesian is required');
  8451. }
  8452. if (!defined(result)) {
  8453. throw new DeveloperError('result is required');
  8454. }
  8455. result.x = Math.abs(cartesian.x);
  8456. result.y = Math.abs(cartesian.y);
  8457. result.z = Math.abs(cartesian.z);
  8458. result.w = Math.abs(cartesian.w);
  8459. return result;
  8460. };
  8461. var lerpScratch = new Cartesian4();
  8462. /**
  8463. * Computes the linear interpolation or extrapolation at t using the provided cartesians.
  8464. *
  8465. * @param {Cartesian4} start The value corresponding to t at 0.0.
  8466. * @param {Cartesian4}end The value corresponding to t at 1.0.
  8467. * @param {Number} t The point along t at which to interpolate.
  8468. * @param {Cartesian4} result The object onto which to store the result.
  8469. * @returns {Cartesian4} The modified result parameter.
  8470. */
  8471. Cartesian4.lerp = function(start, end, t, result) {
  8472. if (!defined(start)) {
  8473. throw new DeveloperError('start is required.');
  8474. }
  8475. if (!defined(end)) {
  8476. throw new DeveloperError('end is required.');
  8477. }
  8478. if (typeof t !== 'number') {
  8479. throw new DeveloperError('t is required and must be a number.');
  8480. }
  8481. if (!defined(result)) {
  8482. throw new DeveloperError('result is required.');
  8483. }
  8484. Cartesian4.multiplyByScalar(end, t, lerpScratch);
  8485. result = Cartesian4.multiplyByScalar(start, 1.0 - t, result);
  8486. return Cartesian4.add(lerpScratch, result, result);
  8487. };
  8488. var mostOrthogonalAxisScratch = new Cartesian4();
  8489. /**
  8490. * Returns the axis that is most orthogonal to the provided Cartesian.
  8491. *
  8492. * @param {Cartesian4} cartesian The Cartesian on which to find the most orthogonal axis.
  8493. * @param {Cartesian4} result The object onto which to store the result.
  8494. * @returns {Cartesian4} The most orthogonal axis.
  8495. */
  8496. Cartesian4.mostOrthogonalAxis = function(cartesian, result) {
  8497. if (!defined(cartesian)) {
  8498. throw new DeveloperError('cartesian is required.');
  8499. }
  8500. if (!defined(result)) {
  8501. throw new DeveloperError('result is required.');
  8502. }
  8503. var f = Cartesian4.normalize(cartesian, mostOrthogonalAxisScratch);
  8504. Cartesian4.abs(f, f);
  8505. if (f.x <= f.y) {
  8506. if (f.x <= f.z) {
  8507. if (f.x <= f.w) {
  8508. result = Cartesian4.clone(Cartesian4.UNIT_X, result);
  8509. } else {
  8510. result = Cartesian4.clone(Cartesian4.UNIT_W, result);
  8511. }
  8512. } else if (f.z <= f.w) {
  8513. result = Cartesian4.clone(Cartesian4.UNIT_Z, result);
  8514. } else {
  8515. result = Cartesian4.clone(Cartesian4.UNIT_W, result);
  8516. }
  8517. } else if (f.y <= f.z) {
  8518. if (f.y <= f.w) {
  8519. result = Cartesian4.clone(Cartesian4.UNIT_Y, result);
  8520. } else {
  8521. result = Cartesian4.clone(Cartesian4.UNIT_W, result);
  8522. }
  8523. } else if (f.z <= f.w) {
  8524. result = Cartesian4.clone(Cartesian4.UNIT_Z, result);
  8525. } else {
  8526. result = Cartesian4.clone(Cartesian4.UNIT_W, result);
  8527. }
  8528. return result;
  8529. };
  8530. /**
  8531. * Compares the provided Cartesians componentwise and returns
  8532. * <code>true</code> if they are equal, <code>false</code> otherwise.
  8533. *
  8534. * @param {Cartesian4} [left] The first Cartesian.
  8535. * @param {Cartesian4} [right] The second Cartesian.
  8536. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  8537. */
  8538. Cartesian4.equals = function(left, right) {
  8539. return (left === right) ||
  8540. ((defined(left)) &&
  8541. (defined(right)) &&
  8542. (left.x === right.x) &&
  8543. (left.y === right.y) &&
  8544. (left.z === right.z) &&
  8545. (left.w === right.w));
  8546. };
  8547. /**
  8548. * @private
  8549. */
  8550. Cartesian4.equalsArray = function(cartesian, array, offset) {
  8551. return cartesian.x === array[offset] &&
  8552. cartesian.y === array[offset + 1] &&
  8553. cartesian.z === array[offset + 2] &&
  8554. cartesian.w === array[offset + 3];
  8555. };
  8556. /**
  8557. * Compares the provided Cartesians componentwise and returns
  8558. * <code>true</code> if they pass an absolute or relative tolerance test,
  8559. * <code>false</code> otherwise.
  8560. *
  8561. * @param {Cartesian4} [left] The first Cartesian.
  8562. * @param {Cartesian4} [right] The second Cartesian.
  8563. * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
  8564. * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
  8565. * @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
  8566. */
  8567. Cartesian4.equalsEpsilon = function(left, right, relativeEpsilon, absoluteEpsilon) {
  8568. return (left === right) ||
  8569. (defined(left) &&
  8570. defined(right) &&
  8571. CesiumMath.equalsEpsilon(left.x, right.x, relativeEpsilon, absoluteEpsilon) &&
  8572. CesiumMath.equalsEpsilon(left.y, right.y, relativeEpsilon, absoluteEpsilon) &&
  8573. CesiumMath.equalsEpsilon(left.z, right.z, relativeEpsilon, absoluteEpsilon) &&
  8574. CesiumMath.equalsEpsilon(left.w, right.w, relativeEpsilon, absoluteEpsilon));
  8575. };
  8576. /**
  8577. * An immutable Cartesian4 instance initialized to (0.0, 0.0, 0.0, 0.0).
  8578. *
  8579. * @type {Cartesian4}
  8580. * @constant
  8581. */
  8582. Cartesian4.ZERO = freezeObject(new Cartesian4(0.0, 0.0, 0.0, 0.0));
  8583. /**
  8584. * An immutable Cartesian4 instance initialized to (1.0, 0.0, 0.0, 0.0).
  8585. *
  8586. * @type {Cartesian4}
  8587. * @constant
  8588. */
  8589. Cartesian4.UNIT_X = freezeObject(new Cartesian4(1.0, 0.0, 0.0, 0.0));
  8590. /**
  8591. * An immutable Cartesian4 instance initialized to (0.0, 1.0, 0.0, 0.0).
  8592. *
  8593. * @type {Cartesian4}
  8594. * @constant
  8595. */
  8596. Cartesian4.UNIT_Y = freezeObject(new Cartesian4(0.0, 1.0, 0.0, 0.0));
  8597. /**
  8598. * An immutable Cartesian4 instance initialized to (0.0, 0.0, 1.0, 0.0).
  8599. *
  8600. * @type {Cartesian4}
  8601. * @constant
  8602. */
  8603. Cartesian4.UNIT_Z = freezeObject(new Cartesian4(0.0, 0.0, 1.0, 0.0));
  8604. /**
  8605. * An immutable Cartesian4 instance initialized to (0.0, 0.0, 0.0, 1.0).
  8606. *
  8607. * @type {Cartesian4}
  8608. * @constant
  8609. */
  8610. Cartesian4.UNIT_W = freezeObject(new Cartesian4(0.0, 0.0, 0.0, 1.0));
  8611. /**
  8612. * Duplicates this Cartesian4 instance.
  8613. *
  8614. * @param {Cartesian4} [result] The object onto which to store the result.
  8615. * @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
  8616. */
  8617. Cartesian4.prototype.clone = function(result) {
  8618. return Cartesian4.clone(this, result);
  8619. };
  8620. /**
  8621. * Compares this Cartesian against the provided Cartesian componentwise and returns
  8622. * <code>true</code> if they are equal, <code>false</code> otherwise.
  8623. *
  8624. * @param {Cartesian4} [right] The right hand side Cartesian.
  8625. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  8626. */
  8627. Cartesian4.prototype.equals = function(right) {
  8628. return Cartesian4.equals(this, right);
  8629. };
  8630. /**
  8631. * Compares this Cartesian against the provided Cartesian componentwise and returns
  8632. * <code>true</code> if they pass an absolute or relative tolerance test,
  8633. * <code>false</code> otherwise.
  8634. *
  8635. * @param {Cartesian4} [right] The right hand side Cartesian.
  8636. * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
  8637. * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
  8638. * @returns {Boolean} <code>true</code> if they are within the provided epsilon, <code>false</code> otherwise.
  8639. */
  8640. Cartesian4.prototype.equalsEpsilon = function(right, relativeEpsilon, absoluteEpsilon) {
  8641. return Cartesian4.equalsEpsilon(this, right, relativeEpsilon, absoluteEpsilon);
  8642. };
  8643. /**
  8644. * Creates a string representing this Cartesian in the format '(x, y)'.
  8645. *
  8646. * @returns {String} A string representing the provided Cartesian in the format '(x, y)'.
  8647. */
  8648. Cartesian4.prototype.toString = function() {
  8649. return '(' + this.x + ', ' + this.y + ', ' + this.z + ', ' + this.w + ')';
  8650. };
  8651. return Cartesian4;
  8652. });
  8653. /*global define*/
  8654. define('Core/RuntimeError',[
  8655. './defined'
  8656. ], function(
  8657. defined) {
  8658. 'use strict';
  8659. /**
  8660. * Constructs an exception object that is thrown due to an error that can occur at runtime, e.g.,
  8661. * out of memory, could not compile shader, etc. If a function may throw this
  8662. * exception, the calling code should be prepared to catch it.
  8663. * <br /><br />
  8664. * On the other hand, a {@link DeveloperError} indicates an exception due
  8665. * to a developer error, e.g., invalid argument, that usually indicates a bug in the
  8666. * calling code.
  8667. *
  8668. * @alias RuntimeError
  8669. * @constructor
  8670. * @extends Error
  8671. *
  8672. * @param {String} [message] The error message for this exception.
  8673. *
  8674. * @see DeveloperError
  8675. */
  8676. function RuntimeError(message) {
  8677. /**
  8678. * 'RuntimeError' indicating that this exception was thrown due to a runtime error.
  8679. * @type {String}
  8680. * @readonly
  8681. */
  8682. this.name = 'RuntimeError';
  8683. /**
  8684. * The explanation for why this exception was thrown.
  8685. * @type {String}
  8686. * @readonly
  8687. */
  8688. this.message = message;
  8689. //Browsers such as IE don't have a stack property until you actually throw the error.
  8690. var stack;
  8691. try {
  8692. throw new Error();
  8693. } catch (e) {
  8694. stack = e.stack;
  8695. }
  8696. /**
  8697. * The stack trace of this exception, if available.
  8698. * @type {String}
  8699. * @readonly
  8700. */
  8701. this.stack = stack;
  8702. }
  8703. if (defined(Object.create)) {
  8704. RuntimeError.prototype = Object.create(Error.prototype);
  8705. RuntimeError.prototype.constructor = RuntimeError;
  8706. }
  8707. RuntimeError.prototype.toString = function() {
  8708. var str = this.name + ': ' + this.message;
  8709. if (defined(this.stack)) {
  8710. str += '\n' + this.stack.toString();
  8711. }
  8712. return str;
  8713. };
  8714. return RuntimeError;
  8715. });
  8716. /*global define*/
  8717. define('Core/Matrix4',[
  8718. './Cartesian3',
  8719. './Cartesian4',
  8720. './defaultValue',
  8721. './defined',
  8722. './defineProperties',
  8723. './DeveloperError',
  8724. './freezeObject',
  8725. './Math',
  8726. './Matrix3',
  8727. './RuntimeError'
  8728. ], function(
  8729. Cartesian3,
  8730. Cartesian4,
  8731. defaultValue,
  8732. defined,
  8733. defineProperties,
  8734. DeveloperError,
  8735. freezeObject,
  8736. CesiumMath,
  8737. Matrix3,
  8738. RuntimeError) {
  8739. 'use strict';
  8740. /**
  8741. * A 4x4 matrix, indexable as a column-major order array.
  8742. * Constructor parameters are in row-major order for code readability.
  8743. * @alias Matrix4
  8744. * @constructor
  8745. *
  8746. * @param {Number} [column0Row0=0.0] The value for column 0, row 0.
  8747. * @param {Number} [column1Row0=0.0] The value for column 1, row 0.
  8748. * @param {Number} [column2Row0=0.0] The value for column 2, row 0.
  8749. * @param {Number} [column3Row0=0.0] The value for column 3, row 0.
  8750. * @param {Number} [column0Row1=0.0] The value for column 0, row 1.
  8751. * @param {Number} [column1Row1=0.0] The value for column 1, row 1.
  8752. * @param {Number} [column2Row1=0.0] The value for column 2, row 1.
  8753. * @param {Number} [column3Row1=0.0] The value for column 3, row 1.
  8754. * @param {Number} [column0Row2=0.0] The value for column 0, row 2.
  8755. * @param {Number} [column1Row2=0.0] The value for column 1, row 2.
  8756. * @param {Number} [column2Row2=0.0] The value for column 2, row 2.
  8757. * @param {Number} [column3Row2=0.0] The value for column 3, row 2.
  8758. * @param {Number} [column0Row3=0.0] The value for column 0, row 3.
  8759. * @param {Number} [column1Row3=0.0] The value for column 1, row 3.
  8760. * @param {Number} [column2Row3=0.0] The value for column 2, row 3.
  8761. * @param {Number} [column3Row3=0.0] The value for column 3, row 3.
  8762. *
  8763. * @see Matrix4.fromColumnMajorArray
  8764. * @see Matrix4.fromRowMajorArray
  8765. * @see Matrix4.fromRotationTranslation
  8766. * @see Matrix4.fromTranslationRotationScale
  8767. * @see Matrix4.fromTranslationQuaternionRotationScale
  8768. * @see Matrix4.fromTranslation
  8769. * @see Matrix4.fromScale
  8770. * @see Matrix4.fromUniformScale
  8771. * @see Matrix4.fromCamera
  8772. * @see Matrix4.computePerspectiveFieldOfView
  8773. * @see Matrix4.computeOrthographicOffCenter
  8774. * @see Matrix4.computePerspectiveOffCenter
  8775. * @see Matrix4.computeInfinitePerspectiveOffCenter
  8776. * @see Matrix4.computeViewportTransformation
  8777. * @see Matrix4.computeView
  8778. * @see Matrix2
  8779. * @see Matrix3
  8780. * @see Packable
  8781. */
  8782. function Matrix4(column0Row0, column1Row0, column2Row0, column3Row0,
  8783. column0Row1, column1Row1, column2Row1, column3Row1,
  8784. column0Row2, column1Row2, column2Row2, column3Row2,
  8785. column0Row3, column1Row3, column2Row3, column3Row3) {
  8786. this[0] = defaultValue(column0Row0, 0.0);
  8787. this[1] = defaultValue(column0Row1, 0.0);
  8788. this[2] = defaultValue(column0Row2, 0.0);
  8789. this[3] = defaultValue(column0Row3, 0.0);
  8790. this[4] = defaultValue(column1Row0, 0.0);
  8791. this[5] = defaultValue(column1Row1, 0.0);
  8792. this[6] = defaultValue(column1Row2, 0.0);
  8793. this[7] = defaultValue(column1Row3, 0.0);
  8794. this[8] = defaultValue(column2Row0, 0.0);
  8795. this[9] = defaultValue(column2Row1, 0.0);
  8796. this[10] = defaultValue(column2Row2, 0.0);
  8797. this[11] = defaultValue(column2Row3, 0.0);
  8798. this[12] = defaultValue(column3Row0, 0.0);
  8799. this[13] = defaultValue(column3Row1, 0.0);
  8800. this[14] = defaultValue(column3Row2, 0.0);
  8801. this[15] = defaultValue(column3Row3, 0.0);
  8802. }
  8803. /**
  8804. * The number of elements used to pack the object into an array.
  8805. * @type {Number}
  8806. */
  8807. Matrix4.packedLength = 16;
  8808. /**
  8809. * Stores the provided instance into the provided array.
  8810. *
  8811. * @param {Matrix4} value The value to pack.
  8812. * @param {Number[]} array The array to pack into.
  8813. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  8814. *
  8815. * @returns {Number[]} The array that was packed into
  8816. */
  8817. Matrix4.pack = function(value, array, startingIndex) {
  8818. if (!defined(value)) {
  8819. throw new DeveloperError('value is required');
  8820. }
  8821. if (!defined(array)) {
  8822. throw new DeveloperError('array is required');
  8823. }
  8824. startingIndex = defaultValue(startingIndex, 0);
  8825. array[startingIndex++] = value[0];
  8826. array[startingIndex++] = value[1];
  8827. array[startingIndex++] = value[2];
  8828. array[startingIndex++] = value[3];
  8829. array[startingIndex++] = value[4];
  8830. array[startingIndex++] = value[5];
  8831. array[startingIndex++] = value[6];
  8832. array[startingIndex++] = value[7];
  8833. array[startingIndex++] = value[8];
  8834. array[startingIndex++] = value[9];
  8835. array[startingIndex++] = value[10];
  8836. array[startingIndex++] = value[11];
  8837. array[startingIndex++] = value[12];
  8838. array[startingIndex++] = value[13];
  8839. array[startingIndex++] = value[14];
  8840. array[startingIndex] = value[15];
  8841. return array;
  8842. };
  8843. /**
  8844. * Retrieves an instance from a packed array.
  8845. *
  8846. * @param {Number[]} array The packed array.
  8847. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  8848. * @param {Matrix4} [result] The object into which to store the result.
  8849. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if one was not provided.
  8850. */
  8851. Matrix4.unpack = function(array, startingIndex, result) {
  8852. if (!defined(array)) {
  8853. throw new DeveloperError('array is required');
  8854. }
  8855. startingIndex = defaultValue(startingIndex, 0);
  8856. if (!defined(result)) {
  8857. result = new Matrix4();
  8858. }
  8859. result[0] = array[startingIndex++];
  8860. result[1] = array[startingIndex++];
  8861. result[2] = array[startingIndex++];
  8862. result[3] = array[startingIndex++];
  8863. result[4] = array[startingIndex++];
  8864. result[5] = array[startingIndex++];
  8865. result[6] = array[startingIndex++];
  8866. result[7] = array[startingIndex++];
  8867. result[8] = array[startingIndex++];
  8868. result[9] = array[startingIndex++];
  8869. result[10] = array[startingIndex++];
  8870. result[11] = array[startingIndex++];
  8871. result[12] = array[startingIndex++];
  8872. result[13] = array[startingIndex++];
  8873. result[14] = array[startingIndex++];
  8874. result[15] = array[startingIndex];
  8875. return result;
  8876. };
  8877. /**
  8878. * Duplicates a Matrix4 instance.
  8879. *
  8880. * @param {Matrix4} matrix The matrix to duplicate.
  8881. * @param {Matrix4} [result] The object onto which to store the result.
  8882. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if one was not provided. (Returns undefined if matrix is undefined)
  8883. */
  8884. Matrix4.clone = function(matrix, result) {
  8885. if (!defined(matrix)) {
  8886. return undefined;
  8887. }
  8888. if (!defined(result)) {
  8889. return new Matrix4(matrix[0], matrix[4], matrix[8], matrix[12],
  8890. matrix[1], matrix[5], matrix[9], matrix[13],
  8891. matrix[2], matrix[6], matrix[10], matrix[14],
  8892. matrix[3], matrix[7], matrix[11], matrix[15]);
  8893. }
  8894. result[0] = matrix[0];
  8895. result[1] = matrix[1];
  8896. result[2] = matrix[2];
  8897. result[3] = matrix[3];
  8898. result[4] = matrix[4];
  8899. result[5] = matrix[5];
  8900. result[6] = matrix[6];
  8901. result[7] = matrix[7];
  8902. result[8] = matrix[8];
  8903. result[9] = matrix[9];
  8904. result[10] = matrix[10];
  8905. result[11] = matrix[11];
  8906. result[12] = matrix[12];
  8907. result[13] = matrix[13];
  8908. result[14] = matrix[14];
  8909. result[15] = matrix[15];
  8910. return result;
  8911. };
  8912. /**
  8913. * Creates a Matrix4 from 16 consecutive elements in an array.
  8914. * @function
  8915. *
  8916. * @param {Number[]} array The array whose 16 consecutive elements correspond to the positions of the matrix. Assumes column-major order.
  8917. * @param {Number} [startingIndex=0] The offset into the array of the first element, which corresponds to first column first row position in the matrix.
  8918. * @param {Matrix4} [result] The object onto which to store the result.
  8919. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if one was not provided.
  8920. *
  8921. * @example
  8922. * // Create the Matrix4:
  8923. * // [1.0, 2.0, 3.0, 4.0]
  8924. * // [1.0, 2.0, 3.0, 4.0]
  8925. * // [1.0, 2.0, 3.0, 4.0]
  8926. * // [1.0, 2.0, 3.0, 4.0]
  8927. *
  8928. * var v = [1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0];
  8929. * var m = Cesium.Matrix4.fromArray(v);
  8930. *
  8931. * // Create same Matrix4 with using an offset into an array
  8932. * var v2 = [0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0];
  8933. * var m2 = Cesium.Matrix4.fromArray(v2, 2);
  8934. */
  8935. Matrix4.fromArray = Matrix4.unpack;
  8936. /**
  8937. * Computes a Matrix4 instance from a column-major order array.
  8938. *
  8939. * @param {Number[]} values The column-major order array.
  8940. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
  8941. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
  8942. */
  8943. Matrix4.fromColumnMajorArray = function(values, result) {
  8944. if (!defined(values)) {
  8945. throw new DeveloperError('values is required');
  8946. }
  8947. return Matrix4.clone(values, result);
  8948. };
  8949. /**
  8950. * Computes a Matrix4 instance from a row-major order array.
  8951. * The resulting matrix will be in column-major order.
  8952. *
  8953. * @param {Number[]} values The row-major order array.
  8954. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
  8955. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
  8956. */
  8957. Matrix4.fromRowMajorArray = function(values, result) {
  8958. if (!defined(values)) {
  8959. throw new DeveloperError('values is required.');
  8960. }
  8961. if (!defined(result)) {
  8962. return new Matrix4(values[0], values[1], values[2], values[3],
  8963. values[4], values[5], values[6], values[7],
  8964. values[8], values[9], values[10], values[11],
  8965. values[12], values[13], values[14], values[15]);
  8966. }
  8967. result[0] = values[0];
  8968. result[1] = values[4];
  8969. result[2] = values[8];
  8970. result[3] = values[12];
  8971. result[4] = values[1];
  8972. result[5] = values[5];
  8973. result[6] = values[9];
  8974. result[7] = values[13];
  8975. result[8] = values[2];
  8976. result[9] = values[6];
  8977. result[10] = values[10];
  8978. result[11] = values[14];
  8979. result[12] = values[3];
  8980. result[13] = values[7];
  8981. result[14] = values[11];
  8982. result[15] = values[15];
  8983. return result;
  8984. };
  8985. /**
  8986. * Computes a Matrix4 instance from a Matrix3 representing the rotation
  8987. * and a Cartesian3 representing the translation.
  8988. *
  8989. * @param {Matrix3} rotation The upper left portion of the matrix representing the rotation.
  8990. * @param {Cartesian3} [translation=Cartesian3.ZERO] The upper right portion of the matrix representing the translation.
  8991. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
  8992. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
  8993. */
  8994. Matrix4.fromRotationTranslation = function(rotation, translation, result) {
  8995. if (!defined(rotation)) {
  8996. throw new DeveloperError('rotation is required.');
  8997. }
  8998. translation = defaultValue(translation, Cartesian3.ZERO);
  8999. if (!defined(result)) {
  9000. return new Matrix4(rotation[0], rotation[3], rotation[6], translation.x,
  9001. rotation[1], rotation[4], rotation[7], translation.y,
  9002. rotation[2], rotation[5], rotation[8], translation.z,
  9003. 0.0, 0.0, 0.0, 1.0);
  9004. }
  9005. result[0] = rotation[0];
  9006. result[1] = rotation[1];
  9007. result[2] = rotation[2];
  9008. result[3] = 0.0;
  9009. result[4] = rotation[3];
  9010. result[5] = rotation[4];
  9011. result[6] = rotation[5];
  9012. result[7] = 0.0;
  9013. result[8] = rotation[6];
  9014. result[9] = rotation[7];
  9015. result[10] = rotation[8];
  9016. result[11] = 0.0;
  9017. result[12] = translation.x;
  9018. result[13] = translation.y;
  9019. result[14] = translation.z;
  9020. result[15] = 1.0;
  9021. return result;
  9022. };
  9023. /**
  9024. * Computes a Matrix4 instance from a translation, rotation, and scale (TRS)
  9025. * representation with the rotation represented as a quaternion.
  9026. *
  9027. * @param {Cartesian3} translation The translation transformation.
  9028. * @param {Quaternion} rotation The rotation transformation.
  9029. * @param {Cartesian3} scale The non-uniform scale transformation.
  9030. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
  9031. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
  9032. *
  9033. * @example
  9034. * var result = Cesium.Matrix4.fromTranslationQuaternionRotationScale(
  9035. * new Cesium.Cartesian3(1.0, 2.0, 3.0), // translation
  9036. * Cesium.Quaternion.IDENTITY, // rotation
  9037. * new Cesium.Cartesian3(7.0, 8.0, 9.0), // scale
  9038. * result);
  9039. */
  9040. Matrix4.fromTranslationQuaternionRotationScale = function(translation, rotation, scale, result) {
  9041. if (!defined(translation)) {
  9042. throw new DeveloperError('translation is required.');
  9043. }
  9044. if (!defined(rotation)) {
  9045. throw new DeveloperError('rotation is required.');
  9046. }
  9047. if (!defined(scale)) {
  9048. throw new DeveloperError('scale is required.');
  9049. }
  9050. if (!defined(result)) {
  9051. result = new Matrix4();
  9052. }
  9053. var scaleX = scale.x;
  9054. var scaleY = scale.y;
  9055. var scaleZ = scale.z;
  9056. var x2 = rotation.x * rotation.x;
  9057. var xy = rotation.x * rotation.y;
  9058. var xz = rotation.x * rotation.z;
  9059. var xw = rotation.x * rotation.w;
  9060. var y2 = rotation.y * rotation.y;
  9061. var yz = rotation.y * rotation.z;
  9062. var yw = rotation.y * rotation.w;
  9063. var z2 = rotation.z * rotation.z;
  9064. var zw = rotation.z * rotation.w;
  9065. var w2 = rotation.w * rotation.w;
  9066. var m00 = x2 - y2 - z2 + w2;
  9067. var m01 = 2.0 * (xy - zw);
  9068. var m02 = 2.0 * (xz + yw);
  9069. var m10 = 2.0 * (xy + zw);
  9070. var m11 = -x2 + y2 - z2 + w2;
  9071. var m12 = 2.0 * (yz - xw);
  9072. var m20 = 2.0 * (xz - yw);
  9073. var m21 = 2.0 * (yz + xw);
  9074. var m22 = -x2 - y2 + z2 + w2;
  9075. result[0] = m00 * scaleX;
  9076. result[1] = m10 * scaleX;
  9077. result[2] = m20 * scaleX;
  9078. result[3] = 0.0;
  9079. result[4] = m01 * scaleY;
  9080. result[5] = m11 * scaleY;
  9081. result[6] = m21 * scaleY;
  9082. result[7] = 0.0;
  9083. result[8] = m02 * scaleZ;
  9084. result[9] = m12 * scaleZ;
  9085. result[10] = m22 * scaleZ;
  9086. result[11] = 0.0;
  9087. result[12] = translation.x;
  9088. result[13] = translation.y;
  9089. result[14] = translation.z;
  9090. result[15] = 1.0;
  9091. return result;
  9092. };
  9093. /**
  9094. * Creates a Matrix4 instance from a {@link TranslationRotationScale} instance.
  9095. *
  9096. * @param {TranslationRotationScale} translationRotationScale The instance.
  9097. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
  9098. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
  9099. */
  9100. Matrix4.fromTranslationRotationScale = function(translationRotationScale, result) {
  9101. if (!defined(translationRotationScale)) {
  9102. throw new DeveloperError('translationRotationScale is required.');
  9103. }
  9104. return Matrix4.fromTranslationQuaternionRotationScale(translationRotationScale.translation, translationRotationScale.rotation, translationRotationScale.scale, result);
  9105. };
  9106. /**
  9107. * Creates a Matrix4 instance from a Cartesian3 representing the translation.
  9108. *
  9109. * @param {Cartesian3} translation The upper right portion of the matrix representing the translation.
  9110. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
  9111. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
  9112. *
  9113. * @see Matrix4.multiplyByTranslation
  9114. */
  9115. Matrix4.fromTranslation = function(translation, result) {
  9116. if (!defined(translation)) {
  9117. throw new DeveloperError('translation is required.');
  9118. }
  9119. return Matrix4.fromRotationTranslation(Matrix3.IDENTITY, translation, result);
  9120. };
  9121. /**
  9122. * Computes a Matrix4 instance representing a non-uniform scale.
  9123. *
  9124. * @param {Cartesian3} scale The x, y, and z scale factors.
  9125. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
  9126. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
  9127. *
  9128. * @example
  9129. * // Creates
  9130. * // [7.0, 0.0, 0.0, 0.0]
  9131. * // [0.0, 8.0, 0.0, 0.0]
  9132. * // [0.0, 0.0, 9.0, 0.0]
  9133. * // [0.0, 0.0, 0.0, 1.0]
  9134. * var m = Cesium.Matrix4.fromScale(new Cesium.Cartesian3(7.0, 8.0, 9.0));
  9135. */
  9136. Matrix4.fromScale = function(scale, result) {
  9137. if (!defined(scale)) {
  9138. throw new DeveloperError('scale is required.');
  9139. }
  9140. if (!defined(result)) {
  9141. return new Matrix4(
  9142. scale.x, 0.0, 0.0, 0.0,
  9143. 0.0, scale.y, 0.0, 0.0,
  9144. 0.0, 0.0, scale.z, 0.0,
  9145. 0.0, 0.0, 0.0, 1.0);
  9146. }
  9147. result[0] = scale.x;
  9148. result[1] = 0.0;
  9149. result[2] = 0.0;
  9150. result[3] = 0.0;
  9151. result[4] = 0.0;
  9152. result[5] = scale.y;
  9153. result[6] = 0.0;
  9154. result[7] = 0.0;
  9155. result[8] = 0.0;
  9156. result[9] = 0.0;
  9157. result[10] = scale.z;
  9158. result[11] = 0.0;
  9159. result[12] = 0.0;
  9160. result[13] = 0.0;
  9161. result[14] = 0.0;
  9162. result[15] = 1.0;
  9163. return result;
  9164. };
  9165. /**
  9166. * Computes a Matrix4 instance representing a uniform scale.
  9167. *
  9168. * @param {Number} scale The uniform scale factor.
  9169. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
  9170. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
  9171. *
  9172. * @example
  9173. * // Creates
  9174. * // [2.0, 0.0, 0.0, 0.0]
  9175. * // [0.0, 2.0, 0.0, 0.0]
  9176. * // [0.0, 0.0, 2.0, 0.0]
  9177. * // [0.0, 0.0, 0.0, 1.0]
  9178. * var m = Cesium.Matrix4.fromUniformScale(2.0);
  9179. */
  9180. Matrix4.fromUniformScale = function(scale, result) {
  9181. if (typeof scale !== 'number') {
  9182. throw new DeveloperError('scale is required.');
  9183. }
  9184. if (!defined(result)) {
  9185. return new Matrix4(scale, 0.0, 0.0, 0.0,
  9186. 0.0, scale, 0.0, 0.0,
  9187. 0.0, 0.0, scale, 0.0,
  9188. 0.0, 0.0, 0.0, 1.0);
  9189. }
  9190. result[0] = scale;
  9191. result[1] = 0.0;
  9192. result[2] = 0.0;
  9193. result[3] = 0.0;
  9194. result[4] = 0.0;
  9195. result[5] = scale;
  9196. result[6] = 0.0;
  9197. result[7] = 0.0;
  9198. result[8] = 0.0;
  9199. result[9] = 0.0;
  9200. result[10] = scale;
  9201. result[11] = 0.0;
  9202. result[12] = 0.0;
  9203. result[13] = 0.0;
  9204. result[14] = 0.0;
  9205. result[15] = 1.0;
  9206. return result;
  9207. };
  9208. var fromCameraF = new Cartesian3();
  9209. var fromCameraR = new Cartesian3();
  9210. var fromCameraU = new Cartesian3();
  9211. /**
  9212. * Computes a Matrix4 instance from a Camera.
  9213. *
  9214. * @param {Camera} camera The camera to use.
  9215. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
  9216. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
  9217. */
  9218. Matrix4.fromCamera = function(camera, result) {
  9219. if (!defined(camera)) {
  9220. throw new DeveloperError('camera is required.');
  9221. }
  9222. var position = camera.position;
  9223. var direction = camera.direction;
  9224. var up = camera.up;
  9225. if (!defined(position)) {
  9226. throw new DeveloperError('camera.position is required.');
  9227. }
  9228. if (!defined(direction)) {
  9229. throw new DeveloperError('camera.direction is required.');
  9230. }
  9231. if (!defined(up)) {
  9232. throw new DeveloperError('camera.up is required.');
  9233. }
  9234. Cartesian3.normalize(direction, fromCameraF);
  9235. Cartesian3.normalize(Cartesian3.cross(fromCameraF, up, fromCameraR), fromCameraR);
  9236. Cartesian3.normalize(Cartesian3.cross(fromCameraR, fromCameraF, fromCameraU), fromCameraU);
  9237. var sX = fromCameraR.x;
  9238. var sY = fromCameraR.y;
  9239. var sZ = fromCameraR.z;
  9240. var fX = fromCameraF.x;
  9241. var fY = fromCameraF.y;
  9242. var fZ = fromCameraF.z;
  9243. var uX = fromCameraU.x;
  9244. var uY = fromCameraU.y;
  9245. var uZ = fromCameraU.z;
  9246. var positionX = position.x;
  9247. var positionY = position.y;
  9248. var positionZ = position.z;
  9249. var t0 = sX * -positionX + sY * -positionY+ sZ * -positionZ;
  9250. var t1 = uX * -positionX + uY * -positionY+ uZ * -positionZ;
  9251. var t2 = fX * positionX + fY * positionY + fZ * positionZ;
  9252. // The code below this comment is an optimized
  9253. // version of the commented lines.
  9254. // Rather that create two matrices and then multiply,
  9255. // we just bake in the multiplcation as part of creation.
  9256. // var rotation = new Matrix4(
  9257. // sX, sY, sZ, 0.0,
  9258. // uX, uY, uZ, 0.0,
  9259. // -fX, -fY, -fZ, 0.0,
  9260. // 0.0, 0.0, 0.0, 1.0);
  9261. // var translation = new Matrix4(
  9262. // 1.0, 0.0, 0.0, -position.x,
  9263. // 0.0, 1.0, 0.0, -position.y,
  9264. // 0.0, 0.0, 1.0, -position.z,
  9265. // 0.0, 0.0, 0.0, 1.0);
  9266. // return rotation.multiply(translation);
  9267. if (!defined(result)) {
  9268. return new Matrix4(
  9269. sX, sY, sZ, t0,
  9270. uX, uY, uZ, t1,
  9271. -fX, -fY, -fZ, t2,
  9272. 0.0, 0.0, 0.0, 1.0);
  9273. }
  9274. result[0] = sX;
  9275. result[1] = uX;
  9276. result[2] = -fX;
  9277. result[3] = 0.0;
  9278. result[4] = sY;
  9279. result[5] = uY;
  9280. result[6] = -fY;
  9281. result[7] = 0.0;
  9282. result[8] = sZ;
  9283. result[9] = uZ;
  9284. result[10] = -fZ;
  9285. result[11] = 0.0;
  9286. result[12] = t0;
  9287. result[13] = t1;
  9288. result[14] = t2;
  9289. result[15] = 1.0;
  9290. return result;
  9291. };
  9292. /**
  9293. * Computes a Matrix4 instance representing a perspective transformation matrix.
  9294. *
  9295. * @param {Number} fovY The field of view along the Y axis in radians.
  9296. * @param {Number} aspectRatio The aspect ratio.
  9297. * @param {Number} near The distance to the near plane in meters.
  9298. * @param {Number} far The distance to the far plane in meters.
  9299. * @param {Matrix4} result The object in which the result will be stored.
  9300. * @returns {Matrix4} The modified result parameter.
  9301. *
  9302. * @exception {DeveloperError} fovY must be in (0, PI].
  9303. * @exception {DeveloperError} aspectRatio must be greater than zero.
  9304. * @exception {DeveloperError} near must be greater than zero.
  9305. * @exception {DeveloperError} far must be greater than zero.
  9306. */
  9307. Matrix4.computePerspectiveFieldOfView = function(fovY, aspectRatio, near, far, result) {
  9308. if (fovY <= 0.0 || fovY > Math.PI) {
  9309. throw new DeveloperError('fovY must be in (0, PI].');
  9310. }
  9311. if (aspectRatio <= 0.0) {
  9312. throw new DeveloperError('aspectRatio must be greater than zero.');
  9313. }
  9314. if (near <= 0.0) {
  9315. throw new DeveloperError('near must be greater than zero.');
  9316. }
  9317. if (far <= 0.0) {
  9318. throw new DeveloperError('far must be greater than zero.');
  9319. }
  9320. if (!defined(result)) {
  9321. throw new DeveloperError('result is required');
  9322. }
  9323. var bottom = Math.tan(fovY * 0.5);
  9324. var column1Row1 = 1.0 / bottom;
  9325. var column0Row0 = column1Row1 / aspectRatio;
  9326. var column2Row2 = (far + near) / (near - far);
  9327. var column3Row2 = (2.0 * far * near) / (near - far);
  9328. result[0] = column0Row0;
  9329. result[1] = 0.0;
  9330. result[2] = 0.0;
  9331. result[3] = 0.0;
  9332. result[4] = 0.0;
  9333. result[5] = column1Row1;
  9334. result[6] = 0.0;
  9335. result[7] = 0.0;
  9336. result[8] = 0.0;
  9337. result[9] = 0.0;
  9338. result[10] = column2Row2;
  9339. result[11] = -1.0;
  9340. result[12] = 0.0;
  9341. result[13] = 0.0;
  9342. result[14] = column3Row2;
  9343. result[15] = 0.0;
  9344. return result;
  9345. };
  9346. /**
  9347. * Computes a Matrix4 instance representing an orthographic transformation matrix.
  9348. *
  9349. * @param {Number} left The number of meters to the left of the camera that will be in view.
  9350. * @param {Number} right The number of meters to the right of the camera that will be in view.
  9351. * @param {Number} bottom The number of meters below of the camera that will be in view.
  9352. * @param {Number} top The number of meters above of the camera that will be in view.
  9353. * @param {Number} near The distance to the near plane in meters.
  9354. * @param {Number} far The distance to the far plane in meters.
  9355. * @param {Matrix4} result The object in which the result will be stored.
  9356. * @returns {Matrix4} The modified result parameter.
  9357. */
  9358. Matrix4.computeOrthographicOffCenter = function(left, right, bottom, top, near, far, result) {
  9359. if (!defined(left)) {
  9360. throw new DeveloperError('left is required.');
  9361. }
  9362. if (!defined(right)) {
  9363. throw new DeveloperError('right is required.');
  9364. }
  9365. if (!defined(bottom)) {
  9366. throw new DeveloperError('bottom is required.');
  9367. }
  9368. if (!defined(top)) {
  9369. throw new DeveloperError('top is required.');
  9370. }
  9371. if (!defined(near)) {
  9372. throw new DeveloperError('near is required.');
  9373. }
  9374. if (!defined(far)) {
  9375. throw new DeveloperError('far is required.');
  9376. }
  9377. if (!defined(result)) {
  9378. throw new DeveloperError('result is required');
  9379. }
  9380. var a = 1.0 / (right - left);
  9381. var b = 1.0 / (top - bottom);
  9382. var c = 1.0 / (far - near);
  9383. var tx = -(right + left) * a;
  9384. var ty = -(top + bottom) * b;
  9385. var tz = -(far + near) * c;
  9386. a *= 2.0;
  9387. b *= 2.0;
  9388. c *= -2.0;
  9389. result[0] = a;
  9390. result[1] = 0.0;
  9391. result[2] = 0.0;
  9392. result[3] = 0.0;
  9393. result[4] = 0.0;
  9394. result[5] = b;
  9395. result[6] = 0.0;
  9396. result[7] = 0.0;
  9397. result[8] = 0.0;
  9398. result[9] = 0.0;
  9399. result[10] = c;
  9400. result[11] = 0.0;
  9401. result[12] = tx;
  9402. result[13] = ty;
  9403. result[14] = tz;
  9404. result[15] = 1.0;
  9405. return result;
  9406. };
  9407. /**
  9408. * Computes a Matrix4 instance representing an off center perspective transformation.
  9409. *
  9410. * @param {Number} left The number of meters to the left of the camera that will be in view.
  9411. * @param {Number} right The number of meters to the right of the camera that will be in view.
  9412. * @param {Number} bottom The number of meters below of the camera that will be in view.
  9413. * @param {Number} top The number of meters above of the camera that will be in view.
  9414. * @param {Number} near The distance to the near plane in meters.
  9415. * @param {Number} far The distance to the far plane in meters.
  9416. * @param {Matrix4} result The object in which the result will be stored.
  9417. * @returns {Matrix4} The modified result parameter.
  9418. */
  9419. Matrix4.computePerspectiveOffCenter = function(left, right, bottom, top, near, far, result) {
  9420. if (!defined(left)) {
  9421. throw new DeveloperError('left is required.');
  9422. }
  9423. if (!defined(right)) {
  9424. throw new DeveloperError('right is required.');
  9425. }
  9426. if (!defined(bottom)) {
  9427. throw new DeveloperError('bottom is required.');
  9428. }
  9429. if (!defined(top)) {
  9430. throw new DeveloperError('top is required.');
  9431. }
  9432. if (!defined(near)) {
  9433. throw new DeveloperError('near is required.');
  9434. }
  9435. if (!defined(far)) {
  9436. throw new DeveloperError('far is required.');
  9437. }
  9438. if (!defined(result)) {
  9439. throw new DeveloperError('result is required');
  9440. }
  9441. var column0Row0 = 2.0 * near / (right - left);
  9442. var column1Row1 = 2.0 * near / (top - bottom);
  9443. var column2Row0 = (right + left) / (right - left);
  9444. var column2Row1 = (top + bottom) / (top - bottom);
  9445. var column2Row2 = -(far + near) / (far - near);
  9446. var column2Row3 = -1.0;
  9447. var column3Row2 = -2.0 * far * near / (far - near);
  9448. result[0] = column0Row0;
  9449. result[1] = 0.0;
  9450. result[2] = 0.0;
  9451. result[3] = 0.0;
  9452. result[4] = 0.0;
  9453. result[5] = column1Row1;
  9454. result[6] = 0.0;
  9455. result[7] = 0.0;
  9456. result[8] = column2Row0;
  9457. result[9] = column2Row1;
  9458. result[10] = column2Row2;
  9459. result[11] = column2Row3;
  9460. result[12] = 0.0;
  9461. result[13] = 0.0;
  9462. result[14] = column3Row2;
  9463. result[15] = 0.0;
  9464. return result;
  9465. };
  9466. /**
  9467. * Computes a Matrix4 instance representing an infinite off center perspective transformation.
  9468. *
  9469. * @param {Number} left The number of meters to the left of the camera that will be in view.
  9470. * @param {Number} right The number of meters to the right of the camera that will be in view.
  9471. * @param {Number} bottom The number of meters below of the camera that will be in view.
  9472. * @param {Number} top The number of meters above of the camera that will be in view.
  9473. * @param {Number} near The distance to the near plane in meters.
  9474. * @param {Matrix4} result The object in which the result will be stored.
  9475. * @returns {Matrix4} The modified result parameter.
  9476. */
  9477. Matrix4.computeInfinitePerspectiveOffCenter = function(left, right, bottom, top, near, result) {
  9478. if (!defined(left)) {
  9479. throw new DeveloperError('left is required.');
  9480. }
  9481. if (!defined(right)) {
  9482. throw new DeveloperError('right is required.');
  9483. }
  9484. if (!defined(bottom)) {
  9485. throw new DeveloperError('bottom is required.');
  9486. }
  9487. if (!defined(top)) {
  9488. throw new DeveloperError('top is required.');
  9489. }
  9490. if (!defined(near)) {
  9491. throw new DeveloperError('near is required.');
  9492. }
  9493. if (!defined(result)) {
  9494. throw new DeveloperError('result is required');
  9495. }
  9496. var column0Row0 = 2.0 * near / (right - left);
  9497. var column1Row1 = 2.0 * near / (top - bottom);
  9498. var column2Row0 = (right + left) / (right - left);
  9499. var column2Row1 = (top + bottom) / (top - bottom);
  9500. var column2Row2 = -1.0;
  9501. var column2Row3 = -1.0;
  9502. var column3Row2 = -2.0 * near;
  9503. result[0] = column0Row0;
  9504. result[1] = 0.0;
  9505. result[2] = 0.0;
  9506. result[3] = 0.0;
  9507. result[4] = 0.0;
  9508. result[5] = column1Row1;
  9509. result[6] = 0.0;
  9510. result[7] = 0.0;
  9511. result[8] = column2Row0;
  9512. result[9] = column2Row1;
  9513. result[10] = column2Row2;
  9514. result[11] = column2Row3;
  9515. result[12] = 0.0;
  9516. result[13] = 0.0;
  9517. result[14] = column3Row2;
  9518. result[15] = 0.0;
  9519. return result;
  9520. };
  9521. /**
  9522. * Computes a Matrix4 instance that transforms from normalized device coordinates to window coordinates.
  9523. *
  9524. * @param {Object}[viewport = { x : 0.0, y : 0.0, width : 0.0, height : 0.0 }] The viewport's corners as shown in Example 1.
  9525. * @param {Number}[nearDepthRange=0.0] The near plane distance in window coordinates.
  9526. * @param {Number}[farDepthRange=1.0] The far plane distance in window coordinates.
  9527. * @param {Matrix4} result The object in which the result will be stored.
  9528. * @returns {Matrix4} The modified result parameter.
  9529. *
  9530. * @example
  9531. * // Create viewport transformation using an explicit viewport and depth range.
  9532. * var m = Cesium.Matrix4.computeViewportTransformation({
  9533. * x : 0.0,
  9534. * y : 0.0,
  9535. * width : 1024.0,
  9536. * height : 768.0
  9537. * }, 0.0, 1.0, new Cesium.Matrix4());
  9538. */
  9539. Matrix4.computeViewportTransformation = function(viewport, nearDepthRange, farDepthRange, result) {
  9540. if (!defined(result)) {
  9541. throw new DeveloperError('result is required');
  9542. }
  9543. viewport = defaultValue(viewport, defaultValue.EMPTY_OBJECT);
  9544. var x = defaultValue(viewport.x, 0.0);
  9545. var y = defaultValue(viewport.y, 0.0);
  9546. var width = defaultValue(viewport.width, 0.0);
  9547. var height = defaultValue(viewport.height, 0.0);
  9548. nearDepthRange = defaultValue(nearDepthRange, 0.0);
  9549. farDepthRange = defaultValue(farDepthRange, 1.0);
  9550. var halfWidth = width * 0.5;
  9551. var halfHeight = height * 0.5;
  9552. var halfDepth = (farDepthRange - nearDepthRange) * 0.5;
  9553. var column0Row0 = halfWidth;
  9554. var column1Row1 = halfHeight;
  9555. var column2Row2 = halfDepth;
  9556. var column3Row0 = x + halfWidth;
  9557. var column3Row1 = y + halfHeight;
  9558. var column3Row2 = nearDepthRange + halfDepth;
  9559. var column3Row3 = 1.0;
  9560. result[0] = column0Row0;
  9561. result[1] = 0.0;
  9562. result[2] = 0.0;
  9563. result[3] = 0.0;
  9564. result[4] = 0.0;
  9565. result[5] = column1Row1;
  9566. result[6] = 0.0;
  9567. result[7] = 0.0;
  9568. result[8] = 0.0;
  9569. result[9] = 0.0;
  9570. result[10] = column2Row2;
  9571. result[11] = 0.0;
  9572. result[12] = column3Row0;
  9573. result[13] = column3Row1;
  9574. result[14] = column3Row2;
  9575. result[15] = column3Row3;
  9576. return result;
  9577. };
  9578. /**
  9579. * Computes a Matrix4 instance that transforms from world space to view space.
  9580. *
  9581. * @param {Cartesian3} position The position of the camera.
  9582. * @param {Cartesian3} direction The forward direction.
  9583. * @param {Cartesian3} up The up direction.
  9584. * @param {Cartesian3} right The right direction.
  9585. * @param {Matrix4} result The object in which the result will be stored.
  9586. * @returns {Matrix4} The modified result parameter.
  9587. */
  9588. Matrix4.computeView = function(position, direction, up, right, result) {
  9589. if (!defined(position)) {
  9590. throw new DeveloperError('position is required');
  9591. }
  9592. if (!defined(direction)) {
  9593. throw new DeveloperError('direction is required');
  9594. }
  9595. if (!defined(up)) {
  9596. throw new DeveloperError('up is required');
  9597. }
  9598. if (!defined(right)) {
  9599. throw new DeveloperError('right is required');
  9600. }
  9601. if (!defined(result)) {
  9602. throw new DeveloperError('result is required');
  9603. }
  9604. result[0] = right.x;
  9605. result[1] = up.x;
  9606. result[2] = -direction.x;
  9607. result[3] = 0.0;
  9608. result[4] = right.y;
  9609. result[5] = up.y;
  9610. result[6] = -direction.y;
  9611. result[7] = 0.0;
  9612. result[8] = right.z;
  9613. result[9] = up.z;
  9614. result[10] = -direction.z;
  9615. result[11] = 0.0;
  9616. result[12] = -Cartesian3.dot(right, position);
  9617. result[13] = -Cartesian3.dot(up, position);
  9618. result[14] = Cartesian3.dot(direction, position);
  9619. result[15] = 1.0;
  9620. return result;
  9621. };
  9622. /**
  9623. * Computes an Array from the provided Matrix4 instance.
  9624. * The array will be in column-major order.
  9625. *
  9626. * @param {Matrix4} matrix The matrix to use..
  9627. * @param {Number[]} [result] The Array onto which to store the result.
  9628. * @returns {Number[]} The modified Array parameter or a new Array instance if one was not provided.
  9629. *
  9630. * @example
  9631. * //create an array from an instance of Matrix4
  9632. * // m = [10.0, 14.0, 18.0, 22.0]
  9633. * // [11.0, 15.0, 19.0, 23.0]
  9634. * // [12.0, 16.0, 20.0, 24.0]
  9635. * // [13.0, 17.0, 21.0, 25.0]
  9636. * var a = Cesium.Matrix4.toArray(m);
  9637. *
  9638. * // m remains the same
  9639. * //creates a = [10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0]
  9640. */
  9641. Matrix4.toArray = function(matrix, result) {
  9642. if (!defined(matrix)) {
  9643. throw new DeveloperError('matrix is required');
  9644. }
  9645. if (!defined(result)) {
  9646. return [matrix[0], matrix[1], matrix[2], matrix[3],
  9647. matrix[4], matrix[5], matrix[6], matrix[7],
  9648. matrix[8], matrix[9], matrix[10], matrix[11],
  9649. matrix[12], matrix[13], matrix[14], matrix[15]];
  9650. }
  9651. result[0] = matrix[0];
  9652. result[1] = matrix[1];
  9653. result[2] = matrix[2];
  9654. result[3] = matrix[3];
  9655. result[4] = matrix[4];
  9656. result[5] = matrix[5];
  9657. result[6] = matrix[6];
  9658. result[7] = matrix[7];
  9659. result[8] = matrix[8];
  9660. result[9] = matrix[9];
  9661. result[10] = matrix[10];
  9662. result[11] = matrix[11];
  9663. result[12] = matrix[12];
  9664. result[13] = matrix[13];
  9665. result[14] = matrix[14];
  9666. result[15] = matrix[15];
  9667. return result;
  9668. };
  9669. /**
  9670. * Computes the array index of the element at the provided row and column.
  9671. *
  9672. * @param {Number} row The zero-based index of the row.
  9673. * @param {Number} column The zero-based index of the column.
  9674. * @returns {Number} The index of the element at the provided row and column.
  9675. *
  9676. * @exception {DeveloperError} row must be 0, 1, 2, or 3.
  9677. * @exception {DeveloperError} column must be 0, 1, 2, or 3.
  9678. *
  9679. * @example
  9680. * var myMatrix = new Cesium.Matrix4();
  9681. * var column1Row0Index = Cesium.Matrix4.getElementIndex(1, 0);
  9682. * var column1Row0 = myMatrix[column1Row0Index];
  9683. * myMatrix[column1Row0Index] = 10.0;
  9684. */
  9685. Matrix4.getElementIndex = function(column, row) {
  9686. if (typeof row !== 'number' || row < 0 || row > 3) {
  9687. throw new DeveloperError('row must be 0, 1, 2, or 3.');
  9688. }
  9689. if (typeof column !== 'number' || column < 0 || column > 3) {
  9690. throw new DeveloperError('column must be 0, 1, 2, or 3.');
  9691. }
  9692. return column * 4 + row;
  9693. };
  9694. /**
  9695. * Retrieves a copy of the matrix column at the provided index as a Cartesian4 instance.
  9696. *
  9697. * @param {Matrix4} matrix The matrix to use.
  9698. * @param {Number} index The zero-based index of the column to retrieve.
  9699. * @param {Cartesian4} result The object onto which to store the result.
  9700. * @returns {Cartesian4} The modified result parameter.
  9701. *
  9702. * @exception {DeveloperError} index must be 0, 1, 2, or 3.
  9703. *
  9704. * @example
  9705. * //returns a Cartesian4 instance with values from the specified column
  9706. * // m = [10.0, 11.0, 12.0, 13.0]
  9707. * // [14.0, 15.0, 16.0, 17.0]
  9708. * // [18.0, 19.0, 20.0, 21.0]
  9709. * // [22.0, 23.0, 24.0, 25.0]
  9710. *
  9711. * //Example 1: Creates an instance of Cartesian
  9712. * var a = Cesium.Matrix4.getColumn(m, 2, new Cesium.Cartesian4());
  9713. *
  9714. * @example
  9715. * //Example 2: Sets values for Cartesian instance
  9716. * var a = new Cesium.Cartesian4();
  9717. * Cesium.Matrix4.getColumn(m, 2, a);
  9718. *
  9719. * // a.x = 12.0; a.y = 16.0; a.z = 20.0; a.w = 24.0;
  9720. */
  9721. Matrix4.getColumn = function(matrix, index, result) {
  9722. if (!defined(matrix)) {
  9723. throw new DeveloperError('matrix is required.');
  9724. }
  9725. if (typeof index !== 'number' || index < 0 || index > 3) {
  9726. throw new DeveloperError('index must be 0, 1, 2, or 3.');
  9727. }
  9728. if (!defined(result)) {
  9729. throw new DeveloperError('result is required');
  9730. }
  9731. var startIndex = index * 4;
  9732. var x = matrix[startIndex];
  9733. var y = matrix[startIndex + 1];
  9734. var z = matrix[startIndex + 2];
  9735. var w = matrix[startIndex + 3];
  9736. result.x = x;
  9737. result.y = y;
  9738. result.z = z;
  9739. result.w = w;
  9740. return result;
  9741. };
  9742. /**
  9743. * Computes a new matrix that replaces the specified column in the provided matrix with the provided Cartesian4 instance.
  9744. *
  9745. * @param {Matrix4} matrix The matrix to use.
  9746. * @param {Number} index The zero-based index of the column to set.
  9747. * @param {Cartesian4} cartesian The Cartesian whose values will be assigned to the specified column.
  9748. * @param {Matrix4} result The object onto which to store the result.
  9749. * @returns {Matrix4} The modified result parameter.
  9750. *
  9751. * @exception {DeveloperError} index must be 0, 1, 2, or 3.
  9752. *
  9753. * @example
  9754. * //creates a new Matrix4 instance with new column values from the Cartesian4 instance
  9755. * // m = [10.0, 11.0, 12.0, 13.0]
  9756. * // [14.0, 15.0, 16.0, 17.0]
  9757. * // [18.0, 19.0, 20.0, 21.0]
  9758. * // [22.0, 23.0, 24.0, 25.0]
  9759. *
  9760. * var a = Cesium.Matrix4.setColumn(m, 2, new Cesium.Cartesian4(99.0, 98.0, 97.0, 96.0), new Cesium.Matrix4());
  9761. *
  9762. * // m remains the same
  9763. * // a = [10.0, 11.0, 99.0, 13.0]
  9764. * // [14.0, 15.0, 98.0, 17.0]
  9765. * // [18.0, 19.0, 97.0, 21.0]
  9766. * // [22.0, 23.0, 96.0, 25.0]
  9767. */
  9768. Matrix4.setColumn = function(matrix, index, cartesian, result) {
  9769. if (!defined(matrix)) {
  9770. throw new DeveloperError('matrix is required');
  9771. }
  9772. if (!defined(cartesian)) {
  9773. throw new DeveloperError('cartesian is required');
  9774. }
  9775. if (typeof index !== 'number' || index < 0 || index > 3) {
  9776. throw new DeveloperError('index must be 0, 1, 2, or 3.');
  9777. }
  9778. if (!defined(result)) {
  9779. throw new DeveloperError('result is required');
  9780. }
  9781. result = Matrix4.clone(matrix, result);
  9782. var startIndex = index * 4;
  9783. result[startIndex] = cartesian.x;
  9784. result[startIndex + 1] = cartesian.y;
  9785. result[startIndex + 2] = cartesian.z;
  9786. result[startIndex + 3] = cartesian.w;
  9787. return result;
  9788. };
  9789. /**
  9790. * Computes a new matrix that replaces the translation in the rightmost column of the provided
  9791. * matrix with the provided translation. This assumes the matrix is an affine transformation
  9792. *
  9793. * @param {Matrix4} matrix The matrix to use.
  9794. * @param {Cartesian3} translation The translation that replaces the translation of the provided matrix.
  9795. * @param {Cartesian4} result The object onto which to store the result.
  9796. * @returns {Matrix4} The modified result parameter.
  9797. */
  9798. Matrix4.setTranslation = function(matrix, translation, result) {
  9799. if (!defined(matrix)) {
  9800. throw new DeveloperError('matrix is required');
  9801. }
  9802. if (!defined(translation)) {
  9803. throw new DeveloperError('translation is required');
  9804. }
  9805. if (!defined(result)) {
  9806. throw new DeveloperError('result is required');
  9807. }
  9808. result[0] = matrix[0];
  9809. result[1] = matrix[1];
  9810. result[2] = matrix[2];
  9811. result[3] = matrix[3];
  9812. result[4] = matrix[4];
  9813. result[5] = matrix[5];
  9814. result[6] = matrix[6];
  9815. result[7] = matrix[7];
  9816. result[8] = matrix[8];
  9817. result[9] = matrix[9];
  9818. result[10] = matrix[10];
  9819. result[11] = matrix[11];
  9820. result[12] = translation.x;
  9821. result[13] = translation.y;
  9822. result[14] = translation.z;
  9823. result[15] = matrix[15];
  9824. return result;
  9825. };
  9826. /**
  9827. * Retrieves a copy of the matrix row at the provided index as a Cartesian4 instance.
  9828. *
  9829. * @param {Matrix4} matrix The matrix to use.
  9830. * @param {Number} index The zero-based index of the row to retrieve.
  9831. * @param {Cartesian4} result The object onto which to store the result.
  9832. * @returns {Cartesian4} The modified result parameter.
  9833. *
  9834. * @exception {DeveloperError} index must be 0, 1, 2, or 3.
  9835. *
  9836. * @example
  9837. * //returns a Cartesian4 instance with values from the specified column
  9838. * // m = [10.0, 11.0, 12.0, 13.0]
  9839. * // [14.0, 15.0, 16.0, 17.0]
  9840. * // [18.0, 19.0, 20.0, 21.0]
  9841. * // [22.0, 23.0, 24.0, 25.0]
  9842. *
  9843. * //Example 1: Returns an instance of Cartesian
  9844. * var a = Cesium.Matrix4.getRow(m, 2, new Cesium.Cartesian4());
  9845. *
  9846. * @example
  9847. * //Example 2: Sets values for a Cartesian instance
  9848. * var a = new Cesium.Cartesian4();
  9849. * Cesium.Matrix4.getRow(m, 2, a);
  9850. *
  9851. * // a.x = 18.0; a.y = 19.0; a.z = 20.0; a.w = 21.0;
  9852. */
  9853. Matrix4.getRow = function(matrix, index, result) {
  9854. if (!defined(matrix)) {
  9855. throw new DeveloperError('matrix is required.');
  9856. }
  9857. if (typeof index !== 'number' || index < 0 || index > 3) {
  9858. throw new DeveloperError('index must be 0, 1, 2, or 3.');
  9859. }
  9860. if (!defined(result)) {
  9861. throw new DeveloperError('result is required');
  9862. }
  9863. var x = matrix[index];
  9864. var y = matrix[index + 4];
  9865. var z = matrix[index + 8];
  9866. var w = matrix[index + 12];
  9867. result.x = x;
  9868. result.y = y;
  9869. result.z = z;
  9870. result.w = w;
  9871. return result;
  9872. };
  9873. /**
  9874. * Computes a new matrix that replaces the specified row in the provided matrix with the provided Cartesian4 instance.
  9875. *
  9876. * @param {Matrix4} matrix The matrix to use.
  9877. * @param {Number} index The zero-based index of the row to set.
  9878. * @param {Cartesian4} cartesian The Cartesian whose values will be assigned to the specified row.
  9879. * @param {Matrix4} result The object onto which to store the result.
  9880. * @returns {Matrix4} The modified result parameter.
  9881. *
  9882. * @exception {DeveloperError} index must be 0, 1, 2, or 3.
  9883. *
  9884. * @example
  9885. * //create a new Matrix4 instance with new row values from the Cartesian4 instance
  9886. * // m = [10.0, 11.0, 12.0, 13.0]
  9887. * // [14.0, 15.0, 16.0, 17.0]
  9888. * // [18.0, 19.0, 20.0, 21.0]
  9889. * // [22.0, 23.0, 24.0, 25.0]
  9890. *
  9891. * var a = Cesium.Matrix4.setRow(m, 2, new Cesium.Cartesian4(99.0, 98.0, 97.0, 96.0), new Cesium.Matrix4());
  9892. *
  9893. * // m remains the same
  9894. * // a = [10.0, 11.0, 12.0, 13.0]
  9895. * // [14.0, 15.0, 16.0, 17.0]
  9896. * // [99.0, 98.0, 97.0, 96.0]
  9897. * // [22.0, 23.0, 24.0, 25.0]
  9898. */
  9899. Matrix4.setRow = function(matrix, index, cartesian, result) {
  9900. if (!defined(matrix)) {
  9901. throw new DeveloperError('matrix is required');
  9902. }
  9903. if (!defined(cartesian)) {
  9904. throw new DeveloperError('cartesian is required');
  9905. }
  9906. if (typeof index !== 'number' || index < 0 || index > 3) {
  9907. throw new DeveloperError('index must be 0, 1, 2, or 3.');
  9908. }
  9909. if (!defined(result)) {
  9910. throw new DeveloperError('result is required');
  9911. }
  9912. result = Matrix4.clone(matrix, result);
  9913. result[index] = cartesian.x;
  9914. result[index + 4] = cartesian.y;
  9915. result[index + 8] = cartesian.z;
  9916. result[index + 12] = cartesian.w;
  9917. return result;
  9918. };
  9919. var scratchColumn = new Cartesian3();
  9920. /**
  9921. * Extracts the non-uniform scale assuming the matrix is an affine transformation.
  9922. *
  9923. * @param {Matrix4} matrix The matrix.
  9924. * @param {Cartesian3} result The object onto which to store the result.
  9925. * @returns {Cartesian3} The modified result parameter
  9926. */
  9927. Matrix4.getScale = function(matrix, result) {
  9928. if (!defined(matrix)) {
  9929. throw new DeveloperError('matrix is required.');
  9930. }
  9931. if (!defined(result)) {
  9932. throw new DeveloperError('result is required');
  9933. }
  9934. result.x = Cartesian3.magnitude(Cartesian3.fromElements(matrix[0], matrix[1], matrix[2], scratchColumn));
  9935. result.y = Cartesian3.magnitude(Cartesian3.fromElements(matrix[4], matrix[5], matrix[6], scratchColumn));
  9936. result.z = Cartesian3.magnitude(Cartesian3.fromElements(matrix[8], matrix[9], matrix[10], scratchColumn));
  9937. return result;
  9938. };
  9939. var scratchScale = new Cartesian3();
  9940. /**
  9941. * Computes the maximum scale assuming the matrix is an affine transformation.
  9942. * The maximum scale is the maximum length of the column vectors in the upper-left
  9943. * 3x3 matrix.
  9944. *
  9945. * @param {Matrix4} matrix The matrix.
  9946. * @returns {Number} The maximum scale.
  9947. */
  9948. Matrix4.getMaximumScale = function(matrix) {
  9949. Matrix4.getScale(matrix, scratchScale);
  9950. return Cartesian3.maximumComponent(scratchScale);
  9951. };
  9952. /**
  9953. * Computes the product of two matrices.
  9954. *
  9955. * @param {Matrix4} left The first matrix.
  9956. * @param {Matrix4} right The second matrix.
  9957. * @param {Matrix4} result The object onto which to store the result.
  9958. * @returns {Matrix4} The modified result parameter.
  9959. */
  9960. Matrix4.multiply = function(left, right, result) {
  9961. if (!defined(left)) {
  9962. throw new DeveloperError('left is required');
  9963. }
  9964. if (!defined(right)) {
  9965. throw new DeveloperError('right is required');
  9966. }
  9967. if (!defined(result)) {
  9968. throw new DeveloperError('result is required');
  9969. }
  9970. var left0 = left[0];
  9971. var left1 = left[1];
  9972. var left2 = left[2];
  9973. var left3 = left[3];
  9974. var left4 = left[4];
  9975. var left5 = left[5];
  9976. var left6 = left[6];
  9977. var left7 = left[7];
  9978. var left8 = left[8];
  9979. var left9 = left[9];
  9980. var left10 = left[10];
  9981. var left11 = left[11];
  9982. var left12 = left[12];
  9983. var left13 = left[13];
  9984. var left14 = left[14];
  9985. var left15 = left[15];
  9986. var right0 = right[0];
  9987. var right1 = right[1];
  9988. var right2 = right[2];
  9989. var right3 = right[3];
  9990. var right4 = right[4];
  9991. var right5 = right[5];
  9992. var right6 = right[6];
  9993. var right7 = right[7];
  9994. var right8 = right[8];
  9995. var right9 = right[9];
  9996. var right10 = right[10];
  9997. var right11 = right[11];
  9998. var right12 = right[12];
  9999. var right13 = right[13];
  10000. var right14 = right[14];
  10001. var right15 = right[15];
  10002. var column0Row0 = left0 * right0 + left4 * right1 + left8 * right2 + left12 * right3;
  10003. var column0Row1 = left1 * right0 + left5 * right1 + left9 * right2 + left13 * right3;
  10004. var column0Row2 = left2 * right0 + left6 * right1 + left10 * right2 + left14 * right3;
  10005. var column0Row3 = left3 * right0 + left7 * right1 + left11 * right2 + left15 * right3;
  10006. var column1Row0 = left0 * right4 + left4 * right5 + left8 * right6 + left12 * right7;
  10007. var column1Row1 = left1 * right4 + left5 * right5 + left9 * right6 + left13 * right7;
  10008. var column1Row2 = left2 * right4 + left6 * right5 + left10 * right6 + left14 * right7;
  10009. var column1Row3 = left3 * right4 + left7 * right5 + left11 * right6 + left15 * right7;
  10010. var column2Row0 = left0 * right8 + left4 * right9 + left8 * right10 + left12 * right11;
  10011. var column2Row1 = left1 * right8 + left5 * right9 + left9 * right10 + left13 * right11;
  10012. var column2Row2 = left2 * right8 + left6 * right9 + left10 * right10 + left14 * right11;
  10013. var column2Row3 = left3 * right8 + left7 * right9 + left11 * right10 + left15 * right11;
  10014. var column3Row0 = left0 * right12 + left4 * right13 + left8 * right14 + left12 * right15;
  10015. var column3Row1 = left1 * right12 + left5 * right13 + left9 * right14 + left13 * right15;
  10016. var column3Row2 = left2 * right12 + left6 * right13 + left10 * right14 + left14 * right15;
  10017. var column3Row3 = left3 * right12 + left7 * right13 + left11 * right14 + left15 * right15;
  10018. result[0] = column0Row0;
  10019. result[1] = column0Row1;
  10020. result[2] = column0Row2;
  10021. result[3] = column0Row3;
  10022. result[4] = column1Row0;
  10023. result[5] = column1Row1;
  10024. result[6] = column1Row2;
  10025. result[7] = column1Row3;
  10026. result[8] = column2Row0;
  10027. result[9] = column2Row1;
  10028. result[10] = column2Row2;
  10029. result[11] = column2Row3;
  10030. result[12] = column3Row0;
  10031. result[13] = column3Row1;
  10032. result[14] = column3Row2;
  10033. result[15] = column3Row3;
  10034. return result;
  10035. };
  10036. /**
  10037. * Computes the sum of two matrices.
  10038. *
  10039. * @param {Matrix4} left The first matrix.
  10040. * @param {Matrix4} right The second matrix.
  10041. * @param {Matrix4} result The object onto which to store the result.
  10042. * @returns {Matrix4} The modified result parameter.
  10043. */
  10044. Matrix4.add = function(left, right, result) {
  10045. if (!defined(left)) {
  10046. throw new DeveloperError('left is required');
  10047. }
  10048. if (!defined(right)) {
  10049. throw new DeveloperError('right is required');
  10050. }
  10051. if (!defined(result)) {
  10052. throw new DeveloperError('result is required');
  10053. }
  10054. result[0] = left[0] + right[0];
  10055. result[1] = left[1] + right[1];
  10056. result[2] = left[2] + right[2];
  10057. result[3] = left[3] + right[3];
  10058. result[4] = left[4] + right[4];
  10059. result[5] = left[5] + right[5];
  10060. result[6] = left[6] + right[6];
  10061. result[7] = left[7] + right[7];
  10062. result[8] = left[8] + right[8];
  10063. result[9] = left[9] + right[9];
  10064. result[10] = left[10] + right[10];
  10065. result[11] = left[11] + right[11];
  10066. result[12] = left[12] + right[12];
  10067. result[13] = left[13] + right[13];
  10068. result[14] = left[14] + right[14];
  10069. result[15] = left[15] + right[15];
  10070. return result;
  10071. };
  10072. /**
  10073. * Computes the difference of two matrices.
  10074. *
  10075. * @param {Matrix4} left The first matrix.
  10076. * @param {Matrix4} right The second matrix.
  10077. * @param {Matrix4} result The object onto which to store the result.
  10078. * @returns {Matrix4} The modified result parameter.
  10079. */
  10080. Matrix4.subtract = function(left, right, result) {
  10081. if (!defined(left)) {
  10082. throw new DeveloperError('left is required');
  10083. }
  10084. if (!defined(right)) {
  10085. throw new DeveloperError('right is required');
  10086. }
  10087. if (!defined(result)) {
  10088. throw new DeveloperError('result is required');
  10089. }
  10090. result[0] = left[0] - right[0];
  10091. result[1] = left[1] - right[1];
  10092. result[2] = left[2] - right[2];
  10093. result[3] = left[3] - right[3];
  10094. result[4] = left[4] - right[4];
  10095. result[5] = left[5] - right[5];
  10096. result[6] = left[6] - right[6];
  10097. result[7] = left[7] - right[7];
  10098. result[8] = left[8] - right[8];
  10099. result[9] = left[9] - right[9];
  10100. result[10] = left[10] - right[10];
  10101. result[11] = left[11] - right[11];
  10102. result[12] = left[12] - right[12];
  10103. result[13] = left[13] - right[13];
  10104. result[14] = left[14] - right[14];
  10105. result[15] = left[15] - right[15];
  10106. return result;
  10107. };
  10108. /**
  10109. * Computes the product of two matrices assuming the matrices are
  10110. * affine transformation matrices, where the upper left 3x3 elements
  10111. * are a rotation matrix, and the upper three elements in the fourth
  10112. * column are the translation. The bottom row is assumed to be [0, 0, 0, 1].
  10113. * The matrix is not verified to be in the proper form.
  10114. * This method is faster than computing the product for general 4x4
  10115. * matrices using {@link Matrix4.multiply}.
  10116. *
  10117. * @param {Matrix4} left The first matrix.
  10118. * @param {Matrix4} right The second matrix.
  10119. * @param {Matrix4} result The object onto which to store the result.
  10120. * @returns {Matrix4} The modified result parameter.
  10121. *
  10122. * @example
  10123. * var m1 = new Cesium.Matrix4(1.0, 6.0, 7.0, 0.0, 2.0, 5.0, 8.0, 0.0, 3.0, 4.0, 9.0, 0.0, 0.0, 0.0, 0.0, 1.0);
  10124. * var m2 = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3(1.0, 1.0, 1.0));
  10125. * var m3 = Cesium.Matrix4.multiplyTransformation(m1, m2, new Cesium.Matrix4());
  10126. */
  10127. Matrix4.multiplyTransformation = function(left, right, result) {
  10128. if (!defined(left)) {
  10129. throw new DeveloperError('left is required');
  10130. }
  10131. if (!defined(right)) {
  10132. throw new DeveloperError('right is required');
  10133. }
  10134. if (!defined(result)) {
  10135. throw new DeveloperError('result is required');
  10136. }
  10137. var left0 = left[0];
  10138. var left1 = left[1];
  10139. var left2 = left[2];
  10140. var left4 = left[4];
  10141. var left5 = left[5];
  10142. var left6 = left[6];
  10143. var left8 = left[8];
  10144. var left9 = left[9];
  10145. var left10 = left[10];
  10146. var left12 = left[12];
  10147. var left13 = left[13];
  10148. var left14 = left[14];
  10149. var right0 = right[0];
  10150. var right1 = right[1];
  10151. var right2 = right[2];
  10152. var right4 = right[4];
  10153. var right5 = right[5];
  10154. var right6 = right[6];
  10155. var right8 = right[8];
  10156. var right9 = right[9];
  10157. var right10 = right[10];
  10158. var right12 = right[12];
  10159. var right13 = right[13];
  10160. var right14 = right[14];
  10161. var column0Row0 = left0 * right0 + left4 * right1 + left8 * right2;
  10162. var column0Row1 = left1 * right0 + left5 * right1 + left9 * right2;
  10163. var column0Row2 = left2 * right0 + left6 * right1 + left10 * right2;
  10164. var column1Row0 = left0 * right4 + left4 * right5 + left8 * right6;
  10165. var column1Row1 = left1 * right4 + left5 * right5 + left9 * right6;
  10166. var column1Row2 = left2 * right4 + left6 * right5 + left10 * right6;
  10167. var column2Row0 = left0 * right8 + left4 * right9 + left8 * right10;
  10168. var column2Row1 = left1 * right8 + left5 * right9 + left9 * right10;
  10169. var column2Row2 = left2 * right8 + left6 * right9 + left10 * right10;
  10170. var column3Row0 = left0 * right12 + left4 * right13 + left8 * right14 + left12;
  10171. var column3Row1 = left1 * right12 + left5 * right13 + left9 * right14 + left13;
  10172. var column3Row2 = left2 * right12 + left6 * right13 + left10 * right14 + left14;
  10173. result[0] = column0Row0;
  10174. result[1] = column0Row1;
  10175. result[2] = column0Row2;
  10176. result[3] = 0.0;
  10177. result[4] = column1Row0;
  10178. result[5] = column1Row1;
  10179. result[6] = column1Row2;
  10180. result[7] = 0.0;
  10181. result[8] = column2Row0;
  10182. result[9] = column2Row1;
  10183. result[10] = column2Row2;
  10184. result[11] = 0.0;
  10185. result[12] = column3Row0;
  10186. result[13] = column3Row1;
  10187. result[14] = column3Row2;
  10188. result[15] = 1.0;
  10189. return result;
  10190. };
  10191. /**
  10192. * Multiplies a transformation matrix (with a bottom row of <code>[0.0, 0.0, 0.0, 1.0]</code>)
  10193. * by a 3x3 rotation matrix. This is an optimization
  10194. * for <code>Matrix4.multiply(m, Matrix4.fromRotationTranslation(rotation), m);</code> with less allocations and arithmetic operations.
  10195. *
  10196. * @param {Matrix4} matrix The matrix on the left-hand side.
  10197. * @param {Matrix3} rotation The 3x3 rotation matrix on the right-hand side.
  10198. * @param {Matrix4} result The object onto which to store the result.
  10199. * @returns {Matrix4} The modified result parameter.
  10200. *
  10201. * @example
  10202. * // Instead of Cesium.Matrix4.multiply(m, Cesium.Matrix4.fromRotationTranslation(rotation), m);
  10203. * Cesium.Matrix4.multiplyByMatrix3(m, rotation, m);
  10204. */
  10205. Matrix4.multiplyByMatrix3 = function(matrix, rotation, result) {
  10206. if (!defined(matrix)) {
  10207. throw new DeveloperError('matrix is required');
  10208. }
  10209. if (!defined(rotation)) {
  10210. throw new DeveloperError('rotation is required');
  10211. }
  10212. if (!defined(result)) {
  10213. throw new DeveloperError('result is required');
  10214. }
  10215. var left0 = matrix[0];
  10216. var left1 = matrix[1];
  10217. var left2 = matrix[2];
  10218. var left4 = matrix[4];
  10219. var left5 = matrix[5];
  10220. var left6 = matrix[6];
  10221. var left8 = matrix[8];
  10222. var left9 = matrix[9];
  10223. var left10 = matrix[10];
  10224. var right0 = rotation[0];
  10225. var right1 = rotation[1];
  10226. var right2 = rotation[2];
  10227. var right4 = rotation[3];
  10228. var right5 = rotation[4];
  10229. var right6 = rotation[5];
  10230. var right8 = rotation[6];
  10231. var right9 = rotation[7];
  10232. var right10 = rotation[8];
  10233. var column0Row0 = left0 * right0 + left4 * right1 + left8 * right2;
  10234. var column0Row1 = left1 * right0 + left5 * right1 + left9 * right2;
  10235. var column0Row2 = left2 * right0 + left6 * right1 + left10 * right2;
  10236. var column1Row0 = left0 * right4 + left4 * right5 + left8 * right6;
  10237. var column1Row1 = left1 * right4 + left5 * right5 + left9 * right6;
  10238. var column1Row2 = left2 * right4 + left6 * right5 + left10 * right6;
  10239. var column2Row0 = left0 * right8 + left4 * right9 + left8 * right10;
  10240. var column2Row1 = left1 * right8 + left5 * right9 + left9 * right10;
  10241. var column2Row2 = left2 * right8 + left6 * right9 + left10 * right10;
  10242. result[0] = column0Row0;
  10243. result[1] = column0Row1;
  10244. result[2] = column0Row2;
  10245. result[3] = 0.0;
  10246. result[4] = column1Row0;
  10247. result[5] = column1Row1;
  10248. result[6] = column1Row2;
  10249. result[7] = 0.0;
  10250. result[8] = column2Row0;
  10251. result[9] = column2Row1;
  10252. result[10] = column2Row2;
  10253. result[11] = 0.0;
  10254. result[12] = matrix[12];
  10255. result[13] = matrix[13];
  10256. result[14] = matrix[14];
  10257. result[15] = matrix[15];
  10258. return result;
  10259. };
  10260. /**
  10261. * Multiplies a transformation matrix (with a bottom row of <code>[0.0, 0.0, 0.0, 1.0]</code>)
  10262. * by an implicit translation matrix defined by a {@link Cartesian3}. This is an optimization
  10263. * for <code>Matrix4.multiply(m, Matrix4.fromTranslation(position), m);</code> with less allocations and arithmetic operations.
  10264. *
  10265. * @param {Matrix4} matrix The matrix on the left-hand side.
  10266. * @param {Cartesian3} translation The translation on the right-hand side.
  10267. * @param {Matrix4} result The object onto which to store the result.
  10268. * @returns {Matrix4} The modified result parameter.
  10269. *
  10270. * @example
  10271. * // Instead of Cesium.Matrix4.multiply(m, Cesium.Matrix4.fromTranslation(position), m);
  10272. * Cesium.Matrix4.multiplyByTranslation(m, position, m);
  10273. */
  10274. Matrix4.multiplyByTranslation = function(matrix, translation, result) {
  10275. if (!defined(matrix)) {
  10276. throw new DeveloperError('matrix is required');
  10277. }
  10278. if (!defined(translation)) {
  10279. throw new DeveloperError('translation is required');
  10280. }
  10281. if (!defined(result)) {
  10282. throw new DeveloperError('result is required');
  10283. }
  10284. var x = translation.x;
  10285. var y = translation.y;
  10286. var z = translation.z;
  10287. var tx = (x * matrix[0]) + (y * matrix[4]) + (z * matrix[8]) + matrix[12];
  10288. var ty = (x * matrix[1]) + (y * matrix[5]) + (z * matrix[9]) + matrix[13];
  10289. var tz = (x * matrix[2]) + (y * matrix[6]) + (z * matrix[10]) + matrix[14];
  10290. result[0] = matrix[0];
  10291. result[1] = matrix[1];
  10292. result[2] = matrix[2];
  10293. result[3] = matrix[3];
  10294. result[4] = matrix[4];
  10295. result[5] = matrix[5];
  10296. result[6] = matrix[6];
  10297. result[7] = matrix[7];
  10298. result[8] = matrix[8];
  10299. result[9] = matrix[9];
  10300. result[10] = matrix[10];
  10301. result[11] = matrix[11];
  10302. result[12] = tx;
  10303. result[13] = ty;
  10304. result[14] = tz;
  10305. result[15] = matrix[15];
  10306. return result;
  10307. };
  10308. var uniformScaleScratch = new Cartesian3();
  10309. /**
  10310. * Multiplies an affine transformation matrix (with a bottom row of <code>[0.0, 0.0, 0.0, 1.0]</code>)
  10311. * by an implicit uniform scale matrix. This is an optimization
  10312. * for <code>Matrix4.multiply(m, Matrix4.fromUniformScale(scale), m);</code>, where
  10313. * <code>m</code> must be an affine matrix.
  10314. * This function performs fewer allocations and arithmetic operations.
  10315. *
  10316. * @param {Matrix4} matrix The affine matrix on the left-hand side.
  10317. * @param {Number} scale The uniform scale on the right-hand side.
  10318. * @param {Matrix4} result The object onto which to store the result.
  10319. * @returns {Matrix4} The modified result parameter.
  10320. *
  10321. *
  10322. * @example
  10323. * // Instead of Cesium.Matrix4.multiply(m, Cesium.Matrix4.fromUniformScale(scale), m);
  10324. * Cesium.Matrix4.multiplyByUniformScale(m, scale, m);
  10325. *
  10326. * @see Matrix4.fromUniformScale
  10327. * @see Matrix4.multiplyByScale
  10328. */
  10329. Matrix4.multiplyByUniformScale = function(matrix, scale, result) {
  10330. if (!defined(matrix)) {
  10331. throw new DeveloperError('matrix is required');
  10332. }
  10333. if (typeof scale !== 'number') {
  10334. throw new DeveloperError('scale is required');
  10335. }
  10336. if (!defined(result)) {
  10337. throw new DeveloperError('result is required');
  10338. }
  10339. uniformScaleScratch.x = scale;
  10340. uniformScaleScratch.y = scale;
  10341. uniformScaleScratch.z = scale;
  10342. return Matrix4.multiplyByScale(matrix, uniformScaleScratch, result);
  10343. };
  10344. /**
  10345. * Multiplies an affine transformation matrix (with a bottom row of <code>[0.0, 0.0, 0.0, 1.0]</code>)
  10346. * by an implicit non-uniform scale matrix. This is an optimization
  10347. * for <code>Matrix4.multiply(m, Matrix4.fromUniformScale(scale), m);</code>, where
  10348. * <code>m</code> must be an affine matrix.
  10349. * This function performs fewer allocations and arithmetic operations.
  10350. *
  10351. * @param {Matrix4} matrix The affine matrix on the left-hand side.
  10352. * @param {Cartesian3} scale The non-uniform scale on the right-hand side.
  10353. * @param {Matrix4} result The object onto which to store the result.
  10354. * @returns {Matrix4} The modified result parameter.
  10355. *
  10356. *
  10357. * @example
  10358. * // Instead of Cesium.Matrix4.multiply(m, Cesium.Matrix4.fromScale(scale), m);
  10359. * Cesium.Matrix4.multiplyByScale(m, scale, m);
  10360. *
  10361. * @see Matrix4.fromScale
  10362. * @see Matrix4.multiplyByUniformScale
  10363. */
  10364. Matrix4.multiplyByScale = function(matrix, scale, result) {
  10365. if (!defined(matrix)) {
  10366. throw new DeveloperError('matrix is required');
  10367. }
  10368. if (!defined(scale)) {
  10369. throw new DeveloperError('scale is required');
  10370. }
  10371. if (!defined(result)) {
  10372. throw new DeveloperError('result is required');
  10373. }
  10374. var scaleX = scale.x;
  10375. var scaleY = scale.y;
  10376. var scaleZ = scale.z;
  10377. // Faster than Cartesian3.equals
  10378. if ((scaleX === 1.0) && (scaleY === 1.0) && (scaleZ === 1.0)) {
  10379. return Matrix4.clone(matrix, result);
  10380. }
  10381. result[0] = scaleX * matrix[0];
  10382. result[1] = scaleX * matrix[1];
  10383. result[2] = scaleX * matrix[2];
  10384. result[3] = 0.0;
  10385. result[4] = scaleY * matrix[4];
  10386. result[5] = scaleY * matrix[5];
  10387. result[6] = scaleY * matrix[6];
  10388. result[7] = 0.0;
  10389. result[8] = scaleZ * matrix[8];
  10390. result[9] = scaleZ * matrix[9];
  10391. result[10] = scaleZ * matrix[10];
  10392. result[11] = 0.0;
  10393. result[12] = matrix[12];
  10394. result[13] = matrix[13];
  10395. result[14] = matrix[14];
  10396. result[15] = 1.0;
  10397. return result;
  10398. };
  10399. /**
  10400. * Computes the product of a matrix and a column vector.
  10401. *
  10402. * @param {Matrix4} matrix The matrix.
  10403. * @param {Cartesian4} cartesian The vector.
  10404. * @param {Cartesian4} result The object onto which to store the result.
  10405. * @returns {Cartesian4} The modified result parameter.
  10406. */
  10407. Matrix4.multiplyByVector = function(matrix, cartesian, result) {
  10408. if (!defined(matrix)) {
  10409. throw new DeveloperError('matrix is required');
  10410. }
  10411. if (!defined(cartesian)) {
  10412. throw new DeveloperError('cartesian is required');
  10413. }
  10414. if (!defined(result)) {
  10415. throw new DeveloperError('result is required');
  10416. }
  10417. var vX = cartesian.x;
  10418. var vY = cartesian.y;
  10419. var vZ = cartesian.z;
  10420. var vW = cartesian.w;
  10421. var x = matrix[0] * vX + matrix[4] * vY + matrix[8] * vZ + matrix[12] * vW;
  10422. var y = matrix[1] * vX + matrix[5] * vY + matrix[9] * vZ + matrix[13] * vW;
  10423. var z = matrix[2] * vX + matrix[6] * vY + matrix[10] * vZ + matrix[14] * vW;
  10424. var w = matrix[3] * vX + matrix[7] * vY + matrix[11] * vZ + matrix[15] * vW;
  10425. result.x = x;
  10426. result.y = y;
  10427. result.z = z;
  10428. result.w = w;
  10429. return result;
  10430. };
  10431. /**
  10432. * Computes the product of a matrix and a {@link Cartesian3}. This is equivalent to calling {@link Matrix4.multiplyByVector}
  10433. * with a {@link Cartesian4} with a <code>w</code> component of zero.
  10434. *
  10435. * @param {Matrix4} matrix The matrix.
  10436. * @param {Cartesian3} cartesian The point.
  10437. * @param {Cartesian3} result The object onto which to store the result.
  10438. * @returns {Cartesian3} The modified result parameter.
  10439. *
  10440. * @example
  10441. * var p = new Cesium.Cartesian3(1.0, 2.0, 3.0);
  10442. * var result = Cesium.Matrix4.multiplyByPointAsVector(matrix, p, new Cesium.Cartesian3());
  10443. * // A shortcut for
  10444. * // Cartesian3 p = ...
  10445. * // Cesium.Matrix4.multiplyByVector(matrix, new Cesium.Cartesian4(p.x, p.y, p.z, 0.0), result);
  10446. */
  10447. Matrix4.multiplyByPointAsVector = function(matrix, cartesian, result) {
  10448. if (!defined(matrix)) {
  10449. throw new DeveloperError('matrix is required');
  10450. }
  10451. if (!defined(cartesian)) {
  10452. throw new DeveloperError('cartesian is required');
  10453. }
  10454. if (!defined(result)) {
  10455. throw new DeveloperError('result is required');
  10456. }
  10457. var vX = cartesian.x;
  10458. var vY = cartesian.y;
  10459. var vZ = cartesian.z;
  10460. var x = matrix[0] * vX + matrix[4] * vY + matrix[8] * vZ;
  10461. var y = matrix[1] * vX + matrix[5] * vY + matrix[9] * vZ;
  10462. var z = matrix[2] * vX + matrix[6] * vY + matrix[10] * vZ;
  10463. result.x = x;
  10464. result.y = y;
  10465. result.z = z;
  10466. return result;
  10467. };
  10468. /**
  10469. * Computes the product of a matrix and a {@link Cartesian3}. This is equivalent to calling {@link Matrix4.multiplyByVector}
  10470. * with a {@link Cartesian4} with a <code>w</code> component of 1, but returns a {@link Cartesian3} instead of a {@link Cartesian4}.
  10471. *
  10472. * @param {Matrix4} matrix The matrix.
  10473. * @param {Cartesian3} cartesian The point.
  10474. * @param {Cartesian3} result The object onto which to store the result.
  10475. * @returns {Cartesian3} The modified result parameter.
  10476. *
  10477. * @example
  10478. * var p = new Cesium.Cartesian3(1.0, 2.0, 3.0);
  10479. * var result = Cesium.Matrix4.multiplyByPoint(matrix, p, new Cesium.Cartesian3());
  10480. */
  10481. Matrix4.multiplyByPoint = function(matrix, cartesian, result) {
  10482. if (!defined(matrix)) {
  10483. throw new DeveloperError('matrix is required');
  10484. }
  10485. if (!defined(cartesian)) {
  10486. throw new DeveloperError('cartesian is required');
  10487. }
  10488. if (!defined(result)) {
  10489. throw new DeveloperError('result is required');
  10490. }
  10491. var vX = cartesian.x;
  10492. var vY = cartesian.y;
  10493. var vZ = cartesian.z;
  10494. var x = matrix[0] * vX + matrix[4] * vY + matrix[8] * vZ + matrix[12];
  10495. var y = matrix[1] * vX + matrix[5] * vY + matrix[9] * vZ + matrix[13];
  10496. var z = matrix[2] * vX + matrix[6] * vY + matrix[10] * vZ + matrix[14];
  10497. result.x = x;
  10498. result.y = y;
  10499. result.z = z;
  10500. return result;
  10501. };
  10502. /**
  10503. * Computes the product of a matrix and a scalar.
  10504. *
  10505. * @param {Matrix4} matrix The matrix.
  10506. * @param {Number} scalar The number to multiply by.
  10507. * @param {Matrix4} result The object onto which to store the result.
  10508. * @returns {Matrix4} The modified result parameter.
  10509. *
  10510. * @example
  10511. * //create a Matrix4 instance which is a scaled version of the supplied Matrix4
  10512. * // m = [10.0, 11.0, 12.0, 13.0]
  10513. * // [14.0, 15.0, 16.0, 17.0]
  10514. * // [18.0, 19.0, 20.0, 21.0]
  10515. * // [22.0, 23.0, 24.0, 25.0]
  10516. *
  10517. * var a = Cesium.Matrix4.multiplyByScalar(m, -2, new Cesium.Matrix4());
  10518. *
  10519. * // m remains the same
  10520. * // a = [-20.0, -22.0, -24.0, -26.0]
  10521. * // [-28.0, -30.0, -32.0, -34.0]
  10522. * // [-36.0, -38.0, -40.0, -42.0]
  10523. * // [-44.0, -46.0, -48.0, -50.0]
  10524. */
  10525. Matrix4.multiplyByScalar = function(matrix, scalar, result) {
  10526. if (!defined(matrix)) {
  10527. throw new DeveloperError('matrix is required');
  10528. }
  10529. if (typeof scalar !== 'number') {
  10530. throw new DeveloperError('scalar must be a number');
  10531. }
  10532. if (!defined(result)) {
  10533. throw new DeveloperError('result is required');
  10534. }
  10535. result[0] = matrix[0] * scalar;
  10536. result[1] = matrix[1] * scalar;
  10537. result[2] = matrix[2] * scalar;
  10538. result[3] = matrix[3] * scalar;
  10539. result[4] = matrix[4] * scalar;
  10540. result[5] = matrix[5] * scalar;
  10541. result[6] = matrix[6] * scalar;
  10542. result[7] = matrix[7] * scalar;
  10543. result[8] = matrix[8] * scalar;
  10544. result[9] = matrix[9] * scalar;
  10545. result[10] = matrix[10] * scalar;
  10546. result[11] = matrix[11] * scalar;
  10547. result[12] = matrix[12] * scalar;
  10548. result[13] = matrix[13] * scalar;
  10549. result[14] = matrix[14] * scalar;
  10550. result[15] = matrix[15] * scalar;
  10551. return result;
  10552. };
  10553. /**
  10554. * Computes a negated copy of the provided matrix.
  10555. *
  10556. * @param {Matrix4} matrix The matrix to negate.
  10557. * @param {Matrix4} result The object onto which to store the result.
  10558. * @returns {Matrix4} The modified result parameter.
  10559. *
  10560. * @example
  10561. * //create a new Matrix4 instance which is a negation of a Matrix4
  10562. * // m = [10.0, 11.0, 12.0, 13.0]
  10563. * // [14.0, 15.0, 16.0, 17.0]
  10564. * // [18.0, 19.0, 20.0, 21.0]
  10565. * // [22.0, 23.0, 24.0, 25.0]
  10566. *
  10567. * var a = Cesium.Matrix4.negate(m, new Cesium.Matrix4());
  10568. *
  10569. * // m remains the same
  10570. * // a = [-10.0, -11.0, -12.0, -13.0]
  10571. * // [-14.0, -15.0, -16.0, -17.0]
  10572. * // [-18.0, -19.0, -20.0, -21.0]
  10573. * // [-22.0, -23.0, -24.0, -25.0]
  10574. */
  10575. Matrix4.negate = function(matrix, result) {
  10576. if (!defined(matrix)) {
  10577. throw new DeveloperError('matrix is required');
  10578. }
  10579. if (!defined(result)) {
  10580. throw new DeveloperError('result is required');
  10581. }
  10582. result[0] = -matrix[0];
  10583. result[1] = -matrix[1];
  10584. result[2] = -matrix[2];
  10585. result[3] = -matrix[3];
  10586. result[4] = -matrix[4];
  10587. result[5] = -matrix[5];
  10588. result[6] = -matrix[6];
  10589. result[7] = -matrix[7];
  10590. result[8] = -matrix[8];
  10591. result[9] = -matrix[9];
  10592. result[10] = -matrix[10];
  10593. result[11] = -matrix[11];
  10594. result[12] = -matrix[12];
  10595. result[13] = -matrix[13];
  10596. result[14] = -matrix[14];
  10597. result[15] = -matrix[15];
  10598. return result;
  10599. };
  10600. /**
  10601. * Computes the transpose of the provided matrix.
  10602. *
  10603. * @param {Matrix4} matrix The matrix to transpose.
  10604. * @param {Matrix4} result The object onto which to store the result.
  10605. * @returns {Matrix4} The modified result parameter.
  10606. *
  10607. * @example
  10608. * //returns transpose of a Matrix4
  10609. * // m = [10.0, 11.0, 12.0, 13.0]
  10610. * // [14.0, 15.0, 16.0, 17.0]
  10611. * // [18.0, 19.0, 20.0, 21.0]
  10612. * // [22.0, 23.0, 24.0, 25.0]
  10613. *
  10614. * var a = Cesium.Matrix4.transpose(m, new Cesium.Matrix4());
  10615. *
  10616. * // m remains the same
  10617. * // a = [10.0, 14.0, 18.0, 22.0]
  10618. * // [11.0, 15.0, 19.0, 23.0]
  10619. * // [12.0, 16.0, 20.0, 24.0]
  10620. * // [13.0, 17.0, 21.0, 25.0]
  10621. */
  10622. Matrix4.transpose = function(matrix, result) {
  10623. if (!defined(matrix)) {
  10624. throw new DeveloperError('matrix is required');
  10625. }
  10626. if (!defined(result)) {
  10627. throw new DeveloperError('result is required');
  10628. }
  10629. var matrix1 = matrix[1];
  10630. var matrix2 = matrix[2];
  10631. var matrix3 = matrix[3];
  10632. var matrix6 = matrix[6];
  10633. var matrix7 = matrix[7];
  10634. var matrix11 = matrix[11];
  10635. result[0] = matrix[0];
  10636. result[1] = matrix[4];
  10637. result[2] = matrix[8];
  10638. result[3] = matrix[12];
  10639. result[4] = matrix1;
  10640. result[5] = matrix[5];
  10641. result[6] = matrix[9];
  10642. result[7] = matrix[13];
  10643. result[8] = matrix2;
  10644. result[9] = matrix6;
  10645. result[10] = matrix[10];
  10646. result[11] = matrix[14];
  10647. result[12] = matrix3;
  10648. result[13] = matrix7;
  10649. result[14] = matrix11;
  10650. result[15] = matrix[15];
  10651. return result;
  10652. };
  10653. /**
  10654. * Computes a matrix, which contains the absolute (unsigned) values of the provided matrix's elements.
  10655. *
  10656. * @param {Matrix4} matrix The matrix with signed elements.
  10657. * @param {Matrix4} result The object onto which to store the result.
  10658. * @returns {Matrix4} The modified result parameter.
  10659. */
  10660. Matrix4.abs = function(matrix, result) {
  10661. if (!defined(matrix)) {
  10662. throw new DeveloperError('matrix is required');
  10663. }
  10664. if (!defined(result)) {
  10665. throw new DeveloperError('result is required');
  10666. }
  10667. result[0] = Math.abs(matrix[0]);
  10668. result[1] = Math.abs(matrix[1]);
  10669. result[2] = Math.abs(matrix[2]);
  10670. result[3] = Math.abs(matrix[3]);
  10671. result[4] = Math.abs(matrix[4]);
  10672. result[5] = Math.abs(matrix[5]);
  10673. result[6] = Math.abs(matrix[6]);
  10674. result[7] = Math.abs(matrix[7]);
  10675. result[8] = Math.abs(matrix[8]);
  10676. result[9] = Math.abs(matrix[9]);
  10677. result[10] = Math.abs(matrix[10]);
  10678. result[11] = Math.abs(matrix[11]);
  10679. result[12] = Math.abs(matrix[12]);
  10680. result[13] = Math.abs(matrix[13]);
  10681. result[14] = Math.abs(matrix[14]);
  10682. result[15] = Math.abs(matrix[15]);
  10683. return result;
  10684. };
  10685. /**
  10686. * Compares the provided matrices componentwise and returns
  10687. * <code>true</code> if they are equal, <code>false</code> otherwise.
  10688. *
  10689. * @param {Matrix4} [left] The first matrix.
  10690. * @param {Matrix4} [right] The second matrix.
  10691. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  10692. *
  10693. * @example
  10694. * //compares two Matrix4 instances
  10695. *
  10696. * // a = [10.0, 14.0, 18.0, 22.0]
  10697. * // [11.0, 15.0, 19.0, 23.0]
  10698. * // [12.0, 16.0, 20.0, 24.0]
  10699. * // [13.0, 17.0, 21.0, 25.0]
  10700. *
  10701. * // b = [10.0, 14.0, 18.0, 22.0]
  10702. * // [11.0, 15.0, 19.0, 23.0]
  10703. * // [12.0, 16.0, 20.0, 24.0]
  10704. * // [13.0, 17.0, 21.0, 25.0]
  10705. *
  10706. * if(Cesium.Matrix4.equals(a,b)) {
  10707. * console.log("Both matrices are equal");
  10708. * } else {
  10709. * console.log("They are not equal");
  10710. * }
  10711. *
  10712. * //Prints "Both matrices are equal" on the console
  10713. */
  10714. Matrix4.equals = function(left, right) {
  10715. // Given that most matrices will be transformation matrices, the elements
  10716. // are tested in order such that the test is likely to fail as early
  10717. // as possible. I _think_ this is just as friendly to the L1 cache
  10718. // as testing in index order. It is certainty faster in practice.
  10719. return (left === right) ||
  10720. (defined(left) &&
  10721. defined(right) &&
  10722. // Translation
  10723. left[12] === right[12] &&
  10724. left[13] === right[13] &&
  10725. left[14] === right[14] &&
  10726. // Rotation/scale
  10727. left[0] === right[0] &&
  10728. left[1] === right[1] &&
  10729. left[2] === right[2] &&
  10730. left[4] === right[4] &&
  10731. left[5] === right[5] &&
  10732. left[6] === right[6] &&
  10733. left[8] === right[8] &&
  10734. left[9] === right[9] &&
  10735. left[10] === right[10] &&
  10736. // Bottom row
  10737. left[3] === right[3] &&
  10738. left[7] === right[7] &&
  10739. left[11] === right[11] &&
  10740. left[15] === right[15]);
  10741. };
  10742. /**
  10743. * Compares the provided matrices componentwise and returns
  10744. * <code>true</code> if they are within the provided epsilon,
  10745. * <code>false</code> otherwise.
  10746. *
  10747. * @param {Matrix4} [left] The first matrix.
  10748. * @param {Matrix4} [right] The second matrix.
  10749. * @param {Number} epsilon The epsilon to use for equality testing.
  10750. * @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
  10751. *
  10752. * @example
  10753. * //compares two Matrix4 instances
  10754. *
  10755. * // a = [10.5, 14.5, 18.5, 22.5]
  10756. * // [11.5, 15.5, 19.5, 23.5]
  10757. * // [12.5, 16.5, 20.5, 24.5]
  10758. * // [13.5, 17.5, 21.5, 25.5]
  10759. *
  10760. * // b = [10.0, 14.0, 18.0, 22.0]
  10761. * // [11.0, 15.0, 19.0, 23.0]
  10762. * // [12.0, 16.0, 20.0, 24.0]
  10763. * // [13.0, 17.0, 21.0, 25.0]
  10764. *
  10765. * if(Cesium.Matrix4.equalsEpsilon(a,b,0.1)){
  10766. * console.log("Difference between both the matrices is less than 0.1");
  10767. * } else {
  10768. * console.log("Difference between both the matrices is not less than 0.1");
  10769. * }
  10770. *
  10771. * //Prints "Difference between both the matrices is not less than 0.1" on the console
  10772. */
  10773. Matrix4.equalsEpsilon = function(left, right, epsilon) {
  10774. if (typeof epsilon !== 'number') {
  10775. throw new DeveloperError('epsilon must be a number');
  10776. }
  10777. return (left === right) ||
  10778. (defined(left) &&
  10779. defined(right) &&
  10780. Math.abs(left[0] - right[0]) <= epsilon &&
  10781. Math.abs(left[1] - right[1]) <= epsilon &&
  10782. Math.abs(left[2] - right[2]) <= epsilon &&
  10783. Math.abs(left[3] - right[3]) <= epsilon &&
  10784. Math.abs(left[4] - right[4]) <= epsilon &&
  10785. Math.abs(left[5] - right[5]) <= epsilon &&
  10786. Math.abs(left[6] - right[6]) <= epsilon &&
  10787. Math.abs(left[7] - right[7]) <= epsilon &&
  10788. Math.abs(left[8] - right[8]) <= epsilon &&
  10789. Math.abs(left[9] - right[9]) <= epsilon &&
  10790. Math.abs(left[10] - right[10]) <= epsilon &&
  10791. Math.abs(left[11] - right[11]) <= epsilon &&
  10792. Math.abs(left[12] - right[12]) <= epsilon &&
  10793. Math.abs(left[13] - right[13]) <= epsilon &&
  10794. Math.abs(left[14] - right[14]) <= epsilon &&
  10795. Math.abs(left[15] - right[15]) <= epsilon);
  10796. };
  10797. /**
  10798. * Gets the translation portion of the provided matrix, assuming the matrix is a affine transformation matrix.
  10799. *
  10800. * @param {Matrix4} matrix The matrix to use.
  10801. * @param {Cartesian3} result The object onto which to store the result.
  10802. * @returns {Cartesian3} The modified result parameter.
  10803. */
  10804. Matrix4.getTranslation = function(matrix, result) {
  10805. if (!defined(matrix)) {
  10806. throw new DeveloperError('matrix is required');
  10807. }
  10808. if (!defined(result)) {
  10809. throw new DeveloperError('result is required');
  10810. }
  10811. result.x = matrix[12];
  10812. result.y = matrix[13];
  10813. result.z = matrix[14];
  10814. return result;
  10815. };
  10816. /**
  10817. * Gets the upper left 3x3 rotation matrix of the provided matrix, assuming the matrix is a affine transformation matrix.
  10818. *
  10819. * @param {Matrix4} matrix The matrix to use.
  10820. * @param {Matrix3} result The object onto which to store the result.
  10821. * @returns {Matrix3} The modified result parameter.
  10822. *
  10823. * @example
  10824. * // returns a Matrix3 instance from a Matrix4 instance
  10825. *
  10826. * // m = [10.0, 14.0, 18.0, 22.0]
  10827. * // [11.0, 15.0, 19.0, 23.0]
  10828. * // [12.0, 16.0, 20.0, 24.0]
  10829. * // [13.0, 17.0, 21.0, 25.0]
  10830. *
  10831. * var b = new Cesium.Matrix3();
  10832. * Cesium.Matrix4.getRotation(m,b);
  10833. *
  10834. * // b = [10.0, 14.0, 18.0]
  10835. * // [11.0, 15.0, 19.0]
  10836. * // [12.0, 16.0, 20.0]
  10837. */
  10838. Matrix4.getRotation = function(matrix, result) {
  10839. if (!defined(matrix)) {
  10840. throw new DeveloperError('matrix is required');
  10841. }
  10842. if (!defined(result)) {
  10843. throw new DeveloperError('result is required');
  10844. }
  10845. result[0] = matrix[0];
  10846. result[1] = matrix[1];
  10847. result[2] = matrix[2];
  10848. result[3] = matrix[4];
  10849. result[4] = matrix[5];
  10850. result[5] = matrix[6];
  10851. result[6] = matrix[8];
  10852. result[7] = matrix[9];
  10853. result[8] = matrix[10];
  10854. return result;
  10855. };
  10856. var scratchInverseRotation = new Matrix3();
  10857. var scratchMatrix3Zero = new Matrix3();
  10858. var scratchBottomRow = new Cartesian4();
  10859. var scratchExpectedBottomRow = new Cartesian4(0.0, 0.0, 0.0, 1.0);
  10860. /**
  10861. * Computes the inverse of the provided matrix using Cramers Rule.
  10862. * If the determinant is zero, the matrix can not be inverted, and an exception is thrown.
  10863. * If the matrix is an affine transformation matrix, it is more efficient
  10864. * to invert it with {@link Matrix4.inverseTransformation}.
  10865. *
  10866. * @param {Matrix4} matrix The matrix to invert.
  10867. * @param {Matrix4} result The object onto which to store the result.
  10868. * @returns {Matrix4} The modified result parameter.
  10869. *
  10870. * @exception {RuntimeError} matrix is not invertible because its determinate is zero.
  10871. */
  10872. Matrix4.inverse = function(matrix, result) {
  10873. if (!defined(matrix)) {
  10874. throw new DeveloperError('matrix is required');
  10875. }
  10876. if (!defined(result)) {
  10877. throw new DeveloperError('result is required');
  10878. }
  10879. // Special case for a zero scale matrix that can occur, for example,
  10880. // when a model's node has a [0, 0, 0] scale.
  10881. if (Matrix3.equalsEpsilon(Matrix4.getRotation(matrix, scratchInverseRotation), scratchMatrix3Zero, CesiumMath.EPSILON7) &&
  10882. Cartesian4.equals(Matrix4.getRow(matrix, 3, scratchBottomRow), scratchExpectedBottomRow)) {
  10883. result[0] = 0.0;
  10884. result[1] = 0.0;
  10885. result[2] = 0.0;
  10886. result[3] = 0.0;
  10887. result[4] = 0.0;
  10888. result[5] = 0.0;
  10889. result[6] = 0.0;
  10890. result[7] = 0.0;
  10891. result[8] = 0.0;
  10892. result[9] = 0.0;
  10893. result[10] = 0.0;
  10894. result[11] = 0.0;
  10895. result[12] = -matrix[12];
  10896. result[13] = -matrix[13];
  10897. result[14] = -matrix[14];
  10898. result[15] = 1.0;
  10899. return result;
  10900. }
  10901. //
  10902. // Ported from:
  10903. // ftp://download.intel.com/design/PentiumIII/sml/24504301.pdf
  10904. //
  10905. var src0 = matrix[0];
  10906. var src1 = matrix[4];
  10907. var src2 = matrix[8];
  10908. var src3 = matrix[12];
  10909. var src4 = matrix[1];
  10910. var src5 = matrix[5];
  10911. var src6 = matrix[9];
  10912. var src7 = matrix[13];
  10913. var src8 = matrix[2];
  10914. var src9 = matrix[6];
  10915. var src10 = matrix[10];
  10916. var src11 = matrix[14];
  10917. var src12 = matrix[3];
  10918. var src13 = matrix[7];
  10919. var src14 = matrix[11];
  10920. var src15 = matrix[15];
  10921. // calculate pairs for first 8 elements (cofactors)
  10922. var tmp0 = src10 * src15;
  10923. var tmp1 = src11 * src14;
  10924. var tmp2 = src9 * src15;
  10925. var tmp3 = src11 * src13;
  10926. var tmp4 = src9 * src14;
  10927. var tmp5 = src10 * src13;
  10928. var tmp6 = src8 * src15;
  10929. var tmp7 = src11 * src12;
  10930. var tmp8 = src8 * src14;
  10931. var tmp9 = src10 * src12;
  10932. var tmp10 = src8 * src13;
  10933. var tmp11 = src9 * src12;
  10934. // calculate first 8 elements (cofactors)
  10935. var dst0 = (tmp0 * src5 + tmp3 * src6 + tmp4 * src7) - (tmp1 * src5 + tmp2 * src6 + tmp5 * src7);
  10936. var dst1 = (tmp1 * src4 + tmp6 * src6 + tmp9 * src7) - (tmp0 * src4 + tmp7 * src6 + tmp8 * src7);
  10937. var dst2 = (tmp2 * src4 + tmp7 * src5 + tmp10 * src7) - (tmp3 * src4 + tmp6 * src5 + tmp11 * src7);
  10938. var dst3 = (tmp5 * src4 + tmp8 * src5 + tmp11 * src6) - (tmp4 * src4 + tmp9 * src5 + tmp10 * src6);
  10939. var dst4 = (tmp1 * src1 + tmp2 * src2 + tmp5 * src3) - (tmp0 * src1 + tmp3 * src2 + tmp4 * src3);
  10940. var dst5 = (tmp0 * src0 + tmp7 * src2 + tmp8 * src3) - (tmp1 * src0 + tmp6 * src2 + tmp9 * src3);
  10941. var dst6 = (tmp3 * src0 + tmp6 * src1 + tmp11 * src3) - (tmp2 * src0 + tmp7 * src1 + tmp10 * src3);
  10942. var dst7 = (tmp4 * src0 + tmp9 * src1 + tmp10 * src2) - (tmp5 * src0 + tmp8 * src1 + tmp11 * src2);
  10943. // calculate pairs for second 8 elements (cofactors)
  10944. tmp0 = src2 * src7;
  10945. tmp1 = src3 * src6;
  10946. tmp2 = src1 * src7;
  10947. tmp3 = src3 * src5;
  10948. tmp4 = src1 * src6;
  10949. tmp5 = src2 * src5;
  10950. tmp6 = src0 * src7;
  10951. tmp7 = src3 * src4;
  10952. tmp8 = src0 * src6;
  10953. tmp9 = src2 * src4;
  10954. tmp10 = src0 * src5;
  10955. tmp11 = src1 * src4;
  10956. // calculate second 8 elements (cofactors)
  10957. var dst8 = (tmp0 * src13 + tmp3 * src14 + tmp4 * src15) - (tmp1 * src13 + tmp2 * src14 + tmp5 * src15);
  10958. var dst9 = (tmp1 * src12 + tmp6 * src14 + tmp9 * src15) - (tmp0 * src12 + tmp7 * src14 + tmp8 * src15);
  10959. var dst10 = (tmp2 * src12 + tmp7 * src13 + tmp10 * src15) - (tmp3 * src12 + tmp6 * src13 + tmp11 * src15);
  10960. var dst11 = (tmp5 * src12 + tmp8 * src13 + tmp11 * src14) - (tmp4 * src12 + tmp9 * src13 + tmp10 * src14);
  10961. var dst12 = (tmp2 * src10 + tmp5 * src11 + tmp1 * src9) - (tmp4 * src11 + tmp0 * src9 + tmp3 * src10);
  10962. var dst13 = (tmp8 * src11 + tmp0 * src8 + tmp7 * src10) - (tmp6 * src10 + tmp9 * src11 + tmp1 * src8);
  10963. var dst14 = (tmp6 * src9 + tmp11 * src11 + tmp3 * src8) - (tmp10 * src11 + tmp2 * src8 + tmp7 * src9);
  10964. var dst15 = (tmp10 * src10 + tmp4 * src8 + tmp9 * src9) - (tmp8 * src9 + tmp11 * src10 + tmp5 * src8);
  10965. // calculate determinant
  10966. var det = src0 * dst0 + src1 * dst1 + src2 * dst2 + src3 * dst3;
  10967. if (Math.abs(det) < CesiumMath.EPSILON20) {
  10968. throw new RuntimeError('matrix is not invertible because its determinate is zero.');
  10969. }
  10970. // calculate matrix inverse
  10971. det = 1.0 / det;
  10972. result[0] = dst0 * det;
  10973. result[1] = dst1 * det;
  10974. result[2] = dst2 * det;
  10975. result[3] = dst3 * det;
  10976. result[4] = dst4 * det;
  10977. result[5] = dst5 * det;
  10978. result[6] = dst6 * det;
  10979. result[7] = dst7 * det;
  10980. result[8] = dst8 * det;
  10981. result[9] = dst9 * det;
  10982. result[10] = dst10 * det;
  10983. result[11] = dst11 * det;
  10984. result[12] = dst12 * det;
  10985. result[13] = dst13 * det;
  10986. result[14] = dst14 * det;
  10987. result[15] = dst15 * det;
  10988. return result;
  10989. };
  10990. /**
  10991. * Computes the inverse of the provided matrix assuming it is
  10992. * an affine transformation matrix, where the upper left 3x3 elements
  10993. * are a rotation matrix, and the upper three elements in the fourth
  10994. * column are the translation. The bottom row is assumed to be [0, 0, 0, 1].
  10995. * The matrix is not verified to be in the proper form.
  10996. * This method is faster than computing the inverse for a general 4x4
  10997. * matrix using {@link Matrix4.inverse}.
  10998. *
  10999. * @param {Matrix4} matrix The matrix to invert.
  11000. * @param {Matrix4} result The object onto which to store the result.
  11001. * @returns {Matrix4} The modified result parameter.
  11002. */
  11003. Matrix4.inverseTransformation = function(matrix, result) {
  11004. if (!defined(matrix)) {
  11005. throw new DeveloperError('matrix is required');
  11006. }
  11007. if (!defined(result)) {
  11008. throw new DeveloperError('result is required');
  11009. }
  11010. //This function is an optimized version of the below 4 lines.
  11011. //var rT = Matrix3.transpose(Matrix4.getRotation(matrix));
  11012. //var rTN = Matrix3.negate(rT);
  11013. //var rTT = Matrix3.multiplyByVector(rTN, Matrix4.getTranslation(matrix));
  11014. //return Matrix4.fromRotationTranslation(rT, rTT, result);
  11015. var matrix0 = matrix[0];
  11016. var matrix1 = matrix[1];
  11017. var matrix2 = matrix[2];
  11018. var matrix4 = matrix[4];
  11019. var matrix5 = matrix[5];
  11020. var matrix6 = matrix[6];
  11021. var matrix8 = matrix[8];
  11022. var matrix9 = matrix[9];
  11023. var matrix10 = matrix[10];
  11024. var vX = matrix[12];
  11025. var vY = matrix[13];
  11026. var vZ = matrix[14];
  11027. var x = -matrix0 * vX - matrix1 * vY - matrix2 * vZ;
  11028. var y = -matrix4 * vX - matrix5 * vY - matrix6 * vZ;
  11029. var z = -matrix8 * vX - matrix9 * vY - matrix10 * vZ;
  11030. result[0] = matrix0;
  11031. result[1] = matrix4;
  11032. result[2] = matrix8;
  11033. result[3] = 0.0;
  11034. result[4] = matrix1;
  11035. result[5] = matrix5;
  11036. result[6] = matrix9;
  11037. result[7] = 0.0;
  11038. result[8] = matrix2;
  11039. result[9] = matrix6;
  11040. result[10] = matrix10;
  11041. result[11] = 0.0;
  11042. result[12] = x;
  11043. result[13] = y;
  11044. result[14] = z;
  11045. result[15] = 1.0;
  11046. return result;
  11047. };
  11048. /**
  11049. * An immutable Matrix4 instance initialized to the identity matrix.
  11050. *
  11051. * @type {Matrix4}
  11052. * @constant
  11053. */
  11054. Matrix4.IDENTITY = freezeObject(new Matrix4(1.0, 0.0, 0.0, 0.0,
  11055. 0.0, 1.0, 0.0, 0.0,
  11056. 0.0, 0.0, 1.0, 0.0,
  11057. 0.0, 0.0, 0.0, 1.0));
  11058. /**
  11059. * An immutable Matrix4 instance initialized to the zero matrix.
  11060. *
  11061. * @type {Matrix4}
  11062. * @constant
  11063. */
  11064. Matrix4.ZERO = freezeObject(new Matrix4(0.0, 0.0, 0.0, 0.0,
  11065. 0.0, 0.0, 0.0, 0.0,
  11066. 0.0, 0.0, 0.0, 0.0,
  11067. 0.0, 0.0, 0.0, 0.0));
  11068. /**
  11069. * The index into Matrix4 for column 0, row 0.
  11070. *
  11071. * @type {Number}
  11072. * @constant
  11073. */
  11074. Matrix4.COLUMN0ROW0 = 0;
  11075. /**
  11076. * The index into Matrix4 for column 0, row 1.
  11077. *
  11078. * @type {Number}
  11079. * @constant
  11080. */
  11081. Matrix4.COLUMN0ROW1 = 1;
  11082. /**
  11083. * The index into Matrix4 for column 0, row 2.
  11084. *
  11085. * @type {Number}
  11086. * @constant
  11087. */
  11088. Matrix4.COLUMN0ROW2 = 2;
  11089. /**
  11090. * The index into Matrix4 for column 0, row 3.
  11091. *
  11092. * @type {Number}
  11093. * @constant
  11094. */
  11095. Matrix4.COLUMN0ROW3 = 3;
  11096. /**
  11097. * The index into Matrix4 for column 1, row 0.
  11098. *
  11099. * @type {Number}
  11100. * @constant
  11101. */
  11102. Matrix4.COLUMN1ROW0 = 4;
  11103. /**
  11104. * The index into Matrix4 for column 1, row 1.
  11105. *
  11106. * @type {Number}
  11107. * @constant
  11108. */
  11109. Matrix4.COLUMN1ROW1 = 5;
  11110. /**
  11111. * The index into Matrix4 for column 1, row 2.
  11112. *
  11113. * @type {Number}
  11114. * @constant
  11115. */
  11116. Matrix4.COLUMN1ROW2 = 6;
  11117. /**
  11118. * The index into Matrix4 for column 1, row 3.
  11119. *
  11120. * @type {Number}
  11121. * @constant
  11122. */
  11123. Matrix4.COLUMN1ROW3 = 7;
  11124. /**
  11125. * The index into Matrix4 for column 2, row 0.
  11126. *
  11127. * @type {Number}
  11128. * @constant
  11129. */
  11130. Matrix4.COLUMN2ROW0 = 8;
  11131. /**
  11132. * The index into Matrix4 for column 2, row 1.
  11133. *
  11134. * @type {Number}
  11135. * @constant
  11136. */
  11137. Matrix4.COLUMN2ROW1 = 9;
  11138. /**
  11139. * The index into Matrix4 for column 2, row 2.
  11140. *
  11141. * @type {Number}
  11142. * @constant
  11143. */
  11144. Matrix4.COLUMN2ROW2 = 10;
  11145. /**
  11146. * The index into Matrix4 for column 2, row 3.
  11147. *
  11148. * @type {Number}
  11149. * @constant
  11150. */
  11151. Matrix4.COLUMN2ROW3 = 11;
  11152. /**
  11153. * The index into Matrix4 for column 3, row 0.
  11154. *
  11155. * @type {Number}
  11156. * @constant
  11157. */
  11158. Matrix4.COLUMN3ROW0 = 12;
  11159. /**
  11160. * The index into Matrix4 for column 3, row 1.
  11161. *
  11162. * @type {Number}
  11163. * @constant
  11164. */
  11165. Matrix4.COLUMN3ROW1 = 13;
  11166. /**
  11167. * The index into Matrix4 for column 3, row 2.
  11168. *
  11169. * @type {Number}
  11170. * @constant
  11171. */
  11172. Matrix4.COLUMN3ROW2 = 14;
  11173. /**
  11174. * The index into Matrix4 for column 3, row 3.
  11175. *
  11176. * @type {Number}
  11177. * @constant
  11178. */
  11179. Matrix4.COLUMN3ROW3 = 15;
  11180. defineProperties(Matrix4.prototype, {
  11181. /**
  11182. * Gets the number of items in the collection.
  11183. * @memberof Matrix4.prototype
  11184. *
  11185. * @type {Number}
  11186. */
  11187. length : {
  11188. get : function() {
  11189. return Matrix4.packedLength;
  11190. }
  11191. }
  11192. });
  11193. /**
  11194. * Duplicates the provided Matrix4 instance.
  11195. *
  11196. * @param {Matrix4} [result] The object onto which to store the result.
  11197. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if one was not provided.
  11198. */
  11199. Matrix4.prototype.clone = function(result) {
  11200. return Matrix4.clone(this, result);
  11201. };
  11202. /**
  11203. * Compares this matrix to the provided matrix componentwise and returns
  11204. * <code>true</code> if they are equal, <code>false</code> otherwise.
  11205. *
  11206. * @param {Matrix4} [right] The right hand side matrix.
  11207. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  11208. */
  11209. Matrix4.prototype.equals = function(right) {
  11210. return Matrix4.equals(this, right);
  11211. };
  11212. /**
  11213. * @private
  11214. */
  11215. Matrix4.equalsArray = function(matrix, array, offset) {
  11216. return matrix[0] === array[offset] &&
  11217. matrix[1] === array[offset + 1] &&
  11218. matrix[2] === array[offset + 2] &&
  11219. matrix[3] === array[offset + 3] &&
  11220. matrix[4] === array[offset + 4] &&
  11221. matrix[5] === array[offset + 5] &&
  11222. matrix[6] === array[offset + 6] &&
  11223. matrix[7] === array[offset + 7] &&
  11224. matrix[8] === array[offset + 8] &&
  11225. matrix[9] === array[offset + 9] &&
  11226. matrix[10] === array[offset + 10] &&
  11227. matrix[11] === array[offset + 11] &&
  11228. matrix[12] === array[offset + 12] &&
  11229. matrix[13] === array[offset + 13] &&
  11230. matrix[14] === array[offset + 14] &&
  11231. matrix[15] === array[offset + 15];
  11232. };
  11233. /**
  11234. * Compares this matrix to the provided matrix componentwise and returns
  11235. * <code>true</code> if they are within the provided epsilon,
  11236. * <code>false</code> otherwise.
  11237. *
  11238. * @param {Matrix4} [right] The right hand side matrix.
  11239. * @param {Number} epsilon The epsilon to use for equality testing.
  11240. * @returns {Boolean} <code>true</code> if they are within the provided epsilon, <code>false</code> otherwise.
  11241. */
  11242. Matrix4.prototype.equalsEpsilon = function(right, epsilon) {
  11243. return Matrix4.equalsEpsilon(this, right, epsilon);
  11244. };
  11245. /**
  11246. * Computes a string representing this Matrix with each row being
  11247. * on a separate line and in the format '(column0, column1, column2, column3)'.
  11248. *
  11249. * @returns {String} A string representing the provided Matrix with each row being on a separate line and in the format '(column0, column1, column2, column3)'.
  11250. */
  11251. Matrix4.prototype.toString = function() {
  11252. return '(' + this[0] + ', ' + this[4] + ', ' + this[8] + ', ' + this[12] +')\n' +
  11253. '(' + this[1] + ', ' + this[5] + ', ' + this[9] + ', ' + this[13] +')\n' +
  11254. '(' + this[2] + ', ' + this[6] + ', ' + this[10] + ', ' + this[14] +')\n' +
  11255. '(' + this[3] + ', ' + this[7] + ', ' + this[11] + ', ' + this[15] +')';
  11256. };
  11257. return Matrix4;
  11258. });
  11259. /*global define*/
  11260. define('Core/BoundingSphere',[
  11261. './Cartesian3',
  11262. './Cartographic',
  11263. './defaultValue',
  11264. './defined',
  11265. './DeveloperError',
  11266. './Ellipsoid',
  11267. './GeographicProjection',
  11268. './Intersect',
  11269. './Interval',
  11270. './Matrix3',
  11271. './Matrix4',
  11272. './Rectangle'
  11273. ], function(
  11274. Cartesian3,
  11275. Cartographic,
  11276. defaultValue,
  11277. defined,
  11278. DeveloperError,
  11279. Ellipsoid,
  11280. GeographicProjection,
  11281. Intersect,
  11282. Interval,
  11283. Matrix3,
  11284. Matrix4,
  11285. Rectangle) {
  11286. 'use strict';
  11287. /**
  11288. * A bounding sphere with a center and a radius.
  11289. * @alias BoundingSphere
  11290. * @constructor
  11291. *
  11292. * @param {Cartesian3} [center=Cartesian3.ZERO] The center of the bounding sphere.
  11293. * @param {Number} [radius=0.0] The radius of the bounding sphere.
  11294. *
  11295. * @see AxisAlignedBoundingBox
  11296. * @see BoundingRectangle
  11297. * @see Packable
  11298. */
  11299. function BoundingSphere(center, radius) {
  11300. /**
  11301. * The center point of the sphere.
  11302. * @type {Cartesian3}
  11303. * @default {@link Cartesian3.ZERO}
  11304. */
  11305. this.center = Cartesian3.clone(defaultValue(center, Cartesian3.ZERO));
  11306. /**
  11307. * The radius of the sphere.
  11308. * @type {Number}
  11309. * @default 0.0
  11310. */
  11311. this.radius = defaultValue(radius, 0.0);
  11312. }
  11313. var fromPointsXMin = new Cartesian3();
  11314. var fromPointsYMin = new Cartesian3();
  11315. var fromPointsZMin = new Cartesian3();
  11316. var fromPointsXMax = new Cartesian3();
  11317. var fromPointsYMax = new Cartesian3();
  11318. var fromPointsZMax = new Cartesian3();
  11319. var fromPointsCurrentPos = new Cartesian3();
  11320. var fromPointsScratch = new Cartesian3();
  11321. var fromPointsRitterCenter = new Cartesian3();
  11322. var fromPointsMinBoxPt = new Cartesian3();
  11323. var fromPointsMaxBoxPt = new Cartesian3();
  11324. var fromPointsNaiveCenterScratch = new Cartesian3();
  11325. /**
  11326. * Computes a tight-fitting bounding sphere enclosing a list of 3D Cartesian points.
  11327. * The bounding sphere is computed by running two algorithms, a naive algorithm and
  11328. * Ritter's algorithm. The smaller of the two spheres is used to ensure a tight fit.
  11329. *
  11330. * @param {Cartesian3[]} positions An array of points that the bounding sphere will enclose. Each point must have <code>x</code>, <code>y</code>, and <code>z</code> properties.
  11331. * @param {BoundingSphere} [result] The object onto which to store the result.
  11332. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if one was not provided.
  11333. *
  11334. * @see {@link http://blogs.agi.com/insight3d/index.php/2008/02/04/a-bounding/|Bounding Sphere computation article}
  11335. */
  11336. BoundingSphere.fromPoints = function(positions, result) {
  11337. if (!defined(result)) {
  11338. result = new BoundingSphere();
  11339. }
  11340. if (!defined(positions) || positions.length === 0) {
  11341. result.center = Cartesian3.clone(Cartesian3.ZERO, result.center);
  11342. result.radius = 0.0;
  11343. return result;
  11344. }
  11345. var currentPos = Cartesian3.clone(positions[0], fromPointsCurrentPos);
  11346. var xMin = Cartesian3.clone(currentPos, fromPointsXMin);
  11347. var yMin = Cartesian3.clone(currentPos, fromPointsYMin);
  11348. var zMin = Cartesian3.clone(currentPos, fromPointsZMin);
  11349. var xMax = Cartesian3.clone(currentPos, fromPointsXMax);
  11350. var yMax = Cartesian3.clone(currentPos, fromPointsYMax);
  11351. var zMax = Cartesian3.clone(currentPos, fromPointsZMax);
  11352. var numPositions = positions.length;
  11353. for (var i = 1; i < numPositions; i++) {
  11354. Cartesian3.clone(positions[i], currentPos);
  11355. var x = currentPos.x;
  11356. var y = currentPos.y;
  11357. var z = currentPos.z;
  11358. // Store points containing the the smallest and largest components
  11359. if (x < xMin.x) {
  11360. Cartesian3.clone(currentPos, xMin);
  11361. }
  11362. if (x > xMax.x) {
  11363. Cartesian3.clone(currentPos, xMax);
  11364. }
  11365. if (y < yMin.y) {
  11366. Cartesian3.clone(currentPos, yMin);
  11367. }
  11368. if (y > yMax.y) {
  11369. Cartesian3.clone(currentPos, yMax);
  11370. }
  11371. if (z < zMin.z) {
  11372. Cartesian3.clone(currentPos, zMin);
  11373. }
  11374. if (z > zMax.z) {
  11375. Cartesian3.clone(currentPos, zMax);
  11376. }
  11377. }
  11378. // Compute x-, y-, and z-spans (Squared distances b/n each component's min. and max.).
  11379. var xSpan = Cartesian3.magnitudeSquared(Cartesian3.subtract(xMax, xMin, fromPointsScratch));
  11380. var ySpan = Cartesian3.magnitudeSquared(Cartesian3.subtract(yMax, yMin, fromPointsScratch));
  11381. var zSpan = Cartesian3.magnitudeSquared(Cartesian3.subtract(zMax, zMin, fromPointsScratch));
  11382. // Set the diameter endpoints to the largest span.
  11383. var diameter1 = xMin;
  11384. var diameter2 = xMax;
  11385. var maxSpan = xSpan;
  11386. if (ySpan > maxSpan) {
  11387. maxSpan = ySpan;
  11388. diameter1 = yMin;
  11389. diameter2 = yMax;
  11390. }
  11391. if (zSpan > maxSpan) {
  11392. maxSpan = zSpan;
  11393. diameter1 = zMin;
  11394. diameter2 = zMax;
  11395. }
  11396. // Calculate the center of the initial sphere found by Ritter's algorithm
  11397. var ritterCenter = fromPointsRitterCenter;
  11398. ritterCenter.x = (diameter1.x + diameter2.x) * 0.5;
  11399. ritterCenter.y = (diameter1.y + diameter2.y) * 0.5;
  11400. ritterCenter.z = (diameter1.z + diameter2.z) * 0.5;
  11401. // Calculate the radius of the initial sphere found by Ritter's algorithm
  11402. var radiusSquared = Cartesian3.magnitudeSquared(Cartesian3.subtract(diameter2, ritterCenter, fromPointsScratch));
  11403. var ritterRadius = Math.sqrt(radiusSquared);
  11404. // Find the center of the sphere found using the Naive method.
  11405. var minBoxPt = fromPointsMinBoxPt;
  11406. minBoxPt.x = xMin.x;
  11407. minBoxPt.y = yMin.y;
  11408. minBoxPt.z = zMin.z;
  11409. var maxBoxPt = fromPointsMaxBoxPt;
  11410. maxBoxPt.x = xMax.x;
  11411. maxBoxPt.y = yMax.y;
  11412. maxBoxPt.z = zMax.z;
  11413. var naiveCenter = Cartesian3.multiplyByScalar(Cartesian3.add(minBoxPt, maxBoxPt, fromPointsScratch), 0.5, fromPointsNaiveCenterScratch);
  11414. // Begin 2nd pass to find naive radius and modify the ritter sphere.
  11415. var naiveRadius = 0;
  11416. for (i = 0; i < numPositions; i++) {
  11417. Cartesian3.clone(positions[i], currentPos);
  11418. // Find the furthest point from the naive center to calculate the naive radius.
  11419. var r = Cartesian3.magnitude(Cartesian3.subtract(currentPos, naiveCenter, fromPointsScratch));
  11420. if (r > naiveRadius) {
  11421. naiveRadius = r;
  11422. }
  11423. // Make adjustments to the Ritter Sphere to include all points.
  11424. var oldCenterToPointSquared = Cartesian3.magnitudeSquared(Cartesian3.subtract(currentPos, ritterCenter, fromPointsScratch));
  11425. if (oldCenterToPointSquared > radiusSquared) {
  11426. var oldCenterToPoint = Math.sqrt(oldCenterToPointSquared);
  11427. // Calculate new radius to include the point that lies outside
  11428. ritterRadius = (ritterRadius + oldCenterToPoint) * 0.5;
  11429. radiusSquared = ritterRadius * ritterRadius;
  11430. // Calculate center of new Ritter sphere
  11431. var oldToNew = oldCenterToPoint - ritterRadius;
  11432. ritterCenter.x = (ritterRadius * ritterCenter.x + oldToNew * currentPos.x) / oldCenterToPoint;
  11433. ritterCenter.y = (ritterRadius * ritterCenter.y + oldToNew * currentPos.y) / oldCenterToPoint;
  11434. ritterCenter.z = (ritterRadius * ritterCenter.z + oldToNew * currentPos.z) / oldCenterToPoint;
  11435. }
  11436. }
  11437. if (ritterRadius < naiveRadius) {
  11438. Cartesian3.clone(ritterCenter, result.center);
  11439. result.radius = ritterRadius;
  11440. } else {
  11441. Cartesian3.clone(naiveCenter, result.center);
  11442. result.radius = naiveRadius;
  11443. }
  11444. return result;
  11445. };
  11446. var defaultProjection = new GeographicProjection();
  11447. var fromRectangle2DLowerLeft = new Cartesian3();
  11448. var fromRectangle2DUpperRight = new Cartesian3();
  11449. var fromRectangle2DSouthwest = new Cartographic();
  11450. var fromRectangle2DNortheast = new Cartographic();
  11451. /**
  11452. * Computes a bounding sphere from an rectangle projected in 2D.
  11453. *
  11454. * @param {Rectangle} rectangle The rectangle around which to create a bounding sphere.
  11455. * @param {Object} [projection=GeographicProjection] The projection used to project the rectangle into 2D.
  11456. * @param {BoundingSphere} [result] The object onto which to store the result.
  11457. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
  11458. */
  11459. BoundingSphere.fromRectangle2D = function(rectangle, projection, result) {
  11460. return BoundingSphere.fromRectangleWithHeights2D(rectangle, projection, 0.0, 0.0, result);
  11461. };
  11462. /**
  11463. * Computes a bounding sphere from an rectangle projected in 2D. The bounding sphere accounts for the
  11464. * object's minimum and maximum heights over the rectangle.
  11465. *
  11466. * @param {Rectangle} rectangle The rectangle around which to create a bounding sphere.
  11467. * @param {Object} [projection=GeographicProjection] The projection used to project the rectangle into 2D.
  11468. * @param {Number} [minimumHeight=0.0] The minimum height over the rectangle.
  11469. * @param {Number} [maximumHeight=0.0] The maximum height over the rectangle.
  11470. * @param {BoundingSphere} [result] The object onto which to store the result.
  11471. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
  11472. */
  11473. BoundingSphere.fromRectangleWithHeights2D = function(rectangle, projection, minimumHeight, maximumHeight, result) {
  11474. if (!defined(result)) {
  11475. result = new BoundingSphere();
  11476. }
  11477. if (!defined(rectangle)) {
  11478. result.center = Cartesian3.clone(Cartesian3.ZERO, result.center);
  11479. result.radius = 0.0;
  11480. return result;
  11481. }
  11482. projection = defaultValue(projection, defaultProjection);
  11483. Rectangle.southwest(rectangle, fromRectangle2DSouthwest);
  11484. fromRectangle2DSouthwest.height = minimumHeight;
  11485. Rectangle.northeast(rectangle, fromRectangle2DNortheast);
  11486. fromRectangle2DNortheast.height = maximumHeight;
  11487. var lowerLeft = projection.project(fromRectangle2DSouthwest, fromRectangle2DLowerLeft);
  11488. var upperRight = projection.project(fromRectangle2DNortheast, fromRectangle2DUpperRight);
  11489. var width = upperRight.x - lowerLeft.x;
  11490. var height = upperRight.y - lowerLeft.y;
  11491. var elevation = upperRight.z - lowerLeft.z;
  11492. result.radius = Math.sqrt(width * width + height * height + elevation * elevation) * 0.5;
  11493. var center = result.center;
  11494. center.x = lowerLeft.x + width * 0.5;
  11495. center.y = lowerLeft.y + height * 0.5;
  11496. center.z = lowerLeft.z + elevation * 0.5;
  11497. return result;
  11498. };
  11499. var fromRectangle3DScratch = [];
  11500. /**
  11501. * Computes a bounding sphere from an rectangle in 3D. The bounding sphere is created using a subsample of points
  11502. * on the ellipsoid and contained in the rectangle. It may not be accurate for all rectangles on all types of ellipsoids.
  11503. *
  11504. * @param {Rectangle} rectangle The valid rectangle used to create a bounding sphere.
  11505. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid used to determine positions of the rectangle.
  11506. * @param {Number} [surfaceHeight=0.0] The height above the surface of the ellipsoid.
  11507. * @param {BoundingSphere} [result] The object onto which to store the result.
  11508. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
  11509. */
  11510. BoundingSphere.fromRectangle3D = function(rectangle, ellipsoid, surfaceHeight, result) {
  11511. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  11512. surfaceHeight = defaultValue(surfaceHeight, 0.0);
  11513. var positions;
  11514. if (defined(rectangle)) {
  11515. positions = Rectangle.subsample(rectangle, ellipsoid, surfaceHeight, fromRectangle3DScratch);
  11516. }
  11517. return BoundingSphere.fromPoints(positions, result);
  11518. };
  11519. /**
  11520. * Computes a tight-fitting bounding sphere enclosing a list of 3D points, where the points are
  11521. * stored in a flat array in X, Y, Z, order. The bounding sphere is computed by running two
  11522. * algorithms, a naive algorithm and Ritter's algorithm. The smaller of the two spheres is used to
  11523. * ensure a tight fit.
  11524. *
  11525. * @param {Number[]} positions An array of points that the bounding sphere will enclose. Each point
  11526. * is formed from three elements in the array in the order X, Y, Z.
  11527. * @param {Cartesian3} [center=Cartesian3.ZERO] The position to which the positions are relative, which need not be the
  11528. * origin of the coordinate system. This is useful when the positions are to be used for
  11529. * relative-to-center (RTC) rendering.
  11530. * @param {Number} [stride=3] The number of array elements per vertex. It must be at least 3, but it may
  11531. * be higher. Regardless of the value of this parameter, the X coordinate of the first position
  11532. * is at array index 0, the Y coordinate is at array index 1, and the Z coordinate is at array index
  11533. * 2. When stride is 3, the X coordinate of the next position then begins at array index 3. If
  11534. * the stride is 5, however, two array elements are skipped and the next position begins at array
  11535. * index 5.
  11536. * @param {BoundingSphere} [result] The object onto which to store the result.
  11537. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if one was not provided.
  11538. *
  11539. * @example
  11540. * // Compute the bounding sphere from 3 positions, each specified relative to a center.
  11541. * // In addition to the X, Y, and Z coordinates, the points array contains two additional
  11542. * // elements per point which are ignored for the purpose of computing the bounding sphere.
  11543. * var center = new Cesium.Cartesian3(1.0, 2.0, 3.0);
  11544. * var points = [1.0, 2.0, 3.0, 0.1, 0.2,
  11545. * 4.0, 5.0, 6.0, 0.1, 0.2,
  11546. * 7.0, 8.0, 9.0, 0.1, 0.2];
  11547. * var sphere = Cesium.BoundingSphere.fromVertices(points, center, 5);
  11548. *
  11549. * @see {@link http://blogs.agi.com/insight3d/index.php/2008/02/04/a-bounding/|Bounding Sphere computation article}
  11550. */
  11551. BoundingSphere.fromVertices = function(positions, center, stride, result) {
  11552. if (!defined(result)) {
  11553. result = new BoundingSphere();
  11554. }
  11555. if (!defined(positions) || positions.length === 0) {
  11556. result.center = Cartesian3.clone(Cartesian3.ZERO, result.center);
  11557. result.radius = 0.0;
  11558. return result;
  11559. }
  11560. center = defaultValue(center, Cartesian3.ZERO);
  11561. stride = defaultValue(stride, 3);
  11562. if (stride < 3) {
  11563. throw new DeveloperError('stride must be 3 or greater.');
  11564. }
  11565. var currentPos = fromPointsCurrentPos;
  11566. currentPos.x = positions[0] + center.x;
  11567. currentPos.y = positions[1] + center.y;
  11568. currentPos.z = positions[2] + center.z;
  11569. var xMin = Cartesian3.clone(currentPos, fromPointsXMin);
  11570. var yMin = Cartesian3.clone(currentPos, fromPointsYMin);
  11571. var zMin = Cartesian3.clone(currentPos, fromPointsZMin);
  11572. var xMax = Cartesian3.clone(currentPos, fromPointsXMax);
  11573. var yMax = Cartesian3.clone(currentPos, fromPointsYMax);
  11574. var zMax = Cartesian3.clone(currentPos, fromPointsZMax);
  11575. var numElements = positions.length;
  11576. for (var i = 0; i < numElements; i += stride) {
  11577. var x = positions[i] + center.x;
  11578. var y = positions[i + 1] + center.y;
  11579. var z = positions[i + 2] + center.z;
  11580. currentPos.x = x;
  11581. currentPos.y = y;
  11582. currentPos.z = z;
  11583. // Store points containing the the smallest and largest components
  11584. if (x < xMin.x) {
  11585. Cartesian3.clone(currentPos, xMin);
  11586. }
  11587. if (x > xMax.x) {
  11588. Cartesian3.clone(currentPos, xMax);
  11589. }
  11590. if (y < yMin.y) {
  11591. Cartesian3.clone(currentPos, yMin);
  11592. }
  11593. if (y > yMax.y) {
  11594. Cartesian3.clone(currentPos, yMax);
  11595. }
  11596. if (z < zMin.z) {
  11597. Cartesian3.clone(currentPos, zMin);
  11598. }
  11599. if (z > zMax.z) {
  11600. Cartesian3.clone(currentPos, zMax);
  11601. }
  11602. }
  11603. // Compute x-, y-, and z-spans (Squared distances b/n each component's min. and max.).
  11604. var xSpan = Cartesian3.magnitudeSquared(Cartesian3.subtract(xMax, xMin, fromPointsScratch));
  11605. var ySpan = Cartesian3.magnitudeSquared(Cartesian3.subtract(yMax, yMin, fromPointsScratch));
  11606. var zSpan = Cartesian3.magnitudeSquared(Cartesian3.subtract(zMax, zMin, fromPointsScratch));
  11607. // Set the diameter endpoints to the largest span.
  11608. var diameter1 = xMin;
  11609. var diameter2 = xMax;
  11610. var maxSpan = xSpan;
  11611. if (ySpan > maxSpan) {
  11612. maxSpan = ySpan;
  11613. diameter1 = yMin;
  11614. diameter2 = yMax;
  11615. }
  11616. if (zSpan > maxSpan) {
  11617. maxSpan = zSpan;
  11618. diameter1 = zMin;
  11619. diameter2 = zMax;
  11620. }
  11621. // Calculate the center of the initial sphere found by Ritter's algorithm
  11622. var ritterCenter = fromPointsRitterCenter;
  11623. ritterCenter.x = (diameter1.x + diameter2.x) * 0.5;
  11624. ritterCenter.y = (diameter1.y + diameter2.y) * 0.5;
  11625. ritterCenter.z = (diameter1.z + diameter2.z) * 0.5;
  11626. // Calculate the radius of the initial sphere found by Ritter's algorithm
  11627. var radiusSquared = Cartesian3.magnitudeSquared(Cartesian3.subtract(diameter2, ritterCenter, fromPointsScratch));
  11628. var ritterRadius = Math.sqrt(radiusSquared);
  11629. // Find the center of the sphere found using the Naive method.
  11630. var minBoxPt = fromPointsMinBoxPt;
  11631. minBoxPt.x = xMin.x;
  11632. minBoxPt.y = yMin.y;
  11633. minBoxPt.z = zMin.z;
  11634. var maxBoxPt = fromPointsMaxBoxPt;
  11635. maxBoxPt.x = xMax.x;
  11636. maxBoxPt.y = yMax.y;
  11637. maxBoxPt.z = zMax.z;
  11638. var naiveCenter = Cartesian3.multiplyByScalar(Cartesian3.add(minBoxPt, maxBoxPt, fromPointsScratch), 0.5, fromPointsNaiveCenterScratch);
  11639. // Begin 2nd pass to find naive radius and modify the ritter sphere.
  11640. var naiveRadius = 0;
  11641. for (i = 0; i < numElements; i += stride) {
  11642. currentPos.x = positions[i] + center.x;
  11643. currentPos.y = positions[i + 1] + center.y;
  11644. currentPos.z = positions[i + 2] + center.z;
  11645. // Find the furthest point from the naive center to calculate the naive radius.
  11646. var r = Cartesian3.magnitude(Cartesian3.subtract(currentPos, naiveCenter, fromPointsScratch));
  11647. if (r > naiveRadius) {
  11648. naiveRadius = r;
  11649. }
  11650. // Make adjustments to the Ritter Sphere to include all points.
  11651. var oldCenterToPointSquared = Cartesian3.magnitudeSquared(Cartesian3.subtract(currentPos, ritterCenter, fromPointsScratch));
  11652. if (oldCenterToPointSquared > radiusSquared) {
  11653. var oldCenterToPoint = Math.sqrt(oldCenterToPointSquared);
  11654. // Calculate new radius to include the point that lies outside
  11655. ritterRadius = (ritterRadius + oldCenterToPoint) * 0.5;
  11656. radiusSquared = ritterRadius * ritterRadius;
  11657. // Calculate center of new Ritter sphere
  11658. var oldToNew = oldCenterToPoint - ritterRadius;
  11659. ritterCenter.x = (ritterRadius * ritterCenter.x + oldToNew * currentPos.x) / oldCenterToPoint;
  11660. ritterCenter.y = (ritterRadius * ritterCenter.y + oldToNew * currentPos.y) / oldCenterToPoint;
  11661. ritterCenter.z = (ritterRadius * ritterCenter.z + oldToNew * currentPos.z) / oldCenterToPoint;
  11662. }
  11663. }
  11664. if (ritterRadius < naiveRadius) {
  11665. Cartesian3.clone(ritterCenter, result.center);
  11666. result.radius = ritterRadius;
  11667. } else {
  11668. Cartesian3.clone(naiveCenter, result.center);
  11669. result.radius = naiveRadius;
  11670. }
  11671. return result;
  11672. };
  11673. /**
  11674. * Computes a tight-fitting bounding sphere enclosing a list of {@link EncodedCartesian3}s, where the points are
  11675. * stored in parallel flat arrays in X, Y, Z, order. The bounding sphere is computed by running two
  11676. * algorithms, a naive algorithm and Ritter's algorithm. The smaller of the two spheres is used to
  11677. * ensure a tight fit.
  11678. *
  11679. * @param {Number[]} positionsHigh An array of high bits of the encoded cartesians that the bounding sphere will enclose. Each point
  11680. * is formed from three elements in the array in the order X, Y, Z.
  11681. * @param {Number[]} positionsLow An array of low bits of the encoded cartesians that the bounding sphere will enclose. Each point
  11682. * is formed from three elements in the array in the order X, Y, Z.
  11683. * @param {BoundingSphere} [result] The object onto which to store the result.
  11684. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if one was not provided.
  11685. *
  11686. * @see {@link http://blogs.agi.com/insight3d/index.php/2008/02/04/a-bounding/|Bounding Sphere computation article}
  11687. */
  11688. BoundingSphere.fromEncodedCartesianVertices = function(positionsHigh, positionsLow, result) {
  11689. if (!defined(result)) {
  11690. result = new BoundingSphere();
  11691. }
  11692. if (!defined(positionsHigh) || !defined(positionsLow) || positionsHigh.length !== positionsLow.length || positionsHigh.length === 0) {
  11693. result.center = Cartesian3.clone(Cartesian3.ZERO, result.center);
  11694. result.radius = 0.0;
  11695. return result;
  11696. }
  11697. var currentPos = fromPointsCurrentPos;
  11698. currentPos.x = positionsHigh[0] + positionsLow[0];
  11699. currentPos.y = positionsHigh[1] + positionsLow[1];
  11700. currentPos.z = positionsHigh[2] + positionsLow[2];
  11701. var xMin = Cartesian3.clone(currentPos, fromPointsXMin);
  11702. var yMin = Cartesian3.clone(currentPos, fromPointsYMin);
  11703. var zMin = Cartesian3.clone(currentPos, fromPointsZMin);
  11704. var xMax = Cartesian3.clone(currentPos, fromPointsXMax);
  11705. var yMax = Cartesian3.clone(currentPos, fromPointsYMax);
  11706. var zMax = Cartesian3.clone(currentPos, fromPointsZMax);
  11707. var numElements = positionsHigh.length;
  11708. for (var i = 0; i < numElements; i += 3) {
  11709. var x = positionsHigh[i] + positionsLow[i];
  11710. var y = positionsHigh[i + 1] + positionsLow[i + 1];
  11711. var z = positionsHigh[i + 2] + positionsLow[i + 2];
  11712. currentPos.x = x;
  11713. currentPos.y = y;
  11714. currentPos.z = z;
  11715. // Store points containing the the smallest and largest components
  11716. if (x < xMin.x) {
  11717. Cartesian3.clone(currentPos, xMin);
  11718. }
  11719. if (x > xMax.x) {
  11720. Cartesian3.clone(currentPos, xMax);
  11721. }
  11722. if (y < yMin.y) {
  11723. Cartesian3.clone(currentPos, yMin);
  11724. }
  11725. if (y > yMax.y) {
  11726. Cartesian3.clone(currentPos, yMax);
  11727. }
  11728. if (z < zMin.z) {
  11729. Cartesian3.clone(currentPos, zMin);
  11730. }
  11731. if (z > zMax.z) {
  11732. Cartesian3.clone(currentPos, zMax);
  11733. }
  11734. }
  11735. // Compute x-, y-, and z-spans (Squared distances b/n each component's min. and max.).
  11736. var xSpan = Cartesian3.magnitudeSquared(Cartesian3.subtract(xMax, xMin, fromPointsScratch));
  11737. var ySpan = Cartesian3.magnitudeSquared(Cartesian3.subtract(yMax, yMin, fromPointsScratch));
  11738. var zSpan = Cartesian3.magnitudeSquared(Cartesian3.subtract(zMax, zMin, fromPointsScratch));
  11739. // Set the diameter endpoints to the largest span.
  11740. var diameter1 = xMin;
  11741. var diameter2 = xMax;
  11742. var maxSpan = xSpan;
  11743. if (ySpan > maxSpan) {
  11744. maxSpan = ySpan;
  11745. diameter1 = yMin;
  11746. diameter2 = yMax;
  11747. }
  11748. if (zSpan > maxSpan) {
  11749. maxSpan = zSpan;
  11750. diameter1 = zMin;
  11751. diameter2 = zMax;
  11752. }
  11753. // Calculate the center of the initial sphere found by Ritter's algorithm
  11754. var ritterCenter = fromPointsRitterCenter;
  11755. ritterCenter.x = (diameter1.x + diameter2.x) * 0.5;
  11756. ritterCenter.y = (diameter1.y + diameter2.y) * 0.5;
  11757. ritterCenter.z = (diameter1.z + diameter2.z) * 0.5;
  11758. // Calculate the radius of the initial sphere found by Ritter's algorithm
  11759. var radiusSquared = Cartesian3.magnitudeSquared(Cartesian3.subtract(diameter2, ritterCenter, fromPointsScratch));
  11760. var ritterRadius = Math.sqrt(radiusSquared);
  11761. // Find the center of the sphere found using the Naive method.
  11762. var minBoxPt = fromPointsMinBoxPt;
  11763. minBoxPt.x = xMin.x;
  11764. minBoxPt.y = yMin.y;
  11765. minBoxPt.z = zMin.z;
  11766. var maxBoxPt = fromPointsMaxBoxPt;
  11767. maxBoxPt.x = xMax.x;
  11768. maxBoxPt.y = yMax.y;
  11769. maxBoxPt.z = zMax.z;
  11770. var naiveCenter = Cartesian3.multiplyByScalar(Cartesian3.add(minBoxPt, maxBoxPt, fromPointsScratch), 0.5, fromPointsNaiveCenterScratch);
  11771. // Begin 2nd pass to find naive radius and modify the ritter sphere.
  11772. var naiveRadius = 0;
  11773. for (i = 0; i < numElements; i += 3) {
  11774. currentPos.x = positionsHigh[i] + positionsLow[i];
  11775. currentPos.y = positionsHigh[i + 1] + positionsLow[i + 1];
  11776. currentPos.z = positionsHigh[i + 2] + positionsLow[i + 2];
  11777. // Find the furthest point from the naive center to calculate the naive radius.
  11778. var r = Cartesian3.magnitude(Cartesian3.subtract(currentPos, naiveCenter, fromPointsScratch));
  11779. if (r > naiveRadius) {
  11780. naiveRadius = r;
  11781. }
  11782. // Make adjustments to the Ritter Sphere to include all points.
  11783. var oldCenterToPointSquared = Cartesian3.magnitudeSquared(Cartesian3.subtract(currentPos, ritterCenter, fromPointsScratch));
  11784. if (oldCenterToPointSquared > radiusSquared) {
  11785. var oldCenterToPoint = Math.sqrt(oldCenterToPointSquared);
  11786. // Calculate new radius to include the point that lies outside
  11787. ritterRadius = (ritterRadius + oldCenterToPoint) * 0.5;
  11788. radiusSquared = ritterRadius * ritterRadius;
  11789. // Calculate center of new Ritter sphere
  11790. var oldToNew = oldCenterToPoint - ritterRadius;
  11791. ritterCenter.x = (ritterRadius * ritterCenter.x + oldToNew * currentPos.x) / oldCenterToPoint;
  11792. ritterCenter.y = (ritterRadius * ritterCenter.y + oldToNew * currentPos.y) / oldCenterToPoint;
  11793. ritterCenter.z = (ritterRadius * ritterCenter.z + oldToNew * currentPos.z) / oldCenterToPoint;
  11794. }
  11795. }
  11796. if (ritterRadius < naiveRadius) {
  11797. Cartesian3.clone(ritterCenter, result.center);
  11798. result.radius = ritterRadius;
  11799. } else {
  11800. Cartesian3.clone(naiveCenter, result.center);
  11801. result.radius = naiveRadius;
  11802. }
  11803. return result;
  11804. };
  11805. /**
  11806. * Computes a bounding sphere from the corner points of an axis-aligned bounding box. The sphere
  11807. * tighly and fully encompases the box.
  11808. *
  11809. * @param {Cartesian3} [corner] The minimum height over the rectangle.
  11810. * @param {Cartesian3} [oppositeCorner] The maximum height over the rectangle.
  11811. * @param {BoundingSphere} [result] The object onto which to store the result.
  11812. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
  11813. *
  11814. * @example
  11815. * // Create a bounding sphere around the unit cube
  11816. * var sphere = Cesium.BoundingSphere.fromCornerPoints(new Cesium.Cartesian3(-0.5, -0.5, -0.5), new Cesium.Cartesian3(0.5, 0.5, 0.5));
  11817. */
  11818. BoundingSphere.fromCornerPoints = function(corner, oppositeCorner, result) {
  11819. if (!defined(corner) || !defined(oppositeCorner)) {
  11820. throw new DeveloperError('corner and oppositeCorner are required.');
  11821. }
  11822. if (!defined(result)) {
  11823. result = new BoundingSphere();
  11824. }
  11825. var center = result.center;
  11826. Cartesian3.add(corner, oppositeCorner, center);
  11827. Cartesian3.multiplyByScalar(center, 0.5, center);
  11828. result.radius = Cartesian3.distance(center, oppositeCorner);
  11829. return result;
  11830. };
  11831. /**
  11832. * Creates a bounding sphere encompassing an ellipsoid.
  11833. *
  11834. * @param {Ellipsoid} ellipsoid The ellipsoid around which to create a bounding sphere.
  11835. * @param {BoundingSphere} [result] The object onto which to store the result.
  11836. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
  11837. *
  11838. * @example
  11839. * var boundingSphere = Cesium.BoundingSphere.fromEllipsoid(ellipsoid);
  11840. */
  11841. BoundingSphere.fromEllipsoid = function(ellipsoid, result) {
  11842. if (!defined(ellipsoid)) {
  11843. throw new DeveloperError('ellipsoid is required.');
  11844. }
  11845. if (!defined(result)) {
  11846. result = new BoundingSphere();
  11847. }
  11848. Cartesian3.clone(Cartesian3.ZERO, result.center);
  11849. result.radius = ellipsoid.maximumRadius;
  11850. return result;
  11851. };
  11852. var fromBoundingSpheresScratch = new Cartesian3();
  11853. /**
  11854. * Computes a tight-fitting bounding sphere enclosing the provided array of bounding spheres.
  11855. *
  11856. * @param {BoundingSphere[]} boundingSpheres The array of bounding spheres.
  11857. * @param {BoundingSphere} [result] The object onto which to store the result.
  11858. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
  11859. */
  11860. BoundingSphere.fromBoundingSpheres = function(boundingSpheres, result) {
  11861. if (!defined(result)) {
  11862. result = new BoundingSphere();
  11863. }
  11864. if (!defined(boundingSpheres) || boundingSpheres.length === 0) {
  11865. result.center = Cartesian3.clone(Cartesian3.ZERO, result.center);
  11866. result.radius = 0.0;
  11867. return result;
  11868. }
  11869. var length = boundingSpheres.length;
  11870. if (length === 1) {
  11871. return BoundingSphere.clone(boundingSpheres[0], result);
  11872. }
  11873. if (length === 2) {
  11874. return BoundingSphere.union(boundingSpheres[0], boundingSpheres[1], result);
  11875. }
  11876. var positions = [];
  11877. for (var i = 0; i < length; i++) {
  11878. positions.push(boundingSpheres[i].center);
  11879. }
  11880. result = BoundingSphere.fromPoints(positions, result);
  11881. var center = result.center;
  11882. var radius = result.radius;
  11883. for (i = 0; i < length; i++) {
  11884. var tmp = boundingSpheres[i];
  11885. radius = Math.max(radius, Cartesian3.distance(center, tmp.center, fromBoundingSpheresScratch) + tmp.radius);
  11886. }
  11887. result.radius = radius;
  11888. return result;
  11889. };
  11890. var fromOrientedBoundingBoxScratchU = new Cartesian3();
  11891. var fromOrientedBoundingBoxScratchV = new Cartesian3();
  11892. var fromOrientedBoundingBoxScratchW = new Cartesian3();
  11893. /**
  11894. * Computes a tight-fitting bounding sphere enclosing the provided oriented bounding box.
  11895. *
  11896. * @param {OrientedBoundingBox} orientedBoundingBox The oriented bounding box.
  11897. * @param {BoundingSphere} [result] The object onto which to store the result.
  11898. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
  11899. */
  11900. BoundingSphere.fromOrientedBoundingBox = function(orientedBoundingBox, result) {
  11901. if (!defined(result)) {
  11902. result = new BoundingSphere();
  11903. }
  11904. var halfAxes = orientedBoundingBox.halfAxes;
  11905. var u = Matrix3.getColumn(halfAxes, 0, fromOrientedBoundingBoxScratchU);
  11906. var v = Matrix3.getColumn(halfAxes, 1, fromOrientedBoundingBoxScratchV);
  11907. var w = Matrix3.getColumn(halfAxes, 2, fromOrientedBoundingBoxScratchW);
  11908. var uHalf = Cartesian3.magnitude(u);
  11909. var vHalf = Cartesian3.magnitude(v);
  11910. var wHalf = Cartesian3.magnitude(w);
  11911. result.center = Cartesian3.clone(orientedBoundingBox.center, result.center);
  11912. result.radius = Math.max(uHalf, vHalf, wHalf);
  11913. return result;
  11914. };
  11915. /**
  11916. * Duplicates a BoundingSphere instance.
  11917. *
  11918. * @param {BoundingSphere} sphere The bounding sphere to duplicate.
  11919. * @param {BoundingSphere} [result] The object onto which to store the result.
  11920. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. (Returns undefined if sphere is undefined)
  11921. */
  11922. BoundingSphere.clone = function(sphere, result) {
  11923. if (!defined(sphere)) {
  11924. return undefined;
  11925. }
  11926. if (!defined(result)) {
  11927. return new BoundingSphere(sphere.center, sphere.radius);
  11928. }
  11929. result.center = Cartesian3.clone(sphere.center, result.center);
  11930. result.radius = sphere.radius;
  11931. return result;
  11932. };
  11933. /**
  11934. * The number of elements used to pack the object into an array.
  11935. * @type {Number}
  11936. */
  11937. BoundingSphere.packedLength = 4;
  11938. /**
  11939. * Stores the provided instance into the provided array.
  11940. *
  11941. * @param {BoundingSphere} value The value to pack.
  11942. * @param {Number[]} array The array to pack into.
  11943. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  11944. *
  11945. * @returns {Number[]} The array that was packed into
  11946. */
  11947. BoundingSphere.pack = function(value, array, startingIndex) {
  11948. if (!defined(value)) {
  11949. throw new DeveloperError('value is required');
  11950. }
  11951. if (!defined(array)) {
  11952. throw new DeveloperError('array is required');
  11953. }
  11954. startingIndex = defaultValue(startingIndex, 0);
  11955. var center = value.center;
  11956. array[startingIndex++] = center.x;
  11957. array[startingIndex++] = center.y;
  11958. array[startingIndex++] = center.z;
  11959. array[startingIndex] = value.radius;
  11960. return array;
  11961. };
  11962. /**
  11963. * Retrieves an instance from a packed array.
  11964. *
  11965. * @param {Number[]} array The packed array.
  11966. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  11967. * @param {BoundingSphere} [result] The object into which to store the result.
  11968. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if one was not provided.
  11969. */
  11970. BoundingSphere.unpack = function(array, startingIndex, result) {
  11971. if (!defined(array)) {
  11972. throw new DeveloperError('array is required');
  11973. }
  11974. startingIndex = defaultValue(startingIndex, 0);
  11975. if (!defined(result)) {
  11976. result = new BoundingSphere();
  11977. }
  11978. var center = result.center;
  11979. center.x = array[startingIndex++];
  11980. center.y = array[startingIndex++];
  11981. center.z = array[startingIndex++];
  11982. result.radius = array[startingIndex];
  11983. return result;
  11984. };
  11985. var unionScratch = new Cartesian3();
  11986. var unionScratchCenter = new Cartesian3();
  11987. /**
  11988. * Computes a bounding sphere that contains both the left and right bounding spheres.
  11989. *
  11990. * @param {BoundingSphere} left A sphere to enclose in a bounding sphere.
  11991. * @param {BoundingSphere} right A sphere to enclose in a bounding sphere.
  11992. * @param {BoundingSphere} [result] The object onto which to store the result.
  11993. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
  11994. */
  11995. BoundingSphere.union = function(left, right, result) {
  11996. if (!defined(left)) {
  11997. throw new DeveloperError('left is required.');
  11998. }
  11999. if (!defined(right)) {
  12000. throw new DeveloperError('right is required.');
  12001. }
  12002. if (!defined(result)) {
  12003. result = new BoundingSphere();
  12004. }
  12005. var leftCenter = left.center;
  12006. var leftRadius = left.radius;
  12007. var rightCenter = right.center;
  12008. var rightRadius = right.radius;
  12009. var toRightCenter = Cartesian3.subtract(rightCenter, leftCenter, unionScratch);
  12010. var centerSeparation = Cartesian3.magnitude(toRightCenter);
  12011. if (leftRadius >= (centerSeparation + rightRadius)) {
  12012. // Left sphere wins.
  12013. left.clone(result);
  12014. return result;
  12015. }
  12016. if (rightRadius >= (centerSeparation + leftRadius)) {
  12017. // Right sphere wins.
  12018. right.clone(result);
  12019. return result;
  12020. }
  12021. // There are two tangent points, one on far side of each sphere.
  12022. var halfDistanceBetweenTangentPoints = (leftRadius + centerSeparation + rightRadius) * 0.5;
  12023. // Compute the center point halfway between the two tangent points.
  12024. var center = Cartesian3.multiplyByScalar(toRightCenter,
  12025. (-leftRadius + halfDistanceBetweenTangentPoints) / centerSeparation, unionScratchCenter);
  12026. Cartesian3.add(center, leftCenter, center);
  12027. Cartesian3.clone(center, result.center);
  12028. result.radius = halfDistanceBetweenTangentPoints;
  12029. return result;
  12030. };
  12031. var expandScratch = new Cartesian3();
  12032. /**
  12033. * Computes a bounding sphere by enlarging the provided sphere to contain the provided point.
  12034. *
  12035. * @param {BoundingSphere} sphere A sphere to expand.
  12036. * @param {Cartesian3} point A point to enclose in a bounding sphere.
  12037. * @param {BoundingSphere} [result] The object onto which to store the result.
  12038. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
  12039. */
  12040. BoundingSphere.expand = function(sphere, point, result) {
  12041. if (!defined(sphere)) {
  12042. throw new DeveloperError('sphere is required.');
  12043. }
  12044. if (!defined(point)) {
  12045. throw new DeveloperError('point is required.');
  12046. }
  12047. result = BoundingSphere.clone(sphere, result);
  12048. var radius = Cartesian3.magnitude(Cartesian3.subtract(point, result.center, expandScratch));
  12049. if (radius > result.radius) {
  12050. result.radius = radius;
  12051. }
  12052. return result;
  12053. };
  12054. /**
  12055. * Determines which side of a plane a sphere is located.
  12056. *
  12057. * @param {BoundingSphere} sphere The bounding sphere to test.
  12058. * @param {Plane} plane The plane to test against.
  12059. * @returns {Intersect} {@link Intersect.INSIDE} if the entire sphere is on the side of the plane
  12060. * the normal is pointing, {@link Intersect.OUTSIDE} if the entire sphere is
  12061. * on the opposite side, and {@link Intersect.INTERSECTING} if the sphere
  12062. * intersects the plane.
  12063. */
  12064. BoundingSphere.intersectPlane = function(sphere, plane) {
  12065. if (!defined(sphere)) {
  12066. throw new DeveloperError('sphere is required.');
  12067. }
  12068. if (!defined(plane)) {
  12069. throw new DeveloperError('plane is required.');
  12070. }
  12071. var center = sphere.center;
  12072. var radius = sphere.radius;
  12073. var normal = plane.normal;
  12074. var distanceToPlane = Cartesian3.dot(normal, center) + plane.distance;
  12075. if (distanceToPlane < -radius) {
  12076. // The center point is negative side of the plane normal
  12077. return Intersect.OUTSIDE;
  12078. } else if (distanceToPlane < radius) {
  12079. // The center point is positive side of the plane, but radius extends beyond it; partial overlap
  12080. return Intersect.INTERSECTING;
  12081. }
  12082. return Intersect.INSIDE;
  12083. };
  12084. /**
  12085. * Applies a 4x4 affine transformation matrix to a bounding sphere.
  12086. *
  12087. * @param {BoundingSphere} sphere The bounding sphere to apply the transformation to.
  12088. * @param {Matrix4} transform The transformation matrix to apply to the bounding sphere.
  12089. * @param {BoundingSphere} [result] The object onto which to store the result.
  12090. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
  12091. */
  12092. BoundingSphere.transform = function(sphere, transform, result) {
  12093. if (!defined(sphere)) {
  12094. throw new DeveloperError('sphere is required.');
  12095. }
  12096. if (!defined(transform)) {
  12097. throw new DeveloperError('transform is required.');
  12098. }
  12099. if (!defined(result)) {
  12100. result = new BoundingSphere();
  12101. }
  12102. result.center = Matrix4.multiplyByPoint(transform, sphere.center, result.center);
  12103. result.radius = Matrix4.getMaximumScale(transform) * sphere.radius;
  12104. return result;
  12105. };
  12106. var distanceSquaredToScratch = new Cartesian3();
  12107. /**
  12108. * Computes the estimated distance squared from the closest point on a bounding sphere to a point.
  12109. *
  12110. * @param {BoundingSphere} sphere The sphere.
  12111. * @param {Cartesian3} cartesian The point
  12112. * @returns {Number} The estimated distance squared from the bounding sphere to the point.
  12113. *
  12114. * @example
  12115. * // Sort bounding spheres from back to front
  12116. * spheres.sort(function(a, b) {
  12117. * return Cesium.BoundingSphere.distanceSquaredTo(b, camera.positionWC) - Cesium.BoundingSphere.distanceSquaredTo(a, camera.positionWC);
  12118. * });
  12119. */
  12120. BoundingSphere.distanceSquaredTo = function(sphere, cartesian) {
  12121. if (!defined(sphere)) {
  12122. throw new DeveloperError('sphere is required.');
  12123. }
  12124. if (!defined(cartesian)) {
  12125. throw new DeveloperError('cartesian is required.');
  12126. }
  12127. var diff = Cartesian3.subtract(sphere.center, cartesian, distanceSquaredToScratch);
  12128. return Cartesian3.magnitudeSquared(diff) - sphere.radius * sphere.radius;
  12129. };
  12130. /**
  12131. * Applies a 4x4 affine transformation matrix to a bounding sphere where there is no scale
  12132. * The transformation matrix is not verified to have a uniform scale of 1.
  12133. * This method is faster than computing the general bounding sphere transform using {@link BoundingSphere.transform}.
  12134. *
  12135. * @param {BoundingSphere} sphere The bounding sphere to apply the transformation to.
  12136. * @param {Matrix4} transform The transformation matrix to apply to the bounding sphere.
  12137. * @param {BoundingSphere} [result] The object onto which to store the result.
  12138. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
  12139. *
  12140. * @example
  12141. * var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(positionOnEllipsoid);
  12142. * var boundingSphere = new Cesium.BoundingSphere();
  12143. * var newBoundingSphere = Cesium.BoundingSphere.transformWithoutScale(boundingSphere, modelMatrix);
  12144. */
  12145. BoundingSphere.transformWithoutScale = function(sphere, transform, result) {
  12146. if (!defined(sphere)) {
  12147. throw new DeveloperError('sphere is required.');
  12148. }
  12149. if (!defined(transform)) {
  12150. throw new DeveloperError('transform is required.');
  12151. }
  12152. if (!defined(result)) {
  12153. result = new BoundingSphere();
  12154. }
  12155. result.center = Matrix4.multiplyByPoint(transform, sphere.center, result.center);
  12156. result.radius = sphere.radius;
  12157. return result;
  12158. };
  12159. var scratchCartesian3 = new Cartesian3();
  12160. /**
  12161. * The distances calculated by the vector from the center of the bounding sphere to position projected onto direction
  12162. * plus/minus the radius of the bounding sphere.
  12163. * <br>
  12164. * If you imagine the infinite number of planes with normal direction, this computes the smallest distance to the
  12165. * closest and farthest planes from position that intersect the bounding sphere.
  12166. *
  12167. * @param {BoundingSphere} sphere The bounding sphere to calculate the distance to.
  12168. * @param {Cartesian3} position The position to calculate the distance from.
  12169. * @param {Cartesian3} direction The direction from position.
  12170. * @param {Interval} [result] A Interval to store the nearest and farthest distances.
  12171. * @returns {Interval} The nearest and farthest distances on the bounding sphere from position in direction.
  12172. */
  12173. BoundingSphere.computePlaneDistances = function(sphere, position, direction, result) {
  12174. if (!defined(sphere)) {
  12175. throw new DeveloperError('sphere is required.');
  12176. }
  12177. if (!defined(position)) {
  12178. throw new DeveloperError('position is required.');
  12179. }
  12180. if (!defined(direction)) {
  12181. throw new DeveloperError('direction is required.');
  12182. }
  12183. if (!defined(result)) {
  12184. result = new Interval();
  12185. }
  12186. var toCenter = Cartesian3.subtract(sphere.center, position, scratchCartesian3);
  12187. var mag = Cartesian3.dot(direction, toCenter);
  12188. result.start = mag - sphere.radius;
  12189. result.stop = mag + sphere.radius;
  12190. return result;
  12191. };
  12192. var projectTo2DNormalScratch = new Cartesian3();
  12193. var projectTo2DEastScratch = new Cartesian3();
  12194. var projectTo2DNorthScratch = new Cartesian3();
  12195. var projectTo2DWestScratch = new Cartesian3();
  12196. var projectTo2DSouthScratch = new Cartesian3();
  12197. var projectTo2DCartographicScratch = new Cartographic();
  12198. var projectTo2DPositionsScratch = new Array(8);
  12199. for (var n = 0; n < 8; ++n) {
  12200. projectTo2DPositionsScratch[n] = new Cartesian3();
  12201. }
  12202. var projectTo2DProjection = new GeographicProjection();
  12203. /**
  12204. * Creates a bounding sphere in 2D from a bounding sphere in 3D world coordinates.
  12205. *
  12206. * @param {BoundingSphere} sphere The bounding sphere to transform to 2D.
  12207. * @param {Object} [projection=GeographicProjection] The projection to 2D.
  12208. * @param {BoundingSphere} [result] The object onto which to store the result.
  12209. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
  12210. */
  12211. BoundingSphere.projectTo2D = function(sphere, projection, result) {
  12212. if (!defined(sphere)) {
  12213. throw new DeveloperError('sphere is required.');
  12214. }
  12215. projection = defaultValue(projection, projectTo2DProjection);
  12216. var ellipsoid = projection.ellipsoid;
  12217. var center = sphere.center;
  12218. var radius = sphere.radius;
  12219. var normal = ellipsoid.geodeticSurfaceNormal(center, projectTo2DNormalScratch);
  12220. var east = Cartesian3.cross(Cartesian3.UNIT_Z, normal, projectTo2DEastScratch);
  12221. Cartesian3.normalize(east, east);
  12222. var north = Cartesian3.cross(normal, east, projectTo2DNorthScratch);
  12223. Cartesian3.normalize(north, north);
  12224. Cartesian3.multiplyByScalar(normal, radius, normal);
  12225. Cartesian3.multiplyByScalar(north, radius, north);
  12226. Cartesian3.multiplyByScalar(east, radius, east);
  12227. var south = Cartesian3.negate(north, projectTo2DSouthScratch);
  12228. var west = Cartesian3.negate(east, projectTo2DWestScratch);
  12229. var positions = projectTo2DPositionsScratch;
  12230. // top NE corner
  12231. var corner = positions[0];
  12232. Cartesian3.add(normal, north, corner);
  12233. Cartesian3.add(corner, east, corner);
  12234. // top NW corner
  12235. corner = positions[1];
  12236. Cartesian3.add(normal, north, corner);
  12237. Cartesian3.add(corner, west, corner);
  12238. // top SW corner
  12239. corner = positions[2];
  12240. Cartesian3.add(normal, south, corner);
  12241. Cartesian3.add(corner, west, corner);
  12242. // top SE corner
  12243. corner = positions[3];
  12244. Cartesian3.add(normal, south, corner);
  12245. Cartesian3.add(corner, east, corner);
  12246. Cartesian3.negate(normal, normal);
  12247. // bottom NE corner
  12248. corner = positions[4];
  12249. Cartesian3.add(normal, north, corner);
  12250. Cartesian3.add(corner, east, corner);
  12251. // bottom NW corner
  12252. corner = positions[5];
  12253. Cartesian3.add(normal, north, corner);
  12254. Cartesian3.add(corner, west, corner);
  12255. // bottom SW corner
  12256. corner = positions[6];
  12257. Cartesian3.add(normal, south, corner);
  12258. Cartesian3.add(corner, west, corner);
  12259. // bottom SE corner
  12260. corner = positions[7];
  12261. Cartesian3.add(normal, south, corner);
  12262. Cartesian3.add(corner, east, corner);
  12263. var length = positions.length;
  12264. for (var i = 0; i < length; ++i) {
  12265. var position = positions[i];
  12266. Cartesian3.add(center, position, position);
  12267. var cartographic = ellipsoid.cartesianToCartographic(position, projectTo2DCartographicScratch);
  12268. projection.project(cartographic, position);
  12269. }
  12270. result = BoundingSphere.fromPoints(positions, result);
  12271. // swizzle center components
  12272. center = result.center;
  12273. var x = center.x;
  12274. var y = center.y;
  12275. var z = center.z;
  12276. center.x = z;
  12277. center.y = x;
  12278. center.z = y;
  12279. return result;
  12280. };
  12281. /**
  12282. * Determines whether or not a sphere is hidden from view by the occluder.
  12283. *
  12284. * @param {BoundingSphere} sphere The bounding sphere surrounding the occludee object.
  12285. * @param {Occluder} occluder The occluder.
  12286. * @returns {Boolean} <code>true</code> if the sphere is not visible; otherwise <code>false</code>.
  12287. */
  12288. BoundingSphere.isOccluded = function(sphere, occluder) {
  12289. if (!defined(sphere)) {
  12290. throw new DeveloperError('sphere is required.');
  12291. }
  12292. if (!defined(occluder)) {
  12293. throw new DeveloperError('occluder is required.');
  12294. }
  12295. return !occluder.isBoundingSphereVisible(sphere);
  12296. };
  12297. /**
  12298. * Compares the provided BoundingSphere componentwise and returns
  12299. * <code>true</code> if they are equal, <code>false</code> otherwise.
  12300. *
  12301. * @param {BoundingSphere} [left] The first BoundingSphere.
  12302. * @param {BoundingSphere} [right] The second BoundingSphere.
  12303. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  12304. */
  12305. BoundingSphere.equals = function(left, right) {
  12306. return (left === right) ||
  12307. ((defined(left)) &&
  12308. (defined(right)) &&
  12309. Cartesian3.equals(left.center, right.center) &&
  12310. left.radius === right.radius);
  12311. };
  12312. /**
  12313. * Determines which side of a plane the sphere is located.
  12314. *
  12315. * @param {Plane} plane The plane to test against.
  12316. * @returns {Intersect} {@link Intersect.INSIDE} if the entire sphere is on the side of the plane
  12317. * the normal is pointing, {@link Intersect.OUTSIDE} if the entire sphere is
  12318. * on the opposite side, and {@link Intersect.INTERSECTING} if the sphere
  12319. * intersects the plane.
  12320. */
  12321. BoundingSphere.prototype.intersectPlane = function(plane) {
  12322. return BoundingSphere.intersectPlane(this, plane);
  12323. };
  12324. /**
  12325. * Computes the estimated distance squared from the closest point on a bounding sphere to a point.
  12326. *
  12327. * @param {Cartesian3} cartesian The point
  12328. * @returns {Number} The estimated distance squared from the bounding sphere to the point.
  12329. *
  12330. * @example
  12331. * // Sort bounding spheres from back to front
  12332. * spheres.sort(function(a, b) {
  12333. * return b.distanceSquaredTo(camera.positionWC) - a.distanceSquaredTo(camera.positionWC);
  12334. * });
  12335. */
  12336. BoundingSphere.prototype.distanceSquaredTo = function(cartesian) {
  12337. return BoundingSphere.distanceSquaredTo(this, cartesian);
  12338. };
  12339. /**
  12340. * The distances calculated by the vector from the center of the bounding sphere to position projected onto direction
  12341. * plus/minus the radius of the bounding sphere.
  12342. * <br>
  12343. * If you imagine the infinite number of planes with normal direction, this computes the smallest distance to the
  12344. * closest and farthest planes from position that intersect the bounding sphere.
  12345. *
  12346. * @param {Cartesian3} position The position to calculate the distance from.
  12347. * @param {Cartesian3} direction The direction from position.
  12348. * @param {Interval} [result] A Interval to store the nearest and farthest distances.
  12349. * @returns {Interval} The nearest and farthest distances on the bounding sphere from position in direction.
  12350. */
  12351. BoundingSphere.prototype.computePlaneDistances = function(position, direction, result) {
  12352. return BoundingSphere.computePlaneDistances(this, position, direction, result);
  12353. };
  12354. /**
  12355. * Determines whether or not a sphere is hidden from view by the occluder.
  12356. *
  12357. * @param {Occluder} occluder The occluder.
  12358. * @returns {Boolean} <code>true</code> if the sphere is not visible; otherwise <code>false</code>.
  12359. */
  12360. BoundingSphere.prototype.isOccluded = function(occluder) {
  12361. return BoundingSphere.isOccluded(this, occluder);
  12362. };
  12363. /**
  12364. * Compares this BoundingSphere against the provided BoundingSphere componentwise and returns
  12365. * <code>true</code> if they are equal, <code>false</code> otherwise.
  12366. *
  12367. * @param {BoundingSphere} [right] The right hand side BoundingSphere.
  12368. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  12369. */
  12370. BoundingSphere.prototype.equals = function(right) {
  12371. return BoundingSphere.equals(this, right);
  12372. };
  12373. /**
  12374. * Duplicates this BoundingSphere instance.
  12375. *
  12376. * @param {BoundingSphere} [result] The object onto which to store the result.
  12377. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
  12378. */
  12379. BoundingSphere.prototype.clone = function(result) {
  12380. return BoundingSphere.clone(this, result);
  12381. };
  12382. return BoundingSphere;
  12383. });
  12384. /*global define*/
  12385. define('Core/EllipsoidalOccluder',[
  12386. './BoundingSphere',
  12387. './Cartesian3',
  12388. './defaultValue',
  12389. './defined',
  12390. './defineProperties',
  12391. './DeveloperError',
  12392. './Rectangle'
  12393. ], function(
  12394. BoundingSphere,
  12395. Cartesian3,
  12396. defaultValue,
  12397. defined,
  12398. defineProperties,
  12399. DeveloperError,
  12400. Rectangle) {
  12401. 'use strict';
  12402. /**
  12403. * Determine whether or not other objects are visible or hidden behind the visible horizon defined by
  12404. * an {@link Ellipsoid} and a camera position. The ellipsoid is assumed to be located at the
  12405. * origin of the coordinate system. This class uses the algorithm described in the
  12406. * {@link http://cesiumjs.org/2013/04/25/Horizon-culling/|Horizon Culling} blog post.
  12407. *
  12408. * @alias EllipsoidalOccluder
  12409. *
  12410. * @param {Ellipsoid} ellipsoid The ellipsoid to use as an occluder.
  12411. * @param {Cartesian3} [cameraPosition] The coordinate of the viewer/camera. If this parameter is not
  12412. * specified, {@link EllipsoidalOccluder#cameraPosition} must be called before
  12413. * testing visibility.
  12414. *
  12415. * @constructor
  12416. *
  12417. * @example
  12418. * // Construct an ellipsoidal occluder with radii 1.0, 1.1, and 0.9.
  12419. * var cameraPosition = new Cesium.Cartesian3(5.0, 6.0, 7.0);
  12420. * var occluderEllipsoid = new Cesium.Ellipsoid(1.0, 1.1, 0.9);
  12421. * var occluder = new Cesium.EllipsoidalOccluder(occluderEllipsoid, cameraPosition);
  12422. *
  12423. * @private
  12424. */
  12425. function EllipsoidalOccluder(ellipsoid, cameraPosition) {
  12426. if (!defined(ellipsoid)) {
  12427. throw new DeveloperError('ellipsoid is required.');
  12428. }
  12429. this._ellipsoid = ellipsoid;
  12430. this._cameraPosition = new Cartesian3();
  12431. this._cameraPositionInScaledSpace = new Cartesian3();
  12432. this._distanceToLimbInScaledSpaceSquared = 0.0;
  12433. // cameraPosition fills in the above values
  12434. if (defined(cameraPosition)) {
  12435. this.cameraPosition = cameraPosition;
  12436. }
  12437. }
  12438. defineProperties(EllipsoidalOccluder.prototype, {
  12439. /**
  12440. * Gets the occluding ellipsoid.
  12441. * @memberof EllipsoidalOccluder.prototype
  12442. * @type {Ellipsoid}
  12443. */
  12444. ellipsoid : {
  12445. get: function() {
  12446. return this._ellipsoid;
  12447. }
  12448. },
  12449. /**
  12450. * Gets or sets the position of the camera.
  12451. * @memberof EllipsoidalOccluder.prototype
  12452. * @type {Cartesian3}
  12453. */
  12454. cameraPosition : {
  12455. get : function() {
  12456. return this._cameraPosition;
  12457. },
  12458. set : function(cameraPosition) {
  12459. // See http://cesiumjs.org/2013/04/25/Horizon-culling/
  12460. var ellipsoid = this._ellipsoid;
  12461. var cv = ellipsoid.transformPositionToScaledSpace(cameraPosition, this._cameraPositionInScaledSpace);
  12462. var vhMagnitudeSquared = Cartesian3.magnitudeSquared(cv) - 1.0;
  12463. Cartesian3.clone(cameraPosition, this._cameraPosition);
  12464. this._cameraPositionInScaledSpace = cv;
  12465. this._distanceToLimbInScaledSpaceSquared = vhMagnitudeSquared;
  12466. }
  12467. }
  12468. });
  12469. var scratchCartesian = new Cartesian3();
  12470. /**
  12471. * Determines whether or not a point, the <code>occludee</code>, is hidden from view by the occluder.
  12472. *
  12473. * @param {Cartesian3} occludee The point to test for visibility.
  12474. * @returns {Boolean} <code>true</code> if the occludee is visible; otherwise <code>false</code>.
  12475. *
  12476. * @example
  12477. * var cameraPosition = new Cesium.Cartesian3(0, 0, 2.5);
  12478. * var ellipsoid = new Cesium.Ellipsoid(1.0, 1.1, 0.9);
  12479. * var occluder = new Cesium.EllipsoidalOccluder(ellipsoid, cameraPosition);
  12480. * var point = new Cesium.Cartesian3(0, -3, -3);
  12481. * occluder.isPointVisible(point); //returns true
  12482. */
  12483. EllipsoidalOccluder.prototype.isPointVisible = function(occludee) {
  12484. var ellipsoid = this._ellipsoid;
  12485. var occludeeScaledSpacePosition = ellipsoid.transformPositionToScaledSpace(occludee, scratchCartesian);
  12486. return this.isScaledSpacePointVisible(occludeeScaledSpacePosition);
  12487. };
  12488. /**
  12489. * Determines whether or not a point expressed in the ellipsoid scaled space, is hidden from view by the
  12490. * occluder. To transform a Cartesian X, Y, Z position in the coordinate system aligned with the ellipsoid
  12491. * into the scaled space, call {@link Ellipsoid#transformPositionToScaledSpace}.
  12492. *
  12493. * @param {Cartesian3} occludeeScaledSpacePosition The point to test for visibility, represented in the scaled space.
  12494. * @returns {Boolean} <code>true</code> if the occludee is visible; otherwise <code>false</code>.
  12495. *
  12496. * @example
  12497. * var cameraPosition = new Cesium.Cartesian3(0, 0, 2.5);
  12498. * var ellipsoid = new Cesium.Ellipsoid(1.0, 1.1, 0.9);
  12499. * var occluder = new Cesium.EllipsoidalOccluder(ellipsoid, cameraPosition);
  12500. * var point = new Cesium.Cartesian3(0, -3, -3);
  12501. * var scaledSpacePoint = ellipsoid.transformPositionToScaledSpace(point);
  12502. * occluder.isScaledSpacePointVisible(scaledSpacePoint); //returns true
  12503. */
  12504. EllipsoidalOccluder.prototype.isScaledSpacePointVisible = function(occludeeScaledSpacePosition) {
  12505. // See http://cesiumjs.org/2013/04/25/Horizon-culling/
  12506. var cv = this._cameraPositionInScaledSpace;
  12507. var vhMagnitudeSquared = this._distanceToLimbInScaledSpaceSquared;
  12508. var vt = Cartesian3.subtract(occludeeScaledSpacePosition, cv, scratchCartesian);
  12509. var vtDotVc = -Cartesian3.dot(vt, cv);
  12510. // If vhMagnitudeSquared < 0 then we are below the surface of the ellipsoid and
  12511. // in this case, set the culling plane to be on V.
  12512. var isOccluded = vhMagnitudeSquared < 0 ? vtDotVc > 0 : (vtDotVc > vhMagnitudeSquared &&
  12513. vtDotVc * vtDotVc / Cartesian3.magnitudeSquared(vt) > vhMagnitudeSquared);
  12514. return !isOccluded;
  12515. };
  12516. /**
  12517. * Computes a point that can be used for horizon culling from a list of positions. If the point is below
  12518. * the horizon, all of the positions are guaranteed to be below the horizon as well. The returned point
  12519. * is expressed in the ellipsoid-scaled space and is suitable for use with
  12520. * {@link EllipsoidalOccluder#isScaledSpacePointVisible}.
  12521. *
  12522. * @param {Cartesian3} directionToPoint The direction that the computed point will lie along.
  12523. * A reasonable direction to use is the direction from the center of the ellipsoid to
  12524. * the center of the bounding sphere computed from the positions. The direction need not
  12525. * be normalized.
  12526. * @param {Cartesian3[]} positions The positions from which to compute the horizon culling point. The positions
  12527. * must be expressed in a reference frame centered at the ellipsoid and aligned with the
  12528. * ellipsoid's axes.
  12529. * @param {Cartesian3} [result] The instance on which to store the result instead of allocating a new instance.
  12530. * @returns {Cartesian3} The computed horizon culling point, expressed in the ellipsoid-scaled space.
  12531. */
  12532. EllipsoidalOccluder.prototype.computeHorizonCullingPoint = function(directionToPoint, positions, result) {
  12533. if (!defined(directionToPoint)) {
  12534. throw new DeveloperError('directionToPoint is required');
  12535. }
  12536. if (!defined(positions)) {
  12537. throw new DeveloperError('positions is required');
  12538. }
  12539. if (!defined(result)) {
  12540. result = new Cartesian3();
  12541. }
  12542. var ellipsoid = this._ellipsoid;
  12543. var scaledSpaceDirectionToPoint = computeScaledSpaceDirectionToPoint(ellipsoid, directionToPoint);
  12544. var resultMagnitude = 0.0;
  12545. for (var i = 0, len = positions.length; i < len; ++i) {
  12546. var position = positions[i];
  12547. var candidateMagnitude = computeMagnitude(ellipsoid, position, scaledSpaceDirectionToPoint);
  12548. resultMagnitude = Math.max(resultMagnitude, candidateMagnitude);
  12549. }
  12550. return magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, result);
  12551. };
  12552. var positionScratch = new Cartesian3();
  12553. /**
  12554. * Computes a point that can be used for horizon culling from a list of positions. If the point is below
  12555. * the horizon, all of the positions are guaranteed to be below the horizon as well. The returned point
  12556. * is expressed in the ellipsoid-scaled space and is suitable for use with
  12557. * {@link EllipsoidalOccluder#isScaledSpacePointVisible}.
  12558. *
  12559. * @param {Cartesian3} directionToPoint The direction that the computed point will lie along.
  12560. * A reasonable direction to use is the direction from the center of the ellipsoid to
  12561. * the center of the bounding sphere computed from the positions. The direction need not
  12562. * be normalized.
  12563. * @param {Number[]} vertices The vertices from which to compute the horizon culling point. The positions
  12564. * must be expressed in a reference frame centered at the ellipsoid and aligned with the
  12565. * ellipsoid's axes.
  12566. * @param {Number} [stride=3]
  12567. * @param {Cartesian3} [center=Cartesian3.ZERO]
  12568. * @param {Cartesian3} [result] The instance on which to store the result instead of allocating a new instance.
  12569. * @returns {Cartesian3} The computed horizon culling point, expressed in the ellipsoid-scaled space.
  12570. */
  12571. EllipsoidalOccluder.prototype.computeHorizonCullingPointFromVertices = function(directionToPoint, vertices, stride, center, result) {
  12572. if (!defined(directionToPoint)) {
  12573. throw new DeveloperError('directionToPoint is required');
  12574. }
  12575. if (!defined(vertices)) {
  12576. throw new DeveloperError('vertices is required');
  12577. }
  12578. if (!defined(stride)) {
  12579. throw new DeveloperError('stride is required');
  12580. }
  12581. if (!defined(result)) {
  12582. result = new Cartesian3();
  12583. }
  12584. center = defaultValue(center, Cartesian3.ZERO);
  12585. var ellipsoid = this._ellipsoid;
  12586. var scaledSpaceDirectionToPoint = computeScaledSpaceDirectionToPoint(ellipsoid, directionToPoint);
  12587. var resultMagnitude = 0.0;
  12588. for (var i = 0, len = vertices.length; i < len; i += stride) {
  12589. positionScratch.x = vertices[i] + center.x;
  12590. positionScratch.y = vertices[i + 1] + center.y;
  12591. positionScratch.z = vertices[i + 2] + center.z;
  12592. var candidateMagnitude = computeMagnitude(ellipsoid, positionScratch, scaledSpaceDirectionToPoint);
  12593. resultMagnitude = Math.max(resultMagnitude, candidateMagnitude);
  12594. }
  12595. return magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, result);
  12596. };
  12597. var subsampleScratch = [];
  12598. /**
  12599. * Computes a point that can be used for horizon culling of an rectangle. If the point is below
  12600. * the horizon, the ellipsoid-conforming rectangle is guaranteed to be below the horizon as well.
  12601. * The returned point is expressed in the ellipsoid-scaled space and is suitable for use with
  12602. * {@link EllipsoidalOccluder#isScaledSpacePointVisible}.
  12603. *
  12604. * @param {Rectangle} rectangle The rectangle for which to compute the horizon culling point.
  12605. * @param {Ellipsoid} ellipsoid The ellipsoid on which the rectangle is defined. This may be different from
  12606. * the ellipsoid used by this instance for occlusion testing.
  12607. * @param {Cartesian3} [result] The instance on which to store the result instead of allocating a new instance.
  12608. * @returns {Cartesian3} The computed horizon culling point, expressed in the ellipsoid-scaled space.
  12609. */
  12610. EllipsoidalOccluder.prototype.computeHorizonCullingPointFromRectangle = function(rectangle, ellipsoid, result) {
  12611. if (!defined(rectangle)) {
  12612. throw new DeveloperError('rectangle is required.');
  12613. }
  12614. var positions = Rectangle.subsample(rectangle, ellipsoid, 0.0, subsampleScratch);
  12615. var bs = BoundingSphere.fromPoints(positions);
  12616. // If the bounding sphere center is too close to the center of the occluder, it doesn't make
  12617. // sense to try to horizon cull it.
  12618. if (Cartesian3.magnitude(bs.center) < 0.1 * ellipsoid.minimumRadius) {
  12619. return undefined;
  12620. }
  12621. return this.computeHorizonCullingPoint(bs.center, positions, result);
  12622. };
  12623. var scaledSpaceScratch = new Cartesian3();
  12624. var directionScratch = new Cartesian3();
  12625. function computeMagnitude(ellipsoid, position, scaledSpaceDirectionToPoint) {
  12626. var scaledSpacePosition = ellipsoid.transformPositionToScaledSpace(position, scaledSpaceScratch);
  12627. var magnitudeSquared = Cartesian3.magnitudeSquared(scaledSpacePosition);
  12628. var magnitude = Math.sqrt(magnitudeSquared);
  12629. var direction = Cartesian3.divideByScalar(scaledSpacePosition, magnitude, directionScratch);
  12630. // For the purpose of this computation, points below the ellipsoid are consider to be on it instead.
  12631. magnitudeSquared = Math.max(1.0, magnitudeSquared);
  12632. magnitude = Math.max(1.0, magnitude);
  12633. var cosAlpha = Cartesian3.dot(direction, scaledSpaceDirectionToPoint);
  12634. var sinAlpha = Cartesian3.magnitude(Cartesian3.cross(direction, scaledSpaceDirectionToPoint, direction));
  12635. var cosBeta = 1.0 / magnitude;
  12636. var sinBeta = Math.sqrt(magnitudeSquared - 1.0) * cosBeta;
  12637. return 1.0 / (cosAlpha * cosBeta - sinAlpha * sinBeta);
  12638. }
  12639. function magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, result) {
  12640. // The horizon culling point is undefined if there were no positions from which to compute it,
  12641. // the directionToPoint is pointing opposite all of the positions, or if we computed NaN or infinity.
  12642. if (resultMagnitude <= 0.0 || resultMagnitude === 1.0 / 0.0 || resultMagnitude !== resultMagnitude) {
  12643. return undefined;
  12644. }
  12645. return Cartesian3.multiplyByScalar(scaledSpaceDirectionToPoint, resultMagnitude, result);
  12646. }
  12647. var directionToPointScratch = new Cartesian3();
  12648. function computeScaledSpaceDirectionToPoint(ellipsoid, directionToPoint) {
  12649. if (Cartesian3.equals(directionToPoint, Cartesian3.ZERO)) {
  12650. return directionToPoint;
  12651. }
  12652. ellipsoid.transformPositionToScaledSpace(directionToPoint, directionToPointScratch);
  12653. return Cartesian3.normalize(directionToPointScratch, directionToPointScratch);
  12654. }
  12655. return EllipsoidalOccluder;
  12656. });
  12657. /*global define*/
  12658. define('Core/QuadraticRealPolynomial',[
  12659. './DeveloperError',
  12660. './Math'
  12661. ], function(
  12662. DeveloperError,
  12663. CesiumMath) {
  12664. 'use strict';
  12665. /**
  12666. * Defines functions for 2nd order polynomial functions of one variable with only real coefficients.
  12667. *
  12668. * @exports QuadraticRealPolynomial
  12669. */
  12670. var QuadraticRealPolynomial = {};
  12671. /**
  12672. * Provides the discriminant of the quadratic equation from the supplied coefficients.
  12673. *
  12674. * @param {Number} a The coefficient of the 2nd order monomial.
  12675. * @param {Number} b The coefficient of the 1st order monomial.
  12676. * @param {Number} c The coefficient of the 0th order monomial.
  12677. * @returns {Number} The value of the discriminant.
  12678. */
  12679. QuadraticRealPolynomial.computeDiscriminant = function(a, b, c) {
  12680. if (typeof a !== 'number') {
  12681. throw new DeveloperError('a is a required number.');
  12682. }
  12683. if (typeof b !== 'number') {
  12684. throw new DeveloperError('b is a required number.');
  12685. }
  12686. if (typeof c !== 'number') {
  12687. throw new DeveloperError('c is a required number.');
  12688. }
  12689. var discriminant = b * b - 4.0 * a * c;
  12690. return discriminant;
  12691. };
  12692. function addWithCancellationCheck(left, right, tolerance) {
  12693. var difference = left + right;
  12694. if ((CesiumMath.sign(left) !== CesiumMath.sign(right)) &&
  12695. Math.abs(difference / Math.max(Math.abs(left), Math.abs(right))) < tolerance) {
  12696. return 0.0;
  12697. }
  12698. return difference;
  12699. }
  12700. /**
  12701. * Provides the real valued roots of the quadratic polynomial with the provided coefficients.
  12702. *
  12703. * @param {Number} a The coefficient of the 2nd order monomial.
  12704. * @param {Number} b The coefficient of the 1st order monomial.
  12705. * @param {Number} c The coefficient of the 0th order monomial.
  12706. * @returns {Number[]} The real valued roots.
  12707. */
  12708. QuadraticRealPolynomial.computeRealRoots = function(a, b, c) {
  12709. if (typeof a !== 'number') {
  12710. throw new DeveloperError('a is a required number.');
  12711. }
  12712. if (typeof b !== 'number') {
  12713. throw new DeveloperError('b is a required number.');
  12714. }
  12715. if (typeof c !== 'number') {
  12716. throw new DeveloperError('c is a required number.');
  12717. }
  12718. var ratio;
  12719. if (a === 0.0) {
  12720. if (b === 0.0) {
  12721. // Constant function: c = 0.
  12722. return [];
  12723. }
  12724. // Linear function: b * x + c = 0.
  12725. return [-c / b];
  12726. } else if (b === 0.0) {
  12727. if (c === 0.0) {
  12728. // 2nd order monomial: a * x^2 = 0.
  12729. return [0.0, 0.0];
  12730. }
  12731. var cMagnitude = Math.abs(c);
  12732. var aMagnitude = Math.abs(a);
  12733. if ((cMagnitude < aMagnitude) && (cMagnitude / aMagnitude < CesiumMath.EPSILON14)) { // c ~= 0.0.
  12734. // 2nd order monomial: a * x^2 = 0.
  12735. return [0.0, 0.0];
  12736. } else if ((cMagnitude > aMagnitude) && (aMagnitude / cMagnitude < CesiumMath.EPSILON14)) { // a ~= 0.0.
  12737. // Constant function: c = 0.
  12738. return [];
  12739. }
  12740. // a * x^2 + c = 0
  12741. ratio = -c / a;
  12742. if (ratio < 0.0) {
  12743. // Both roots are complex.
  12744. return [];
  12745. }
  12746. // Both roots are real.
  12747. var root = Math.sqrt(ratio);
  12748. return [-root, root];
  12749. } else if (c === 0.0) {
  12750. // a * x^2 + b * x = 0
  12751. ratio = -b / a;
  12752. if (ratio < 0.0) {
  12753. return [ratio, 0.0];
  12754. }
  12755. return [0.0, ratio];
  12756. }
  12757. // a * x^2 + b * x + c = 0
  12758. var b2 = b * b;
  12759. var four_ac = 4.0 * a * c;
  12760. var radicand = addWithCancellationCheck(b2, -four_ac, CesiumMath.EPSILON14);
  12761. if (radicand < 0.0) {
  12762. // Both roots are complex.
  12763. return [];
  12764. }
  12765. var q = -0.5 * addWithCancellationCheck(b, CesiumMath.sign(b) * Math.sqrt(radicand), CesiumMath.EPSILON14);
  12766. if (b > 0.0) {
  12767. return [q / a, c / q];
  12768. }
  12769. return [c / q, q / a];
  12770. };
  12771. return QuadraticRealPolynomial;
  12772. });
  12773. /*global define*/
  12774. define('Core/CubicRealPolynomial',[
  12775. './DeveloperError',
  12776. './QuadraticRealPolynomial'
  12777. ], function(
  12778. DeveloperError,
  12779. QuadraticRealPolynomial) {
  12780. 'use strict';
  12781. /**
  12782. * Defines functions for 3rd order polynomial functions of one variable with only real coefficients.
  12783. *
  12784. * @exports CubicRealPolynomial
  12785. */
  12786. var CubicRealPolynomial = {};
  12787. /**
  12788. * Provides the discriminant of the cubic equation from the supplied coefficients.
  12789. *
  12790. * @param {Number} a The coefficient of the 3rd order monomial.
  12791. * @param {Number} b The coefficient of the 2nd order monomial.
  12792. * @param {Number} c The coefficient of the 1st order monomial.
  12793. * @param {Number} d The coefficient of the 0th order monomial.
  12794. * @returns {Number} The value of the discriminant.
  12795. */
  12796. CubicRealPolynomial.computeDiscriminant = function(a, b, c, d) {
  12797. if (typeof a !== 'number') {
  12798. throw new DeveloperError('a is a required number.');
  12799. }
  12800. if (typeof b !== 'number') {
  12801. throw new DeveloperError('b is a required number.');
  12802. }
  12803. if (typeof c !== 'number') {
  12804. throw new DeveloperError('c is a required number.');
  12805. }
  12806. if (typeof d !== 'number') {
  12807. throw new DeveloperError('d is a required number.');
  12808. }
  12809. var a2 = a * a;
  12810. var b2 = b * b;
  12811. var c2 = c * c;
  12812. var d2 = d * d;
  12813. var discriminant = 18.0 * a * b * c * d + b2 * c2 - 27.0 * a2 * d2 - 4.0 * (a * c2 * c + b2 * b * d);
  12814. return discriminant;
  12815. };
  12816. function computeRealRoots(a, b, c, d) {
  12817. var A = a;
  12818. var B = b / 3.0;
  12819. var C = c / 3.0;
  12820. var D = d;
  12821. var AC = A * C;
  12822. var BD = B * D;
  12823. var B2 = B * B;
  12824. var C2 = C * C;
  12825. var delta1 = A * C - B2;
  12826. var delta2 = A * D - B * C;
  12827. var delta3 = B * D - C2;
  12828. var discriminant = 4.0 * delta1 * delta3 - delta2 * delta2;
  12829. var temp;
  12830. var temp1;
  12831. if (discriminant < 0.0) {
  12832. var ABar;
  12833. var CBar;
  12834. var DBar;
  12835. if (B2 * BD >= AC * C2) {
  12836. ABar = A;
  12837. CBar = delta1;
  12838. DBar = -2.0 * B * delta1 + A * delta2;
  12839. } else {
  12840. ABar = D;
  12841. CBar = delta3;
  12842. DBar = -D * delta2 + 2.0 * C * delta3;
  12843. }
  12844. var s = (DBar < 0.0) ? -1.0 : 1.0; // This is not Math.Sign()!
  12845. var temp0 = -s * Math.abs(ABar) * Math.sqrt(-discriminant);
  12846. temp1 = -DBar + temp0;
  12847. var x = temp1 / 2.0;
  12848. var p = x < 0.0 ? -Math.pow(-x, 1.0 / 3.0) : Math.pow(x, 1.0 / 3.0);
  12849. var q = (temp1 === temp0) ? -p : -CBar / p;
  12850. temp = (CBar <= 0.0) ? p + q : -DBar / (p * p + q * q + CBar);
  12851. if (B2 * BD >= AC * C2) {
  12852. return [(temp - B) / A];
  12853. }
  12854. return [-D / (temp + C)];
  12855. }
  12856. var CBarA = delta1;
  12857. var DBarA = -2.0 * B * delta1 + A * delta2;
  12858. var CBarD = delta3;
  12859. var DBarD = -D * delta2 + 2.0 * C * delta3;
  12860. var squareRootOfDiscriminant = Math.sqrt(discriminant);
  12861. var halfSquareRootOf3 = Math.sqrt(3.0) / 2.0;
  12862. var theta = Math.abs(Math.atan2(A * squareRootOfDiscriminant, -DBarA) / 3.0);
  12863. temp = 2.0 * Math.sqrt(-CBarA);
  12864. var cosine = Math.cos(theta);
  12865. temp1 = temp * cosine;
  12866. var temp3 = temp * (-cosine / 2.0 - halfSquareRootOf3 * Math.sin(theta));
  12867. var numeratorLarge = (temp1 + temp3 > 2.0 * B) ? temp1 - B : temp3 - B;
  12868. var denominatorLarge = A;
  12869. var root1 = numeratorLarge / denominatorLarge;
  12870. theta = Math.abs(Math.atan2(D * squareRootOfDiscriminant, -DBarD) / 3.0);
  12871. temp = 2.0 * Math.sqrt(-CBarD);
  12872. cosine = Math.cos(theta);
  12873. temp1 = temp * cosine;
  12874. temp3 = temp * (-cosine / 2.0 - halfSquareRootOf3 * Math.sin(theta));
  12875. var numeratorSmall = -D;
  12876. var denominatorSmall = (temp1 + temp3 < 2.0 * C) ? temp1 + C : temp3 + C;
  12877. var root3 = numeratorSmall / denominatorSmall;
  12878. var E = denominatorLarge * denominatorSmall;
  12879. var F = -numeratorLarge * denominatorSmall - denominatorLarge * numeratorSmall;
  12880. var G = numeratorLarge * numeratorSmall;
  12881. var root2 = (C * F - B * G) / (-B * F + C * E);
  12882. if (root1 <= root2) {
  12883. if (root1 <= root3) {
  12884. if (root2 <= root3) {
  12885. return [root1, root2, root3];
  12886. }
  12887. return [root1, root3, root2];
  12888. }
  12889. return [root3, root1, root2];
  12890. }
  12891. if (root1 <= root3) {
  12892. return [root2, root1, root3];
  12893. }
  12894. if (root2 <= root3) {
  12895. return [root2, root3, root1];
  12896. }
  12897. return [root3, root2, root1];
  12898. }
  12899. /**
  12900. * Provides the real valued roots of the cubic polynomial with the provided coefficients.
  12901. *
  12902. * @param {Number} a The coefficient of the 3rd order monomial.
  12903. * @param {Number} b The coefficient of the 2nd order monomial.
  12904. * @param {Number} c The coefficient of the 1st order monomial.
  12905. * @param {Number} d The coefficient of the 0th order monomial.
  12906. * @returns {Number[]} The real valued roots.
  12907. */
  12908. CubicRealPolynomial.computeRealRoots = function(a, b, c, d) {
  12909. if (typeof a !== 'number') {
  12910. throw new DeveloperError('a is a required number.');
  12911. }
  12912. if (typeof b !== 'number') {
  12913. throw new DeveloperError('b is a required number.');
  12914. }
  12915. if (typeof c !== 'number') {
  12916. throw new DeveloperError('c is a required number.');
  12917. }
  12918. if (typeof d !== 'number') {
  12919. throw new DeveloperError('d is a required number.');
  12920. }
  12921. var roots;
  12922. var ratio;
  12923. if (a === 0.0) {
  12924. // Quadratic function: b * x^2 + c * x + d = 0.
  12925. return QuadraticRealPolynomial.computeRealRoots(b, c, d);
  12926. } else if (b === 0.0) {
  12927. if (c === 0.0) {
  12928. if (d === 0.0) {
  12929. // 3rd order monomial: a * x^3 = 0.
  12930. return [0.0, 0.0, 0.0];
  12931. }
  12932. // a * x^3 + d = 0
  12933. ratio = -d / a;
  12934. var root = (ratio < 0.0) ? -Math.pow(-ratio, 1.0 / 3.0) : Math.pow(ratio, 1.0 / 3.0);
  12935. return [root, root, root];
  12936. } else if (d === 0.0) {
  12937. // x * (a * x^2 + c) = 0.
  12938. roots = QuadraticRealPolynomial.computeRealRoots(a, 0, c);
  12939. // Return the roots in ascending order.
  12940. if (roots.Length === 0) {
  12941. return [0.0];
  12942. }
  12943. return [roots[0], 0.0, roots[1]];
  12944. }
  12945. // Deflated cubic polynomial: a * x^3 + c * x + d= 0.
  12946. return computeRealRoots(a, 0, c, d);
  12947. } else if (c === 0.0) {
  12948. if (d === 0.0) {
  12949. // x^2 * (a * x + b) = 0.
  12950. ratio = -b / a;
  12951. if (ratio < 0.0) {
  12952. return [ratio, 0.0, 0.0];
  12953. }
  12954. return [0.0, 0.0, ratio];
  12955. }
  12956. // a * x^3 + b * x^2 + d = 0.
  12957. return computeRealRoots(a, b, 0, d);
  12958. } else if (d === 0.0) {
  12959. // x * (a * x^2 + b * x + c) = 0
  12960. roots = QuadraticRealPolynomial.computeRealRoots(a, b, c);
  12961. // Return the roots in ascending order.
  12962. if (roots.length === 0) {
  12963. return [0.0];
  12964. } else if (roots[1] <= 0.0) {
  12965. return [roots[0], roots[1], 0.0];
  12966. } else if (roots[0] >= 0.0) {
  12967. return [0.0, roots[0], roots[1]];
  12968. }
  12969. return [roots[0], 0.0, roots[1]];
  12970. }
  12971. return computeRealRoots(a, b, c, d);
  12972. };
  12973. return CubicRealPolynomial;
  12974. });
  12975. /*global define*/
  12976. define('Core/QuarticRealPolynomial',[
  12977. './CubicRealPolynomial',
  12978. './DeveloperError',
  12979. './Math',
  12980. './QuadraticRealPolynomial'
  12981. ], function(
  12982. CubicRealPolynomial,
  12983. DeveloperError,
  12984. CesiumMath,
  12985. QuadraticRealPolynomial) {
  12986. 'use strict';
  12987. /**
  12988. * Defines functions for 4th order polynomial functions of one variable with only real coefficients.
  12989. *
  12990. * @exports QuarticRealPolynomial
  12991. */
  12992. var QuarticRealPolynomial = {};
  12993. /**
  12994. * Provides the discriminant of the quartic equation from the supplied coefficients.
  12995. *
  12996. * @param {Number} a The coefficient of the 4th order monomial.
  12997. * @param {Number} b The coefficient of the 3rd order monomial.
  12998. * @param {Number} c The coefficient of the 2nd order monomial.
  12999. * @param {Number} d The coefficient of the 1st order monomial.
  13000. * @param {Number} e The coefficient of the 0th order monomial.
  13001. * @returns {Number} The value of the discriminant.
  13002. */
  13003. QuarticRealPolynomial.computeDiscriminant = function(a, b, c, d, e) {
  13004. if (typeof a !== 'number') {
  13005. throw new DeveloperError('a is a required number.');
  13006. }
  13007. if (typeof b !== 'number') {
  13008. throw new DeveloperError('b is a required number.');
  13009. }
  13010. if (typeof c !== 'number') {
  13011. throw new DeveloperError('c is a required number.');
  13012. }
  13013. if (typeof d !== 'number') {
  13014. throw new DeveloperError('d is a required number.');
  13015. }
  13016. if (typeof e !== 'number') {
  13017. throw new DeveloperError('e is a required number.');
  13018. }
  13019. var a2 = a * a;
  13020. var a3 = a2 * a;
  13021. var b2 = b * b;
  13022. var b3 = b2 * b;
  13023. var c2 = c * c;
  13024. var c3 = c2 * c;
  13025. var d2 = d * d;
  13026. var d3 = d2 * d;
  13027. var e2 = e * e;
  13028. var e3 = e2 * e;
  13029. var discriminant = (b2 * c2 * d2 - 4.0 * b3 * d3 - 4.0 * a * c3 * d2 + 18 * a * b * c * d3 - 27.0 * a2 * d2 * d2 + 256.0 * a3 * e3) +
  13030. e * (18.0 * b3 * c * d - 4.0 * b2 * c3 + 16.0 * a * c2 * c2 - 80.0 * a * b * c2 * d - 6.0 * a * b2 * d2 + 144.0 * a2 * c * d2) +
  13031. e2 * (144.0 * a * b2 * c - 27.0 * b2 * b2 - 128.0 * a2 * c2 - 192.0 * a2 * b * d);
  13032. return discriminant;
  13033. };
  13034. function original(a3, a2, a1, a0) {
  13035. var a3Squared = a3 * a3;
  13036. var p = a2 - 3.0 * a3Squared / 8.0;
  13037. var q = a1 - a2 * a3 / 2.0 + a3Squared * a3 / 8.0;
  13038. var r = a0 - a1 * a3 / 4.0 + a2 * a3Squared / 16.0 - 3.0 * a3Squared * a3Squared / 256.0;
  13039. // Find the roots of the cubic equations: h^6 + 2 p h^4 + (p^2 - 4 r) h^2 - q^2 = 0.
  13040. var cubicRoots = CubicRealPolynomial.computeRealRoots(1.0, 2.0 * p, p * p - 4.0 * r, -q * q);
  13041. if (cubicRoots.length > 0) {
  13042. var temp = -a3 / 4.0;
  13043. // Use the largest positive root.
  13044. var hSquared = cubicRoots[cubicRoots.length - 1];
  13045. if (Math.abs(hSquared) < CesiumMath.EPSILON14) {
  13046. // y^4 + p y^2 + r = 0.
  13047. var roots = QuadraticRealPolynomial.computeRealRoots(1.0, p, r);
  13048. if (roots.length === 2) {
  13049. var root0 = roots[0];
  13050. var root1 = roots[1];
  13051. var y;
  13052. if (root0 >= 0.0 && root1 >= 0.0) {
  13053. var y0 = Math.sqrt(root0);
  13054. var y1 = Math.sqrt(root1);
  13055. return [temp - y1, temp - y0, temp + y0, temp + y1];
  13056. } else if (root0 >= 0.0 && root1 < 0.0) {
  13057. y = Math.sqrt(root0);
  13058. return [temp - y, temp + y];
  13059. } else if (root0 < 0.0 && root1 >= 0.0) {
  13060. y = Math.sqrt(root1);
  13061. return [temp - y, temp + y];
  13062. }
  13063. }
  13064. return [];
  13065. } else if (hSquared > 0.0) {
  13066. var h = Math.sqrt(hSquared);
  13067. var m = (p + hSquared - q / h) / 2.0;
  13068. var n = (p + hSquared + q / h) / 2.0;
  13069. // Now solve the two quadratic factors: (y^2 + h y + m)(y^2 - h y + n);
  13070. var roots1 = QuadraticRealPolynomial.computeRealRoots(1.0, h, m);
  13071. var roots2 = QuadraticRealPolynomial.computeRealRoots(1.0, -h, n);
  13072. if (roots1.length !== 0) {
  13073. roots1[0] += temp;
  13074. roots1[1] += temp;
  13075. if (roots2.length !== 0) {
  13076. roots2[0] += temp;
  13077. roots2[1] += temp;
  13078. if (roots1[1] <= roots2[0]) {
  13079. return [roots1[0], roots1[1], roots2[0], roots2[1]];
  13080. } else if (roots2[1] <= roots1[0]) {
  13081. return [roots2[0], roots2[1], roots1[0], roots1[1]];
  13082. } else if (roots1[0] >= roots2[0] && roots1[1] <= roots2[1]) {
  13083. return [roots2[0], roots1[0], roots1[1], roots2[1]];
  13084. } else if (roots2[0] >= roots1[0] && roots2[1] <= roots1[1]) {
  13085. return [roots1[0], roots2[0], roots2[1], roots1[1]];
  13086. } else if (roots1[0] > roots2[0] && roots1[0] < roots2[1]) {
  13087. return [roots2[0], roots1[0], roots2[1], roots1[1]];
  13088. }
  13089. return [roots1[0], roots2[0], roots1[1], roots2[1]];
  13090. }
  13091. return roots1;
  13092. }
  13093. if (roots2.length !== 0) {
  13094. roots2[0] += temp;
  13095. roots2[1] += temp;
  13096. return roots2;
  13097. }
  13098. return [];
  13099. }
  13100. }
  13101. return [];
  13102. }
  13103. function neumark(a3, a2, a1, a0) {
  13104. var a1Squared = a1 * a1;
  13105. var a2Squared = a2 * a2;
  13106. var a3Squared = a3 * a3;
  13107. var p = -2.0 * a2;
  13108. var q = a1 * a3 + a2Squared - 4.0 * a0;
  13109. var r = a3Squared * a0 - a1 * a2 * a3 + a1Squared;
  13110. var cubicRoots = CubicRealPolynomial.computeRealRoots(1.0, p, q, r);
  13111. if (cubicRoots.length > 0) {
  13112. // Use the most positive root
  13113. var y = cubicRoots[0];
  13114. var temp = (a2 - y);
  13115. var tempSquared = temp * temp;
  13116. var g1 = a3 / 2.0;
  13117. var h1 = temp / 2.0;
  13118. var m = tempSquared - 4.0 * a0;
  13119. var mError = tempSquared + 4.0 * Math.abs(a0);
  13120. var n = a3Squared - 4.0 * y;
  13121. var nError = a3Squared + 4.0 * Math.abs(y);
  13122. var g2;
  13123. var h2;
  13124. if (y < 0.0 || (m * nError < n * mError)) {
  13125. var squareRootOfN = Math.sqrt(n);
  13126. g2 = squareRootOfN / 2.0;
  13127. h2 = squareRootOfN === 0.0 ? 0.0 : (a3 * h1 - a1) / squareRootOfN;
  13128. } else {
  13129. var squareRootOfM = Math.sqrt(m);
  13130. g2 = squareRootOfM === 0.0 ? 0.0 : (a3 * h1 - a1) / squareRootOfM;
  13131. h2 = squareRootOfM / 2.0;
  13132. }
  13133. var G;
  13134. var g;
  13135. if (g1 === 0.0 && g2 === 0.0) {
  13136. G = 0.0;
  13137. g = 0.0;
  13138. } else if (CesiumMath.sign(g1) === CesiumMath.sign(g2)) {
  13139. G = g1 + g2;
  13140. g = y / G;
  13141. } else {
  13142. g = g1 - g2;
  13143. G = y / g;
  13144. }
  13145. var H;
  13146. var h;
  13147. if (h1 === 0.0 && h2 === 0.0) {
  13148. H = 0.0;
  13149. h = 0.0;
  13150. } else if (CesiumMath.sign(h1) === CesiumMath.sign(h2)) {
  13151. H = h1 + h2;
  13152. h = a0 / H;
  13153. } else {
  13154. h = h1 - h2;
  13155. H = a0 / h;
  13156. }
  13157. // Now solve the two quadratic factors: (y^2 + G y + H)(y^2 + g y + h);
  13158. var roots1 = QuadraticRealPolynomial.computeRealRoots(1.0, G, H);
  13159. var roots2 = QuadraticRealPolynomial.computeRealRoots(1.0, g, h);
  13160. if (roots1.length !== 0) {
  13161. if (roots2.length !== 0) {
  13162. if (roots1[1] <= roots2[0]) {
  13163. return [roots1[0], roots1[1], roots2[0], roots2[1]];
  13164. } else if (roots2[1] <= roots1[0]) {
  13165. return [roots2[0], roots2[1], roots1[0], roots1[1]];
  13166. } else if (roots1[0] >= roots2[0] && roots1[1] <= roots2[1]) {
  13167. return [roots2[0], roots1[0], roots1[1], roots2[1]];
  13168. } else if (roots2[0] >= roots1[0] && roots2[1] <= roots1[1]) {
  13169. return [roots1[0], roots2[0], roots2[1], roots1[1]];
  13170. } else if (roots1[0] > roots2[0] && roots1[0] < roots2[1]) {
  13171. return [roots2[0], roots1[0], roots2[1], roots1[1]];
  13172. } else {
  13173. return [roots1[0], roots2[0], roots1[1], roots2[1]];
  13174. }
  13175. }
  13176. return roots1;
  13177. }
  13178. if (roots2.length !== 0) {
  13179. return roots2;
  13180. }
  13181. }
  13182. return [];
  13183. }
  13184. /**
  13185. * Provides the real valued roots of the quartic polynomial with the provided coefficients.
  13186. *
  13187. * @param {Number} a The coefficient of the 4th order monomial.
  13188. * @param {Number} b The coefficient of the 3rd order monomial.
  13189. * @param {Number} c The coefficient of the 2nd order monomial.
  13190. * @param {Number} d The coefficient of the 1st order monomial.
  13191. * @param {Number} e The coefficient of the 0th order monomial.
  13192. * @returns {Number[]} The real valued roots.
  13193. */
  13194. QuarticRealPolynomial.computeRealRoots = function(a, b, c, d, e) {
  13195. if (typeof a !== 'number') {
  13196. throw new DeveloperError('a is a required number.');
  13197. }
  13198. if (typeof b !== 'number') {
  13199. throw new DeveloperError('b is a required number.');
  13200. }
  13201. if (typeof c !== 'number') {
  13202. throw new DeveloperError('c is a required number.');
  13203. }
  13204. if (typeof d !== 'number') {
  13205. throw new DeveloperError('d is a required number.');
  13206. }
  13207. if (typeof e !== 'number') {
  13208. throw new DeveloperError('e is a required number.');
  13209. }
  13210. if (Math.abs(a) < CesiumMath.EPSILON15) {
  13211. return CubicRealPolynomial.computeRealRoots(b, c, d, e);
  13212. }
  13213. var a3 = b / a;
  13214. var a2 = c / a;
  13215. var a1 = d / a;
  13216. var a0 = e / a;
  13217. var k = (a3 < 0.0) ? 1 : 0;
  13218. k += (a2 < 0.0) ? k + 1 : k;
  13219. k += (a1 < 0.0) ? k + 1 : k;
  13220. k += (a0 < 0.0) ? k + 1 : k;
  13221. switch (k) {
  13222. case 0:
  13223. return original(a3, a2, a1, a0);
  13224. case 1:
  13225. return neumark(a3, a2, a1, a0);
  13226. case 2:
  13227. return neumark(a3, a2, a1, a0);
  13228. case 3:
  13229. return original(a3, a2, a1, a0);
  13230. case 4:
  13231. return original(a3, a2, a1, a0);
  13232. case 5:
  13233. return neumark(a3, a2, a1, a0);
  13234. case 6:
  13235. return original(a3, a2, a1, a0);
  13236. case 7:
  13237. return original(a3, a2, a1, a0);
  13238. case 8:
  13239. return neumark(a3, a2, a1, a0);
  13240. case 9:
  13241. return original(a3, a2, a1, a0);
  13242. case 10:
  13243. return original(a3, a2, a1, a0);
  13244. case 11:
  13245. return neumark(a3, a2, a1, a0);
  13246. case 12:
  13247. return original(a3, a2, a1, a0);
  13248. case 13:
  13249. return original(a3, a2, a1, a0);
  13250. case 14:
  13251. return original(a3, a2, a1, a0);
  13252. case 15:
  13253. return original(a3, a2, a1, a0);
  13254. default:
  13255. return undefined;
  13256. }
  13257. };
  13258. return QuarticRealPolynomial;
  13259. });
  13260. /*global define*/
  13261. define('Core/Ray',[
  13262. './Cartesian3',
  13263. './defaultValue',
  13264. './defined',
  13265. './DeveloperError'
  13266. ], function(
  13267. Cartesian3,
  13268. defaultValue,
  13269. defined,
  13270. DeveloperError) {
  13271. 'use strict';
  13272. /**
  13273. * Represents a ray that extends infinitely from the provided origin in the provided direction.
  13274. * @alias Ray
  13275. * @constructor
  13276. *
  13277. * @param {Cartesian3} [origin=Cartesian3.ZERO] The origin of the ray.
  13278. * @param {Cartesian3} [direction=Cartesian3.ZERO] The direction of the ray.
  13279. */
  13280. function Ray(origin, direction) {
  13281. direction = Cartesian3.clone(defaultValue(direction, Cartesian3.ZERO));
  13282. if (!Cartesian3.equals(direction, Cartesian3.ZERO)) {
  13283. Cartesian3.normalize(direction, direction);
  13284. }
  13285. /**
  13286. * The origin of the ray.
  13287. * @type {Cartesian3}
  13288. * @default {@link Cartesian3.ZERO}
  13289. */
  13290. this.origin = Cartesian3.clone(defaultValue(origin, Cartesian3.ZERO));
  13291. /**
  13292. * The direction of the ray.
  13293. * @type {Cartesian3}
  13294. */
  13295. this.direction = direction;
  13296. }
  13297. /**
  13298. * Computes the point along the ray given by r(t) = o + t*d,
  13299. * where o is the origin of the ray and d is the direction.
  13300. *
  13301. * @param {Ray} ray The ray.
  13302. * @param {Number} t A scalar value.
  13303. * @param {Cartesian3} [result] The object in which the result will be stored.
  13304. * @returns {Cartesian3} The modified result parameter, or a new instance if none was provided.
  13305. *
  13306. * @example
  13307. * //Get the first intersection point of a ray and an ellipsoid.
  13308. * var intersection = Cesium.IntersectionTests.rayEllipsoid(ray, ellipsoid);
  13309. * var point = Cesium.Ray.getPoint(ray, intersection.start);
  13310. */
  13311. Ray.getPoint = function(ray, t, result) {
  13312. if (!defined(ray)){
  13313. throw new DeveloperError('ray is requred');
  13314. }
  13315. if (typeof t !== 'number') {
  13316. throw new DeveloperError('t is a required number');
  13317. }
  13318. if (!defined(result)) {
  13319. result = new Cartesian3();
  13320. }
  13321. result = Cartesian3.multiplyByScalar(ray.direction, t, result);
  13322. return Cartesian3.add(ray.origin, result, result);
  13323. };
  13324. return Ray;
  13325. });
  13326. /*global define*/
  13327. define('Core/IntersectionTests',[
  13328. './Cartesian3',
  13329. './Cartographic',
  13330. './defaultValue',
  13331. './defined',
  13332. './DeveloperError',
  13333. './Math',
  13334. './Matrix3',
  13335. './QuadraticRealPolynomial',
  13336. './QuarticRealPolynomial',
  13337. './Ray'
  13338. ], function(
  13339. Cartesian3,
  13340. Cartographic,
  13341. defaultValue,
  13342. defined,
  13343. DeveloperError,
  13344. CesiumMath,
  13345. Matrix3,
  13346. QuadraticRealPolynomial,
  13347. QuarticRealPolynomial,
  13348. Ray) {
  13349. 'use strict';
  13350. /**
  13351. * Functions for computing the intersection between geometries such as rays, planes, triangles, and ellipsoids.
  13352. *
  13353. * @exports IntersectionTests
  13354. */
  13355. var IntersectionTests = {};
  13356. /**
  13357. * Computes the intersection of a ray and a plane.
  13358. *
  13359. * @param {Ray} ray The ray.
  13360. * @param {Plane} plane The plane.
  13361. * @param {Cartesian3} [result] The object onto which to store the result.
  13362. * @returns {Cartesian3} The intersection point or undefined if there is no intersections.
  13363. */
  13364. IntersectionTests.rayPlane = function(ray, plane, result) {
  13365. if (!defined(ray)) {
  13366. throw new DeveloperError('ray is required.');
  13367. }
  13368. if (!defined(plane)) {
  13369. throw new DeveloperError('plane is required.');
  13370. }
  13371. if (!defined(result)) {
  13372. result = new Cartesian3();
  13373. }
  13374. var origin = ray.origin;
  13375. var direction = ray.direction;
  13376. var normal = plane.normal;
  13377. var denominator = Cartesian3.dot(normal, direction);
  13378. if (Math.abs(denominator) < CesiumMath.EPSILON15) {
  13379. // Ray is parallel to plane. The ray may be in the polygon's plane.
  13380. return undefined;
  13381. }
  13382. var t = (-plane.distance - Cartesian3.dot(normal, origin)) / denominator;
  13383. if (t < 0) {
  13384. return undefined;
  13385. }
  13386. result = Cartesian3.multiplyByScalar(direction, t, result);
  13387. return Cartesian3.add(origin, result, result);
  13388. };
  13389. var scratchEdge0 = new Cartesian3();
  13390. var scratchEdge1 = new Cartesian3();
  13391. var scratchPVec = new Cartesian3();
  13392. var scratchTVec = new Cartesian3();
  13393. var scratchQVec = new Cartesian3();
  13394. /**
  13395. * Computes the intersection of a ray and a triangle as a parametric distance along the input ray.
  13396. *
  13397. * Implements {@link https://cadxfem.org/inf/Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf|
  13398. * Fast Minimum Storage Ray/Triangle Intersection} by Tomas Moller and Ben Trumbore.
  13399. *
  13400. * @memberof IntersectionTests
  13401. *
  13402. * @param {Ray} ray The ray.
  13403. * @param {Cartesian3} p0 The first vertex of the triangle.
  13404. * @param {Cartesian3} p1 The second vertex of the triangle.
  13405. * @param {Cartesian3} p2 The third vertex of the triangle.
  13406. * @param {Boolean} [cullBackFaces=false] If <code>true</code>, will only compute an intersection with the front face of the triangle
  13407. * and return undefined for intersections with the back face.
  13408. * @returns {Number} The intersection as a parametric distance along the ray, or undefined if there is no intersection.
  13409. */
  13410. IntersectionTests.rayTriangleParametric = function(ray, p0, p1, p2, cullBackFaces) {
  13411. if (!defined(ray)) {
  13412. throw new DeveloperError('ray is required.');
  13413. }
  13414. if (!defined(p0)) {
  13415. throw new DeveloperError('p0 is required.');
  13416. }
  13417. if (!defined(p1)) {
  13418. throw new DeveloperError('p1 is required.');
  13419. }
  13420. if (!defined(p2)) {
  13421. throw new DeveloperError('p2 is required.');
  13422. }
  13423. cullBackFaces = defaultValue(cullBackFaces, false);
  13424. var origin = ray.origin;
  13425. var direction = ray.direction;
  13426. var edge0 = Cartesian3.subtract(p1, p0, scratchEdge0);
  13427. var edge1 = Cartesian3.subtract(p2, p0, scratchEdge1);
  13428. var p = Cartesian3.cross(direction, edge1, scratchPVec);
  13429. var det = Cartesian3.dot(edge0, p);
  13430. var tvec;
  13431. var q;
  13432. var u;
  13433. var v;
  13434. var t;
  13435. if (cullBackFaces) {
  13436. if (det < CesiumMath.EPSILON6) {
  13437. return undefined;
  13438. }
  13439. tvec = Cartesian3.subtract(origin, p0, scratchTVec);
  13440. u = Cartesian3.dot(tvec, p);
  13441. if (u < 0.0 || u > det) {
  13442. return undefined;
  13443. }
  13444. q = Cartesian3.cross(tvec, edge0, scratchQVec);
  13445. v = Cartesian3.dot(direction, q);
  13446. if (v < 0.0 || u + v > det) {
  13447. return undefined;
  13448. }
  13449. t = Cartesian3.dot(edge1, q) / det;
  13450. } else {
  13451. if (Math.abs(det) < CesiumMath.EPSILON6) {
  13452. return undefined;
  13453. }
  13454. var invDet = 1.0 / det;
  13455. tvec = Cartesian3.subtract(origin, p0, scratchTVec);
  13456. u = Cartesian3.dot(tvec, p) * invDet;
  13457. if (u < 0.0 || u > 1.0) {
  13458. return undefined;
  13459. }
  13460. q = Cartesian3.cross(tvec, edge0, scratchQVec);
  13461. v = Cartesian3.dot(direction, q) * invDet;
  13462. if (v < 0.0 || u + v > 1.0) {
  13463. return undefined;
  13464. }
  13465. t = Cartesian3.dot(edge1, q) * invDet;
  13466. }
  13467. return t;
  13468. };
  13469. /**
  13470. * Computes the intersection of a ray and a triangle as a Cartesian3 coordinate.
  13471. *
  13472. * Implements {@link https://cadxfem.org/inf/Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf|
  13473. * Fast Minimum Storage Ray/Triangle Intersection} by Tomas Moller and Ben Trumbore.
  13474. *
  13475. * @memberof IntersectionTests
  13476. *
  13477. * @param {Ray} ray The ray.
  13478. * @param {Cartesian3} p0 The first vertex of the triangle.
  13479. * @param {Cartesian3} p1 The second vertex of the triangle.
  13480. * @param {Cartesian3} p2 The third vertex of the triangle.
  13481. * @param {Boolean} [cullBackFaces=false] If <code>true</code>, will only compute an intersection with the front face of the triangle
  13482. * and return undefined for intersections with the back face.
  13483. * @param {Cartesian3} [result] The <code>Cartesian3</code> onto which to store the result.
  13484. * @returns {Cartesian3} The intersection point or undefined if there is no intersections.
  13485. */
  13486. IntersectionTests.rayTriangle = function(ray, p0, p1, p2, cullBackFaces, result) {
  13487. var t = IntersectionTests.rayTriangleParametric(ray, p0, p1, p2, cullBackFaces);
  13488. if (!defined(t) || t < 0.0) {
  13489. return undefined;
  13490. }
  13491. if (!defined(result)) {
  13492. result = new Cartesian3();
  13493. }
  13494. Cartesian3.multiplyByScalar(ray.direction, t, result);
  13495. return Cartesian3.add(ray.origin, result, result);
  13496. };
  13497. var scratchLineSegmentTriangleRay = new Ray();
  13498. /**
  13499. * Computes the intersection of a line segment and a triangle.
  13500. * @memberof IntersectionTests
  13501. *
  13502. * @param {Cartesian3} v0 The an end point of the line segment.
  13503. * @param {Cartesian3} v1 The other end point of the line segment.
  13504. * @param {Cartesian3} p0 The first vertex of the triangle.
  13505. * @param {Cartesian3} p1 The second vertex of the triangle.
  13506. * @param {Cartesian3} p2 The third vertex of the triangle.
  13507. * @param {Boolean} [cullBackFaces=false] If <code>true</code>, will only compute an intersection with the front face of the triangle
  13508. * and return undefined for intersections with the back face.
  13509. * @param {Cartesian3} [result] The <code>Cartesian3</code> onto which to store the result.
  13510. * @returns {Cartesian3} The intersection point or undefined if there is no intersections.
  13511. */
  13512. IntersectionTests.lineSegmentTriangle = function(v0, v1, p0, p1, p2, cullBackFaces, result) {
  13513. if (!defined(v0)) {
  13514. throw new DeveloperError('v0 is required.');
  13515. }
  13516. if (!defined(v1)) {
  13517. throw new DeveloperError('v1 is required.');
  13518. }
  13519. if (!defined(p0)) {
  13520. throw new DeveloperError('p0 is required.');
  13521. }
  13522. if (!defined(p1)) {
  13523. throw new DeveloperError('p1 is required.');
  13524. }
  13525. if (!defined(p2)) {
  13526. throw new DeveloperError('p2 is required.');
  13527. }
  13528. var ray = scratchLineSegmentTriangleRay;
  13529. Cartesian3.clone(v0, ray.origin);
  13530. Cartesian3.subtract(v1, v0, ray.direction);
  13531. Cartesian3.normalize(ray.direction, ray.direction);
  13532. var t = IntersectionTests.rayTriangleParametric(ray, p0, p1, p2, cullBackFaces);
  13533. if (!defined(t) || t < 0.0 || t > Cartesian3.distance(v0, v1)) {
  13534. return undefined;
  13535. }
  13536. if (!defined(result)) {
  13537. result = new Cartesian3();
  13538. }
  13539. Cartesian3.multiplyByScalar(ray.direction, t, result);
  13540. return Cartesian3.add(ray.origin, result, result);
  13541. };
  13542. function solveQuadratic(a, b, c, result) {
  13543. var det = b * b - 4.0 * a * c;
  13544. if (det < 0.0) {
  13545. return undefined;
  13546. } else if (det > 0.0) {
  13547. var denom = 1.0 / (2.0 * a);
  13548. var disc = Math.sqrt(det);
  13549. var root0 = (-b + disc) * denom;
  13550. var root1 = (-b - disc) * denom;
  13551. if (root0 < root1) {
  13552. result.root0 = root0;
  13553. result.root1 = root1;
  13554. } else {
  13555. result.root0 = root1;
  13556. result.root1 = root0;
  13557. }
  13558. return result;
  13559. }
  13560. var root = -b / (2.0 * a);
  13561. if (root === 0.0) {
  13562. return undefined;
  13563. }
  13564. result.root0 = result.root1 = root;
  13565. return result;
  13566. }
  13567. var raySphereRoots = {
  13568. root0 : 0.0,
  13569. root1 : 0.0
  13570. };
  13571. function raySphere(ray, sphere, result) {
  13572. if (!defined(result)) {
  13573. result = {};
  13574. }
  13575. var origin = ray.origin;
  13576. var direction = ray.direction;
  13577. var center = sphere.center;
  13578. var radiusSquared = sphere.radius * sphere.radius;
  13579. var diff = Cartesian3.subtract(origin, center, scratchPVec);
  13580. var a = Cartesian3.dot(direction, direction);
  13581. var b = 2.0 * Cartesian3.dot(direction, diff);
  13582. var c = Cartesian3.magnitudeSquared(diff) - radiusSquared;
  13583. var roots = solveQuadratic(a, b, c, raySphereRoots);
  13584. if (!defined(roots)) {
  13585. return undefined;
  13586. }
  13587. result.start = roots.root0;
  13588. result.stop = roots.root1;
  13589. return result;
  13590. }
  13591. /**
  13592. * Computes the intersection points of a ray with a sphere.
  13593. * @memberof IntersectionTests
  13594. *
  13595. * @param {Ray} ray The ray.
  13596. * @param {BoundingSphere} sphere The sphere.
  13597. * @param {Object} [result] The result onto which to store the result.
  13598. * @returns {Object} An object with the first (<code>start</code>) and the second (<code>stop</code>) intersection scalars for points along the ray or undefined if there are no intersections.
  13599. */
  13600. IntersectionTests.raySphere = function(ray, sphere, result) {
  13601. if (!defined(ray)) {
  13602. throw new DeveloperError('ray is required.');
  13603. }
  13604. if (!defined(sphere)) {
  13605. throw new DeveloperError('sphere is required.');
  13606. }
  13607. result = raySphere(ray, sphere, result);
  13608. if (!defined(result) || result.stop < 0.0) {
  13609. return undefined;
  13610. }
  13611. result.start = Math.max(result.start, 0.0);
  13612. return result;
  13613. };
  13614. var scratchLineSegmentRay = new Ray();
  13615. /**
  13616. * Computes the intersection points of a line segment with a sphere.
  13617. * @memberof IntersectionTests
  13618. *
  13619. * @param {Cartesian3} p0 An end point of the line segment.
  13620. * @param {Cartesian3} p1 The other end point of the line segment.
  13621. * @param {BoundingSphere} sphere The sphere.
  13622. * @param {Object} [result] The result onto which to store the result.
  13623. * @returns {Object} An object with the first (<code>start</code>) and the second (<code>stop</code>) intersection scalars for points along the line segment or undefined if there are no intersections.
  13624. */
  13625. IntersectionTests.lineSegmentSphere = function(p0, p1, sphere, result) {
  13626. if (!defined(p0)) {
  13627. throw new DeveloperError('p0 is required.');
  13628. }
  13629. if (!defined(p1)) {
  13630. throw new DeveloperError('p1 is required.');
  13631. }
  13632. if (!defined(sphere)) {
  13633. throw new DeveloperError('sphere is required.');
  13634. }
  13635. var ray = scratchLineSegmentRay;
  13636. Cartesian3.clone(p0, ray.origin);
  13637. var direction = Cartesian3.subtract(p1, p0, ray.direction);
  13638. var maxT = Cartesian3.magnitude(direction);
  13639. Cartesian3.normalize(direction, direction);
  13640. result = raySphere(ray, sphere, result);
  13641. if (!defined(result) || result.stop < 0.0 || result.start > maxT) {
  13642. return undefined;
  13643. }
  13644. result.start = Math.max(result.start, 0.0);
  13645. result.stop = Math.min(result.stop, maxT);
  13646. return result;
  13647. };
  13648. var scratchQ = new Cartesian3();
  13649. var scratchW = new Cartesian3();
  13650. /**
  13651. * Computes the intersection points of a ray with an ellipsoid.
  13652. *
  13653. * @param {Ray} ray The ray.
  13654. * @param {Ellipsoid} ellipsoid The ellipsoid.
  13655. * @returns {Object} An object with the first (<code>start</code>) and the second (<code>stop</code>) intersection scalars for points along the ray or undefined if there are no intersections.
  13656. */
  13657. IntersectionTests.rayEllipsoid = function(ray, ellipsoid) {
  13658. if (!defined(ray)) {
  13659. throw new DeveloperError('ray is required.');
  13660. }
  13661. if (!defined(ellipsoid)) {
  13662. throw new DeveloperError('ellipsoid is required.');
  13663. }
  13664. var inverseRadii = ellipsoid.oneOverRadii;
  13665. var q = Cartesian3.multiplyComponents(inverseRadii, ray.origin, scratchQ);
  13666. var w = Cartesian3.multiplyComponents(inverseRadii, ray.direction, scratchW);
  13667. var q2 = Cartesian3.magnitudeSquared(q);
  13668. var qw = Cartesian3.dot(q, w);
  13669. var difference, w2, product, discriminant, temp;
  13670. if (q2 > 1.0) {
  13671. // Outside ellipsoid.
  13672. if (qw >= 0.0) {
  13673. // Looking outward or tangent (0 intersections).
  13674. return undefined;
  13675. }
  13676. // qw < 0.0.
  13677. var qw2 = qw * qw;
  13678. difference = q2 - 1.0; // Positively valued.
  13679. w2 = Cartesian3.magnitudeSquared(w);
  13680. product = w2 * difference;
  13681. if (qw2 < product) {
  13682. // Imaginary roots (0 intersections).
  13683. return undefined;
  13684. } else if (qw2 > product) {
  13685. // Distinct roots (2 intersections).
  13686. discriminant = qw * qw - product;
  13687. temp = -qw + Math.sqrt(discriminant); // Avoid cancellation.
  13688. var root0 = temp / w2;
  13689. var root1 = difference / temp;
  13690. if (root0 < root1) {
  13691. return {
  13692. start : root0,
  13693. stop : root1
  13694. };
  13695. }
  13696. return {
  13697. start : root1,
  13698. stop : root0
  13699. };
  13700. } else {
  13701. // qw2 == product. Repeated roots (2 intersections).
  13702. var root = Math.sqrt(difference / w2);
  13703. return {
  13704. start : root,
  13705. stop : root
  13706. };
  13707. }
  13708. } else if (q2 < 1.0) {
  13709. // Inside ellipsoid (2 intersections).
  13710. difference = q2 - 1.0; // Negatively valued.
  13711. w2 = Cartesian3.magnitudeSquared(w);
  13712. product = w2 * difference; // Negatively valued.
  13713. discriminant = qw * qw - product;
  13714. temp = -qw + Math.sqrt(discriminant); // Positively valued.
  13715. return {
  13716. start : 0.0,
  13717. stop : temp / w2
  13718. };
  13719. } else {
  13720. // q2 == 1.0. On ellipsoid.
  13721. if (qw < 0.0) {
  13722. // Looking inward.
  13723. w2 = Cartesian3.magnitudeSquared(w);
  13724. return {
  13725. start : 0.0,
  13726. stop : -qw / w2
  13727. };
  13728. }
  13729. // qw >= 0.0. Looking outward or tangent.
  13730. return undefined;
  13731. }
  13732. };
  13733. function addWithCancellationCheck(left, right, tolerance) {
  13734. var difference = left + right;
  13735. if ((CesiumMath.sign(left) !== CesiumMath.sign(right)) &&
  13736. Math.abs(difference / Math.max(Math.abs(left), Math.abs(right))) < tolerance) {
  13737. return 0.0;
  13738. }
  13739. return difference;
  13740. }
  13741. function quadraticVectorExpression(A, b, c, x, w) {
  13742. var xSquared = x * x;
  13743. var wSquared = w * w;
  13744. var l2 = (A[Matrix3.COLUMN1ROW1] - A[Matrix3.COLUMN2ROW2]) * wSquared;
  13745. var l1 = w * (x * addWithCancellationCheck(A[Matrix3.COLUMN1ROW0], A[Matrix3.COLUMN0ROW1], CesiumMath.EPSILON15) + b.y);
  13746. var l0 = (A[Matrix3.COLUMN0ROW0] * xSquared + A[Matrix3.COLUMN2ROW2] * wSquared) + x * b.x + c;
  13747. var r1 = wSquared * addWithCancellationCheck(A[Matrix3.COLUMN2ROW1], A[Matrix3.COLUMN1ROW2], CesiumMath.EPSILON15);
  13748. var r0 = w * (x * addWithCancellationCheck(A[Matrix3.COLUMN2ROW0], A[Matrix3.COLUMN0ROW2]) + b.z);
  13749. var cosines;
  13750. var solutions = [];
  13751. if (r0 === 0.0 && r1 === 0.0) {
  13752. cosines = QuadraticRealPolynomial.computeRealRoots(l2, l1, l0);
  13753. if (cosines.length === 0) {
  13754. return solutions;
  13755. }
  13756. var cosine0 = cosines[0];
  13757. var sine0 = Math.sqrt(Math.max(1.0 - cosine0 * cosine0, 0.0));
  13758. solutions.push(new Cartesian3(x, w * cosine0, w * -sine0));
  13759. solutions.push(new Cartesian3(x, w * cosine0, w * sine0));
  13760. if (cosines.length === 2) {
  13761. var cosine1 = cosines[1];
  13762. var sine1 = Math.sqrt(Math.max(1.0 - cosine1 * cosine1, 0.0));
  13763. solutions.push(new Cartesian3(x, w * cosine1, w * -sine1));
  13764. solutions.push(new Cartesian3(x, w * cosine1, w * sine1));
  13765. }
  13766. return solutions;
  13767. }
  13768. var r0Squared = r0 * r0;
  13769. var r1Squared = r1 * r1;
  13770. var l2Squared = l2 * l2;
  13771. var r0r1 = r0 * r1;
  13772. var c4 = l2Squared + r1Squared;
  13773. var c3 = 2.0 * (l1 * l2 + r0r1);
  13774. var c2 = 2.0 * l0 * l2 + l1 * l1 - r1Squared + r0Squared;
  13775. var c1 = 2.0 * (l0 * l1 - r0r1);
  13776. var c0 = l0 * l0 - r0Squared;
  13777. if (c4 === 0.0 && c3 === 0.0 && c2 === 0.0 && c1 === 0.0) {
  13778. return solutions;
  13779. }
  13780. cosines = QuarticRealPolynomial.computeRealRoots(c4, c3, c2, c1, c0);
  13781. var length = cosines.length;
  13782. if (length === 0) {
  13783. return solutions;
  13784. }
  13785. for ( var i = 0; i < length; ++i) {
  13786. var cosine = cosines[i];
  13787. var cosineSquared = cosine * cosine;
  13788. var sineSquared = Math.max(1.0 - cosineSquared, 0.0);
  13789. var sine = Math.sqrt(sineSquared);
  13790. //var left = l2 * cosineSquared + l1 * cosine + l0;
  13791. var left;
  13792. if (CesiumMath.sign(l2) === CesiumMath.sign(l0)) {
  13793. left = addWithCancellationCheck(l2 * cosineSquared + l0, l1 * cosine, CesiumMath.EPSILON12);
  13794. } else if (CesiumMath.sign(l0) === CesiumMath.sign(l1 * cosine)) {
  13795. left = addWithCancellationCheck(l2 * cosineSquared, l1 * cosine + l0, CesiumMath.EPSILON12);
  13796. } else {
  13797. left = addWithCancellationCheck(l2 * cosineSquared + l1 * cosine, l0, CesiumMath.EPSILON12);
  13798. }
  13799. var right = addWithCancellationCheck(r1 * cosine, r0, CesiumMath.EPSILON15);
  13800. var product = left * right;
  13801. if (product < 0.0) {
  13802. solutions.push(new Cartesian3(x, w * cosine, w * sine));
  13803. } else if (product > 0.0) {
  13804. solutions.push(new Cartesian3(x, w * cosine, w * -sine));
  13805. } else if (sine !== 0.0) {
  13806. solutions.push(new Cartesian3(x, w * cosine, w * -sine));
  13807. solutions.push(new Cartesian3(x, w * cosine, w * sine));
  13808. ++i;
  13809. } else {
  13810. solutions.push(new Cartesian3(x, w * cosine, w * sine));
  13811. }
  13812. }
  13813. return solutions;
  13814. }
  13815. var firstAxisScratch = new Cartesian3();
  13816. var secondAxisScratch = new Cartesian3();
  13817. var thirdAxisScratch = new Cartesian3();
  13818. var referenceScratch = new Cartesian3();
  13819. var bCart = new Cartesian3();
  13820. var bScratch = new Matrix3();
  13821. var btScratch = new Matrix3();
  13822. var diScratch = new Matrix3();
  13823. var dScratch = new Matrix3();
  13824. var cScratch = new Matrix3();
  13825. var tempMatrix = new Matrix3();
  13826. var aScratch = new Matrix3();
  13827. var sScratch = new Cartesian3();
  13828. var closestScratch = new Cartesian3();
  13829. var surfPointScratch = new Cartographic();
  13830. /**
  13831. * Provides the point along the ray which is nearest to the ellipsoid.
  13832. *
  13833. * @param {Ray} ray The ray.
  13834. * @param {Ellipsoid} ellipsoid The ellipsoid.
  13835. * @returns {Cartesian3} The nearest planetodetic point on the ray.
  13836. */
  13837. IntersectionTests.grazingAltitudeLocation = function(ray, ellipsoid) {
  13838. if (!defined(ray)) {
  13839. throw new DeveloperError('ray is required.');
  13840. }
  13841. if (!defined(ellipsoid)) {
  13842. throw new DeveloperError('ellipsoid is required.');
  13843. }
  13844. var position = ray.origin;
  13845. var direction = ray.direction;
  13846. if (!Cartesian3.equals(position, Cartesian3.ZERO)) {
  13847. var normal = ellipsoid.geodeticSurfaceNormal(position, firstAxisScratch);
  13848. if (Cartesian3.dot(direction, normal) >= 0.0) { // The location provided is the closest point in altitude
  13849. return position;
  13850. }
  13851. }
  13852. var intersects = defined(this.rayEllipsoid(ray, ellipsoid));
  13853. // Compute the scaled direction vector.
  13854. var f = ellipsoid.transformPositionToScaledSpace(direction, firstAxisScratch);
  13855. // Constructs a basis from the unit scaled direction vector. Construct its rotation and transpose.
  13856. var firstAxis = Cartesian3.normalize(f, f);
  13857. var reference = Cartesian3.mostOrthogonalAxis(f, referenceScratch);
  13858. var secondAxis = Cartesian3.normalize(Cartesian3.cross(reference, firstAxis, secondAxisScratch), secondAxisScratch);
  13859. var thirdAxis = Cartesian3.normalize(Cartesian3.cross(firstAxis, secondAxis, thirdAxisScratch), thirdAxisScratch);
  13860. var B = bScratch;
  13861. B[0] = firstAxis.x;
  13862. B[1] = firstAxis.y;
  13863. B[2] = firstAxis.z;
  13864. B[3] = secondAxis.x;
  13865. B[4] = secondAxis.y;
  13866. B[5] = secondAxis.z;
  13867. B[6] = thirdAxis.x;
  13868. B[7] = thirdAxis.y;
  13869. B[8] = thirdAxis.z;
  13870. var B_T = Matrix3.transpose(B, btScratch);
  13871. // Get the scaling matrix and its inverse.
  13872. var D_I = Matrix3.fromScale(ellipsoid.radii, diScratch);
  13873. var D = Matrix3.fromScale(ellipsoid.oneOverRadii, dScratch);
  13874. var C = cScratch;
  13875. C[0] = 0.0;
  13876. C[1] = -direction.z;
  13877. C[2] = direction.y;
  13878. C[3] = direction.z;
  13879. C[4] = 0.0;
  13880. C[5] = -direction.x;
  13881. C[6] = -direction.y;
  13882. C[7] = direction.x;
  13883. C[8] = 0.0;
  13884. var temp = Matrix3.multiply(Matrix3.multiply(B_T, D, tempMatrix), C, tempMatrix);
  13885. var A = Matrix3.multiply(Matrix3.multiply(temp, D_I, aScratch), B, aScratch);
  13886. var b = Matrix3.multiplyByVector(temp, position, bCart);
  13887. // Solve for the solutions to the expression in standard form:
  13888. var solutions = quadraticVectorExpression(A, Cartesian3.negate(b, firstAxisScratch), 0.0, 0.0, 1.0);
  13889. var s;
  13890. var altitude;
  13891. var length = solutions.length;
  13892. if (length > 0) {
  13893. var closest = Cartesian3.clone(Cartesian3.ZERO, closestScratch);
  13894. var maximumValue = Number.NEGATIVE_INFINITY;
  13895. for ( var i = 0; i < length; ++i) {
  13896. s = Matrix3.multiplyByVector(D_I, Matrix3.multiplyByVector(B, solutions[i], sScratch), sScratch);
  13897. var v = Cartesian3.normalize(Cartesian3.subtract(s, position, referenceScratch), referenceScratch);
  13898. var dotProduct = Cartesian3.dot(v, direction);
  13899. if (dotProduct > maximumValue) {
  13900. maximumValue = dotProduct;
  13901. closest = Cartesian3.clone(s, closest);
  13902. }
  13903. }
  13904. var surfacePoint = ellipsoid.cartesianToCartographic(closest, surfPointScratch);
  13905. maximumValue = CesiumMath.clamp(maximumValue, 0.0, 1.0);
  13906. altitude = Cartesian3.magnitude(Cartesian3.subtract(closest, position, referenceScratch)) * Math.sqrt(1.0 - maximumValue * maximumValue);
  13907. altitude = intersects ? -altitude : altitude;
  13908. surfacePoint.height = altitude;
  13909. return ellipsoid.cartographicToCartesian(surfacePoint, new Cartesian3());
  13910. }
  13911. return undefined;
  13912. };
  13913. var lineSegmentPlaneDifference = new Cartesian3();
  13914. /**
  13915. * Computes the intersection of a line segment and a plane.
  13916. *
  13917. * @param {Cartesian3} endPoint0 An end point of the line segment.
  13918. * @param {Cartesian3} endPoint1 The other end point of the line segment.
  13919. * @param {Plane} plane The plane.
  13920. * @param {Cartesian3} [result] The object onto which to store the result.
  13921. * @returns {Cartesian3} The intersection point or undefined if there is no intersection.
  13922. *
  13923. * @example
  13924. * var origin = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883);
  13925. * var normal = ellipsoid.geodeticSurfaceNormal(origin);
  13926. * var plane = Cesium.Plane.fromPointNormal(origin, normal);
  13927. *
  13928. * var p0 = new Cesium.Cartesian3(...);
  13929. * var p1 = new Cesium.Cartesian3(...);
  13930. *
  13931. * // find the intersection of the line segment from p0 to p1 and the tangent plane at origin.
  13932. * var intersection = Cesium.IntersectionTests.lineSegmentPlane(p0, p1, plane);
  13933. */
  13934. IntersectionTests.lineSegmentPlane = function(endPoint0, endPoint1, plane, result) {
  13935. if (!defined(endPoint0)) {
  13936. throw new DeveloperError('endPoint0 is required.');
  13937. }
  13938. if (!defined(endPoint1)) {
  13939. throw new DeveloperError('endPoint1 is required.');
  13940. }
  13941. if (!defined(plane)) {
  13942. throw new DeveloperError('plane is required.');
  13943. }
  13944. if (!defined(result)) {
  13945. result = new Cartesian3();
  13946. }
  13947. var difference = Cartesian3.subtract(endPoint1, endPoint0, lineSegmentPlaneDifference);
  13948. var normal = plane.normal;
  13949. var nDotDiff = Cartesian3.dot(normal, difference);
  13950. // check if the segment and plane are parallel
  13951. if (Math.abs(nDotDiff) < CesiumMath.EPSILON6) {
  13952. return undefined;
  13953. }
  13954. var nDotP0 = Cartesian3.dot(normal, endPoint0);
  13955. var t = -(plane.distance + nDotP0) / nDotDiff;
  13956. // intersection only if t is in [0, 1]
  13957. if (t < 0.0 || t > 1.0) {
  13958. return undefined;
  13959. }
  13960. // intersection is endPoint0 + t * (endPoint1 - endPoint0)
  13961. Cartesian3.multiplyByScalar(difference, t, result);
  13962. Cartesian3.add(endPoint0, result, result);
  13963. return result;
  13964. };
  13965. /**
  13966. * Computes the intersection of a triangle and a plane
  13967. *
  13968. * @param {Cartesian3} p0 First point of the triangle
  13969. * @param {Cartesian3} p1 Second point of the triangle
  13970. * @param {Cartesian3} p2 Third point of the triangle
  13971. * @param {Plane} plane Intersection plane
  13972. * @returns {Object} An object with properties <code>positions</code> and <code>indices</code>, which are arrays that represent three triangles that do not cross the plane. (Undefined if no intersection exists)
  13973. *
  13974. * @example
  13975. * var origin = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883);
  13976. * var normal = ellipsoid.geodeticSurfaceNormal(origin);
  13977. * var plane = Cesium.Plane.fromPointNormal(origin, normal);
  13978. *
  13979. * var p0 = new Cesium.Cartesian3(...);
  13980. * var p1 = new Cesium.Cartesian3(...);
  13981. * var p2 = new Cesium.Cartesian3(...);
  13982. *
  13983. * // convert the triangle composed of points (p0, p1, p2) to three triangles that don't cross the plane
  13984. * var triangles = Cesium.IntersectionTests.trianglePlaneIntersection(p0, p1, p2, plane);
  13985. */
  13986. IntersectionTests.trianglePlaneIntersection = function(p0, p1, p2, plane) {
  13987. if ((!defined(p0)) ||
  13988. (!defined(p1)) ||
  13989. (!defined(p2)) ||
  13990. (!defined(plane))) {
  13991. throw new DeveloperError('p0, p1, p2, and plane are required.');
  13992. }
  13993. var planeNormal = plane.normal;
  13994. var planeD = plane.distance;
  13995. var p0Behind = (Cartesian3.dot(planeNormal, p0) + planeD) < 0.0;
  13996. var p1Behind = (Cartesian3.dot(planeNormal, p1) + planeD) < 0.0;
  13997. var p2Behind = (Cartesian3.dot(planeNormal, p2) + planeD) < 0.0;
  13998. // Given these dots products, the calls to lineSegmentPlaneIntersection
  13999. // always have defined results.
  14000. var numBehind = 0;
  14001. numBehind += p0Behind ? 1 : 0;
  14002. numBehind += p1Behind ? 1 : 0;
  14003. numBehind += p2Behind ? 1 : 0;
  14004. var u1, u2;
  14005. if (numBehind === 1 || numBehind === 2) {
  14006. u1 = new Cartesian3();
  14007. u2 = new Cartesian3();
  14008. }
  14009. if (numBehind === 1) {
  14010. if (p0Behind) {
  14011. IntersectionTests.lineSegmentPlane(p0, p1, plane, u1);
  14012. IntersectionTests.lineSegmentPlane(p0, p2, plane, u2);
  14013. return {
  14014. positions : [p0, p1, p2, u1, u2 ],
  14015. indices : [
  14016. // Behind
  14017. 0, 3, 4,
  14018. // In front
  14019. 1, 2, 4,
  14020. 1, 4, 3
  14021. ]
  14022. };
  14023. } else if (p1Behind) {
  14024. IntersectionTests.lineSegmentPlane(p1, p2, plane, u1);
  14025. IntersectionTests.lineSegmentPlane(p1, p0, plane, u2);
  14026. return {
  14027. positions : [p0, p1, p2, u1, u2 ],
  14028. indices : [
  14029. // Behind
  14030. 1, 3, 4,
  14031. // In front
  14032. 2, 0, 4,
  14033. 2, 4, 3
  14034. ]
  14035. };
  14036. } else if (p2Behind) {
  14037. IntersectionTests.lineSegmentPlane(p2, p0, plane, u1);
  14038. IntersectionTests.lineSegmentPlane(p2, p1, plane, u2);
  14039. return {
  14040. positions : [p0, p1, p2, u1, u2 ],
  14041. indices : [
  14042. // Behind
  14043. 2, 3, 4,
  14044. // In front
  14045. 0, 1, 4,
  14046. 0, 4, 3
  14047. ]
  14048. };
  14049. }
  14050. } else if (numBehind === 2) {
  14051. if (!p0Behind) {
  14052. IntersectionTests.lineSegmentPlane(p1, p0, plane, u1);
  14053. IntersectionTests.lineSegmentPlane(p2, p0, plane, u2);
  14054. return {
  14055. positions : [p0, p1, p2, u1, u2 ],
  14056. indices : [
  14057. // Behind
  14058. 1, 2, 4,
  14059. 1, 4, 3,
  14060. // In front
  14061. 0, 3, 4
  14062. ]
  14063. };
  14064. } else if (!p1Behind) {
  14065. IntersectionTests.lineSegmentPlane(p2, p1, plane, u1);
  14066. IntersectionTests.lineSegmentPlane(p0, p1, plane, u2);
  14067. return {
  14068. positions : [p0, p1, p2, u1, u2 ],
  14069. indices : [
  14070. // Behind
  14071. 2, 0, 4,
  14072. 2, 4, 3,
  14073. // In front
  14074. 1, 3, 4
  14075. ]
  14076. };
  14077. } else if (!p2Behind) {
  14078. IntersectionTests.lineSegmentPlane(p0, p2, plane, u1);
  14079. IntersectionTests.lineSegmentPlane(p1, p2, plane, u2);
  14080. return {
  14081. positions : [p0, p1, p2, u1, u2 ],
  14082. indices : [
  14083. // Behind
  14084. 0, 1, 4,
  14085. 0, 4, 3,
  14086. // In front
  14087. 2, 3, 4
  14088. ]
  14089. };
  14090. }
  14091. }
  14092. // if numBehind is 3, the triangle is completely behind the plane;
  14093. // otherwise, it is completely in front (numBehind is 0).
  14094. return undefined;
  14095. };
  14096. return IntersectionTests;
  14097. });
  14098. /*global define*/
  14099. define('Core/Plane',[
  14100. './Cartesian3',
  14101. './defined',
  14102. './DeveloperError',
  14103. './freezeObject'
  14104. ], function(
  14105. Cartesian3,
  14106. defined,
  14107. DeveloperError,
  14108. freezeObject) {
  14109. 'use strict';
  14110. /**
  14111. * A plane in Hessian Normal Form defined by
  14112. * <pre>
  14113. * ax + by + cz + d = 0
  14114. * </pre>
  14115. * where (a, b, c) is the plane's <code>normal</code>, d is the signed
  14116. * <code>distance</code> to the plane, and (x, y, z) is any point on
  14117. * the plane.
  14118. *
  14119. * @alias Plane
  14120. * @constructor
  14121. *
  14122. * @param {Cartesian3} normal The plane's normal (normalized).
  14123. * @param {Number} distance The shortest distance from the origin to the plane. The sign of
  14124. * <code>distance</code> determines which side of the plane the origin
  14125. * is on. If <code>distance</code> is positive, the origin is in the half-space
  14126. * in the direction of the normal; if negative, the origin is in the half-space
  14127. * opposite to the normal; if zero, the plane passes through the origin.
  14128. *
  14129. * @example
  14130. * // The plane x=0
  14131. * var plane = new Cesium.Plane(Cesium.Cartesian3.UNIT_X, 0.0);
  14132. */
  14133. function Plane(normal, distance) {
  14134. if (!defined(normal)) {
  14135. throw new DeveloperError('normal is required.');
  14136. }
  14137. if (!defined(distance)) {
  14138. throw new DeveloperError('distance is required.');
  14139. }
  14140. /**
  14141. * The plane's normal.
  14142. *
  14143. * @type {Cartesian3}
  14144. */
  14145. this.normal = Cartesian3.clone(normal);
  14146. /**
  14147. * The shortest distance from the origin to the plane. The sign of
  14148. * <code>distance</code> determines which side of the plane the origin
  14149. * is on. If <code>distance</code> is positive, the origin is in the half-space
  14150. * in the direction of the normal; if negative, the origin is in the half-space
  14151. * opposite to the normal; if zero, the plane passes through the origin.
  14152. *
  14153. * @type {Number}
  14154. */
  14155. this.distance = distance;
  14156. }
  14157. /**
  14158. * Creates a plane from a normal and a point on the plane.
  14159. *
  14160. * @param {Cartesian3} point The point on the plane.
  14161. * @param {Cartesian3} normal The plane's normal (normalized).
  14162. * @param {Plane} [result] The object onto which to store the result.
  14163. * @returns {Plane} A new plane instance or the modified result parameter.
  14164. *
  14165. * @example
  14166. * var point = Cesium.Cartesian3.fromDegrees(-72.0, 40.0);
  14167. * var normal = ellipsoid.geodeticSurfaceNormal(point);
  14168. * var tangentPlane = Cesium.Plane.fromPointNormal(point, normal);
  14169. */
  14170. Plane.fromPointNormal = function(point, normal, result) {
  14171. if (!defined(point)) {
  14172. throw new DeveloperError('point is required.');
  14173. }
  14174. if (!defined(normal)) {
  14175. throw new DeveloperError('normal is required.');
  14176. }
  14177. var distance = -Cartesian3.dot(normal, point);
  14178. if (!defined(result)) {
  14179. return new Plane(normal, distance);
  14180. }
  14181. Cartesian3.clone(normal, result.normal);
  14182. result.distance = distance;
  14183. return result;
  14184. };
  14185. var scratchNormal = new Cartesian3();
  14186. /**
  14187. * Creates a plane from the general equation
  14188. *
  14189. * @param {Cartesian4} coefficients The plane's normal (normalized).
  14190. * @param {Plane} [result] The object onto which to store the result.
  14191. * @returns {Plane} A new plane instance or the modified result parameter.
  14192. */
  14193. Plane.fromCartesian4 = function(coefficients, result) {
  14194. if (!defined(coefficients)) {
  14195. throw new DeveloperError('coefficients is required.');
  14196. }
  14197. var normal = Cartesian3.fromCartesian4(coefficients, scratchNormal);
  14198. var distance = coefficients.w;
  14199. if (!defined(result)) {
  14200. return new Plane(normal, distance);
  14201. } else {
  14202. Cartesian3.clone(normal, result.normal);
  14203. result.distance = distance;
  14204. return result;
  14205. }
  14206. };
  14207. /**
  14208. * Computes the signed shortest distance of a point to a plane.
  14209. * The sign of the distance determines which side of the plane the point
  14210. * is on. If the distance is positive, the point is in the half-space
  14211. * in the direction of the normal; if negative, the point is in the half-space
  14212. * opposite to the normal; if zero, the plane passes through the point.
  14213. *
  14214. * @param {Plane} plane The plane.
  14215. * @param {Cartesian3} point The point.
  14216. * @returns {Number} The signed shortest distance of the point to the plane.
  14217. */
  14218. Plane.getPointDistance = function(plane, point) {
  14219. if (!defined(plane)) {
  14220. throw new DeveloperError('plane is required.');
  14221. }
  14222. if (!defined(point)) {
  14223. throw new DeveloperError('point is required.');
  14224. }
  14225. return Cartesian3.dot(plane.normal, point) + plane.distance;
  14226. };
  14227. /**
  14228. * A constant initialized to the XY plane passing through the origin, with normal in positive Z.
  14229. *
  14230. * @type {Plane}
  14231. * @constant
  14232. */
  14233. Plane.ORIGIN_XY_PLANE = freezeObject(new Plane(Cartesian3.UNIT_Z, 0.0));
  14234. /**
  14235. * A constant initialized to the YZ plane passing through the origin, with normal in positive X.
  14236. *
  14237. * @type {Plane}
  14238. * @constant
  14239. */
  14240. Plane.ORIGIN_YZ_PLANE = freezeObject(new Plane(Cartesian3.UNIT_X, 0.0));
  14241. /**
  14242. * A constant initialized to the ZX plane passing through the origin, with normal in positive Y.
  14243. *
  14244. * @type {Plane}
  14245. * @constant
  14246. */
  14247. Plane.ORIGIN_ZX_PLANE = freezeObject(new Plane(Cartesian3.UNIT_Y, 0.0));
  14248. return Plane;
  14249. });
  14250. /*global define*/
  14251. define('Core/oneTimeWarning',[
  14252. './defaultValue',
  14253. './defined',
  14254. './DeveloperError'
  14255. ], function(
  14256. defaultValue,
  14257. defined,
  14258. DeveloperError) {
  14259. "use strict";
  14260. var warnings = {};
  14261. /**
  14262. * Logs a one time message to the console. Use this function instead of
  14263. * <code>console.log</code> directly since this does not log duplicate messages
  14264. * unless it is called from multiple workers.
  14265. *
  14266. * @exports oneTimeWarning
  14267. *
  14268. * @param {String} identifier The unique identifier for this warning.
  14269. * @param {String} [message=identifier] The message to log to the console.
  14270. *
  14271. * @example
  14272. * for(var i=0;i<foo.length;++i) {
  14273. * if (!defined(foo[i].bar)) {
  14274. * // Something that can be recovered from but may happen a lot
  14275. * oneTimeWarning('foo.bar undefined', 'foo.bar is undefined. Setting to 0.');
  14276. * foo[i].bar = 0;
  14277. * // ...
  14278. * }
  14279. * }
  14280. *
  14281. * @private
  14282. */
  14283. function oneTimeWarning(identifier, message) {
  14284. if (!defined(identifier)) {
  14285. throw new DeveloperError('identifier is required.');
  14286. }
  14287. if (!defined(warnings[identifier])) {
  14288. warnings[identifier] = true;
  14289. console.log(defaultValue(message, identifier));
  14290. }
  14291. }
  14292. oneTimeWarning.geometryOutlines = 'Entity geometry outlines are unsupported on terrain. Outlines will be disabled. To enable outlines, disable geometry terrain clamping by explicitly setting height to 0.';
  14293. return oneTimeWarning;
  14294. });
  14295. /*global define*/
  14296. define('Core/deprecationWarning',[
  14297. './defined',
  14298. './DeveloperError',
  14299. './oneTimeWarning'
  14300. ], function(
  14301. defined,
  14302. DeveloperError,
  14303. oneTimeWarning) {
  14304. 'use strict';
  14305. /**
  14306. * Logs a deprecation message to the console. Use this function instead of
  14307. * <code>console.log</code> directly since this does not log duplicate messages
  14308. * unless it is called from multiple workers.
  14309. *
  14310. * @exports deprecationWarning
  14311. *
  14312. * @param {String} identifier The unique identifier for this deprecated API.
  14313. * @param {String} message The message to log to the console.
  14314. *
  14315. * @example
  14316. * // Deprecated function or class
  14317. * function Foo() {
  14318. * deprecationWarning('Foo', 'Foo was deprecated in Cesium 1.01. It will be removed in 1.03. Use newFoo instead.');
  14319. * // ...
  14320. * }
  14321. *
  14322. * // Deprecated function
  14323. * Bar.prototype.func = function() {
  14324. * deprecationWarning('Bar.func', 'Bar.func() was deprecated in Cesium 1.01. It will be removed in 1.03. Use Bar.newFunc() instead.');
  14325. * // ...
  14326. * };
  14327. *
  14328. * // Deprecated property
  14329. * defineProperties(Bar.prototype, {
  14330. * prop : {
  14331. * get : function() {
  14332. * deprecationWarning('Bar.prop', 'Bar.prop was deprecated in Cesium 1.01. It will be removed in 1.03. Use Bar.newProp instead.');
  14333. * // ...
  14334. * },
  14335. * set : function(value) {
  14336. * deprecationWarning('Bar.prop', 'Bar.prop was deprecated in Cesium 1.01. It will be removed in 1.03. Use Bar.newProp instead.');
  14337. * // ...
  14338. * }
  14339. * }
  14340. * });
  14341. *
  14342. * @private
  14343. */
  14344. function deprecationWarning(identifier, message) {
  14345. if (!defined(identifier) || !defined(message)) {
  14346. throw new DeveloperError('identifier and message are required.');
  14347. }
  14348. oneTimeWarning(identifier, message);
  14349. }
  14350. return deprecationWarning;
  14351. });
  14352. /*global define*/
  14353. define('Core/binarySearch',[
  14354. './defined',
  14355. './DeveloperError'
  14356. ], function(
  14357. defined,
  14358. DeveloperError) {
  14359. 'use strict';
  14360. /**
  14361. * Finds an item in a sorted array.
  14362. *
  14363. * @exports binarySearch
  14364. *
  14365. * @param {Array} array The sorted array to search.
  14366. * @param {Object} itemToFind The item to find in the array.
  14367. * @param {binarySearch~Comparator} comparator The function to use to compare the item to
  14368. * elements in the array.
  14369. * @returns {Number} The index of <code>itemToFind</code> in the array, if it exists. If <code>itemToFind</code>
  14370. * does not exist, the return value is a negative number which is the bitwise complement (~)
  14371. * of the index before which the itemToFind should be inserted in order to maintain the
  14372. * sorted order of the array.
  14373. *
  14374. * @example
  14375. * // Create a comparator function to search through an array of numbers.
  14376. * function comparator(a, b) {
  14377. * return a - b;
  14378. * };
  14379. * var numbers = [0, 2, 4, 6, 8];
  14380. * var index = Cesium.binarySearch(numbers, 6, comparator); // 3
  14381. */
  14382. function binarySearch(array, itemToFind, comparator) {
  14383. if (!defined(array)) {
  14384. throw new DeveloperError('array is required.');
  14385. }
  14386. if (!defined(itemToFind)) {
  14387. throw new DeveloperError('itemToFind is required.');
  14388. }
  14389. if (!defined(comparator)) {
  14390. throw new DeveloperError('comparator is required.');
  14391. }
  14392. var low = 0;
  14393. var high = array.length - 1;
  14394. var i;
  14395. var comparison;
  14396. while (low <= high) {
  14397. i = ~~((low + high) / 2);
  14398. comparison = comparator(array[i], itemToFind);
  14399. if (comparison < 0) {
  14400. low = i + 1;
  14401. continue;
  14402. }
  14403. if (comparison > 0) {
  14404. high = i - 1;
  14405. continue;
  14406. }
  14407. return i;
  14408. }
  14409. return ~(high + 1);
  14410. }
  14411. /**
  14412. * A function used to compare two items while performing a binary search.
  14413. * @callback binarySearch~Comparator
  14414. *
  14415. * @param {Object} a An item in the array.
  14416. * @param {Object} b The item being searched for.
  14417. * @returns {Number} Returns a negative value if <code>a</code> is less than <code>b</code>,
  14418. * a positive value if <code>a</code> is greater than <code>b</code>, or
  14419. * 0 if <code>a</code> is equal to <code>b</code>.
  14420. *
  14421. * @example
  14422. * function compareNumbers(a, b) {
  14423. * return a - b;
  14424. * }
  14425. */
  14426. return binarySearch;
  14427. });
  14428. /*global define*/
  14429. define('Core/EarthOrientationParametersSample',[],function() {
  14430. 'use strict';
  14431. /**
  14432. * A set of Earth Orientation Parameters (EOP) sampled at a time.
  14433. *
  14434. * @alias EarthOrientationParametersSample
  14435. * @constructor
  14436. *
  14437. * @param {Number} xPoleWander The pole wander about the X axis, in radians.
  14438. * @param {Number} yPoleWander The pole wander about the Y axis, in radians.
  14439. * @param {Number} xPoleOffset The offset to the Celestial Intermediate Pole (CIP) about the X axis, in radians.
  14440. * @param {Number} yPoleOffset The offset to the Celestial Intermediate Pole (CIP) about the Y axis, in radians.
  14441. * @param {Number} ut1MinusUtc The difference in time standards, UT1 - UTC, in seconds.
  14442. *
  14443. * @private
  14444. */
  14445. function EarthOrientationParametersSample(xPoleWander, yPoleWander, xPoleOffset, yPoleOffset, ut1MinusUtc) {
  14446. /**
  14447. * The pole wander about the X axis, in radians.
  14448. * @type {Number}
  14449. */
  14450. this.xPoleWander = xPoleWander;
  14451. /**
  14452. * The pole wander about the Y axis, in radians.
  14453. * @type {Number}
  14454. */
  14455. this.yPoleWander = yPoleWander;
  14456. /**
  14457. * The offset to the Celestial Intermediate Pole (CIP) about the X axis, in radians.
  14458. * @type {Number}
  14459. */
  14460. this.xPoleOffset = xPoleOffset;
  14461. /**
  14462. * The offset to the Celestial Intermediate Pole (CIP) about the Y axis, in radians.
  14463. * @type {Number}
  14464. */
  14465. this.yPoleOffset = yPoleOffset;
  14466. /**
  14467. * The difference in time standards, UT1 - UTC, in seconds.
  14468. * @type {Number}
  14469. */
  14470. this.ut1MinusUtc = ut1MinusUtc;
  14471. }
  14472. return EarthOrientationParametersSample;
  14473. });
  14474. /**
  14475. @license
  14476. sprintf.js from the php.js project - https://github.com/kvz/phpjs
  14477. Directly from https://github.com/kvz/phpjs/blob/master/functions/strings/sprintf.js
  14478. php.js is copyright 2012 Kevin van Zonneveld.
  14479. Portions copyright Brett Zamir (http://brett-zamir.me), Kevin van Zonneveld
  14480. (http://kevin.vanzonneveld.net), Onno Marsman, Theriault, Michael White
  14481. (http://getsprink.com), Waldo Malqui Silva, Paulo Freitas, Jack, Jonas
  14482. Raoni Soares Silva (http://www.jsfromhell.com), Philip Peterson, Legaev
  14483. Andrey, Ates Goral (http://magnetiq.com), Alex, Ratheous, Martijn Wieringa,
  14484. Rafa? Kukawski (http://blog.kukawski.pl), lmeyrick
  14485. (https://sourceforge.net/projects/bcmath-js/), Nate, Philippe Baumann,
  14486. Enrique Gonzalez, Webtoolkit.info (http://www.webtoolkit.info/), Carlos R.
  14487. L. Rodrigues (http://www.jsfromhell.com), Ash Searle
  14488. (http://hexmen.com/blog/), Jani Hartikainen, travc, Ole Vrijenhoek,
  14489. Erkekjetter, Michael Grier, Rafa? Kukawski (http://kukawski.pl), Johnny
  14490. Mast (http://www.phpvrouwen.nl), T.Wild, d3x,
  14491. http://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hex-in-javascript,
  14492. Rafa? Kukawski (http://blog.kukawski.pl/), stag019, pilus, WebDevHobo
  14493. (http://webdevhobo.blogspot.com/), marrtins, GeekFG
  14494. (http://geekfg.blogspot.com), Andrea Giammarchi
  14495. (http://webreflection.blogspot.com), Arpad Ray (mailto:arpad@php.net),
  14496. gorthaur, Paul Smith, Tim de Koning (http://www.kingsquare.nl), Joris, Oleg
  14497. Eremeev, Steve Hilder, majak, gettimeofday, KELAN, Josh Fraser
  14498. (http://onlineaspect.com/2007/06/08/auto-detect-a-time-zone-with-javascript/),
  14499. Marc Palau, Martin
  14500. (http://www.erlenwiese.de/), Breaking Par Consulting Inc
  14501. (http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256CFB006C45F7),
  14502. Chris, Mirek Slugen, saulius, Alfonso Jimenez
  14503. (http://www.alfonsojimenez.com), Diplom@t (http://difane.com/), felix,
  14504. Mailfaker (http://www.weedem.fr/), Tyler Akins (http://rumkin.com), Caio
  14505. Ariede (http://caioariede.com), Robin, Kankrelune
  14506. (http://www.webfaktory.info/), Karol Kowalski, Imgen Tata
  14507. (http://www.myipdf.com/), mdsjack (http://www.mdsjack.bo.it), Dreamer,
  14508. Felix Geisendoerfer (http://www.debuggable.com/felix), Lars Fischer, AJ,
  14509. David, Aman Gupta, Michael White, Public Domain
  14510. (http://www.json.org/json2.js), Steven Levithan
  14511. (http://blog.stevenlevithan.com), Sakimori, Pellentesque Malesuada,
  14512. Thunder.m, Dj (http://phpjs.org/functions/htmlentities:425#comment_134018),
  14513. Steve Clay, David James, Francois, class_exists, nobbler, T. Wild, Itsacon
  14514. (http://www.itsacon.net/), date, Ole Vrijenhoek (http://www.nervous.nl/),
  14515. Fox, Raphael (Ao RUDLER), Marco, noname, Mateusz "loonquawl" Zalega, Frank
  14516. Forte, Arno, ger, mktime, john (http://www.jd-tech.net), Nick Kolosov
  14517. (http://sammy.ru), marc andreu, Scott Cariss, Douglas Crockford
  14518. (http://javascript.crockford.com), madipta, Slawomir Kaniecki,
  14519. ReverseSyntax, Nathan, Alex Wilson, kenneth, Bayron Guevara, Adam Wallner
  14520. (http://web2.bitbaro.hu/), paulo kuong, jmweb, Lincoln Ramsay, djmix,
  14521. Pyerre, Jon Hohle, Thiago Mata (http://thiagomata.blog.com), lmeyrick
  14522. (https://sourceforge.net/projects/bcmath-js/this.), Linuxworld, duncan,
  14523. Gilbert, Sanjoy Roy, Shingo, sankai, Oskar Larsson H?gfeldt
  14524. (http://oskar-lh.name/), Denny Wardhana, 0m3r, Everlasto, Subhasis Deb,
  14525. josh, jd, Pier Paolo Ramon (http://www.mastersoup.com/), P, merabi, Soren
  14526. Hansen, Eugene Bulkin (http://doubleaw.com/), Der Simon
  14527. (http://innerdom.sourceforge.net/), echo is bad, Ozh, XoraX
  14528. (http://www.xorax.info), EdorFaus, JB, J A R, Marc Jansen, Francesco, LH,
  14529. Stoyan Kyosev (http://www.svest.org/), nord_ua, omid
  14530. (http://phpjs.org/functions/380:380#comment_137122), Brad Touesnard, MeEtc
  14531. (http://yass.meetcweb.com), Peter-Paul Koch
  14532. (http://www.quirksmode.org/js/beat.html), Olivier Louvignes
  14533. (http://mg-crea.com/), T0bsn, Tim Wiel, Bryan Elliott, Jalal Berrami,
  14534. Martin, JT, David Randall, Thomas Beaucourt (http://www.webapp.fr), taith,
  14535. vlado houba, Pierre-Luc Paour, Kristof Coomans (SCK-CEN Belgian Nucleair
  14536. Research Centre), Martin Pool, Kirk Strobeck, Rick Waldron, Brant Messenger
  14537. (http://www.brantmessenger.com/), Devan Penner-Woelk, Saulo Vallory, Wagner
  14538. B. Soares, Artur Tchernychev, Valentina De Rosa, Jason Wong
  14539. (http://carrot.org/), Christoph, Daniel Esteban, strftime, Mick@el, rezna,
  14540. Simon Willison (http://simonwillison.net), Anton Ongson, Gabriel Paderni,
  14541. Marco van Oort, penutbutterjelly, Philipp Lenssen, Bjorn Roesbeke
  14542. (http://www.bjornroesbeke.be/), Bug?, Eric Nagel, Tomasz Wesolowski,
  14543. Evertjan Garretsen, Bobby Drake, Blues (http://tech.bluesmoon.info/), Luke
  14544. Godfrey, Pul, uestla, Alan C, Ulrich, Rafal Kukawski, Yves Sucaet,
  14545. sowberry, Norman "zEh" Fuchs, hitwork, Zahlii, johnrembo, Nick Callen,
  14546. Steven Levithan (stevenlevithan.com), ejsanders, Scott Baker, Brian Tafoya
  14547. (http://www.premasolutions.com/), Philippe Jausions
  14548. (http://pear.php.net/user/jausions), Aidan Lister
  14549. (http://aidanlister.com/), Rob, e-mike, HKM, ChaosNo1, metjay, strcasecmp,
  14550. strcmp, Taras Bogach, jpfle, Alexander Ermolaev
  14551. (http://snippets.dzone.com/user/AlexanderErmolaev), DxGx, kilops, Orlando,
  14552. dptr1988, Le Torbi, James (http://www.james-bell.co.uk/), Pedro Tainha
  14553. (http://www.pedrotainha.com), James, Arnout Kazemier
  14554. (http://www.3rd-Eden.com), Chris McMacken, gabriel paderni, Yannoo,
  14555. FGFEmperor, baris ozdil, Tod Gentille, Greg Frazier, jakes, 3D-GRAF, Allan
  14556. Jensen (http://www.winternet.no), Howard Yeend, Benjamin Lupton, davook,
  14557. daniel airton wermann (http://wermann.com.br), Atli T¨®r, Maximusya, Ryan
  14558. W Tenney (http://ryan.10e.us), Alexander M Beedie, fearphage
  14559. (http://http/my.opera.com/fearphage/), Nathan Sepulveda, Victor, Matteo,
  14560. Billy, stensi, Cord, Manish, T.J. Leahy, Riddler
  14561. (http://www.frontierwebdev.com/), Rafa? Kukawski, FremyCompany, Matt
  14562. Bradley, Tim de Koning, Luis Salazar (http://www.freaky-media.com/), Diogo
  14563. Resende, Rival, Andrej Pavlovic, Garagoth, Le Torbi
  14564. (http://www.letorbi.de/), Dino, Josep Sanz (http://www.ws3.es/), rem,
  14565. Russell Walker (http://www.nbill.co.uk/), Jamie Beck
  14566. (http://www.terabit.ca/), setcookie, Michael, YUI Library:
  14567. http://developer.yahoo.com/yui/docs/YAHOO.util.DateLocale.html, Blues at
  14568. http://hacks.bluesmoon.info/strftime/strftime.js, Ben
  14569. (http://benblume.co.uk/), DtTvB
  14570. (http://dt.in.th/2008-09-16.string-length-in-bytes.html), Andreas, William,
  14571. meo, incidence, Cagri Ekin, Amirouche, Amir Habibi
  14572. (http://www.residence-mixte.com/), Luke Smith (http://lucassmith.name),
  14573. Kheang Hok Chin (http://www.distantia.ca/), Jay Klehr, Lorenzo Pisani,
  14574. Tony, Yen-Wei Liu, Greenseed, mk.keck, Leslie Hoare, dude, booeyOH, Ben
  14575. Bryan
  14576. Licensed under the MIT (MIT-LICENSE.txt) license.
  14577. Permission is hereby granted, free of charge, to any person obtaining a
  14578. copy of this software and associated documentation files (the
  14579. "Software"), to deal in the Software without restriction, including
  14580. without limitation the rights to use, copy, modify, merge, publish,
  14581. distribute, sublicense, and/or sell copies of the Software, and to
  14582. permit persons to whom the Software is furnished to do so, subject to
  14583. the following conditions:
  14584. The above copyright notice and this permission notice shall be included
  14585. in all copies or substantial portions of the Software.
  14586. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  14587. OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  14588. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  14589. IN NO EVENT SHALL KEVIN VAN ZONNEVELD BE LIABLE FOR ANY CLAIM, DAMAGES
  14590. OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  14591. ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  14592. OTHER DEALINGS IN THE SOFTWARE.
  14593. */
  14594. /*global define*/
  14595. define('ThirdParty/sprintf',[],function() {
  14596. function sprintf () {
  14597. // http://kevin.vanzonneveld.net
  14598. // + original by: Ash Searle (http://hexmen.com/blog/)
  14599. // + namespaced by: Michael White (http://getsprink.com)
  14600. // + tweaked by: Jack
  14601. // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  14602. // + input by: Paulo Freitas
  14603. // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  14604. // + input by: Brett Zamir (http://brett-zamir.me)
  14605. // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  14606. // + improved by: Dj
  14607. // + improved by: Allidylls
  14608. // * example 1: sprintf("%01.2f", 123.1);
  14609. // * returns 1: 123.10
  14610. // * example 2: sprintf("[%10s]", 'monkey');
  14611. // * returns 2: '[ monkey]'
  14612. // * example 3: sprintf("[%'#10s]", 'monkey');
  14613. // * returns 3: '[####monkey]'
  14614. // * example 4: sprintf("%d", 123456789012345);
  14615. // * returns 4: '123456789012345'
  14616. var regex = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuideEfFgG])/g;
  14617. var a = arguments,
  14618. i = 0,
  14619. format = a[i++];
  14620. // pad()
  14621. var pad = function (str, len, chr, leftJustify) {
  14622. if (!chr) {
  14623. chr = ' ';
  14624. }
  14625. var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr);
  14626. return leftJustify ? str + padding : padding + str;
  14627. };
  14628. // justify()
  14629. var justify = function (value, prefix, leftJustify, minWidth, zeroPad, customPadChar) {
  14630. var diff = minWidth - value.length;
  14631. if (diff > 0) {
  14632. if (leftJustify || !zeroPad) {
  14633. value = pad(value, minWidth, customPadChar, leftJustify);
  14634. } else {
  14635. value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
  14636. }
  14637. }
  14638. return value;
  14639. };
  14640. // formatBaseX()
  14641. var formatBaseX = function (value, base, prefix, leftJustify, minWidth, precision, zeroPad) {
  14642. // Note: casts negative numbers to positive ones
  14643. var number = value >>> 0;
  14644. prefix = prefix && number && {
  14645. '2': '0b',
  14646. '8': '0',
  14647. '16': '0x'
  14648. }[base] || '';
  14649. value = prefix + pad(number.toString(base), precision || 0, '0', false);
  14650. return justify(value, prefix, leftJustify, minWidth, zeroPad);
  14651. };
  14652. // formatString()
  14653. var formatString = function (value, leftJustify, minWidth, precision, zeroPad, customPadChar) {
  14654. if (precision != null) {
  14655. value = value.slice(0, precision);
  14656. }
  14657. return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar);
  14658. };
  14659. // doFormat()
  14660. var doFormat = function (substring, valueIndex, flags, minWidth, _, precision, type) {
  14661. var number;
  14662. var prefix;
  14663. var method;
  14664. var textTransform;
  14665. var value;
  14666. if (substring == '%%') {
  14667. return '%';
  14668. }
  14669. // parse flags
  14670. var leftJustify = false,
  14671. positivePrefix = '',
  14672. zeroPad = false,
  14673. prefixBaseX = false,
  14674. customPadChar = ' ';
  14675. var flagsl = flags.length;
  14676. for (var j = 0; flags && j < flagsl; j++) {
  14677. switch (flags.charAt(j)) {
  14678. case ' ':
  14679. positivePrefix = ' ';
  14680. break;
  14681. case '+':
  14682. positivePrefix = '+';
  14683. break;
  14684. case '-':
  14685. leftJustify = true;
  14686. break;
  14687. case "'":
  14688. customPadChar = flags.charAt(j + 1);
  14689. break;
  14690. case '0':
  14691. zeroPad = true;
  14692. break;
  14693. case '#':
  14694. prefixBaseX = true;
  14695. break;
  14696. }
  14697. }
  14698. // parameters may be null, undefined, empty-string or real valued
  14699. // we want to ignore null, undefined and empty-string values
  14700. if (!minWidth) {
  14701. minWidth = 0;
  14702. } else if (minWidth == '*') {
  14703. minWidth = +a[i++];
  14704. } else if (minWidth.charAt(0) == '*') {
  14705. minWidth = +a[minWidth.slice(1, -1)];
  14706. } else {
  14707. minWidth = +minWidth;
  14708. }
  14709. // Note: undocumented perl feature:
  14710. if (minWidth < 0) {
  14711. minWidth = -minWidth;
  14712. leftJustify = true;
  14713. }
  14714. if (!isFinite(minWidth)) {
  14715. throw new Error('sprintf: (minimum-)width must be finite');
  14716. }
  14717. if (!precision) {
  14718. precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : undefined;
  14719. } else if (precision == '*') {
  14720. precision = +a[i++];
  14721. } else if (precision.charAt(0) == '*') {
  14722. precision = +a[precision.slice(1, -1)];
  14723. } else {
  14724. precision = +precision;
  14725. }
  14726. // grab value using valueIndex if required?
  14727. value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];
  14728. switch (type) {
  14729. case 's':
  14730. return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar);
  14731. case 'c':
  14732. return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad);
  14733. case 'b':
  14734. return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
  14735. case 'o':
  14736. return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
  14737. case 'x':
  14738. return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
  14739. case 'X':
  14740. return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase();
  14741. case 'u':
  14742. return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
  14743. case 'i':
  14744. case 'd':
  14745. number = +value || 0;
  14746. number = Math.round(number - number % 1); // Plain Math.round doesn't just truncate
  14747. prefix = number < 0 ? '-' : positivePrefix;
  14748. value = prefix + pad(String(Math.abs(number)), precision, '0', false);
  14749. return justify(value, prefix, leftJustify, minWidth, zeroPad);
  14750. case 'e':
  14751. case 'E':
  14752. case 'f': // Should handle locales (as per setlocale)
  14753. case 'F':
  14754. case 'g':
  14755. case 'G':
  14756. number = +value;
  14757. prefix = number < 0 ? '-' : positivePrefix;
  14758. method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
  14759. textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
  14760. value = prefix + Math.abs(number)[method](precision);
  14761. return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform]();
  14762. default:
  14763. return substring;
  14764. }
  14765. };
  14766. return format.replace(regex, doFormat);
  14767. }
  14768. return sprintf;
  14769. });
  14770. /*global define*/
  14771. define('Core/GregorianDate',[],function() {
  14772. 'use strict';
  14773. /**
  14774. * Represents a Gregorian date in a more precise format than the JavaScript Date object.
  14775. * In addition to submillisecond precision, this object can also represent leap seconds.
  14776. * @alias GregorianDate
  14777. * @constructor
  14778. *
  14779. * @see JulianDate#toGregorianDate
  14780. */
  14781. function GregorianDate(year, month, day, hour, minute, second, millisecond, isLeapSecond) {
  14782. /**
  14783. * Gets or sets the year as a whole number.
  14784. * @type {Number}
  14785. */
  14786. this.year = year;
  14787. /**
  14788. * Gets or sets the month as a whole number with range [1, 12].
  14789. * @type {Number}
  14790. */
  14791. this.month = month;
  14792. /**
  14793. * Gets or sets the day of the month as a whole number starting at 1.
  14794. * @type {Number}
  14795. */
  14796. this.day = day;
  14797. /**
  14798. * Gets or sets the hour as a whole number with range [0, 23].
  14799. * @type {Number}
  14800. */
  14801. this.hour = hour;
  14802. /**
  14803. * Gets or sets the minute of the hour as a whole number with range [0, 59].
  14804. * @type {Number}
  14805. */
  14806. this.minute = minute;
  14807. /**
  14808. * Gets or sets the second of the minute as a whole number with range [0, 60], with 60 representing a leap second.
  14809. * @type {Number}
  14810. */
  14811. this.second = second;
  14812. /**
  14813. * Gets or sets the millisecond of the second as a floating point number with range [0.0, 1000.0).
  14814. * @type {Number}
  14815. */
  14816. this.millisecond = millisecond;
  14817. /**
  14818. * Gets or sets whether this time is during a leap second.
  14819. * @type {Boolean}
  14820. */
  14821. this.isLeapSecond = isLeapSecond;
  14822. }
  14823. return GregorianDate;
  14824. });
  14825. /*global define*/
  14826. define('Core/isLeapYear',[
  14827. './DeveloperError'
  14828. ], function(
  14829. DeveloperError) {
  14830. 'use strict';
  14831. /**
  14832. * Determines if a given date is a leap year.
  14833. *
  14834. * @exports isLeapYear
  14835. *
  14836. * @param {Number} year The year to be tested.
  14837. * @returns {Boolean} True if <code>year</code> is a leap year.
  14838. *
  14839. * @example
  14840. * var leapYear = Cesium.isLeapYear(2000); // true
  14841. */
  14842. function isLeapYear(year) {
  14843. if (year === null || isNaN(year)) {
  14844. throw new DeveloperError('year is required and must be a number.');
  14845. }
  14846. return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
  14847. }
  14848. return isLeapYear;
  14849. });
  14850. /*global define*/
  14851. define('Core/LeapSecond',[],function() {
  14852. 'use strict';
  14853. /**
  14854. * Describes a single leap second, which is constructed from a {@link JulianDate} and a
  14855. * numerical offset representing the number of seconds TAI is ahead of the UTC time standard.
  14856. * @alias LeapSecond
  14857. * @constructor
  14858. *
  14859. * @param {JulianDate} [date] A Julian date representing the time of the leap second.
  14860. * @param {Number} [offset] The cumulative number of seconds that TAI is ahead of UTC at the provided date.
  14861. */
  14862. function LeapSecond(date, offset) {
  14863. /**
  14864. * Gets or sets the date at which this leap second occurs.
  14865. * @type {JulianDate}
  14866. */
  14867. this.julianDate = date;
  14868. /**
  14869. * Gets or sets the cumulative number of seconds between the UTC and TAI time standards at the time
  14870. * of this leap second.
  14871. * @type {Number}
  14872. */
  14873. this.offset = offset;
  14874. }
  14875. return LeapSecond;
  14876. });
  14877. /*global define*/
  14878. define('Core/TimeConstants',[
  14879. './freezeObject'
  14880. ], function(
  14881. freezeObject) {
  14882. 'use strict';
  14883. /**
  14884. * Constants for time conversions like those done by {@link JulianDate}.
  14885. *
  14886. * @exports TimeConstants
  14887. *
  14888. * @see JulianDate
  14889. *
  14890. * @private
  14891. */
  14892. var TimeConstants = {
  14893. /**
  14894. * The number of seconds in one millisecond: <code>0.001</code>
  14895. * @type {Number}
  14896. * @constant
  14897. */
  14898. SECONDS_PER_MILLISECOND : 0.001,
  14899. /**
  14900. * The number of seconds in one minute: <code>60</code>.
  14901. * @type {Number}
  14902. * @constant
  14903. */
  14904. SECONDS_PER_MINUTE : 60.0,
  14905. /**
  14906. * The number of minutes in one hour: <code>60</code>.
  14907. * @type {Number}
  14908. * @constant
  14909. */
  14910. MINUTES_PER_HOUR : 60.0,
  14911. /**
  14912. * The number of hours in one day: <code>24</code>.
  14913. * @type {Number}
  14914. * @constant
  14915. */
  14916. HOURS_PER_DAY : 24.0,
  14917. /**
  14918. * The number of seconds in one hour: <code>3600</code>.
  14919. * @type {Number}
  14920. * @constant
  14921. */
  14922. SECONDS_PER_HOUR : 3600.0,
  14923. /**
  14924. * The number of minutes in one day: <code>1440</code>.
  14925. * @type {Number}
  14926. * @constant
  14927. */
  14928. MINUTES_PER_DAY : 1440.0,
  14929. /**
  14930. * The number of seconds in one day, ignoring leap seconds: <code>86400</code>.
  14931. * @type {Number}
  14932. * @constant
  14933. */
  14934. SECONDS_PER_DAY : 86400.0,
  14935. /**
  14936. * The number of days in one Julian century: <code>36525</code>.
  14937. * @type {Number}
  14938. * @constant
  14939. */
  14940. DAYS_PER_JULIAN_CENTURY : 36525.0,
  14941. /**
  14942. * One trillionth of a second.
  14943. * @type {Number}
  14944. * @constant
  14945. */
  14946. PICOSECOND : 0.000000001,
  14947. /**
  14948. * The number of days to subtract from a Julian date to determine the
  14949. * modified Julian date, which gives the number of days since midnight
  14950. * on November 17, 1858.
  14951. * @type {Number}
  14952. * @constant
  14953. */
  14954. MODIFIED_JULIAN_DATE_DIFFERENCE : 2400000.5
  14955. };
  14956. return freezeObject(TimeConstants);
  14957. });
  14958. /*global define*/
  14959. define('Core/TimeStandard',[
  14960. './freezeObject'
  14961. ], function(
  14962. freezeObject) {
  14963. 'use strict';
  14964. /**
  14965. * Provides the type of time standards which JulianDate can take as input.
  14966. *
  14967. * @exports TimeStandard
  14968. *
  14969. * @see JulianDate
  14970. */
  14971. var TimeStandard = {
  14972. /**
  14973. * Represents the coordinated Universal Time (UTC) time standard.
  14974. *
  14975. * UTC is related to TAI according to the relationship
  14976. * <code>UTC = TAI - deltaT</code> where <code>deltaT</code> is the number of leap
  14977. * seconds which have been introduced as of the time in TAI.
  14978. *
  14979. */
  14980. UTC : 0,
  14981. /**
  14982. * Represents the International Atomic Time (TAI) time standard.
  14983. * TAI is the principal time standard to which the other time standards are related.
  14984. */
  14985. TAI : 1
  14986. };
  14987. return freezeObject(TimeStandard);
  14988. });
  14989. /*global define*/
  14990. define('Core/JulianDate',[
  14991. '../ThirdParty/sprintf',
  14992. './binarySearch',
  14993. './defaultValue',
  14994. './defined',
  14995. './DeveloperError',
  14996. './GregorianDate',
  14997. './isLeapYear',
  14998. './LeapSecond',
  14999. './TimeConstants',
  15000. './TimeStandard'
  15001. ], function(
  15002. sprintf,
  15003. binarySearch,
  15004. defaultValue,
  15005. defined,
  15006. DeveloperError,
  15007. GregorianDate,
  15008. isLeapYear,
  15009. LeapSecond,
  15010. TimeConstants,
  15011. TimeStandard) {
  15012. 'use strict';
  15013. var gregorianDateScratch = new GregorianDate();
  15014. var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  15015. var daysInLeapFeburary = 29;
  15016. function compareLeapSecondDates(leapSecond, dateToFind) {
  15017. return JulianDate.compare(leapSecond.julianDate, dateToFind.julianDate);
  15018. }
  15019. // we don't really need a leap second instance, anything with a julianDate property will do
  15020. var binarySearchScratchLeapSecond = new LeapSecond();
  15021. function convertUtcToTai(julianDate) {
  15022. //Even though julianDate is in UTC, we'll treat it as TAI and
  15023. //search the leap second table for it.
  15024. binarySearchScratchLeapSecond.julianDate = julianDate;
  15025. var leapSeconds = JulianDate.leapSeconds;
  15026. var index = binarySearch(leapSeconds, binarySearchScratchLeapSecond, compareLeapSecondDates);
  15027. if (index < 0) {
  15028. index = ~index;
  15029. }
  15030. if (index >= leapSeconds.length) {
  15031. index = leapSeconds.length - 1;
  15032. }
  15033. var offset = leapSeconds[index].offset;
  15034. if (index > 0) {
  15035. //Now we have the index of the closest leap second that comes on or after our UTC time.
  15036. //However, if the difference between the UTC date being converted and the TAI
  15037. //defined leap second is greater than the offset, we are off by one and need to use
  15038. //the previous leap second.
  15039. var difference = JulianDate.secondsDifference(leapSeconds[index].julianDate, julianDate);
  15040. if (difference > offset) {
  15041. index--;
  15042. offset = leapSeconds[index].offset;
  15043. }
  15044. }
  15045. JulianDate.addSeconds(julianDate, offset, julianDate);
  15046. }
  15047. function convertTaiToUtc(julianDate, result) {
  15048. binarySearchScratchLeapSecond.julianDate = julianDate;
  15049. var leapSeconds = JulianDate.leapSeconds;
  15050. var index = binarySearch(leapSeconds, binarySearchScratchLeapSecond, compareLeapSecondDates);
  15051. if (index < 0) {
  15052. index = ~index;
  15053. }
  15054. //All times before our first leap second get the first offset.
  15055. if (index === 0) {
  15056. return JulianDate.addSeconds(julianDate, -leapSeconds[0].offset, result);
  15057. }
  15058. //All times after our leap second get the last offset.
  15059. if (index >= leapSeconds.length) {
  15060. return JulianDate.addSeconds(julianDate, -leapSeconds[index - 1].offset, result);
  15061. }
  15062. //Compute the difference between the found leap second and the time we are converting.
  15063. var difference = JulianDate.secondsDifference(leapSeconds[index].julianDate, julianDate);
  15064. if (difference === 0) {
  15065. //The date is in our leap second table.
  15066. return JulianDate.addSeconds(julianDate, -leapSeconds[index].offset, result);
  15067. }
  15068. if (difference <= 1.0) {
  15069. //The requested date is during the moment of a leap second, then we cannot convert to UTC
  15070. return undefined;
  15071. }
  15072. //The time is in between two leap seconds, index is the leap second after the date
  15073. //we're converting, so we subtract one to get the correct LeapSecond instance.
  15074. return JulianDate.addSeconds(julianDate, -leapSeconds[--index].offset, result);
  15075. }
  15076. function setComponents(wholeDays, secondsOfDay, julianDate) {
  15077. var extraDays = (secondsOfDay / TimeConstants.SECONDS_PER_DAY) | 0;
  15078. wholeDays += extraDays;
  15079. secondsOfDay -= TimeConstants.SECONDS_PER_DAY * extraDays;
  15080. if (secondsOfDay < 0) {
  15081. wholeDays--;
  15082. secondsOfDay += TimeConstants.SECONDS_PER_DAY;
  15083. }
  15084. julianDate.dayNumber = wholeDays;
  15085. julianDate.secondsOfDay = secondsOfDay;
  15086. return julianDate;
  15087. }
  15088. function computeJulianDateComponents(year, month, day, hour, minute, second, millisecond) {
  15089. // Algorithm from page 604 of the Explanatory Supplement to the
  15090. // Astronomical Almanac (Seidelmann 1992).
  15091. var a = ((month - 14) / 12) | 0;
  15092. var b = year + 4800 + a;
  15093. var dayNumber = (((1461 * b) / 4) | 0) + (((367 * (month - 2 - 12 * a)) / 12) | 0) - (((3 * (((b + 100) / 100) | 0)) / 4) | 0) + day - 32075;
  15094. // JulianDates are noon-based
  15095. hour = hour - 12;
  15096. if (hour < 0) {
  15097. hour += 24;
  15098. }
  15099. var secondsOfDay = second + ((hour * TimeConstants.SECONDS_PER_HOUR) + (minute * TimeConstants.SECONDS_PER_MINUTE) + (millisecond * TimeConstants.SECONDS_PER_MILLISECOND));
  15100. if (secondsOfDay >= 43200.0) {
  15101. dayNumber -= 1;
  15102. }
  15103. return [dayNumber, secondsOfDay];
  15104. }
  15105. //Regular expressions used for ISO8601 date parsing.
  15106. //YYYY
  15107. var matchCalendarYear = /^(\d{4})$/;
  15108. //YYYY-MM (YYYYMM is invalid)
  15109. var matchCalendarMonth = /^(\d{4})-(\d{2})$/;
  15110. //YYYY-DDD or YYYYDDD
  15111. var matchOrdinalDate = /^(\d{4})-?(\d{3})$/;
  15112. //YYYY-Www or YYYYWww or YYYY-Www-D or YYYYWwwD
  15113. var matchWeekDate = /^(\d{4})-?W(\d{2})-?(\d{1})?$/;
  15114. //YYYY-MM-DD or YYYYMMDD
  15115. var matchCalendarDate = /^(\d{4})-?(\d{2})-?(\d{2})$/;
  15116. // Match utc offset
  15117. var utcOffset = /([Z+\-])?(\d{2})?:?(\d{2})?$/;
  15118. // Match hours HH or HH.xxxxx
  15119. var matchHours = /^(\d{2})(\.\d+)?/.source + utcOffset.source;
  15120. // Match hours/minutes HH:MM HHMM.xxxxx
  15121. var matchHoursMinutes = /^(\d{2}):?(\d{2})(\.\d+)?/.source + utcOffset.source;
  15122. // Match hours/minutes HH:MM:SS HHMMSS.xxxxx
  15123. var matchHoursMinutesSeconds = /^(\d{2}):?(\d{2}):?(\d{2})(\.\d+)?/.source + utcOffset.source;
  15124. var iso8601ErrorMessage = 'Invalid ISO 8601 date.';
  15125. /**
  15126. * Represents an astronomical Julian date, which is the number of days since noon on January 1, -4712 (4713 BC).
  15127. * For increased precision, this class stores the whole number part of the date and the seconds
  15128. * part of the date in separate components. In order to be safe for arithmetic and represent
  15129. * leap seconds, the date is always stored in the International Atomic Time standard
  15130. * {@link TimeStandard.TAI}.
  15131. * @alias JulianDate
  15132. * @constructor
  15133. *
  15134. * @param {Number} [julianDayNumber=0.0] The Julian Day Number representing the number of whole days. Fractional days will also be handled correctly.
  15135. * @param {Number} [secondsOfDay=0.0] The number of seconds into the current Julian Day Number. Fractional seconds, negative seconds and seconds greater than a day will be handled correctly.
  15136. * @param {TimeStandard} [timeStandard=TimeStandard.UTC] The time standard in which the first two parameters are defined.
  15137. */
  15138. function JulianDate(julianDayNumber, secondsOfDay, timeStandard) {
  15139. /**
  15140. * Gets or sets the number of whole days.
  15141. * @type {Number}
  15142. */
  15143. this.dayNumber = undefined;
  15144. /**
  15145. * Gets or sets the number of seconds into the current day.
  15146. * @type {Number}
  15147. */
  15148. this.secondsOfDay = undefined;
  15149. julianDayNumber = defaultValue(julianDayNumber, 0.0);
  15150. secondsOfDay = defaultValue(secondsOfDay, 0.0);
  15151. timeStandard = defaultValue(timeStandard, TimeStandard.UTC);
  15152. //If julianDayNumber is fractional, make it an integer and add the number of seconds the fraction represented.
  15153. var wholeDays = julianDayNumber | 0;
  15154. secondsOfDay = secondsOfDay + (julianDayNumber - wholeDays) * TimeConstants.SECONDS_PER_DAY;
  15155. setComponents(wholeDays, secondsOfDay, this);
  15156. if (timeStandard === TimeStandard.UTC) {
  15157. convertUtcToTai(this);
  15158. }
  15159. }
  15160. /**
  15161. * Creates a new instance from a JavaScript Date.
  15162. *
  15163. * @param {Date} date A JavaScript Date.
  15164. * @param {JulianDate} [result] An existing instance to use for the result.
  15165. * @returns {JulianDate} The modified result parameter or a new instance if none was provided.
  15166. *
  15167. * @exception {DeveloperError} date must be a valid JavaScript Date.
  15168. */
  15169. JulianDate.fromDate = function(date, result) {
  15170. if (!(date instanceof Date) || isNaN(date.getTime())) {
  15171. throw new DeveloperError('date must be a valid JavaScript Date.');
  15172. }
  15173. var components = computeJulianDateComponents(date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds());
  15174. if (!defined(result)) {
  15175. return new JulianDate(components[0], components[1], TimeStandard.UTC);
  15176. }
  15177. setComponents(components[0], components[1], result);
  15178. convertUtcToTai(result);
  15179. return result;
  15180. };
  15181. /**
  15182. * Creates a new instance from a from an {@link http://en.wikipedia.org/wiki/ISO_8601|ISO 8601} date.
  15183. * This method is superior to <code>Date.parse</code> because it will handle all valid formats defined by the ISO 8601
  15184. * specification, including leap seconds and sub-millisecond times, which discarded by most JavaScript implementations.
  15185. *
  15186. * @param {String} iso8601String An ISO 8601 date.
  15187. * @param {JulianDate} [result] An existing instance to use for the result.
  15188. * @returns {JulianDate} The modified result parameter or a new instance if none was provided.
  15189. *
  15190. * @exception {DeveloperError} Invalid ISO 8601 date.
  15191. */
  15192. JulianDate.fromIso8601 = function(iso8601String, result) {
  15193. if (typeof iso8601String !== 'string') {
  15194. throw new DeveloperError(iso8601ErrorMessage);
  15195. }
  15196. //Comma and decimal point both indicate a fractional number according to ISO 8601,
  15197. //start out by blanket replacing , with . which is the only valid such symbol in JS.
  15198. iso8601String = iso8601String.replace(',', '.');
  15199. //Split the string into its date and time components, denoted by a mandatory T
  15200. var tokens = iso8601String.split('T');
  15201. var year;
  15202. var month = 1;
  15203. var day = 1;
  15204. var hour = 0;
  15205. var minute = 0;
  15206. var second = 0;
  15207. var millisecond = 0;
  15208. //Lacking a time is okay, but a missing date is illegal.
  15209. var date = tokens[0];
  15210. var time = tokens[1];
  15211. var tmp;
  15212. var inLeapYear;
  15213. if (!defined(date)) {
  15214. throw new DeveloperError(iso8601ErrorMessage);
  15215. }
  15216. var dashCount;
  15217. //First match the date against possible regular expressions.
  15218. tokens = date.match(matchCalendarDate);
  15219. if (tokens !== null) {
  15220. dashCount = date.split('-').length - 1;
  15221. if (dashCount > 0 && dashCount !== 2) {
  15222. throw new DeveloperError(iso8601ErrorMessage);
  15223. }
  15224. year = +tokens[1];
  15225. month = +tokens[2];
  15226. day = +tokens[3];
  15227. } else {
  15228. tokens = date.match(matchCalendarMonth);
  15229. if (tokens !== null) {
  15230. year = +tokens[1];
  15231. month = +tokens[2];
  15232. } else {
  15233. tokens = date.match(matchCalendarYear);
  15234. if (tokens !== null) {
  15235. year = +tokens[1];
  15236. } else {
  15237. //Not a year/month/day so it must be an ordinal date.
  15238. var dayOfYear;
  15239. tokens = date.match(matchOrdinalDate);
  15240. if (tokens !== null) {
  15241. year = +tokens[1];
  15242. dayOfYear = +tokens[2];
  15243. inLeapYear = isLeapYear(year);
  15244. //This validation is only applicable for this format.
  15245. if (dayOfYear < 1 || (inLeapYear && dayOfYear > 366) || (!inLeapYear && dayOfYear > 365)) {
  15246. throw new DeveloperError(iso8601ErrorMessage);
  15247. }
  15248. } else {
  15249. tokens = date.match(matchWeekDate);
  15250. if (tokens !== null) {
  15251. //ISO week date to ordinal date from
  15252. //http://en.wikipedia.org/w/index.php?title=ISO_week_date&oldid=474176775
  15253. year = +tokens[1];
  15254. var weekNumber = +tokens[2];
  15255. var dayOfWeek = +tokens[3] || 0;
  15256. dashCount = date.split('-').length - 1;
  15257. if (dashCount > 0 &&
  15258. ((!defined(tokens[3]) && dashCount !== 1) ||
  15259. (defined(tokens[3]) && dashCount !== 2))) {
  15260. throw new DeveloperError(iso8601ErrorMessage);
  15261. }
  15262. var january4 = new Date(Date.UTC(year, 0, 4));
  15263. dayOfYear = (weekNumber * 7) + dayOfWeek - january4.getUTCDay() - 3;
  15264. } else {
  15265. //None of our regular expressions succeeded in parsing the date properly.
  15266. throw new DeveloperError(iso8601ErrorMessage);
  15267. }
  15268. }
  15269. //Split an ordinal date into month/day.
  15270. tmp = new Date(Date.UTC(year, 0, 1));
  15271. tmp.setUTCDate(dayOfYear);
  15272. month = tmp.getUTCMonth() + 1;
  15273. day = tmp.getUTCDate();
  15274. }
  15275. }
  15276. }
  15277. //Now that we have all of the date components, validate them to make sure nothing is out of range.
  15278. inLeapYear = isLeapYear(year);
  15279. if (month < 1 || month > 12 || day < 1 || ((month !== 2 || !inLeapYear) && day > daysInMonth[month - 1]) || (inLeapYear && month === 2 && day > daysInLeapFeburary)) {
  15280. throw new DeveloperError(iso8601ErrorMessage);
  15281. }
  15282. //Not move onto the time string, which is much simpler.
  15283. var offsetIndex;
  15284. if (defined(time)) {
  15285. tokens = time.match(matchHoursMinutesSeconds);
  15286. if (tokens !== null) {
  15287. dashCount = time.split(':').length - 1;
  15288. if (dashCount > 0 && dashCount !== 2 && dashCount !== 3) {
  15289. throw new DeveloperError(iso8601ErrorMessage);
  15290. }
  15291. hour = +tokens[1];
  15292. minute = +tokens[2];
  15293. second = +tokens[3];
  15294. millisecond = +(tokens[4] || 0) * 1000.0;
  15295. offsetIndex = 5;
  15296. } else {
  15297. tokens = time.match(matchHoursMinutes);
  15298. if (tokens !== null) {
  15299. dashCount = time.split(':').length - 1;
  15300. if (dashCount > 2) {
  15301. throw new DeveloperError(iso8601ErrorMessage);
  15302. }
  15303. hour = +tokens[1];
  15304. minute = +tokens[2];
  15305. second = +(tokens[3] || 0) * 60.0;
  15306. offsetIndex = 4;
  15307. } else {
  15308. tokens = time.match(matchHours);
  15309. if (tokens !== null) {
  15310. hour = +tokens[1];
  15311. minute = +(tokens[2] || 0) * 60.0;
  15312. offsetIndex = 3;
  15313. } else {
  15314. throw new DeveloperError(iso8601ErrorMessage);
  15315. }
  15316. }
  15317. }
  15318. //Validate that all values are in proper range. Minutes and hours have special cases at 60 and 24.
  15319. if (minute >= 60 || second >= 61 || hour > 24 || (hour === 24 && (minute > 0 || second > 0 || millisecond > 0))) {
  15320. throw new DeveloperError(iso8601ErrorMessage);
  15321. }
  15322. //Check the UTC offset value, if no value exists, use local time
  15323. //a Z indicates UTC, + or - are offsets.
  15324. var offset = tokens[offsetIndex];
  15325. var offsetHours = +(tokens[offsetIndex + 1]);
  15326. var offsetMinutes = +(tokens[offsetIndex + 2] || 0);
  15327. switch (offset) {
  15328. case '+':
  15329. hour = hour - offsetHours;
  15330. minute = minute - offsetMinutes;
  15331. break;
  15332. case '-':
  15333. hour = hour + offsetHours;
  15334. minute = minute + offsetMinutes;
  15335. break;
  15336. case 'Z':
  15337. break;
  15338. default:
  15339. minute = minute + new Date(Date.UTC(year, month - 1, day, hour, minute)).getTimezoneOffset();
  15340. break;
  15341. }
  15342. } else {
  15343. //If no time is specified, it is considered the beginning of the day, local time.
  15344. minute = minute + new Date(year, month - 1, day).getTimezoneOffset();
  15345. }
  15346. //ISO8601 denotes a leap second by any time having a seconds component of 60 seconds.
  15347. //If that's the case, we need to temporarily subtract a second in order to build a UTC date.
  15348. //Then we add it back in after converting to TAI.
  15349. var isLeapSecond = second === 60;
  15350. if (isLeapSecond) {
  15351. second--;
  15352. }
  15353. //Even if we successfully parsed the string into its components, after applying UTC offset or
  15354. //special cases like 24:00:00 denoting midnight, we need to normalize the data appropriately.
  15355. //milliseconds can never be greater than 1000, and seconds can't be above 60, so we start with minutes
  15356. while (minute >= 60) {
  15357. minute -= 60;
  15358. hour++;
  15359. }
  15360. while (hour >= 24) {
  15361. hour -= 24;
  15362. day++;
  15363. }
  15364. tmp = (inLeapYear && month === 2) ? daysInLeapFeburary : daysInMonth[month - 1];
  15365. while (day > tmp) {
  15366. day -= tmp;
  15367. month++;
  15368. if (month > 12) {
  15369. month -= 12;
  15370. year++;
  15371. }
  15372. tmp = (inLeapYear && month === 2) ? daysInLeapFeburary : daysInMonth[month - 1];
  15373. }
  15374. //If UTC offset is at the beginning/end of the day, minutes can be negative.
  15375. while (minute < 0) {
  15376. minute += 60;
  15377. hour--;
  15378. }
  15379. while (hour < 0) {
  15380. hour += 24;
  15381. day--;
  15382. }
  15383. while (day < 1) {
  15384. month--;
  15385. if (month < 1) {
  15386. month += 12;
  15387. year--;
  15388. }
  15389. tmp = (inLeapYear && month === 2) ? daysInLeapFeburary : daysInMonth[month - 1];
  15390. day += tmp;
  15391. }
  15392. //Now create the JulianDate components from the Gregorian date and actually create our instance.
  15393. var components = computeJulianDateComponents(year, month, day, hour, minute, second, millisecond);
  15394. if (!defined(result)) {
  15395. result = new JulianDate(components[0], components[1], TimeStandard.UTC);
  15396. } else {
  15397. setComponents(components[0], components[1], result);
  15398. convertUtcToTai(result);
  15399. }
  15400. //If we were on a leap second, add it back.
  15401. if (isLeapSecond) {
  15402. JulianDate.addSeconds(result, 1, result);
  15403. }
  15404. return result;
  15405. };
  15406. /**
  15407. * Creates a new instance that represents the current system time.
  15408. * This is equivalent to calling <code>JulianDate.fromDate(new Date());</code>.
  15409. *
  15410. * @param {JulianDate} [result] An existing instance to use for the result.
  15411. * @returns {JulianDate} The modified result parameter or a new instance if none was provided.
  15412. */
  15413. JulianDate.now = function(result) {
  15414. return JulianDate.fromDate(new Date(), result);
  15415. };
  15416. var toGregorianDateScratch = new JulianDate(0, 0, TimeStandard.TAI);
  15417. /**
  15418. * Creates a {@link GregorianDate} from the provided instance.
  15419. *
  15420. * @param {JulianDate} julianDate The date to be converted.
  15421. * @param {GregorianDate} [result] An existing instance to use for the result.
  15422. * @returns {GregorianDate} The modified result parameter or a new instance if none was provided.
  15423. */
  15424. JulianDate.toGregorianDate = function(julianDate, result) {
  15425. if (!defined(julianDate)) {
  15426. throw new DeveloperError('julianDate is required.');
  15427. }
  15428. var isLeapSecond = false;
  15429. var thisUtc = convertTaiToUtc(julianDate, toGregorianDateScratch);
  15430. if (!defined(thisUtc)) {
  15431. //Conversion to UTC will fail if we are during a leap second.
  15432. //If that's the case, subtract a second and convert again.
  15433. //JavaScript doesn't support leap seconds, so this results in second 59 being repeated twice.
  15434. JulianDate.addSeconds(julianDate, -1, toGregorianDateScratch);
  15435. thisUtc = convertTaiToUtc(toGregorianDateScratch, toGregorianDateScratch);
  15436. isLeapSecond = true;
  15437. }
  15438. var julianDayNumber = thisUtc.dayNumber;
  15439. var secondsOfDay = thisUtc.secondsOfDay;
  15440. if (secondsOfDay >= 43200.0) {
  15441. julianDayNumber += 1;
  15442. }
  15443. // Algorithm from page 604 of the Explanatory Supplement to the
  15444. // Astronomical Almanac (Seidelmann 1992).
  15445. var L = (julianDayNumber + 68569) | 0;
  15446. var N = (4 * L / 146097) | 0;
  15447. L = (L - (((146097 * N + 3) / 4) | 0)) | 0;
  15448. var I = ((4000 * (L + 1)) / 1461001) | 0;
  15449. L = (L - (((1461 * I) / 4) | 0) + 31) | 0;
  15450. var J = ((80 * L) / 2447) | 0;
  15451. var day = (L - (((2447 * J) / 80) | 0)) | 0;
  15452. L = (J / 11) | 0;
  15453. var month = (J + 2 - 12 * L) | 0;
  15454. var year = (100 * (N - 49) + I + L) | 0;
  15455. var hour = (secondsOfDay / TimeConstants.SECONDS_PER_HOUR) | 0;
  15456. var remainingSeconds = secondsOfDay - (hour * TimeConstants.SECONDS_PER_HOUR);
  15457. var minute = (remainingSeconds / TimeConstants.SECONDS_PER_MINUTE) | 0;
  15458. remainingSeconds = remainingSeconds - (minute * TimeConstants.SECONDS_PER_MINUTE);
  15459. var second = remainingSeconds | 0;
  15460. var millisecond = ((remainingSeconds - second) / TimeConstants.SECONDS_PER_MILLISECOND);
  15461. // JulianDates are noon-based
  15462. hour += 12;
  15463. if (hour > 23) {
  15464. hour -= 24;
  15465. }
  15466. //If we were on a leap second, add it back.
  15467. if (isLeapSecond) {
  15468. second += 1;
  15469. }
  15470. if (!defined(result)) {
  15471. return new GregorianDate(year, month, day, hour, minute, second, millisecond, isLeapSecond);
  15472. }
  15473. result.year = year;
  15474. result.month = month;
  15475. result.day = day;
  15476. result.hour = hour;
  15477. result.minute = minute;
  15478. result.second = second;
  15479. result.millisecond = millisecond;
  15480. result.isLeapSecond = isLeapSecond;
  15481. return result;
  15482. };
  15483. /**
  15484. * Creates a JavaScript Date from the provided instance.
  15485. * Since JavaScript dates are only accurate to the nearest millisecond and
  15486. * cannot represent a leap second, consider using {@link JulianDate.toGregorianDate} instead.
  15487. * If the provided JulianDate is during a leap second, the previous second is used.
  15488. *
  15489. * @param {JulianDate} julianDate The date to be converted.
  15490. * @returns {Date} A new instance representing the provided date.
  15491. */
  15492. JulianDate.toDate = function(julianDate) {
  15493. if (!defined(julianDate)) {
  15494. throw new DeveloperError('julianDate is required.');
  15495. }
  15496. var gDate = JulianDate.toGregorianDate(julianDate, gregorianDateScratch);
  15497. var second = gDate.second;
  15498. if (gDate.isLeapSecond) {
  15499. second -= 1;
  15500. }
  15501. return new Date(Date.UTC(gDate.year, gDate.month - 1, gDate.day, gDate.hour, gDate.minute, second, gDate.millisecond));
  15502. };
  15503. /**
  15504. * Creates an ISO8601 representation of the provided date.
  15505. *
  15506. * @param {JulianDate} julianDate The date to be converted.
  15507. * @param {Number} [precision] The number of fractional digits used to represent the seconds component. By default, the most precise representation is used.
  15508. * @returns {String} The ISO8601 representation of the provided date.
  15509. */
  15510. JulianDate.toIso8601 = function(julianDate, precision) {
  15511. if (!defined(julianDate)) {
  15512. throw new DeveloperError('julianDate is required.');
  15513. }
  15514. var gDate = JulianDate.toGregorianDate(julianDate, gDate);
  15515. var millisecondStr;
  15516. if (!defined(precision) && gDate.millisecond !== 0) {
  15517. //Forces milliseconds into a number with at least 3 digits to whatever the default toString() precision is.
  15518. millisecondStr = (gDate.millisecond * 0.01).toString().replace('.', '');
  15519. return sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%sZ", gDate.year, gDate.month, gDate.day, gDate.hour, gDate.minute, gDate.second, millisecondStr);
  15520. }
  15521. //Precision is either 0 or milliseconds is 0 with undefined precision, in either case, leave off milliseconds entirely
  15522. if (!defined(precision) || precision === 0) {
  15523. return sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ", gDate.year, gDate.month, gDate.day, gDate.hour, gDate.minute, gDate.second);
  15524. }
  15525. //Forces milliseconds into a number with at least 3 digits to whatever the specified precision is.
  15526. millisecondStr = (gDate.millisecond * 0.01).toFixed(precision).replace('.', '').slice(0, precision);
  15527. return sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%sZ", gDate.year, gDate.month, gDate.day, gDate.hour, gDate.minute, gDate.second, millisecondStr);
  15528. };
  15529. /**
  15530. * Duplicates a JulianDate instance.
  15531. *
  15532. * @param {JulianDate} julianDate The date to duplicate.
  15533. * @param {JulianDate} [result] An existing instance to use for the result.
  15534. * @returns {JulianDate} The modified result parameter or a new instance if none was provided. Returns undefined if julianDate is undefined.
  15535. */
  15536. JulianDate.clone = function(julianDate, result) {
  15537. if (!defined(julianDate)) {
  15538. return undefined;
  15539. }
  15540. if (!defined(result)) {
  15541. return new JulianDate(julianDate.dayNumber, julianDate.secondsOfDay, TimeStandard.TAI);
  15542. }
  15543. result.dayNumber = julianDate.dayNumber;
  15544. result.secondsOfDay = julianDate.secondsOfDay;
  15545. return result;
  15546. };
  15547. /**
  15548. * Compares two instances.
  15549. *
  15550. * @param {JulianDate} left The first instance.
  15551. * @param {JulianDate} right The second instance.
  15552. * @returns {Number} A negative value if left is less than right, a positive value if left is greater than right, or zero if left and right are equal.
  15553. */
  15554. JulianDate.compare = function(left, right) {
  15555. if (!defined(left)) {
  15556. throw new DeveloperError('left is required.');
  15557. }
  15558. if (!defined(right)) {
  15559. throw new DeveloperError('right is required.');
  15560. }
  15561. var julianDayNumberDifference = left.dayNumber - right.dayNumber;
  15562. if (julianDayNumberDifference !== 0) {
  15563. return julianDayNumberDifference;
  15564. }
  15565. return left.secondsOfDay - right.secondsOfDay;
  15566. };
  15567. /**
  15568. * Compares two instances and returns <code>true</code> if they are equal, <code>false</code> otherwise.
  15569. *
  15570. * @param {JulianDate} [left] The first instance.
  15571. * @param {JulianDate} [right] The second instance.
  15572. * @returns {Boolean} <code>true</code> if the dates are equal; otherwise, <code>false</code>.
  15573. */
  15574. JulianDate.equals = function(left, right) {
  15575. return (left === right) ||
  15576. (defined(left) &&
  15577. defined(right) &&
  15578. left.dayNumber === right.dayNumber &&
  15579. left.secondsOfDay === right.secondsOfDay);
  15580. };
  15581. /**
  15582. * Compares two instances and returns <code>true</code> if they are within <code>epsilon</code> seconds of
  15583. * each other. That is, in order for the dates to be considered equal (and for
  15584. * this function to return <code>true</code>), the absolute value of the difference between them, in
  15585. * seconds, must be less than <code>epsilon</code>.
  15586. *
  15587. * @param {JulianDate} [left] The first instance.
  15588. * @param {JulianDate} [right] The second instance.
  15589. * @param {Number} epsilon The maximum number of seconds that should separate the two instances.
  15590. * @returns {Boolean} <code>true</code> if the two dates are within <code>epsilon</code> seconds of each other; otherwise <code>false</code>.
  15591. */
  15592. JulianDate.equalsEpsilon = function(left, right, epsilon) {
  15593. if (!defined(epsilon)) {
  15594. throw new DeveloperError('epsilon is required.');
  15595. }
  15596. return (left === right) ||
  15597. (defined(left) &&
  15598. defined(right) &&
  15599. Math.abs(JulianDate.secondsDifference(left, right)) <= epsilon);
  15600. };
  15601. /**
  15602. * Computes the total number of whole and fractional days represented by the provided instance.
  15603. *
  15604. * @param {JulianDate} julianDate The date.
  15605. * @returns {Number} The Julian date as single floating point number.
  15606. */
  15607. JulianDate.totalDays = function(julianDate) {
  15608. if (!defined(julianDate)) {
  15609. throw new DeveloperError('julianDate is required.');
  15610. }
  15611. return julianDate.dayNumber + (julianDate.secondsOfDay / TimeConstants.SECONDS_PER_DAY);
  15612. };
  15613. /**
  15614. * Computes the difference in seconds between the provided instance.
  15615. *
  15616. * @param {JulianDate} left The first instance.
  15617. * @param {JulianDate} right The second instance.
  15618. * @returns {Number} The difference, in seconds, when subtracting <code>right</code> from <code>left</code>.
  15619. */
  15620. JulianDate.secondsDifference = function(left, right) {
  15621. if (!defined(left)) {
  15622. throw new DeveloperError('left is required.');
  15623. }
  15624. if (!defined(right)) {
  15625. throw new DeveloperError('right is required.');
  15626. }
  15627. var dayDifference = (left.dayNumber - right.dayNumber) * TimeConstants.SECONDS_PER_DAY;
  15628. return (dayDifference + (left.secondsOfDay - right.secondsOfDay));
  15629. };
  15630. /**
  15631. * Computes the difference in days between the provided instance.
  15632. *
  15633. * @param {JulianDate} left The first instance.
  15634. * @param {JulianDate} right The second instance.
  15635. * @returns {Number} The difference, in days, when subtracting <code>right</code> from <code>left</code>.
  15636. */
  15637. JulianDate.daysDifference = function(left, right) {
  15638. if (!defined(left)) {
  15639. throw new DeveloperError('left is required.');
  15640. }
  15641. if (!defined(right)) {
  15642. throw new DeveloperError('right is required.');
  15643. }
  15644. var dayDifference = (left.dayNumber - right.dayNumber);
  15645. var secondDifference = (left.secondsOfDay - right.secondsOfDay) / TimeConstants.SECONDS_PER_DAY;
  15646. return dayDifference + secondDifference;
  15647. };
  15648. /**
  15649. * Computes the number of seconds the provided instance is ahead of UTC.
  15650. *
  15651. * @param {JulianDate} julianDate The date.
  15652. * @returns {Number} The number of seconds the provided instance is ahead of UTC
  15653. */
  15654. JulianDate.computeTaiMinusUtc = function(julianDate) {
  15655. binarySearchScratchLeapSecond.julianDate = julianDate;
  15656. var leapSeconds = JulianDate.leapSeconds;
  15657. var index = binarySearch(leapSeconds, binarySearchScratchLeapSecond, compareLeapSecondDates);
  15658. if (index < 0) {
  15659. index = ~index;
  15660. --index;
  15661. if (index < 0) {
  15662. index = 0;
  15663. }
  15664. }
  15665. return leapSeconds[index].offset;
  15666. };
  15667. /**
  15668. * Adds the provided number of seconds to the provided date instance.
  15669. *
  15670. * @param {JulianDate} julianDate The date.
  15671. * @param {Number} seconds The number of seconds to add or subtract.
  15672. * @param {JulianDate} result An existing instance to use for the result.
  15673. * @returns {JulianDate} The modified result parameter.
  15674. */
  15675. JulianDate.addSeconds = function(julianDate, seconds, result) {
  15676. if (!defined(julianDate)) {
  15677. throw new DeveloperError('julianDate is required.');
  15678. }
  15679. if (!defined(seconds)) {
  15680. throw new DeveloperError('seconds is required.');
  15681. }
  15682. if (!defined(result)) {
  15683. throw new DeveloperError('result is required.');
  15684. }
  15685. return setComponents(julianDate.dayNumber, julianDate.secondsOfDay + seconds, result);
  15686. };
  15687. /**
  15688. * Adds the provided number of minutes to the provided date instance.
  15689. *
  15690. * @param {JulianDate} julianDate The date.
  15691. * @param {Number} minutes The number of minutes to add or subtract.
  15692. * @param {JulianDate} result An existing instance to use for the result.
  15693. * @returns {JulianDate} The modified result parameter.
  15694. */
  15695. JulianDate.addMinutes = function(julianDate, minutes, result) {
  15696. if (!defined(julianDate)) {
  15697. throw new DeveloperError('julianDate is required.');
  15698. }
  15699. if (!defined(minutes)) {
  15700. throw new DeveloperError('minutes is required.');
  15701. }
  15702. if (!defined(result)) {
  15703. throw new DeveloperError('result is required.');
  15704. }
  15705. var newSecondsOfDay = julianDate.secondsOfDay + (minutes * TimeConstants.SECONDS_PER_MINUTE);
  15706. return setComponents(julianDate.dayNumber, newSecondsOfDay, result);
  15707. };
  15708. /**
  15709. * Adds the provided number of hours to the provided date instance.
  15710. *
  15711. * @param {JulianDate} julianDate The date.
  15712. * @param {Number} hours The number of hours to add or subtract.
  15713. * @param {JulianDate} result An existing instance to use for the result.
  15714. * @returns {JulianDate} The modified result parameter.
  15715. */
  15716. JulianDate.addHours = function(julianDate, hours, result) {
  15717. if (!defined(julianDate)) {
  15718. throw new DeveloperError('julianDate is required.');
  15719. }
  15720. if (!defined(hours)) {
  15721. throw new DeveloperError('hours is required.');
  15722. }
  15723. if (!defined(result)) {
  15724. throw new DeveloperError('result is required.');
  15725. }
  15726. var newSecondsOfDay = julianDate.secondsOfDay + (hours * TimeConstants.SECONDS_PER_HOUR);
  15727. return setComponents(julianDate.dayNumber, newSecondsOfDay, result);
  15728. };
  15729. /**
  15730. * Adds the provided number of days to the provided date instance.
  15731. *
  15732. * @param {JulianDate} julianDate The date.
  15733. * @param {Number} days The number of days to add or subtract.
  15734. * @param {JulianDate} result An existing instance to use for the result.
  15735. * @returns {JulianDate} The modified result parameter.
  15736. */
  15737. JulianDate.addDays = function(julianDate, days, result) {
  15738. if (!defined(julianDate)) {
  15739. throw new DeveloperError('julianDate is required.');
  15740. }
  15741. if (!defined(days)) {
  15742. throw new DeveloperError('days is required.');
  15743. }
  15744. if (!defined(result)) {
  15745. throw new DeveloperError('result is required.');
  15746. }
  15747. var newJulianDayNumber = julianDate.dayNumber + days;
  15748. return setComponents(newJulianDayNumber, julianDate.secondsOfDay, result);
  15749. };
  15750. /**
  15751. * Compares the provided instances and returns <code>true</code> if <code>left</code> is earlier than <code>right</code>, <code>false</code> otherwise.
  15752. *
  15753. * @param {JulianDate} left The first instance.
  15754. * @param {JulianDate} right The second instance.
  15755. * @returns {Boolean} <code>true</code> if <code>left</code> is earlier than <code>right</code>, <code>false</code> otherwise.
  15756. */
  15757. JulianDate.lessThan = function(left, right) {
  15758. return JulianDate.compare(left, right) < 0;
  15759. };
  15760. /**
  15761. * Compares the provided instances and returns <code>true</code> if <code>left</code> is earlier than or equal to <code>right</code>, <code>false</code> otherwise.
  15762. *
  15763. * @param {JulianDate} left The first instance.
  15764. * @param {JulianDate} right The second instance.
  15765. * @returns {Boolean} <code>true</code> if <code>left</code> is earlier than or equal to <code>right</code>, <code>false</code> otherwise.
  15766. */
  15767. JulianDate.lessThanOrEquals = function(left, right) {
  15768. return JulianDate.compare(left, right) <= 0;
  15769. };
  15770. /**
  15771. * Compares the provided instances and returns <code>true</code> if <code>left</code> is later than <code>right</code>, <code>false</code> otherwise.
  15772. *
  15773. * @param {JulianDate} left The first instance.
  15774. * @param {JulianDate} right The second instance.
  15775. * @returns {Boolean} <code>true</code> if <code>left</code> is later than <code>right</code>, <code>false</code> otherwise.
  15776. */
  15777. JulianDate.greaterThan = function(left, right) {
  15778. return JulianDate.compare(left, right) > 0;
  15779. };
  15780. /**
  15781. * Compares the provided instances and returns <code>true</code> if <code>left</code> is later than or equal to <code>right</code>, <code>false</code> otherwise.
  15782. *
  15783. * @param {JulianDate} left The first instance.
  15784. * @param {JulianDate} right The second instance.
  15785. * @returns {Boolean} <code>true</code> if <code>left</code> is later than or equal to <code>right</code>, <code>false</code> otherwise.
  15786. */
  15787. JulianDate.greaterThanOrEquals = function(left, right) {
  15788. return JulianDate.compare(left, right) >= 0;
  15789. };
  15790. /**
  15791. * Duplicates this instance.
  15792. *
  15793. * @param {JulianDate} [result] An existing instance to use for the result.
  15794. * @returns {JulianDate} The modified result parameter or a new instance if none was provided.
  15795. */
  15796. JulianDate.prototype.clone = function(result) {
  15797. return JulianDate.clone(this, result);
  15798. };
  15799. /**
  15800. * Compares this and the provided instance and returns <code>true</code> if they are equal, <code>false</code> otherwise.
  15801. *
  15802. * @param {JulianDate} [right] The second instance.
  15803. * @returns {Boolean} <code>true</code> if the dates are equal; otherwise, <code>false</code>.
  15804. */
  15805. JulianDate.prototype.equals = function(right) {
  15806. return JulianDate.equals(this, right);
  15807. };
  15808. /**
  15809. * Compares this and the provided instance and returns <code>true</code> if they are within <code>epsilon</code> seconds of
  15810. * each other. That is, in order for the dates to be considered equal (and for
  15811. * this function to return <code>true</code>), the absolute value of the difference between them, in
  15812. * seconds, must be less than <code>epsilon</code>.
  15813. *
  15814. * @param {JulianDate} [right] The second instance.
  15815. * @param {Number} epsilon The maximum number of seconds that should separate the two instances.
  15816. * @returns {Boolean} <code>true</code> if the two dates are within <code>epsilon</code> seconds of each other; otherwise <code>false</code>.
  15817. */
  15818. JulianDate.prototype.equalsEpsilon = function(right, epsilon) {
  15819. return JulianDate.equalsEpsilon(this, right, epsilon);
  15820. };
  15821. /**
  15822. * Creates a string representing this date in ISO8601 format.
  15823. *
  15824. * @returns {String} A string representing this date in ISO8601 format.
  15825. */
  15826. JulianDate.prototype.toString = function() {
  15827. return JulianDate.toIso8601(this);
  15828. };
  15829. /**
  15830. * Gets or sets the list of leap seconds used throughout Cesium.
  15831. * @memberof JulianDate
  15832. * @type {LeapSecond[]}
  15833. */
  15834. JulianDate.leapSeconds = [
  15835. new LeapSecond(new JulianDate(2441317, 43210.0, TimeStandard.TAI), 10), // January 1, 1972 00:00:00 UTC
  15836. new LeapSecond(new JulianDate(2441499, 43211.0, TimeStandard.TAI), 11), // July 1, 1972 00:00:00 UTC
  15837. new LeapSecond(new JulianDate(2441683, 43212.0, TimeStandard.TAI), 12), // January 1, 1973 00:00:00 UTC
  15838. new LeapSecond(new JulianDate(2442048, 43213.0, TimeStandard.TAI), 13), // January 1, 1974 00:00:00 UTC
  15839. new LeapSecond(new JulianDate(2442413, 43214.0, TimeStandard.TAI), 14), // January 1, 1975 00:00:00 UTC
  15840. new LeapSecond(new JulianDate(2442778, 43215.0, TimeStandard.TAI), 15), // January 1, 1976 00:00:00 UTC
  15841. new LeapSecond(new JulianDate(2443144, 43216.0, TimeStandard.TAI), 16), // January 1, 1977 00:00:00 UTC
  15842. new LeapSecond(new JulianDate(2443509, 43217.0, TimeStandard.TAI), 17), // January 1, 1978 00:00:00 UTC
  15843. new LeapSecond(new JulianDate(2443874, 43218.0, TimeStandard.TAI), 18), // January 1, 1979 00:00:00 UTC
  15844. new LeapSecond(new JulianDate(2444239, 43219.0, TimeStandard.TAI), 19), // January 1, 1980 00:00:00 UTC
  15845. new LeapSecond(new JulianDate(2444786, 43220.0, TimeStandard.TAI), 20), // July 1, 1981 00:00:00 UTC
  15846. new LeapSecond(new JulianDate(2445151, 43221.0, TimeStandard.TAI), 21), // July 1, 1982 00:00:00 UTC
  15847. new LeapSecond(new JulianDate(2445516, 43222.0, TimeStandard.TAI), 22), // July 1, 1983 00:00:00 UTC
  15848. new LeapSecond(new JulianDate(2446247, 43223.0, TimeStandard.TAI), 23), // July 1, 1985 00:00:00 UTC
  15849. new LeapSecond(new JulianDate(2447161, 43224.0, TimeStandard.TAI), 24), // January 1, 1988 00:00:00 UTC
  15850. new LeapSecond(new JulianDate(2447892, 43225.0, TimeStandard.TAI), 25), // January 1, 1990 00:00:00 UTC
  15851. new LeapSecond(new JulianDate(2448257, 43226.0, TimeStandard.TAI), 26), // January 1, 1991 00:00:00 UTC
  15852. new LeapSecond(new JulianDate(2448804, 43227.0, TimeStandard.TAI), 27), // July 1, 1992 00:00:00 UTC
  15853. new LeapSecond(new JulianDate(2449169, 43228.0, TimeStandard.TAI), 28), // July 1, 1993 00:00:00 UTC
  15854. new LeapSecond(new JulianDate(2449534, 43229.0, TimeStandard.TAI), 29), // July 1, 1994 00:00:00 UTC
  15855. new LeapSecond(new JulianDate(2450083, 43230.0, TimeStandard.TAI), 30), // January 1, 1996 00:00:00 UTC
  15856. new LeapSecond(new JulianDate(2450630, 43231.0, TimeStandard.TAI), 31), // July 1, 1997 00:00:00 UTC
  15857. new LeapSecond(new JulianDate(2451179, 43232.0, TimeStandard.TAI), 32), // January 1, 1999 00:00:00 UTC
  15858. new LeapSecond(new JulianDate(2453736, 43233.0, TimeStandard.TAI), 33), // January 1, 2006 00:00:00 UTC
  15859. new LeapSecond(new JulianDate(2454832, 43234.0, TimeStandard.TAI), 34), // January 1, 2009 00:00:00 UTC
  15860. new LeapSecond(new JulianDate(2456109, 43235.0, TimeStandard.TAI), 35), // July 1, 2012 00:00:00 UTC
  15861. new LeapSecond(new JulianDate(2457204, 43236.0, TimeStandard.TAI), 36), // July 1, 2015 00:00:00 UTC
  15862. new LeapSecond(new JulianDate(2457754, 43237.0, TimeStandard.TAI), 37) // January 1, 2017 00:00:00 UTC
  15863. ];
  15864. return JulianDate;
  15865. });
  15866. /*global define*/
  15867. define('Core/clone',[
  15868. './defaultValue'
  15869. ], function(
  15870. defaultValue) {
  15871. 'use strict';
  15872. /**
  15873. * Clones an object, returning a new object containing the same properties.
  15874. *
  15875. * @exports clone
  15876. *
  15877. * @param {Object} object The object to clone.
  15878. * @param {Boolean} [deep=false] If true, all properties will be deep cloned recursively.
  15879. * @returns {Object} The cloned object.
  15880. */
  15881. function clone(object, deep) {
  15882. if (object === null || typeof object !== 'object') {
  15883. return object;
  15884. }
  15885. deep = defaultValue(deep, false);
  15886. var result = new object.constructor();
  15887. for ( var propertyName in object) {
  15888. if (object.hasOwnProperty(propertyName)) {
  15889. var value = object[propertyName];
  15890. if (deep) {
  15891. value = clone(value, deep);
  15892. }
  15893. result[propertyName] = value;
  15894. }
  15895. }
  15896. return result;
  15897. }
  15898. return clone;
  15899. });
  15900. /*global define*/
  15901. define('Core/parseResponseHeaders',[], function() {
  15902. 'use strict';
  15903. /**
  15904. * Parses the result of XMLHttpRequest's getAllResponseHeaders() method into
  15905. * a dictionary.
  15906. *
  15907. * @exports parseResponseHeaders
  15908. *
  15909. * @param {String} headerString The header string returned by getAllResponseHeaders(). The format is
  15910. * described here: http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders()-method
  15911. * @returns {Object} A dictionary of key/value pairs, where each key is the name of a header and the corresponding value
  15912. * is that header's value.
  15913. *
  15914. * @private
  15915. */
  15916. function parseResponseHeaders(headerString) {
  15917. var headers = {};
  15918. if (!headerString) {
  15919. return headers;
  15920. }
  15921. var headerPairs = headerString.split('\u000d\u000a');
  15922. for (var i = 0; i < headerPairs.length; ++i) {
  15923. var headerPair = headerPairs[i];
  15924. // Can't use split() here because it does the wrong thing
  15925. // if the header value has the string ": " in it.
  15926. var index = headerPair.indexOf('\u003a\u0020');
  15927. if (index > 0) {
  15928. var key = headerPair.substring(0, index);
  15929. var val = headerPair.substring(index + 2);
  15930. headers[key] = val;
  15931. }
  15932. }
  15933. return headers;
  15934. }
  15935. return parseResponseHeaders;
  15936. });
  15937. /*global define*/
  15938. define('Core/RequestErrorEvent',[
  15939. './defined',
  15940. './parseResponseHeaders'
  15941. ], function(
  15942. defined,
  15943. parseResponseHeaders) {
  15944. 'use strict';
  15945. /**
  15946. * An event that is raised when a request encounters an error.
  15947. *
  15948. * @constructor
  15949. * @alias RequestErrorEvent
  15950. *
  15951. * @param {Number} [statusCode] The HTTP error status code, such as 404.
  15952. * @param {Object} [response] The response included along with the error.
  15953. * @param {String|Object} [responseHeaders] The response headers, represented either as an object literal or as a
  15954. * string in the format returned by XMLHttpRequest's getAllResponseHeaders() function.
  15955. */
  15956. function RequestErrorEvent(statusCode, response, responseHeaders) {
  15957. /**
  15958. * The HTTP error status code, such as 404. If the error does not have a particular
  15959. * HTTP code, this property will be undefined.
  15960. *
  15961. * @type {Number}
  15962. */
  15963. this.statusCode = statusCode;
  15964. /**
  15965. * The response included along with the error. If the error does not include a response,
  15966. * this property will be undefined.
  15967. *
  15968. * @type {Object}
  15969. */
  15970. this.response = response;
  15971. /**
  15972. * The headers included in the response, represented as an object literal of key/value pairs.
  15973. * If the error does not include any headers, this property will be undefined.
  15974. *
  15975. * @type {Object}
  15976. */
  15977. this.responseHeaders = responseHeaders;
  15978. if (typeof this.responseHeaders === 'string') {
  15979. this.responseHeaders = parseResponseHeaders(this.responseHeaders);
  15980. }
  15981. }
  15982. /**
  15983. * Creates a string representing this RequestErrorEvent.
  15984. * @memberof RequestErrorEvent
  15985. *
  15986. * @returns {String} A string representing the provided RequestErrorEvent.
  15987. */
  15988. RequestErrorEvent.prototype.toString = function() {
  15989. var str = 'Request has failed.';
  15990. if (defined(this.statusCode)) {
  15991. str += ' Status Code: ' + this.statusCode;
  15992. }
  15993. return str;
  15994. };
  15995. return RequestErrorEvent;
  15996. });
  15997. /**
  15998. * @license
  15999. *
  16000. * Grauw URI utilities
  16001. *
  16002. * See: http://hg.grauw.nl/grauw-lib/file/tip/src/uri.js
  16003. *
  16004. * @author Laurens Holst (http://www.grauw.nl/)
  16005. *
  16006. * Copyright 2012 Laurens Holst
  16007. *
  16008. * Licensed under the Apache License, Version 2.0 (the "License");
  16009. * you may not use this file except in compliance with the License.
  16010. * You may obtain a copy of the License at
  16011. *
  16012. * http://www.apache.org/licenses/LICENSE-2.0
  16013. *
  16014. * Unless required by applicable law or agreed to in writing, software
  16015. * distributed under the License is distributed on an "AS IS" BASIS,
  16016. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16017. * See the License for the specific language governing permissions and
  16018. * limitations under the License.
  16019. *
  16020. */
  16021. /*global define*/
  16022. define('ThirdParty/Uri',[],function() {
  16023. /**
  16024. * Constructs a URI object.
  16025. * @constructor
  16026. * @class Implementation of URI parsing and base URI resolving algorithm in RFC 3986.
  16027. * @param {string|URI} uri A string or URI object to create the object from.
  16028. */
  16029. function URI(uri) {
  16030. if (uri instanceof URI) { // copy constructor
  16031. this.scheme = uri.scheme;
  16032. this.authority = uri.authority;
  16033. this.path = uri.path;
  16034. this.query = uri.query;
  16035. this.fragment = uri.fragment;
  16036. } else if (uri) { // uri is URI string or cast to string
  16037. var c = parseRegex.exec(uri);
  16038. this.scheme = c[1];
  16039. this.authority = c[2];
  16040. this.path = c[3];
  16041. this.query = c[4];
  16042. this.fragment = c[5];
  16043. }
  16044. }
  16045. // Initial values on the prototype
  16046. URI.prototype.scheme = null;
  16047. URI.prototype.authority = null;
  16048. URI.prototype.path = '';
  16049. URI.prototype.query = null;
  16050. URI.prototype.fragment = null;
  16051. // Regular expression from RFC 3986 appendix B
  16052. var parseRegex = new RegExp('^(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\\?([^#]*))?(?:#(.*))?$');
  16053. /**
  16054. * Returns the scheme part of the URI.
  16055. * In "http://example.com:80/a/b?x#y" this is "http".
  16056. */
  16057. URI.prototype.getScheme = function() {
  16058. return this.scheme;
  16059. };
  16060. /**
  16061. * Returns the authority part of the URI.
  16062. * In "http://example.com:80/a/b?x#y" this is "example.com:80".
  16063. */
  16064. URI.prototype.getAuthority = function() {
  16065. return this.authority;
  16066. };
  16067. /**
  16068. * Returns the path part of the URI.
  16069. * In "http://example.com:80/a/b?x#y" this is "/a/b".
  16070. * In "mailto:mike@example.com" this is "mike@example.com".
  16071. */
  16072. URI.prototype.getPath = function() {
  16073. return this.path;
  16074. };
  16075. /**
  16076. * Returns the query part of the URI.
  16077. * In "http://example.com:80/a/b?x#y" this is "x".
  16078. */
  16079. URI.prototype.getQuery = function() {
  16080. return this.query;
  16081. };
  16082. /**
  16083. * Returns the fragment part of the URI.
  16084. * In "http://example.com:80/a/b?x#y" this is "y".
  16085. */
  16086. URI.prototype.getFragment = function() {
  16087. return this.fragment;
  16088. };
  16089. /**
  16090. * Tests whether the URI is an absolute URI.
  16091. * See RFC 3986 section 4.3.
  16092. */
  16093. URI.prototype.isAbsolute = function() {
  16094. return !!this.scheme && !this.fragment;
  16095. };
  16096. ///**
  16097. //* Extensive validation of the URI against the ABNF in RFC 3986
  16098. //*/
  16099. //URI.prototype.validate
  16100. /**
  16101. * Tests whether the URI is a same-document reference.
  16102. * See RFC 3986 section 4.4.
  16103. *
  16104. * To perform more thorough comparison, you can normalise the URI objects.
  16105. */
  16106. URI.prototype.isSameDocumentAs = function(uri) {
  16107. return uri.scheme == this.scheme &&
  16108. uri.authority == this.authority &&
  16109. uri.path == this.path &&
  16110. uri.query == this.query;
  16111. };
  16112. /**
  16113. * Simple String Comparison of two URIs.
  16114. * See RFC 3986 section 6.2.1.
  16115. *
  16116. * To perform more thorough comparison, you can normalise the URI objects.
  16117. */
  16118. URI.prototype.equals = function(uri) {
  16119. return this.isSameDocumentAs(uri) && uri.fragment == this.fragment;
  16120. };
  16121. /**
  16122. * Normalizes the URI using syntax-based normalization.
  16123. * This includes case normalization, percent-encoding normalization and path segment normalization.
  16124. * XXX: Percent-encoding normalization does not escape characters that need to be escaped.
  16125. * (Although that would not be a valid URI in the first place. See validate().)
  16126. * See RFC 3986 section 6.2.2.
  16127. */
  16128. URI.prototype.normalize = function() {
  16129. this.removeDotSegments();
  16130. if (this.scheme)
  16131. this.scheme = this.scheme.toLowerCase();
  16132. if (this.authority)
  16133. this.authority = this.authority.replace(authorityRegex, replaceAuthority).
  16134. replace(caseRegex, replaceCase);
  16135. if (this.path)
  16136. this.path = this.path.replace(caseRegex, replaceCase);
  16137. if (this.query)
  16138. this.query = this.query.replace(caseRegex, replaceCase);
  16139. if (this.fragment)
  16140. this.fragment = this.fragment.replace(caseRegex, replaceCase);
  16141. };
  16142. var caseRegex = /%[0-9a-z]{2}/gi;
  16143. var percentRegex = /[a-zA-Z0-9\-\._~]/;
  16144. var authorityRegex = /(.*@)?([^@:]*)(:.*)?/;
  16145. function replaceCase(str) {
  16146. var dec = unescape(str);
  16147. return percentRegex.test(dec) ? dec : str.toUpperCase();
  16148. }
  16149. function replaceAuthority(str, p1, p2, p3) {
  16150. return (p1 || '') + p2.toLowerCase() + (p3 || '');
  16151. }
  16152. /**
  16153. * Resolve a relative URI (this) against a base URI.
  16154. * The base URI must be an absolute URI.
  16155. * See RFC 3986 section 5.2
  16156. */
  16157. URI.prototype.resolve = function(baseURI) {
  16158. var uri = new URI();
  16159. if (this.scheme) {
  16160. uri.scheme = this.scheme;
  16161. uri.authority = this.authority;
  16162. uri.path = this.path;
  16163. uri.query = this.query;
  16164. } else {
  16165. uri.scheme = baseURI.scheme;
  16166. if (this.authority) {
  16167. uri.authority = this.authority;
  16168. uri.path = this.path;
  16169. uri.query = this.query;
  16170. } else {
  16171. uri.authority = baseURI.authority;
  16172. if (this.path == '') {
  16173. uri.path = baseURI.path;
  16174. uri.query = this.query || baseURI.query;
  16175. } else {
  16176. if (this.path.charAt(0) == '/') {
  16177. uri.path = this.path;
  16178. uri.removeDotSegments();
  16179. } else {
  16180. if (baseURI.authority && baseURI.path == '') {
  16181. uri.path = '/' + this.path;
  16182. } else {
  16183. uri.path = baseURI.path.substring(0, baseURI.path.lastIndexOf('/') + 1) + this.path;
  16184. }
  16185. uri.removeDotSegments();
  16186. }
  16187. uri.query = this.query;
  16188. }
  16189. }
  16190. }
  16191. uri.fragment = this.fragment;
  16192. return uri;
  16193. };
  16194. /**
  16195. * Remove dot segments from path.
  16196. * See RFC 3986 section 5.2.4
  16197. * @private
  16198. */
  16199. URI.prototype.removeDotSegments = function() {
  16200. var input = this.path.split('/'),
  16201. output = [],
  16202. segment,
  16203. absPath = input[0] == '';
  16204. if (absPath)
  16205. input.shift();
  16206. var sFirst = input[0] == '' ? input.shift() : null;
  16207. while (input.length) {
  16208. segment = input.shift();
  16209. if (segment == '..') {
  16210. output.pop();
  16211. } else if (segment != '.') {
  16212. output.push(segment);
  16213. }
  16214. }
  16215. if (segment == '.' || segment == '..')
  16216. output.push('');
  16217. if (absPath)
  16218. output.unshift('');
  16219. this.path = output.join('/');
  16220. };
  16221. // We don't like this function because it builds up a cache that is never cleared.
  16222. // /**
  16223. // * Resolves a relative URI against an absolute base URI.
  16224. // * Convenience method.
  16225. // * @param {String} uri the relative URI to resolve
  16226. // * @param {String} baseURI the base URI (must be absolute) to resolve against
  16227. // */
  16228. // URI.resolve = function(sURI, sBaseURI) {
  16229. // var uri = cache[sURI] || (cache[sURI] = new URI(sURI));
  16230. // var baseURI = cache[sBaseURI] || (cache[sBaseURI] = new URI(sBaseURI));
  16231. // return uri.resolve(baseURI).toString();
  16232. // };
  16233. // var cache = {};
  16234. /**
  16235. * Serialises the URI to a string.
  16236. */
  16237. URI.prototype.toString = function() {
  16238. var result = '';
  16239. if (this.scheme)
  16240. result += this.scheme + ':';
  16241. if (this.authority)
  16242. result += '//' + this.authority;
  16243. result += this.path;
  16244. if (this.query)
  16245. result += '?' + this.query;
  16246. if (this.fragment)
  16247. result += '#' + this.fragment;
  16248. return result;
  16249. };
  16250. return URI;
  16251. });
  16252. /*global define*/
  16253. define('Core/TrustedServers',[
  16254. '../ThirdParty/Uri',
  16255. './defined',
  16256. './DeveloperError'
  16257. ], function(
  16258. Uri,
  16259. defined,
  16260. DeveloperError) {
  16261. 'use strict';
  16262. /**
  16263. * A singleton that contains all of the servers that are trusted. Credentials will be sent with
  16264. * any requests to these servers.
  16265. *
  16266. * @exports TrustedServers
  16267. *
  16268. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  16269. */
  16270. var TrustedServers = {};
  16271. var _servers = {};
  16272. /**
  16273. * Adds a trusted server to the registry
  16274. *
  16275. * @param {String} host The host to be added.
  16276. * @param {Number} port The port used to access the host.
  16277. *
  16278. * @example
  16279. * // Add a trusted server
  16280. * TrustedServers.add('my.server.com', 80);
  16281. */
  16282. TrustedServers.add = function(host, port) {
  16283. if (!defined(host)) {
  16284. throw new DeveloperError('host is required.');
  16285. }
  16286. if (!defined(port) || port <= 0) {
  16287. throw new DeveloperError('port is required to be greater than 0.');
  16288. }
  16289. var authority = host.toLowerCase() + ':' + port;
  16290. if (!defined(_servers[authority])) {
  16291. _servers[authority] = true;
  16292. }
  16293. };
  16294. /**
  16295. * Removes a trusted server from the registry
  16296. *
  16297. * @param {String} host The host to be removed.
  16298. * @param {Number} port The port used to access the host.
  16299. *
  16300. * @example
  16301. * // Remove a trusted server
  16302. * TrustedServers.remove('my.server.com', 80);
  16303. */
  16304. TrustedServers.remove = function(host, port) {
  16305. if (!defined(host)) {
  16306. throw new DeveloperError('host is required.');
  16307. }
  16308. if (!defined(port) || port <= 0) {
  16309. throw new DeveloperError('port is required to be greater than 0.');
  16310. }
  16311. var authority = host.toLowerCase() + ':' + port;
  16312. if (defined(_servers[authority])) {
  16313. delete _servers[authority];
  16314. }
  16315. };
  16316. function getAuthority(url) {
  16317. var uri = new Uri(url);
  16318. uri.normalize();
  16319. // Removes username:password@ so we just have host[:port]
  16320. var authority = uri.getAuthority();
  16321. if (!defined(authority)) {
  16322. return undefined; // Relative URL
  16323. }
  16324. if (authority.indexOf('@') !== -1) {
  16325. var parts = authority.split('@');
  16326. authority = parts[1];
  16327. }
  16328. // If the port is missing add one based on the scheme
  16329. if (authority.indexOf(':') === -1) {
  16330. var scheme = uri.getScheme();
  16331. if (!defined(scheme)) {
  16332. scheme = window.location.protocol;
  16333. scheme = scheme.substring(0, scheme.length-1);
  16334. }
  16335. if (scheme === 'http') {
  16336. authority += ':80';
  16337. } else if (scheme === 'https') {
  16338. authority += ':443';
  16339. } else {
  16340. return undefined;
  16341. }
  16342. }
  16343. return authority;
  16344. }
  16345. /**
  16346. * Tests whether a server is trusted or not. The server must have been added with the port if it is included in the url.
  16347. *
  16348. * @param {String} url The url to be tested against the trusted list
  16349. *
  16350. * @returns {boolean} Returns true if url is trusted, false otherwise.
  16351. *
  16352. * @example
  16353. * // Add server
  16354. * TrustedServers.add('my.server.com', 81);
  16355. *
  16356. * // Check if server is trusted
  16357. * if (TrustedServers.contains('https://my.server.com:81/path/to/file.png')) {
  16358. * // my.server.com:81 is trusted
  16359. * }
  16360. * if (TrustedServers.contains('https://my.server.com/path/to/file.png')) {
  16361. * // my.server.com isn't trusted
  16362. * }
  16363. */
  16364. TrustedServers.contains = function(url) {
  16365. if (!defined(url)) {
  16366. throw new DeveloperError('url is required.');
  16367. }
  16368. var authority = getAuthority(url);
  16369. if (defined(authority) && defined(_servers[authority])) {
  16370. return true;
  16371. }
  16372. return false;
  16373. };
  16374. /**
  16375. * Clears the registry
  16376. *
  16377. * @example
  16378. * // Remove a trusted server
  16379. * TrustedServers.clear();
  16380. */
  16381. TrustedServers.clear = function() {
  16382. _servers = {};
  16383. };
  16384. return TrustedServers;
  16385. });
  16386. /*global define*/
  16387. define('Core/loadWithXhr',[
  16388. '../ThirdParty/when',
  16389. './defaultValue',
  16390. './defined',
  16391. './DeveloperError',
  16392. './RequestErrorEvent',
  16393. './RuntimeError',
  16394. './TrustedServers'
  16395. ], function(
  16396. when,
  16397. defaultValue,
  16398. defined,
  16399. DeveloperError,
  16400. RequestErrorEvent,
  16401. RuntimeError,
  16402. TrustedServers) {
  16403. 'use strict';
  16404. /**
  16405. * Asynchronously loads the given URL. Returns a promise that will resolve to
  16406. * the result once loaded, or reject if the URL failed to load. The data is loaded
  16407. * using XMLHttpRequest, which means that in order to make requests to another origin,
  16408. * the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
  16409. *
  16410. * @exports loadWithXhr
  16411. *
  16412. * @param {Object} options Object with the following properties:
  16413. * @param {String|Promise.<String>} options.url The URL of the data, or a promise for the URL.
  16414. * @param {String} [options.responseType] The type of response. This controls the type of item returned.
  16415. * @param {String} [options.method='GET'] The HTTP method to use.
  16416. * @param {String} [options.data] The data to send with the request, if any.
  16417. * @param {Object} [options.headers] HTTP headers to send with the request, if any.
  16418. * @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
  16419. * @returns {Promise.<Object>} a promise that will resolve to the requested data when loaded.
  16420. *
  16421. *
  16422. * @example
  16423. * // Load a single URL asynchronously. In real code, you should use loadBlob instead.
  16424. * Cesium.loadWithXhr({
  16425. * url : 'some/url',
  16426. * responseType : 'blob'
  16427. * }).then(function(blob) {
  16428. * // use the data
  16429. * }).otherwise(function(error) {
  16430. * // an error occurred
  16431. * });
  16432. *
  16433. * @see loadArrayBuffer
  16434. * @see loadBlob
  16435. * @see loadJson
  16436. * @see loadText
  16437. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  16438. * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
  16439. */
  16440. function loadWithXhr(options) {
  16441. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  16442. if (!defined(options.url)) {
  16443. throw new DeveloperError('options.url is required.');
  16444. }
  16445. var responseType = options.responseType;
  16446. var method = defaultValue(options.method, 'GET');
  16447. var data = options.data;
  16448. var headers = options.headers;
  16449. var overrideMimeType = options.overrideMimeType;
  16450. return when(options.url, function(url) {
  16451. var deferred = when.defer();
  16452. loadWithXhr.load(url, responseType, method, data, headers, deferred, overrideMimeType);
  16453. return deferred.promise;
  16454. });
  16455. }
  16456. var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
  16457. function decodeDataUriText(isBase64, data) {
  16458. var result = decodeURIComponent(data);
  16459. if (isBase64) {
  16460. return atob(result);
  16461. }
  16462. return result;
  16463. }
  16464. function decodeDataUriArrayBuffer(isBase64, data) {
  16465. var byteString = decodeDataUriText(isBase64, data);
  16466. var buffer = new ArrayBuffer(byteString.length);
  16467. var view = new Uint8Array(buffer);
  16468. for (var i = 0; i < byteString.length; i++) {
  16469. view[i] = byteString.charCodeAt(i);
  16470. }
  16471. return buffer;
  16472. }
  16473. function decodeDataUri(dataUriRegexResult, responseType) {
  16474. responseType = defaultValue(responseType, '');
  16475. var mimeType = dataUriRegexResult[1];
  16476. var isBase64 = !!dataUriRegexResult[2];
  16477. var data = dataUriRegexResult[3];
  16478. switch (responseType) {
  16479. case '':
  16480. case 'text':
  16481. return decodeDataUriText(isBase64, data);
  16482. case 'arraybuffer':
  16483. return decodeDataUriArrayBuffer(isBase64, data);
  16484. case 'blob':
  16485. var buffer = decodeDataUriArrayBuffer(isBase64, data);
  16486. return new Blob([buffer], {
  16487. type : mimeType
  16488. });
  16489. case 'document':
  16490. var parser = new DOMParser();
  16491. return parser.parseFromString(decodeDataUriText(isBase64, data), mimeType);
  16492. case 'json':
  16493. return JSON.parse(decodeDataUriText(isBase64, data));
  16494. default:
  16495. throw new DeveloperError('Unhandled responseType: ' + responseType);
  16496. }
  16497. }
  16498. // This is broken out into a separate function so that it can be mocked for testing purposes.
  16499. loadWithXhr.load = function(url, responseType, method, data, headers, deferred, overrideMimeType) {
  16500. var dataUriRegexResult = dataUriRegex.exec(url);
  16501. if (dataUriRegexResult !== null) {
  16502. deferred.resolve(decodeDataUri(dataUriRegexResult, responseType));
  16503. return;
  16504. }
  16505. var xhr = new XMLHttpRequest();
  16506. if (TrustedServers.contains(url)) {
  16507. xhr.withCredentials = true;
  16508. }
  16509. if (defined(overrideMimeType) && defined(xhr.overrideMimeType)) {
  16510. xhr.overrideMimeType(overrideMimeType);
  16511. }
  16512. xhr.open(method, url, true);
  16513. if (defined(headers)) {
  16514. for (var key in headers) {
  16515. if (headers.hasOwnProperty(key)) {
  16516. xhr.setRequestHeader(key, headers[key]);
  16517. }
  16518. }
  16519. }
  16520. if (defined(responseType)) {
  16521. xhr.responseType = responseType;
  16522. }
  16523. xhr.onload = function() {
  16524. if (xhr.status < 200 || xhr.status >= 300) {
  16525. deferred.reject(new RequestErrorEvent(xhr.status, xhr.response, xhr.getAllResponseHeaders()));
  16526. return;
  16527. }
  16528. var response = xhr.response;
  16529. var browserResponseType = xhr.responseType;
  16530. //All modern browsers will go into either the first if block or last else block.
  16531. //Other code paths support older browsers that either do not support the supplied responseType
  16532. //or do not support the xhr.response property.
  16533. if (defined(response) && (!defined(responseType) || (browserResponseType === responseType))) {
  16534. deferred.resolve(response);
  16535. } else if ((responseType === 'json') && typeof response === 'string') {
  16536. try {
  16537. deferred.resolve(JSON.parse(response));
  16538. } catch (e) {
  16539. deferred.reject(e);
  16540. }
  16541. } else if ((browserResponseType === '' || browserResponseType === 'document') && defined(xhr.responseXML) && xhr.responseXML.hasChildNodes()) {
  16542. deferred.resolve(xhr.responseXML);
  16543. } else if ((browserResponseType === '' || browserResponseType === 'text') && defined(xhr.responseText)) {
  16544. deferred.resolve(xhr.responseText);
  16545. } else {
  16546. deferred.reject(new RuntimeError('Invalid XMLHttpRequest response type.'));
  16547. }
  16548. };
  16549. xhr.onerror = function(e) {
  16550. deferred.reject(new RequestErrorEvent());
  16551. };
  16552. xhr.send(data);
  16553. };
  16554. loadWithXhr.defaultLoad = loadWithXhr.load;
  16555. return loadWithXhr;
  16556. });
  16557. /*global define*/
  16558. define('Core/loadText',[
  16559. './loadWithXhr'
  16560. ], function(
  16561. loadWithXhr) {
  16562. 'use strict';
  16563. /**
  16564. * Asynchronously loads the given URL as text. Returns a promise that will resolve to
  16565. * a String once loaded, or reject if the URL failed to load. The data is loaded
  16566. * using XMLHttpRequest, which means that in order to make requests to another origin,
  16567. * the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
  16568. *
  16569. * @exports loadText
  16570. *
  16571. * @param {String|Promise.<String>} url The URL to request, or a promise for the URL.
  16572. * @param {Object} [headers] HTTP headers to send with the request.
  16573. * @returns {Promise.<String>} a promise that will resolve to the requested data when loaded.
  16574. *
  16575. *
  16576. * @example
  16577. * // load text from a URL, setting a custom header
  16578. * Cesium.loadText('http://someUrl.com/someJson.txt', {
  16579. * 'X-Custom-Header' : 'some value'
  16580. * }).then(function(text) {
  16581. * // Do something with the text
  16582. * }).otherwise(function(error) {
  16583. * // an error occurred
  16584. * });
  16585. *
  16586. * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest|XMLHttpRequest}
  16587. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  16588. * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
  16589. */
  16590. function loadText(url, headers) {
  16591. return loadWithXhr({
  16592. url : url,
  16593. headers : headers
  16594. });
  16595. }
  16596. return loadText;
  16597. });
  16598. /*global define*/
  16599. define('Core/loadJson',[
  16600. './clone',
  16601. './defined',
  16602. './DeveloperError',
  16603. './loadText'
  16604. ], function(
  16605. clone,
  16606. defined,
  16607. DeveloperError,
  16608. loadText) {
  16609. 'use strict';
  16610. var defaultHeaders = {
  16611. Accept : 'application/json,*/*;q=0.01'
  16612. };
  16613. // note: &#42;&#47;&#42; below is */* but that ends the comment block early
  16614. /**
  16615. * Asynchronously loads the given URL as JSON. Returns a promise that will resolve to
  16616. * a JSON object once loaded, or reject if the URL failed to load. The data is loaded
  16617. * using XMLHttpRequest, which means that in order to make requests to another origin,
  16618. * the server must have Cross-Origin Resource Sharing (CORS) headers enabled. This function
  16619. * adds 'Accept: application/json,&#42;&#47;&#42;;q=0.01' to the request headers, if not
  16620. * already specified.
  16621. *
  16622. * @exports loadJson
  16623. *
  16624. * @param {String|Promise.<String>} url The URL to request, or a promise for the URL.
  16625. * @param {Object} [headers] HTTP headers to send with the request.
  16626. * 'Accept: application/json,&#42;&#47;&#42;;q=0.01' is added to the request headers automatically
  16627. * if not specified.
  16628. * @returns {Promise.<Object>} a promise that will resolve to the requested data when loaded.
  16629. *
  16630. *
  16631. * @example
  16632. * Cesium.loadJson('http://someUrl.com/someJson.txt').then(function(jsonData) {
  16633. * // Do something with the JSON object
  16634. * }).otherwise(function(error) {
  16635. * // an error occurred
  16636. * });
  16637. *
  16638. * @see loadText
  16639. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  16640. * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
  16641. */
  16642. function loadJson(url, headers) {
  16643. if (!defined(url)) {
  16644. throw new DeveloperError('url is required.');
  16645. }
  16646. if (!defined(headers)) {
  16647. headers = defaultHeaders;
  16648. } else if (!defined(headers.Accept)) {
  16649. // clone before adding the Accept header
  16650. headers = clone(headers);
  16651. headers.Accept = defaultHeaders.Accept;
  16652. }
  16653. return loadText(url, headers).then(function(value) {
  16654. return JSON.parse(value);
  16655. });
  16656. }
  16657. return loadJson;
  16658. });
  16659. /*global define*/
  16660. define('Core/EarthOrientationParameters',[
  16661. '../ThirdParty/when',
  16662. './binarySearch',
  16663. './defaultValue',
  16664. './defined',
  16665. './EarthOrientationParametersSample',
  16666. './freezeObject',
  16667. './JulianDate',
  16668. './LeapSecond',
  16669. './loadJson',
  16670. './RuntimeError',
  16671. './TimeConstants',
  16672. './TimeStandard'
  16673. ], function(
  16674. when,
  16675. binarySearch,
  16676. defaultValue,
  16677. defined,
  16678. EarthOrientationParametersSample,
  16679. freezeObject,
  16680. JulianDate,
  16681. LeapSecond,
  16682. loadJson,
  16683. RuntimeError,
  16684. TimeConstants,
  16685. TimeStandard) {
  16686. 'use strict';
  16687. /**
  16688. * Specifies Earth polar motion coordinates and the difference between UT1 and UTC.
  16689. * These Earth Orientation Parameters (EOP) are primarily used in the transformation from
  16690. * the International Celestial Reference Frame (ICRF) to the International Terrestrial
  16691. * Reference Frame (ITRF).
  16692. *
  16693. * @alias EarthOrientationParameters
  16694. * @constructor
  16695. *
  16696. * @param {Object} [options] Object with the following properties:
  16697. * @param {String} [options.url] The URL from which to obtain EOP data. If neither this
  16698. * parameter nor options.data is specified, all EOP values are assumed
  16699. * to be 0.0. If options.data is specified, this parameter is
  16700. * ignored.
  16701. * @param {Object} [options.data] The actual EOP data. If neither this
  16702. * parameter nor options.data is specified, all EOP values are assumed
  16703. * to be 0.0.
  16704. * @param {Boolean} [options.addNewLeapSeconds=true] True if leap seconds that
  16705. * are specified in the EOP data but not in {@link JulianDate.leapSeconds}
  16706. * should be added to {@link JulianDate.leapSeconds}. False if
  16707. * new leap seconds should be handled correctly in the context
  16708. * of the EOP data but otherwise ignored.
  16709. *
  16710. * @example
  16711. * // An example EOP data file, EOP.json:
  16712. * {
  16713. * "columnNames" : ["dateIso8601","modifiedJulianDateUtc","xPoleWanderRadians","yPoleWanderRadians","ut1MinusUtcSeconds","lengthOfDayCorrectionSeconds","xCelestialPoleOffsetRadians","yCelestialPoleOffsetRadians","taiMinusUtcSeconds"],
  16714. * "samples" : [
  16715. * "2011-07-01T00:00:00Z",55743.0,2.117957047295119e-7,2.111518721609984e-6,-0.2908948,-2.956e-4,3.393695767766752e-11,3.3452143996557983e-10,34.0,
  16716. * "2011-07-02T00:00:00Z",55744.0,2.193297093339541e-7,2.115460256837405e-6,-0.29065,-1.824e-4,-8.241832578862112e-11,5.623838700870617e-10,34.0,
  16717. * "2011-07-03T00:00:00Z",55745.0,2.262286080161428e-7,2.1191157519929706e-6,-0.2905572,1.9e-6,-3.490658503988659e-10,6.981317007977318e-10,34.0
  16718. * ]
  16719. * }
  16720. *
  16721. * @example
  16722. * // Loading the EOP data
  16723. * var eop = new Cesium.EarthOrientationParameters({ url : 'Data/EOP.json' });
  16724. * Cesium.Transforms.earthOrientationParameters = eop;
  16725. *
  16726. * @private
  16727. */
  16728. function EarthOrientationParameters(options) {
  16729. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  16730. this._dates = undefined;
  16731. this._samples = undefined;
  16732. this._dateColumn = -1;
  16733. this._xPoleWanderRadiansColumn = -1;
  16734. this._yPoleWanderRadiansColumn = -1;
  16735. this._ut1MinusUtcSecondsColumn = -1;
  16736. this._xCelestialPoleOffsetRadiansColumn = -1;
  16737. this._yCelestialPoleOffsetRadiansColumn = -1;
  16738. this._taiMinusUtcSecondsColumn = -1;
  16739. this._columnCount = 0;
  16740. this._lastIndex = -1;
  16741. this._downloadPromise = undefined;
  16742. this._dataError = undefined;
  16743. this._addNewLeapSeconds = defaultValue(options.addNewLeapSeconds, true);
  16744. if (defined(options.data)) {
  16745. // Use supplied EOP data.
  16746. onDataReady(this, options.data);
  16747. } else if (defined(options.url)) {
  16748. // Download EOP data.
  16749. var that = this;
  16750. this._downloadPromise = when(loadJson(options.url), function(eopData) {
  16751. onDataReady(that, eopData);
  16752. }, function() {
  16753. that._dataError = 'An error occurred while retrieving the EOP data from the URL ' + options.url + '.';
  16754. });
  16755. } else {
  16756. // Use all zeros for EOP data.
  16757. onDataReady(this, {
  16758. 'columnNames' : ['dateIso8601', 'modifiedJulianDateUtc', 'xPoleWanderRadians', 'yPoleWanderRadians', 'ut1MinusUtcSeconds', 'lengthOfDayCorrectionSeconds', 'xCelestialPoleOffsetRadians', 'yCelestialPoleOffsetRadians', 'taiMinusUtcSeconds'],
  16759. 'samples' : []
  16760. });
  16761. }
  16762. }
  16763. /**
  16764. * A default {@link EarthOrientationParameters} instance that returns zero for all EOP values.
  16765. */
  16766. EarthOrientationParameters.NONE = freezeObject({
  16767. getPromiseToLoad : function() {
  16768. return when();
  16769. },
  16770. compute : function(date, result) {
  16771. if (!defined(result)) {
  16772. result = new EarthOrientationParametersSample(0.0, 0.0, 0.0, 0.0, 0.0);
  16773. } else {
  16774. result.xPoleWander = 0.0;
  16775. result.yPoleWander = 0.0;
  16776. result.xPoleOffset = 0.0;
  16777. result.yPoleOffset = 0.0;
  16778. result.ut1MinusUtc = 0.0;
  16779. }
  16780. return result;
  16781. }
  16782. });
  16783. /**
  16784. * Gets a promise that, when resolved, indicates that the EOP data has been loaded and is
  16785. * ready to use.
  16786. *
  16787. * @returns {Promise.<undefined>} The promise.
  16788. *
  16789. * @see when
  16790. */
  16791. EarthOrientationParameters.prototype.getPromiseToLoad = function() {
  16792. return when(this._downloadPromise);
  16793. };
  16794. /**
  16795. * Computes the Earth Orientation Parameters (EOP) for a given date by interpolating.
  16796. * If the EOP data has not yet been download, this method returns undefined.
  16797. *
  16798. * @param {JulianDate} date The date for each to evaluate the EOP.
  16799. * @param {EarthOrientationParametersSample} [result] The instance to which to copy the result.
  16800. * If this parameter is undefined, a new instance is created and returned.
  16801. * @returns {EarthOrientationParametersSample} The EOP evaluated at the given date, or
  16802. * undefined if the data necessary to evaluate EOP at the date has not yet been
  16803. * downloaded.
  16804. *
  16805. * @exception {RuntimeError} The loaded EOP data has an error and cannot be used.
  16806. *
  16807. * @see EarthOrientationParameters#getPromiseToLoad
  16808. */
  16809. EarthOrientationParameters.prototype.compute = function(date, result) {
  16810. // We cannot compute until the samples are available.
  16811. if (!defined(this._samples)) {
  16812. if (defined(this._dataError)) {
  16813. throw new RuntimeError(this._dataError);
  16814. }
  16815. return undefined;
  16816. }
  16817. if (!defined(result)) {
  16818. result = new EarthOrientationParametersSample(0.0, 0.0, 0.0, 0.0, 0.0);
  16819. }
  16820. if (this._samples.length === 0) {
  16821. result.xPoleWander = 0.0;
  16822. result.yPoleWander = 0.0;
  16823. result.xPoleOffset = 0.0;
  16824. result.yPoleOffset = 0.0;
  16825. result.ut1MinusUtc = 0.0;
  16826. return result;
  16827. }
  16828. var dates = this._dates;
  16829. var lastIndex = this._lastIndex;
  16830. var before = 0;
  16831. var after = 0;
  16832. if (defined(lastIndex)) {
  16833. var previousIndexDate = dates[lastIndex];
  16834. var nextIndexDate = dates[lastIndex + 1];
  16835. var isAfterPrevious = JulianDate.lessThanOrEquals(previousIndexDate, date);
  16836. var isAfterLastSample = !defined(nextIndexDate);
  16837. var isBeforeNext = isAfterLastSample || JulianDate.greaterThanOrEquals(nextIndexDate, date);
  16838. if (isAfterPrevious && isBeforeNext) {
  16839. before = lastIndex;
  16840. if (!isAfterLastSample && nextIndexDate.equals(date)) {
  16841. ++before;
  16842. }
  16843. after = before + 1;
  16844. interpolate(this, dates, this._samples, date, before, after, result);
  16845. return result;
  16846. }
  16847. }
  16848. var index = binarySearch(dates, date, JulianDate.compare, this._dateColumn);
  16849. if (index >= 0) {
  16850. // If the next entry is the same date, use the later entry. This way, if two entries
  16851. // describe the same moment, one before a leap second and the other after, then we will use
  16852. // the post-leap second data.
  16853. if (index < dates.length - 1 && dates[index + 1].equals(date)) {
  16854. ++index;
  16855. }
  16856. before = index;
  16857. after = index;
  16858. } else {
  16859. after = ~index;
  16860. before = after - 1;
  16861. // Use the first entry if the date requested is before the beginning of the data.
  16862. if (before < 0) {
  16863. before = 0;
  16864. }
  16865. }
  16866. this._lastIndex = before;
  16867. interpolate(this, dates, this._samples, date, before, after, result);
  16868. return result;
  16869. };
  16870. function compareLeapSecondDates(leapSecond, dateToFind) {
  16871. return JulianDate.compare(leapSecond.julianDate, dateToFind);
  16872. }
  16873. function onDataReady(eop, eopData) {
  16874. if (!defined(eopData.columnNames)) {
  16875. eop._dataError = 'Error in loaded EOP data: The columnNames property is required.';
  16876. return;
  16877. }
  16878. if (!defined(eopData.samples)) {
  16879. eop._dataError = 'Error in loaded EOP data: The samples property is required.';
  16880. return;
  16881. }
  16882. var dateColumn = eopData.columnNames.indexOf('modifiedJulianDateUtc');
  16883. var xPoleWanderRadiansColumn = eopData.columnNames.indexOf('xPoleWanderRadians');
  16884. var yPoleWanderRadiansColumn = eopData.columnNames.indexOf('yPoleWanderRadians');
  16885. var ut1MinusUtcSecondsColumn = eopData.columnNames.indexOf('ut1MinusUtcSeconds');
  16886. var xCelestialPoleOffsetRadiansColumn = eopData.columnNames.indexOf('xCelestialPoleOffsetRadians');
  16887. var yCelestialPoleOffsetRadiansColumn = eopData.columnNames.indexOf('yCelestialPoleOffsetRadians');
  16888. var taiMinusUtcSecondsColumn = eopData.columnNames.indexOf('taiMinusUtcSeconds');
  16889. if (dateColumn < 0 || xPoleWanderRadiansColumn < 0 || yPoleWanderRadiansColumn < 0 || ut1MinusUtcSecondsColumn < 0 || xCelestialPoleOffsetRadiansColumn < 0 || yCelestialPoleOffsetRadiansColumn < 0 || taiMinusUtcSecondsColumn < 0) {
  16890. eop._dataError = 'Error in loaded EOP data: The columnNames property must include modifiedJulianDateUtc, xPoleWanderRadians, yPoleWanderRadians, ut1MinusUtcSeconds, xCelestialPoleOffsetRadians, yCelestialPoleOffsetRadians, and taiMinusUtcSeconds columns';
  16891. return;
  16892. }
  16893. var samples = eop._samples = eopData.samples;
  16894. var dates = eop._dates = [];
  16895. eop._dateColumn = dateColumn;
  16896. eop._xPoleWanderRadiansColumn = xPoleWanderRadiansColumn;
  16897. eop._yPoleWanderRadiansColumn = yPoleWanderRadiansColumn;
  16898. eop._ut1MinusUtcSecondsColumn = ut1MinusUtcSecondsColumn;
  16899. eop._xCelestialPoleOffsetRadiansColumn = xCelestialPoleOffsetRadiansColumn;
  16900. eop._yCelestialPoleOffsetRadiansColumn = yCelestialPoleOffsetRadiansColumn;
  16901. eop._taiMinusUtcSecondsColumn = taiMinusUtcSecondsColumn;
  16902. eop._columnCount = eopData.columnNames.length;
  16903. eop._lastIndex = undefined;
  16904. var lastTaiMinusUtc;
  16905. var addNewLeapSeconds = eop._addNewLeapSeconds;
  16906. // Convert the ISO8601 dates to JulianDates.
  16907. for (var i = 0, len = samples.length; i < len; i += eop._columnCount) {
  16908. var mjd = samples[i + dateColumn];
  16909. var taiMinusUtc = samples[i + taiMinusUtcSecondsColumn];
  16910. var day = mjd + TimeConstants.MODIFIED_JULIAN_DATE_DIFFERENCE;
  16911. var date = new JulianDate(day, taiMinusUtc, TimeStandard.TAI);
  16912. dates.push(date);
  16913. if (addNewLeapSeconds) {
  16914. if (taiMinusUtc !== lastTaiMinusUtc && defined(lastTaiMinusUtc)) {
  16915. // We crossed a leap second boundary, so add the leap second
  16916. // if it does not already exist.
  16917. var leapSeconds = JulianDate.leapSeconds;
  16918. var leapSecondIndex = binarySearch(leapSeconds, date, compareLeapSecondDates);
  16919. if (leapSecondIndex < 0) {
  16920. var leapSecond = new LeapSecond(date, taiMinusUtc);
  16921. leapSeconds.splice(~leapSecondIndex, 0, leapSecond);
  16922. }
  16923. }
  16924. lastTaiMinusUtc = taiMinusUtc;
  16925. }
  16926. }
  16927. }
  16928. function fillResultFromIndex(eop, samples, index, columnCount, result) {
  16929. var start = index * columnCount;
  16930. result.xPoleWander = samples[start + eop._xPoleWanderRadiansColumn];
  16931. result.yPoleWander = samples[start + eop._yPoleWanderRadiansColumn];
  16932. result.xPoleOffset = samples[start + eop._xCelestialPoleOffsetRadiansColumn];
  16933. result.yPoleOffset = samples[start + eop._yCelestialPoleOffsetRadiansColumn];
  16934. result.ut1MinusUtc = samples[start + eop._ut1MinusUtcSecondsColumn];
  16935. }
  16936. function linearInterp(dx, y1, y2) {
  16937. return y1 + dx * (y2 - y1);
  16938. }
  16939. function interpolate(eop, dates, samples, date, before, after, result) {
  16940. var columnCount = eop._columnCount;
  16941. // First check the bounds on the EOP data
  16942. // If we are after the bounds of the data, return zeros.
  16943. // The 'before' index should never be less than zero.
  16944. if (after > dates.length - 1) {
  16945. result.xPoleWander = 0;
  16946. result.yPoleWander = 0;
  16947. result.xPoleOffset = 0;
  16948. result.yPoleOffset = 0;
  16949. result.ut1MinusUtc = 0;
  16950. return result;
  16951. }
  16952. var beforeDate = dates[before];
  16953. var afterDate = dates[after];
  16954. if (beforeDate.equals(afterDate) || date.equals(beforeDate)) {
  16955. fillResultFromIndex(eop, samples, before, columnCount, result);
  16956. return result;
  16957. } else if (date.equals(afterDate)) {
  16958. fillResultFromIndex(eop, samples, after, columnCount, result);
  16959. return result;
  16960. }
  16961. var factor = JulianDate.secondsDifference(date, beforeDate) / JulianDate.secondsDifference(afterDate, beforeDate);
  16962. var startBefore = before * columnCount;
  16963. var startAfter = after * columnCount;
  16964. // Handle UT1 leap second edge case
  16965. var beforeUt1MinusUtc = samples[startBefore + eop._ut1MinusUtcSecondsColumn];
  16966. var afterUt1MinusUtc = samples[startAfter + eop._ut1MinusUtcSecondsColumn];
  16967. var offsetDifference = afterUt1MinusUtc - beforeUt1MinusUtc;
  16968. if (offsetDifference > 0.5 || offsetDifference < -0.5) {
  16969. // The absolute difference between the values is more than 0.5, so we may have
  16970. // crossed a leap second. Check if this is the case and, if so, adjust the
  16971. // afterValue to account for the leap second. This way, our interpolation will
  16972. // produce reasonable results.
  16973. var beforeTaiMinusUtc = samples[startBefore + eop._taiMinusUtcSecondsColumn];
  16974. var afterTaiMinusUtc = samples[startAfter + eop._taiMinusUtcSecondsColumn];
  16975. if (beforeTaiMinusUtc !== afterTaiMinusUtc) {
  16976. if (afterDate.equals(date)) {
  16977. // If we are at the end of the leap second interval, take the second value
  16978. // Otherwise, the interpolation below will yield the wrong side of the
  16979. // discontinuity
  16980. // At the end of the leap second, we need to start accounting for the jump
  16981. beforeUt1MinusUtc = afterUt1MinusUtc;
  16982. } else {
  16983. // Otherwise, remove the leap second so that the interpolation is correct
  16984. afterUt1MinusUtc -= afterTaiMinusUtc - beforeTaiMinusUtc;
  16985. }
  16986. }
  16987. }
  16988. result.xPoleWander = linearInterp(factor, samples[startBefore + eop._xPoleWanderRadiansColumn], samples[startAfter + eop._xPoleWanderRadiansColumn]);
  16989. result.yPoleWander = linearInterp(factor, samples[startBefore + eop._yPoleWanderRadiansColumn], samples[startAfter + eop._yPoleWanderRadiansColumn]);
  16990. result.xPoleOffset = linearInterp(factor, samples[startBefore + eop._xCelestialPoleOffsetRadiansColumn], samples[startAfter + eop._xCelestialPoleOffsetRadiansColumn]);
  16991. result.yPoleOffset = linearInterp(factor, samples[startBefore + eop._yCelestialPoleOffsetRadiansColumn], samples[startAfter + eop._yCelestialPoleOffsetRadiansColumn]);
  16992. result.ut1MinusUtc = linearInterp(factor, beforeUt1MinusUtc, afterUt1MinusUtc);
  16993. return result;
  16994. }
  16995. return EarthOrientationParameters;
  16996. });
  16997. /*global define*/
  16998. define('Core/HeadingPitchRoll',[
  16999. './defaultValue',
  17000. './defined',
  17001. './DeveloperError',
  17002. './Math'
  17003. ], function(
  17004. defaultValue,
  17005. defined,
  17006. DeveloperError,
  17007. CesiumMath) {
  17008. "use strict";
  17009. /**
  17010. * A rotation expressed as a heading, pitch, and roll. Heading is the rotation about the
  17011. * negative z axis. Pitch is the rotation about the negative y axis. Roll is the rotation about
  17012. * the positive x axis.
  17013. * @alias HeadingPitchRoll
  17014. * @constructor
  17015. *
  17016. * @param {Number} [heading=0.0] The heading component in radians.
  17017. * @param {Number} [pitch=0.0] The pitch component in radians.
  17018. * @param {Number} [roll=0.0] The roll component in radians.
  17019. */
  17020. function HeadingPitchRoll(heading, pitch, roll) {
  17021. this.heading = defaultValue(heading, 0.0);
  17022. this.pitch = defaultValue(pitch, 0.0);
  17023. this.roll = defaultValue(roll, 0.0);
  17024. }
  17025. /**
  17026. * Computes the heading, pitch and roll from a quaternion (see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles )
  17027. *
  17028. * @param {Quaternion} quaternion The quaternion from which to retrieve heading, pitch, and roll, all expressed in radians.
  17029. * @param {Quaternion} [result] The object in which to store the result. If not provided, a new instance is created and returned.
  17030. * @returns {HeadingPitchRoll} The modified result parameter or a new HeadingPitchRoll instance if one was not provided.
  17031. */
  17032. HeadingPitchRoll.fromQuaternion = function(quaternion, result) {
  17033. if (!defined(quaternion)) {
  17034. throw new DeveloperError('quaternion is required');
  17035. }
  17036. if (!defined(result)) {
  17037. result = new HeadingPitchRoll();
  17038. }
  17039. var test = 2 * (quaternion.w * quaternion.y - quaternion.z * quaternion.x);
  17040. var denominatorRoll = 1 - 2 * (quaternion.x * quaternion.x + quaternion.y * quaternion.y);
  17041. var numeratorRoll = 2 * (quaternion.w * quaternion.x + quaternion.y * quaternion.z);
  17042. var denominatorHeading = 1 - 2 * (quaternion.y * quaternion.y + quaternion.z * quaternion.z);
  17043. var numeratorHeading = 2 * (quaternion.w * quaternion.z + quaternion.x * quaternion.y);
  17044. result.heading = -Math.atan2(numeratorHeading, denominatorHeading);
  17045. result.roll = Math.atan2(numeratorRoll, denominatorRoll);
  17046. result.pitch = -Math.asin(test);
  17047. return result;
  17048. };
  17049. /**
  17050. * Returns a new HeadingPitchRoll instance from angles given in degrees.
  17051. *
  17052. * @param {Number} heading the heading in degrees
  17053. * @param {Number} pitch the pitch in degrees
  17054. * @param {Number} roll the heading in degrees
  17055. * @param {HeadingPitchRoll} [result] The object in which to store the result. If not provided, a new instance is created and returned.
  17056. * @returns {HeadingPitchRoll} A new HeadingPitchRoll instance
  17057. */
  17058. HeadingPitchRoll.fromDegrees = function(heading, pitch, roll, result) {
  17059. if (!defined(heading)) {
  17060. throw new DeveloperError('heading is required');
  17061. }
  17062. if (!defined(pitch)) {
  17063. throw new DeveloperError('pitch is required');
  17064. }
  17065. if (!defined(roll)) {
  17066. throw new DeveloperError('roll is required');
  17067. }
  17068. if (!defined(result)) {
  17069. result = new HeadingPitchRoll();
  17070. }
  17071. result.heading = heading * CesiumMath.RADIANS_PER_DEGREE;
  17072. result.pitch = pitch * CesiumMath.RADIANS_PER_DEGREE;
  17073. result.roll = roll * CesiumMath.RADIANS_PER_DEGREE;
  17074. return result;
  17075. };
  17076. /**
  17077. * Duplicates a HeadingPitchRoll instance.
  17078. *
  17079. * @param {HeadingPitchRoll} headingPitchRoll The HeadingPitchRoll to duplicate.
  17080. * @param {HeadingPitchRoll} [result] The object onto which to store the result.
  17081. * @returns {HeadingPitchRoll} The modified result parameter or a new HeadingPitchRoll instance if one was not provided. (Returns undefined if headingPitchRoll is undefined)
  17082. */
  17083. HeadingPitchRoll.clone = function(headingPitchRoll, result) {
  17084. if (!defined(headingPitchRoll)) {
  17085. return undefined;
  17086. }
  17087. if (!defined(result)) {
  17088. return new HeadingPitchRoll(headingPitchRoll.heading, headingPitchRoll.pitch, headingPitchRoll.roll);
  17089. }
  17090. result.heading = headingPitchRoll.heading;
  17091. result.pitch = headingPitchRoll.pitch;
  17092. result.roll = headingPitchRoll.roll;
  17093. return result;
  17094. };
  17095. /**
  17096. * Compares the provided HeadingPitchRolls componentwise and returns
  17097. * <code>true</code> if they are equal, <code>false</code> otherwise.
  17098. *
  17099. * @param {HeadingPitchRoll} [left] The first HeadingPitchRoll.
  17100. * @param {HeadingPitchRoll} [right] The second HeadingPitchRoll.
  17101. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  17102. */
  17103. HeadingPitchRoll.equals = function(left, right) {
  17104. return (left === right) ||
  17105. ((defined(left)) &&
  17106. (defined(right)) &&
  17107. (left.heading === right.heading) &&
  17108. (left.pitch === right.pitch) &&
  17109. (left.roll === right.roll));
  17110. };
  17111. /**
  17112. * Compares the provided HeadingPitchRolls componentwise and returns
  17113. * <code>true</code> if they pass an absolute or relative tolerance test,
  17114. * <code>false</code> otherwise.
  17115. *
  17116. * @param {HeadingPitchRoll} [left] The first HeadingPitchRoll.
  17117. * @param {HeadingPitchRoll} [right] The second HeadingPitchRoll.
  17118. * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
  17119. * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
  17120. * @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
  17121. */
  17122. HeadingPitchRoll.equalsEpsilon = function(left, right, relativeEpsilon, absoluteEpsilon) {
  17123. return (left === right) ||
  17124. (defined(left) &&
  17125. defined(right) &&
  17126. CesiumMath.equalsEpsilon(left.heading, right.heading, relativeEpsilon, absoluteEpsilon) &&
  17127. CesiumMath.equalsEpsilon(left.pitch, right.pitch, relativeEpsilon, absoluteEpsilon) &&
  17128. CesiumMath.equalsEpsilon(left.roll, right.roll, relativeEpsilon, absoluteEpsilon));
  17129. };
  17130. /**
  17131. * Duplicates this HeadingPitchRoll instance.
  17132. *
  17133. * @param {HeadingPitchRoll} [result] The object onto which to store the result.
  17134. * @returns {HeadingPitchRoll} The modified result parameter or a new HeadingPitchRoll instance if one was not provided.
  17135. */
  17136. HeadingPitchRoll.prototype.clone = function(result) {
  17137. return HeadingPitchRoll.clone(this, result);
  17138. };
  17139. /**
  17140. * Compares this HeadingPitchRoll against the provided HeadingPitchRoll componentwise and returns
  17141. * <code>true</code> if they are equal, <code>false</code> otherwise.
  17142. *
  17143. * @param {HeadingPitchRoll} [right] The right hand side HeadingPitchRoll.
  17144. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  17145. */
  17146. HeadingPitchRoll.prototype.equals = function(right) {
  17147. return HeadingPitchRoll.equals(this, right);
  17148. };
  17149. /**
  17150. * Compares this HeadingPitchRoll against the provided HeadingPitchRoll componentwise and returns
  17151. * <code>true</code> if they pass an absolute or relative tolerance test,
  17152. * <code>false</code> otherwise.
  17153. *
  17154. * @param {HeadingPitchRoll} [right] The right hand side HeadingPitchRoll.
  17155. * @param {Number} relativeEpsilon The relative epsilon tolerance to use for equality testing.
  17156. * @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
  17157. * @returns {Boolean} <code>true</code> if they are within the provided epsilon, <code>false</code> otherwise.
  17158. */
  17159. HeadingPitchRoll.prototype.equalsEpsilon = function(right, relativeEpsilon, absoluteEpsilon) {
  17160. return HeadingPitchRoll.equalsEpsilon(this, right, relativeEpsilon, absoluteEpsilon);
  17161. };
  17162. /**
  17163. * Creates a string representing this HeadingPitchRoll in the format '(heading, pitch, roll)' in radians.
  17164. *
  17165. * @returns {String} A string representing the provided HeadingPitchRoll in the format '(heading, pitch, roll)'.
  17166. */
  17167. HeadingPitchRoll.prototype.toString = function() {
  17168. return '(' + this.heading + ', ' + this.pitch + ', ' + this.roll + ')';
  17169. };
  17170. return HeadingPitchRoll;
  17171. });
  17172. /*global define*/
  17173. define('Core/getAbsoluteUri',[
  17174. '../ThirdParty/Uri',
  17175. './defaultValue',
  17176. './defined',
  17177. './DeveloperError'
  17178. ], function(
  17179. Uri,
  17180. defaultValue,
  17181. defined,
  17182. DeveloperError) {
  17183. 'use strict';
  17184. /**
  17185. * Given a relative Uri and a base Uri, returns the absolute Uri of the relative Uri.
  17186. * @exports getAbsoluteUri
  17187. *
  17188. * @param {String} relative The relative Uri.
  17189. * @param {String} [base] The base Uri.
  17190. * @returns {String} The absolute Uri of the given relative Uri.
  17191. *
  17192. * @example
  17193. * //absolute Uri will be "https://test.com/awesome.png";
  17194. * var absoluteUri = Cesium.getAbsoluteUri('awesome.png', 'https://test.com');
  17195. */
  17196. function getAbsoluteUri(relative, base) {
  17197. if (!defined(relative)) {
  17198. throw new DeveloperError('relative uri is required.');
  17199. }
  17200. base = defaultValue(base, document.location.href);
  17201. var baseUri = new Uri(base);
  17202. var relativeUri = new Uri(relative);
  17203. return relativeUri.resolve(baseUri).toString();
  17204. }
  17205. return getAbsoluteUri;
  17206. });
  17207. /*global define*/
  17208. define('Core/joinUrls',[
  17209. '../ThirdParty/Uri',
  17210. './defaultValue',
  17211. './defined',
  17212. './DeveloperError'
  17213. ], function(
  17214. Uri,
  17215. defaultValue,
  17216. defined,
  17217. DeveloperError) {
  17218. 'use strict';
  17219. /**
  17220. * Function for joining URLs in a manner that is aware of query strings and fragments.
  17221. * This is useful when the base URL has a query string that needs to be maintained
  17222. * (e.g. a presigned base URL).
  17223. * @param {String|Uri} first The base URL.
  17224. * @param {String|Uri} second The URL path to join to the base URL. If this URL is absolute, it is returned unmodified.
  17225. * @param {Boolean} [appendSlash=true] The boolean determining whether there should be a forward slash between first and second.
  17226. * @private
  17227. */
  17228. function joinUrls(first, second, appendSlash) {
  17229. if (!defined(first)) {
  17230. throw new DeveloperError('first is required');
  17231. }
  17232. if (!defined(second)) {
  17233. throw new DeveloperError('second is required');
  17234. }
  17235. appendSlash = defaultValue(appendSlash, true);
  17236. if (!(first instanceof Uri)) {
  17237. first = new Uri(first);
  17238. }
  17239. if (!(second instanceof Uri)) {
  17240. second = new Uri(second);
  17241. }
  17242. // Uri.isAbsolute returns false for a URL like '//foo.com'. So if we have an authority but
  17243. // not a scheme, add a scheme matching the page's scheme.
  17244. if (defined(second.authority) && !defined(second.scheme)) {
  17245. if (typeof document !== 'undefined' && defined(document.location) && defined(document.location.href)) {
  17246. second.scheme = new Uri(document.location.href).scheme;
  17247. } else {
  17248. // Not in a browser? Use the first URL's scheme instead.
  17249. second.scheme = first.scheme;
  17250. }
  17251. }
  17252. // If the second URL is absolute, use it for the scheme, authority, and path.
  17253. var baseUri = first;
  17254. if (second.isAbsolute()) {
  17255. baseUri = second;
  17256. }
  17257. var url = '';
  17258. if (defined(baseUri.scheme)) {
  17259. url += baseUri.scheme + ':';
  17260. }
  17261. if (defined(baseUri.authority)) {
  17262. url += '//' + baseUri.authority;
  17263. if (baseUri.path !== '' && baseUri.path !== '/') {
  17264. url = url.replace(/\/?$/, '/');
  17265. baseUri.path = baseUri.path.replace(/^\/?/g, '');
  17266. }
  17267. }
  17268. // Combine the paths (only if second is relative).
  17269. if (baseUri === first) {
  17270. if (appendSlash) {
  17271. url += first.path.replace(/\/?$/, '/') + second.path.replace(/^\/?/g, '');
  17272. } else {
  17273. url += first.path + second.path;
  17274. }
  17275. } else {
  17276. url += second.path;
  17277. }
  17278. // Combine the queries and fragments.
  17279. var hasFirstQuery = defined(first.query);
  17280. var hasSecondQuery = defined(second.query);
  17281. if (hasFirstQuery && hasSecondQuery) {
  17282. url += '?' + first.query + '&' + second.query;
  17283. } else if (hasFirstQuery && !hasSecondQuery) {
  17284. url += '?' + first.query;
  17285. } else if (!hasFirstQuery && hasSecondQuery) {
  17286. url += '?' + second.query;
  17287. }
  17288. var hasSecondFragment = defined(second.fragment);
  17289. if (defined(first.fragment) && !hasSecondFragment) {
  17290. url += '#' + first.fragment;
  17291. } else if (hasSecondFragment) {
  17292. url += '#' + second.fragment;
  17293. }
  17294. return url;
  17295. }
  17296. return joinUrls;
  17297. });
  17298. /*global define*/
  17299. define('Core/buildModuleUrl',[
  17300. '../ThirdParty/Uri',
  17301. './defined',
  17302. './DeveloperError',
  17303. './getAbsoluteUri',
  17304. './joinUrls',
  17305. 'require'
  17306. ], function(
  17307. Uri,
  17308. defined,
  17309. DeveloperError,
  17310. getAbsoluteUri,
  17311. joinUrls,
  17312. require) {
  17313. 'use strict';
  17314. /*global CESIUM_BASE_URL*/
  17315. var cesiumScriptRegex = /((?:.*\/)|^)cesium[\w-]*\.js(?:\W|$)/i;
  17316. function getBaseUrlFromCesiumScript() {
  17317. var scripts = document.getElementsByTagName('script');
  17318. for ( var i = 0, len = scripts.length; i < len; ++i) {
  17319. var src = scripts[i].getAttribute('src');
  17320. var result = cesiumScriptRegex.exec(src);
  17321. if (result !== null) {
  17322. return result[1];
  17323. }
  17324. }
  17325. return undefined;
  17326. }
  17327. var baseUrl;
  17328. function getCesiumBaseUrl() {
  17329. if (defined(baseUrl)) {
  17330. return baseUrl;
  17331. }
  17332. var baseUrlString;
  17333. if (typeof CESIUM_BASE_URL !== 'undefined') {
  17334. baseUrlString = CESIUM_BASE_URL;
  17335. } else {
  17336. baseUrlString = getBaseUrlFromCesiumScript();
  17337. }
  17338. if (!defined(baseUrlString)) {
  17339. throw new DeveloperError('Unable to determine Cesium base URL automatically, try defining a global variable called CESIUM_BASE_URL.');
  17340. }
  17341. baseUrl = new Uri(getAbsoluteUri(baseUrlString));
  17342. return baseUrl;
  17343. }
  17344. function buildModuleUrlFromRequireToUrl(moduleID) {
  17345. //moduleID will be non-relative, so require it relative to this module, in Core.
  17346. return require.toUrl('../' + moduleID);
  17347. }
  17348. function buildModuleUrlFromBaseUrl(moduleID) {
  17349. return joinUrls(getCesiumBaseUrl(), moduleID);
  17350. }
  17351. var implementation;
  17352. var a;
  17353. /**
  17354. * Given a non-relative moduleID, returns an absolute URL to the file represented by that module ID,
  17355. * using, in order of preference, require.toUrl, the value of a global CESIUM_BASE_URL, or
  17356. * the base URL of the Cesium.js script.
  17357. *
  17358. * @private
  17359. */
  17360. function buildModuleUrl(moduleID) {
  17361. if (!defined(implementation)) {
  17362. //select implementation
  17363. if (defined(require.toUrl)) {
  17364. implementation = buildModuleUrlFromRequireToUrl;
  17365. } else {
  17366. implementation = buildModuleUrlFromBaseUrl;
  17367. }
  17368. }
  17369. if (!defined(a)) {
  17370. a = document.createElement('a');
  17371. }
  17372. var url = implementation(moduleID);
  17373. a.href = url;
  17374. a.href = a.href; // IE only absolutizes href on get, not set
  17375. return a.href;
  17376. }
  17377. // exposed for testing
  17378. buildModuleUrl._cesiumScriptRegex = cesiumScriptRegex;
  17379. /**
  17380. * Sets the base URL for resolving modules.
  17381. * @param {String} value The new base URL.
  17382. */
  17383. buildModuleUrl.setBaseUrl = function(value) {
  17384. baseUrl = new Uri(value).resolve(new Uri(document.location.href));
  17385. };
  17386. return buildModuleUrl;
  17387. });
  17388. /*global define*/
  17389. define('Core/Iau2006XysSample',[],function() {
  17390. 'use strict';
  17391. /**
  17392. * An IAU 2006 XYS value sampled at a particular time.
  17393. *
  17394. * @alias Iau2006XysSample
  17395. * @constructor
  17396. *
  17397. * @param {Number} x The X value.
  17398. * @param {Number} y The Y value.
  17399. * @param {Number} s The S value.
  17400. *
  17401. * @private
  17402. */
  17403. function Iau2006XysSample(x, y, s) {
  17404. /**
  17405. * The X value.
  17406. * @type {Number}
  17407. */
  17408. this.x = x;
  17409. /**
  17410. * The Y value.
  17411. * @type {Number}
  17412. */
  17413. this.y = y;
  17414. /**
  17415. * The S value.
  17416. * @type {Number}
  17417. */
  17418. this.s = s;
  17419. }
  17420. return Iau2006XysSample;
  17421. });
  17422. /*global define*/
  17423. define('Core/Iau2006XysData',[
  17424. '../ThirdParty/when',
  17425. './buildModuleUrl',
  17426. './defaultValue',
  17427. './defined',
  17428. './Iau2006XysSample',
  17429. './JulianDate',
  17430. './loadJson',
  17431. './TimeStandard'
  17432. ], function(
  17433. when,
  17434. buildModuleUrl,
  17435. defaultValue,
  17436. defined,
  17437. Iau2006XysSample,
  17438. JulianDate,
  17439. loadJson,
  17440. TimeStandard) {
  17441. 'use strict';
  17442. /**
  17443. * A set of IAU2006 XYS data that is used to evaluate the transformation between the International
  17444. * Celestial Reference Frame (ICRF) and the International Terrestrial Reference Frame (ITRF).
  17445. *
  17446. * @alias Iau2006XysData
  17447. * @constructor
  17448. *
  17449. * @param {Object} [options] Object with the following properties:
  17450. * @param {String} [options.xysFileUrlTemplate='Assets/IAU2006_XYS/IAU2006_XYS_{0}.json'] A template URL for obtaining the XYS data. In the template,
  17451. * `{0}` will be replaced with the file index.
  17452. * @param {Number} [options.interpolationOrder=9] The order of interpolation to perform on the XYS data.
  17453. * @param {Number} [options.sampleZeroJulianEphemerisDate=2442396.5] The Julian ephemeris date (JED) of the
  17454. * first XYS sample.
  17455. * @param {Number} [options.stepSizeDays=1.0] The step size, in days, between successive XYS samples.
  17456. * @param {Number} [options.samplesPerXysFile=1000] The number of samples in each XYS file.
  17457. * @param {Number} [options.totalSamples=27426] The total number of samples in all XYS files.
  17458. *
  17459. * @private
  17460. */
  17461. function Iau2006XysData(options) {
  17462. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  17463. this._xysFileUrlTemplate = options.xysFileUrlTemplate;
  17464. this._interpolationOrder = defaultValue(options.interpolationOrder, 9);
  17465. this._sampleZeroJulianEphemerisDate = defaultValue(options.sampleZeroJulianEphemerisDate, 2442396.5);
  17466. this._sampleZeroDateTT = new JulianDate(this._sampleZeroJulianEphemerisDate, 0.0, TimeStandard.TAI);
  17467. this._stepSizeDays = defaultValue(options.stepSizeDays, 1.0);
  17468. this._samplesPerXysFile = defaultValue(options.samplesPerXysFile, 1000);
  17469. this._totalSamples = defaultValue(options.totalSamples, 27426);
  17470. this._samples = new Array(this._totalSamples * 3);
  17471. this._chunkDownloadsInProgress = [];
  17472. var order = this._interpolationOrder;
  17473. // Compute denominators and X values for interpolation.
  17474. var denom = this._denominators = new Array(order + 1);
  17475. var xTable = this._xTable = new Array(order + 1);
  17476. var stepN = Math.pow(this._stepSizeDays, order);
  17477. for ( var i = 0; i <= order; ++i) {
  17478. denom[i] = stepN;
  17479. xTable[i] = i * this._stepSizeDays;
  17480. for ( var j = 0; j <= order; ++j) {
  17481. if (j !== i) {
  17482. denom[i] *= (i - j);
  17483. }
  17484. }
  17485. denom[i] = 1.0 / denom[i];
  17486. }
  17487. // Allocate scratch arrays for interpolation.
  17488. this._work = new Array(order + 1);
  17489. this._coef = new Array(order + 1);
  17490. }
  17491. var julianDateScratch = new JulianDate(0, 0.0, TimeStandard.TAI);
  17492. function getDaysSinceEpoch(xys, dayTT, secondTT) {
  17493. var dateTT = julianDateScratch;
  17494. dateTT.dayNumber = dayTT;
  17495. dateTT.secondsOfDay = secondTT;
  17496. return JulianDate.daysDifference(dateTT, xys._sampleZeroDateTT);
  17497. }
  17498. /**
  17499. * Preloads XYS data for a specified date range.
  17500. *
  17501. * @param {Number} startDayTT The Julian day number of the beginning of the interval to preload, expressed in
  17502. * the Terrestrial Time (TT) time standard.
  17503. * @param {Number} startSecondTT The seconds past noon of the beginning of the interval to preload, expressed in
  17504. * the Terrestrial Time (TT) time standard.
  17505. * @param {Number} stopDayTT The Julian day number of the end of the interval to preload, expressed in
  17506. * the Terrestrial Time (TT) time standard.
  17507. * @param {Number} stopSecondTT The seconds past noon of the end of the interval to preload, expressed in
  17508. * the Terrestrial Time (TT) time standard.
  17509. * @returns {Promise.<undefined>} A promise that, when resolved, indicates that the requested interval has been
  17510. * preloaded.
  17511. */
  17512. Iau2006XysData.prototype.preload = function(startDayTT, startSecondTT, stopDayTT, stopSecondTT) {
  17513. var startDaysSinceEpoch = getDaysSinceEpoch(this, startDayTT, startSecondTT);
  17514. var stopDaysSinceEpoch = getDaysSinceEpoch(this, stopDayTT, stopSecondTT);
  17515. var startIndex = (startDaysSinceEpoch / this._stepSizeDays - this._interpolationOrder / 2) | 0;
  17516. if (startIndex < 0) {
  17517. startIndex = 0;
  17518. }
  17519. var stopIndex = (stopDaysSinceEpoch / this._stepSizeDays - this._interpolationOrder / 2) | 0 + this._interpolationOrder;
  17520. if (stopIndex >= this._totalSamples) {
  17521. stopIndex = this._totalSamples - 1;
  17522. }
  17523. var startChunk = (startIndex / this._samplesPerXysFile) | 0;
  17524. var stopChunk = (stopIndex / this._samplesPerXysFile) | 0;
  17525. var promises = [];
  17526. for ( var i = startChunk; i <= stopChunk; ++i) {
  17527. promises.push(requestXysChunk(this, i));
  17528. }
  17529. return when.all(promises);
  17530. };
  17531. /**
  17532. * Computes the XYS values for a given date by interpolating. If the required data is not yet downloaded,
  17533. * this method will return undefined.
  17534. *
  17535. * @param {Number} dayTT The Julian day number for which to compute the XYS value, expressed in
  17536. * the Terrestrial Time (TT) time standard.
  17537. * @param {Number} secondTT The seconds past noon of the date for which to compute the XYS value, expressed in
  17538. * the Terrestrial Time (TT) time standard.
  17539. * @param {Iau2006XysSample} [result] The instance to which to copy the interpolated result. If this parameter
  17540. * is undefined, a new instance is allocated and returned.
  17541. * @returns {Iau2006XysSample} The interpolated XYS values, or undefined if the required data for this
  17542. * computation has not yet been downloaded.
  17543. *
  17544. * @see Iau2006XysData#preload
  17545. */
  17546. Iau2006XysData.prototype.computeXysRadians = function(dayTT, secondTT, result) {
  17547. var daysSinceEpoch = getDaysSinceEpoch(this, dayTT, secondTT);
  17548. if (daysSinceEpoch < 0.0) {
  17549. // Can't evaluate prior to the epoch of the data.
  17550. return undefined;
  17551. }
  17552. var centerIndex = (daysSinceEpoch / this._stepSizeDays) | 0;
  17553. if (centerIndex >= this._totalSamples) {
  17554. // Can't evaluate after the last sample in the data.
  17555. return undefined;
  17556. }
  17557. var degree = this._interpolationOrder;
  17558. var firstIndex = centerIndex - ((degree / 2) | 0);
  17559. if (firstIndex < 0) {
  17560. firstIndex = 0;
  17561. }
  17562. var lastIndex = firstIndex + degree;
  17563. if (lastIndex >= this._totalSamples) {
  17564. lastIndex = this._totalSamples - 1;
  17565. firstIndex = lastIndex - degree;
  17566. if (firstIndex < 0) {
  17567. firstIndex = 0;
  17568. }
  17569. }
  17570. // Are all the samples we need present?
  17571. // We can assume so if the first and last are present
  17572. var isDataMissing = false;
  17573. var samples = this._samples;
  17574. if (!defined(samples[firstIndex * 3])) {
  17575. requestXysChunk(this, (firstIndex / this._samplesPerXysFile) | 0);
  17576. isDataMissing = true;
  17577. }
  17578. if (!defined(samples[lastIndex * 3])) {
  17579. requestXysChunk(this, (lastIndex / this._samplesPerXysFile) | 0);
  17580. isDataMissing = true;
  17581. }
  17582. if (isDataMissing) {
  17583. return undefined;
  17584. }
  17585. if (!defined(result)) {
  17586. result = new Iau2006XysSample(0.0, 0.0, 0.0);
  17587. } else {
  17588. result.x = 0.0;
  17589. result.y = 0.0;
  17590. result.s = 0.0;
  17591. }
  17592. var x = daysSinceEpoch - firstIndex * this._stepSizeDays;
  17593. var work = this._work;
  17594. var denom = this._denominators;
  17595. var coef = this._coef;
  17596. var xTable = this._xTable;
  17597. var i, j;
  17598. for (i = 0; i <= degree; ++i) {
  17599. work[i] = x - xTable[i];
  17600. }
  17601. for (i = 0; i <= degree; ++i) {
  17602. coef[i] = 1.0;
  17603. for (j = 0; j <= degree; ++j) {
  17604. if (j !== i) {
  17605. coef[i] *= work[j];
  17606. }
  17607. }
  17608. coef[i] *= denom[i];
  17609. var sampleIndex = (firstIndex + i) * 3;
  17610. result.x += coef[i] * samples[sampleIndex++];
  17611. result.y += coef[i] * samples[sampleIndex++];
  17612. result.s += coef[i] * samples[sampleIndex];
  17613. }
  17614. return result;
  17615. };
  17616. function requestXysChunk(xysData, chunkIndex) {
  17617. if (xysData._chunkDownloadsInProgress[chunkIndex]) {
  17618. // Chunk has already been requested.
  17619. return xysData._chunkDownloadsInProgress[chunkIndex];
  17620. }
  17621. var deferred = when.defer();
  17622. xysData._chunkDownloadsInProgress[chunkIndex] = deferred;
  17623. var chunkUrl;
  17624. var xysFileUrlTemplate = xysData._xysFileUrlTemplate;
  17625. if (defined(xysFileUrlTemplate)) {
  17626. chunkUrl = xysFileUrlTemplate.replace('{0}', chunkIndex);
  17627. } else {
  17628. chunkUrl = buildModuleUrl('Assets/IAU2006_XYS/IAU2006_XYS_' + chunkIndex + '.json');
  17629. }
  17630. when(loadJson(chunkUrl), function(chunk) {
  17631. xysData._chunkDownloadsInProgress[chunkIndex] = false;
  17632. var samples = xysData._samples;
  17633. var newSamples = chunk.samples;
  17634. var startIndex = chunkIndex * xysData._samplesPerXysFile * 3;
  17635. for ( var i = 0, len = newSamples.length; i < len; ++i) {
  17636. samples[startIndex + i] = newSamples[i];
  17637. }
  17638. deferred.resolve();
  17639. });
  17640. return deferred.promise;
  17641. }
  17642. return Iau2006XysData;
  17643. });
  17644. /*global define*/
  17645. define('Core/Fullscreen',[
  17646. './defined',
  17647. './defineProperties'
  17648. ], function(
  17649. defined,
  17650. defineProperties) {
  17651. 'use strict';
  17652. var _supportsFullscreen;
  17653. var _names = {
  17654. requestFullscreen : undefined,
  17655. exitFullscreen : undefined,
  17656. fullscreenEnabled : undefined,
  17657. fullscreenElement : undefined,
  17658. fullscreenchange : undefined,
  17659. fullscreenerror : undefined
  17660. };
  17661. /**
  17662. * Browser-independent functions for working with the standard fullscreen API.
  17663. *
  17664. * @exports Fullscreen
  17665. *
  17666. * @see {@link http://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html|W3C Fullscreen Living Specification}
  17667. */
  17668. var Fullscreen = {};
  17669. defineProperties(Fullscreen, {
  17670. /**
  17671. * The element that is currently fullscreen, if any. To simply check if the
  17672. * browser is in fullscreen mode or not, use {@link Fullscreen#fullscreen}.
  17673. * @memberof Fullscreen
  17674. * @type {Object}
  17675. * @readonly
  17676. */
  17677. element : {
  17678. get : function() {
  17679. if (!Fullscreen.supportsFullscreen()) {
  17680. return undefined;
  17681. }
  17682. return document[_names.fullscreenElement];
  17683. }
  17684. },
  17685. /**
  17686. * The name of the event on the document that is fired when fullscreen is
  17687. * entered or exited. This event name is intended for use with addEventListener.
  17688. * In your event handler, to determine if the browser is in fullscreen mode or not,
  17689. * use {@link Fullscreen#fullscreen}.
  17690. * @memberof Fullscreen
  17691. * @type {String}
  17692. * @readonly
  17693. */
  17694. changeEventName : {
  17695. get : function() {
  17696. if (!Fullscreen.supportsFullscreen()) {
  17697. return undefined;
  17698. }
  17699. return _names.fullscreenchange;
  17700. }
  17701. },
  17702. /**
  17703. * The name of the event that is fired when a fullscreen error
  17704. * occurs. This event name is intended for use with addEventListener.
  17705. * @memberof Fullscreen
  17706. * @type {String}
  17707. * @readonly
  17708. */
  17709. errorEventName : {
  17710. get : function() {
  17711. if (!Fullscreen.supportsFullscreen()) {
  17712. return undefined;
  17713. }
  17714. return _names.fullscreenerror;
  17715. }
  17716. },
  17717. /**
  17718. * Determine whether the browser will allow an element to be made fullscreen, or not.
  17719. * For example, by default, iframes cannot go fullscreen unless the containing page
  17720. * adds an "allowfullscreen" attribute (or prefixed equivalent).
  17721. * @memberof Fullscreen
  17722. * @type {Boolean}
  17723. * @readonly
  17724. */
  17725. enabled : {
  17726. get : function() {
  17727. if (!Fullscreen.supportsFullscreen()) {
  17728. return undefined;
  17729. }
  17730. return document[_names.fullscreenEnabled];
  17731. }
  17732. },
  17733. /**
  17734. * Determines if the browser is currently in fullscreen mode.
  17735. * @memberof Fullscreen
  17736. * @type {Boolean}
  17737. * @readonly
  17738. */
  17739. fullscreen : {
  17740. get : function() {
  17741. if (!Fullscreen.supportsFullscreen()) {
  17742. return undefined;
  17743. }
  17744. return Fullscreen.element !== null;
  17745. }
  17746. }
  17747. });
  17748. /**
  17749. * Detects whether the browser supports the standard fullscreen API.
  17750. *
  17751. * @returns {Boolean} <code>true</code> if the browser supports the standard fullscreen API,
  17752. * <code>false</code> otherwise.
  17753. */
  17754. Fullscreen.supportsFullscreen = function() {
  17755. if (defined(_supportsFullscreen)) {
  17756. return _supportsFullscreen;
  17757. }
  17758. _supportsFullscreen = false;
  17759. var body = document.body;
  17760. if (typeof body.requestFullscreen === 'function') {
  17761. // go with the unprefixed, standard set of names
  17762. _names.requestFullscreen = 'requestFullscreen';
  17763. _names.exitFullscreen = 'exitFullscreen';
  17764. _names.fullscreenEnabled = 'fullscreenEnabled';
  17765. _names.fullscreenElement = 'fullscreenElement';
  17766. _names.fullscreenchange = 'fullscreenchange';
  17767. _names.fullscreenerror = 'fullscreenerror';
  17768. _supportsFullscreen = true;
  17769. return _supportsFullscreen;
  17770. }
  17771. //check for the correct combination of prefix plus the various names that browsers use
  17772. var prefixes = ['webkit', 'moz', 'o', 'ms', 'khtml'];
  17773. var name;
  17774. for (var i = 0, len = prefixes.length; i < len; ++i) {
  17775. var prefix = prefixes[i];
  17776. // casing of Fullscreen differs across browsers
  17777. name = prefix + 'RequestFullscreen';
  17778. if (typeof body[name] === 'function') {
  17779. _names.requestFullscreen = name;
  17780. _supportsFullscreen = true;
  17781. } else {
  17782. name = prefix + 'RequestFullScreen';
  17783. if (typeof body[name] === 'function') {
  17784. _names.requestFullscreen = name;
  17785. _supportsFullscreen = true;
  17786. }
  17787. }
  17788. // disagreement about whether it's "exit" as per spec, or "cancel"
  17789. name = prefix + 'ExitFullscreen';
  17790. if (typeof document[name] === 'function') {
  17791. _names.exitFullscreen = name;
  17792. } else {
  17793. name = prefix + 'CancelFullScreen';
  17794. if (typeof document[name] === 'function') {
  17795. _names.exitFullscreen = name;
  17796. }
  17797. }
  17798. // casing of Fullscreen differs across browsers
  17799. name = prefix + 'FullscreenEnabled';
  17800. if (document[name] !== undefined) {
  17801. _names.fullscreenEnabled = name;
  17802. } else {
  17803. name = prefix + 'FullScreenEnabled';
  17804. if (document[name] !== undefined) {
  17805. _names.fullscreenEnabled = name;
  17806. }
  17807. }
  17808. // casing of Fullscreen differs across browsers
  17809. name = prefix + 'FullscreenElement';
  17810. if (document[name] !== undefined) {
  17811. _names.fullscreenElement = name;
  17812. } else {
  17813. name = prefix + 'FullScreenElement';
  17814. if (document[name] !== undefined) {
  17815. _names.fullscreenElement = name;
  17816. }
  17817. }
  17818. // thankfully, event names are all lowercase per spec
  17819. name = prefix + 'fullscreenchange';
  17820. // event names do not have 'on' in the front, but the property on the document does
  17821. if (document['on' + name] !== undefined) {
  17822. //except on IE
  17823. if (prefix === 'ms') {
  17824. name = 'MSFullscreenChange';
  17825. }
  17826. _names.fullscreenchange = name;
  17827. }
  17828. name = prefix + 'fullscreenerror';
  17829. if (document['on' + name] !== undefined) {
  17830. //except on IE
  17831. if (prefix === 'ms') {
  17832. name = 'MSFullscreenError';
  17833. }
  17834. _names.fullscreenerror = name;
  17835. }
  17836. }
  17837. return _supportsFullscreen;
  17838. };
  17839. /**
  17840. * Asynchronously requests the browser to enter fullscreen mode on the given element.
  17841. * If fullscreen mode is not supported by the browser, does nothing.
  17842. *
  17843. * @param {Object} element The HTML element which will be placed into fullscreen mode.
  17844. * @param {HMDVRDevice} [vrDevice] The VR device.
  17845. *
  17846. * @example
  17847. * // Put the entire page into fullscreen.
  17848. * Cesium.Fullscreen.requestFullscreen(document.body)
  17849. *
  17850. * // Place only the Cesium canvas into fullscreen.
  17851. * Cesium.Fullscreen.requestFullscreen(scene.canvas)
  17852. */
  17853. Fullscreen.requestFullscreen = function(element, vrDevice) {
  17854. if (!Fullscreen.supportsFullscreen()) {
  17855. return;
  17856. }
  17857. element[_names.requestFullscreen]({ vrDisplay: vrDevice });
  17858. };
  17859. /**
  17860. * Asynchronously exits fullscreen mode. If the browser is not currently
  17861. * in fullscreen, or if fullscreen mode is not supported by the browser, does nothing.
  17862. */
  17863. Fullscreen.exitFullscreen = function() {
  17864. if (!Fullscreen.supportsFullscreen()) {
  17865. return;
  17866. }
  17867. document[_names.exitFullscreen]();
  17868. };
  17869. return Fullscreen;
  17870. });
  17871. /*global define*/
  17872. define('Core/FeatureDetection',[
  17873. './defaultValue',
  17874. './defined',
  17875. './Fullscreen'
  17876. ], function(
  17877. defaultValue,
  17878. defined,
  17879. Fullscreen) {
  17880. 'use strict';
  17881. var theNavigator;
  17882. if (typeof navigator !== 'undefined') {
  17883. theNavigator = navigator;
  17884. } else {
  17885. theNavigator = {};
  17886. }
  17887. function extractVersion(versionString) {
  17888. var parts = versionString.split('.');
  17889. for (var i = 0, len = parts.length; i < len; ++i) {
  17890. parts[i] = parseInt(parts[i], 10);
  17891. }
  17892. return parts;
  17893. }
  17894. var isChromeResult;
  17895. var chromeVersionResult;
  17896. function isChrome() {
  17897. if (!defined(isChromeResult)) {
  17898. isChromeResult = false;
  17899. // Edge contains Chrome in the user agent too
  17900. if (!isEdge()) {
  17901. var fields = (/ Chrome\/([\.0-9]+)/).exec(theNavigator.userAgent);
  17902. if (fields !== null) {
  17903. isChromeResult = true;
  17904. chromeVersionResult = extractVersion(fields[1]);
  17905. }
  17906. }
  17907. }
  17908. return isChromeResult;
  17909. }
  17910. function chromeVersion() {
  17911. return isChrome() && chromeVersionResult;
  17912. }
  17913. var isSafariResult;
  17914. var safariVersionResult;
  17915. function isSafari() {
  17916. if (!defined(isSafariResult)) {
  17917. isSafariResult = false;
  17918. // Chrome and Edge contain Safari in the user agent too
  17919. if (!isChrome() && !isEdge() && (/ Safari\/[\.0-9]+/).test(theNavigator.userAgent)) {
  17920. var fields = (/ Version\/([\.0-9]+)/).exec(theNavigator.userAgent);
  17921. if (fields !== null) {
  17922. isSafariResult = true;
  17923. safariVersionResult = extractVersion(fields[1]);
  17924. }
  17925. }
  17926. }
  17927. return isSafariResult;
  17928. }
  17929. function safariVersion() {
  17930. return isSafari() && safariVersionResult;
  17931. }
  17932. var isWebkitResult;
  17933. var webkitVersionResult;
  17934. function isWebkit() {
  17935. if (!defined(isWebkitResult)) {
  17936. isWebkitResult = false;
  17937. var fields = (/ AppleWebKit\/([\.0-9]+)(\+?)/).exec(theNavigator.userAgent);
  17938. if (fields !== null) {
  17939. isWebkitResult = true;
  17940. webkitVersionResult = extractVersion(fields[1]);
  17941. webkitVersionResult.isNightly = !!fields[2];
  17942. }
  17943. }
  17944. return isWebkitResult;
  17945. }
  17946. function webkitVersion() {
  17947. return isWebkit() && webkitVersionResult;
  17948. }
  17949. var isInternetExplorerResult;
  17950. var internetExplorerVersionResult;
  17951. function isInternetExplorer() {
  17952. if (!defined(isInternetExplorerResult)) {
  17953. isInternetExplorerResult = false;
  17954. var fields;
  17955. if (theNavigator.appName === 'Microsoft Internet Explorer') {
  17956. fields = /MSIE ([0-9]{1,}[\.0-9]{0,})/.exec(theNavigator.userAgent);
  17957. if (fields !== null) {
  17958. isInternetExplorerResult = true;
  17959. internetExplorerVersionResult = extractVersion(fields[1]);
  17960. }
  17961. } else if (theNavigator.appName === 'Netscape') {
  17962. fields = /Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/.exec(theNavigator.userAgent);
  17963. if (fields !== null) {
  17964. isInternetExplorerResult = true;
  17965. internetExplorerVersionResult = extractVersion(fields[1]);
  17966. }
  17967. }
  17968. }
  17969. return isInternetExplorerResult;
  17970. }
  17971. function internetExplorerVersion() {
  17972. return isInternetExplorer() && internetExplorerVersionResult;
  17973. }
  17974. var isEdgeResult;
  17975. var edgeVersionResult;
  17976. function isEdge() {
  17977. if (!defined(isEdgeResult)) {
  17978. isEdgeResult = false;
  17979. var fields = (/ Edge\/([\.0-9]+)/).exec(theNavigator.userAgent);
  17980. if (fields !== null) {
  17981. isEdgeResult = true;
  17982. edgeVersionResult = extractVersion(fields[1]);
  17983. }
  17984. }
  17985. return isEdgeResult;
  17986. }
  17987. function edgeVersion() {
  17988. return isEdge() && edgeVersionResult;
  17989. }
  17990. var isFirefoxResult;
  17991. var firefoxVersionResult;
  17992. function isFirefox() {
  17993. if (!defined(isFirefoxResult)) {
  17994. isFirefoxResult = false;
  17995. var fields = /Firefox\/([\.0-9]+)/.exec(theNavigator.userAgent);
  17996. if (fields !== null) {
  17997. isFirefoxResult = true;
  17998. firefoxVersionResult = extractVersion(fields[1]);
  17999. }
  18000. }
  18001. return isFirefoxResult;
  18002. }
  18003. var isWindowsResult;
  18004. function isWindows() {
  18005. if (!defined(isWindowsResult)) {
  18006. isWindowsResult = /Windows/i.test(theNavigator.appVersion);
  18007. }
  18008. return isWindowsResult;
  18009. }
  18010. function firefoxVersion() {
  18011. return isFirefox() && firefoxVersionResult;
  18012. }
  18013. var hasPointerEvents;
  18014. function supportsPointerEvents() {
  18015. if (!defined(hasPointerEvents)) {
  18016. //While navigator.pointerEnabled is deprecated in the W3C specification
  18017. //we still need to use it if it exists in order to support browsers
  18018. //that rely on it, such as the Windows WebBrowser control which defines
  18019. //PointerEvent but sets navigator.pointerEnabled to false.
  18020. hasPointerEvents = typeof PointerEvent !== 'undefined' && (!defined(theNavigator.pointerEnabled) || theNavigator.pointerEnabled);
  18021. }
  18022. return hasPointerEvents;
  18023. }
  18024. var imageRenderingValueResult;
  18025. var supportsImageRenderingPixelatedResult;
  18026. function supportsImageRenderingPixelated() {
  18027. if (!defined(supportsImageRenderingPixelatedResult)) {
  18028. var canvas = document.createElement('canvas');
  18029. canvas.setAttribute('style',
  18030. 'image-rendering: -moz-crisp-edges;' +
  18031. 'image-rendering: pixelated;');
  18032. //canvas.style.imageRendering will be undefined, null or an empty string on unsupported browsers.
  18033. var tmp = canvas.style.imageRendering;
  18034. supportsImageRenderingPixelatedResult = defined(tmp) && tmp !== '';
  18035. if (supportsImageRenderingPixelatedResult) {
  18036. imageRenderingValueResult = tmp;
  18037. }
  18038. }
  18039. return supportsImageRenderingPixelatedResult;
  18040. }
  18041. function imageRenderingValue() {
  18042. return supportsImageRenderingPixelated() ? imageRenderingValueResult : undefined;
  18043. }
  18044. /**
  18045. * A set of functions to detect whether the current browser supports
  18046. * various features.
  18047. *
  18048. * @exports FeatureDetection
  18049. */
  18050. var FeatureDetection = {
  18051. isChrome : isChrome,
  18052. chromeVersion : chromeVersion,
  18053. isSafari : isSafari,
  18054. safariVersion : safariVersion,
  18055. isWebkit : isWebkit,
  18056. webkitVersion : webkitVersion,
  18057. isInternetExplorer : isInternetExplorer,
  18058. internetExplorerVersion : internetExplorerVersion,
  18059. isEdge : isEdge,
  18060. edgeVersion : edgeVersion,
  18061. isFirefox : isFirefox,
  18062. firefoxVersion : firefoxVersion,
  18063. isWindows : isWindows,
  18064. hardwareConcurrency : defaultValue(theNavigator.hardwareConcurrency, 3),
  18065. supportsPointerEvents : supportsPointerEvents,
  18066. supportsImageRenderingPixelated: supportsImageRenderingPixelated,
  18067. imageRenderingValue: imageRenderingValue
  18068. };
  18069. /**
  18070. * Detects whether the current browser supports the full screen standard.
  18071. *
  18072. * @returns {Boolean} true if the browser supports the full screen standard, false if not.
  18073. *
  18074. * @see Fullscreen
  18075. * @see {@link http://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html|W3C Fullscreen Living Specification}
  18076. */
  18077. FeatureDetection.supportsFullscreen = function() {
  18078. return Fullscreen.supportsFullscreen();
  18079. };
  18080. /**
  18081. * Detects whether the current browser supports typed arrays.
  18082. *
  18083. * @returns {Boolean} true if the browser supports typed arrays, false if not.
  18084. *
  18085. * @see {@link http://www.khronos.org/registry/typedarray/specs/latest/|Typed Array Specification}
  18086. */
  18087. FeatureDetection.supportsTypedArrays = function() {
  18088. return typeof ArrayBuffer !== 'undefined';
  18089. };
  18090. /**
  18091. * Detects whether the current browser supports Web Workers.
  18092. *
  18093. * @returns {Boolean} true if the browsers supports Web Workers, false if not.
  18094. *
  18095. * @see {@link http://www.w3.org/TR/workers/}
  18096. */
  18097. FeatureDetection.supportsWebWorkers = function() {
  18098. return typeof Worker !== 'undefined';
  18099. };
  18100. return FeatureDetection;
  18101. });
  18102. /*global define*/
  18103. define('Core/Quaternion',[
  18104. './Cartesian3',
  18105. './defaultValue',
  18106. './defined',
  18107. './DeveloperError',
  18108. './FeatureDetection',
  18109. './freezeObject',
  18110. './Math',
  18111. './Matrix3'
  18112. ], function(
  18113. Cartesian3,
  18114. defaultValue,
  18115. defined,
  18116. DeveloperError,
  18117. FeatureDetection,
  18118. freezeObject,
  18119. CesiumMath,
  18120. Matrix3) {
  18121. 'use strict';
  18122. /**
  18123. * A set of 4-dimensional coordinates used to represent rotation in 3-dimensional space.
  18124. * @alias Quaternion
  18125. * @constructor
  18126. *
  18127. * @param {Number} [x=0.0] The X component.
  18128. * @param {Number} [y=0.0] The Y component.
  18129. * @param {Number} [z=0.0] The Z component.
  18130. * @param {Number} [w=0.0] The W component.
  18131. *
  18132. * @see PackableForInterpolation
  18133. */
  18134. function Quaternion(x, y, z, w) {
  18135. /**
  18136. * The X component.
  18137. * @type {Number}
  18138. * @default 0.0
  18139. */
  18140. this.x = defaultValue(x, 0.0);
  18141. /**
  18142. * The Y component.
  18143. * @type {Number}
  18144. * @default 0.0
  18145. */
  18146. this.y = defaultValue(y, 0.0);
  18147. /**
  18148. * The Z component.
  18149. * @type {Number}
  18150. * @default 0.0
  18151. */
  18152. this.z = defaultValue(z, 0.0);
  18153. /**
  18154. * The W component.
  18155. * @type {Number}
  18156. * @default 0.0
  18157. */
  18158. this.w = defaultValue(w, 0.0);
  18159. }
  18160. var fromAxisAngleScratch = new Cartesian3();
  18161. /**
  18162. * Computes a quaternion representing a rotation around an axis.
  18163. *
  18164. * @param {Cartesian3} axis The axis of rotation.
  18165. * @param {Number} angle The angle in radians to rotate around the axis.
  18166. * @param {Quaternion} [result] The object onto which to store the result.
  18167. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided.
  18168. */
  18169. Quaternion.fromAxisAngle = function(axis, angle, result) {
  18170. if (!defined(axis)) {
  18171. throw new DeveloperError('axis is required.');
  18172. }
  18173. if (typeof angle !== 'number') {
  18174. throw new DeveloperError('angle is required and must be a number.');
  18175. }
  18176. var halfAngle = angle / 2.0;
  18177. var s = Math.sin(halfAngle);
  18178. fromAxisAngleScratch = Cartesian3.normalize(axis, fromAxisAngleScratch);
  18179. var x = fromAxisAngleScratch.x * s;
  18180. var y = fromAxisAngleScratch.y * s;
  18181. var z = fromAxisAngleScratch.z * s;
  18182. var w = Math.cos(halfAngle);
  18183. if (!defined(result)) {
  18184. return new Quaternion(x, y, z, w);
  18185. }
  18186. result.x = x;
  18187. result.y = y;
  18188. result.z = z;
  18189. result.w = w;
  18190. return result;
  18191. };
  18192. var fromRotationMatrixNext = [1, 2, 0];
  18193. var fromRotationMatrixQuat = new Array(3);
  18194. /**
  18195. * Computes a Quaternion from the provided Matrix3 instance.
  18196. *
  18197. * @param {Matrix3} matrix The rotation matrix.
  18198. * @param {Quaternion} [result] The object onto which to store the result.
  18199. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided.
  18200. *
  18201. * @see Matrix3.fromQuaternion
  18202. */
  18203. Quaternion.fromRotationMatrix = function(matrix, result) {
  18204. if (!defined(matrix)) {
  18205. throw new DeveloperError('matrix is required.');
  18206. }
  18207. var root;
  18208. var x;
  18209. var y;
  18210. var z;
  18211. var w;
  18212. var m00 = matrix[Matrix3.COLUMN0ROW0];
  18213. var m11 = matrix[Matrix3.COLUMN1ROW1];
  18214. var m22 = matrix[Matrix3.COLUMN2ROW2];
  18215. var trace = m00 + m11 + m22;
  18216. if (trace > 0.0) {
  18217. // |w| > 1/2, may as well choose w > 1/2
  18218. root = Math.sqrt(trace + 1.0); // 2w
  18219. w = 0.5 * root;
  18220. root = 0.5 / root; // 1/(4w)
  18221. x = (matrix[Matrix3.COLUMN1ROW2] - matrix[Matrix3.COLUMN2ROW1]) * root;
  18222. y = (matrix[Matrix3.COLUMN2ROW0] - matrix[Matrix3.COLUMN0ROW2]) * root;
  18223. z = (matrix[Matrix3.COLUMN0ROW1] - matrix[Matrix3.COLUMN1ROW0]) * root;
  18224. } else {
  18225. // |w| <= 1/2
  18226. var next = fromRotationMatrixNext;
  18227. var i = 0;
  18228. if (m11 > m00) {
  18229. i = 1;
  18230. }
  18231. if (m22 > m00 && m22 > m11) {
  18232. i = 2;
  18233. }
  18234. var j = next[i];
  18235. var k = next[j];
  18236. root = Math.sqrt(matrix[Matrix3.getElementIndex(i, i)] - matrix[Matrix3.getElementIndex(j, j)] - matrix[Matrix3.getElementIndex(k, k)] + 1.0);
  18237. var quat = fromRotationMatrixQuat;
  18238. quat[i] = 0.5 * root;
  18239. root = 0.5 / root;
  18240. w = (matrix[Matrix3.getElementIndex(k, j)] - matrix[Matrix3.getElementIndex(j, k)]) * root;
  18241. quat[j] = (matrix[Matrix3.getElementIndex(j, i)] + matrix[Matrix3.getElementIndex(i, j)]) * root;
  18242. quat[k] = (matrix[Matrix3.getElementIndex(k, i)] + matrix[Matrix3.getElementIndex(i, k)]) * root;
  18243. x = -quat[0];
  18244. y = -quat[1];
  18245. z = -quat[2];
  18246. }
  18247. if (!defined(result)) {
  18248. return new Quaternion(x, y, z, w);
  18249. }
  18250. result.x = x;
  18251. result.y = y;
  18252. result.z = z;
  18253. result.w = w;
  18254. return result;
  18255. };
  18256. var scratchHPRQuaternion = new Quaternion();
  18257. /**
  18258. * Computes a rotation from the given heading, pitch and roll angles. Heading is the rotation about the
  18259. * negative z axis. Pitch is the rotation about the negative y axis. Roll is the rotation about
  18260. * the positive x axis.
  18261. *
  18262. * @param {Number} heading The heading angle in radians.
  18263. * @param {Number} pitch The pitch angle in radians.
  18264. * @param {Number} roll The roll angle in radians.
  18265. * @param {Quaternion} [result] The object onto which to store the result.
  18266. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if none was provided.
  18267. */
  18268. Quaternion.fromHeadingPitchRoll = function(heading, pitch, roll, result) {
  18269. if (!defined(heading)) {
  18270. throw new DeveloperError('heading is required.');
  18271. }
  18272. if (!defined(pitch)) {
  18273. throw new DeveloperError('pitch is required.');
  18274. }
  18275. if (!defined(roll)) {
  18276. throw new DeveloperError('roll is required.');
  18277. }
  18278. var rollQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_X, roll, scratchHPRQuaternion);
  18279. var pitchQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Y, -pitch, result);
  18280. result = Quaternion.multiply(pitchQuaternion, rollQuaternion, pitchQuaternion);
  18281. var headingQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Z, -heading, scratchHPRQuaternion);
  18282. return Quaternion.multiply(headingQuaternion, result, result);
  18283. };
  18284. var sampledQuaternionAxis = new Cartesian3();
  18285. var sampledQuaternionRotation = new Cartesian3();
  18286. var sampledQuaternionTempQuaternion = new Quaternion();
  18287. var sampledQuaternionQuaternion0 = new Quaternion();
  18288. var sampledQuaternionQuaternion0Conjugate = new Quaternion();
  18289. /**
  18290. * The number of elements used to pack the object into an array.
  18291. * @type {Number}
  18292. */
  18293. Quaternion.packedLength = 4;
  18294. /**
  18295. * Stores the provided instance into the provided array.
  18296. *
  18297. * @param {Quaternion} value The value to pack.
  18298. * @param {Number[]} array The array to pack into.
  18299. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  18300. *
  18301. * @returns {Number[]} The array that was packed into
  18302. */
  18303. Quaternion.pack = function(value, array, startingIndex) {
  18304. if (!defined(value)) {
  18305. throw new DeveloperError('value is required');
  18306. }
  18307. if (!defined(array)) {
  18308. throw new DeveloperError('array is required');
  18309. }
  18310. startingIndex = defaultValue(startingIndex, 0);
  18311. array[startingIndex++] = value.x;
  18312. array[startingIndex++] = value.y;
  18313. array[startingIndex++] = value.z;
  18314. array[startingIndex] = value.w;
  18315. return array;
  18316. };
  18317. /**
  18318. * Retrieves an instance from a packed array.
  18319. *
  18320. * @param {Number[]} array The packed array.
  18321. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  18322. * @param {Quaternion} [result] The object into which to store the result.
  18323. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided.
  18324. */
  18325. Quaternion.unpack = function(array, startingIndex, result) {
  18326. if (!defined(array)) {
  18327. throw new DeveloperError('array is required');
  18328. }
  18329. startingIndex = defaultValue(startingIndex, 0);
  18330. if (!defined(result)) {
  18331. result = new Quaternion();
  18332. }
  18333. result.x = array[startingIndex];
  18334. result.y = array[startingIndex + 1];
  18335. result.z = array[startingIndex + 2];
  18336. result.w = array[startingIndex + 3];
  18337. return result;
  18338. };
  18339. /**
  18340. * The number of elements used to store the object into an array in its interpolatable form.
  18341. * @type {Number}
  18342. */
  18343. Quaternion.packedInterpolationLength = 3;
  18344. /**
  18345. * Converts a packed array into a form suitable for interpolation.
  18346. *
  18347. * @param {Number[]} packedArray The packed array.
  18348. * @param {Number} [startingIndex=0] The index of the first element to be converted.
  18349. * @param {Number} [lastIndex=packedArray.length] The index of the last element to be converted.
  18350. * @param {Number[]} result The object into which to store the result.
  18351. */
  18352. Quaternion.convertPackedArrayForInterpolation = function(packedArray, startingIndex, lastIndex, result) {
  18353. Quaternion.unpack(packedArray, lastIndex * 4, sampledQuaternionQuaternion0Conjugate);
  18354. Quaternion.conjugate(sampledQuaternionQuaternion0Conjugate, sampledQuaternionQuaternion0Conjugate);
  18355. for (var i = 0, len = lastIndex - startingIndex + 1; i < len; i++) {
  18356. var offset = i * 3;
  18357. Quaternion.unpack(packedArray, (startingIndex + i) * 4, sampledQuaternionTempQuaternion);
  18358. Quaternion.multiply(sampledQuaternionTempQuaternion, sampledQuaternionQuaternion0Conjugate, sampledQuaternionTempQuaternion);
  18359. if (sampledQuaternionTempQuaternion.w < 0) {
  18360. Quaternion.negate(sampledQuaternionTempQuaternion, sampledQuaternionTempQuaternion);
  18361. }
  18362. Quaternion.computeAxis(sampledQuaternionTempQuaternion, sampledQuaternionAxis);
  18363. var angle = Quaternion.computeAngle(sampledQuaternionTempQuaternion);
  18364. result[offset] = sampledQuaternionAxis.x * angle;
  18365. result[offset + 1] = sampledQuaternionAxis.y * angle;
  18366. result[offset + 2] = sampledQuaternionAxis.z * angle;
  18367. }
  18368. };
  18369. /**
  18370. * Retrieves an instance from a packed array converted with {@link convertPackedArrayForInterpolation}.
  18371. *
  18372. * @param {Number[]} array The array previously packed for interpolation.
  18373. * @param {Number[]} sourceArray The original packed array.
  18374. * @param {Number} [startingIndex=0] The startingIndex used to convert the array.
  18375. * @param {Number} [lastIndex=packedArray.length] The lastIndex used to convert the array.
  18376. * @param {Quaternion} [result] The object into which to store the result.
  18377. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided.
  18378. */
  18379. Quaternion.unpackInterpolationResult = function(array, sourceArray, firstIndex, lastIndex, result) {
  18380. if (!defined(result)) {
  18381. result = new Quaternion();
  18382. }
  18383. Cartesian3.fromArray(array, 0, sampledQuaternionRotation);
  18384. var magnitude = Cartesian3.magnitude(sampledQuaternionRotation);
  18385. Quaternion.unpack(sourceArray, lastIndex * 4, sampledQuaternionQuaternion0);
  18386. if (magnitude === 0) {
  18387. Quaternion.clone(Quaternion.IDENTITY, sampledQuaternionTempQuaternion);
  18388. } else {
  18389. Quaternion.fromAxisAngle(sampledQuaternionRotation, magnitude, sampledQuaternionTempQuaternion);
  18390. }
  18391. return Quaternion.multiply(sampledQuaternionTempQuaternion, sampledQuaternionQuaternion0, result);
  18392. };
  18393. /**
  18394. * Duplicates a Quaternion instance.
  18395. *
  18396. * @param {Quaternion} quaternion The quaternion to duplicate.
  18397. * @param {Quaternion} [result] The object onto which to store the result.
  18398. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided. (Returns undefined if quaternion is undefined)
  18399. */
  18400. Quaternion.clone = function(quaternion, result) {
  18401. if (!defined(quaternion)) {
  18402. return undefined;
  18403. }
  18404. if (!defined(result)) {
  18405. return new Quaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w);
  18406. }
  18407. result.x = quaternion.x;
  18408. result.y = quaternion.y;
  18409. result.z = quaternion.z;
  18410. result.w = quaternion.w;
  18411. return result;
  18412. };
  18413. /**
  18414. * Computes the conjugate of the provided quaternion.
  18415. *
  18416. * @param {Quaternion} quaternion The quaternion to conjugate.
  18417. * @param {Quaternion} result The object onto which to store the result.
  18418. * @returns {Quaternion} The modified result parameter.
  18419. */
  18420. Quaternion.conjugate = function(quaternion, result) {
  18421. if (!defined(quaternion)) {
  18422. throw new DeveloperError('quaternion is required');
  18423. }
  18424. if (!defined(result)) {
  18425. throw new DeveloperError('result is required');
  18426. }
  18427. result.x = -quaternion.x;
  18428. result.y = -quaternion.y;
  18429. result.z = -quaternion.z;
  18430. result.w = quaternion.w;
  18431. return result;
  18432. };
  18433. /**
  18434. * Computes magnitude squared for the provided quaternion.
  18435. *
  18436. * @param {Quaternion} quaternion The quaternion to conjugate.
  18437. * @returns {Number} The magnitude squared.
  18438. */
  18439. Quaternion.magnitudeSquared = function(quaternion) {
  18440. if (!defined(quaternion)) {
  18441. throw new DeveloperError('quaternion is required');
  18442. }
  18443. return quaternion.x * quaternion.x + quaternion.y * quaternion.y + quaternion.z * quaternion.z + quaternion.w * quaternion.w;
  18444. };
  18445. /**
  18446. * Computes magnitude for the provided quaternion.
  18447. *
  18448. * @param {Quaternion} quaternion The quaternion to conjugate.
  18449. * @returns {Number} The magnitude.
  18450. */
  18451. Quaternion.magnitude = function(quaternion) {
  18452. return Math.sqrt(Quaternion.magnitudeSquared(quaternion));
  18453. };
  18454. /**
  18455. * Computes the normalized form of the provided quaternion.
  18456. *
  18457. * @param {Quaternion} quaternion The quaternion to normalize.
  18458. * @param {Quaternion} result The object onto which to store the result.
  18459. * @returns {Quaternion} The modified result parameter.
  18460. */
  18461. Quaternion.normalize = function(quaternion, result) {
  18462. if (!defined(result)) {
  18463. throw new DeveloperError('result is required');
  18464. }
  18465. var inverseMagnitude = 1.0 / Quaternion.magnitude(quaternion);
  18466. var x = quaternion.x * inverseMagnitude;
  18467. var y = quaternion.y * inverseMagnitude;
  18468. var z = quaternion.z * inverseMagnitude;
  18469. var w = quaternion.w * inverseMagnitude;
  18470. result.x = x;
  18471. result.y = y;
  18472. result.z = z;
  18473. result.w = w;
  18474. return result;
  18475. };
  18476. /**
  18477. * Computes the inverse of the provided quaternion.
  18478. *
  18479. * @param {Quaternion} quaternion The quaternion to normalize.
  18480. * @param {Quaternion} result The object onto which to store the result.
  18481. * @returns {Quaternion} The modified result parameter.
  18482. */
  18483. Quaternion.inverse = function(quaternion, result) {
  18484. if (!defined(result)) {
  18485. throw new DeveloperError('result is required');
  18486. }
  18487. var magnitudeSquared = Quaternion.magnitudeSquared(quaternion);
  18488. result = Quaternion.conjugate(quaternion, result);
  18489. return Quaternion.multiplyByScalar(result, 1.0 / magnitudeSquared, result);
  18490. };
  18491. /**
  18492. * Computes the componentwise sum of two quaternions.
  18493. *
  18494. * @param {Quaternion} left The first quaternion.
  18495. * @param {Quaternion} right The second quaternion.
  18496. * @param {Quaternion} result The object onto which to store the result.
  18497. * @returns {Quaternion} The modified result parameter.
  18498. */
  18499. Quaternion.add = function(left, right, result) {
  18500. if (!defined(left)) {
  18501. throw new DeveloperError('left is required');
  18502. }
  18503. if (!defined(right)) {
  18504. throw new DeveloperError('right is required');
  18505. }
  18506. if (!defined(result)) {
  18507. throw new DeveloperError('result is required');
  18508. }
  18509. result.x = left.x + right.x;
  18510. result.y = left.y + right.y;
  18511. result.z = left.z + right.z;
  18512. result.w = left.w + right.w;
  18513. return result;
  18514. };
  18515. /**
  18516. * Computes the componentwise difference of two quaternions.
  18517. *
  18518. * @param {Quaternion} left The first quaternion.
  18519. * @param {Quaternion} right The second quaternion.
  18520. * @param {Quaternion} result The object onto which to store the result.
  18521. * @returns {Quaternion} The modified result parameter.
  18522. */
  18523. Quaternion.subtract = function(left, right, result) {
  18524. if (!defined(left)) {
  18525. throw new DeveloperError('left is required');
  18526. }
  18527. if (!defined(right)) {
  18528. throw new DeveloperError('right is required');
  18529. }
  18530. if (!defined(result)) {
  18531. throw new DeveloperError('result is required');
  18532. }
  18533. result.x = left.x - right.x;
  18534. result.y = left.y - right.y;
  18535. result.z = left.z - right.z;
  18536. result.w = left.w - right.w;
  18537. return result;
  18538. };
  18539. /**
  18540. * Negates the provided quaternion.
  18541. *
  18542. * @param {Quaternion} quaternion The quaternion to be negated.
  18543. * @param {Quaternion} result The object onto which to store the result.
  18544. * @returns {Quaternion} The modified result parameter.
  18545. */
  18546. Quaternion.negate = function(quaternion, result) {
  18547. if (!defined(quaternion)) {
  18548. throw new DeveloperError('quaternion is required');
  18549. }
  18550. if (!defined(result)) {
  18551. throw new DeveloperError('result is required');
  18552. }
  18553. result.x = -quaternion.x;
  18554. result.y = -quaternion.y;
  18555. result.z = -quaternion.z;
  18556. result.w = -quaternion.w;
  18557. return result;
  18558. };
  18559. /**
  18560. * Computes the dot (scalar) product of two quaternions.
  18561. *
  18562. * @param {Quaternion} left The first quaternion.
  18563. * @param {Quaternion} right The second quaternion.
  18564. * @returns {Number} The dot product.
  18565. */
  18566. Quaternion.dot = function(left, right) {
  18567. if (!defined(left)) {
  18568. throw new DeveloperError('left is required');
  18569. }
  18570. if (!defined(right)) {
  18571. throw new DeveloperError('right is required');
  18572. }
  18573. return left.x * right.x + left.y * right.y + left.z * right.z + left.w * right.w;
  18574. };
  18575. /**
  18576. * Computes the product of two quaternions.
  18577. *
  18578. * @param {Quaternion} left The first quaternion.
  18579. * @param {Quaternion} right The second quaternion.
  18580. * @param {Quaternion} result The object onto which to store the result.
  18581. * @returns {Quaternion} The modified result parameter.
  18582. */
  18583. Quaternion.multiply = function(left, right, result) {
  18584. if (!defined(left)) {
  18585. throw new DeveloperError('left is required');
  18586. }
  18587. if (!defined(right)) {
  18588. throw new DeveloperError('right is required');
  18589. }
  18590. if (!defined(result)) {
  18591. throw new DeveloperError('result is required');
  18592. }
  18593. var leftX = left.x;
  18594. var leftY = left.y;
  18595. var leftZ = left.z;
  18596. var leftW = left.w;
  18597. var rightX = right.x;
  18598. var rightY = right.y;
  18599. var rightZ = right.z;
  18600. var rightW = right.w;
  18601. var x = leftW * rightX + leftX * rightW + leftY * rightZ - leftZ * rightY;
  18602. var y = leftW * rightY - leftX * rightZ + leftY * rightW + leftZ * rightX;
  18603. var z = leftW * rightZ + leftX * rightY - leftY * rightX + leftZ * rightW;
  18604. var w = leftW * rightW - leftX * rightX - leftY * rightY - leftZ * rightZ;
  18605. result.x = x;
  18606. result.y = y;
  18607. result.z = z;
  18608. result.w = w;
  18609. return result;
  18610. };
  18611. /**
  18612. * Multiplies the provided quaternion componentwise by the provided scalar.
  18613. *
  18614. * @param {Quaternion} quaternion The quaternion to be scaled.
  18615. * @param {Number} scalar The scalar to multiply with.
  18616. * @param {Quaternion} result The object onto which to store the result.
  18617. * @returns {Quaternion} The modified result parameter.
  18618. */
  18619. Quaternion.multiplyByScalar = function(quaternion, scalar, result) {
  18620. if (!defined(quaternion)) {
  18621. throw new DeveloperError('quaternion is required');
  18622. }
  18623. if (typeof scalar !== 'number') {
  18624. throw new DeveloperError('scalar is required and must be a number.');
  18625. }
  18626. if (!defined(result)) {
  18627. throw new DeveloperError('result is required');
  18628. }
  18629. result.x = quaternion.x * scalar;
  18630. result.y = quaternion.y * scalar;
  18631. result.z = quaternion.z * scalar;
  18632. result.w = quaternion.w * scalar;
  18633. return result;
  18634. };
  18635. /**
  18636. * Divides the provided quaternion componentwise by the provided scalar.
  18637. *
  18638. * @param {Quaternion} quaternion The quaternion to be divided.
  18639. * @param {Number} scalar The scalar to divide by.
  18640. * @param {Quaternion} result The object onto which to store the result.
  18641. * @returns {Quaternion} The modified result parameter.
  18642. */
  18643. Quaternion.divideByScalar = function(quaternion, scalar, result) {
  18644. if (!defined(quaternion)) {
  18645. throw new DeveloperError('quaternion is required');
  18646. }
  18647. if (typeof scalar !== 'number') {
  18648. throw new DeveloperError('scalar is required and must be a number.');
  18649. }
  18650. if (!defined(result)) {
  18651. throw new DeveloperError('result is required');
  18652. }
  18653. result.x = quaternion.x / scalar;
  18654. result.y = quaternion.y / scalar;
  18655. result.z = quaternion.z / scalar;
  18656. result.w = quaternion.w / scalar;
  18657. return result;
  18658. };
  18659. /**
  18660. * Computes the axis of rotation of the provided quaternion.
  18661. *
  18662. * @param {Quaternion} quaternion The quaternion to use.
  18663. * @param {Cartesian3} result The object onto which to store the result.
  18664. * @returns {Cartesian3} The modified result parameter.
  18665. */
  18666. Quaternion.computeAxis = function(quaternion, result) {
  18667. if (!defined(quaternion)) {
  18668. throw new DeveloperError('quaternion is required');
  18669. }
  18670. if (!defined(result)) {
  18671. throw new DeveloperError('result is required');
  18672. }
  18673. var w = quaternion.w;
  18674. if (Math.abs(w - 1.0) < CesiumMath.EPSILON6) {
  18675. result.x = result.y = result.z = 0;
  18676. return result;
  18677. }
  18678. var scalar = 1.0 / Math.sqrt(1.0 - (w * w));
  18679. result.x = quaternion.x * scalar;
  18680. result.y = quaternion.y * scalar;
  18681. result.z = quaternion.z * scalar;
  18682. return result;
  18683. };
  18684. /**
  18685. * Computes the angle of rotation of the provided quaternion.
  18686. *
  18687. * @param {Quaternion} quaternion The quaternion to use.
  18688. * @returns {Number} The angle of rotation.
  18689. */
  18690. Quaternion.computeAngle = function(quaternion) {
  18691. if (!defined(quaternion)) {
  18692. throw new DeveloperError('quaternion is required');
  18693. }
  18694. if (Math.abs(quaternion.w - 1.0) < CesiumMath.EPSILON6) {
  18695. return 0.0;
  18696. }
  18697. return 2.0 * Math.acos(quaternion.w);
  18698. };
  18699. var lerpScratch = new Quaternion();
  18700. /**
  18701. * Computes the linear interpolation or extrapolation at t using the provided quaternions.
  18702. *
  18703. * @param {Quaternion} start The value corresponding to t at 0.0.
  18704. * @param {Quaternion} end The value corresponding to t at 1.0.
  18705. * @param {Number} t The point along t at which to interpolate.
  18706. * @param {Quaternion} result The object onto which to store the result.
  18707. * @returns {Quaternion} The modified result parameter.
  18708. */
  18709. Quaternion.lerp = function(start, end, t, result) {
  18710. if (!defined(start)) {
  18711. throw new DeveloperError('start is required.');
  18712. }
  18713. if (!defined(end)) {
  18714. throw new DeveloperError('end is required.');
  18715. }
  18716. if (typeof t !== 'number') {
  18717. throw new DeveloperError('t is required and must be a number.');
  18718. }
  18719. if (!defined(result)) {
  18720. throw new DeveloperError('result is required');
  18721. }
  18722. lerpScratch = Quaternion.multiplyByScalar(end, t, lerpScratch);
  18723. result = Quaternion.multiplyByScalar(start, 1.0 - t, result);
  18724. return Quaternion.add(lerpScratch, result, result);
  18725. };
  18726. var slerpEndNegated = new Quaternion();
  18727. var slerpScaledP = new Quaternion();
  18728. var slerpScaledR = new Quaternion();
  18729. /**
  18730. * Computes the spherical linear interpolation or extrapolation at t using the provided quaternions.
  18731. *
  18732. * @param {Quaternion} start The value corresponding to t at 0.0.
  18733. * @param {Quaternion} end The value corresponding to t at 1.0.
  18734. * @param {Number} t The point along t at which to interpolate.
  18735. * @param {Quaternion} result The object onto which to store the result.
  18736. * @returns {Quaternion} The modified result parameter.
  18737. *
  18738. * @see Quaternion#fastSlerp
  18739. */
  18740. Quaternion.slerp = function(start, end, t, result) {
  18741. if (!defined(start)) {
  18742. throw new DeveloperError('start is required.');
  18743. }
  18744. if (!defined(end)) {
  18745. throw new DeveloperError('end is required.');
  18746. }
  18747. if (typeof t !== 'number') {
  18748. throw new DeveloperError('t is required and must be a number.');
  18749. }
  18750. if (!defined(result)) {
  18751. throw new DeveloperError('result is required');
  18752. }
  18753. var dot = Quaternion.dot(start, end);
  18754. // The angle between start must be acute. Since q and -q represent
  18755. // the same rotation, negate q to get the acute angle.
  18756. var r = end;
  18757. if (dot < 0.0) {
  18758. dot = -dot;
  18759. r = slerpEndNegated = Quaternion.negate(end, slerpEndNegated);
  18760. }
  18761. // dot > 0, as the dot product approaches 1, the angle between the
  18762. // quaternions vanishes. use linear interpolation.
  18763. if (1.0 - dot < CesiumMath.EPSILON6) {
  18764. return Quaternion.lerp(start, r, t, result);
  18765. }
  18766. var theta = Math.acos(dot);
  18767. slerpScaledP = Quaternion.multiplyByScalar(start, Math.sin((1 - t) * theta), slerpScaledP);
  18768. slerpScaledR = Quaternion.multiplyByScalar(r, Math.sin(t * theta), slerpScaledR);
  18769. result = Quaternion.add(slerpScaledP, slerpScaledR, result);
  18770. return Quaternion.multiplyByScalar(result, 1.0 / Math.sin(theta), result);
  18771. };
  18772. /**
  18773. * The logarithmic quaternion function.
  18774. *
  18775. * @param {Quaternion} quaternion The unit quaternion.
  18776. * @param {Cartesian3} result The object onto which to store the result.
  18777. * @returns {Cartesian3} The modified result parameter.
  18778. */
  18779. Quaternion.log = function(quaternion, result) {
  18780. if (!defined(quaternion)) {
  18781. throw new DeveloperError('quaternion is required.');
  18782. }
  18783. if (!defined(result)) {
  18784. throw new DeveloperError('result is required');
  18785. }
  18786. var theta = CesiumMath.acosClamped(quaternion.w);
  18787. var thetaOverSinTheta = 0.0;
  18788. if (theta !== 0.0) {
  18789. thetaOverSinTheta = theta / Math.sin(theta);
  18790. }
  18791. return Cartesian3.multiplyByScalar(quaternion, thetaOverSinTheta, result);
  18792. };
  18793. /**
  18794. * The exponential quaternion function.
  18795. *
  18796. * @param {Cartesian3} cartesian The cartesian.
  18797. * @param {Quaternion} result The object onto which to store the result.
  18798. * @returns {Quaternion} The modified result parameter.
  18799. */
  18800. Quaternion.exp = function(cartesian, result) {
  18801. if (!defined(cartesian)) {
  18802. throw new DeveloperError('cartesian is required.');
  18803. }
  18804. if (!defined(result)) {
  18805. throw new DeveloperError('result is required');
  18806. }
  18807. var theta = Cartesian3.magnitude(cartesian);
  18808. var sinThetaOverTheta = 0.0;
  18809. if (theta !== 0.0) {
  18810. sinThetaOverTheta = Math.sin(theta) / theta;
  18811. }
  18812. result.x = cartesian.x * sinThetaOverTheta;
  18813. result.y = cartesian.y * sinThetaOverTheta;
  18814. result.z = cartesian.z * sinThetaOverTheta;
  18815. result.w = Math.cos(theta);
  18816. return result;
  18817. };
  18818. var squadScratchCartesian0 = new Cartesian3();
  18819. var squadScratchCartesian1 = new Cartesian3();
  18820. var squadScratchQuaternion0 = new Quaternion();
  18821. var squadScratchQuaternion1 = new Quaternion();
  18822. /**
  18823. * Computes an inner quadrangle point.
  18824. * <p>This will compute quaternions that ensure a squad curve is C<sup>1</sup>.</p>
  18825. *
  18826. * @param {Quaternion} q0 The first quaternion.
  18827. * @param {Quaternion} q1 The second quaternion.
  18828. * @param {Quaternion} q2 The third quaternion.
  18829. * @param {Quaternion} result The object onto which to store the result.
  18830. * @returns {Quaternion} The modified result parameter.
  18831. *
  18832. * @see Quaternion#squad
  18833. */
  18834. Quaternion.computeInnerQuadrangle = function(q0, q1, q2, result) {
  18835. if (!defined(q0) || !defined(q1) || !defined(q2)) {
  18836. throw new DeveloperError('q0, q1, and q2 are required.');
  18837. }
  18838. if (!defined(result)) {
  18839. throw new DeveloperError('result is required');
  18840. }
  18841. var qInv = Quaternion.conjugate(q1, squadScratchQuaternion0);
  18842. Quaternion.multiply(qInv, q2, squadScratchQuaternion1);
  18843. var cart0 = Quaternion.log(squadScratchQuaternion1, squadScratchCartesian0);
  18844. Quaternion.multiply(qInv, q0, squadScratchQuaternion1);
  18845. var cart1 = Quaternion.log(squadScratchQuaternion1, squadScratchCartesian1);
  18846. Cartesian3.add(cart0, cart1, cart0);
  18847. Cartesian3.multiplyByScalar(cart0, 0.25, cart0);
  18848. Cartesian3.negate(cart0, cart0);
  18849. Quaternion.exp(cart0, squadScratchQuaternion0);
  18850. return Quaternion.multiply(q1, squadScratchQuaternion0, result);
  18851. };
  18852. /**
  18853. * Computes the spherical quadrangle interpolation between quaternions.
  18854. *
  18855. * @param {Quaternion} q0 The first quaternion.
  18856. * @param {Quaternion} q1 The second quaternion.
  18857. * @param {Quaternion} s0 The first inner quadrangle.
  18858. * @param {Quaternion} s1 The second inner quadrangle.
  18859. * @param {Number} t The time in [0,1] used to interpolate.
  18860. * @param {Quaternion} result The object onto which to store the result.
  18861. * @returns {Quaternion} The modified result parameter.
  18862. *
  18863. *
  18864. * @example
  18865. * // 1. compute the squad interpolation between two quaternions on a curve
  18866. * var s0 = Cesium.Quaternion.computeInnerQuadrangle(quaternions[i - 1], quaternions[i], quaternions[i + 1], new Cesium.Quaternion());
  18867. * var s1 = Cesium.Quaternion.computeInnerQuadrangle(quaternions[i], quaternions[i + 1], quaternions[i + 2], new Cesium.Quaternion());
  18868. * var q = Cesium.Quaternion.squad(quaternions[i], quaternions[i + 1], s0, s1, t, new Cesium.Quaternion());
  18869. *
  18870. * // 2. compute the squad interpolation as above but where the first quaternion is a end point.
  18871. * var s1 = Cesium.Quaternion.computeInnerQuadrangle(quaternions[0], quaternions[1], quaternions[2], new Cesium.Quaternion());
  18872. * var q = Cesium.Quaternion.squad(quaternions[0], quaternions[1], quaternions[0], s1, t, new Cesium.Quaternion());
  18873. *
  18874. * @see Quaternion#computeInnerQuadrangle
  18875. */
  18876. Quaternion.squad = function(q0, q1, s0, s1, t, result) {
  18877. if (!defined(q0) || !defined(q1) || !defined(s0) || !defined(s1)) {
  18878. throw new DeveloperError('q0, q1, s0, and s1 are required.');
  18879. }
  18880. if (typeof t !== 'number') {
  18881. throw new DeveloperError('t is required and must be a number.');
  18882. }
  18883. if (!defined(result)) {
  18884. throw new DeveloperError('result is required');
  18885. }
  18886. var slerp0 = Quaternion.slerp(q0, q1, t, squadScratchQuaternion0);
  18887. var slerp1 = Quaternion.slerp(s0, s1, t, squadScratchQuaternion1);
  18888. return Quaternion.slerp(slerp0, slerp1, 2.0 * t * (1.0 - t), result);
  18889. };
  18890. var fastSlerpScratchQuaternion = new Quaternion();
  18891. var opmu = 1.90110745351730037;
  18892. var u = FeatureDetection.supportsTypedArrays() ? new Float32Array(8) : [];
  18893. var v = FeatureDetection.supportsTypedArrays() ? new Float32Array(8) : [];
  18894. var bT = FeatureDetection.supportsTypedArrays() ? new Float32Array(8) : [];
  18895. var bD = FeatureDetection.supportsTypedArrays() ? new Float32Array(8) : [];
  18896. for (var i = 0; i < 7; ++i) {
  18897. var s = i + 1.0;
  18898. var t = 2.0 * s + 1.0;
  18899. u[i] = 1.0 / (s * t);
  18900. v[i] = s / t;
  18901. }
  18902. u[7] = opmu / (8.0 * 17.0);
  18903. v[7] = opmu * 8.0 / 17.0;
  18904. /**
  18905. * Computes the spherical linear interpolation or extrapolation at t using the provided quaternions.
  18906. * This implementation is faster than {@link Quaternion#slerp}, but is only accurate up to 10<sup>-6</sup>.
  18907. *
  18908. * @param {Quaternion} start The value corresponding to t at 0.0.
  18909. * @param {Quaternion} end The value corresponding to t at 1.0.
  18910. * @param {Number} t The point along t at which to interpolate.
  18911. * @param {Quaternion} result The object onto which to store the result.
  18912. * @returns {Quaternion} The modified result parameter.
  18913. *
  18914. * @see Quaternion#slerp
  18915. */
  18916. Quaternion.fastSlerp = function(start, end, t, result) {
  18917. if (!defined(start)) {
  18918. throw new DeveloperError('start is required.');
  18919. }
  18920. if (!defined(end)) {
  18921. throw new DeveloperError('end is required.');
  18922. }
  18923. if (typeof t !== 'number') {
  18924. throw new DeveloperError('t is required and must be a number.');
  18925. }
  18926. if (!defined(result)) {
  18927. throw new DeveloperError('result is required');
  18928. }
  18929. var x = Quaternion.dot(start, end);
  18930. var sign;
  18931. if (x >= 0) {
  18932. sign = 1.0;
  18933. } else {
  18934. sign = -1.0;
  18935. x = -x;
  18936. }
  18937. var xm1 = x - 1.0;
  18938. var d = 1.0 - t;
  18939. var sqrT = t * t;
  18940. var sqrD = d * d;
  18941. for (var i = 7; i >= 0; --i) {
  18942. bT[i] = (u[i] * sqrT - v[i]) * xm1;
  18943. bD[i] = (u[i] * sqrD - v[i]) * xm1;
  18944. }
  18945. var cT = sign * t * (
  18946. 1.0 + bT[0] * (1.0 + bT[1] * (1.0 + bT[2] * (1.0 + bT[3] * (
  18947. 1.0 + bT[4] * (1.0 + bT[5] * (1.0 + bT[6] * (1.0 + bT[7]))))))));
  18948. var cD = d * (
  18949. 1.0 + bD[0] * (1.0 + bD[1] * (1.0 + bD[2] * (1.0 + bD[3] * (
  18950. 1.0 + bD[4] * (1.0 + bD[5] * (1.0 + bD[6] * (1.0 + bD[7]))))))));
  18951. var temp = Quaternion.multiplyByScalar(start, cD, fastSlerpScratchQuaternion);
  18952. Quaternion.multiplyByScalar(end, cT, result);
  18953. return Quaternion.add(temp, result, result);
  18954. };
  18955. /**
  18956. * Computes the spherical quadrangle interpolation between quaternions.
  18957. * An implementation that is faster than {@link Quaternion#squad}, but less accurate.
  18958. *
  18959. * @param {Quaternion} q0 The first quaternion.
  18960. * @param {Quaternion} q1 The second quaternion.
  18961. * @param {Quaternion} s0 The first inner quadrangle.
  18962. * @param {Quaternion} s1 The second inner quadrangle.
  18963. * @param {Number} t The time in [0,1] used to interpolate.
  18964. * @param {Quaternion} result The object onto which to store the result.
  18965. * @returns {Quaternion} The modified result parameter or a new instance if none was provided.
  18966. *
  18967. * @see Quaternion#squad
  18968. */
  18969. Quaternion.fastSquad = function(q0, q1, s0, s1, t, result) {
  18970. if (!defined(q0) || !defined(q1) || !defined(s0) || !defined(s1)) {
  18971. throw new DeveloperError('q0, q1, s0, and s1 are required.');
  18972. }
  18973. if (typeof t !== 'number') {
  18974. throw new DeveloperError('t is required and must be a number.');
  18975. }
  18976. if (!defined(result)) {
  18977. throw new DeveloperError('result is required');
  18978. }
  18979. var slerp0 = Quaternion.fastSlerp(q0, q1, t, squadScratchQuaternion0);
  18980. var slerp1 = Quaternion.fastSlerp(s0, s1, t, squadScratchQuaternion1);
  18981. return Quaternion.fastSlerp(slerp0, slerp1, 2.0 * t * (1.0 - t), result);
  18982. };
  18983. /**
  18984. * Compares the provided quaternions componentwise and returns
  18985. * <code>true</code> if they are equal, <code>false</code> otherwise.
  18986. *
  18987. * @param {Quaternion} [left] The first quaternion.
  18988. * @param {Quaternion} [right] The second quaternion.
  18989. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  18990. */
  18991. Quaternion.equals = function(left, right) {
  18992. return (left === right) ||
  18993. ((defined(left)) &&
  18994. (defined(right)) &&
  18995. (left.x === right.x) &&
  18996. (left.y === right.y) &&
  18997. (left.z === right.z) &&
  18998. (left.w === right.w));
  18999. };
  19000. /**
  19001. * Compares the provided quaternions componentwise and returns
  19002. * <code>true</code> if they are within the provided epsilon,
  19003. * <code>false</code> otherwise.
  19004. *
  19005. * @param {Quaternion} [left] The first quaternion.
  19006. * @param {Quaternion} [right] The second quaternion.
  19007. * @param {Number} epsilon The epsilon to use for equality testing.
  19008. * @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
  19009. */
  19010. Quaternion.equalsEpsilon = function(left, right, epsilon) {
  19011. if (typeof epsilon !== 'number') {
  19012. throw new DeveloperError('epsilon is required and must be a number.');
  19013. }
  19014. return (left === right) ||
  19015. ((defined(left)) &&
  19016. (defined(right)) &&
  19017. (Math.abs(left.x - right.x) <= epsilon) &&
  19018. (Math.abs(left.y - right.y) <= epsilon) &&
  19019. (Math.abs(left.z - right.z) <= epsilon) &&
  19020. (Math.abs(left.w - right.w) <= epsilon));
  19021. };
  19022. /**
  19023. * An immutable Quaternion instance initialized to (0.0, 0.0, 0.0, 0.0).
  19024. *
  19025. * @type {Quaternion}
  19026. * @constant
  19027. */
  19028. Quaternion.ZERO = freezeObject(new Quaternion(0.0, 0.0, 0.0, 0.0));
  19029. /**
  19030. * An immutable Quaternion instance initialized to (0.0, 0.0, 0.0, 1.0).
  19031. *
  19032. * @type {Quaternion}
  19033. * @constant
  19034. */
  19035. Quaternion.IDENTITY = freezeObject(new Quaternion(0.0, 0.0, 0.0, 1.0));
  19036. /**
  19037. * Duplicates this Quaternion instance.
  19038. *
  19039. * @param {Quaternion} [result] The object onto which to store the result.
  19040. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if one was not provided.
  19041. */
  19042. Quaternion.prototype.clone = function(result) {
  19043. return Quaternion.clone(this, result);
  19044. };
  19045. /**
  19046. * Compares this and the provided quaternion componentwise and returns
  19047. * <code>true</code> if they are equal, <code>false</code> otherwise.
  19048. *
  19049. * @param {Quaternion} [right] The right hand side quaternion.
  19050. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  19051. */
  19052. Quaternion.prototype.equals = function(right) {
  19053. return Quaternion.equals(this, right);
  19054. };
  19055. /**
  19056. * Compares this and the provided quaternion componentwise and returns
  19057. * <code>true</code> if they are within the provided epsilon,
  19058. * <code>false</code> otherwise.
  19059. *
  19060. * @param {Quaternion} [right] The right hand side quaternion.
  19061. * @param {Number} epsilon The epsilon to use for equality testing.
  19062. * @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
  19063. */
  19064. Quaternion.prototype.equalsEpsilon = function(right, epsilon) {
  19065. return Quaternion.equalsEpsilon(this, right, epsilon);
  19066. };
  19067. /**
  19068. * Returns a string representing this quaternion in the format (x, y, z, w).
  19069. *
  19070. * @returns {String} A string representing this Quaternion.
  19071. */
  19072. Quaternion.prototype.toString = function() {
  19073. return '(' + this.x + ', ' + this.y + ', ' + this.z + ', ' + this.w + ')';
  19074. };
  19075. return Quaternion;
  19076. });
  19077. /*global define*/
  19078. define('Core/Transforms',[
  19079. '../ThirdParty/when',
  19080. './Cartesian2',
  19081. './Cartesian3',
  19082. './Cartesian4',
  19083. './Cartographic',
  19084. './defaultValue',
  19085. './defined',
  19086. './deprecationWarning',
  19087. './DeveloperError',
  19088. './EarthOrientationParameters',
  19089. './EarthOrientationParametersSample',
  19090. './Ellipsoid',
  19091. './HeadingPitchRoll',
  19092. './Iau2006XysData',
  19093. './Iau2006XysSample',
  19094. './JulianDate',
  19095. './Math',
  19096. './Matrix3',
  19097. './Matrix4',
  19098. './Quaternion',
  19099. './TimeConstants'
  19100. ], function(
  19101. when,
  19102. Cartesian2,
  19103. Cartesian3,
  19104. Cartesian4,
  19105. Cartographic,
  19106. defaultValue,
  19107. defined,
  19108. deprecationWarning,
  19109. DeveloperError,
  19110. EarthOrientationParameters,
  19111. EarthOrientationParametersSample,
  19112. Ellipsoid,
  19113. HeadingPitchRoll,
  19114. Iau2006XysData,
  19115. Iau2006XysSample,
  19116. JulianDate,
  19117. CesiumMath,
  19118. Matrix3,
  19119. Matrix4,
  19120. Quaternion,
  19121. TimeConstants) {
  19122. 'use strict';
  19123. /**
  19124. * Contains functions for transforming positions to various reference frames.
  19125. *
  19126. * @exports Transforms
  19127. */
  19128. var Transforms = {};
  19129. var eastNorthUpToFixedFrameNormal = new Cartesian3();
  19130. var eastNorthUpToFixedFrameTangent = new Cartesian3();
  19131. var eastNorthUpToFixedFrameBitangent = new Cartesian3();
  19132. /**
  19133. * Computes a 4x4 transformation matrix from a reference frame with an east-north-up axes
  19134. * centered at the provided origin to the provided ellipsoid's fixed reference frame.
  19135. * The local axes are defined as:
  19136. * <ul>
  19137. * <li>The <code>x</code> axis points in the local east direction.</li>
  19138. * <li>The <code>y</code> axis points in the local north direction.</li>
  19139. * <li>The <code>z</code> axis points in the direction of the ellipsoid surface normal which passes through the position.</li>
  19140. * </ul>
  19141. *
  19142. * @param {Cartesian3} origin The center point of the local reference frame.
  19143. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
  19144. * @param {Matrix4} [result] The object onto which to store the result.
  19145. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
  19146. *
  19147. * @example
  19148. * // Get the transform from local east-north-up at cartographic (0.0, 0.0) to Earth's fixed frame.
  19149. * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  19150. * var transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);
  19151. */
  19152. Transforms.eastNorthUpToFixedFrame = function(origin, ellipsoid, result) {
  19153. if (!defined(origin)) {
  19154. throw new DeveloperError('origin is required.');
  19155. }
  19156. // If x and y are zero, assume origin is at a pole, which is a special case.
  19157. if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) &&
  19158. CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) {
  19159. var sign = CesiumMath.sign(origin.z);
  19160. if (!defined(result)) {
  19161. return new Matrix4(
  19162. 0.0, -sign, 0.0, origin.x,
  19163. 1.0, 0.0, 0.0, origin.y,
  19164. 0.0, 0.0, sign, origin.z,
  19165. 0.0, 0.0, 0.0, 1.0);
  19166. }
  19167. result[0] = 0.0;
  19168. result[1] = 1.0;
  19169. result[2] = 0.0;
  19170. result[3] = 0.0;
  19171. result[4] = -sign;
  19172. result[5] = 0.0;
  19173. result[6] = 0.0;
  19174. result[7] = 0.0;
  19175. result[8] = 0.0;
  19176. result[9] = 0.0;
  19177. result[10] = sign;
  19178. result[11] = 0.0;
  19179. result[12] = origin.x;
  19180. result[13] = origin.y;
  19181. result[14] = origin.z;
  19182. result[15] = 1.0;
  19183. return result;
  19184. }
  19185. var normal = eastNorthUpToFixedFrameNormal;
  19186. var tangent = eastNorthUpToFixedFrameTangent;
  19187. var bitangent = eastNorthUpToFixedFrameBitangent;
  19188. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  19189. ellipsoid.geodeticSurfaceNormal(origin, normal);
  19190. tangent.x = -origin.y;
  19191. tangent.y = origin.x;
  19192. tangent.z = 0.0;
  19193. Cartesian3.normalize(tangent, tangent);
  19194. Cartesian3.cross(normal, tangent, bitangent);
  19195. if (!defined(result)) {
  19196. return new Matrix4(
  19197. tangent.x, bitangent.x, normal.x, origin.x,
  19198. tangent.y, bitangent.y, normal.y, origin.y,
  19199. tangent.z, bitangent.z, normal.z, origin.z,
  19200. 0.0, 0.0, 0.0, 1.0);
  19201. }
  19202. result[0] = tangent.x;
  19203. result[1] = tangent.y;
  19204. result[2] = tangent.z;
  19205. result[3] = 0.0;
  19206. result[4] = bitangent.x;
  19207. result[5] = bitangent.y;
  19208. result[6] = bitangent.z;
  19209. result[7] = 0.0;
  19210. result[8] = normal.x;
  19211. result[9] = normal.y;
  19212. result[10] = normal.z;
  19213. result[11] = 0.0;
  19214. result[12] = origin.x;
  19215. result[13] = origin.y;
  19216. result[14] = origin.z;
  19217. result[15] = 1.0;
  19218. return result;
  19219. };
  19220. var northEastDownToFixedFrameNormal = new Cartesian3();
  19221. var northEastDownToFixedFrameTangent = new Cartesian3();
  19222. var northEastDownToFixedFrameBitangent = new Cartesian3();
  19223. /**
  19224. * Computes a 4x4 transformation matrix from a reference frame with an north-east-down axes
  19225. * centered at the provided origin to the provided ellipsoid's fixed reference frame.
  19226. * The local axes are defined as:
  19227. * <ul>
  19228. * <li>The <code>x</code> axis points in the local north direction.</li>
  19229. * <li>The <code>y</code> axis points in the local east direction.</li>
  19230. * <li>The <code>z</code> axis points in the opposite direction of the ellipsoid surface normal which passes through the position.</li>
  19231. * </ul>
  19232. *
  19233. * @param {Cartesian3} origin The center point of the local reference frame.
  19234. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
  19235. * @param {Matrix4} [result] The object onto which to store the result.
  19236. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
  19237. *
  19238. * @example
  19239. * // Get the transform from local north-east-down at cartographic (0.0, 0.0) to Earth's fixed frame.
  19240. * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  19241. * var transform = Cesium.Transforms.northEastDownToFixedFrame(center);
  19242. */
  19243. Transforms.northEastDownToFixedFrame = function(origin, ellipsoid, result) {
  19244. if (!defined(origin)) {
  19245. throw new DeveloperError('origin is required.');
  19246. }
  19247. if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) &&
  19248. CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) {
  19249. // The poles are special cases. If x and y are zero, assume origin is at a pole.
  19250. var sign = CesiumMath.sign(origin.z);
  19251. if (!defined(result)) {
  19252. return new Matrix4(
  19253. -sign, 0.0, 0.0, origin.x,
  19254. 0.0, 1.0, 0.0, origin.y,
  19255. 0.0, 0.0, -sign, origin.z,
  19256. 0.0, 0.0, 0.0, 1.0);
  19257. }
  19258. result[0] = -sign;
  19259. result[1] = 0.0;
  19260. result[2] = 0.0;
  19261. result[3] = 0.0;
  19262. result[4] = 0.0;
  19263. result[5] = 1.0;
  19264. result[6] = 0.0;
  19265. result[7] = 0.0;
  19266. result[8] = 0.0;
  19267. result[9] = 0.0;
  19268. result[10] = -sign;
  19269. result[11] = 0.0;
  19270. result[12] = origin.x;
  19271. result[13] = origin.y;
  19272. result[14] = origin.z;
  19273. result[15] = 1.0;
  19274. return result;
  19275. }
  19276. var normal = northEastDownToFixedFrameNormal;
  19277. var tangent = northEastDownToFixedFrameTangent;
  19278. var bitangent = northEastDownToFixedFrameBitangent;
  19279. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  19280. ellipsoid.geodeticSurfaceNormal(origin, normal);
  19281. tangent.x = -origin.y;
  19282. tangent.y = origin.x;
  19283. tangent.z = 0.0;
  19284. Cartesian3.normalize(tangent, tangent);
  19285. Cartesian3.cross(normal, tangent, bitangent);
  19286. if (!defined(result)) {
  19287. return new Matrix4(
  19288. bitangent.x, tangent.x, -normal.x, origin.x,
  19289. bitangent.y, tangent.y, -normal.y, origin.y,
  19290. bitangent.z, tangent.z, -normal.z, origin.z,
  19291. 0.0, 0.0, 0.0, 1.0);
  19292. }
  19293. result[0] = bitangent.x;
  19294. result[1] = bitangent.y;
  19295. result[2] = bitangent.z;
  19296. result[3] = 0.0;
  19297. result[4] = tangent.x;
  19298. result[5] = tangent.y;
  19299. result[6] = tangent.z;
  19300. result[7] = 0.0;
  19301. result[8] = -normal.x;
  19302. result[9] = -normal.y;
  19303. result[10] = -normal.z;
  19304. result[11] = 0.0;
  19305. result[12] = origin.x;
  19306. result[13] = origin.y;
  19307. result[14] = origin.z;
  19308. result[15] = 1.0;
  19309. return result;
  19310. };
  19311. /**
  19312. * Computes a 4x4 transformation matrix from a reference frame with an north-up-east axes
  19313. * centered at the provided origin to the provided ellipsoid's fixed reference frame.
  19314. * The local axes are defined as:
  19315. * <ul>
  19316. * <li>The <code>x</code> axis points in the local north direction.</li>
  19317. * <li>The <code>y</code> axis points in the direction of the ellipsoid surface normal which passes through the position.</li>
  19318. * <li>The <code>z</code> axis points in the local east direction.</li>
  19319. * </ul>
  19320. *
  19321. * @param {Cartesian3} origin The center point of the local reference frame.
  19322. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
  19323. * @param {Matrix4} [result] The object onto which to store the result.
  19324. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
  19325. *
  19326. * @example
  19327. * // Get the transform from local north-up-east at cartographic (0.0, 0.0) to Earth's fixed frame.
  19328. * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  19329. * var transform = Cesium.Transforms.northUpEastToFixedFrame(center);
  19330. */
  19331. Transforms.northUpEastToFixedFrame = function(origin, ellipsoid, result) {
  19332. if (!defined(origin)) {
  19333. throw new DeveloperError('origin is required.');
  19334. }
  19335. // If x and y are zero, assume origin is at a pole, which is a special case.
  19336. if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) &&
  19337. CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) {
  19338. var sign = CesiumMath.sign(origin.z);
  19339. if (!defined(result)) {
  19340. return new Matrix4(
  19341. -sign, 0.0, 0.0, origin.x,
  19342. 0.0, 0.0, 1.0, origin.y,
  19343. 0.0, sign, 0.0, origin.z,
  19344. 0.0, 0.0, 0.0, 1.0);
  19345. }
  19346. result[0] = -sign;
  19347. result[1] = 0.0;
  19348. result[2] = 0.0;
  19349. result[3] = 0.0;
  19350. result[4] = 0.0;
  19351. result[5] = 0.0;
  19352. result[6] = sign;
  19353. result[7] = 0.0;
  19354. result[8] = 0.0;
  19355. result[9] = 1.0;
  19356. result[10] = 0.0;
  19357. result[11] = 0.0;
  19358. result[12] = origin.x;
  19359. result[13] = origin.y;
  19360. result[14] = origin.z;
  19361. result[15] = 1.0;
  19362. return result;
  19363. }
  19364. var normal = eastNorthUpToFixedFrameNormal;
  19365. var tangent = eastNorthUpToFixedFrameTangent;
  19366. var bitangent = eastNorthUpToFixedFrameBitangent;
  19367. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  19368. ellipsoid.geodeticSurfaceNormal(origin, normal);
  19369. tangent.x = -origin.y;
  19370. tangent.y = origin.x;
  19371. tangent.z = 0.0;
  19372. Cartesian3.normalize(tangent, tangent);
  19373. Cartesian3.cross(normal, tangent, bitangent);
  19374. if (!defined(result)) {
  19375. return new Matrix4(
  19376. bitangent.x, normal.x, tangent.x, origin.x,
  19377. bitangent.y, normal.y, tangent.y, origin.y,
  19378. bitangent.z, normal.z, tangent.z, origin.z,
  19379. 0.0, 0.0, 0.0, 1.0);
  19380. }
  19381. result[0] = bitangent.x;
  19382. result[1] = bitangent.y;
  19383. result[2] = bitangent.z;
  19384. result[3] = 0.0;
  19385. result[4] = normal.x;
  19386. result[5] = normal.y;
  19387. result[6] = normal.z;
  19388. result[7] = 0.0;
  19389. result[8] = tangent.x;
  19390. result[9] = tangent.y;
  19391. result[10] = tangent.z;
  19392. result[11] = 0.0;
  19393. result[12] = origin.x;
  19394. result[13] = origin.y;
  19395. result[14] = origin.z;
  19396. result[15] = 1.0;
  19397. return result;
  19398. };
  19399. /**
  19400. * Computes a 4x4 transformation matrix from a reference frame with an north-west-up axes
  19401. * centered at the provided origin to the provided ellipsoid's fixed reference frame.
  19402. * The local axes are defined as:
  19403. * <ul>
  19404. * <li>The <code>x</code> axis points in the local north direction.</li>
  19405. * <li>The <code>y</code> axis points in the local west direction.</li>
  19406. * <li>The <code>z</code> axis points in the direction of the ellipsoid surface normal which passes through the position.</li>
  19407. * </ul>
  19408. *
  19409. * @param {Cartesian3} origin The center point of the local reference frame.
  19410. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
  19411. * @param {Matrix4} [result] The object onto which to store the result.
  19412. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
  19413. *
  19414. * @example
  19415. * // Get the transform from local north-West-Up at cartographic (0.0, 0.0) to Earth's fixed frame.
  19416. * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  19417. * var transform = Cesium.Transforms.northWestUpToFixedFrame(center);
  19418. */
  19419. Transforms.northWestUpToFixedFrame = function(origin, ellipsoid, result) {
  19420. if (!defined(origin)) {
  19421. throw new DeveloperError('origin is required.');
  19422. }
  19423. // If x and y are zero, assume origin is at a pole, which is a special case.
  19424. if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) &&
  19425. CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) {
  19426. var sign = CesiumMath.sign(origin.z);
  19427. if (!defined(result)) {
  19428. return new Matrix4(
  19429. -sign, 0.0, 0.0, origin.x,
  19430. 0.0, -1.0, 0.0, origin.y,
  19431. 0.0, 0.0, sign, origin.z,
  19432. 0.0, 0.0, 0.0, 1.0);
  19433. }
  19434. result[0] = -sign;
  19435. result[1] = 0.0;
  19436. result[2] = 0.0;
  19437. result[3] = 0.0;
  19438. result[4] = 0.0;
  19439. result[5] = -1.0;
  19440. result[6] = 0.0;
  19441. result[7] = 0.0;
  19442. result[8] = 0.0;
  19443. result[9] = 0.0;
  19444. result[10] = sign;
  19445. result[11] = 0.0;
  19446. result[12] = origin.x;
  19447. result[13] = origin.y;
  19448. result[14] = origin.z;
  19449. result[15] = 1.0;
  19450. return result;
  19451. }
  19452. var normal = eastNorthUpToFixedFrameNormal;//Up
  19453. var tangent = eastNorthUpToFixedFrameTangent;//East
  19454. var bitangent = eastNorthUpToFixedFrameBitangent;//North
  19455. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  19456. ellipsoid.geodeticSurfaceNormal(origin, normal);
  19457. tangent.x = -origin.y;
  19458. tangent.y = origin.x;
  19459. tangent.z = 0.0;
  19460. Cartesian3.normalize(tangent, tangent);
  19461. Cartesian3.cross(normal, tangent, bitangent);
  19462. if (!defined(result)) {
  19463. return new Matrix4(
  19464. bitangent.x, -tangent.x, normal.x, origin.x,
  19465. bitangent.y, -tangent.y, normal.y, origin.y,
  19466. bitangent.z, -tangent.z, normal.z, origin.z,
  19467. 0.0, 0.0, 0.0, 1.0);
  19468. }
  19469. result[0] = bitangent.x;
  19470. result[1] = bitangent.y;
  19471. result[2] = bitangent.z;
  19472. result[3] = 0.0;
  19473. result[4] = -tangent.x;
  19474. result[5] = -tangent.y;
  19475. result[6] = -tangent.z;
  19476. result[7] = 0.0;
  19477. result[8] = normal.x;
  19478. result[9] = normal.y;
  19479. result[10] = normal.z;
  19480. result[11] = 0.0;
  19481. result[12] = origin.x;
  19482. result[13] = origin.y;
  19483. result[14] = origin.z;
  19484. result[15] = 1.0;
  19485. return result;
  19486. };
  19487. var scratchHPRQuaternion = new Quaternion();
  19488. var scratchScale = new Cartesian3(1.0, 1.0, 1.0);
  19489. var scratchHPRMatrix4 = new Matrix4();
  19490. /**
  19491. * Computes a 4x4 transformation matrix from a reference frame with axes computed from the heading-pitch-roll angles
  19492. * centered at the provided origin to the provided ellipsoid's fixed reference frame. Heading is the rotation from the local north
  19493. * direction where a positive angle is increasing eastward. Pitch is the rotation from the local east-north plane. Positive pitch angles
  19494. * are above the plane. Negative pitch angles are below the plane. Roll is the first rotation applied about the local east axis.
  19495. *
  19496. * @param {Cartesian3} origin The center point of the local reference frame.
  19497. * @param {HeadingPitchRoll} headingPitchRoll The heading, pitch, and roll.
  19498. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
  19499. * @param {Matrix4} [result] The object onto which to store the result.
  19500. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
  19501. *
  19502. * @example
  19503. * // Get the transform from local heading-pitch-roll at cartographic (0.0, 0.0) to Earth's fixed frame.
  19504. * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  19505. * var heading = -Cesium.Math.PI_OVER_TWO;
  19506. * var pitch = Cesium.Math.PI_OVER_FOUR;
  19507. * var roll = 0.0;
  19508. * var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
  19509. * var transform = Cesium.Transforms.headingPitchRollToFixedFrame(center, hpr);
  19510. */
  19511. Transforms.headingPitchRollToFixedFrame = function(origin, headingPitchRoll, pitch, roll, ellipsoid, result) {
  19512. var heading;
  19513. if (typeof headingPitchRoll === 'object') {
  19514. // Shift arguments using assignments to encourage JIT optimization.
  19515. ellipsoid = pitch;
  19516. result = roll;
  19517. heading = headingPitchRoll.heading;
  19518. pitch = headingPitchRoll.pitch;
  19519. roll = headingPitchRoll.roll;
  19520. } else {
  19521. deprecationWarning('headingPitchRollToFixedFrame', 'headingPitchRollToFixedFrame with separate heading, pitch, and roll arguments was deprecated in 1.27. It will be removed in 1.30. Use a HeadingPitchRoll object.');
  19522. heading = headingPitchRoll;
  19523. }
  19524. // checks for required parameters happen in the called functions
  19525. var hprQuaternion = Quaternion.fromHeadingPitchRoll(heading, pitch, roll, scratchHPRQuaternion);
  19526. var hprMatrix = Matrix4.fromTranslationQuaternionRotationScale(Cartesian3.ZERO, hprQuaternion, scratchScale, scratchHPRMatrix4);
  19527. result = Transforms.eastNorthUpToFixedFrame(origin, ellipsoid, result);
  19528. return Matrix4.multiply(result, hprMatrix, result);
  19529. };
  19530. var scratchHPR = new HeadingPitchRoll();
  19531. var scratchENUMatrix4 = new Matrix4();
  19532. var scratchHPRMatrix3 = new Matrix3();
  19533. /**
  19534. * Computes a quaternion from a reference frame with axes computed from the heading-pitch-roll angles
  19535. * centered at the provided origin. Heading is the rotation from the local north
  19536. * direction where a positive angle is increasing eastward. Pitch is the rotation from the local east-north plane. Positive pitch angles
  19537. * are above the plane. Negative pitch angles are below the plane. Roll is the first rotation applied about the local east axis.
  19538. *
  19539. * @param {Cartesian3} origin The center point of the local reference frame.
  19540. * @param {HeadingPitchRoll} headingPitchRoll The heading, pitch, and roll.
  19541. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
  19542. * @param {Quaternion} [result] The object onto which to store the result.
  19543. * @returns {Quaternion} The modified result parameter or a new Quaternion instance if none was provided.
  19544. *
  19545. * @example
  19546. * // Get the quaternion from local heading-pitch-roll at cartographic (0.0, 0.0) to Earth's fixed frame.
  19547. * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  19548. * var heading = -Cesium.Math.PI_OVER_TWO;
  19549. * var pitch = Cesium.Math.PI_OVER_FOUR;
  19550. * var roll = 0.0;
  19551. * var hpr = new HeadingPitchRoll(heading, pitch, roll);
  19552. * var quaternion = Cesium.Transforms.headingPitchRollQuaternion(center, hpr);
  19553. */
  19554. Transforms.headingPitchRollQuaternion = function(origin, headingPitchRoll, pitch, roll, ellipsoid, result) {
  19555. var hpr;
  19556. if (typeof headingPitchRoll === 'object') {
  19557. // Shift arguments using assignment to encourage JIT optimization.
  19558. hpr = headingPitchRoll;
  19559. ellipsoid = pitch;
  19560. result = roll;
  19561. } else {
  19562. deprecationWarning('headingPitchRollQuaternion', 'headingPitchRollQuaternion with separate heading, pitch, and roll arguments was deprecated in 1.27. It will be removed in 1.30. Use a HeadingPitchRoll object.');
  19563. scratchHPR.heading = headingPitchRoll;
  19564. scratchHPR.pitch = pitch;
  19565. scratchHPR.roll = roll;
  19566. hpr = scratchHPR;
  19567. }
  19568. // checks for required parameters happen in the called functions
  19569. var transform = Transforms.headingPitchRollToFixedFrame(origin, hpr, ellipsoid, scratchENUMatrix4);
  19570. var rotation = Matrix4.getRotation(transform, scratchHPRMatrix3);
  19571. return Quaternion.fromRotationMatrix(rotation, result);
  19572. };
  19573. var gmstConstant0 = 6 * 3600 + 41 * 60 + 50.54841;
  19574. var gmstConstant1 = 8640184.812866;
  19575. var gmstConstant2 = 0.093104;
  19576. var gmstConstant3 = -6.2E-6;
  19577. var rateCoef = 1.1772758384668e-19;
  19578. var wgs84WRPrecessing = 7.2921158553E-5;
  19579. var twoPiOverSecondsInDay = CesiumMath.TWO_PI / 86400.0;
  19580. var dateInUtc = new JulianDate();
  19581. /**
  19582. * Computes a rotation matrix to transform a point or vector from True Equator Mean Equinox (TEME) axes to the
  19583. * pseudo-fixed axes at a given time. This method treats the UT1 time standard as equivalent to UTC.
  19584. *
  19585. * @param {JulianDate} date The time at which to compute the rotation matrix.
  19586. * @param {Matrix3} [result] The object onto which to store the result.
  19587. * @returns {Matrix3} The modified result parameter or a new Matrix3 instance if none was provided.
  19588. *
  19589. * @example
  19590. * //Set the view to in the inertial frame.
  19591. * scene.preRender.addEventListener(function(scene, time) {
  19592. * var now = Cesium.JulianDate.now();
  19593. * var offset = Cesium.Matrix4.multiplyByPoint(camera.transform, camera.position, new Cesium.Cartesian3());
  19594. * var transform = Cesium.Matrix4.fromRotationTranslation(Cesium.Transforms.computeTemeToPseudoFixedMatrix(now));
  19595. * var inverseTransform = Cesium.Matrix4.inverseTransformation(transform, new Cesium.Matrix4());
  19596. * Cesium.Matrix4.multiplyByPoint(inverseTransform, offset, offset);
  19597. * camera.lookAtTransform(transform, offset);
  19598. * });
  19599. */
  19600. Transforms.computeTemeToPseudoFixedMatrix = function (date, result) {
  19601. if (!defined(date)) {
  19602. throw new DeveloperError('date is required.');
  19603. }
  19604. // GMST is actually computed using UT1. We're using UTC as an approximation of UT1.
  19605. // We do not want to use the function like convertTaiToUtc in JulianDate because
  19606. // we explicitly do not want to fail when inside the leap second.
  19607. dateInUtc = JulianDate.addSeconds(date, -JulianDate.computeTaiMinusUtc(date), dateInUtc);
  19608. var utcDayNumber = dateInUtc.dayNumber;
  19609. var utcSecondsIntoDay = dateInUtc.secondsOfDay;
  19610. var t;
  19611. var diffDays = utcDayNumber - 2451545;
  19612. if (utcSecondsIntoDay >= 43200.0) {
  19613. t = (diffDays + 0.5) / TimeConstants.DAYS_PER_JULIAN_CENTURY;
  19614. } else {
  19615. t = (diffDays - 0.5) / TimeConstants.DAYS_PER_JULIAN_CENTURY;
  19616. }
  19617. var gmst0 = gmstConstant0 + t * (gmstConstant1 + t * (gmstConstant2 + t * gmstConstant3));
  19618. var angle = (gmst0 * twoPiOverSecondsInDay) % CesiumMath.TWO_PI;
  19619. var ratio = wgs84WRPrecessing + rateCoef * (utcDayNumber - 2451545.5);
  19620. var secondsSinceMidnight = (utcSecondsIntoDay + TimeConstants.SECONDS_PER_DAY * 0.5) % TimeConstants.SECONDS_PER_DAY;
  19621. var gha = angle + (ratio * secondsSinceMidnight);
  19622. var cosGha = Math.cos(gha);
  19623. var sinGha = Math.sin(gha);
  19624. if (!defined(result)) {
  19625. return new Matrix3(cosGha, sinGha, 0.0,
  19626. -sinGha, cosGha, 0.0,
  19627. 0.0, 0.0, 1.0);
  19628. }
  19629. result[0] = cosGha;
  19630. result[1] = -sinGha;
  19631. result[2] = 0.0;
  19632. result[3] = sinGha;
  19633. result[4] = cosGha;
  19634. result[5] = 0.0;
  19635. result[6] = 0.0;
  19636. result[7] = 0.0;
  19637. result[8] = 1.0;
  19638. return result;
  19639. };
  19640. /**
  19641. * The source of IAU 2006 XYS data, used for computing the transformation between the
  19642. * Fixed and ICRF axes.
  19643. * @type {Iau2006XysData}
  19644. *
  19645. * @see Transforms.computeIcrfToFixedMatrix
  19646. * @see Transforms.computeFixedToIcrfMatrix
  19647. *
  19648. * @private
  19649. */
  19650. Transforms.iau2006XysData = new Iau2006XysData();
  19651. /**
  19652. * The source of Earth Orientation Parameters (EOP) data, used for computing the transformation
  19653. * between the Fixed and ICRF axes. By default, zero values are used for all EOP values,
  19654. * yielding a reasonable but not completely accurate representation of the ICRF axes.
  19655. * @type {EarthOrientationParameters}
  19656. *
  19657. * @see Transforms.computeIcrfToFixedMatrix
  19658. * @see Transforms.computeFixedToIcrfMatrix
  19659. *
  19660. * @private
  19661. */
  19662. Transforms.earthOrientationParameters = EarthOrientationParameters.NONE;
  19663. var ttMinusTai = 32.184;
  19664. var j2000ttDays = 2451545.0;
  19665. /**
  19666. * Preloads the data necessary to transform between the ICRF and Fixed axes, in either
  19667. * direction, over a given interval. This function returns a promise that, when resolved,
  19668. * indicates that the preload has completed.
  19669. *
  19670. * @param {TimeInterval} timeInterval The interval to preload.
  19671. * @returns {Promise.<undefined>} A promise that, when resolved, indicates that the preload has completed
  19672. * and evaluation of the transformation between the fixed and ICRF axes will
  19673. * no longer return undefined for a time inside the interval.
  19674. *
  19675. *
  19676. * @example
  19677. * var interval = new Cesium.TimeInterval(...);
  19678. * when(Cesium.Transforms.preloadIcrfFixed(interval), function() {
  19679. * // the data is now loaded
  19680. * });
  19681. *
  19682. * @see Transforms.computeIcrfToFixedMatrix
  19683. * @see Transforms.computeFixedToIcrfMatrix
  19684. * @see when
  19685. */
  19686. Transforms.preloadIcrfFixed = function(timeInterval) {
  19687. var startDayTT = timeInterval.start.dayNumber;
  19688. var startSecondTT = timeInterval.start.secondsOfDay + ttMinusTai;
  19689. var stopDayTT = timeInterval.stop.dayNumber;
  19690. var stopSecondTT = timeInterval.stop.secondsOfDay + ttMinusTai;
  19691. var xysPromise = Transforms.iau2006XysData.preload(startDayTT, startSecondTT, stopDayTT, stopSecondTT);
  19692. var eopPromise = Transforms.earthOrientationParameters.getPromiseToLoad();
  19693. return when.all([xysPromise, eopPromise]);
  19694. };
  19695. /**
  19696. * Computes a rotation matrix to transform a point or vector from the International Celestial
  19697. * Reference Frame (GCRF/ICRF) inertial frame axes to the Earth-Fixed frame axes (ITRF)
  19698. * at a given time. This function may return undefined if the data necessary to
  19699. * do the transformation is not yet loaded.
  19700. *
  19701. * @param {JulianDate} date The time at which to compute the rotation matrix.
  19702. * @param {Matrix3} [result] The object onto which to store the result. If this parameter is
  19703. * not specified, a new instance is created and returned.
  19704. * @returns {Matrix3} The rotation matrix, or undefined if the data necessary to do the
  19705. * transformation is not yet loaded.
  19706. *
  19707. *
  19708. * @example
  19709. * scene.preRender.addEventListener(function(scene, time) {
  19710. * var icrfToFixed = Cesium.Transforms.computeIcrfToFixedMatrix(time);
  19711. * if (Cesium.defined(icrfToFixed)) {
  19712. * var offset = Cesium.Matrix4.multiplyByPoint(camera.transform, camera.position, new Cesium.Cartesian3());
  19713. * var transform = Cesium.Matrix4.fromRotationTranslation(icrfToFixed)
  19714. * var inverseTransform = Cesium.Matrix4.inverseTransformation(transform, new Cesium.Matrix4());
  19715. * Cesium.Matrix4.multiplyByPoint(inverseTransform, offset, offset);
  19716. * camera.lookAtTransform(transform, offset);
  19717. * }
  19718. * });
  19719. *
  19720. * @see Transforms.preloadIcrfFixed
  19721. */
  19722. Transforms.computeIcrfToFixedMatrix = function(date, result) {
  19723. if (!defined(date)) {
  19724. throw new DeveloperError('date is required.');
  19725. }
  19726. if (!defined(result)) {
  19727. result = new Matrix3();
  19728. }
  19729. var fixedToIcrfMtx = Transforms.computeFixedToIcrfMatrix(date, result);
  19730. if (!defined(fixedToIcrfMtx)) {
  19731. return undefined;
  19732. }
  19733. return Matrix3.transpose(fixedToIcrfMtx, result);
  19734. };
  19735. var xysScratch = new Iau2006XysSample(0.0, 0.0, 0.0);
  19736. var eopScratch = new EarthOrientationParametersSample(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
  19737. var rotation1Scratch = new Matrix3();
  19738. var rotation2Scratch = new Matrix3();
  19739. /**
  19740. * Computes a rotation matrix to transform a point or vector from the Earth-Fixed frame axes (ITRF)
  19741. * to the International Celestial Reference Frame (GCRF/ICRF) inertial frame axes
  19742. * at a given time. This function may return undefined if the data necessary to
  19743. * do the transformation is not yet loaded.
  19744. *
  19745. * @param {JulianDate} date The time at which to compute the rotation matrix.
  19746. * @param {Matrix3} [result] The object onto which to store the result. If this parameter is
  19747. * not specified, a new instance is created and returned.
  19748. * @returns {Matrix3} The rotation matrix, or undefined if the data necessary to do the
  19749. * transformation is not yet loaded.
  19750. *
  19751. *
  19752. * @example
  19753. * // Transform a point from the ICRF axes to the Fixed axes.
  19754. * var now = Cesium.JulianDate.now();
  19755. * var pointInFixed = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  19756. * var fixedToIcrf = Cesium.Transforms.computeIcrfToFixedMatrix(now);
  19757. * var pointInInertial = new Cesium.Cartesian3();
  19758. * if (Cesium.defined(fixedToIcrf)) {
  19759. * pointInInertial = Cesium.Matrix3.multiplyByVector(fixedToIcrf, pointInFixed, pointInInertial);
  19760. * }
  19761. *
  19762. * @see Transforms.preloadIcrfFixed
  19763. */
  19764. Transforms.computeFixedToIcrfMatrix = function(date, result) {
  19765. if (!defined(date)) {
  19766. throw new DeveloperError('date is required.');
  19767. }
  19768. if (!defined(result)) {
  19769. result = new Matrix3();
  19770. }
  19771. // Compute pole wander
  19772. var eop = Transforms.earthOrientationParameters.compute(date, eopScratch);
  19773. if (!defined(eop)) {
  19774. return undefined;
  19775. }
  19776. // There is no external conversion to Terrestrial Time (TT).
  19777. // So use International Atomic Time (TAI) and convert using offsets.
  19778. // Here we are assuming that dayTT and secondTT are positive
  19779. var dayTT = date.dayNumber;
  19780. // It's possible here that secondTT could roll over 86400
  19781. // This does not seem to affect the precision (unit tests check for this)
  19782. var secondTT = date.secondsOfDay + ttMinusTai;
  19783. var xys = Transforms.iau2006XysData.computeXysRadians(dayTT, secondTT, xysScratch);
  19784. if (!defined(xys)) {
  19785. return undefined;
  19786. }
  19787. var x = xys.x + eop.xPoleOffset;
  19788. var y = xys.y + eop.yPoleOffset;
  19789. // Compute XYS rotation
  19790. var a = 1.0 / (1.0 + Math.sqrt(1.0 - x * x - y * y));
  19791. var rotation1 = rotation1Scratch;
  19792. rotation1[0] = 1.0 - a * x * x;
  19793. rotation1[3] = -a * x * y;
  19794. rotation1[6] = x;
  19795. rotation1[1] = -a * x * y;
  19796. rotation1[4] = 1 - a * y * y;
  19797. rotation1[7] = y;
  19798. rotation1[2] = -x;
  19799. rotation1[5] = -y;
  19800. rotation1[8] = 1 - a * (x * x + y * y);
  19801. var rotation2 = Matrix3.fromRotationZ(-xys.s, rotation2Scratch);
  19802. var matrixQ = Matrix3.multiply(rotation1, rotation2, rotation1Scratch);
  19803. // Similar to TT conversions above
  19804. // It's possible here that secondTT could roll over 86400
  19805. // This does not seem to affect the precision (unit tests check for this)
  19806. var dateUt1day = date.dayNumber;
  19807. var dateUt1sec = date.secondsOfDay - JulianDate.computeTaiMinusUtc(date) + eop.ut1MinusUtc;
  19808. // Compute Earth rotation angle
  19809. // The IERS standard for era is
  19810. // era = 0.7790572732640 + 1.00273781191135448 * Tu
  19811. // where
  19812. // Tu = JulianDateInUt1 - 2451545.0
  19813. // However, you get much more precision if you make the following simplification
  19814. // era = a + (1 + b) * (JulianDayNumber + FractionOfDay - 2451545)
  19815. // era = a + (JulianDayNumber - 2451545) + FractionOfDay + b (JulianDayNumber - 2451545 + FractionOfDay)
  19816. // era = a + FractionOfDay + b (JulianDayNumber - 2451545 + FractionOfDay)
  19817. // since (JulianDayNumber - 2451545) represents an integer number of revolutions which will be discarded anyway.
  19818. var daysSinceJ2000 = dateUt1day - 2451545;
  19819. var fractionOfDay = dateUt1sec / TimeConstants.SECONDS_PER_DAY;
  19820. var era = 0.7790572732640 + fractionOfDay + 0.00273781191135448 * (daysSinceJ2000 + fractionOfDay);
  19821. era = (era % 1.0) * CesiumMath.TWO_PI;
  19822. var earthRotation = Matrix3.fromRotationZ(era, rotation2Scratch);
  19823. // pseudoFixed to ICRF
  19824. var pfToIcrf = Matrix3.multiply(matrixQ, earthRotation, rotation1Scratch);
  19825. // Compute pole wander matrix
  19826. var cosxp = Math.cos(eop.xPoleWander);
  19827. var cosyp = Math.cos(eop.yPoleWander);
  19828. var sinxp = Math.sin(eop.xPoleWander);
  19829. var sinyp = Math.sin(eop.yPoleWander);
  19830. var ttt = (dayTT - j2000ttDays) + secondTT / TimeConstants.SECONDS_PER_DAY;
  19831. ttt /= 36525.0;
  19832. // approximate sp value in rad
  19833. var sp = -47.0e-6 * ttt * CesiumMath.RADIANS_PER_DEGREE / 3600.0;
  19834. var cossp = Math.cos(sp);
  19835. var sinsp = Math.sin(sp);
  19836. var fToPfMtx = rotation2Scratch;
  19837. fToPfMtx[0] = cosxp * cossp;
  19838. fToPfMtx[1] = cosxp * sinsp;
  19839. fToPfMtx[2] = sinxp;
  19840. fToPfMtx[3] = -cosyp * sinsp + sinyp * sinxp * cossp;
  19841. fToPfMtx[4] = cosyp * cossp + sinyp * sinxp * sinsp;
  19842. fToPfMtx[5] = -sinyp * cosxp;
  19843. fToPfMtx[6] = -sinyp * sinsp - cosyp * sinxp * cossp;
  19844. fToPfMtx[7] = sinyp * cossp - cosyp * sinxp * sinsp;
  19845. fToPfMtx[8] = cosyp * cosxp;
  19846. return Matrix3.multiply(pfToIcrf, fToPfMtx, result);
  19847. };
  19848. var pointToWindowCoordinatesTemp = new Cartesian4();
  19849. /**
  19850. * Transform a point from model coordinates to window coordinates.
  19851. *
  19852. * @param {Matrix4} modelViewProjectionMatrix The 4x4 model-view-projection matrix.
  19853. * @param {Matrix4} viewportTransformation The 4x4 viewport transformation.
  19854. * @param {Cartesian3} point The point to transform.
  19855. * @param {Cartesian2} [result] The object onto which to store the result.
  19856. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if none was provided.
  19857. */
  19858. Transforms.pointToWindowCoordinates = function (modelViewProjectionMatrix, viewportTransformation, point, result) {
  19859. result = Transforms.pointToGLWindowCoordinates(modelViewProjectionMatrix, viewportTransformation, point, result);
  19860. result.y = 2.0 * viewportTransformation[5] - result.y;
  19861. return result;
  19862. };
  19863. /**
  19864. * @private
  19865. */
  19866. Transforms.pointToGLWindowCoordinates = function(modelViewProjectionMatrix, viewportTransformation, point, result) {
  19867. if (!defined(modelViewProjectionMatrix)) {
  19868. throw new DeveloperError('modelViewProjectionMatrix is required.');
  19869. }
  19870. if (!defined(viewportTransformation)) {
  19871. throw new DeveloperError('viewportTransformation is required.');
  19872. }
  19873. if (!defined(point)) {
  19874. throw new DeveloperError('point is required.');
  19875. }
  19876. if (!defined(result)) {
  19877. result = new Cartesian2();
  19878. }
  19879. var tmp = pointToWindowCoordinatesTemp;
  19880. Matrix4.multiplyByVector(modelViewProjectionMatrix, Cartesian4.fromElements(point.x, point.y, point.z, 1, tmp), tmp);
  19881. Cartesian4.multiplyByScalar(tmp, 1.0 / tmp.w, tmp);
  19882. Matrix4.multiplyByVector(viewportTransformation, tmp, tmp);
  19883. return Cartesian2.fromCartesian4(tmp, result);
  19884. };
  19885. var normalScratch = new Cartesian3();
  19886. var rightScratch = new Cartesian3();
  19887. var upScratch = new Cartesian3();
  19888. /**
  19889. * @private
  19890. */
  19891. Transforms.rotationMatrixFromPositionVelocity = function(position, velocity, ellipsoid, result) {
  19892. if (!defined(position)) {
  19893. throw new DeveloperError('position is required.');
  19894. }
  19895. if (!defined(velocity)) {
  19896. throw new DeveloperError('velocity is required.');
  19897. }
  19898. var normal = defaultValue(ellipsoid, Ellipsoid.WGS84).geodeticSurfaceNormal(position, normalScratch);
  19899. var right = Cartesian3.cross(velocity, normal, rightScratch);
  19900. if (Cartesian3.equalsEpsilon(right, Cartesian3.ZERO, CesiumMath.EPSILON6)) {
  19901. right = Cartesian3.clone(Cartesian3.UNIT_X, right);
  19902. }
  19903. var up = Cartesian3.cross(right, velocity, upScratch);
  19904. Cartesian3.cross(velocity, up, right);
  19905. Cartesian3.negate(right, right);
  19906. if (!defined(result)) {
  19907. result = new Matrix3();
  19908. }
  19909. result[0] = velocity.x;
  19910. result[1] = velocity.y;
  19911. result[2] = velocity.z;
  19912. result[3] = right.x;
  19913. result[4] = right.y;
  19914. result[5] = right.z;
  19915. result[6] = up.x;
  19916. result[7] = up.y;
  19917. result[8] = up.z;
  19918. return result;
  19919. };
  19920. var scratchCartographic = new Cartographic();
  19921. var scratchCartesian3Projection = new Cartesian3();
  19922. var scratchCartesian3 = new Cartesian3();
  19923. var scratchCartesian4Origin = new Cartesian4();
  19924. var scratchCartesian4NewOrigin = new Cartesian4();
  19925. var scratchCartesian4NewXAxis = new Cartesian4();
  19926. var scratchCartesian4NewYAxis = new Cartesian4();
  19927. var scratchCartesian4NewZAxis = new Cartesian4();
  19928. var scratchFromENU = new Matrix4();
  19929. var scratchToENU = new Matrix4();
  19930. /**
  19931. * @private
  19932. */
  19933. Transforms.basisTo2D = function(projection, matrix, result) {
  19934. if (!defined(projection)) {
  19935. throw new DeveloperError('projection is required.');
  19936. }
  19937. if (!defined(matrix)) {
  19938. throw new DeveloperError('matrix is required.');
  19939. }
  19940. if (!defined(result)) {
  19941. throw new DeveloperError('result is required.');
  19942. }
  19943. var ellipsoid = projection.ellipsoid;
  19944. var origin = Matrix4.getColumn(matrix, 3, scratchCartesian4Origin);
  19945. var cartographic = ellipsoid.cartesianToCartographic(origin, scratchCartographic);
  19946. var fromENU = Transforms.eastNorthUpToFixedFrame(origin, ellipsoid, scratchFromENU);
  19947. var toENU = Matrix4.inverseTransformation(fromENU, scratchToENU);
  19948. var projectedPosition = projection.project(cartographic, scratchCartesian3Projection);
  19949. var newOrigin = scratchCartesian4NewOrigin;
  19950. newOrigin.x = projectedPosition.z;
  19951. newOrigin.y = projectedPosition.x;
  19952. newOrigin.z = projectedPosition.y;
  19953. newOrigin.w = 1.0;
  19954. var xAxis = Matrix4.getColumn(matrix, 0, scratchCartesian3);
  19955. var xScale = Cartesian3.magnitude(xAxis);
  19956. var newXAxis = Matrix4.multiplyByVector(toENU, xAxis, scratchCartesian4NewXAxis);
  19957. Cartesian4.fromElements(newXAxis.z, newXAxis.x, newXAxis.y, 0.0, newXAxis);
  19958. var yAxis = Matrix4.getColumn(matrix, 1, scratchCartesian3);
  19959. var yScale = Cartesian3.magnitude(yAxis);
  19960. var newYAxis = Matrix4.multiplyByVector(toENU, yAxis, scratchCartesian4NewYAxis);
  19961. Cartesian4.fromElements(newYAxis.z, newYAxis.x, newYAxis.y, 0.0, newYAxis);
  19962. var zAxis = Matrix4.getColumn(matrix, 2, scratchCartesian3);
  19963. var zScale = Cartesian3.magnitude(zAxis);
  19964. var newZAxis = scratchCartesian4NewZAxis;
  19965. Cartesian3.cross(newXAxis, newYAxis, newZAxis);
  19966. Cartesian3.normalize(newZAxis, newZAxis);
  19967. Cartesian3.cross(newYAxis, newZAxis, newXAxis);
  19968. Cartesian3.normalize(newXAxis, newXAxis);
  19969. Cartesian3.cross(newZAxis, newXAxis, newYAxis);
  19970. Cartesian3.normalize(newYAxis, newYAxis);
  19971. Cartesian3.multiplyByScalar(newXAxis, xScale, newXAxis);
  19972. Cartesian3.multiplyByScalar(newYAxis, yScale, newYAxis);
  19973. Cartesian3.multiplyByScalar(newZAxis, zScale, newZAxis);
  19974. Matrix4.setColumn(result, 0, newXAxis, result);
  19975. Matrix4.setColumn(result, 1, newYAxis, result);
  19976. Matrix4.setColumn(result, 2, newZAxis, result);
  19977. Matrix4.setColumn(result, 3, newOrigin, result);
  19978. return result;
  19979. };
  19980. return Transforms;
  19981. });
  19982. /*global define*/
  19983. define('Core/EllipsoidTangentPlane',[
  19984. './AxisAlignedBoundingBox',
  19985. './Cartesian2',
  19986. './Cartesian3',
  19987. './Cartesian4',
  19988. './defaultValue',
  19989. './defined',
  19990. './defineProperties',
  19991. './DeveloperError',
  19992. './Ellipsoid',
  19993. './IntersectionTests',
  19994. './Matrix4',
  19995. './Plane',
  19996. './Ray',
  19997. './Transforms'
  19998. ], function(
  19999. AxisAlignedBoundingBox,
  20000. Cartesian2,
  20001. Cartesian3,
  20002. Cartesian4,
  20003. defaultValue,
  20004. defined,
  20005. defineProperties,
  20006. DeveloperError,
  20007. Ellipsoid,
  20008. IntersectionTests,
  20009. Matrix4,
  20010. Plane,
  20011. Ray,
  20012. Transforms) {
  20013. 'use strict';
  20014. var scratchCart4 = new Cartesian4();
  20015. /**
  20016. * A plane tangent to the provided ellipsoid at the provided origin.
  20017. * If origin is not on the surface of the ellipsoid, it's surface projection will be used.
  20018. * If origin is at the center of the ellipsoid, an exception will be thrown.
  20019. * @alias EllipsoidTangentPlane
  20020. * @constructor
  20021. *
  20022. * @param {Cartesian3} origin The point on the surface of the ellipsoid where the tangent plane touches.
  20023. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid to use.
  20024. *
  20025. * @exception {DeveloperError} origin must not be at the center of the ellipsoid.
  20026. */
  20027. function EllipsoidTangentPlane(origin, ellipsoid) {
  20028. if (!defined(origin)) {
  20029. throw new DeveloperError('origin is required.');
  20030. }
  20031. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  20032. origin = ellipsoid.scaleToGeodeticSurface(origin);
  20033. if (!defined(origin)) {
  20034. throw new DeveloperError('origin must not be at the center of the ellipsoid.');
  20035. }
  20036. var eastNorthUp = Transforms.eastNorthUpToFixedFrame(origin, ellipsoid);
  20037. this._ellipsoid = ellipsoid;
  20038. this._origin = origin;
  20039. this._xAxis = Cartesian3.fromCartesian4(Matrix4.getColumn(eastNorthUp, 0, scratchCart4));
  20040. this._yAxis = Cartesian3.fromCartesian4(Matrix4.getColumn(eastNorthUp, 1, scratchCart4));
  20041. var normal = Cartesian3.fromCartesian4(Matrix4.getColumn(eastNorthUp, 2, scratchCart4));
  20042. this._plane = Plane.fromPointNormal(origin, normal);
  20043. }
  20044. defineProperties(EllipsoidTangentPlane.prototype, {
  20045. /**
  20046. * Gets the ellipsoid.
  20047. * @memberof EllipsoidTangentPlane.prototype
  20048. * @type {Ellipsoid}
  20049. */
  20050. ellipsoid : {
  20051. get : function() {
  20052. return this._ellipsoid;
  20053. }
  20054. },
  20055. /**
  20056. * Gets the origin.
  20057. * @memberof EllipsoidTangentPlane.prototype
  20058. * @type {Cartesian3}
  20059. */
  20060. origin : {
  20061. get : function() {
  20062. return this._origin;
  20063. }
  20064. },
  20065. /**
  20066. * Gets the plane which is tangent to the ellipsoid.
  20067. * @memberof EllipsoidTangentPlane.prototype
  20068. * @readonly
  20069. * @type {Plane}
  20070. */
  20071. plane : {
  20072. get : function() {
  20073. return this._plane;
  20074. }
  20075. },
  20076. /**
  20077. * Gets the local X-axis (east) of the tangent plane.
  20078. * @memberof EllipsoidTangentPlane.prototype
  20079. * @readonly
  20080. * @type {Cartesian3}
  20081. */
  20082. xAxis : {
  20083. get : function() {
  20084. return this._xAxis;
  20085. }
  20086. },
  20087. /**
  20088. * Gets the local Y-axis (north) of the tangent plane.
  20089. * @memberof EllipsoidTangentPlane.prototype
  20090. * @readonly
  20091. * @type {Cartesian3}
  20092. */
  20093. yAxis : {
  20094. get : function() {
  20095. return this._yAxis;
  20096. }
  20097. },
  20098. /**
  20099. * Gets the local Z-axis (up) of the tangent plane.
  20100. * @member EllipsoidTangentPlane.prototype
  20101. * @readonly
  20102. * @type {Cartesian3}
  20103. */
  20104. zAxis : {
  20105. get : function() {
  20106. return this._plane.normal;
  20107. }
  20108. }
  20109. });
  20110. var tmp = new AxisAlignedBoundingBox();
  20111. /**
  20112. * Creates a new instance from the provided ellipsoid and the center
  20113. * point of the provided Cartesians.
  20114. *
  20115. * @param {Ellipsoid} ellipsoid The ellipsoid to use.
  20116. * @param {Cartesian3} cartesians The list of positions surrounding the center point.
  20117. */
  20118. EllipsoidTangentPlane.fromPoints = function(cartesians, ellipsoid) {
  20119. if (!defined(cartesians)) {
  20120. throw new DeveloperError('cartesians is required.');
  20121. }
  20122. var box = AxisAlignedBoundingBox.fromPoints(cartesians, tmp);
  20123. return new EllipsoidTangentPlane(box.center, ellipsoid);
  20124. };
  20125. var scratchProjectPointOntoPlaneRay = new Ray();
  20126. var scratchProjectPointOntoPlaneCartesian3 = new Cartesian3();
  20127. /**
  20128. * Computes the projection of the provided 3D position onto the 2D plane, radially outward from the {@link EllipsoidTangentPlane.ellipsoid} coordinate system origin.
  20129. *
  20130. * @param {Cartesian3} cartesian The point to project.
  20131. * @param {Cartesian2} [result] The object onto which to store the result.
  20132. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if none was provided. Undefined if there is no intersection point
  20133. */
  20134. EllipsoidTangentPlane.prototype.projectPointOntoPlane = function(cartesian, result) {
  20135. if (!defined(cartesian)) {
  20136. throw new DeveloperError('cartesian is required.');
  20137. }
  20138. var ray = scratchProjectPointOntoPlaneRay;
  20139. ray.origin = cartesian;
  20140. Cartesian3.normalize(cartesian, ray.direction);
  20141. var intersectionPoint = IntersectionTests.rayPlane(ray, this._plane, scratchProjectPointOntoPlaneCartesian3);
  20142. if (!defined(intersectionPoint)) {
  20143. Cartesian3.negate(ray.direction, ray.direction);
  20144. intersectionPoint = IntersectionTests.rayPlane(ray, this._plane, scratchProjectPointOntoPlaneCartesian3);
  20145. }
  20146. if (defined(intersectionPoint)) {
  20147. var v = Cartesian3.subtract(intersectionPoint, this._origin, intersectionPoint);
  20148. var x = Cartesian3.dot(this._xAxis, v);
  20149. var y = Cartesian3.dot(this._yAxis, v);
  20150. if (!defined(result)) {
  20151. return new Cartesian2(x, y);
  20152. }
  20153. result.x = x;
  20154. result.y = y;
  20155. return result;
  20156. }
  20157. return undefined;
  20158. };
  20159. /**
  20160. * Computes the projection of the provided 3D positions onto the 2D plane (where possible), radially outward from the global origin.
  20161. * The resulting array may be shorter than the input array - if a single projection is impossible it will not be included.
  20162. *
  20163. * @see EllipsoidTangentPlane.projectPointOntoPlane
  20164. *
  20165. * @param {Cartesian3[]} cartesians The array of points to project.
  20166. * @param {Cartesian2[]} [result] The array of Cartesian2 instances onto which to store results.
  20167. * @returns {Cartesian2[]} The modified result parameter or a new array of Cartesian2 instances if none was provided.
  20168. */
  20169. EllipsoidTangentPlane.prototype.projectPointsOntoPlane = function(cartesians, result) {
  20170. if (!defined(cartesians)) {
  20171. throw new DeveloperError('cartesians is required.');
  20172. }
  20173. if (!defined(result)) {
  20174. result = [];
  20175. }
  20176. var count = 0;
  20177. var length = cartesians.length;
  20178. for ( var i = 0; i < length; i++) {
  20179. var p = this.projectPointOntoPlane(cartesians[i], result[count]);
  20180. if (defined(p)) {
  20181. result[count] = p;
  20182. count++;
  20183. }
  20184. }
  20185. result.length = count;
  20186. return result;
  20187. };
  20188. /**
  20189. * Computes the projection of the provided 3D position onto the 2D plane, along the plane normal.
  20190. *
  20191. * @param {Cartesian3} cartesian The point to project.
  20192. * @param {Cartesian2} [result] The object onto which to store the result.
  20193. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if none was provided.
  20194. */
  20195. EllipsoidTangentPlane.prototype.projectPointToNearestOnPlane = function(cartesian, result) {
  20196. if (!defined(cartesian)) {
  20197. throw new DeveloperError('cartesian is required.');
  20198. }
  20199. if (!defined(result)) {
  20200. result = new Cartesian2();
  20201. }
  20202. var ray = scratchProjectPointOntoPlaneRay;
  20203. ray.origin = cartesian;
  20204. Cartesian3.clone(this._plane.normal, ray.direction);
  20205. var intersectionPoint = IntersectionTests.rayPlane(ray, this._plane, scratchProjectPointOntoPlaneCartesian3);
  20206. if (!defined(intersectionPoint)) {
  20207. Cartesian3.negate(ray.direction, ray.direction);
  20208. intersectionPoint = IntersectionTests.rayPlane(ray, this._plane, scratchProjectPointOntoPlaneCartesian3);
  20209. }
  20210. var v = Cartesian3.subtract(intersectionPoint, this._origin, intersectionPoint);
  20211. var x = Cartesian3.dot(this._xAxis, v);
  20212. var y = Cartesian3.dot(this._yAxis, v);
  20213. result.x = x;
  20214. result.y = y;
  20215. return result;
  20216. };
  20217. /**
  20218. * Computes the projection of the provided 3D positions onto the 2D plane, along the plane normal.
  20219. *
  20220. * @see EllipsoidTangentPlane.projectPointToNearestOnPlane
  20221. *
  20222. * @param {Cartesian3[]} cartesians The array of points to project.
  20223. * @param {Cartesian2[]} [result] The array of Cartesian2 instances onto which to store results.
  20224. * @returns {Cartesian2[]} The modified result parameter or a new array of Cartesian2 instances if none was provided. This will have the same length as <code>cartesians</code>.
  20225. */
  20226. EllipsoidTangentPlane.prototype.projectPointsToNearestOnPlane = function(cartesians, result) {
  20227. if (!defined(cartesians)) {
  20228. throw new DeveloperError('cartesians is required.');
  20229. }
  20230. if (!defined(result)) {
  20231. result = [];
  20232. }
  20233. var length = cartesians.length;
  20234. result.length = length;
  20235. for (var i = 0; i < length; i++) {
  20236. result[i] = this.projectPointToNearestOnPlane(cartesians[i], result[i]);
  20237. }
  20238. return result;
  20239. };
  20240. var projectPointsOntoEllipsoidScratch = new Cartesian3();
  20241. /**
  20242. * Computes the projection of the provided 2D positions onto the 3D ellipsoid.
  20243. *
  20244. * @param {Cartesian2[]} cartesians The array of points to project.
  20245. * @param {Cartesian3[]} [result] The array of Cartesian3 instances onto which to store results.
  20246. * @returns {Cartesian3[]} The modified result parameter or a new array of Cartesian3 instances if none was provided.
  20247. */
  20248. EllipsoidTangentPlane.prototype.projectPointsOntoEllipsoid = function(cartesians, result) {
  20249. if (!defined(cartesians)) {
  20250. throw new DeveloperError('cartesians is required.');
  20251. }
  20252. var length = cartesians.length;
  20253. if (!defined(result)) {
  20254. result = new Array(length);
  20255. } else {
  20256. result.length = length;
  20257. }
  20258. var ellipsoid = this._ellipsoid;
  20259. var origin = this._origin;
  20260. var xAxis = this._xAxis;
  20261. var yAxis = this._yAxis;
  20262. var tmp = projectPointsOntoEllipsoidScratch;
  20263. for ( var i = 0; i < length; ++i) {
  20264. var position = cartesians[i];
  20265. Cartesian3.multiplyByScalar(xAxis, position.x, tmp);
  20266. if (!defined(result[i])) {
  20267. result[i] = new Cartesian3();
  20268. }
  20269. var point = Cartesian3.add(origin, tmp, result[i]);
  20270. Cartesian3.multiplyByScalar(yAxis, position.y, tmp);
  20271. Cartesian3.add(point, tmp, point);
  20272. ellipsoid.scaleToGeocentricSurface(point, point);
  20273. }
  20274. return result;
  20275. };
  20276. return EllipsoidTangentPlane;
  20277. });
  20278. /*global define*/
  20279. define('Core/OrientedBoundingBox',[
  20280. './BoundingSphere',
  20281. './Cartesian2',
  20282. './Cartesian3',
  20283. './Cartographic',
  20284. './defaultValue',
  20285. './defined',
  20286. './DeveloperError',
  20287. './Ellipsoid',
  20288. './EllipsoidTangentPlane',
  20289. './Intersect',
  20290. './Interval',
  20291. './Math',
  20292. './Matrix3',
  20293. './Plane',
  20294. './Rectangle'
  20295. ], function(
  20296. BoundingSphere,
  20297. Cartesian2,
  20298. Cartesian3,
  20299. Cartographic,
  20300. defaultValue,
  20301. defined,
  20302. DeveloperError,
  20303. Ellipsoid,
  20304. EllipsoidTangentPlane,
  20305. Intersect,
  20306. Interval,
  20307. CesiumMath,
  20308. Matrix3,
  20309. Plane,
  20310. Rectangle) {
  20311. 'use strict';
  20312. /**
  20313. * Creates an instance of an OrientedBoundingBox.
  20314. * An OrientedBoundingBox of some object is a closed and convex cuboid. It can provide a tighter bounding volume than {@link BoundingSphere} or {@link AxisAlignedBoundingBox} in many cases.
  20315. * @alias OrientedBoundingBox
  20316. * @constructor
  20317. *
  20318. * @param {Cartesian3} [center=Cartesian3.ZERO] The center of the box.
  20319. * @param {Matrix3} [halfAxes=Matrix3.ZERO] The three orthogonal half-axes of the bounding box.
  20320. * Equivalently, the transformation matrix, to rotate and scale a 2x2x2
  20321. * cube centered at the origin.
  20322. *
  20323. *
  20324. * @example
  20325. * // Create an OrientedBoundingBox using a transformation matrix, a position where the box will be translated, and a scale.
  20326. * var center = new Cesium.Cartesian3(1.0, 0.0, 0.0);
  20327. * var halfAxes = Cesium.Matrix3.fromScale(new Cesium.Cartesian3(1.0, 3.0, 2.0), new Cesium.Matrix3());
  20328. *
  20329. * var obb = new Cesium.OrientedBoundingBox(center, halfAxes);
  20330. *
  20331. * @see BoundingSphere
  20332. * @see BoundingRectangle
  20333. */
  20334. function OrientedBoundingBox(center, halfAxes) {
  20335. /**
  20336. * The center of the box.
  20337. * @type {Cartesian3}
  20338. * @default {@link Cartesian3.ZERO}
  20339. */
  20340. this.center = Cartesian3.clone(defaultValue(center, Cartesian3.ZERO));
  20341. /**
  20342. * The transformation matrix, to rotate the box to the right position.
  20343. * @type {Matrix3}
  20344. * @default {@link Matrix3.IDENTITY}
  20345. */
  20346. this.halfAxes = Matrix3.clone(defaultValue(halfAxes, Matrix3.ZERO));
  20347. }
  20348. var scratchCartesian1 = new Cartesian3();
  20349. var scratchCartesian2 = new Cartesian3();
  20350. var scratchCartesian3 = new Cartesian3();
  20351. var scratchCartesian4 = new Cartesian3();
  20352. var scratchCartesian5 = new Cartesian3();
  20353. var scratchCartesian6 = new Cartesian3();
  20354. var scratchCovarianceResult = new Matrix3();
  20355. var scratchEigenResult = {
  20356. unitary : new Matrix3(),
  20357. diagonal : new Matrix3()
  20358. };
  20359. /**
  20360. * Computes an instance of an OrientedBoundingBox of the given positions.
  20361. * This is an implementation of Stefan Gottschalk's Collision Queries using Oriented Bounding Boxes solution (PHD thesis).
  20362. * Reference: http://gamma.cs.unc.edu/users/gottschalk/main.pdf
  20363. *
  20364. * @param {Cartesian3[]} positions List of {@link Cartesian3} points that the bounding box will enclose.
  20365. * @param {OrientedBoundingBox} [result] The object onto which to store the result.
  20366. * @returns {OrientedBoundingBox} The modified result parameter or a new OrientedBoundingBox instance if one was not provided.
  20367. *
  20368. * @example
  20369. * // Compute an object oriented bounding box enclosing two points.
  20370. * var box = Cesium.OrientedBoundingBox.fromPoints([new Cesium.Cartesian3(2, 0, 0), new Cesium.Cartesian3(-2, 0, 0)]);
  20371. */
  20372. OrientedBoundingBox.fromPoints = function(positions, result) {
  20373. if (!defined(result)) {
  20374. result = new OrientedBoundingBox();
  20375. }
  20376. if (!defined(positions) || positions.length === 0) {
  20377. result.halfAxes = Matrix3.ZERO;
  20378. result.center = Cartesian3.ZERO;
  20379. return result;
  20380. }
  20381. var i;
  20382. var length = positions.length;
  20383. var meanPoint = Cartesian3.clone(positions[0], scratchCartesian1);
  20384. for (i = 1; i < length; i++) {
  20385. Cartesian3.add(meanPoint, positions[i], meanPoint);
  20386. }
  20387. var invLength = 1.0 / length;
  20388. Cartesian3.multiplyByScalar(meanPoint, invLength, meanPoint);
  20389. var exx = 0.0;
  20390. var exy = 0.0;
  20391. var exz = 0.0;
  20392. var eyy = 0.0;
  20393. var eyz = 0.0;
  20394. var ezz = 0.0;
  20395. var p;
  20396. for (i = 0; i < length; i++) {
  20397. p = Cartesian3.subtract(positions[i], meanPoint, scratchCartesian2);
  20398. exx += p.x * p.x;
  20399. exy += p.x * p.y;
  20400. exz += p.x * p.z;
  20401. eyy += p.y * p.y;
  20402. eyz += p.y * p.z;
  20403. ezz += p.z * p.z;
  20404. }
  20405. exx *= invLength;
  20406. exy *= invLength;
  20407. exz *= invLength;
  20408. eyy *= invLength;
  20409. eyz *= invLength;
  20410. ezz *= invLength;
  20411. var covarianceMatrix = scratchCovarianceResult;
  20412. covarianceMatrix[0] = exx;
  20413. covarianceMatrix[1] = exy;
  20414. covarianceMatrix[2] = exz;
  20415. covarianceMatrix[3] = exy;
  20416. covarianceMatrix[4] = eyy;
  20417. covarianceMatrix[5] = eyz;
  20418. covarianceMatrix[6] = exz;
  20419. covarianceMatrix[7] = eyz;
  20420. covarianceMatrix[8] = ezz;
  20421. var eigenDecomposition = Matrix3.computeEigenDecomposition(covarianceMatrix, scratchEigenResult);
  20422. var rotation = Matrix3.clone(eigenDecomposition.unitary, result.halfAxes);
  20423. var v1 = Matrix3.getColumn(rotation, 0, scratchCartesian4);
  20424. var v2 = Matrix3.getColumn(rotation, 1, scratchCartesian5);
  20425. var v3 = Matrix3.getColumn(rotation, 2, scratchCartesian6);
  20426. var u1 = -Number.MAX_VALUE;
  20427. var u2 = -Number.MAX_VALUE;
  20428. var u3 = -Number.MAX_VALUE;
  20429. var l1 = Number.MAX_VALUE;
  20430. var l2 = Number.MAX_VALUE;
  20431. var l3 = Number.MAX_VALUE;
  20432. for (i = 0; i < length; i++) {
  20433. p = positions[i];
  20434. u1 = Math.max(Cartesian3.dot(v1, p), u1);
  20435. u2 = Math.max(Cartesian3.dot(v2, p), u2);
  20436. u3 = Math.max(Cartesian3.dot(v3, p), u3);
  20437. l1 = Math.min(Cartesian3.dot(v1, p), l1);
  20438. l2 = Math.min(Cartesian3.dot(v2, p), l2);
  20439. l3 = Math.min(Cartesian3.dot(v3, p), l3);
  20440. }
  20441. v1 = Cartesian3.multiplyByScalar(v1, 0.5 * (l1 + u1), v1);
  20442. v2 = Cartesian3.multiplyByScalar(v2, 0.5 * (l2 + u2), v2);
  20443. v3 = Cartesian3.multiplyByScalar(v3, 0.5 * (l3 + u3), v3);
  20444. var center = Cartesian3.add(v1, v2, result.center);
  20445. center = Cartesian3.add(center, v3, center);
  20446. var scale = scratchCartesian3;
  20447. scale.x = u1 - l1;
  20448. scale.y = u2 - l2;
  20449. scale.z = u3 - l3;
  20450. Cartesian3.multiplyByScalar(scale, 0.5, scale);
  20451. Matrix3.multiplyByScale(result.halfAxes, scale, result.halfAxes);
  20452. return result;
  20453. };
  20454. var scratchOffset = new Cartesian3();
  20455. var scratchScale = new Cartesian3();
  20456. /**
  20457. * Computes an OrientedBoundingBox given extents in the east-north-up space of the tangent plane.
  20458. *
  20459. * @param {Number} minimumX Minimum X extent in tangent plane space.
  20460. * @param {Number} maximumX Maximum X extent in tangent plane space.
  20461. * @param {Number} minimumY Minimum Y extent in tangent plane space.
  20462. * @param {Number} maximumY Maximum Y extent in tangent plane space.
  20463. * @param {Number} minimumZ Minimum Z extent in tangent plane space.
  20464. * @param {Number} maximumZ Maximum Z extent in tangent plane space.
  20465. * @param {OrientedBoundingBox} [result] The object onto which to store the result.
  20466. * @returns {OrientedBoundingBox} The modified result parameter or a new OrientedBoundingBox instance if one was not provided.
  20467. */
  20468. function fromTangentPlaneExtents(tangentPlane, minimumX, maximumX, minimumY, maximumY, minimumZ, maximumZ, result) {
  20469. if (!defined(minimumX) ||
  20470. !defined(maximumX) ||
  20471. !defined(minimumY) ||
  20472. !defined(maximumY) ||
  20473. !defined(minimumZ) ||
  20474. !defined(maximumZ)) {
  20475. throw new DeveloperError('all extents (minimum/maximum X/Y/Z) are required.');
  20476. }
  20477. if (!defined(result)) {
  20478. result = new OrientedBoundingBox();
  20479. }
  20480. var halfAxes = result.halfAxes;
  20481. Matrix3.setColumn(halfAxes, 0, tangentPlane.xAxis, halfAxes);
  20482. Matrix3.setColumn(halfAxes, 1, tangentPlane.yAxis, halfAxes);
  20483. Matrix3.setColumn(halfAxes, 2, tangentPlane.zAxis, halfAxes);
  20484. var centerOffset = scratchOffset;
  20485. centerOffset.x = (minimumX + maximumX) / 2.0;
  20486. centerOffset.y = (minimumY + maximumY) / 2.0;
  20487. centerOffset.z = (minimumZ + maximumZ) / 2.0;
  20488. var scale = scratchScale;
  20489. scale.x = (maximumX - minimumX) / 2.0;
  20490. scale.y = (maximumY - minimumY) / 2.0;
  20491. scale.z = (maximumZ - minimumZ) / 2.0;
  20492. var center = result.center;
  20493. centerOffset = Matrix3.multiplyByVector(halfAxes, centerOffset, centerOffset);
  20494. Cartesian3.add(tangentPlane.origin, centerOffset, center);
  20495. Matrix3.multiplyByScale(halfAxes, scale, halfAxes);
  20496. return result;
  20497. }
  20498. var scratchRectangleCenterCartographic = new Cartographic();
  20499. var scratchRectangleCenter = new Cartesian3();
  20500. var perimeterCartographicScratch = [new Cartographic(), new Cartographic(), new Cartographic(), new Cartographic(), new Cartographic(), new Cartographic(), new Cartographic(), new Cartographic()];
  20501. var perimeterCartesianScratch = [new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3()];
  20502. var perimeterProjectedScratch = [new Cartesian2(), new Cartesian2(), new Cartesian2(), new Cartesian2(), new Cartesian2(), new Cartesian2(), new Cartesian2(), new Cartesian2()];
  20503. /**
  20504. * Computes an OrientedBoundingBox that bounds a {@link Rectangle} on the surface of an {@link Ellipsoid}.
  20505. * There are no guarantees about the orientation of the bounding box.
  20506. *
  20507. * @param {Rectangle} rectangle The cartographic rectangle on the surface of the ellipsoid.
  20508. * @param {Number} [minimumHeight=0.0] The minimum height (elevation) within the tile.
  20509. * @param {Number} [maximumHeight=0.0] The maximum height (elevation) within the tile.
  20510. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the rectangle is defined.
  20511. * @param {OrientedBoundingBox} [result] The object onto which to store the result.
  20512. * @returns {OrientedBoundingBox} The modified result parameter or a new OrientedBoundingBox instance if none was provided.
  20513. *
  20514. * @exception {DeveloperError} rectangle.width must be between 0 and pi.
  20515. * @exception {DeveloperError} rectangle.height must be between 0 and pi.
  20516. * @exception {DeveloperError} ellipsoid must be an ellipsoid of revolution (<code>radii.x == radii.y</code>)
  20517. */
  20518. OrientedBoundingBox.fromRectangle = function(rectangle, minimumHeight, maximumHeight, ellipsoid, result) {
  20519. if (!defined(rectangle)) {
  20520. throw new DeveloperError('rectangle is required');
  20521. }
  20522. if (rectangle.width < 0.0 || rectangle.width > CesiumMath.PI) {
  20523. throw new DeveloperError('Rectangle width must be between 0 and pi');
  20524. }
  20525. if (rectangle.height < 0.0 || rectangle.height > CesiumMath.PI) {
  20526. throw new DeveloperError('Rectangle height must be between 0 and pi');
  20527. }
  20528. if (defined(ellipsoid) && !CesiumMath.equalsEpsilon(ellipsoid.radii.x, ellipsoid.radii.y, CesiumMath.EPSILON15)) {
  20529. throw new DeveloperError('Ellipsoid must be an ellipsoid of revolution (radii.x == radii.y)');
  20530. }
  20531. minimumHeight = defaultValue(minimumHeight, 0.0);
  20532. maximumHeight = defaultValue(maximumHeight, 0.0);
  20533. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  20534. // The bounding box will be aligned with the tangent plane at the center of the rectangle.
  20535. var tangentPointCartographic = Rectangle.center(rectangle, scratchRectangleCenterCartographic);
  20536. var tangentPoint = ellipsoid.cartographicToCartesian(tangentPointCartographic, scratchRectangleCenter);
  20537. var tangentPlane = new EllipsoidTangentPlane(tangentPoint, ellipsoid);
  20538. var plane = tangentPlane.plane;
  20539. // Corner arrangement:
  20540. // N/+y
  20541. // [0] [1] [2]
  20542. // W/-x [7] [3] E/+x
  20543. // [6] [5] [4]
  20544. // S/-y
  20545. // "C" refers to the central lat/long, which by default aligns with the tangent point (above).
  20546. // If the rectangle spans the equator, CW and CE are instead aligned with the equator.
  20547. var perimeterNW = perimeterCartographicScratch[0];
  20548. var perimeterNC = perimeterCartographicScratch[1];
  20549. var perimeterNE = perimeterCartographicScratch[2];
  20550. var perimeterCE = perimeterCartographicScratch[3];
  20551. var perimeterSE = perimeterCartographicScratch[4];
  20552. var perimeterSC = perimeterCartographicScratch[5];
  20553. var perimeterSW = perimeterCartographicScratch[6];
  20554. var perimeterCW = perimeterCartographicScratch[7];
  20555. var lonCenter = tangentPointCartographic.longitude;
  20556. var latCenter = (rectangle.south < 0.0 && rectangle.north > 0.0) ? 0.0 : tangentPointCartographic.latitude;
  20557. perimeterSW.latitude = perimeterSC.latitude = perimeterSE.latitude = rectangle.south;
  20558. perimeterCW.latitude = perimeterCE.latitude = latCenter;
  20559. perimeterNW.latitude = perimeterNC.latitude = perimeterNE.latitude = rectangle.north;
  20560. perimeterSW.longitude = perimeterCW.longitude = perimeterNW.longitude = rectangle.west;
  20561. perimeterSC.longitude = perimeterNC.longitude = lonCenter;
  20562. perimeterSE.longitude = perimeterCE.longitude = perimeterNE.longitude = rectangle.east;
  20563. // Compute XY extents using the rectangle at maximum height
  20564. perimeterNE.height = perimeterNC.height = perimeterNW.height = perimeterCW.height = perimeterSW.height = perimeterSC.height = perimeterSE.height = perimeterCE.height = maximumHeight;
  20565. ellipsoid.cartographicArrayToCartesianArray(perimeterCartographicScratch, perimeterCartesianScratch);
  20566. tangentPlane.projectPointsToNearestOnPlane(perimeterCartesianScratch, perimeterProjectedScratch);
  20567. // See the `perimeterXX` definitions above for what these are
  20568. var minX = Math.min(perimeterProjectedScratch[6].x, perimeterProjectedScratch[7].x, perimeterProjectedScratch[0].x);
  20569. var maxX = Math.max(perimeterProjectedScratch[2].x, perimeterProjectedScratch[3].x, perimeterProjectedScratch[4].x);
  20570. var minY = Math.min(perimeterProjectedScratch[4].y, perimeterProjectedScratch[5].y, perimeterProjectedScratch[6].y);
  20571. var maxY = Math.max(perimeterProjectedScratch[0].y, perimeterProjectedScratch[1].y, perimeterProjectedScratch[2].y);
  20572. // Compute minimum Z using the rectangle at minimum height
  20573. perimeterNE.height = perimeterNW.height = perimeterSE.height = perimeterSW.height = minimumHeight;
  20574. ellipsoid.cartographicArrayToCartesianArray(perimeterCartographicScratch, perimeterCartesianScratch);
  20575. var minZ = Math.min(Plane.getPointDistance(plane, perimeterCartesianScratch[0]),
  20576. Plane.getPointDistance(plane, perimeterCartesianScratch[2]),
  20577. Plane.getPointDistance(plane, perimeterCartesianScratch[4]),
  20578. Plane.getPointDistance(plane, perimeterCartesianScratch[6]));
  20579. var maxZ = maximumHeight; // Since the tangent plane touches the surface at height = 0, this is okay
  20580. return fromTangentPlaneExtents(tangentPlane, minX, maxX, minY, maxY, minZ, maxZ, result);
  20581. };
  20582. /**
  20583. * Duplicates a OrientedBoundingBox instance.
  20584. *
  20585. * @param {OrientedBoundingBox} box The bounding box to duplicate.
  20586. * @param {OrientedBoundingBox} [result] The object onto which to store the result.
  20587. * @returns {OrientedBoundingBox} The modified result parameter or a new OrientedBoundingBox instance if none was provided. (Returns undefined if box is undefined)
  20588. */
  20589. OrientedBoundingBox.clone = function(box, result) {
  20590. if (!defined(box)) {
  20591. return undefined;
  20592. }
  20593. if (!defined(result)) {
  20594. return new OrientedBoundingBox(box.center, box.halfAxes);
  20595. }
  20596. Cartesian3.clone(box.center, result.center);
  20597. Matrix3.clone(box.halfAxes, result.halfAxes);
  20598. return result;
  20599. };
  20600. /**
  20601. * Determines which side of a plane the oriented bounding box is located.
  20602. *
  20603. * @param {OrientedBoundingBox} box The oriented bounding box to test.
  20604. * @param {Plane} plane The plane to test against.
  20605. * @returns {Intersect} {@link Intersect.INSIDE} if the entire box is on the side of the plane
  20606. * the normal is pointing, {@link Intersect.OUTSIDE} if the entire box is
  20607. * on the opposite side, and {@link Intersect.INTERSECTING} if the box
  20608. * intersects the plane.
  20609. */
  20610. OrientedBoundingBox.intersectPlane = function(box, plane) {
  20611. if (!defined(box)) {
  20612. throw new DeveloperError('box is required.');
  20613. }
  20614. if (!defined(plane)) {
  20615. throw new DeveloperError('plane is required.');
  20616. }
  20617. var center = box.center;
  20618. var normal = plane.normal;
  20619. var halfAxes = box.halfAxes;
  20620. var normalX = normal.x, normalY = normal.y, normalZ = normal.z;
  20621. // plane is used as if it is its normal; the first three components are assumed to be normalized
  20622. var radEffective = Math.abs(normalX * halfAxes[Matrix3.COLUMN0ROW0] + normalY * halfAxes[Matrix3.COLUMN0ROW1] + normalZ * halfAxes[Matrix3.COLUMN0ROW2]) +
  20623. Math.abs(normalX * halfAxes[Matrix3.COLUMN1ROW0] + normalY * halfAxes[Matrix3.COLUMN1ROW1] + normalZ * halfAxes[Matrix3.COLUMN1ROW2]) +
  20624. Math.abs(normalX * halfAxes[Matrix3.COLUMN2ROW0] + normalY * halfAxes[Matrix3.COLUMN2ROW1] + normalZ * halfAxes[Matrix3.COLUMN2ROW2]);
  20625. var distanceToPlane = Cartesian3.dot(normal, center) + plane.distance;
  20626. if (distanceToPlane <= -radEffective) {
  20627. // The entire box is on the negative side of the plane normal
  20628. return Intersect.OUTSIDE;
  20629. } else if (distanceToPlane >= radEffective) {
  20630. // The entire box is on the positive side of the plane normal
  20631. return Intersect.INSIDE;
  20632. }
  20633. return Intersect.INTERSECTING;
  20634. };
  20635. var scratchCartesianU = new Cartesian3();
  20636. var scratchCartesianV = new Cartesian3();
  20637. var scratchCartesianW = new Cartesian3();
  20638. var scratchPPrime = new Cartesian3();
  20639. /**
  20640. * Computes the estimated distance squared from the closest point on a bounding box to a point.
  20641. *
  20642. * @param {OrientedBoundingBox} box The box.
  20643. * @param {Cartesian3} cartesian The point
  20644. * @returns {Number} The estimated distance squared from the bounding sphere to the point.
  20645. *
  20646. * @example
  20647. * // Sort bounding boxes from back to front
  20648. * boxes.sort(function(a, b) {
  20649. * return Cesium.OrientedBoundingBox.distanceSquaredTo(b, camera.positionWC) - Cesium.OrientedBoundingBox.distanceSquaredTo(a, camera.positionWC);
  20650. * });
  20651. */
  20652. OrientedBoundingBox.distanceSquaredTo = function(box, cartesian) {
  20653. // See Geometric Tools for Computer Graphics 10.4.2
  20654. if (!defined(box)) {
  20655. throw new DeveloperError('box is required.');
  20656. }
  20657. if (!defined(cartesian)) {
  20658. throw new DeveloperError('cartesian is required.');
  20659. }
  20660. var offset = Cartesian3.subtract(cartesian, box.center, scratchOffset);
  20661. var halfAxes = box.halfAxes;
  20662. var u = Matrix3.getColumn(halfAxes, 0, scratchCartesianU);
  20663. var v = Matrix3.getColumn(halfAxes, 1, scratchCartesianV);
  20664. var w = Matrix3.getColumn(halfAxes, 2, scratchCartesianW);
  20665. var uHalf = Cartesian3.magnitude(u);
  20666. var vHalf = Cartesian3.magnitude(v);
  20667. var wHalf = Cartesian3.magnitude(w);
  20668. Cartesian3.normalize(u, u);
  20669. Cartesian3.normalize(v, v);
  20670. Cartesian3.normalize(w, w);
  20671. var pPrime = scratchPPrime;
  20672. pPrime.x = Cartesian3.dot(offset, u);
  20673. pPrime.y = Cartesian3.dot(offset, v);
  20674. pPrime.z = Cartesian3.dot(offset, w);
  20675. var distanceSquared = 0.0;
  20676. var d;
  20677. if (pPrime.x < -uHalf) {
  20678. d = pPrime.x + uHalf;
  20679. distanceSquared += d * d;
  20680. } else if (pPrime.x > uHalf) {
  20681. d = pPrime.x - uHalf;
  20682. distanceSquared += d * d;
  20683. }
  20684. if (pPrime.y < -vHalf) {
  20685. d = pPrime.y + vHalf;
  20686. distanceSquared += d * d;
  20687. } else if (pPrime.y > vHalf) {
  20688. d = pPrime.y - vHalf;
  20689. distanceSquared += d * d;
  20690. }
  20691. if (pPrime.z < -wHalf) {
  20692. d = pPrime.z + wHalf;
  20693. distanceSquared += d * d;
  20694. } else if (pPrime.z > wHalf) {
  20695. d = pPrime.z - wHalf;
  20696. distanceSquared += d * d;
  20697. }
  20698. return distanceSquared;
  20699. };
  20700. var scratchCorner = new Cartesian3();
  20701. var scratchToCenter = new Cartesian3();
  20702. /**
  20703. * The distances calculated by the vector from the center of the bounding box to position projected onto direction.
  20704. * <br>
  20705. * If you imagine the infinite number of planes with normal direction, this computes the smallest distance to the
  20706. * closest and farthest planes from position that intersect the bounding box.
  20707. *
  20708. * @param {OrientedBoundingBox} box The bounding box to calculate the distance to.
  20709. * @param {Cartesian3} position The position to calculate the distance from.
  20710. * @param {Cartesian3} direction The direction from position.
  20711. * @param {Interval} [result] A Interval to store the nearest and farthest distances.
  20712. * @returns {Interval} The nearest and farthest distances on the bounding box from position in direction.
  20713. */
  20714. OrientedBoundingBox.computePlaneDistances = function(box, position, direction, result) {
  20715. if (!defined(box)) {
  20716. throw new DeveloperError('box is required.');
  20717. }
  20718. if (!defined(position)) {
  20719. throw new DeveloperError('position is required.');
  20720. }
  20721. if (!defined(direction)) {
  20722. throw new DeveloperError('direction is required.');
  20723. }
  20724. if (!defined(result)) {
  20725. result = new Interval();
  20726. }
  20727. var minDist = Number.POSITIVE_INFINITY;
  20728. var maxDist = Number.NEGATIVE_INFINITY;
  20729. var center = box.center;
  20730. var halfAxes = box.halfAxes;
  20731. var u = Matrix3.getColumn(halfAxes, 0, scratchCartesianU);
  20732. var v = Matrix3.getColumn(halfAxes, 1, scratchCartesianV);
  20733. var w = Matrix3.getColumn(halfAxes, 2, scratchCartesianW);
  20734. // project first corner
  20735. var corner = Cartesian3.add(u, v, scratchCorner);
  20736. Cartesian3.add(corner, w, corner);
  20737. Cartesian3.add(corner, center, corner);
  20738. var toCenter = Cartesian3.subtract(corner, position, scratchToCenter);
  20739. var mag = Cartesian3.dot(direction, toCenter);
  20740. minDist = Math.min(mag, minDist);
  20741. maxDist = Math.max(mag, maxDist);
  20742. // project second corner
  20743. Cartesian3.add(center, u, corner);
  20744. Cartesian3.add(corner, v, corner);
  20745. Cartesian3.subtract(corner, w, corner);
  20746. Cartesian3.subtract(corner, position, toCenter);
  20747. mag = Cartesian3.dot(direction, toCenter);
  20748. minDist = Math.min(mag, minDist);
  20749. maxDist = Math.max(mag, maxDist);
  20750. // project third corner
  20751. Cartesian3.add(center, u, corner);
  20752. Cartesian3.subtract(corner, v, corner);
  20753. Cartesian3.add(corner, w, corner);
  20754. Cartesian3.subtract(corner, position, toCenter);
  20755. mag = Cartesian3.dot(direction, toCenter);
  20756. minDist = Math.min(mag, minDist);
  20757. maxDist = Math.max(mag, maxDist);
  20758. // project fourth corner
  20759. Cartesian3.add(center, u, corner);
  20760. Cartesian3.subtract(corner, v, corner);
  20761. Cartesian3.subtract(corner, w, corner);
  20762. Cartesian3.subtract(corner, position, toCenter);
  20763. mag = Cartesian3.dot(direction, toCenter);
  20764. minDist = Math.min(mag, minDist);
  20765. maxDist = Math.max(mag, maxDist);
  20766. // project fifth corner
  20767. Cartesian3.subtract(center, u, corner);
  20768. Cartesian3.add(corner, v, corner);
  20769. Cartesian3.add(corner, w, corner);
  20770. Cartesian3.subtract(corner, position, toCenter);
  20771. mag = Cartesian3.dot(direction, toCenter);
  20772. minDist = Math.min(mag, minDist);
  20773. maxDist = Math.max(mag, maxDist);
  20774. // project sixth corner
  20775. Cartesian3.subtract(center, u, corner);
  20776. Cartesian3.add(corner, v, corner);
  20777. Cartesian3.subtract(corner, w, corner);
  20778. Cartesian3.subtract(corner, position, toCenter);
  20779. mag = Cartesian3.dot(direction, toCenter);
  20780. minDist = Math.min(mag, minDist);
  20781. maxDist = Math.max(mag, maxDist);
  20782. // project seventh corner
  20783. Cartesian3.subtract(center, u, corner);
  20784. Cartesian3.subtract(corner, v, corner);
  20785. Cartesian3.add(corner, w, corner);
  20786. Cartesian3.subtract(corner, position, toCenter);
  20787. mag = Cartesian3.dot(direction, toCenter);
  20788. minDist = Math.min(mag, minDist);
  20789. maxDist = Math.max(mag, maxDist);
  20790. // project eighth corner
  20791. Cartesian3.subtract(center, u, corner);
  20792. Cartesian3.subtract(corner, v, corner);
  20793. Cartesian3.subtract(corner, w, corner);
  20794. Cartesian3.subtract(corner, position, toCenter);
  20795. mag = Cartesian3.dot(direction, toCenter);
  20796. minDist = Math.min(mag, minDist);
  20797. maxDist = Math.max(mag, maxDist);
  20798. result.start = minDist;
  20799. result.stop = maxDist;
  20800. return result;
  20801. };
  20802. var scratchBoundingSphere = new BoundingSphere();
  20803. /**
  20804. * Determines whether or not a bounding box is hidden from view by the occluder.
  20805. *
  20806. * @param {OrientedBoundingBox} box The bounding box surrounding the occludee object.
  20807. * @param {Occluder} occluder The occluder.
  20808. * @returns {Boolean} <code>true</code> if the box is not visible; otherwise <code>false</code>.
  20809. */
  20810. OrientedBoundingBox.isOccluded = function(box, occluder) {
  20811. if (!defined(box)) {
  20812. throw new DeveloperError('box is required.');
  20813. }
  20814. if (!defined(occluder)) {
  20815. throw new DeveloperError('occluder is required.');
  20816. }
  20817. var sphere = BoundingSphere.fromOrientedBoundingBox(box, scratchBoundingSphere);
  20818. return !occluder.isBoundingSphereVisible(sphere);
  20819. };
  20820. /**
  20821. * Determines which side of a plane the oriented bounding box is located.
  20822. *
  20823. * @param {Plane} plane The plane to test against.
  20824. * @returns {Intersect} {@link Intersect.INSIDE} if the entire box is on the side of the plane
  20825. * the normal is pointing, {@link Intersect.OUTSIDE} if the entire box is
  20826. * on the opposite side, and {@link Intersect.INTERSECTING} if the box
  20827. * intersects the plane.
  20828. */
  20829. OrientedBoundingBox.prototype.intersectPlane = function(plane) {
  20830. return OrientedBoundingBox.intersectPlane(this, plane);
  20831. };
  20832. /**
  20833. * Computes the estimated distance squared from the closest point on a bounding box to a point.
  20834. *
  20835. * @param {Cartesian3} cartesian The point
  20836. * @returns {Number} The estimated distance squared from the bounding sphere to the point.
  20837. *
  20838. * @example
  20839. * // Sort bounding boxes from back to front
  20840. * boxes.sort(function(a, b) {
  20841. * return b.distanceSquaredTo(camera.positionWC) - a.distanceSquaredTo(camera.positionWC);
  20842. * });
  20843. */
  20844. OrientedBoundingBox.prototype.distanceSquaredTo = function(cartesian) {
  20845. return OrientedBoundingBox.distanceSquaredTo(this, cartesian);
  20846. };
  20847. /**
  20848. * The distances calculated by the vector from the center of the bounding box to position projected onto direction.
  20849. * <br>
  20850. * If you imagine the infinite number of planes with normal direction, this computes the smallest distance to the
  20851. * closest and farthest planes from position that intersect the bounding box.
  20852. *
  20853. * @param {Cartesian3} position The position to calculate the distance from.
  20854. * @param {Cartesian3} direction The direction from position.
  20855. * @param {Interval} [result] A Interval to store the nearest and farthest distances.
  20856. * @returns {Interval} The nearest and farthest distances on the bounding box from position in direction.
  20857. */
  20858. OrientedBoundingBox.prototype.computePlaneDistances = function(position, direction, result) {
  20859. return OrientedBoundingBox.computePlaneDistances(this, position, direction, result);
  20860. };
  20861. /**
  20862. * Determines whether or not a bounding box is hidden from view by the occluder.
  20863. *
  20864. * @param {Occluder} occluder The occluder.
  20865. * @returns {Boolean} <code>true</code> if the sphere is not visible; otherwise <code>false</code>.
  20866. */
  20867. OrientedBoundingBox.prototype.isOccluded = function(occluder) {
  20868. return OrientedBoundingBox.isOccluded(this, occluder);
  20869. };
  20870. /**
  20871. * Compares the provided OrientedBoundingBox componentwise and returns
  20872. * <code>true</code> if they are equal, <code>false</code> otherwise.
  20873. *
  20874. * @param {OrientedBoundingBox} left The first OrientedBoundingBox.
  20875. * @param {OrientedBoundingBox} right The second OrientedBoundingBox.
  20876. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  20877. */
  20878. OrientedBoundingBox.equals = function(left, right) {
  20879. return (left === right) ||
  20880. ((defined(left)) &&
  20881. (defined(right)) &&
  20882. Cartesian3.equals(left.center, right.center) &&
  20883. Matrix3.equals(left.halfAxes, right.halfAxes));
  20884. };
  20885. /**
  20886. * Duplicates this OrientedBoundingBox instance.
  20887. *
  20888. * @param {OrientedBoundingBox} [result] The object onto which to store the result.
  20889. * @returns {OrientedBoundingBox} The modified result parameter or a new OrientedBoundingBox instance if one was not provided.
  20890. */
  20891. OrientedBoundingBox.prototype.clone = function(result) {
  20892. return OrientedBoundingBox.clone(this, result);
  20893. };
  20894. /**
  20895. * Compares this OrientedBoundingBox against the provided OrientedBoundingBox componentwise and returns
  20896. * <code>true</code> if they are equal, <code>false</code> otherwise.
  20897. *
  20898. * @param {OrientedBoundingBox} [right] The right hand side OrientedBoundingBox.
  20899. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  20900. */
  20901. OrientedBoundingBox.prototype.equals = function(right) {
  20902. return OrientedBoundingBox.equals(this, right);
  20903. };
  20904. return OrientedBoundingBox;
  20905. });
  20906. /*global define*/
  20907. define('Core/AttributeCompression',[
  20908. './Cartesian2',
  20909. './Cartesian3',
  20910. './defined',
  20911. './DeveloperError',
  20912. './Math'
  20913. ], function(
  20914. Cartesian2,
  20915. Cartesian3,
  20916. defined,
  20917. DeveloperError,
  20918. CesiumMath) {
  20919. 'use strict';
  20920. /**
  20921. * Attribute compression and decompression functions.
  20922. *
  20923. * @exports AttributeCompression
  20924. *
  20925. * @private
  20926. */
  20927. var AttributeCompression = {};
  20928. /**
  20929. * Encodes a normalized vector into 2 SNORM values in the range of [0-rangeMax] following the 'oct' encoding.
  20930. *
  20931. * Oct encoding is a compact representation of unit length vectors.
  20932. * The 'oct' encoding is described in "A Survey of Efficient Representations of Independent Unit Vectors",
  20933. * Cigolle et al 2014: {@link http://jcgt.org/published/0003/02/01/}
  20934. *
  20935. * @param {Cartesian3} vector The normalized vector to be compressed into 2 component 'oct' encoding.
  20936. * @param {Cartesian2} result The 2 component oct-encoded unit length vector.
  20937. * @param {Number} rangeMax The maximum value of the SNORM range. The encoded vector is stored in log2(rangeMax+1) bits.
  20938. * @returns {Cartesian2} The 2 component oct-encoded unit length vector.
  20939. *
  20940. * @exception {DeveloperError} vector must be normalized.
  20941. *
  20942. * @see AttributeCompression.octDecodeInRange
  20943. */
  20944. AttributeCompression.octEncodeInRange = function(vector, rangeMax, result) {
  20945. if (!defined(vector)) {
  20946. throw new DeveloperError('vector is required.');
  20947. }
  20948. if (!defined(result)) {
  20949. throw new DeveloperError('result is required.');
  20950. }
  20951. var magSquared = Cartesian3.magnitudeSquared(vector);
  20952. if (Math.abs(magSquared - 1.0) > CesiumMath.EPSILON6) {
  20953. throw new DeveloperError('vector must be normalized.');
  20954. }
  20955. result.x = vector.x / (Math.abs(vector.x) + Math.abs(vector.y) + Math.abs(vector.z));
  20956. result.y = vector.y / (Math.abs(vector.x) + Math.abs(vector.y) + Math.abs(vector.z));
  20957. if (vector.z < 0) {
  20958. var x = result.x;
  20959. var y = result.y;
  20960. result.x = (1.0 - Math.abs(y)) * CesiumMath.signNotZero(x);
  20961. result.y = (1.0 - Math.abs(x)) * CesiumMath.signNotZero(y);
  20962. }
  20963. result.x = CesiumMath.toSNorm(result.x, rangeMax);
  20964. result.y = CesiumMath.toSNorm(result.y, rangeMax);
  20965. return result;
  20966. };
  20967. /**
  20968. * Encodes a normalized vector into 2 SNORM values in the range of [0-255] following the 'oct' encoding.
  20969. *
  20970. * @param {Cartesian3} vector The normalized vector to be compressed into 2 byte 'oct' encoding.
  20971. * @param {Cartesian2} result The 2 byte oct-encoded unit length vector.
  20972. * @returns {Cartesian2} The 2 byte oct-encoded unit length vector.
  20973. *
  20974. * @exception {DeveloperError} vector must be normalized.
  20975. *
  20976. * @see AttributeCompression.octEncodeInRange
  20977. * @see AttributeCompression.octDecode
  20978. */
  20979. AttributeCompression.octEncode = function(vector, result) {
  20980. return AttributeCompression.octEncodeInRange(vector, 255, result);
  20981. };
  20982. /**
  20983. * Decodes a unit-length vector in 'oct' encoding to a normalized 3-component vector.
  20984. *
  20985. * @param {Number} x The x component of the oct-encoded unit length vector.
  20986. * @param {Number} y The y component of the oct-encoded unit length vector.
  20987. * @param {Number} rangeMax The maximum value of the SNORM range. The encoded vector is stored in log2(rangeMax+1) bits.
  20988. * @param {Cartesian3} result The decoded and normalized vector
  20989. * @returns {Cartesian3} The decoded and normalized vector.
  20990. *
  20991. * @exception {DeveloperError} x and y must be an unsigned normalized integer between 0 and rangeMax.
  20992. *
  20993. * @see AttributeCompression.octEncodeInRange
  20994. */
  20995. AttributeCompression.octDecodeInRange = function(x, y, rangeMax, result) {
  20996. if (!defined(result)) {
  20997. throw new DeveloperError('result is required.');
  20998. }
  20999. if (x < 0 || x > rangeMax || y < 0 || y > rangeMax) {
  21000. throw new DeveloperError('x and y must be a signed normalized integer between 0 and ' + rangeMax);
  21001. }
  21002. result.x = CesiumMath.fromSNorm(x, rangeMax);
  21003. result.y = CesiumMath.fromSNorm(y, rangeMax);
  21004. result.z = 1.0 - (Math.abs(result.x) + Math.abs(result.y));
  21005. if (result.z < 0.0)
  21006. {
  21007. var oldVX = result.x;
  21008. result.x = (1.0 - Math.abs(result.y)) * CesiumMath.signNotZero(oldVX);
  21009. result.y = (1.0 - Math.abs(oldVX)) * CesiumMath.signNotZero(result.y);
  21010. }
  21011. return Cartesian3.normalize(result, result);
  21012. };
  21013. /**
  21014. * Decodes a unit-length vector in 2 byte 'oct' encoding to a normalized 3-component vector.
  21015. *
  21016. * @param {Number} x The x component of the oct-encoded unit length vector.
  21017. * @param {Number} y The y component of the oct-encoded unit length vector.
  21018. * @param {Cartesian3} result The decoded and normalized vector.
  21019. * @returns {Cartesian3} The decoded and normalized vector.
  21020. *
  21021. * @exception {DeveloperError} x and y must be an unsigned normalized integer between 0 and 255.
  21022. *
  21023. * @see AttributeCompression.octDecodeInRange
  21024. */
  21025. AttributeCompression.octDecode = function(x, y, result) {
  21026. return AttributeCompression.octDecodeInRange(x, y, 255, result);
  21027. };
  21028. /**
  21029. * Packs an oct encoded vector into a single floating-point number.
  21030. *
  21031. * @param {Cartesian2} encoded The oct encoded vector.
  21032. * @returns {Number} The oct encoded vector packed into a single float.
  21033. *
  21034. */
  21035. AttributeCompression.octPackFloat = function(encoded) {
  21036. if (!defined(encoded)) {
  21037. throw new DeveloperError('encoded is required.');
  21038. }
  21039. return 256.0 * encoded.x + encoded.y;
  21040. };
  21041. var scratchEncodeCart2 = new Cartesian2();
  21042. /**
  21043. * Encodes a normalized vector into 2 SNORM values in the range of [0-255] following the 'oct' encoding and
  21044. * stores those values in a single float-point number.
  21045. *
  21046. * @param {Cartesian3} vector The normalized vector to be compressed into 2 byte 'oct' encoding.
  21047. * @returns {Number} The 2 byte oct-encoded unit length vector.
  21048. *
  21049. * @exception {DeveloperError} vector must be normalized.
  21050. */
  21051. AttributeCompression.octEncodeFloat = function(vector) {
  21052. AttributeCompression.octEncode(vector, scratchEncodeCart2);
  21053. return AttributeCompression.octPackFloat(scratchEncodeCart2);
  21054. };
  21055. /**
  21056. * Decodes a unit-length vector in 'oct' encoding packed in a floating-point number to a normalized 3-component vector.
  21057. *
  21058. * @param {Number} value The oct-encoded unit length vector stored as a single floating-point number.
  21059. * @param {Cartesian3} result The decoded and normalized vector
  21060. * @returns {Cartesian3} The decoded and normalized vector.
  21061. *
  21062. */
  21063. AttributeCompression.octDecodeFloat = function(value, result) {
  21064. if (!defined(value)) {
  21065. throw new DeveloperError('value is required.');
  21066. }
  21067. var temp = value / 256.0;
  21068. var x = Math.floor(temp);
  21069. var y = (temp - x) * 256.0;
  21070. return AttributeCompression.octDecode(x, y, result);
  21071. };
  21072. /**
  21073. * Encodes three normalized vectors into 6 SNORM values in the range of [0-255] following the 'oct' encoding and
  21074. * packs those into two floating-point numbers.
  21075. *
  21076. * @param {Cartesian3} v1 A normalized vector to be compressed.
  21077. * @param {Cartesian3} v2 A normalized vector to be compressed.
  21078. * @param {Cartesian3} v3 A normalized vector to be compressed.
  21079. * @param {Cartesian2} result The 'oct' encoded vectors packed into two floating-point numbers.
  21080. * @returns {Cartesian2} The 'oct' encoded vectors packed into two floating-point numbers.
  21081. *
  21082. */
  21083. AttributeCompression.octPack = function(v1, v2, v3, result) {
  21084. if (!defined(v1)) {
  21085. throw new DeveloperError('v1 is required.');
  21086. }
  21087. if (!defined(v2)) {
  21088. throw new DeveloperError('v2 is required.');
  21089. }
  21090. if (!defined(v3)) {
  21091. throw new DeveloperError('v3 is required.');
  21092. }
  21093. if (!defined(result)) {
  21094. throw new DeveloperError('result is required.');
  21095. }
  21096. var encoded1 = AttributeCompression.octEncodeFloat(v1);
  21097. var encoded2 = AttributeCompression.octEncodeFloat(v2);
  21098. var encoded3 = AttributeCompression.octEncode(v3, scratchEncodeCart2);
  21099. result.x = 65536.0 * encoded3.x + encoded1;
  21100. result.y = 65536.0 * encoded3.y + encoded2;
  21101. return result;
  21102. };
  21103. /**
  21104. * Decodes three unit-length vectors in 'oct' encoding packed into a floating-point number to a normalized 3-component vector.
  21105. *
  21106. * @param {Cartesian2} packed The three oct-encoded unit length vectors stored as two floating-point number.
  21107. * @param {Cartesian3} v1 One decoded and normalized vector.
  21108. * @param {Cartesian3} v2 One decoded and normalized vector.
  21109. * @param {Cartesian3} v3 One decoded and normalized vector.
  21110. */
  21111. AttributeCompression.octUnpack = function(packed, v1, v2, v3) {
  21112. if (!defined(packed)) {
  21113. throw new DeveloperError('packed is required.');
  21114. }
  21115. if (!defined(v1)) {
  21116. throw new DeveloperError('v1 is required.');
  21117. }
  21118. if (!defined(v2)) {
  21119. throw new DeveloperError('v2 is required.');
  21120. }
  21121. if (!defined(v3)) {
  21122. throw new DeveloperError('v3 is required.');
  21123. }
  21124. var temp = packed.x / 65536.0;
  21125. var x = Math.floor(temp);
  21126. var encodedFloat1 = (temp - x) * 65536.0;
  21127. temp = packed.y / 65536.0;
  21128. var y = Math.floor(temp);
  21129. var encodedFloat2 = (temp - y) * 65536.0;
  21130. AttributeCompression.octDecodeFloat(encodedFloat1, v1);
  21131. AttributeCompression.octDecodeFloat(encodedFloat2, v2);
  21132. AttributeCompression.octDecode(x, y, v3);
  21133. };
  21134. /**
  21135. * Pack texture coordinates into a single float. The texture coordinates will only preserve 12 bits of precision.
  21136. *
  21137. * @param {Cartesian2} textureCoordinates The texture coordinates to compress. Both coordinates must be in the range 0.0-1.0.
  21138. * @returns {Number} The packed texture coordinates.
  21139. *
  21140. */
  21141. AttributeCompression.compressTextureCoordinates = function(textureCoordinates) {
  21142. if (!defined(textureCoordinates)) {
  21143. throw new DeveloperError('textureCoordinates is required.');
  21144. }
  21145. // Move x and y to the range 0-4095;
  21146. var x = (textureCoordinates.x * 4095.0) | 0;
  21147. var y = (textureCoordinates.y * 4095.0) | 0;
  21148. return 4096.0 * x + y;
  21149. };
  21150. /**
  21151. * Decompresses texture coordinates that were packed into a single float.
  21152. *
  21153. * @param {Number} compressed The compressed texture coordinates.
  21154. * @param {Cartesian2} result The decompressed texture coordinates.
  21155. * @returns {Cartesian2} The modified result parameter.
  21156. *
  21157. */
  21158. AttributeCompression.decompressTextureCoordinates = function(compressed, result) {
  21159. if (!defined(compressed)) {
  21160. throw new DeveloperError('compressed is required.');
  21161. }
  21162. if (!defined(result)) {
  21163. throw new DeveloperError('result is required.');
  21164. }
  21165. var temp = compressed / 4096.0;
  21166. var xZeroTo4095 = Math.floor(temp);
  21167. result.x = xZeroTo4095 / 4095.0;
  21168. result.y = (compressed - xZeroTo4095 * 4096) / 4095;
  21169. return result;
  21170. };
  21171. return AttributeCompression;
  21172. });
  21173. /*global define*/
  21174. define('Core/WebGLConstants',[
  21175. './freezeObject'
  21176. ], function(
  21177. freezeObject) {
  21178. 'use strict';
  21179. /**
  21180. * Enum containing WebGL Constant values by name.
  21181. * for use without an active WebGL context, or in cases where certain constants are unavailable using the WebGL context
  21182. * (For example, in [Safari 9]{@link https://github.com/AnalyticalGraphicsInc/cesium/issues/2989}).
  21183. *
  21184. * These match the constants from the [WebGL 1.0]{@link https://www.khronos.org/registry/webgl/specs/latest/1.0/}
  21185. * and [WebGL 2.0]{@link https://www.khronos.org/registry/webgl/specs/latest/2.0/}
  21186. * specifications.
  21187. *
  21188. * @exports WebGLConstants
  21189. */
  21190. var WebGLConstants = {
  21191. DEPTH_BUFFER_BIT : 0x00000100,
  21192. STENCIL_BUFFER_BIT : 0x00000400,
  21193. COLOR_BUFFER_BIT : 0x00004000,
  21194. POINTS : 0x0000,
  21195. LINES : 0x0001,
  21196. LINE_LOOP : 0x0002,
  21197. LINE_STRIP : 0x0003,
  21198. TRIANGLES : 0x0004,
  21199. TRIANGLE_STRIP : 0x0005,
  21200. TRIANGLE_FAN : 0x0006,
  21201. ZERO : 0,
  21202. ONE : 1,
  21203. SRC_COLOR : 0x0300,
  21204. ONE_MINUS_SRC_COLOR : 0x0301,
  21205. SRC_ALPHA : 0x0302,
  21206. ONE_MINUS_SRC_ALPHA : 0x0303,
  21207. DST_ALPHA : 0x0304,
  21208. ONE_MINUS_DST_ALPHA : 0x0305,
  21209. DST_COLOR : 0x0306,
  21210. ONE_MINUS_DST_COLOR : 0x0307,
  21211. SRC_ALPHA_SATURATE : 0x0308,
  21212. FUNC_ADD : 0x8006,
  21213. BLEND_EQUATION : 0x8009,
  21214. BLEND_EQUATION_RGB : 0x8009, // same as BLEND_EQUATION
  21215. BLEND_EQUATION_ALPHA : 0x883D,
  21216. FUNC_SUBTRACT : 0x800A,
  21217. FUNC_REVERSE_SUBTRACT : 0x800B,
  21218. BLEND_DST_RGB : 0x80C8,
  21219. BLEND_SRC_RGB : 0x80C9,
  21220. BLEND_DST_ALPHA : 0x80CA,
  21221. BLEND_SRC_ALPHA : 0x80CB,
  21222. CONSTANT_COLOR : 0x8001,
  21223. ONE_MINUS_CONSTANT_COLOR : 0x8002,
  21224. CONSTANT_ALPHA : 0x8003,
  21225. ONE_MINUS_CONSTANT_ALPHA : 0x8004,
  21226. BLEND_COLOR : 0x8005,
  21227. ARRAY_BUFFER : 0x8892,
  21228. ELEMENT_ARRAY_BUFFER : 0x8893,
  21229. ARRAY_BUFFER_BINDING : 0x8894,
  21230. ELEMENT_ARRAY_BUFFER_BINDING : 0x8895,
  21231. STREAM_DRAW : 0x88E0,
  21232. STATIC_DRAW : 0x88E4,
  21233. DYNAMIC_DRAW : 0x88E8,
  21234. BUFFER_SIZE : 0x8764,
  21235. BUFFER_USAGE : 0x8765,
  21236. CURRENT_VERTEX_ATTRIB : 0x8626,
  21237. FRONT : 0x0404,
  21238. BACK : 0x0405,
  21239. FRONT_AND_BACK : 0x0408,
  21240. CULL_FACE : 0x0B44,
  21241. BLEND : 0x0BE2,
  21242. DITHER : 0x0BD0,
  21243. STENCIL_TEST : 0x0B90,
  21244. DEPTH_TEST : 0x0B71,
  21245. SCISSOR_TEST : 0x0C11,
  21246. POLYGON_OFFSET_FILL : 0x8037,
  21247. SAMPLE_ALPHA_TO_COVERAGE : 0x809E,
  21248. SAMPLE_COVERAGE : 0x80A0,
  21249. NO_ERROR : 0,
  21250. INVALID_ENUM : 0x0500,
  21251. INVALID_VALUE : 0x0501,
  21252. INVALID_OPERATION : 0x0502,
  21253. OUT_OF_MEMORY : 0x0505,
  21254. CW : 0x0900,
  21255. CCW : 0x0901,
  21256. LINE_WIDTH : 0x0B21,
  21257. ALIASED_POINT_SIZE_RANGE : 0x846D,
  21258. ALIASED_LINE_WIDTH_RANGE : 0x846E,
  21259. CULL_FACE_MODE : 0x0B45,
  21260. FRONT_FACE : 0x0B46,
  21261. DEPTH_RANGE : 0x0B70,
  21262. DEPTH_WRITEMASK : 0x0B72,
  21263. DEPTH_CLEAR_VALUE : 0x0B73,
  21264. DEPTH_FUNC : 0x0B74,
  21265. STENCIL_CLEAR_VALUE : 0x0B91,
  21266. STENCIL_FUNC : 0x0B92,
  21267. STENCIL_FAIL : 0x0B94,
  21268. STENCIL_PASS_DEPTH_FAIL : 0x0B95,
  21269. STENCIL_PASS_DEPTH_PASS : 0x0B96,
  21270. STENCIL_REF : 0x0B97,
  21271. STENCIL_VALUE_MASK : 0x0B93,
  21272. STENCIL_WRITEMASK : 0x0B98,
  21273. STENCIL_BACK_FUNC : 0x8800,
  21274. STENCIL_BACK_FAIL : 0x8801,
  21275. STENCIL_BACK_PASS_DEPTH_FAIL : 0x8802,
  21276. STENCIL_BACK_PASS_DEPTH_PASS : 0x8803,
  21277. STENCIL_BACK_REF : 0x8CA3,
  21278. STENCIL_BACK_VALUE_MASK : 0x8CA4,
  21279. STENCIL_BACK_WRITEMASK : 0x8CA5,
  21280. VIEWPORT : 0x0BA2,
  21281. SCISSOR_BOX : 0x0C10,
  21282. COLOR_CLEAR_VALUE : 0x0C22,
  21283. COLOR_WRITEMASK : 0x0C23,
  21284. UNPACK_ALIGNMENT : 0x0CF5,
  21285. PACK_ALIGNMENT : 0x0D05,
  21286. MAX_TEXTURE_SIZE : 0x0D33,
  21287. MAX_VIEWPORT_DIMS : 0x0D3A,
  21288. SUBPIXEL_BITS : 0x0D50,
  21289. RED_BITS : 0x0D52,
  21290. GREEN_BITS : 0x0D53,
  21291. BLUE_BITS : 0x0D54,
  21292. ALPHA_BITS : 0x0D55,
  21293. DEPTH_BITS : 0x0D56,
  21294. STENCIL_BITS : 0x0D57,
  21295. POLYGON_OFFSET_UNITS : 0x2A00,
  21296. POLYGON_OFFSET_FACTOR : 0x8038,
  21297. TEXTURE_BINDING_2D : 0x8069,
  21298. SAMPLE_BUFFERS : 0x80A8,
  21299. SAMPLES : 0x80A9,
  21300. SAMPLE_COVERAGE_VALUE : 0x80AA,
  21301. SAMPLE_COVERAGE_INVERT : 0x80AB,
  21302. COMPRESSED_TEXTURE_FORMATS : 0x86A3,
  21303. DONT_CARE : 0x1100,
  21304. FASTEST : 0x1101,
  21305. NICEST : 0x1102,
  21306. GENERATE_MIPMAP_HINT : 0x8192,
  21307. BYTE : 0x1400,
  21308. UNSIGNED_BYTE : 0x1401,
  21309. SHORT : 0x1402,
  21310. UNSIGNED_SHORT : 0x1403,
  21311. INT : 0x1404,
  21312. UNSIGNED_INT : 0x1405,
  21313. FLOAT : 0x1406,
  21314. DEPTH_COMPONENT : 0x1902,
  21315. ALPHA : 0x1906,
  21316. RGB : 0x1907,
  21317. RGBA : 0x1908,
  21318. LUMINANCE : 0x1909,
  21319. LUMINANCE_ALPHA : 0x190A,
  21320. UNSIGNED_SHORT_4_4_4_4 : 0x8033,
  21321. UNSIGNED_SHORT_5_5_5_1 : 0x8034,
  21322. UNSIGNED_SHORT_5_6_5 : 0x8363,
  21323. FRAGMENT_SHADER : 0x8B30,
  21324. VERTEX_SHADER : 0x8B31,
  21325. MAX_VERTEX_ATTRIBS : 0x8869,
  21326. MAX_VERTEX_UNIFORM_VECTORS : 0x8DFB,
  21327. MAX_VARYING_VECTORS : 0x8DFC,
  21328. MAX_COMBINED_TEXTURE_IMAGE_UNITS : 0x8B4D,
  21329. MAX_VERTEX_TEXTURE_IMAGE_UNITS : 0x8B4C,
  21330. MAX_TEXTURE_IMAGE_UNITS : 0x8872,
  21331. MAX_FRAGMENT_UNIFORM_VECTORS : 0x8DFD,
  21332. SHADER_TYPE : 0x8B4F,
  21333. DELETE_STATUS : 0x8B80,
  21334. LINK_STATUS : 0x8B82,
  21335. VALIDATE_STATUS : 0x8B83,
  21336. ATTACHED_SHADERS : 0x8B85,
  21337. ACTIVE_UNIFORMS : 0x8B86,
  21338. ACTIVE_ATTRIBUTES : 0x8B89,
  21339. SHADING_LANGUAGE_VERSION : 0x8B8C,
  21340. CURRENT_PROGRAM : 0x8B8D,
  21341. NEVER : 0x0200,
  21342. LESS : 0x0201,
  21343. EQUAL : 0x0202,
  21344. LEQUAL : 0x0203,
  21345. GREATER : 0x0204,
  21346. NOTEQUAL : 0x0205,
  21347. GEQUAL : 0x0206,
  21348. ALWAYS : 0x0207,
  21349. KEEP : 0x1E00,
  21350. REPLACE : 0x1E01,
  21351. INCR : 0x1E02,
  21352. DECR : 0x1E03,
  21353. INVERT : 0x150A,
  21354. INCR_WRAP : 0x8507,
  21355. DECR_WRAP : 0x8508,
  21356. VENDOR : 0x1F00,
  21357. RENDERER : 0x1F01,
  21358. VERSION : 0x1F02,
  21359. NEAREST : 0x2600,
  21360. LINEAR : 0x2601,
  21361. NEAREST_MIPMAP_NEAREST : 0x2700,
  21362. LINEAR_MIPMAP_NEAREST : 0x2701,
  21363. NEAREST_MIPMAP_LINEAR : 0x2702,
  21364. LINEAR_MIPMAP_LINEAR : 0x2703,
  21365. TEXTURE_MAG_FILTER : 0x2800,
  21366. TEXTURE_MIN_FILTER : 0x2801,
  21367. TEXTURE_WRAP_S : 0x2802,
  21368. TEXTURE_WRAP_T : 0x2803,
  21369. TEXTURE_2D : 0x0DE1,
  21370. TEXTURE : 0x1702,
  21371. TEXTURE_CUBE_MAP : 0x8513,
  21372. TEXTURE_BINDING_CUBE_MAP : 0x8514,
  21373. TEXTURE_CUBE_MAP_POSITIVE_X : 0x8515,
  21374. TEXTURE_CUBE_MAP_NEGATIVE_X : 0x8516,
  21375. TEXTURE_CUBE_MAP_POSITIVE_Y : 0x8517,
  21376. TEXTURE_CUBE_MAP_NEGATIVE_Y : 0x8518,
  21377. TEXTURE_CUBE_MAP_POSITIVE_Z : 0x8519,
  21378. TEXTURE_CUBE_MAP_NEGATIVE_Z : 0x851A,
  21379. MAX_CUBE_MAP_TEXTURE_SIZE : 0x851C,
  21380. TEXTURE0 : 0x84C0,
  21381. TEXTURE1 : 0x84C1,
  21382. TEXTURE2 : 0x84C2,
  21383. TEXTURE3 : 0x84C3,
  21384. TEXTURE4 : 0x84C4,
  21385. TEXTURE5 : 0x84C5,
  21386. TEXTURE6 : 0x84C6,
  21387. TEXTURE7 : 0x84C7,
  21388. TEXTURE8 : 0x84C8,
  21389. TEXTURE9 : 0x84C9,
  21390. TEXTURE10 : 0x84CA,
  21391. TEXTURE11 : 0x84CB,
  21392. TEXTURE12 : 0x84CC,
  21393. TEXTURE13 : 0x84CD,
  21394. TEXTURE14 : 0x84CE,
  21395. TEXTURE15 : 0x84CF,
  21396. TEXTURE16 : 0x84D0,
  21397. TEXTURE17 : 0x84D1,
  21398. TEXTURE18 : 0x84D2,
  21399. TEXTURE19 : 0x84D3,
  21400. TEXTURE20 : 0x84D4,
  21401. TEXTURE21 : 0x84D5,
  21402. TEXTURE22 : 0x84D6,
  21403. TEXTURE23 : 0x84D7,
  21404. TEXTURE24 : 0x84D8,
  21405. TEXTURE25 : 0x84D9,
  21406. TEXTURE26 : 0x84DA,
  21407. TEXTURE27 : 0x84DB,
  21408. TEXTURE28 : 0x84DC,
  21409. TEXTURE29 : 0x84DD,
  21410. TEXTURE30 : 0x84DE,
  21411. TEXTURE31 : 0x84DF,
  21412. ACTIVE_TEXTURE : 0x84E0,
  21413. REPEAT : 0x2901,
  21414. CLAMP_TO_EDGE : 0x812F,
  21415. MIRRORED_REPEAT : 0x8370,
  21416. FLOAT_VEC2 : 0x8B50,
  21417. FLOAT_VEC3 : 0x8B51,
  21418. FLOAT_VEC4 : 0x8B52,
  21419. INT_VEC2 : 0x8B53,
  21420. INT_VEC3 : 0x8B54,
  21421. INT_VEC4 : 0x8B55,
  21422. BOOL : 0x8B56,
  21423. BOOL_VEC2 : 0x8B57,
  21424. BOOL_VEC3 : 0x8B58,
  21425. BOOL_VEC4 : 0x8B59,
  21426. FLOAT_MAT2 : 0x8B5A,
  21427. FLOAT_MAT3 : 0x8B5B,
  21428. FLOAT_MAT4 : 0x8B5C,
  21429. SAMPLER_2D : 0x8B5E,
  21430. SAMPLER_CUBE : 0x8B60,
  21431. VERTEX_ATTRIB_ARRAY_ENABLED : 0x8622,
  21432. VERTEX_ATTRIB_ARRAY_SIZE : 0x8623,
  21433. VERTEX_ATTRIB_ARRAY_STRIDE : 0x8624,
  21434. VERTEX_ATTRIB_ARRAY_TYPE : 0x8625,
  21435. VERTEX_ATTRIB_ARRAY_NORMALIZED : 0x886A,
  21436. VERTEX_ATTRIB_ARRAY_POINTER : 0x8645,
  21437. VERTEX_ATTRIB_ARRAY_BUFFER_BINDING : 0x889F,
  21438. IMPLEMENTATION_COLOR_READ_TYPE : 0x8B9A,
  21439. IMPLEMENTATION_COLOR_READ_FORMAT : 0x8B9B,
  21440. COMPILE_STATUS : 0x8B81,
  21441. LOW_FLOAT : 0x8DF0,
  21442. MEDIUM_FLOAT : 0x8DF1,
  21443. HIGH_FLOAT : 0x8DF2,
  21444. LOW_INT : 0x8DF3,
  21445. MEDIUM_INT : 0x8DF4,
  21446. HIGH_INT : 0x8DF5,
  21447. FRAMEBUFFER : 0x8D40,
  21448. RENDERBUFFER : 0x8D41,
  21449. RGBA4 : 0x8056,
  21450. RGB5_A1 : 0x8057,
  21451. RGB565 : 0x8D62,
  21452. DEPTH_COMPONENT16 : 0x81A5,
  21453. STENCIL_INDEX : 0x1901,
  21454. STENCIL_INDEX8 : 0x8D48,
  21455. DEPTH_STENCIL : 0x84F9,
  21456. RENDERBUFFER_WIDTH : 0x8D42,
  21457. RENDERBUFFER_HEIGHT : 0x8D43,
  21458. RENDERBUFFER_INTERNAL_FORMAT : 0x8D44,
  21459. RENDERBUFFER_RED_SIZE : 0x8D50,
  21460. RENDERBUFFER_GREEN_SIZE : 0x8D51,
  21461. RENDERBUFFER_BLUE_SIZE : 0x8D52,
  21462. RENDERBUFFER_ALPHA_SIZE : 0x8D53,
  21463. RENDERBUFFER_DEPTH_SIZE : 0x8D54,
  21464. RENDERBUFFER_STENCIL_SIZE : 0x8D55,
  21465. FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE : 0x8CD0,
  21466. FRAMEBUFFER_ATTACHMENT_OBJECT_NAME : 0x8CD1,
  21467. FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL : 0x8CD2,
  21468. FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE : 0x8CD3,
  21469. COLOR_ATTACHMENT0 : 0x8CE0,
  21470. DEPTH_ATTACHMENT : 0x8D00,
  21471. STENCIL_ATTACHMENT : 0x8D20,
  21472. DEPTH_STENCIL_ATTACHMENT : 0x821A,
  21473. NONE : 0,
  21474. FRAMEBUFFER_COMPLETE : 0x8CD5,
  21475. FRAMEBUFFER_INCOMPLETE_ATTACHMENT : 0x8CD6,
  21476. FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : 0x8CD7,
  21477. FRAMEBUFFER_INCOMPLETE_DIMENSIONS : 0x8CD9,
  21478. FRAMEBUFFER_UNSUPPORTED : 0x8CDD,
  21479. FRAMEBUFFER_BINDING : 0x8CA6,
  21480. RENDERBUFFER_BINDING : 0x8CA7,
  21481. MAX_RENDERBUFFER_SIZE : 0x84E8,
  21482. INVALID_FRAMEBUFFER_OPERATION : 0x0506,
  21483. UNPACK_FLIP_Y_WEBGL : 0x9240,
  21484. UNPACK_PREMULTIPLY_ALPHA_WEBGL : 0x9241,
  21485. CONTEXT_LOST_WEBGL : 0x9242,
  21486. UNPACK_COLORSPACE_CONVERSION_WEBGL : 0x9243,
  21487. BROWSER_DEFAULT_WEBGL : 0x9244,
  21488. // Desktop OpenGL
  21489. DOUBLE : 0x140A,
  21490. // WebGL 2
  21491. READ_BUFFER : 0x0C02,
  21492. UNPACK_ROW_LENGTH : 0x0CF2,
  21493. UNPACK_SKIP_ROWS : 0x0CF3,
  21494. UNPACK_SKIP_PIXELS : 0x0CF4,
  21495. PACK_ROW_LENGTH : 0x0D02,
  21496. PACK_SKIP_ROWS : 0x0D03,
  21497. PACK_SKIP_PIXELS : 0x0D04,
  21498. COLOR : 0x1800,
  21499. DEPTH : 0x1801,
  21500. STENCIL : 0x1802,
  21501. RED : 0x1903,
  21502. RGB8 : 0x8051,
  21503. RGBA8 : 0x8058,
  21504. RGB10_A2 : 0x8059,
  21505. TEXTURE_BINDING_3D : 0x806A,
  21506. UNPACK_SKIP_IMAGES : 0x806D,
  21507. UNPACK_IMAGE_HEIGHT : 0x806E,
  21508. TEXTURE_3D : 0x806F,
  21509. TEXTURE_WRAP_R : 0x8072,
  21510. MAX_3D_TEXTURE_SIZE : 0x8073,
  21511. UNSIGNED_INT_2_10_10_10_REV : 0x8368,
  21512. MAX_ELEMENTS_VERTICES : 0x80E8,
  21513. MAX_ELEMENTS_INDICES : 0x80E9,
  21514. TEXTURE_MIN_LOD : 0x813A,
  21515. TEXTURE_MAX_LOD : 0x813B,
  21516. TEXTURE_BASE_LEVEL : 0x813C,
  21517. TEXTURE_MAX_LEVEL : 0x813D,
  21518. MIN : 0x8007,
  21519. MAX : 0x8008,
  21520. DEPTH_COMPONENT24 : 0x81A6,
  21521. MAX_TEXTURE_LOD_BIAS : 0x84FD,
  21522. TEXTURE_COMPARE_MODE : 0x884C,
  21523. TEXTURE_COMPARE_FUNC : 0x884D,
  21524. CURRENT_QUERY : 0x8865,
  21525. QUERY_RESULT : 0x8866,
  21526. QUERY_RESULT_AVAILABLE : 0x8867,
  21527. STREAM_READ : 0x88E1,
  21528. STREAM_COPY : 0x88E2,
  21529. STATIC_READ : 0x88E5,
  21530. STATIC_COPY : 0x88E6,
  21531. DYNAMIC_READ : 0x88E9,
  21532. DYNAMIC_COPY : 0x88EA,
  21533. MAX_DRAW_BUFFERS : 0x8824,
  21534. DRAW_BUFFER0 : 0x8825,
  21535. DRAW_BUFFER1 : 0x8826,
  21536. DRAW_BUFFER2 : 0x8827,
  21537. DRAW_BUFFER3 : 0x8828,
  21538. DRAW_BUFFER4 : 0x8829,
  21539. DRAW_BUFFER5 : 0x882A,
  21540. DRAW_BUFFER6 : 0x882B,
  21541. DRAW_BUFFER7 : 0x882C,
  21542. DRAW_BUFFER8 : 0x882D,
  21543. DRAW_BUFFER9 : 0x882E,
  21544. DRAW_BUFFER10 : 0x882F,
  21545. DRAW_BUFFER11 : 0x8830,
  21546. DRAW_BUFFER12 : 0x8831,
  21547. DRAW_BUFFER13 : 0x8832,
  21548. DRAW_BUFFER14 : 0x8833,
  21549. DRAW_BUFFER15 : 0x8834,
  21550. MAX_FRAGMENT_UNIFORM_COMPONENTS : 0x8B49,
  21551. MAX_VERTEX_UNIFORM_COMPONENTS : 0x8B4A,
  21552. SAMPLER_3D : 0x8B5F,
  21553. SAMPLER_2D_SHADOW : 0x8B62,
  21554. FRAGMENT_SHADER_DERIVATIVE_HINT : 0x8B8B,
  21555. PIXEL_PACK_BUFFER : 0x88EB,
  21556. PIXEL_UNPACK_BUFFER : 0x88EC,
  21557. PIXEL_PACK_BUFFER_BINDING : 0x88ED,
  21558. PIXEL_UNPACK_BUFFER_BINDING : 0x88EF,
  21559. FLOAT_MAT2x3 : 0x8B65,
  21560. FLOAT_MAT2x4 : 0x8B66,
  21561. FLOAT_MAT3x2 : 0x8B67,
  21562. FLOAT_MAT3x4 : 0x8B68,
  21563. FLOAT_MAT4x2 : 0x8B69,
  21564. FLOAT_MAT4x3 : 0x8B6A,
  21565. SRGB : 0x8C40,
  21566. SRGB8 : 0x8C41,
  21567. SRGB8_ALPHA8 : 0x8C43,
  21568. COMPARE_REF_TO_TEXTURE : 0x884E,
  21569. RGBA32F : 0x8814,
  21570. RGB32F : 0x8815,
  21571. RGBA16F : 0x881A,
  21572. RGB16F : 0x881B,
  21573. VERTEX_ATTRIB_ARRAY_INTEGER : 0x88FD,
  21574. MAX_ARRAY_TEXTURE_LAYERS : 0x88FF,
  21575. MIN_PROGRAM_TEXEL_OFFSET : 0x8904,
  21576. MAX_PROGRAM_TEXEL_OFFSET : 0x8905,
  21577. MAX_VARYING_COMPONENTS : 0x8B4B,
  21578. TEXTURE_2D_ARRAY : 0x8C1A,
  21579. TEXTURE_BINDING_2D_ARRAY : 0x8C1D,
  21580. R11F_G11F_B10F : 0x8C3A,
  21581. UNSIGNED_INT_10F_11F_11F_REV : 0x8C3B,
  21582. RGB9_E5 : 0x8C3D,
  21583. UNSIGNED_INT_5_9_9_9_REV : 0x8C3E,
  21584. TRANSFORM_FEEDBACK_BUFFER_MODE : 0x8C7F,
  21585. MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS : 0x8C80,
  21586. TRANSFORM_FEEDBACK_VARYINGS : 0x8C83,
  21587. TRANSFORM_FEEDBACK_BUFFER_START : 0x8C84,
  21588. TRANSFORM_FEEDBACK_BUFFER_SIZE : 0x8C85,
  21589. TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN : 0x8C88,
  21590. RASTERIZER_DISCARD : 0x8C89,
  21591. MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS : 0x8C8A,
  21592. MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS : 0x8C8B,
  21593. INTERLEAVED_ATTRIBS : 0x8C8C,
  21594. SEPARATE_ATTRIBS : 0x8C8D,
  21595. TRANSFORM_FEEDBACK_BUFFER : 0x8C8E,
  21596. TRANSFORM_FEEDBACK_BUFFER_BINDING : 0x8C8F,
  21597. RGBA32UI : 0x8D70,
  21598. RGB32UI : 0x8D71,
  21599. RGBA16UI : 0x8D76,
  21600. RGB16UI : 0x8D77,
  21601. RGBA8UI : 0x8D7C,
  21602. RGB8UI : 0x8D7D,
  21603. RGBA32I : 0x8D82,
  21604. RGB32I : 0x8D83,
  21605. RGBA16I : 0x8D88,
  21606. RGB16I : 0x8D89,
  21607. RGBA8I : 0x8D8E,
  21608. RGB8I : 0x8D8F,
  21609. RED_INTEGER : 0x8D94,
  21610. RGB_INTEGER : 0x8D98,
  21611. RGBA_INTEGER : 0x8D99,
  21612. SAMPLER_2D_ARRAY : 0x8DC1,
  21613. SAMPLER_2D_ARRAY_SHADOW : 0x8DC4,
  21614. SAMPLER_CUBE_SHADOW : 0x8DC5,
  21615. UNSIGNED_INT_VEC2 : 0x8DC6,
  21616. UNSIGNED_INT_VEC3 : 0x8DC7,
  21617. UNSIGNED_INT_VEC4 : 0x8DC8,
  21618. INT_SAMPLER_2D : 0x8DCA,
  21619. INT_SAMPLER_3D : 0x8DCB,
  21620. INT_SAMPLER_CUBE : 0x8DCC,
  21621. INT_SAMPLER_2D_ARRAY : 0x8DCF,
  21622. UNSIGNED_INT_SAMPLER_2D : 0x8DD2,
  21623. UNSIGNED_INT_SAMPLER_3D : 0x8DD3,
  21624. UNSIGNED_INT_SAMPLER_CUBE : 0x8DD4,
  21625. UNSIGNED_INT_SAMPLER_2D_ARRAY : 0x8DD7,
  21626. DEPTH_COMPONENT32F : 0x8CAC,
  21627. DEPTH32F_STENCIL8 : 0x8CAD,
  21628. FLOAT_32_UNSIGNED_INT_24_8_REV : 0x8DAD,
  21629. FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING : 0x8210,
  21630. FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE : 0x8211,
  21631. FRAMEBUFFER_ATTACHMENT_RED_SIZE : 0x8212,
  21632. FRAMEBUFFER_ATTACHMENT_GREEN_SIZE : 0x8213,
  21633. FRAMEBUFFER_ATTACHMENT_BLUE_SIZE : 0x8214,
  21634. FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE : 0x8215,
  21635. FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE : 0x8216,
  21636. FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE : 0x8217,
  21637. FRAMEBUFFER_DEFAULT : 0x8218,
  21638. UNSIGNED_INT_24_8 : 0x84FA,
  21639. DEPTH24_STENCIL8 : 0x88F0,
  21640. UNSIGNED_NORMALIZED : 0x8C17,
  21641. DRAW_FRAMEBUFFER_BINDING : 0x8CA6, // Same as FRAMEBUFFER_BINDING
  21642. READ_FRAMEBUFFER : 0x8CA8,
  21643. DRAW_FRAMEBUFFER : 0x8CA9,
  21644. READ_FRAMEBUFFER_BINDING : 0x8CAA,
  21645. RENDERBUFFER_SAMPLES : 0x8CAB,
  21646. FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER : 0x8CD4,
  21647. MAX_COLOR_ATTACHMENTS : 0x8CDF,
  21648. COLOR_ATTACHMENT1 : 0x8CE1,
  21649. COLOR_ATTACHMENT2 : 0x8CE2,
  21650. COLOR_ATTACHMENT3 : 0x8CE3,
  21651. COLOR_ATTACHMENT4 : 0x8CE4,
  21652. COLOR_ATTACHMENT5 : 0x8CE5,
  21653. COLOR_ATTACHMENT6 : 0x8CE6,
  21654. COLOR_ATTACHMENT7 : 0x8CE7,
  21655. COLOR_ATTACHMENT8 : 0x8CE8,
  21656. COLOR_ATTACHMENT9 : 0x8CE9,
  21657. COLOR_ATTACHMENT10 : 0x8CEA,
  21658. COLOR_ATTACHMENT11 : 0x8CEB,
  21659. COLOR_ATTACHMENT12 : 0x8CEC,
  21660. COLOR_ATTACHMENT13 : 0x8CED,
  21661. COLOR_ATTACHMENT14 : 0x8CEE,
  21662. COLOR_ATTACHMENT15 : 0x8CEF,
  21663. FRAMEBUFFER_INCOMPLETE_MULTISAMPLE : 0x8D56,
  21664. MAX_SAMPLES : 0x8D57,
  21665. HALF_FLOAT : 0x140B,
  21666. RG : 0x8227,
  21667. RG_INTEGER : 0x8228,
  21668. R8 : 0x8229,
  21669. RG8 : 0x822B,
  21670. R16F : 0x822D,
  21671. R32F : 0x822E,
  21672. RG16F : 0x822F,
  21673. RG32F : 0x8230,
  21674. R8I : 0x8231,
  21675. R8UI : 0x8232,
  21676. R16I : 0x8233,
  21677. R16UI : 0x8234,
  21678. R32I : 0x8235,
  21679. R32UI : 0x8236,
  21680. RG8I : 0x8237,
  21681. RG8UI : 0x8238,
  21682. RG16I : 0x8239,
  21683. RG16UI : 0x823A,
  21684. RG32I : 0x823B,
  21685. RG32UI : 0x823C,
  21686. VERTEX_ARRAY_BINDING : 0x85B5,
  21687. R8_SNORM : 0x8F94,
  21688. RG8_SNORM : 0x8F95,
  21689. RGB8_SNORM : 0x8F96,
  21690. RGBA8_SNORM : 0x8F97,
  21691. SIGNED_NORMALIZED : 0x8F9C,
  21692. COPY_READ_BUFFER : 0x8F36,
  21693. COPY_WRITE_BUFFER : 0x8F37,
  21694. COPY_READ_BUFFER_BINDING : 0x8F36, // Same as COPY_READ_BUFFER
  21695. COPY_WRITE_BUFFER_BINDING : 0x8F37, // Same as COPY_WRITE_BUFFER
  21696. UNIFORM_BUFFER : 0x8A11,
  21697. UNIFORM_BUFFER_BINDING : 0x8A28,
  21698. UNIFORM_BUFFER_START : 0x8A29,
  21699. UNIFORM_BUFFER_SIZE : 0x8A2A,
  21700. MAX_VERTEX_UNIFORM_BLOCKS : 0x8A2B,
  21701. MAX_FRAGMENT_UNIFORM_BLOCKS : 0x8A2D,
  21702. MAX_COMBINED_UNIFORM_BLOCKS : 0x8A2E,
  21703. MAX_UNIFORM_BUFFER_BINDINGS : 0x8A2F,
  21704. MAX_UNIFORM_BLOCK_SIZE : 0x8A30,
  21705. MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS : 0x8A31,
  21706. MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS : 0x8A33,
  21707. UNIFORM_BUFFER_OFFSET_ALIGNMENT : 0x8A34,
  21708. ACTIVE_UNIFORM_BLOCKS : 0x8A36,
  21709. UNIFORM_TYPE : 0x8A37,
  21710. UNIFORM_SIZE : 0x8A38,
  21711. UNIFORM_BLOCK_INDEX : 0x8A3A,
  21712. UNIFORM_OFFSET : 0x8A3B,
  21713. UNIFORM_ARRAY_STRIDE : 0x8A3C,
  21714. UNIFORM_MATRIX_STRIDE : 0x8A3D,
  21715. UNIFORM_IS_ROW_MAJOR : 0x8A3E,
  21716. UNIFORM_BLOCK_BINDING : 0x8A3F,
  21717. UNIFORM_BLOCK_DATA_SIZE : 0x8A40,
  21718. UNIFORM_BLOCK_ACTIVE_UNIFORMS : 0x8A42,
  21719. UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES : 0x8A43,
  21720. UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER : 0x8A44,
  21721. UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER : 0x8A46,
  21722. INVALID_INDEX : 0xFFFFFFFF,
  21723. MAX_VERTEX_OUTPUT_COMPONENTS : 0x9122,
  21724. MAX_FRAGMENT_INPUT_COMPONENTS : 0x9125,
  21725. MAX_SERVER_WAIT_TIMEOUT : 0x9111,
  21726. OBJECT_TYPE : 0x9112,
  21727. SYNC_CONDITION : 0x9113,
  21728. SYNC_STATUS : 0x9114,
  21729. SYNC_FLAGS : 0x9115,
  21730. SYNC_FENCE : 0x9116,
  21731. SYNC_GPU_COMMANDS_COMPLETE : 0x9117,
  21732. UNSIGNALED : 0x9118,
  21733. SIGNALED : 0x9119,
  21734. ALREADY_SIGNALED : 0x911A,
  21735. TIMEOUT_EXPIRED : 0x911B,
  21736. CONDITION_SATISFIED : 0x911C,
  21737. WAIT_FAILED : 0x911D,
  21738. SYNC_FLUSH_COMMANDS_BIT : 0x00000001,
  21739. VERTEX_ATTRIB_ARRAY_DIVISOR : 0x88FE,
  21740. ANY_SAMPLES_PASSED : 0x8C2F,
  21741. ANY_SAMPLES_PASSED_CONSERVATIVE : 0x8D6A,
  21742. SAMPLER_BINDING : 0x8919,
  21743. RGB10_A2UI : 0x906F,
  21744. INT_2_10_10_10_REV : 0x8D9F,
  21745. TRANSFORM_FEEDBACK : 0x8E22,
  21746. TRANSFORM_FEEDBACK_PAUSED : 0x8E23,
  21747. TRANSFORM_FEEDBACK_ACTIVE : 0x8E24,
  21748. TRANSFORM_FEEDBACK_BINDING : 0x8E25,
  21749. COMPRESSED_R11_EAC : 0x9270,
  21750. COMPRESSED_SIGNED_R11_EAC : 0x9271,
  21751. COMPRESSED_RG11_EAC : 0x9272,
  21752. COMPRESSED_SIGNED_RG11_EAC : 0x9273,
  21753. COMPRESSED_RGB8_ETC2 : 0x9274,
  21754. COMPRESSED_SRGB8_ETC2 : 0x9275,
  21755. COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 : 0x9276,
  21756. COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 : 0x9277,
  21757. COMPRESSED_RGBA8_ETC2_EAC : 0x9278,
  21758. COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : 0x9279,
  21759. TEXTURE_IMMUTABLE_FORMAT : 0x912F,
  21760. MAX_ELEMENT_INDEX : 0x8D6B,
  21761. TEXTURE_IMMUTABLE_LEVELS : 0x82DF
  21762. };
  21763. return freezeObject(WebGLConstants);
  21764. });
  21765. /*global define*/
  21766. define('Core/ComponentDatatype',[
  21767. './defaultValue',
  21768. './defined',
  21769. './DeveloperError',
  21770. './FeatureDetection',
  21771. './freezeObject',
  21772. './WebGLConstants'
  21773. ], function(
  21774. defaultValue,
  21775. defined,
  21776. DeveloperError,
  21777. FeatureDetection,
  21778. freezeObject,
  21779. WebGLConstants) {
  21780. 'use strict';
  21781. // Bail out if the browser doesn't support typed arrays, to prevent the setup function
  21782. // from failing, since we won't be able to create a WebGL context anyway.
  21783. if (!FeatureDetection.supportsTypedArrays()) {
  21784. return {};
  21785. }
  21786. /**
  21787. * WebGL component datatypes. Components are intrinsics,
  21788. * which form attributes, which form vertices.
  21789. *
  21790. * @exports ComponentDatatype
  21791. */
  21792. var ComponentDatatype = {
  21793. /**
  21794. * 8-bit signed byte corresponding to <code>gl.BYTE</code> and the type
  21795. * of an element in <code>Int8Array</code>.
  21796. *
  21797. * @type {Number}
  21798. * @constant
  21799. */
  21800. BYTE : WebGLConstants.BYTE,
  21801. /**
  21802. * 8-bit unsigned byte corresponding to <code>UNSIGNED_BYTE</code> and the type
  21803. * of an element in <code>Uint8Array</code>.
  21804. *
  21805. * @type {Number}
  21806. * @constant
  21807. */
  21808. UNSIGNED_BYTE : WebGLConstants.UNSIGNED_BYTE,
  21809. /**
  21810. * 16-bit signed short corresponding to <code>SHORT</code> and the type
  21811. * of an element in <code>Int16Array</code>.
  21812. *
  21813. * @type {Number}
  21814. * @constant
  21815. */
  21816. SHORT : WebGLConstants.SHORT,
  21817. /**
  21818. * 16-bit unsigned short corresponding to <code>UNSIGNED_SHORT</code> and the type
  21819. * of an element in <code>Uint16Array</code>.
  21820. *
  21821. * @type {Number}
  21822. * @constant
  21823. */
  21824. UNSIGNED_SHORT : WebGLConstants.UNSIGNED_SHORT,
  21825. /**
  21826. * 32-bit signed int corresponding to <code>INT</code> and the type
  21827. * of an element in <code>Int32Array</code>.
  21828. *
  21829. * @memberOf ComponentDatatype
  21830. *
  21831. * @type {Number}
  21832. * @constant
  21833. */
  21834. INT : WebGLConstants.INT,
  21835. /**
  21836. * 32-bit unsigned int corresponding to <code>UNSIGNED_INT</code> and the type
  21837. * of an element in <code>Uint32Array</code>.
  21838. *
  21839. * @memberOf ComponentDatatype
  21840. *
  21841. * @type {Number}
  21842. * @constant
  21843. */
  21844. UNSIGNED_INT : WebGLConstants.UNSIGNED_INT,
  21845. /**
  21846. * 32-bit floating-point corresponding to <code>FLOAT</code> and the type
  21847. * of an element in <code>Float32Array</code>.
  21848. *
  21849. * @type {Number}
  21850. * @constant
  21851. */
  21852. FLOAT : WebGLConstants.FLOAT,
  21853. /**
  21854. * 64-bit floating-point corresponding to <code>gl.DOUBLE</code> (in Desktop OpenGL;
  21855. * this is not supported in WebGL, and is emulated in Cesium via {@link GeometryPipeline.encodeAttribute})
  21856. * and the type of an element in <code>Float64Array</code>.
  21857. *
  21858. * @memberOf ComponentDatatype
  21859. *
  21860. * @type {Number}
  21861. * @constant
  21862. * @default 0x140A
  21863. */
  21864. DOUBLE : WebGLConstants.DOUBLE
  21865. };
  21866. /**
  21867. * Returns the size, in bytes, of the corresponding datatype.
  21868. *
  21869. * @param {ComponentDatatype} componentDatatype The component datatype to get the size of.
  21870. * @returns {Number} The size in bytes.
  21871. *
  21872. * @exception {DeveloperError} componentDatatype is not a valid value.
  21873. *
  21874. * @example
  21875. * // Returns Int8Array.BYTES_PER_ELEMENT
  21876. * var size = Cesium.ComponentDatatype.getSizeInBytes(Cesium.ComponentDatatype.BYTE);
  21877. */
  21878. ComponentDatatype.getSizeInBytes = function(componentDatatype){
  21879. if (!defined(componentDatatype)) {
  21880. throw new DeveloperError('value is required.');
  21881. }
  21882. switch (componentDatatype) {
  21883. case ComponentDatatype.BYTE:
  21884. return Int8Array.BYTES_PER_ELEMENT;
  21885. case ComponentDatatype.UNSIGNED_BYTE:
  21886. return Uint8Array.BYTES_PER_ELEMENT;
  21887. case ComponentDatatype.SHORT:
  21888. return Int16Array.BYTES_PER_ELEMENT;
  21889. case ComponentDatatype.UNSIGNED_SHORT:
  21890. return Uint16Array.BYTES_PER_ELEMENT;
  21891. case ComponentDatatype.INT:
  21892. return Int32Array.BYTES_PER_ELEMENT;
  21893. case ComponentDatatype.UNSIGNED_INT:
  21894. return Uint32Array.BYTES_PER_ELEMENT;
  21895. case ComponentDatatype.FLOAT:
  21896. return Float32Array.BYTES_PER_ELEMENT;
  21897. case ComponentDatatype.DOUBLE:
  21898. return Float64Array.BYTES_PER_ELEMENT;
  21899. default:
  21900. throw new DeveloperError('componentDatatype is not a valid value.');
  21901. }
  21902. };
  21903. /**
  21904. * Gets the {@link ComponentDatatype} for the provided TypedArray instance.
  21905. *
  21906. * @param {TypedArray} array The typed array.
  21907. * @returns {ComponentDatatype} The ComponentDatatype for the provided array, or undefined if the array is not a TypedArray.
  21908. */
  21909. ComponentDatatype.fromTypedArray = function(array) {
  21910. if (array instanceof Int8Array) {
  21911. return ComponentDatatype.BYTE;
  21912. }
  21913. if (array instanceof Uint8Array) {
  21914. return ComponentDatatype.UNSIGNED_BYTE;
  21915. }
  21916. if (array instanceof Int16Array) {
  21917. return ComponentDatatype.SHORT;
  21918. }
  21919. if (array instanceof Uint16Array) {
  21920. return ComponentDatatype.UNSIGNED_SHORT;
  21921. }
  21922. if (array instanceof Int32Array) {
  21923. return ComponentDatatype.INT;
  21924. }
  21925. if (array instanceof Uint32Array) {
  21926. return ComponentDatatype.UNSIGNED_INT;
  21927. }
  21928. if (array instanceof Float32Array) {
  21929. return ComponentDatatype.FLOAT;
  21930. }
  21931. if (array instanceof Float64Array) {
  21932. return ComponentDatatype.DOUBLE;
  21933. }
  21934. };
  21935. /**
  21936. * Validates that the provided component datatype is a valid {@link ComponentDatatype}
  21937. *
  21938. * @param {ComponentDatatype} componentDatatype The component datatype to validate.
  21939. * @returns {Boolean} <code>true</code> if the provided component datatype is a valid value; otherwise, <code>false</code>.
  21940. *
  21941. * @example
  21942. * if (!Cesium.ComponentDatatype.validate(componentDatatype)) {
  21943. * throw new Cesium.DeveloperError('componentDatatype must be a valid value.');
  21944. * }
  21945. */
  21946. ComponentDatatype.validate = function(componentDatatype) {
  21947. return defined(componentDatatype) &&
  21948. (componentDatatype === ComponentDatatype.BYTE ||
  21949. componentDatatype === ComponentDatatype.UNSIGNED_BYTE ||
  21950. componentDatatype === ComponentDatatype.SHORT ||
  21951. componentDatatype === ComponentDatatype.UNSIGNED_SHORT ||
  21952. componentDatatype === ComponentDatatype.INT ||
  21953. componentDatatype === ComponentDatatype.UNSIGNED_INT ||
  21954. componentDatatype === ComponentDatatype.FLOAT ||
  21955. componentDatatype === ComponentDatatype.DOUBLE);
  21956. };
  21957. /**
  21958. * Creates a typed array corresponding to component data type.
  21959. *
  21960. * @param {ComponentDatatype} componentDatatype The component data type.
  21961. * @param {Number|Array} valuesOrLength The length of the array to create or an array.
  21962. * @returns {Int8Array|Uint8Array|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} A typed array.
  21963. *
  21964. * @exception {DeveloperError} componentDatatype is not a valid value.
  21965. *
  21966. * @example
  21967. * // creates a Float32Array with length of 100
  21968. * var typedArray = Cesium.ComponentDatatype.createTypedArray(Cesium.ComponentDatatype.FLOAT, 100);
  21969. */
  21970. ComponentDatatype.createTypedArray = function(componentDatatype, valuesOrLength) {
  21971. if (!defined(componentDatatype)) {
  21972. throw new DeveloperError('componentDatatype is required.');
  21973. }
  21974. if (!defined(valuesOrLength)) {
  21975. throw new DeveloperError('valuesOrLength is required.');
  21976. }
  21977. switch (componentDatatype) {
  21978. case ComponentDatatype.BYTE:
  21979. return new Int8Array(valuesOrLength);
  21980. case ComponentDatatype.UNSIGNED_BYTE:
  21981. return new Uint8Array(valuesOrLength);
  21982. case ComponentDatatype.SHORT:
  21983. return new Int16Array(valuesOrLength);
  21984. case ComponentDatatype.UNSIGNED_SHORT:
  21985. return new Uint16Array(valuesOrLength);
  21986. case ComponentDatatype.INT:
  21987. return new Int32Array(valuesOrLength);
  21988. case ComponentDatatype.UNSIGNED_INT:
  21989. return new Uint32Array(valuesOrLength);
  21990. case ComponentDatatype.FLOAT:
  21991. return new Float32Array(valuesOrLength);
  21992. case ComponentDatatype.DOUBLE:
  21993. return new Float64Array(valuesOrLength);
  21994. default:
  21995. throw new DeveloperError('componentDatatype is not a valid value.');
  21996. }
  21997. };
  21998. /**
  21999. * Creates a typed view of an array of bytes.
  22000. *
  22001. * @param {ComponentDatatype} componentDatatype The type of the view to create.
  22002. * @param {ArrayBuffer} buffer The buffer storage to use for the view.
  22003. * @param {Number} [byteOffset] The offset, in bytes, to the first element in the view.
  22004. * @param {Number} [length] The number of elements in the view.
  22005. * @returns {Int8Array|Uint8Array|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} A typed array view of the buffer.
  22006. *
  22007. * @exception {DeveloperError} componentDatatype is not a valid value.
  22008. */
  22009. ComponentDatatype.createArrayBufferView = function(componentDatatype, buffer, byteOffset, length) {
  22010. if (!defined(componentDatatype)) {
  22011. throw new DeveloperError('componentDatatype is required.');
  22012. }
  22013. if (!defined(buffer)) {
  22014. throw new DeveloperError('buffer is required.');
  22015. }
  22016. byteOffset = defaultValue(byteOffset, 0);
  22017. length = defaultValue(length, (buffer.byteLength - byteOffset) / ComponentDatatype.getSizeInBytes(componentDatatype));
  22018. switch (componentDatatype) {
  22019. case ComponentDatatype.BYTE:
  22020. return new Int8Array(buffer, byteOffset, length);
  22021. case ComponentDatatype.UNSIGNED_BYTE:
  22022. return new Uint8Array(buffer, byteOffset, length);
  22023. case ComponentDatatype.SHORT:
  22024. return new Int16Array(buffer, byteOffset, length);
  22025. case ComponentDatatype.UNSIGNED_SHORT:
  22026. return new Uint16Array(buffer, byteOffset, length);
  22027. case ComponentDatatype.INT:
  22028. return new Int32Array(buffer, byteOffset, length);
  22029. case ComponentDatatype.UNSIGNED_INT:
  22030. return new Uint32Array(buffer, byteOffset, length);
  22031. case ComponentDatatype.FLOAT:
  22032. return new Float32Array(buffer, byteOffset, length);
  22033. case ComponentDatatype.DOUBLE:
  22034. return new Float64Array(buffer, byteOffset, length);
  22035. default:
  22036. throw new DeveloperError('componentDatatype is not a valid value.');
  22037. }
  22038. };
  22039. /**
  22040. * Get the ComponentDatatype from its name.
  22041. *
  22042. * @param {String} name The name of the ComponentDatatype.
  22043. * @returns {ComponentDatatype} The ComponentDatatype.
  22044. *
  22045. * @exception {DeveloperError} name is not a valid value.
  22046. */
  22047. ComponentDatatype.fromName = function(name) {
  22048. switch (name) {
  22049. case 'BYTE':
  22050. return ComponentDatatype.BYTE;
  22051. case 'UNSIGNED_BYTE':
  22052. return ComponentDatatype.UNSIGNED_BYTE;
  22053. case 'SHORT':
  22054. return ComponentDatatype.SHORT;
  22055. case 'UNSIGNED_SHORT':
  22056. return ComponentDatatype.UNSIGNED_SHORT;
  22057. case 'INT':
  22058. return ComponentDatatype.INT;
  22059. case 'UNSIGNED_INT':
  22060. return ComponentDatatype.UNSIGNED_INT;
  22061. case 'FLOAT':
  22062. return ComponentDatatype.FLOAT;
  22063. case 'DOUBLE':
  22064. return ComponentDatatype.DOUBLE;
  22065. default:
  22066. throw new DeveloperError('name is not a valid value.');
  22067. }
  22068. };
  22069. return freezeObject(ComponentDatatype);
  22070. });
  22071. /*global define*/
  22072. define('Core/TerrainQuantization',[
  22073. './freezeObject'
  22074. ], function(
  22075. freezeObject) {
  22076. 'use strict';
  22077. /**
  22078. * This enumerated type is used to determine how the vertices of the terrain mesh are compressed.
  22079. *
  22080. * @exports TerrainQuantization
  22081. *
  22082. * @private
  22083. */
  22084. var TerrainQuantization = {
  22085. /**
  22086. * The vertices are not compressed.
  22087. *
  22088. * @type {Number}
  22089. * @constant
  22090. */
  22091. NONE : 0,
  22092. /**
  22093. * The vertices are compressed to 12 bits.
  22094. *
  22095. * @type {Number}
  22096. * @constant
  22097. */
  22098. BITS12 : 1
  22099. };
  22100. return freezeObject(TerrainQuantization);
  22101. });
  22102. /*global define*/
  22103. define('Core/TerrainEncoding',[
  22104. './AttributeCompression',
  22105. './Cartesian2',
  22106. './Cartesian3',
  22107. './ComponentDatatype',
  22108. './defaultValue',
  22109. './defined',
  22110. './Math',
  22111. './Matrix4',
  22112. './TerrainQuantization'
  22113. ], function(
  22114. AttributeCompression,
  22115. Cartesian2,
  22116. Cartesian3,
  22117. ComponentDatatype,
  22118. defaultValue,
  22119. defined,
  22120. CesiumMath,
  22121. Matrix4,
  22122. TerrainQuantization) {
  22123. 'use strict';
  22124. var cartesian3Scratch = new Cartesian3();
  22125. var cartesian3DimScratch = new Cartesian3();
  22126. var cartesian2Scratch = new Cartesian2();
  22127. var matrix4Scratch = new Matrix4();
  22128. var matrix4Scratch2 = new Matrix4();
  22129. var SHIFT_LEFT_12 = Math.pow(2.0, 12.0);
  22130. /**
  22131. * Data used to quantize and pack the terrain mesh. The position can be unpacked for picking and all attributes
  22132. * are unpacked in the vertex shader.
  22133. *
  22134. * @alias TerrainEncoding
  22135. * @constructor
  22136. *
  22137. * @param {AxisAlignedBoundingBox} axisAlignedBoundingBox The bounds of the tile in the east-north-up coordinates at the tiles center.
  22138. * @param {Number} minimumHeight The minimum height.
  22139. * @param {Number} maximumHeight The maximum height.
  22140. * @param {Matrix4} fromENU The east-north-up to fixed frame matrix at the center of the terrain mesh.
  22141. * @param {Boolean} hasVertexNormals If the mesh has vertex normals.
  22142. * @param {Boolean} [hasWebMercatorT=false] true if the terrain data includes a Web Mercator texture coordinate; otherwise, false.
  22143. *
  22144. * @private
  22145. */
  22146. function TerrainEncoding(axisAlignedBoundingBox, minimumHeight, maximumHeight, fromENU, hasVertexNormals, hasWebMercatorT) {
  22147. var quantization;
  22148. var center;
  22149. var toENU;
  22150. var matrix;
  22151. if (defined(axisAlignedBoundingBox) && defined(minimumHeight) && defined(maximumHeight) && defined(fromENU)) {
  22152. var minimum = axisAlignedBoundingBox.minimum;
  22153. var maximum = axisAlignedBoundingBox.maximum;
  22154. var dimensions = Cartesian3.subtract(maximum, minimum, cartesian3DimScratch);
  22155. var hDim = maximumHeight - minimumHeight;
  22156. var maxDim = Math.max(Cartesian3.maximumComponent(dimensions), hDim);
  22157. if (maxDim < SHIFT_LEFT_12 - 1.0) {
  22158. quantization = TerrainQuantization.BITS12;
  22159. } else {
  22160. quantization = TerrainQuantization.NONE;
  22161. }
  22162. center = axisAlignedBoundingBox.center;
  22163. toENU = Matrix4.inverseTransformation(fromENU, new Matrix4());
  22164. var translation = Cartesian3.negate(minimum, cartesian3Scratch);
  22165. Matrix4.multiply(Matrix4.fromTranslation(translation, matrix4Scratch), toENU, toENU);
  22166. var scale = cartesian3Scratch;
  22167. scale.x = 1.0 / dimensions.x;
  22168. scale.y = 1.0 / dimensions.y;
  22169. scale.z = 1.0 / dimensions.z;
  22170. Matrix4.multiply(Matrix4.fromScale(scale, matrix4Scratch), toENU, toENU);
  22171. matrix = Matrix4.clone(fromENU);
  22172. Matrix4.setTranslation(matrix, Cartesian3.ZERO, matrix);
  22173. fromENU = Matrix4.clone(fromENU, new Matrix4());
  22174. var translationMatrix = Matrix4.fromTranslation(minimum, matrix4Scratch);
  22175. var scaleMatrix = Matrix4.fromScale(dimensions, matrix4Scratch2);
  22176. var st = Matrix4.multiply(translationMatrix, scaleMatrix,matrix4Scratch);
  22177. Matrix4.multiply(fromENU, st, fromENU);
  22178. Matrix4.multiply(matrix, st, matrix);
  22179. }
  22180. /**
  22181. * How the vertices of the mesh were compressed.
  22182. * @type {TerrainQuantization}
  22183. */
  22184. this.quantization = quantization;
  22185. /**
  22186. * The minimum height of the tile including the skirts.
  22187. * @type {Number}
  22188. */
  22189. this.minimumHeight = minimumHeight;
  22190. /**
  22191. * The maximum height of the tile.
  22192. * @type {Number}
  22193. */
  22194. this.maximumHeight = maximumHeight;
  22195. /**
  22196. * The center of the tile.
  22197. * @type {Cartesian3}
  22198. */
  22199. this.center = center;
  22200. /**
  22201. * A matrix that takes a vertex from the tile, transforms it to east-north-up at the center and scales
  22202. * it so each component is in the [0, 1] range.
  22203. * @type {Matrix4}
  22204. */
  22205. this.toScaledENU = toENU;
  22206. /**
  22207. * A matrix that restores a vertex transformed with toScaledENU back to the earth fixed reference frame
  22208. * @type {Matrix4}
  22209. */
  22210. this.fromScaledENU = fromENU;
  22211. /**
  22212. * The matrix used to decompress the terrain vertices in the shader for RTE rendering.
  22213. * @type {Matrix4}
  22214. */
  22215. this.matrix = matrix;
  22216. /**
  22217. * The terrain mesh contains normals.
  22218. * @type {Boolean}
  22219. */
  22220. this.hasVertexNormals = hasVertexNormals;
  22221. /**
  22222. * The terrain mesh contains a vertical texture coordinate following the Web Mercator projection.
  22223. * @type {Boolean}
  22224. */
  22225. this.hasWebMercatorT = defaultValue(hasWebMercatorT, false);
  22226. }
  22227. TerrainEncoding.prototype.encode = function(vertexBuffer, bufferIndex, position, uv, height, normalToPack, webMercatorT) {
  22228. var u = uv.x;
  22229. var v = uv.y;
  22230. if (this.quantization === TerrainQuantization.BITS12) {
  22231. position = Matrix4.multiplyByPoint(this.toScaledENU, position, cartesian3Scratch);
  22232. position.x = CesiumMath.clamp(position.x, 0.0, 1.0);
  22233. position.y = CesiumMath.clamp(position.y, 0.0, 1.0);
  22234. position.z = CesiumMath.clamp(position.z, 0.0, 1.0);
  22235. var hDim = this.maximumHeight - this.minimumHeight;
  22236. var h = CesiumMath.clamp((height - this.minimumHeight) / hDim, 0.0, 1.0);
  22237. Cartesian2.fromElements(position.x, position.y, cartesian2Scratch);
  22238. var compressed0 = AttributeCompression.compressTextureCoordinates(cartesian2Scratch);
  22239. Cartesian2.fromElements(position.z, h, cartesian2Scratch);
  22240. var compressed1 = AttributeCompression.compressTextureCoordinates(cartesian2Scratch);
  22241. Cartesian2.fromElements(u, v, cartesian2Scratch);
  22242. var compressed2 = AttributeCompression.compressTextureCoordinates(cartesian2Scratch);
  22243. vertexBuffer[bufferIndex++] = compressed0;
  22244. vertexBuffer[bufferIndex++] = compressed1;
  22245. vertexBuffer[bufferIndex++] = compressed2;
  22246. if (this.hasWebMercatorT) {
  22247. Cartesian2.fromElements(webMercatorT, 0.0, cartesian2Scratch);
  22248. var compressed3 = AttributeCompression.compressTextureCoordinates(cartesian2Scratch);
  22249. vertexBuffer[bufferIndex++] = compressed3;
  22250. }
  22251. } else {
  22252. Cartesian3.subtract(position, this.center, cartesian3Scratch);
  22253. vertexBuffer[bufferIndex++] = cartesian3Scratch.x;
  22254. vertexBuffer[bufferIndex++] = cartesian3Scratch.y;
  22255. vertexBuffer[bufferIndex++] = cartesian3Scratch.z;
  22256. vertexBuffer[bufferIndex++] = height;
  22257. vertexBuffer[bufferIndex++] = u;
  22258. vertexBuffer[bufferIndex++] = v;
  22259. if (this.hasWebMercatorT) {
  22260. vertexBuffer[bufferIndex++] = webMercatorT;
  22261. }
  22262. }
  22263. if (this.hasVertexNormals) {
  22264. vertexBuffer[bufferIndex++] = AttributeCompression.octPackFloat(normalToPack);
  22265. }
  22266. return bufferIndex;
  22267. };
  22268. TerrainEncoding.prototype.decodePosition = function(buffer, index, result) {
  22269. if (!defined(result)) {
  22270. result = new Cartesian3();
  22271. }
  22272. index *= this.getStride();
  22273. if (this.quantization === TerrainQuantization.BITS12) {
  22274. var xy = AttributeCompression.decompressTextureCoordinates(buffer[index], cartesian2Scratch);
  22275. result.x = xy.x;
  22276. result.y = xy.y;
  22277. var zh = AttributeCompression.decompressTextureCoordinates(buffer[index + 1], cartesian2Scratch);
  22278. result.z = zh.x;
  22279. return Matrix4.multiplyByPoint(this.fromScaledENU, result, result);
  22280. }
  22281. result.x = buffer[index];
  22282. result.y = buffer[index + 1];
  22283. result.z = buffer[index + 2];
  22284. return Cartesian3.add(result, this.center, result);
  22285. };
  22286. TerrainEncoding.prototype.decodeTextureCoordinates = function(buffer, index, result) {
  22287. if (!defined(result)) {
  22288. result = new Cartesian2();
  22289. }
  22290. index *= this.getStride();
  22291. if (this.quantization === TerrainQuantization.BITS12) {
  22292. return AttributeCompression.decompressTextureCoordinates(buffer[index + 2], result);
  22293. }
  22294. return Cartesian2.fromElements(buffer[index + 4], buffer[index + 5], result);
  22295. };
  22296. TerrainEncoding.prototype.decodeHeight = function(buffer, index) {
  22297. index *= this.getStride();
  22298. if (this.quantization === TerrainQuantization.BITS12) {
  22299. var zh = AttributeCompression.decompressTextureCoordinates(buffer[index + 1], cartesian2Scratch);
  22300. return zh.y * (this.maximumHeight - this.minimumHeight) + this.minimumHeight;
  22301. }
  22302. return buffer[index + 3];
  22303. };
  22304. TerrainEncoding.prototype.getOctEncodedNormal = function(buffer, index, result) {
  22305. var stride = this.getStride();
  22306. index = (index + 1) * stride - 1;
  22307. var temp = buffer[index] / 256.0;
  22308. var x = Math.floor(temp);
  22309. var y = (temp - x) * 256.0;
  22310. return Cartesian2.fromElements(x, y, result);
  22311. };
  22312. TerrainEncoding.prototype.getStride = function() {
  22313. var vertexStride;
  22314. switch (this.quantization) {
  22315. case TerrainQuantization.BITS12:
  22316. vertexStride = 3;
  22317. break;
  22318. default:
  22319. vertexStride = 6;
  22320. }
  22321. if (this.hasWebMercatorT) {
  22322. ++vertexStride;
  22323. }
  22324. if (this.hasVertexNormals) {
  22325. ++vertexStride;
  22326. }
  22327. return vertexStride;
  22328. };
  22329. var attributesNone = {
  22330. position3DAndHeight : 0,
  22331. textureCoordAndEncodedNormals : 1
  22332. };
  22333. var attributes = {
  22334. compressed0 : 0,
  22335. compressed1 : 1
  22336. };
  22337. TerrainEncoding.prototype.getAttributes = function(buffer) {
  22338. var datatype = ComponentDatatype.FLOAT;
  22339. var sizeInBytes = ComponentDatatype.getSizeInBytes(datatype);
  22340. var stride;
  22341. if (this.quantization === TerrainQuantization.NONE) {
  22342. var position3DAndHeightLength = 4;
  22343. var numTexCoordComponents = 2;
  22344. if (this.hasWebMercatorT) {
  22345. ++numTexCoordComponents;
  22346. }
  22347. if (this.hasVertexNormals) {
  22348. ++numTexCoordComponents;
  22349. }
  22350. stride = (position3DAndHeightLength + numTexCoordComponents) * sizeInBytes;
  22351. return [{
  22352. index : attributesNone.position3DAndHeight,
  22353. vertexBuffer : buffer,
  22354. componentDatatype : datatype,
  22355. componentsPerAttribute : position3DAndHeightLength,
  22356. offsetInBytes : 0,
  22357. strideInBytes : stride
  22358. }, {
  22359. index : attributesNone.textureCoordAndEncodedNormals,
  22360. vertexBuffer : buffer,
  22361. componentDatatype : datatype,
  22362. componentsPerAttribute : numTexCoordComponents,
  22363. offsetInBytes : position3DAndHeightLength * sizeInBytes,
  22364. strideInBytes : stride
  22365. }];
  22366. }
  22367. var numCompressed0 = 3;
  22368. var numCompressed1 = 0;
  22369. if (this.hasWebMercatorT || this.hasVertexNormals) {
  22370. ++numCompressed0;
  22371. }
  22372. if (this.hasWebMercatorT && this.hasVertexNormals) {
  22373. ++numCompressed1;
  22374. stride = (numCompressed0 + numCompressed1) * sizeInBytes;
  22375. return [{
  22376. index : attributes.compressed0,
  22377. vertexBuffer : buffer,
  22378. componentDatatype : datatype,
  22379. componentsPerAttribute : numCompressed0,
  22380. offsetInBytes : 0,
  22381. strideInBytes : stride
  22382. }, {
  22383. index : attributes.compressed1,
  22384. vertexBuffer : buffer,
  22385. componentDatatype : datatype,
  22386. componentsPerAttribute : numCompressed1,
  22387. offsetInBytes : numCompressed0 * sizeInBytes,
  22388. strideInBytes : stride
  22389. }];
  22390. } else {
  22391. return [{
  22392. index : attributes.compressed0,
  22393. vertexBuffer : buffer,
  22394. componentDatatype : datatype,
  22395. componentsPerAttribute : numCompressed0
  22396. }];
  22397. }
  22398. };
  22399. TerrainEncoding.prototype.getAttributeLocations = function() {
  22400. if (this.quantization === TerrainQuantization.NONE) {
  22401. return attributesNone;
  22402. } else {
  22403. return attributes;
  22404. }
  22405. };
  22406. TerrainEncoding.clone = function(encoding, result) {
  22407. if (!defined(result)) {
  22408. result = new TerrainEncoding();
  22409. }
  22410. result.quantization = encoding.quantization;
  22411. result.minimumHeight = encoding.minimumHeight;
  22412. result.maximumHeight = encoding.maximumHeight;
  22413. result.center = Cartesian3.clone(encoding.center);
  22414. result.toScaledENU = Matrix4.clone(encoding.toScaledENU);
  22415. result.fromScaledENU = Matrix4.clone(encoding.fromScaledENU);
  22416. result.matrix = Matrix4.clone(encoding.matrix);
  22417. result.hasVertexNormals = encoding.hasVertexNormals;
  22418. result.hasWebMercatorT = encoding.hasWebMercatorT;
  22419. return result;
  22420. };
  22421. return TerrainEncoding;
  22422. });
  22423. /*global define*/
  22424. define('Core/WebMercatorProjection',[
  22425. './Cartesian3',
  22426. './Cartographic',
  22427. './defaultValue',
  22428. './defined',
  22429. './defineProperties',
  22430. './DeveloperError',
  22431. './Ellipsoid',
  22432. './Math'
  22433. ], function(
  22434. Cartesian3,
  22435. Cartographic,
  22436. defaultValue,
  22437. defined,
  22438. defineProperties,
  22439. DeveloperError,
  22440. Ellipsoid,
  22441. CesiumMath) {
  22442. 'use strict';
  22443. /**
  22444. * The map projection used by Google Maps, Bing Maps, and most of ArcGIS Online, EPSG:3857. This
  22445. * projection use longitude and latitude expressed with the WGS84 and transforms them to Mercator using
  22446. * the spherical (rather than ellipsoidal) equations.
  22447. *
  22448. * @alias WebMercatorProjection
  22449. * @constructor
  22450. *
  22451. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid.
  22452. *
  22453. * @see GeographicProjection
  22454. */
  22455. function WebMercatorProjection(ellipsoid) {
  22456. this._ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  22457. this._semimajorAxis = this._ellipsoid.maximumRadius;
  22458. this._oneOverSemimajorAxis = 1.0 / this._semimajorAxis;
  22459. }
  22460. defineProperties(WebMercatorProjection.prototype, {
  22461. /**
  22462. * Gets the {@link Ellipsoid}.
  22463. *
  22464. * @memberof WebMercatorProjection.prototype
  22465. *
  22466. * @type {Ellipsoid}
  22467. * @readonly
  22468. */
  22469. ellipsoid : {
  22470. get : function() {
  22471. return this._ellipsoid;
  22472. }
  22473. }
  22474. });
  22475. /**
  22476. * Converts a Mercator angle, in the range -PI to PI, to a geodetic latitude
  22477. * in the range -PI/2 to PI/2.
  22478. *
  22479. * @param {Number} mercatorAngle The angle to convert.
  22480. * @returns {Number} The geodetic latitude in radians.
  22481. */
  22482. WebMercatorProjection.mercatorAngleToGeodeticLatitude = function(mercatorAngle) {
  22483. return CesiumMath.PI_OVER_TWO - (2.0 * Math.atan(Math.exp(-mercatorAngle)));
  22484. };
  22485. /**
  22486. * Converts a geodetic latitude in radians, in the range -PI/2 to PI/2, to a Mercator
  22487. * angle in the range -PI to PI.
  22488. *
  22489. * @param {Number} latitude The geodetic latitude in radians.
  22490. * @returns {Number} The Mercator angle.
  22491. */
  22492. WebMercatorProjection.geodeticLatitudeToMercatorAngle = function(latitude) {
  22493. // Clamp the latitude coordinate to the valid Mercator bounds.
  22494. if (latitude > WebMercatorProjection.MaximumLatitude) {
  22495. latitude = WebMercatorProjection.MaximumLatitude;
  22496. } else if (latitude < -WebMercatorProjection.MaximumLatitude) {
  22497. latitude = -WebMercatorProjection.MaximumLatitude;
  22498. }
  22499. var sinLatitude = Math.sin(latitude);
  22500. return 0.5 * Math.log((1.0 + sinLatitude) / (1.0 - sinLatitude));
  22501. };
  22502. /**
  22503. * The maximum latitude (both North and South) supported by a Web Mercator
  22504. * (EPSG:3857) projection. Technically, the Mercator projection is defined
  22505. * for any latitude up to (but not including) 90 degrees, but it makes sense
  22506. * to cut it off sooner because it grows exponentially with increasing latitude.
  22507. * The logic behind this particular cutoff value, which is the one used by
  22508. * Google Maps, Bing Maps, and Esri, is that it makes the projection
  22509. * square. That is, the rectangle is equal in the X and Y directions.
  22510. *
  22511. * The constant value is computed by calling:
  22512. * WebMercatorProjection.mercatorAngleToGeodeticLatitude(Math.PI)
  22513. *
  22514. * @type {Number}
  22515. */
  22516. WebMercatorProjection.MaximumLatitude = WebMercatorProjection.mercatorAngleToGeodeticLatitude(Math.PI);
  22517. /**
  22518. * Converts geodetic ellipsoid coordinates, in radians, to the equivalent Web Mercator
  22519. * X, Y, Z coordinates expressed in meters and returned in a {@link Cartesian3}. The height
  22520. * is copied unmodified to the Z coordinate.
  22521. *
  22522. * @param {Cartographic} cartographic The cartographic coordinates in radians.
  22523. * @param {Cartesian3} [result] The instance to which to copy the result, or undefined if a
  22524. * new instance should be created.
  22525. * @returns {Cartesian3} The equivalent web mercator X, Y, Z coordinates, in meters.
  22526. */
  22527. WebMercatorProjection.prototype.project = function(cartographic, result) {
  22528. var semimajorAxis = this._semimajorAxis;
  22529. var x = cartographic.longitude * semimajorAxis;
  22530. var y = WebMercatorProjection.geodeticLatitudeToMercatorAngle(cartographic.latitude) * semimajorAxis;
  22531. var z = cartographic.height;
  22532. if (!defined(result)) {
  22533. return new Cartesian3(x, y, z);
  22534. }
  22535. result.x = x;
  22536. result.y = y;
  22537. result.z = z;
  22538. return result;
  22539. };
  22540. /**
  22541. * Converts Web Mercator X, Y coordinates, expressed in meters, to a {@link Cartographic}
  22542. * containing geodetic ellipsoid coordinates. The Z coordinate is copied unmodified to the
  22543. * height.
  22544. *
  22545. * @param {Cartesian3} cartesian The web mercator Cartesian position to unrproject with height (z) in meters.
  22546. * @param {Cartographic} [result] The instance to which to copy the result, or undefined if a
  22547. * new instance should be created.
  22548. * @returns {Cartographic} The equivalent cartographic coordinates.
  22549. */
  22550. WebMercatorProjection.prototype.unproject = function(cartesian, result) {
  22551. if (!defined(cartesian)) {
  22552. throw new DeveloperError('cartesian is required');
  22553. }
  22554. var oneOverEarthSemimajorAxis = this._oneOverSemimajorAxis;
  22555. var longitude = cartesian.x * oneOverEarthSemimajorAxis;
  22556. var latitude = WebMercatorProjection.mercatorAngleToGeodeticLatitude(cartesian.y * oneOverEarthSemimajorAxis);
  22557. var height = cartesian.z;
  22558. if (!defined(result)) {
  22559. return new Cartographic(longitude, latitude, height);
  22560. }
  22561. result.longitude = longitude;
  22562. result.latitude = latitude;
  22563. result.height = height;
  22564. return result;
  22565. };
  22566. return WebMercatorProjection;
  22567. });
  22568. /*global define*/
  22569. define('Core/HeightmapTessellator',[
  22570. './AxisAlignedBoundingBox',
  22571. './BoundingSphere',
  22572. './Cartesian2',
  22573. './Cartesian3',
  22574. './defaultValue',
  22575. './defined',
  22576. './DeveloperError',
  22577. './Ellipsoid',
  22578. './EllipsoidalOccluder',
  22579. './freezeObject',
  22580. './Math',
  22581. './Matrix4',
  22582. './OrientedBoundingBox',
  22583. './Rectangle',
  22584. './TerrainEncoding',
  22585. './Transforms',
  22586. './WebMercatorProjection'
  22587. ], function(
  22588. AxisAlignedBoundingBox,
  22589. BoundingSphere,
  22590. Cartesian2,
  22591. Cartesian3,
  22592. defaultValue,
  22593. defined,
  22594. DeveloperError,
  22595. Ellipsoid,
  22596. EllipsoidalOccluder,
  22597. freezeObject,
  22598. CesiumMath,
  22599. Matrix4,
  22600. OrientedBoundingBox,
  22601. Rectangle,
  22602. TerrainEncoding,
  22603. Transforms,
  22604. WebMercatorProjection) {
  22605. 'use strict';
  22606. /**
  22607. * Contains functions to create a mesh from a heightmap image.
  22608. *
  22609. * @exports HeightmapTessellator
  22610. *
  22611. * @private
  22612. */
  22613. var HeightmapTessellator = {};
  22614. /**
  22615. * The default structure of a heightmap, as given to {@link HeightmapTessellator.computeVertices}.
  22616. *
  22617. * @constant
  22618. */
  22619. HeightmapTessellator.DEFAULT_STRUCTURE = freezeObject({
  22620. heightScale : 1.0,
  22621. heightOffset : 0.0,
  22622. elementsPerHeight : 1,
  22623. stride : 1,
  22624. elementMultiplier : 256.0,
  22625. isBigEndian : false
  22626. });
  22627. var cartesian3Scratch = new Cartesian3();
  22628. var matrix4Scratch = new Matrix4();
  22629. var minimumScratch = new Cartesian3();
  22630. var maximumScratch = new Cartesian3();
  22631. /**
  22632. * Fills an array of vertices from a heightmap image.
  22633. *
  22634. * @param {Object} options Object with the following properties:
  22635. * @param {TypedArray} options.heightmap The heightmap to tessellate.
  22636. * @param {Number} options.width The width of the heightmap, in height samples.
  22637. * @param {Number} options.height The height of the heightmap, in height samples.
  22638. * @param {Number} options.skirtHeight The height of skirts to drape at the edges of the heightmap.
  22639. * @param {Rectangle} options.nativeRectangle An rectangle in the native coordinates of the heightmap's projection. For
  22640. * a heightmap with a geographic projection, this is degrees. For the web mercator
  22641. * projection, this is meters.
  22642. * @param {Number} [options.exaggeration=1.0] The scale used to exaggerate the terrain.
  22643. * @param {Rectangle} [options.rectangle] The rectangle covered by the heightmap, in geodetic coordinates with north, south, east and
  22644. * west properties in radians. Either rectangle or nativeRectangle must be provided. If both
  22645. * are provided, they're assumed to be consistent.
  22646. * @param {Boolean} [options.isGeographic=true] True if the heightmap uses a {@link GeographicProjection}, or false if it uses
  22647. * a {@link WebMercatorProjection}.
  22648. * @param {Cartesian3} [options.relativeToCenter=Cartesian3.ZERO] The positions will be computed as <code>Cartesian3.subtract(worldPosition, relativeToCenter)</code>.
  22649. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to which the heightmap applies.
  22650. * @param {Object} [options.structure] An object describing the structure of the height data.
  22651. * @param {Number} [options.structure.heightScale=1.0] The factor by which to multiply height samples in order to obtain
  22652. * the height above the heightOffset, in meters. The heightOffset is added to the resulting
  22653. * height after multiplying by the scale.
  22654. * @param {Number} [options.structure.heightOffset=0.0] The offset to add to the scaled height to obtain the final
  22655. * height in meters. The offset is added after the height sample is multiplied by the
  22656. * heightScale.
  22657. * @param {Number} [options.structure.elementsPerHeight=1] The number of elements in the buffer that make up a single height
  22658. * sample. This is usually 1, indicating that each element is a separate height sample. If
  22659. * it is greater than 1, that number of elements together form the height sample, which is
  22660. * computed according to the structure.elementMultiplier and structure.isBigEndian properties.
  22661. * @param {Number} [options.structure.stride=1] The number of elements to skip to get from the first element of
  22662. * one height to the first element of the next height.
  22663. * @param {Number} [options.structure.elementMultiplier=256.0] The multiplier used to compute the height value when the
  22664. * stride property is greater than 1. For example, if the stride is 4 and the strideMultiplier
  22665. * is 256, the height is computed as follows:
  22666. * `height = buffer[index] + buffer[index + 1] * 256 + buffer[index + 2] * 256 * 256 + buffer[index + 3] * 256 * 256 * 256`
  22667. * This is assuming that the isBigEndian property is false. If it is true, the order of the
  22668. * elements is reversed.
  22669. * @param {Number} [options.structure.lowestEncodedHeight] The lowest value that can be stored in the height buffer. Any heights that are lower
  22670. * than this value after encoding with the `heightScale` and `heightOffset` are clamped to this value. For example, if the height
  22671. * buffer is a `Uint16Array`, this value should be 0 because a `Uint16Array` cannot store negative numbers. If this parameter is
  22672. * not specified, no minimum value is enforced.
  22673. * @param {Number} [options.structure.highestEncodedHeight] The highest value that can be stored in the height buffer. Any heights that are higher
  22674. * than this value after encoding with the `heightScale` and `heightOffset` are clamped to this value. For example, if the height
  22675. * buffer is a `Uint16Array`, this value should be `256 * 256 - 1` or 65535 because a `Uint16Array` cannot store numbers larger
  22676. * than 65535. If this parameter is not specified, no maximum value is enforced.
  22677. * @param {Boolean} [options.structure.isBigEndian=false] Indicates endianness of the elements in the buffer when the
  22678. * stride property is greater than 1. If this property is false, the first element is the
  22679. * low-order element. If it is true, the first element is the high-order element.
  22680. *
  22681. * @example
  22682. * var width = 5;
  22683. * var height = 5;
  22684. * var statistics = Cesium.HeightmapTessellator.computeVertices({
  22685. * heightmap : [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0],
  22686. * width : width,
  22687. * height : height,
  22688. * skirtHeight : 0.0,
  22689. * nativeRectangle : {
  22690. * west : 10.0,
  22691. * east : 20.0,
  22692. * south : 30.0,
  22693. * north : 40.0
  22694. * }
  22695. * });
  22696. *
  22697. * var encoding = statistics.encoding;
  22698. * var position = encoding.decodePosition(statistics.vertices, index * encoding.getStride());
  22699. */
  22700. HeightmapTessellator.computeVertices = function(options) {
  22701. if (!defined(options) || !defined(options.heightmap)) {
  22702. throw new DeveloperError('options.heightmap is required.');
  22703. }
  22704. if (!defined(options.width) || !defined(options.height)) {
  22705. throw new DeveloperError('options.width and options.height are required.');
  22706. }
  22707. if (!defined(options.nativeRectangle)) {
  22708. throw new DeveloperError('options.nativeRectangle is required.');
  22709. }
  22710. if (!defined(options.skirtHeight)) {
  22711. throw new DeveloperError('options.skirtHeight is required.');
  22712. }
  22713. // This function tends to be a performance hotspot for terrain rendering,
  22714. // so it employs a lot of inlining and unrolling as an optimization.
  22715. // In particular, the functionality of Ellipsoid.cartographicToCartesian
  22716. // is inlined.
  22717. var cos = Math.cos;
  22718. var sin = Math.sin;
  22719. var sqrt = Math.sqrt;
  22720. var atan = Math.atan;
  22721. var exp = Math.exp;
  22722. var piOverTwo = CesiumMath.PI_OVER_TWO;
  22723. var toRadians = CesiumMath.toRadians;
  22724. var heightmap = options.heightmap;
  22725. var width = options.width;
  22726. var height = options.height;
  22727. var skirtHeight = options.skirtHeight;
  22728. var isGeographic = defaultValue(options.isGeographic, true);
  22729. var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  22730. var oneOverGlobeSemimajorAxis = 1.0 / ellipsoid.maximumRadius;
  22731. var nativeRectangle = options.nativeRectangle;
  22732. var geographicWest;
  22733. var geographicSouth;
  22734. var geographicEast;
  22735. var geographicNorth;
  22736. var rectangle = options.rectangle;
  22737. if (!defined(rectangle)) {
  22738. if (isGeographic) {
  22739. geographicWest = toRadians(nativeRectangle.west);
  22740. geographicSouth = toRadians(nativeRectangle.south);
  22741. geographicEast = toRadians(nativeRectangle.east);
  22742. geographicNorth = toRadians(nativeRectangle.north);
  22743. } else {
  22744. geographicWest = nativeRectangle.west * oneOverGlobeSemimajorAxis;
  22745. geographicSouth = piOverTwo - (2.0 * atan(exp(-nativeRectangle.south * oneOverGlobeSemimajorAxis)));
  22746. geographicEast = nativeRectangle.east * oneOverGlobeSemimajorAxis;
  22747. geographicNorth = piOverTwo - (2.0 * atan(exp(-nativeRectangle.north * oneOverGlobeSemimajorAxis)));
  22748. }
  22749. } else {
  22750. geographicWest = rectangle.west;
  22751. geographicSouth = rectangle.south;
  22752. geographicEast = rectangle.east;
  22753. geographicNorth = rectangle.north;
  22754. }
  22755. var relativeToCenter = options.relativeToCenter;
  22756. var hasRelativeToCenter = defined(relativeToCenter);
  22757. relativeToCenter = hasRelativeToCenter ? relativeToCenter : Cartesian3.ZERO;
  22758. var exaggeration = defaultValue(options.exaggeration, 1.0);
  22759. var includeWebMercatorT = defaultValue(options.includeWebMercatorT, false);
  22760. var structure = defaultValue(options.structure, HeightmapTessellator.DEFAULT_STRUCTURE);
  22761. var heightScale = defaultValue(structure.heightScale, HeightmapTessellator.DEFAULT_STRUCTURE.heightScale);
  22762. var heightOffset = defaultValue(structure.heightOffset, HeightmapTessellator.DEFAULT_STRUCTURE.heightOffset);
  22763. var elementsPerHeight = defaultValue(structure.elementsPerHeight, HeightmapTessellator.DEFAULT_STRUCTURE.elementsPerHeight);
  22764. var stride = defaultValue(structure.stride, HeightmapTessellator.DEFAULT_STRUCTURE.stride);
  22765. var elementMultiplier = defaultValue(structure.elementMultiplier, HeightmapTessellator.DEFAULT_STRUCTURE.elementMultiplier);
  22766. var isBigEndian = defaultValue(structure.isBigEndian, HeightmapTessellator.DEFAULT_STRUCTURE.isBigEndian);
  22767. var granularityX = Rectangle.computeWidth(nativeRectangle) / (width - 1);
  22768. var granularityY = Rectangle.computeHeight(nativeRectangle) / (height - 1);
  22769. var radiiSquared = ellipsoid.radiiSquared;
  22770. var radiiSquaredX = radiiSquared.x;
  22771. var radiiSquaredY = radiiSquared.y;
  22772. var radiiSquaredZ = radiiSquared.z;
  22773. var minimumHeight = 65536.0;
  22774. var maximumHeight = -65536.0;
  22775. var fromENU = Transforms.eastNorthUpToFixedFrame(relativeToCenter, ellipsoid);
  22776. var toENU = Matrix4.inverseTransformation(fromENU, matrix4Scratch);
  22777. var southMercatorY;
  22778. var oneOverMercatorHeight;
  22779. if (includeWebMercatorT) {
  22780. southMercatorY = WebMercatorProjection.geodeticLatitudeToMercatorAngle(geographicSouth);
  22781. oneOverMercatorHeight = 1.0 / (WebMercatorProjection.geodeticLatitudeToMercatorAngle(geographicNorth) - southMercatorY);
  22782. }
  22783. var minimum = minimumScratch;
  22784. minimum.x = Number.POSITIVE_INFINITY;
  22785. minimum.y = Number.POSITIVE_INFINITY;
  22786. minimum.z = Number.POSITIVE_INFINITY;
  22787. var maximum = maximumScratch;
  22788. maximum.x = Number.NEGATIVE_INFINITY;
  22789. maximum.y = Number.NEGATIVE_INFINITY;
  22790. maximum.z = Number.NEGATIVE_INFINITY;
  22791. var hMin = Number.POSITIVE_INFINITY;
  22792. var arrayWidth = width + (skirtHeight > 0.0 ? 2.0 : 0.0);
  22793. var arrayHeight = height + (skirtHeight > 0.0 ? 2.0 : 0.0);
  22794. var size = arrayWidth * arrayHeight;
  22795. var positions = new Array(size);
  22796. var heights = new Array(size);
  22797. var uvs = new Array(size);
  22798. var webMercatorTs = includeWebMercatorT ? new Array(size) : [];
  22799. var startRow = 0;
  22800. var endRow = height;
  22801. var startCol = 0;
  22802. var endCol = width;
  22803. if (skirtHeight > 0) {
  22804. --startRow;
  22805. ++endRow;
  22806. --startCol;
  22807. ++endCol;
  22808. }
  22809. var index = 0;
  22810. for (var rowIndex = startRow; rowIndex < endRow; ++rowIndex) {
  22811. var row = rowIndex;
  22812. if (row < 0) {
  22813. row = 0;
  22814. }
  22815. if (row >= height) {
  22816. row = height - 1;
  22817. }
  22818. var latitude = nativeRectangle.north - granularityY * row;
  22819. if (!isGeographic) {
  22820. latitude = piOverTwo - (2.0 * atan(exp(-latitude * oneOverGlobeSemimajorAxis)));
  22821. } else {
  22822. latitude = toRadians(latitude);
  22823. }
  22824. var cosLatitude = cos(latitude);
  22825. var nZ = sin(latitude);
  22826. var kZ = radiiSquaredZ * nZ;
  22827. var v = (latitude - geographicSouth) / (geographicNorth - geographicSouth);
  22828. v = CesiumMath.clamp(v, 0.0, 1.0);
  22829. var webMercatorT;
  22830. if (includeWebMercatorT) {
  22831. webMercatorT = (WebMercatorProjection.geodeticLatitudeToMercatorAngle(latitude) - southMercatorY) * oneOverMercatorHeight;
  22832. }
  22833. for (var colIndex = startCol; colIndex < endCol; ++colIndex) {
  22834. var col = colIndex;
  22835. if (col < 0) {
  22836. col = 0;
  22837. }
  22838. if (col >= width) {
  22839. col = width - 1;
  22840. }
  22841. var longitude = nativeRectangle.west + granularityX * col;
  22842. if (!isGeographic) {
  22843. longitude = longitude * oneOverGlobeSemimajorAxis;
  22844. } else {
  22845. longitude = toRadians(longitude);
  22846. }
  22847. var terrainOffset = row * (width * stride) + col * stride;
  22848. var heightSample;
  22849. if (elementsPerHeight === 1) {
  22850. heightSample = heightmap[terrainOffset];
  22851. } else {
  22852. heightSample = 0;
  22853. var elementOffset;
  22854. if (isBigEndian) {
  22855. for (elementOffset = 0; elementOffset < elementsPerHeight; ++elementOffset) {
  22856. heightSample = (heightSample * elementMultiplier) + heightmap[terrainOffset + elementOffset];
  22857. }
  22858. } else {
  22859. for (elementOffset = elementsPerHeight - 1; elementOffset >= 0; --elementOffset) {
  22860. heightSample = (heightSample * elementMultiplier) + heightmap[terrainOffset + elementOffset];
  22861. }
  22862. }
  22863. }
  22864. heightSample = (heightSample * heightScale + heightOffset) * exaggeration;
  22865. maximumHeight = Math.max(maximumHeight, heightSample);
  22866. minimumHeight = Math.min(minimumHeight, heightSample);
  22867. if (colIndex !== col || rowIndex !== row) {
  22868. heightSample -= skirtHeight;
  22869. }
  22870. var nX = cosLatitude * cos(longitude);
  22871. var nY = cosLatitude * sin(longitude);
  22872. var kX = radiiSquaredX * nX;
  22873. var kY = radiiSquaredY * nY;
  22874. var gamma = sqrt((kX * nX) + (kY * nY) + (kZ * nZ));
  22875. var oneOverGamma = 1.0 / gamma;
  22876. var rSurfaceX = kX * oneOverGamma;
  22877. var rSurfaceY = kY * oneOverGamma;
  22878. var rSurfaceZ = kZ * oneOverGamma;
  22879. var position = new Cartesian3();
  22880. position.x = rSurfaceX + nX * heightSample;
  22881. position.y = rSurfaceY + nY * heightSample;
  22882. position.z = rSurfaceZ + nZ * heightSample;
  22883. positions[index] = position;
  22884. heights[index] = heightSample;
  22885. var u = (longitude - geographicWest) / (geographicEast - geographicWest);
  22886. u = CesiumMath.clamp(u, 0.0, 1.0);
  22887. uvs[index] = new Cartesian2(u, v);
  22888. if (includeWebMercatorT) {
  22889. webMercatorTs[index] = webMercatorT;
  22890. }
  22891. index++;
  22892. Matrix4.multiplyByPoint(toENU, position, cartesian3Scratch);
  22893. Cartesian3.minimumByComponent(cartesian3Scratch, minimum, minimum);
  22894. Cartesian3.maximumByComponent(cartesian3Scratch, maximum, maximum);
  22895. hMin = Math.min(hMin, heightSample);
  22896. }
  22897. }
  22898. var boundingSphere3D = BoundingSphere.fromPoints(positions);
  22899. var orientedBoundingBox;
  22900. if (defined(rectangle) && rectangle.width < CesiumMath.PI_OVER_TWO + CesiumMath.EPSILON5) {
  22901. // Here, rectangle.width < pi/2, and rectangle.height < pi
  22902. // (though it would still work with rectangle.width up to pi)
  22903. orientedBoundingBox = OrientedBoundingBox.fromRectangle(rectangle, minimumHeight, maximumHeight, ellipsoid);
  22904. }
  22905. var occludeePointInScaledSpace;
  22906. if (hasRelativeToCenter) {
  22907. var occluder = new EllipsoidalOccluder(ellipsoid);
  22908. occludeePointInScaledSpace = occluder.computeHorizonCullingPoint(relativeToCenter, positions);
  22909. }
  22910. var aaBox = new AxisAlignedBoundingBox(minimum, maximum, relativeToCenter);
  22911. var encoding = new TerrainEncoding(aaBox, hMin, maximumHeight, fromENU, false, includeWebMercatorT);
  22912. var vertices = new Float32Array(size * encoding.getStride());
  22913. var bufferIndex = 0;
  22914. for (var j = 0; j < size; ++j) {
  22915. bufferIndex = encoding.encode(vertices, bufferIndex, positions[j], uvs[j], heights[j], undefined, webMercatorTs[j]);
  22916. }
  22917. return {
  22918. vertices : vertices,
  22919. maximumHeight : maximumHeight,
  22920. minimumHeight : minimumHeight,
  22921. encoding : encoding,
  22922. boundingSphere3D : boundingSphere3D,
  22923. orientedBoundingBox : orientedBoundingBox,
  22924. occludeePointInScaledSpace : occludeePointInScaledSpace
  22925. };
  22926. };
  22927. return HeightmapTessellator;
  22928. });
  22929. /*global define*/
  22930. define('Core/destroyObject',[
  22931. './defaultValue',
  22932. './DeveloperError'
  22933. ], function(
  22934. defaultValue,
  22935. DeveloperError) {
  22936. 'use strict';
  22937. function returnTrue() {
  22938. return true;
  22939. }
  22940. /**
  22941. * Destroys an object. Each of the object's functions, including functions in its prototype,
  22942. * is replaced with a function that throws a {@link DeveloperError}, except for the object's
  22943. * <code>isDestroyed</code> function, which is set to a function that returns <code>true</code>.
  22944. * The object's properties are removed with <code>delete</code>.
  22945. * <br /><br />
  22946. * This function is used by objects that hold native resources, e.g., WebGL resources, which
  22947. * need to be explicitly released. Client code calls an object's <code>destroy</code> function,
  22948. * which then releases the native resource and calls <code>destroyObject</code> to put itself
  22949. * in a destroyed state.
  22950. *
  22951. * @exports destroyObject
  22952. *
  22953. * @param {Object} object The object to destroy.
  22954. * @param {String} [message] The message to include in the exception that is thrown if
  22955. * a destroyed object's function is called.
  22956. *
  22957. *
  22958. * @example
  22959. * // How a texture would destroy itself.
  22960. * this.destroy = function () {
  22961. * _gl.deleteTexture(_texture);
  22962. * return Cesium.destroyObject(this);
  22963. * };
  22964. *
  22965. * @see DeveloperError
  22966. */
  22967. function destroyObject(object, message) {
  22968. message = defaultValue(message, 'This object was destroyed, i.e., destroy() was called.');
  22969. function throwOnDestroyed() {
  22970. throw new DeveloperError(message);
  22971. }
  22972. for ( var key in object) {
  22973. if (typeof object[key] === 'function') {
  22974. object[key] = throwOnDestroyed;
  22975. }
  22976. }
  22977. object.isDestroyed = returnTrue;
  22978. return undefined;
  22979. }
  22980. return destroyObject;
  22981. });
  22982. /*global define*/
  22983. define('Core/isCrossOriginUrl',[
  22984. './defined'
  22985. ], function(
  22986. defined) {
  22987. 'use strict';
  22988. var a;
  22989. /**
  22990. * Given a URL, determine whether that URL is considered cross-origin to the current page.
  22991. *
  22992. * @private
  22993. */
  22994. function isCrossOriginUrl(url) {
  22995. if (!defined(a)) {
  22996. a = document.createElement('a');
  22997. }
  22998. // copy window location into the anchor to get consistent results
  22999. // when the port is default for the protocol (e.g. 80 for HTTP)
  23000. a.href = window.location.href;
  23001. // host includes both hostname and port if the port is not standard
  23002. var host = a.host;
  23003. var protocol = a.protocol;
  23004. a.href = url;
  23005. a.href = a.href; // IE only absolutizes href on get, not set
  23006. return protocol !== a.protocol || host !== a.host;
  23007. }
  23008. return isCrossOriginUrl;
  23009. });
  23010. /*global define*/
  23011. define('Core/TaskProcessor',[
  23012. '../ThirdParty/when',
  23013. './buildModuleUrl',
  23014. './defaultValue',
  23015. './defined',
  23016. './destroyObject',
  23017. './DeveloperError',
  23018. './getAbsoluteUri',
  23019. './isCrossOriginUrl',
  23020. './RuntimeError',
  23021. 'require'
  23022. ], function(
  23023. when,
  23024. buildModuleUrl,
  23025. defaultValue,
  23026. defined,
  23027. destroyObject,
  23028. DeveloperError,
  23029. getAbsoluteUri,
  23030. isCrossOriginUrl,
  23031. RuntimeError,
  23032. require) {
  23033. 'use strict';
  23034. function canTransferArrayBuffer() {
  23035. if (!defined(TaskProcessor._canTransferArrayBuffer)) {
  23036. var worker = new Worker(getWorkerUrl('Workers/transferTypedArrayTest.js'));
  23037. worker.postMessage = defaultValue(worker.webkitPostMessage, worker.postMessage);
  23038. var value = 99;
  23039. var array = new Int8Array([value]);
  23040. try {
  23041. // postMessage might fail with a DataCloneError
  23042. // if transferring array buffers is not supported.
  23043. worker.postMessage({
  23044. array : array
  23045. }, [array.buffer]);
  23046. } catch (e) {
  23047. TaskProcessor._canTransferArrayBuffer = false;
  23048. return TaskProcessor._canTransferArrayBuffer;
  23049. }
  23050. var deferred = when.defer();
  23051. worker.onmessage = function(event) {
  23052. var array = event.data.array;
  23053. // some versions of Firefox silently fail to transfer typed arrays.
  23054. // https://bugzilla.mozilla.org/show_bug.cgi?id=841904
  23055. // Check to make sure the value round-trips successfully.
  23056. var result = defined(array) && array[0] === value;
  23057. deferred.resolve(result);
  23058. worker.terminate();
  23059. TaskProcessor._canTransferArrayBuffer = result;
  23060. };
  23061. TaskProcessor._canTransferArrayBuffer = deferred.promise;
  23062. }
  23063. return TaskProcessor._canTransferArrayBuffer;
  23064. }
  23065. function completeTask(processor, data) {
  23066. --processor._activeTasks;
  23067. var id = data.id;
  23068. if (!defined(id)) {
  23069. // This is not one of ours.
  23070. return;
  23071. }
  23072. var deferreds = processor._deferreds;
  23073. var deferred = deferreds[id];
  23074. if (defined(data.error)) {
  23075. var error = data.error;
  23076. if (error.name === 'RuntimeError') {
  23077. error = new RuntimeError(data.error.message);
  23078. error.stack = data.error.stack;
  23079. } else if (error.name === 'DeveloperError') {
  23080. error = new DeveloperError(data.error.message);
  23081. error.stack = data.error.stack;
  23082. }
  23083. deferred.reject(error);
  23084. } else {
  23085. deferred.resolve(data.result);
  23086. }
  23087. delete deferreds[id];
  23088. }
  23089. function getWorkerUrl(moduleID) {
  23090. var url = buildModuleUrl(moduleID);
  23091. if (isCrossOriginUrl(url)) {
  23092. //to load cross-origin, create a shim worker from a blob URL
  23093. var script = 'importScripts("' + url + '");';
  23094. var blob;
  23095. try {
  23096. blob = new Blob([script], {
  23097. type : 'application/javascript'
  23098. });
  23099. } catch (e) {
  23100. var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
  23101. var blobBuilder = new BlobBuilder();
  23102. blobBuilder.append(script);
  23103. blob = blobBuilder.getBlob('application/javascript');
  23104. }
  23105. var URL = window.URL || window.webkitURL;
  23106. url = URL.createObjectURL(blob);
  23107. }
  23108. return url;
  23109. }
  23110. var bootstrapperUrlResult;
  23111. function getBootstrapperUrl() {
  23112. if (!defined(bootstrapperUrlResult)) {
  23113. bootstrapperUrlResult = getWorkerUrl('Workers/cesiumWorkerBootstrapper.js');
  23114. }
  23115. return bootstrapperUrlResult;
  23116. }
  23117. function createWorker(processor) {
  23118. var worker = new Worker(getBootstrapperUrl());
  23119. worker.postMessage = defaultValue(worker.webkitPostMessage, worker.postMessage);
  23120. var bootstrapMessage = {
  23121. loaderConfig : {},
  23122. workerModule : TaskProcessor._workerModulePrefix + processor._workerName
  23123. };
  23124. if (defined(TaskProcessor._loaderConfig)) {
  23125. bootstrapMessage.loaderConfig = TaskProcessor._loaderConfig;
  23126. } else if (defined(require.toUrl)) {
  23127. bootstrapMessage.loaderConfig.baseUrl =
  23128. getAbsoluteUri('..', buildModuleUrl('Workers/cesiumWorkerBootstrapper.js'));
  23129. } else {
  23130. bootstrapMessage.loaderConfig.paths = {
  23131. 'Workers' : buildModuleUrl('Workers')
  23132. };
  23133. }
  23134. worker.postMessage(bootstrapMessage);
  23135. worker.onmessage = function(event) {
  23136. completeTask(processor, event.data);
  23137. };
  23138. return worker;
  23139. }
  23140. /**
  23141. * A wrapper around a web worker that allows scheduling tasks for a given worker,
  23142. * returning results asynchronously via a promise.
  23143. *
  23144. * The Worker is not constructed until a task is scheduled.
  23145. *
  23146. * @alias TaskProcessor
  23147. * @constructor
  23148. *
  23149. * @param {String} workerName The name of the worker. This is expected to be a script
  23150. * in the Workers folder.
  23151. * @param {Number} [maximumActiveTasks=5] The maximum number of active tasks. Once exceeded,
  23152. * scheduleTask will not queue any more tasks, allowing
  23153. * work to be rescheduled in future frames.
  23154. */
  23155. function TaskProcessor(workerName, maximumActiveTasks) {
  23156. this._workerName = workerName;
  23157. this._maximumActiveTasks = defaultValue(maximumActiveTasks, 5);
  23158. this._activeTasks = 0;
  23159. this._deferreds = {};
  23160. this._nextID = 0;
  23161. }
  23162. var emptyTransferableObjectArray = [];
  23163. /**
  23164. * Schedule a task to be processed by the web worker asynchronously. If there are currently more
  23165. * tasks active than the maximum set by the constructor, will immediately return undefined.
  23166. * Otherwise, returns a promise that will resolve to the result posted back by the worker when
  23167. * finished.
  23168. *
  23169. * @param {*} parameters Any input data that will be posted to the worker.
  23170. * @param {Object[]} [transferableObjects] An array of objects contained in parameters that should be
  23171. * transferred to the worker instead of copied.
  23172. * @returns {Promise.<Object>|undefined} Either a promise that will resolve to the result when available, or undefined
  23173. * if there are too many active tasks,
  23174. *
  23175. * @example
  23176. * var taskProcessor = new Cesium.TaskProcessor('myWorkerName');
  23177. * var promise = taskProcessor.scheduleTask({
  23178. * someParameter : true,
  23179. * another : 'hello'
  23180. * });
  23181. * if (!Cesium.defined(promise)) {
  23182. * // too many active tasks - try again later
  23183. * } else {
  23184. * Cesium.when(promise, function(result) {
  23185. * // use the result of the task
  23186. * });
  23187. * }
  23188. */
  23189. TaskProcessor.prototype.scheduleTask = function(parameters, transferableObjects) {
  23190. if (!defined(this._worker)) {
  23191. this._worker = createWorker(this);
  23192. }
  23193. if (this._activeTasks >= this._maximumActiveTasks) {
  23194. return undefined;
  23195. }
  23196. ++this._activeTasks;
  23197. var processor = this;
  23198. return when(canTransferArrayBuffer(), function(canTransferArrayBuffer) {
  23199. if (!defined(transferableObjects)) {
  23200. transferableObjects = emptyTransferableObjectArray;
  23201. } else if (!canTransferArrayBuffer) {
  23202. transferableObjects.length = 0;
  23203. }
  23204. var id = processor._nextID++;
  23205. var deferred = when.defer();
  23206. processor._deferreds[id] = deferred;
  23207. processor._worker.postMessage({
  23208. id : id,
  23209. parameters : parameters,
  23210. canTransferArrayBuffer : canTransferArrayBuffer
  23211. }, transferableObjects);
  23212. return deferred.promise;
  23213. });
  23214. };
  23215. /**
  23216. * Returns true if this object was destroyed; otherwise, false.
  23217. * <br /><br />
  23218. * If this object was destroyed, it should not be used; calling any function other than
  23219. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  23220. *
  23221. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  23222. *
  23223. * @see TaskProcessor#destroy
  23224. */
  23225. TaskProcessor.prototype.isDestroyed = function() {
  23226. return false;
  23227. };
  23228. /**
  23229. * Destroys this object. This will immediately terminate the Worker.
  23230. * <br /><br />
  23231. * Once an object is destroyed, it should not be used; calling any function other than
  23232. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  23233. *
  23234. * @returns {undefined}
  23235. */
  23236. TaskProcessor.prototype.destroy = function() {
  23237. if (defined(this._worker)) {
  23238. this._worker.terminate();
  23239. }
  23240. return destroyObject(this);
  23241. };
  23242. // exposed for testing purposes
  23243. TaskProcessor._defaultWorkerModulePrefix = 'Workers/';
  23244. TaskProcessor._workerModulePrefix = TaskProcessor._defaultWorkerModulePrefix;
  23245. TaskProcessor._loaderConfig = undefined;
  23246. TaskProcessor._canTransferArrayBuffer = undefined;
  23247. return TaskProcessor;
  23248. });
  23249. /*global define*/
  23250. define('Core/TerrainMesh',[
  23251. './defaultValue'
  23252. ], function(
  23253. defaultValue) {
  23254. 'use strict';
  23255. /**
  23256. * A mesh plus related metadata for a single tile of terrain. Instances of this type are
  23257. * usually created from raw {@link TerrainData}.
  23258. *
  23259. * @alias TerrainMesh
  23260. * @constructor
  23261. *
  23262. * @param {Cartesian3} center The center of the tile. Vertex positions are specified relative to this center.
  23263. * @param {Float32Array} vertices The vertex data, including positions, texture coordinates, and heights.
  23264. * The vertex data is in the order [X, Y, Z, H, U, V], where X, Y, and Z represent
  23265. * the Cartesian position of the vertex, H is the height above the ellipsoid, and
  23266. * U and V are the texture coordinates.
  23267. * @param {Uint16Array|Uint32Array} indices The indices describing how the vertices are connected to form triangles.
  23268. * @param {Number} minimumHeight The lowest height in the tile, in meters above the ellipsoid.
  23269. * @param {Number} maximumHeight The highest height in the tile, in meters above the ellipsoid.
  23270. * @param {BoundingSphere} boundingSphere3D A bounding sphere that completely contains the tile.
  23271. * @param {Cartesian3} occludeePointInScaledSpace The occludee point of the tile, represented in ellipsoid-
  23272. * scaled space, and used for horizon culling. If this point is below the horizon,
  23273. * the tile is considered to be entirely below the horizon.
  23274. * @param {Number} [vertexStride=6] The number of components in each vertex.
  23275. * @param {OrientedBoundingBox} [orientedBoundingBox] A bounding box that completely contains the tile.
  23276. * @param {TerrainEncoding} encoding Information used to decode the mesh.
  23277. *
  23278. * @private
  23279. */
  23280. function TerrainMesh(center, vertices, indices, minimumHeight, maximumHeight, boundingSphere3D, occludeePointInScaledSpace, vertexStride, orientedBoundingBox, encoding, exaggeration) {
  23281. /**
  23282. * The center of the tile. Vertex positions are specified relative to this center.
  23283. * @type {Cartesian3}
  23284. */
  23285. this.center = center;
  23286. /**
  23287. * The vertex data, including positions, texture coordinates, and heights.
  23288. * The vertex data is in the order [X, Y, Z, H, U, V], where X, Y, and Z represent
  23289. * the Cartesian position of the vertex, H is the height above the ellipsoid, and
  23290. * U and V are the texture coordinates. The vertex data may have additional attributes after those
  23291. * mentioned above when the {@link TerrainMesh#stride} is greater than 6.
  23292. * @type {Float32Array}
  23293. */
  23294. this.vertices = vertices;
  23295. /**
  23296. * The number of components in each vertex. Typically this is 6 for the 6 components
  23297. * [X, Y, Z, H, U, V], but if each vertex has additional data (such as a vertex normal), this value
  23298. * may be higher.
  23299. * @type {Number}
  23300. */
  23301. this.stride = defaultValue(vertexStride, 6);
  23302. /**
  23303. * The indices describing how the vertices are connected to form triangles.
  23304. * @type {Uint16Array|Uint32Array}
  23305. */
  23306. this.indices = indices;
  23307. /**
  23308. * The lowest height in the tile, in meters above the ellipsoid.
  23309. * @type {Number}
  23310. */
  23311. this.minimumHeight = minimumHeight;
  23312. /**
  23313. * The highest height in the tile, in meters above the ellipsoid.
  23314. * @type {Number}
  23315. */
  23316. this.maximumHeight = maximumHeight;
  23317. /**
  23318. * A bounding sphere that completely contains the tile.
  23319. * @type {BoundingSphere}
  23320. */
  23321. this.boundingSphere3D = boundingSphere3D;
  23322. /**
  23323. * The occludee point of the tile, represented in ellipsoid-
  23324. * scaled space, and used for horizon culling. If this point is below the horizon,
  23325. * the tile is considered to be entirely below the horizon.
  23326. * @type {Cartesian3}
  23327. */
  23328. this.occludeePointInScaledSpace = occludeePointInScaledSpace;
  23329. /**
  23330. * A bounding box that completely contains the tile.
  23331. * @type {OrientedBoundingBox}
  23332. */
  23333. this.orientedBoundingBox = orientedBoundingBox;
  23334. /**
  23335. * Information for decoding the mesh vertices.
  23336. * @type {TerrainEncoding}
  23337. */
  23338. this.encoding = encoding;
  23339. /**
  23340. * The amount that this mesh was exaggerated.
  23341. * @type {Number}
  23342. */
  23343. this.exaggeration = exaggeration;
  23344. }
  23345. return TerrainMesh;
  23346. });
  23347. /*global define*/
  23348. define('Core/TerrainProvider',[
  23349. './defined',
  23350. './defineProperties',
  23351. './DeveloperError',
  23352. './Math'
  23353. ], function(
  23354. defined,
  23355. defineProperties,
  23356. DeveloperError,
  23357. CesiumMath) {
  23358. 'use strict';
  23359. /**
  23360. * Provides terrain or other geometry for the surface of an ellipsoid. The surface geometry is
  23361. * organized into a pyramid of tiles according to a {@link TilingScheme}. This type describes an
  23362. * interface and is not intended to be instantiated directly.
  23363. *
  23364. * @alias TerrainProvider
  23365. * @constructor
  23366. *
  23367. * @see EllipsoidTerrainProvider
  23368. * @see CesiumTerrainProvider
  23369. * @see ArcGisImageServerTerrainProvider
  23370. */
  23371. function TerrainProvider() {
  23372. DeveloperError.throwInstantiationError();
  23373. }
  23374. defineProperties(TerrainProvider.prototype, {
  23375. /**
  23376. * Gets an event that is raised when the terrain provider encounters an asynchronous error.. By subscribing
  23377. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  23378. * are passed an instance of {@link TileProviderError}.
  23379. * @memberof TerrainProvider.prototype
  23380. * @type {Event}
  23381. */
  23382. errorEvent : {
  23383. get : DeveloperError.throwInstantiationError
  23384. },
  23385. /**
  23386. * Gets the credit to display when this terrain provider is active. Typically this is used to credit
  23387. * the source of the terrain. This function should
  23388. * not be called before {@link TerrainProvider#ready} returns true.
  23389. * @memberof TerrainProvider.prototype
  23390. * @type {Credit}
  23391. */
  23392. credit : {
  23393. get : DeveloperError.throwInstantiationError
  23394. },
  23395. /**
  23396. * Gets the tiling scheme used by the provider. This function should
  23397. * not be called before {@link TerrainProvider#ready} returns true.
  23398. * @memberof TerrainProvider.prototype
  23399. * @type {TilingScheme}
  23400. */
  23401. tilingScheme : {
  23402. get : DeveloperError.throwInstantiationError
  23403. },
  23404. /**
  23405. * Gets a value indicating whether or not the provider is ready for use.
  23406. * @memberof TerrainProvider.prototype
  23407. * @type {Boolean}
  23408. */
  23409. ready : {
  23410. get : DeveloperError.throwInstantiationError
  23411. },
  23412. /**
  23413. * Gets a promise that resolves to true when the provider is ready for use.
  23414. * @memberof TerrainProvider.prototype
  23415. * @type {Promise.<Boolean>}
  23416. * @readonly
  23417. */
  23418. readyPromise : {
  23419. get : DeveloperError.throwInstantiationError
  23420. },
  23421. /**
  23422. * Gets a value indicating whether or not the provider includes a water mask. The water mask
  23423. * indicates which areas of the globe are water rather than land, so they can be rendered
  23424. * as a reflective surface with animated waves. This function should not be
  23425. * called before {@link TerrainProvider#ready} returns true.
  23426. * @memberof TerrainProvider.prototype
  23427. * @type {Boolean}
  23428. */
  23429. hasWaterMask : {
  23430. get : DeveloperError.throwInstantiationError
  23431. },
  23432. /**
  23433. * Gets a value indicating whether or not the requested tiles include vertex normals.
  23434. * This function should not be called before {@link TerrainProvider#ready} returns true.
  23435. * @memberof TerrainProvider.prototype
  23436. * @type {Boolean}
  23437. */
  23438. hasVertexNormals : {
  23439. get : DeveloperError.throwInstantiationError
  23440. }
  23441. });
  23442. var regularGridIndexArrays = [];
  23443. /**
  23444. * Gets a list of indices for a triangle mesh representing a regular grid. Calling
  23445. * this function multiple times with the same grid width and height returns the
  23446. * same list of indices. The total number of vertices must be less than or equal
  23447. * to 65536.
  23448. *
  23449. * @param {Number} width The number of vertices in the regular grid in the horizontal direction.
  23450. * @param {Number} height The number of vertices in the regular grid in the vertical direction.
  23451. * @returns {Uint16Array} The list of indices.
  23452. */
  23453. TerrainProvider.getRegularGridIndices = function(width, height) {
  23454. if (width * height >= CesiumMath.SIXTY_FOUR_KILOBYTES) {
  23455. throw new DeveloperError('The total number of vertices (width * height) must be less than 65536.');
  23456. }
  23457. var byWidth = regularGridIndexArrays[width];
  23458. if (!defined(byWidth)) {
  23459. regularGridIndexArrays[width] = byWidth = [];
  23460. }
  23461. var indices = byWidth[height];
  23462. if (!defined(indices)) {
  23463. indices = byWidth[height] = new Uint16Array((width - 1) * (height - 1) * 6);
  23464. var index = 0;
  23465. var indicesIndex = 0;
  23466. for (var j = 0; j < height - 1; ++j) {
  23467. for (var i = 0; i < width - 1; ++i) {
  23468. var upperLeft = index;
  23469. var lowerLeft = upperLeft + width;
  23470. var lowerRight = lowerLeft + 1;
  23471. var upperRight = upperLeft + 1;
  23472. indices[indicesIndex++] = upperLeft;
  23473. indices[indicesIndex++] = lowerLeft;
  23474. indices[indicesIndex++] = upperRight;
  23475. indices[indicesIndex++] = upperRight;
  23476. indices[indicesIndex++] = lowerLeft;
  23477. indices[indicesIndex++] = lowerRight;
  23478. ++index;
  23479. }
  23480. ++index;
  23481. }
  23482. }
  23483. return indices;
  23484. };
  23485. /**
  23486. * Specifies the quality of terrain created from heightmaps. A value of 1.0 will
  23487. * ensure that adjacent heightmap vertices are separated by no more than
  23488. * {@link Globe.maximumScreenSpaceError} screen pixels and will probably go very slowly.
  23489. * A value of 0.5 will cut the estimated level zero geometric error in half, allowing twice the
  23490. * screen pixels between adjacent heightmap vertices and thus rendering more quickly.
  23491. * @type {Number}
  23492. */
  23493. TerrainProvider.heightmapTerrainQuality = 0.25;
  23494. /**
  23495. * Determines an appropriate geometric error estimate when the geometry comes from a heightmap.
  23496. *
  23497. * @param {Ellipsoid} ellipsoid The ellipsoid to which the terrain is attached.
  23498. * @param {Number} tileImageWidth The width, in pixels, of the heightmap associated with a single tile.
  23499. * @param {Number} numberOfTilesAtLevelZero The number of tiles in the horizontal direction at tile level zero.
  23500. * @returns {Number} An estimated geometric error.
  23501. */
  23502. TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap = function(ellipsoid, tileImageWidth, numberOfTilesAtLevelZero) {
  23503. return ellipsoid.maximumRadius * 2 * Math.PI * TerrainProvider.heightmapTerrainQuality / (tileImageWidth * numberOfTilesAtLevelZero);
  23504. };
  23505. /**
  23506. * Requests the geometry for a given tile. This function should not be called before
  23507. * {@link TerrainProvider#ready} returns true. The result must include terrain data and
  23508. * may optionally include a water mask and an indication of which child tiles are available.
  23509. * @function
  23510. *
  23511. * @param {Number} x The X coordinate of the tile for which to request geometry.
  23512. * @param {Number} y The Y coordinate of the tile for which to request geometry.
  23513. * @param {Number} level The level of the tile for which to request geometry.
  23514. * @param {Boolean} [throttleRequests=true] True if the number of simultaneous requests should be limited,
  23515. * or false if the request should be initiated regardless of the number of requests
  23516. * already in progress.
  23517. * @returns {Promise.<TerrainData>|undefined} A promise for the requested geometry. If this method
  23518. * returns undefined instead of a promise, it is an indication that too many requests are already
  23519. * pending and the request will be retried later.
  23520. */
  23521. TerrainProvider.prototype.requestTileGeometry = DeveloperError.throwInstantiationError;
  23522. /**
  23523. * Gets the maximum geometric error allowed in a tile at a given level. This function should not be
  23524. * called before {@link TerrainProvider#ready} returns true.
  23525. * @function
  23526. *
  23527. * @param {Number} level The tile level for which to get the maximum geometric error.
  23528. * @returns {Number} The maximum geometric error.
  23529. */
  23530. TerrainProvider.prototype.getLevelMaximumGeometricError = DeveloperError.throwInstantiationError;
  23531. /**
  23532. * Determines whether data for a tile is available to be loaded.
  23533. * @function
  23534. *
  23535. * @param {Number} x The X coordinate of the tile for which to request geometry.
  23536. * @param {Number} y The Y coordinate of the tile for which to request geometry.
  23537. * @param {Number} level The level of the tile for which to request geometry.
  23538. * @returns {Boolean} Undefined if not supported by the terrain provider, otherwise true or false.
  23539. */
  23540. TerrainProvider.prototype.getTileDataAvailable = DeveloperError.throwInstantiationError;
  23541. return TerrainProvider;
  23542. });
  23543. /*global define*/
  23544. define('Core/HeightmapTerrainData',[
  23545. '../ThirdParty/when',
  23546. './defaultValue',
  23547. './defined',
  23548. './defineProperties',
  23549. './DeveloperError',
  23550. './GeographicTilingScheme',
  23551. './HeightmapTessellator',
  23552. './Math',
  23553. './Rectangle',
  23554. './TaskProcessor',
  23555. './TerrainEncoding',
  23556. './TerrainMesh',
  23557. './TerrainProvider'
  23558. ], function(
  23559. when,
  23560. defaultValue,
  23561. defined,
  23562. defineProperties,
  23563. DeveloperError,
  23564. GeographicTilingScheme,
  23565. HeightmapTessellator,
  23566. CesiumMath,
  23567. Rectangle,
  23568. TaskProcessor,
  23569. TerrainEncoding,
  23570. TerrainMesh,
  23571. TerrainProvider) {
  23572. 'use strict';
  23573. /**
  23574. * Terrain data for a single tile where the terrain data is represented as a heightmap. A heightmap
  23575. * is a rectangular array of heights in row-major order from south to north and west to east.
  23576. *
  23577. * @alias HeightmapTerrainData
  23578. * @constructor
  23579. *
  23580. * @param {Object} options Object with the following properties:
  23581. * @param {TypedArray} options.buffer The buffer containing height data.
  23582. * @param {Number} options.width The width (longitude direction) of the heightmap, in samples.
  23583. * @param {Number} options.height The height (latitude direction) of the heightmap, in samples.
  23584. * @param {Number} [options.childTileMask=15] A bit mask indicating which of this tile's four children exist.
  23585. * If a child's bit is set, geometry will be requested for that tile as well when it
  23586. * is needed. If the bit is cleared, the child tile is not requested and geometry is
  23587. * instead upsampled from the parent. The bit values are as follows:
  23588. * <table>
  23589. * <tr><th>Bit Position</th><th>Bit Value</th><th>Child Tile</th></tr>
  23590. * <tr><td>0</td><td>1</td><td>Southwest</td></tr>
  23591. * <tr><td>1</td><td>2</td><td>Southeast</td></tr>
  23592. * <tr><td>2</td><td>4</td><td>Northwest</td></tr>
  23593. * <tr><td>3</td><td>8</td><td>Northeast</td></tr>
  23594. * </table>
  23595. * @param {Object} [options.structure] An object describing the structure of the height data.
  23596. * @param {Number} [options.structure.heightScale=1.0] The factor by which to multiply height samples in order to obtain
  23597. * the height above the heightOffset, in meters. The heightOffset is added to the resulting
  23598. * height after multiplying by the scale.
  23599. * @param {Number} [options.structure.heightOffset=0.0] The offset to add to the scaled height to obtain the final
  23600. * height in meters. The offset is added after the height sample is multiplied by the
  23601. * heightScale.
  23602. * @param {Number} [options.structure.elementsPerHeight=1] The number of elements in the buffer that make up a single height
  23603. * sample. This is usually 1, indicating that each element is a separate height sample. If
  23604. * it is greater than 1, that number of elements together form the height sample, which is
  23605. * computed according to the structure.elementMultiplier and structure.isBigEndian properties.
  23606. * @param {Number} [options.structure.stride=1] The number of elements to skip to get from the first element of
  23607. * one height to the first element of the next height.
  23608. * @param {Number} [options.structure.elementMultiplier=256.0] The multiplier used to compute the height value when the
  23609. * stride property is greater than 1. For example, if the stride is 4 and the strideMultiplier
  23610. * is 256, the height is computed as follows:
  23611. * `height = buffer[index] + buffer[index + 1] * 256 + buffer[index + 2] * 256 * 256 + buffer[index + 3] * 256 * 256 * 256`
  23612. * This is assuming that the isBigEndian property is false. If it is true, the order of the
  23613. * elements is reversed.
  23614. * @param {Boolean} [options.structure.isBigEndian=false] Indicates endianness of the elements in the buffer when the
  23615. * stride property is greater than 1. If this property is false, the first element is the
  23616. * low-order element. If it is true, the first element is the high-order element.
  23617. * @param {Number} [options.structure.lowestEncodedHeight] The lowest value that can be stored in the height buffer. Any heights that are lower
  23618. * than this value after encoding with the `heightScale` and `heightOffset` are clamped to this value. For example, if the height
  23619. * buffer is a `Uint16Array`, this value should be 0 because a `Uint16Array` cannot store negative numbers. If this parameter is
  23620. * not specified, no minimum value is enforced.
  23621. * @param {Number} [options.structure.highestEncodedHeight] The highest value that can be stored in the height buffer. Any heights that are higher
  23622. * than this value after encoding with the `heightScale` and `heightOffset` are clamped to this value. For example, if the height
  23623. * buffer is a `Uint16Array`, this value should be `256 * 256 - 1` or 65535 because a `Uint16Array` cannot store numbers larger
  23624. * than 65535. If this parameter is not specified, no maximum value is enforced.
  23625. * @param {Boolean} [options.createdByUpsampling=false] True if this instance was created by upsampling another instance;
  23626. * otherwise, false.
  23627. *
  23628. *
  23629. * @example
  23630. * var buffer = ...
  23631. * var heightBuffer = new Uint16Array(buffer, 0, that._heightmapWidth * that._heightmapWidth);
  23632. * var childTileMask = new Uint8Array(buffer, heightBuffer.byteLength, 1)[0];
  23633. * var waterMask = new Uint8Array(buffer, heightBuffer.byteLength + 1, buffer.byteLength - heightBuffer.byteLength - 1);
  23634. * var terrainData = new Cesium.HeightmapTerrainData({
  23635. * buffer : heightBuffer,
  23636. * width : 65,
  23637. * height : 65,
  23638. * childTileMask : childTileMask,
  23639. * waterMask : waterMask
  23640. * });
  23641. *
  23642. * @see TerrainData
  23643. * @see QuantizedMeshTerrainData
  23644. */
  23645. function HeightmapTerrainData(options) {
  23646. if (!defined(options) || !defined(options.buffer)) {
  23647. throw new DeveloperError('options.buffer is required.');
  23648. }
  23649. if (!defined(options.width)) {
  23650. throw new DeveloperError('options.width is required.');
  23651. }
  23652. if (!defined(options.height)) {
  23653. throw new DeveloperError('options.height is required.');
  23654. }
  23655. this._buffer = options.buffer;
  23656. this._width = options.width;
  23657. this._height = options.height;
  23658. this._childTileMask = defaultValue(options.childTileMask, 15);
  23659. var defaultStructure = HeightmapTessellator.DEFAULT_STRUCTURE;
  23660. var structure = options.structure;
  23661. if (!defined(structure)) {
  23662. structure = defaultStructure;
  23663. } else if (structure !== defaultStructure) {
  23664. structure.heightScale = defaultValue(structure.heightScale, defaultStructure.heightScale);
  23665. structure.heightOffset = defaultValue(structure.heightOffset, defaultStructure.heightOffset);
  23666. structure.elementsPerHeight = defaultValue(structure.elementsPerHeight, defaultStructure.elementsPerHeight);
  23667. structure.stride = defaultValue(structure.stride, defaultStructure.stride);
  23668. structure.elementMultiplier = defaultValue(structure.elementMultiplier, defaultStructure.elementMultiplier);
  23669. structure.isBigEndian = defaultValue(structure.isBigEndian, defaultStructure.isBigEndian);
  23670. }
  23671. this._structure = structure;
  23672. this._createdByUpsampling = defaultValue(options.createdByUpsampling, false);
  23673. this._waterMask = options.waterMask;
  23674. this._skirtHeight = undefined;
  23675. this._bufferType = this._buffer.constructor;
  23676. this._mesh = undefined;
  23677. }
  23678. defineProperties(HeightmapTerrainData.prototype, {
  23679. /**
  23680. * The water mask included in this terrain data, if any. A water mask is a rectangular
  23681. * Uint8Array or image where a value of 255 indicates water and a value of 0 indicates land.
  23682. * Values in between 0 and 255 are allowed as well to smoothly blend between land and water.
  23683. * @memberof HeightmapTerrainData.prototype
  23684. * @type {Uint8Array|Image|Canvas}
  23685. */
  23686. waterMask : {
  23687. get : function() {
  23688. return this._waterMask;
  23689. }
  23690. }
  23691. });
  23692. var taskProcessor = new TaskProcessor('createVerticesFromHeightmap');
  23693. /**
  23694. * Creates a {@link TerrainMesh} from this terrain data.
  23695. *
  23696. * @private
  23697. *
  23698. * @param {TilingScheme} tilingScheme The tiling scheme to which this tile belongs.
  23699. * @param {Number} x The X coordinate of the tile for which to create the terrain data.
  23700. * @param {Number} y The Y coordinate of the tile for which to create the terrain data.
  23701. * @param {Number} level The level of the tile for which to create the terrain data.
  23702. * @param {Number} [exaggeration=1.0] The scale used to exaggerate the terrain.
  23703. * @returns {Promise.<TerrainMesh>|undefined} A promise for the terrain mesh, or undefined if too many
  23704. * asynchronous mesh creations are already in progress and the operation should
  23705. * be retried later.
  23706. */
  23707. HeightmapTerrainData.prototype.createMesh = function(tilingScheme, x, y, level, exaggeration) {
  23708. if (!defined(tilingScheme)) {
  23709. throw new DeveloperError('tilingScheme is required.');
  23710. }
  23711. if (!defined(x)) {
  23712. throw new DeveloperError('x is required.');
  23713. }
  23714. if (!defined(y)) {
  23715. throw new DeveloperError('y is required.');
  23716. }
  23717. if (!defined(level)) {
  23718. throw new DeveloperError('level is required.');
  23719. }
  23720. var ellipsoid = tilingScheme.ellipsoid;
  23721. var nativeRectangle = tilingScheme.tileXYToNativeRectangle(x, y, level);
  23722. var rectangle = tilingScheme.tileXYToRectangle(x, y, level);
  23723. exaggeration = defaultValue(exaggeration, 1.0);
  23724. // Compute the center of the tile for RTC rendering.
  23725. var center = ellipsoid.cartographicToCartesian(Rectangle.center(rectangle));
  23726. var structure = this._structure;
  23727. var levelZeroMaxError = TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(ellipsoid, this._width, tilingScheme.getNumberOfXTilesAtLevel(0));
  23728. var thisLevelMaxError = levelZeroMaxError / (1 << level);
  23729. this._skirtHeight = Math.min(thisLevelMaxError * 4.0, 1000.0);
  23730. var verticesPromise = taskProcessor.scheduleTask({
  23731. heightmap : this._buffer,
  23732. structure : structure,
  23733. includeWebMercatorT : true,
  23734. width : this._width,
  23735. height : this._height,
  23736. nativeRectangle : nativeRectangle,
  23737. rectangle : rectangle,
  23738. relativeToCenter : center,
  23739. ellipsoid : ellipsoid,
  23740. skirtHeight : this._skirtHeight,
  23741. isGeographic : tilingScheme instanceof GeographicTilingScheme,
  23742. exaggeration : exaggeration
  23743. });
  23744. if (!defined(verticesPromise)) {
  23745. // Postponed
  23746. return undefined;
  23747. }
  23748. var that = this;
  23749. return when(verticesPromise, function(result) {
  23750. that._mesh = new TerrainMesh(
  23751. center,
  23752. new Float32Array(result.vertices),
  23753. TerrainProvider.getRegularGridIndices(result.gridWidth, result.gridHeight),
  23754. result.minimumHeight,
  23755. result.maximumHeight,
  23756. result.boundingSphere3D,
  23757. result.occludeePointInScaledSpace,
  23758. result.numberOfAttributes,
  23759. result.orientedBoundingBox,
  23760. TerrainEncoding.clone(result.encoding),
  23761. exaggeration);
  23762. // Free memory received from server after mesh is created.
  23763. that._buffer = undefined;
  23764. return that._mesh;
  23765. });
  23766. };
  23767. /**
  23768. * Computes the terrain height at a specified longitude and latitude.
  23769. *
  23770. * @param {Rectangle} rectangle The rectangle covered by this terrain data.
  23771. * @param {Number} longitude The longitude in radians.
  23772. * @param {Number} latitude The latitude in radians.
  23773. * @returns {Number} The terrain height at the specified position. If the position
  23774. * is outside the rectangle, this method will extrapolate the height, which is likely to be wildly
  23775. * incorrect for positions far outside the rectangle.
  23776. */
  23777. HeightmapTerrainData.prototype.interpolateHeight = function(rectangle, longitude, latitude) {
  23778. var width = this._width;
  23779. var height = this._height;
  23780. var structure = this._structure;
  23781. var stride = structure.stride;
  23782. var elementsPerHeight = structure.elementsPerHeight;
  23783. var elementMultiplier = structure.elementMultiplier;
  23784. var isBigEndian = structure.isBigEndian;
  23785. var heightOffset = structure.heightOffset;
  23786. var heightScale = structure.heightScale;
  23787. var heightSample;
  23788. if (defined(this._mesh)) {
  23789. var buffer = this._mesh.vertices;
  23790. var encoding = this._mesh.encoding;
  23791. var skirtHeight = this._skirtHeight;
  23792. var exaggeration = this._mesh.exaggeration;
  23793. heightSample = interpolateMeshHeight(buffer, encoding, heightOffset, heightScale, skirtHeight, rectangle, width, height, longitude, latitude, exaggeration);
  23794. } else {
  23795. heightSample = interpolateHeight(this._buffer, elementsPerHeight, elementMultiplier, stride, isBigEndian, rectangle, width, height, longitude, latitude);
  23796. heightSample = heightSample * heightScale + heightOffset;
  23797. }
  23798. return heightSample;
  23799. };
  23800. /**
  23801. * Upsamples this terrain data for use by a descendant tile. The resulting instance will contain a subset of the
  23802. * height samples in this instance, interpolated if necessary.
  23803. *
  23804. * @param {TilingScheme} tilingScheme The tiling scheme of this terrain data.
  23805. * @param {Number} thisX The X coordinate of this tile in the tiling scheme.
  23806. * @param {Number} thisY The Y coordinate of this tile in the tiling scheme.
  23807. * @param {Number} thisLevel The level of this tile in the tiling scheme.
  23808. * @param {Number} descendantX The X coordinate within the tiling scheme of the descendant tile for which we are upsampling.
  23809. * @param {Number} descendantY The Y coordinate within the tiling scheme of the descendant tile for which we are upsampling.
  23810. * @param {Number} descendantLevel The level within the tiling scheme of the descendant tile for which we are upsampling.
  23811. * @returns {Promise.<HeightmapTerrainData>|undefined} A promise for upsampled heightmap terrain data for the descendant tile,
  23812. * or undefined if too many asynchronous upsample operations are in progress and the request has been
  23813. * deferred.
  23814. */
  23815. HeightmapTerrainData.prototype.upsample = function(tilingScheme, thisX, thisY, thisLevel, descendantX, descendantY, descendantLevel) {
  23816. if (!defined(tilingScheme)) {
  23817. throw new DeveloperError('tilingScheme is required.');
  23818. }
  23819. if (!defined(thisX)) {
  23820. throw new DeveloperError('thisX is required.');
  23821. }
  23822. if (!defined(thisY)) {
  23823. throw new DeveloperError('thisY is required.');
  23824. }
  23825. if (!defined(thisLevel)) {
  23826. throw new DeveloperError('thisLevel is required.');
  23827. }
  23828. if (!defined(descendantX)) {
  23829. throw new DeveloperError('descendantX is required.');
  23830. }
  23831. if (!defined(descendantY)) {
  23832. throw new DeveloperError('descendantY is required.');
  23833. }
  23834. if (!defined(descendantLevel)) {
  23835. throw new DeveloperError('descendantLevel is required.');
  23836. }
  23837. var levelDifference = descendantLevel - thisLevel;
  23838. if (levelDifference > 1) {
  23839. throw new DeveloperError('Upsampling through more than one level at a time is not currently supported.');
  23840. }
  23841. var width = this._width;
  23842. var height = this._height;
  23843. var structure = this._structure;
  23844. var skirtHeight = this._skirtHeight;
  23845. var stride = structure.stride;
  23846. var heights = new this._bufferType(width * height * stride);
  23847. var meshData = this._mesh;
  23848. if (!defined(meshData)) {
  23849. return undefined;
  23850. }
  23851. var buffer = meshData.vertices;
  23852. var encoding = meshData.encoding;
  23853. // PERFORMANCE_IDEA: don't recompute these rectangles - the caller already knows them.
  23854. var sourceRectangle = tilingScheme.tileXYToRectangle(thisX, thisY, thisLevel);
  23855. var destinationRectangle = tilingScheme.tileXYToRectangle(descendantX, descendantY, descendantLevel);
  23856. var heightOffset = structure.heightOffset;
  23857. var heightScale = structure.heightScale;
  23858. var exaggeration = meshData.exaggeration;
  23859. var elementsPerHeight = structure.elementsPerHeight;
  23860. var elementMultiplier = structure.elementMultiplier;
  23861. var isBigEndian = structure.isBigEndian;
  23862. var divisor = Math.pow(elementMultiplier, elementsPerHeight - 1);
  23863. for (var j = 0; j < height; ++j) {
  23864. var latitude = CesiumMath.lerp(destinationRectangle.north, destinationRectangle.south, j / (height - 1));
  23865. for (var i = 0; i < width; ++i) {
  23866. var longitude = CesiumMath.lerp(destinationRectangle.west, destinationRectangle.east, i / (width - 1));
  23867. var heightSample = interpolateMeshHeight(buffer, encoding, heightOffset, heightScale, skirtHeight, sourceRectangle, width, height, longitude, latitude, exaggeration);
  23868. // Use conditionals here instead of Math.min and Math.max so that an undefined
  23869. // lowestEncodedHeight or highestEncodedHeight has no effect.
  23870. heightSample = heightSample < structure.lowestEncodedHeight ? structure.lowestEncodedHeight : heightSample;
  23871. heightSample = heightSample > structure.highestEncodedHeight ? structure.highestEncodedHeight : heightSample;
  23872. setHeight(heights, elementsPerHeight, elementMultiplier, divisor, stride, isBigEndian, j * width + i, heightSample);
  23873. }
  23874. }
  23875. return new HeightmapTerrainData({
  23876. buffer : heights,
  23877. width : width,
  23878. height : height,
  23879. childTileMask : 0,
  23880. structure : this._structure,
  23881. createdByUpsampling : true
  23882. });
  23883. };
  23884. /**
  23885. * Determines if a given child tile is available, based on the
  23886. * {@link HeightmapTerrainData.childTileMask}. The given child tile coordinates are assumed
  23887. * to be one of the four children of this tile. If non-child tile coordinates are
  23888. * given, the availability of the southeast child tile is returned.
  23889. *
  23890. * @param {Number} thisX The tile X coordinate of this (the parent) tile.
  23891. * @param {Number} thisY The tile Y coordinate of this (the parent) tile.
  23892. * @param {Number} childX The tile X coordinate of the child tile to check for availability.
  23893. * @param {Number} childY The tile Y coordinate of the child tile to check for availability.
  23894. * @returns {Boolean} True if the child tile is available; otherwise, false.
  23895. */
  23896. HeightmapTerrainData.prototype.isChildAvailable = function(thisX, thisY, childX, childY) {
  23897. if (!defined(thisX)) {
  23898. throw new DeveloperError('thisX is required.');
  23899. }
  23900. if (!defined(thisY)) {
  23901. throw new DeveloperError('thisY is required.');
  23902. }
  23903. if (!defined(childX)) {
  23904. throw new DeveloperError('childX is required.');
  23905. }
  23906. if (!defined(childY)) {
  23907. throw new DeveloperError('childY is required.');
  23908. }
  23909. var bitNumber = 2; // northwest child
  23910. if (childX !== thisX * 2) {
  23911. ++bitNumber; // east child
  23912. }
  23913. if (childY !== thisY * 2) {
  23914. bitNumber -= 2; // south child
  23915. }
  23916. return (this._childTileMask & (1 << bitNumber)) !== 0;
  23917. };
  23918. /**
  23919. * Gets a value indicating whether or not this terrain data was created by upsampling lower resolution
  23920. * terrain data. If this value is false, the data was obtained from some other source, such
  23921. * as by downloading it from a remote server. This method should return true for instances
  23922. * returned from a call to {@link HeightmapTerrainData#upsample}.
  23923. *
  23924. * @returns {Boolean} True if this instance was created by upsampling; otherwise, false.
  23925. */
  23926. HeightmapTerrainData.prototype.wasCreatedByUpsampling = function() {
  23927. return this._createdByUpsampling;
  23928. };
  23929. function interpolateHeight(sourceHeights, elementsPerHeight, elementMultiplier, stride, isBigEndian, sourceRectangle, width, height, longitude, latitude) {
  23930. var fromWest = (longitude - sourceRectangle.west) * (width - 1) / (sourceRectangle.east - sourceRectangle.west);
  23931. var fromSouth = (latitude - sourceRectangle.south) * (height - 1) / (sourceRectangle.north - sourceRectangle.south);
  23932. var westInteger = fromWest | 0;
  23933. var eastInteger = westInteger + 1;
  23934. if (eastInteger >= width) {
  23935. eastInteger = width - 1;
  23936. westInteger = width - 2;
  23937. }
  23938. var southInteger = fromSouth | 0;
  23939. var northInteger = southInteger + 1;
  23940. if (northInteger >= height) {
  23941. northInteger = height - 1;
  23942. southInteger = height - 2;
  23943. }
  23944. var dx = fromWest - westInteger;
  23945. var dy = fromSouth - southInteger;
  23946. southInteger = height - 1 - southInteger;
  23947. northInteger = height - 1 - northInteger;
  23948. var southwestHeight = getHeight(sourceHeights, elementsPerHeight, elementMultiplier, stride, isBigEndian, southInteger * width + westInteger);
  23949. var southeastHeight = getHeight(sourceHeights, elementsPerHeight, elementMultiplier, stride, isBigEndian, southInteger * width + eastInteger);
  23950. var northwestHeight = getHeight(sourceHeights, elementsPerHeight, elementMultiplier, stride, isBigEndian, northInteger * width + westInteger);
  23951. var northeastHeight = getHeight(sourceHeights, elementsPerHeight, elementMultiplier, stride, isBigEndian, northInteger * width + eastInteger);
  23952. return triangleInterpolateHeight(dx, dy, southwestHeight, southeastHeight, northwestHeight, northeastHeight);
  23953. }
  23954. function interpolateMeshHeight(buffer, encoding, heightOffset, heightScale, skirtHeight, sourceRectangle, width, height, longitude, latitude, exaggeration) {
  23955. // returns a height encoded according to the structure's heightScale and heightOffset.
  23956. var fromWest = (longitude - sourceRectangle.west) * (width - 1) / (sourceRectangle.east - sourceRectangle.west);
  23957. var fromSouth = (latitude - sourceRectangle.south) * (height - 1) / (sourceRectangle.north - sourceRectangle.south);
  23958. if (skirtHeight > 0) {
  23959. fromWest += 1.0;
  23960. fromSouth += 1.0;
  23961. width += 2;
  23962. height += 2;
  23963. }
  23964. var widthEdge = (skirtHeight > 0) ? width - 1 : width;
  23965. var westInteger = fromWest | 0;
  23966. var eastInteger = westInteger + 1;
  23967. if (eastInteger >= widthEdge) {
  23968. eastInteger = width - 1;
  23969. westInteger = width - 2;
  23970. }
  23971. var heightEdge = (skirtHeight > 0) ? height - 1 : height;
  23972. var southInteger = fromSouth | 0;
  23973. var northInteger = southInteger + 1;
  23974. if (northInteger >= heightEdge) {
  23975. northInteger = height - 1;
  23976. southInteger = height - 2;
  23977. }
  23978. var dx = fromWest - westInteger;
  23979. var dy = fromSouth - southInteger;
  23980. southInteger = height - 1 - southInteger;
  23981. northInteger = height - 1 - northInteger;
  23982. var southwestHeight = (encoding.decodeHeight(buffer, southInteger * width + westInteger) / exaggeration - heightOffset) / heightScale;
  23983. var southeastHeight = (encoding.decodeHeight(buffer, southInteger * width + eastInteger) / exaggeration - heightOffset) / heightScale;
  23984. var northwestHeight = (encoding.decodeHeight(buffer, northInteger * width + westInteger) / exaggeration - heightOffset) / heightScale;
  23985. var northeastHeight = (encoding.decodeHeight(buffer, northInteger * width + eastInteger) / exaggeration - heightOffset) / heightScale;
  23986. return triangleInterpolateHeight(dx, dy, southwestHeight, southeastHeight, northwestHeight, northeastHeight);
  23987. }
  23988. function triangleInterpolateHeight(dX, dY, southwestHeight, southeastHeight, northwestHeight, northeastHeight) {
  23989. // The HeightmapTessellator bisects the quad from southwest to northeast.
  23990. if (dY < dX) {
  23991. // Lower right triangle
  23992. return southwestHeight + (dX * (southeastHeight - southwestHeight)) + (dY * (northeastHeight - southeastHeight));
  23993. }
  23994. // Upper left triangle
  23995. return southwestHeight + (dX * (northeastHeight - northwestHeight)) + (dY * (northwestHeight - southwestHeight));
  23996. }
  23997. function getHeight(heights, elementsPerHeight, elementMultiplier, stride, isBigEndian, index) {
  23998. index *= stride;
  23999. var height = 0;
  24000. var i;
  24001. if (isBigEndian) {
  24002. for (i = 0; i < elementsPerHeight; ++i) {
  24003. height = (height * elementMultiplier) + heights[index + i];
  24004. }
  24005. } else {
  24006. for (i = elementsPerHeight - 1; i >= 0; --i) {
  24007. height = (height * elementMultiplier) + heights[index + i];
  24008. }
  24009. }
  24010. return height;
  24011. }
  24012. function setHeight(heights, elementsPerHeight, elementMultiplier, divisor, stride, isBigEndian, index, height) {
  24013. index *= stride;
  24014. var i;
  24015. if (isBigEndian) {
  24016. for (i = 0; i < elementsPerHeight - 1; ++i) {
  24017. heights[index + i] = (height / divisor) | 0;
  24018. height -= heights[index + i] * divisor;
  24019. divisor /= elementMultiplier;
  24020. }
  24021. } else {
  24022. for (i = elementsPerHeight - 1; i > 0; --i) {
  24023. heights[index + i] = (height / divisor) | 0;
  24024. height -= heights[index + i] * divisor;
  24025. divisor /= elementMultiplier;
  24026. }
  24027. }
  24028. heights[index + i] = height;
  24029. }
  24030. return HeightmapTerrainData;
  24031. });
  24032. /*global define*/
  24033. define('Core/loadImage',[
  24034. '../ThirdParty/when',
  24035. './defaultValue',
  24036. './defined',
  24037. './DeveloperError',
  24038. './isCrossOriginUrl',
  24039. './TrustedServers'
  24040. ], function(
  24041. when,
  24042. defaultValue,
  24043. defined,
  24044. DeveloperError,
  24045. isCrossOriginUrl,
  24046. TrustedServers) {
  24047. 'use strict';
  24048. var dataUriRegex = /^data:/;
  24049. /**
  24050. * Asynchronously loads the given image URL. Returns a promise that will resolve to
  24051. * an {@link Image} once loaded, or reject if the image failed to load.
  24052. *
  24053. * @exports loadImage
  24054. *
  24055. * @param {String|Promise.<String>} url The source of the image, or a promise for the URL.
  24056. * @param {Boolean} [allowCrossOrigin=true] Whether to request the image using Cross-Origin
  24057. * Resource Sharing (CORS). CORS is only actually used if the image URL is actually cross-origin.
  24058. * Data URIs are never requested using CORS.
  24059. * @returns {Promise.<Image>} a promise that will resolve to the requested data when loaded.
  24060. *
  24061. *
  24062. * @example
  24063. * // load a single image asynchronously
  24064. * Cesium.loadImage('some/image/url.png').then(function(image) {
  24065. * // use the loaded image
  24066. * }).otherwise(function(error) {
  24067. * // an error occurred
  24068. * });
  24069. *
  24070. * // load several images in parallel
  24071. * when.all([loadImage('image1.png'), loadImage('image2.png')]).then(function(images) {
  24072. * // images is an array containing all the loaded images
  24073. * });
  24074. *
  24075. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  24076. * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
  24077. */
  24078. function loadImage(url, allowCrossOrigin) {
  24079. if (!defined(url)) {
  24080. throw new DeveloperError('url is required.');
  24081. }
  24082. allowCrossOrigin = defaultValue(allowCrossOrigin, true);
  24083. return when(url, function(url) {
  24084. var crossOrigin;
  24085. // data URIs can't have allowCrossOrigin set.
  24086. if (dataUriRegex.test(url) || !allowCrossOrigin) {
  24087. crossOrigin = false;
  24088. } else {
  24089. crossOrigin = isCrossOriginUrl(url);
  24090. }
  24091. var deferred = when.defer();
  24092. loadImage.createImage(url, crossOrigin, deferred);
  24093. return deferred.promise;
  24094. });
  24095. }
  24096. // This is broken out into a separate function so that it can be mocked for testing purposes.
  24097. loadImage.createImage = function(url, crossOrigin, deferred) {
  24098. var image = new Image();
  24099. image.onload = function() {
  24100. deferred.resolve(image);
  24101. };
  24102. image.onerror = function(e) {
  24103. deferred.reject(e);
  24104. };
  24105. if (crossOrigin) {
  24106. if (TrustedServers.contains(url)) {
  24107. image.crossOrigin = 'use-credentials';
  24108. } else {
  24109. image.crossOrigin = '';
  24110. }
  24111. }
  24112. image.src = url;
  24113. };
  24114. loadImage.defaultCreateImage = loadImage.createImage;
  24115. return loadImage;
  24116. });
  24117. /*global define*/
  24118. define('Core/throttleRequestByServer',[
  24119. '../ThirdParty/Uri',
  24120. '../ThirdParty/when',
  24121. './defaultValue'
  24122. ], function(
  24123. Uri,
  24124. when,
  24125. defaultValue) {
  24126. 'use strict';
  24127. var activeRequests = {};
  24128. var pageUri = typeof document !== 'undefined' ? new Uri(document.location.href) : new Uri();
  24129. function getServer(url) {
  24130. var uri = new Uri(url).resolve(pageUri);
  24131. uri.normalize();
  24132. var server = uri.authority;
  24133. if (!/:/.test(server)) {
  24134. server = server + ':' + (uri.scheme === 'https' ? '443' : '80');
  24135. }
  24136. return server;
  24137. }
  24138. /**
  24139. * Because browsers throttle the number of parallel requests allowed to each server,
  24140. * this function tracks the number of active requests in progress to each server, and
  24141. * returns undefined immediately if the request would exceed the maximum, allowing
  24142. * the caller to retry later, instead of queueing indefinitely under the browser's control.
  24143. *
  24144. * @exports throttleRequestByServer
  24145. *
  24146. * @param {String} url The URL to request.
  24147. * @param {throttleRequestByServer~RequestFunction} requestFunction The actual function that
  24148. * makes the request.
  24149. * @returns {Promise.<Object>|undefined} Either undefined, meaning the request would exceed the maximum number of
  24150. * parallel requests, or a Promise for the requested data.
  24151. *
  24152. *
  24153. * @example
  24154. * // throttle requests for an image
  24155. * var url = 'http://madeupserver.example.com/myImage.png';
  24156. * function requestFunction(url) {
  24157. * // in this simple example, loadImage could be used directly as requestFunction.
  24158. * return Cesium.loadImage(url);
  24159. * };
  24160. * var promise = Cesium.throttleRequestByServer(url, requestFunction);
  24161. * if (!Cesium.defined(promise)) {
  24162. * // too many active requests in progress, try again later.
  24163. * } else {
  24164. * promise.then(function(image) {
  24165. * // handle loaded image
  24166. * });
  24167. * }
  24168. *
  24169. * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
  24170. */
  24171. function throttleRequestByServer(url, requestFunction) {
  24172. var server = getServer(url);
  24173. var activeRequestsForServer = defaultValue(activeRequests[server], 0);
  24174. if (activeRequestsForServer >= throttleRequestByServer.maximumRequestsPerServer) {
  24175. return undefined;
  24176. }
  24177. activeRequests[server] = activeRequestsForServer + 1;
  24178. return when(requestFunction(url), function(result) {
  24179. activeRequests[server]--;
  24180. return result;
  24181. }).otherwise(function(error) {
  24182. activeRequests[server]--;
  24183. return when.reject(error);
  24184. });
  24185. }
  24186. /**
  24187. * Specifies the maximum number of requests that can be simultaneously open to a single server. If this value is higher than
  24188. * the number of requests per server actually allowed by the web browser, Cesium's ability to prioritize requests will be adversely
  24189. * affected.
  24190. * @type {Number}
  24191. * @default 6
  24192. */
  24193. throttleRequestByServer.maximumRequestsPerServer = 6;
  24194. /**
  24195. * A function that will make a request if there are available slots to the server.
  24196. * @callback throttleRequestByServer~RequestFunction
  24197. *
  24198. * @param {String} url The url to request.
  24199. * @returns {Promise.<Object>} A promise for the requested data.
  24200. */
  24201. return throttleRequestByServer;
  24202. });
  24203. /*global define*/
  24204. define('Core/ArcGisImageServerTerrainProvider',[
  24205. '../ThirdParty/when',
  24206. './Credit',
  24207. './defaultValue',
  24208. './defined',
  24209. './defineProperties',
  24210. './DeveloperError',
  24211. './Ellipsoid',
  24212. './Event',
  24213. './GeographicTilingScheme',
  24214. './getImagePixels',
  24215. './HeightmapTerrainData',
  24216. './loadImage',
  24217. './Math',
  24218. './TerrainProvider',
  24219. './throttleRequestByServer'
  24220. ], function(
  24221. when,
  24222. Credit,
  24223. defaultValue,
  24224. defined,
  24225. defineProperties,
  24226. DeveloperError,
  24227. Ellipsoid,
  24228. Event,
  24229. GeographicTilingScheme,
  24230. getImagePixels,
  24231. HeightmapTerrainData,
  24232. loadImage,
  24233. CesiumMath,
  24234. TerrainProvider,
  24235. throttleRequestByServer) {
  24236. 'use strict';
  24237. /**
  24238. * A {@link TerrainProvider} that produces terrain geometry by tessellating height maps
  24239. * retrieved from an ArcGIS ImageServer.
  24240. *
  24241. * @alias ArcGisImageServerTerrainProvider
  24242. * @constructor
  24243. *
  24244. * @param {Object} options Object with the following properties:
  24245. * @param {String} options.url The URL of the ArcGIS ImageServer service.
  24246. * @param {String} [options.token] The authorization token to use to connect to the service.
  24247. * @param {Object} [options.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL, if needed.
  24248. * @param {TilingScheme} [options.tilingScheme] The tiling scheme specifying how the terrain
  24249. * is broken into tiles. If this parameter is not provided, a {@link GeographicTilingScheme}
  24250. * is used.
  24251. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If the tilingScheme is specified,
  24252. * this parameter is ignored and the tiling scheme's ellipsoid is used instead.
  24253. * If neither parameter is specified, the WGS84 ellipsoid is used.
  24254. * @param {Credit|String} [options.credit] The credit, which will is displayed on the canvas.
  24255. *
  24256. *
  24257. * @example
  24258. * var terrainProvider = new Cesium.ArcGisImageServerTerrainProvider({
  24259. * url : 'https://elevation.arcgisonline.com/ArcGIS/rest/services/WorldElevation/DTMEllipsoidal/ImageServer',
  24260. * token : 'KED1aF_I4UzXOHy3BnhwyBHU4l5oY6rO6walkmHoYqGp4XyIWUd5YZUC1ZrLAzvV40pR6gBXQayh0eFA8m6vPg..',
  24261. * proxy : new Cesium.DefaultProxy('/terrain/')
  24262. * });
  24263. * viewer.terrainProvider = terrainProvider;
  24264. *
  24265. * @see TerrainProvider
  24266. */
  24267. function ArcGisImageServerTerrainProvider(options) {
  24268. if (!defined(options) || !defined(options.url)) {
  24269. throw new DeveloperError('options.url is required.');
  24270. }
  24271. this._url = options.url;
  24272. this._token = options.token;
  24273. this._tilingScheme = options.tilingScheme;
  24274. if (!defined(this._tilingScheme)) {
  24275. this._tilingScheme = new GeographicTilingScheme({
  24276. ellipsoid : defaultValue(options.ellipsoid, Ellipsoid.WGS84)
  24277. });
  24278. }
  24279. this._heightmapWidth = 65;
  24280. this._levelZeroMaximumGeometricError = TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(this._tilingScheme.ellipsoid, this._heightmapWidth, this._tilingScheme.getNumberOfXTilesAtLevel(0));
  24281. this._proxy = options.proxy;
  24282. this._terrainDataStructure = {
  24283. heightScale : 1.0 / 1000.0,
  24284. heightOffset : -1000.0,
  24285. elementsPerHeight : 3,
  24286. stride : 4,
  24287. elementMultiplier : 256.0,
  24288. isBigEndian : true,
  24289. lowestEncodedHeight : 0,
  24290. highestEncodedHeight : 256 * 256 * 256 - 1
  24291. };
  24292. this._errorEvent = new Event();
  24293. var credit = options.credit;
  24294. if (typeof credit === 'string') {
  24295. credit = new Credit(credit);
  24296. }
  24297. this._credit = credit;
  24298. this._readyPromise = when.resolve(true);
  24299. }
  24300. defineProperties(ArcGisImageServerTerrainProvider.prototype, {
  24301. /**
  24302. * Gets an event that is raised when the terrain provider encounters an asynchronous error. By subscribing
  24303. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  24304. * are passed an instance of {@link TileProviderError}.
  24305. * @memberof ArcGisImageServerTerrainProvider.prototype
  24306. * @type {Event}
  24307. */
  24308. errorEvent : {
  24309. get : function() {
  24310. return this._errorEvent;
  24311. }
  24312. },
  24313. /**
  24314. * Gets the credit to display when this terrain provider is active. Typically this is used to credit
  24315. * the source of the terrain. This function should not be called before {@link ArcGisImageServerTerrainProvider#ready} returns true.
  24316. * @memberof ArcGisImageServerTerrainProvider.prototype
  24317. * @type {Credit}
  24318. */
  24319. credit : {
  24320. get : function() {
  24321. return this._credit;
  24322. }
  24323. },
  24324. /**
  24325. * Gets the tiling scheme used by this provider. This function should
  24326. * not be called before {@link ArcGisImageServerTerrainProvider#ready} returns true.
  24327. * @memberof ArcGisImageServerTerrainProvider.prototype
  24328. * @type {GeographicTilingScheme}
  24329. */
  24330. tilingScheme : {
  24331. get : function() {
  24332. return this._tilingScheme;
  24333. }
  24334. },
  24335. /**
  24336. * Gets a value indicating whether or not the provider is ready for use.
  24337. * @memberof ArcGisImageServerTerrainProvider.prototype
  24338. * @type {Boolean}
  24339. */
  24340. ready : {
  24341. get : function() {
  24342. return true;
  24343. }
  24344. },
  24345. /**
  24346. * Gets a promise that resolves to true when the provider is ready for use.
  24347. * @memberof ArcGisImageServerTerrainProvider.prototype
  24348. * @type {Promise.<Boolean>}
  24349. * @readonly
  24350. */
  24351. readyPromise : {
  24352. get : function() {
  24353. return this._readyPromise;
  24354. }
  24355. },
  24356. /**
  24357. * Gets a value indicating whether or not the provider includes a water mask. The water mask
  24358. * indicates which areas of the globe are water rather than land, so they can be rendered
  24359. * as a reflective surface with animated waves. This function should not be
  24360. * called before {@link ArcGisImageServerTerrainProvider#ready} returns true.
  24361. * @memberof ArcGisImageServerTerrainProvider.prototype
  24362. * @type {Boolean}
  24363. */
  24364. hasWaterMask : {
  24365. get : function() {
  24366. return false;
  24367. }
  24368. },
  24369. /**
  24370. * Gets a value indicating whether or not the requested tiles include vertex normals.
  24371. * This function should not be called before {@link ArcGisImageServerTerrainProvider#ready} returns true.
  24372. * @memberof ArcGisImageServerTerrainProvider.prototype
  24373. * @type {Boolean}
  24374. */
  24375. hasVertexNormals : {
  24376. get : function() {
  24377. return false;
  24378. }
  24379. }
  24380. });
  24381. /**
  24382. * Requests the geometry for a given tile. This function should not be called before
  24383. * {@link ArcGisImageServerTerrainProvider#ready} returns true. The result includes terrain
  24384. * data and indicates that all child tiles are available.
  24385. *
  24386. * @param {Number} x The X coordinate of the tile for which to request geometry.
  24387. * @param {Number} y The Y coordinate of the tile for which to request geometry.
  24388. * @param {Number} level The level of the tile for which to request geometry.
  24389. * @returns {Promise.<TerrainData>|undefined} A promise for the requested geometry. If this method
  24390. * returns undefined instead of a promise, it is an indication that too many requests are already
  24391. * pending and the request will be retried later.
  24392. */
  24393. ArcGisImageServerTerrainProvider.prototype.requestTileGeometry = function(x, y, level) {
  24394. var rectangle = this._tilingScheme.tileXYToRectangle(x, y, level);
  24395. // Each pixel in the heightmap represents the height at the center of that
  24396. // pixel. So expand the rectangle by half a sample spacing in each direction
  24397. // so that the first height is on the edge of the rectangle we need rather than
  24398. // half a sample spacing into the rectangle.
  24399. var xSpacing = (rectangle.east - rectangle.west) / (this._heightmapWidth - 1);
  24400. var ySpacing = (rectangle.north - rectangle.south) / (this._heightmapWidth - 1);
  24401. rectangle.west -= xSpacing * 0.5;
  24402. rectangle.east += xSpacing * 0.5;
  24403. rectangle.south -= ySpacing * 0.5;
  24404. rectangle.north += ySpacing * 0.5;
  24405. var bbox = CesiumMath.toDegrees(rectangle.west) + '%2C' + CesiumMath.toDegrees(rectangle.south) + '%2C' + CesiumMath.toDegrees(rectangle.east) + '%2C' + CesiumMath.toDegrees(rectangle.north);
  24406. var url = this._url + '/exportImage?interpolation=RSP_BilinearInterpolation&format=tiff&f=image&size=' + this._heightmapWidth + '%2C' + this._heightmapWidth + '&bboxSR=4326&imageSR=4326&bbox=' + bbox;
  24407. if (this._token) {
  24408. url += '&token=' + this._token;
  24409. }
  24410. var proxy = this._proxy;
  24411. if (defined(proxy)) {
  24412. url = proxy.getURL(url);
  24413. }
  24414. var promise = throttleRequestByServer(url, loadImage);
  24415. if (!defined(promise)) {
  24416. return undefined;
  24417. }
  24418. var that = this;
  24419. return when(promise, function(image) {
  24420. return new HeightmapTerrainData({
  24421. buffer : getImagePixels(image),
  24422. width : that._heightmapWidth,
  24423. height : that._heightmapWidth,
  24424. childTileMask : 15, // all children present
  24425. structure : that._terrainDataStructure
  24426. });
  24427. });
  24428. };
  24429. /**
  24430. * Gets the maximum geometric error allowed in a tile at a given level.
  24431. *
  24432. * @param {Number} level The tile level for which to get the maximum geometric error.
  24433. * @returns {Number} The maximum geometric error.
  24434. */
  24435. ArcGisImageServerTerrainProvider.prototype.getLevelMaximumGeometricError = function(level) {
  24436. return this._levelZeroMaximumGeometricError / (1 << level);
  24437. };
  24438. /**
  24439. * Determines whether data for a tile is available to be loaded.
  24440. *
  24441. * @param {Number} x The X coordinate of the tile for which to request geometry.
  24442. * @param {Number} y The Y coordinate of the tile for which to request geometry.
  24443. * @param {Number} level The level of the tile for which to request geometry.
  24444. * @returns {Boolean} Undefined if not supported, otherwise true or false.
  24445. */
  24446. ArcGisImageServerTerrainProvider.prototype.getTileDataAvailable = function(x, y, level) {
  24447. return undefined;
  24448. };
  24449. return ArcGisImageServerTerrainProvider;
  24450. });
  24451. /*global define*/
  24452. define('Core/arrayRemoveDuplicates',[
  24453. './defaultValue',
  24454. './defined',
  24455. './DeveloperError',
  24456. './Math'
  24457. ], function(
  24458. defaultValue,
  24459. defined,
  24460. DeveloperError,
  24461. CesiumMath) {
  24462. 'use strict';
  24463. var removeDuplicatesEpsilon = CesiumMath.EPSILON10;
  24464. /**
  24465. * Removes adjacent duplicate values in an array of values.
  24466. *
  24467. * @param {Object[]} [values] The array of values.
  24468. * @param {Function} equalsEpsilon Function to compare values with an epsilon. Boolean equalsEpsilon(left, right, epsilon).
  24469. * @param {Boolean} [wrapAround=false] Compare the last value in the array against the first value.
  24470. * @returns {Object[]|undefined} A new array of values with no adjacent duplicate values or the input array if no duplicates were found.
  24471. *
  24472. * @example
  24473. * // Returns [(1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0), (1.0, 1.0, 1.0)]
  24474. * var values = [
  24475. * new Cesium.Cartesian3(1.0, 1.0, 1.0),
  24476. * new Cesium.Cartesian3(1.0, 1.0, 1.0),
  24477. * new Cesium.Cartesian3(2.0, 2.0, 2.0),
  24478. * new Cesium.Cartesian3(3.0, 3.0, 3.0),
  24479. * new Cesium.Cartesian3(1.0, 1.0, 1.0)];
  24480. * var nonDuplicatevalues = Cesium.PolylinePipeline.removeDuplicates(values, Cartesian3.equalsEpsilon);
  24481. *
  24482. * @example
  24483. * // Returns [(1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0)]
  24484. * var values = [
  24485. * new Cesium.Cartesian3(1.0, 1.0, 1.0),
  24486. * new Cesium.Cartesian3(1.0, 1.0, 1.0),
  24487. * new Cesium.Cartesian3(2.0, 2.0, 2.0),
  24488. * new Cesium.Cartesian3(3.0, 3.0, 3.0),
  24489. * new Cesium.Cartesian3(1.0, 1.0, 1.0)];
  24490. * var nonDuplicatevalues = Cesium.PolylinePipeline.removeDuplicates(values, Cartesian3.equalsEpsilon, true);
  24491. *
  24492. * @private
  24493. */
  24494. function arrayRemoveDuplicates(values, equalsEpsilon, wrapAround) {
  24495. if (!defined(equalsEpsilon)) {
  24496. throw new DeveloperError('equalsEpsilon is required.');
  24497. }
  24498. if (!defined(values)) {
  24499. return undefined;
  24500. }
  24501. wrapAround = defaultValue(wrapAround, false);
  24502. var length = values.length;
  24503. if (length < 2) {
  24504. return values;
  24505. }
  24506. var i;
  24507. var v0;
  24508. var v1;
  24509. for (i = 1; i < length; ++i) {
  24510. v0 = values[i - 1];
  24511. v1 = values[i];
  24512. if (equalsEpsilon(v0, v1, removeDuplicatesEpsilon)) {
  24513. break;
  24514. }
  24515. }
  24516. if (i === length) {
  24517. if (wrapAround && equalsEpsilon(values[0], values[values.length - 1], removeDuplicatesEpsilon)) {
  24518. return values.slice(1);
  24519. }
  24520. return values;
  24521. }
  24522. var cleanedvalues = values.slice(0, i);
  24523. for (; i < length; ++i) {
  24524. // v0 is set by either the previous loop, or the previous clean point.
  24525. v1 = values[i];
  24526. if (!equalsEpsilon(v0, v1, removeDuplicatesEpsilon)) {
  24527. cleanedvalues.push(v1);
  24528. v0 = v1;
  24529. }
  24530. }
  24531. if (wrapAround && cleanedvalues.length > 1 && equalsEpsilon(cleanedvalues[0], cleanedvalues[cleanedvalues.length - 1], removeDuplicatesEpsilon)) {
  24532. cleanedvalues.shift();
  24533. }
  24534. return cleanedvalues;
  24535. }
  24536. return arrayRemoveDuplicates;
  24537. });
  24538. /*global define*/
  24539. define('Core/AssociativeArray',[
  24540. './defined',
  24541. './defineProperties',
  24542. './DeveloperError'
  24543. ], function(
  24544. defined,
  24545. defineProperties,
  24546. DeveloperError) {
  24547. 'use strict';
  24548. /**
  24549. * A collection of key-value pairs that is stored as a hash for easy
  24550. * lookup but also provides an array for fast iteration.
  24551. * @alias AssociativeArray
  24552. * @constructor
  24553. */
  24554. function AssociativeArray() {
  24555. this._array = [];
  24556. this._hash = {};
  24557. }
  24558. defineProperties(AssociativeArray.prototype, {
  24559. /**
  24560. * Gets the number of items in the collection.
  24561. * @memberof AssociativeArray.prototype
  24562. *
  24563. * @type {Number}
  24564. */
  24565. length : {
  24566. get : function() {
  24567. return this._array.length;
  24568. }
  24569. },
  24570. /**
  24571. * Gets an unordered array of all values in the collection.
  24572. * This is a live array that will automatically reflect the values in the collection,
  24573. * it should not be modified directly.
  24574. * @memberof AssociativeArray.prototype
  24575. *
  24576. * @type {Array}
  24577. */
  24578. values : {
  24579. get : function() {
  24580. return this._array;
  24581. }
  24582. }
  24583. });
  24584. /**
  24585. * Determines if the provided key is in the array.
  24586. *
  24587. * @param {String|Number} key The key to check.
  24588. * @returns {Boolean} <code>true</code> if the key is in the array, <code>false</code> otherwise.
  24589. */
  24590. AssociativeArray.prototype.contains = function(key) {
  24591. if (typeof key !== 'string' && typeof key !== 'number') {
  24592. throw new DeveloperError('key is required to be a string or number.');
  24593. }
  24594. return defined(this._hash[key]);
  24595. };
  24596. /**
  24597. * Associates the provided key with the provided value. If the key already
  24598. * exists, it is overwritten with the new value.
  24599. *
  24600. * @param {String|Number} key A unique identifier.
  24601. * @param {Object} value The value to associate with the provided key.
  24602. */
  24603. AssociativeArray.prototype.set = function(key, value) {
  24604. if (typeof key !== 'string' && typeof key !== 'number') {
  24605. throw new DeveloperError('key is required to be a string or number.');
  24606. }
  24607. var oldValue = this._hash[key];
  24608. if (value !== oldValue) {
  24609. this.remove(key);
  24610. this._hash[key] = value;
  24611. this._array.push(value);
  24612. }
  24613. };
  24614. /**
  24615. * Retrieves the value associated with the provided key.
  24616. *
  24617. * @param {String|Number} key The key whose value is to be retrieved.
  24618. * @returns {Object} The associated value, or undefined if the key does not exist in the collection.
  24619. */
  24620. AssociativeArray.prototype.get = function(key) {
  24621. if (typeof key !== 'string' && typeof key !== 'number') {
  24622. throw new DeveloperError('key is required to be a string or number.');
  24623. }
  24624. return this._hash[key];
  24625. };
  24626. /**
  24627. * Removes a key-value pair from the collection.
  24628. *
  24629. * @param {String|Number} key The key to be removed.
  24630. * @returns {Boolean} True if it was removed, false if the key was not in the collection.
  24631. */
  24632. AssociativeArray.prototype.remove = function(key) {
  24633. if (defined(key) && typeof key !== 'string' && typeof key !== 'number') {
  24634. throw new DeveloperError('key is required to be a string or number.');
  24635. }
  24636. var value = this._hash[key];
  24637. var hasValue = defined(value);
  24638. if (hasValue) {
  24639. var array = this._array;
  24640. array.splice(array.indexOf(value), 1);
  24641. delete this._hash[key];
  24642. }
  24643. return hasValue;
  24644. };
  24645. /**
  24646. * Clears the collection.
  24647. */
  24648. AssociativeArray.prototype.removeAll = function() {
  24649. var array = this._array;
  24650. if (array.length > 0) {
  24651. this._hash = {};
  24652. array.length = 0;
  24653. }
  24654. };
  24655. return AssociativeArray;
  24656. });
  24657. /*global define*/
  24658. define('Core/barycentricCoordinates',[
  24659. './Cartesian2',
  24660. './Cartesian3',
  24661. './defined',
  24662. './DeveloperError'
  24663. ], function(
  24664. Cartesian2,
  24665. Cartesian3,
  24666. defined,
  24667. DeveloperError) {
  24668. 'use strict';
  24669. var scratchCartesian1 = new Cartesian3();
  24670. var scratchCartesian2 = new Cartesian3();
  24671. var scratchCartesian3 = new Cartesian3();
  24672. /**
  24673. * Computes the barycentric coordinates for a point with respect to a triangle.
  24674. *
  24675. * @exports barycentricCoordinates
  24676. *
  24677. * @param {Cartesian2|Cartesian3} point The point to test.
  24678. * @param {Cartesian2|Cartesian3} p0 The first point of the triangle, corresponding to the barycentric x-axis.
  24679. * @param {Cartesian2|Cartesian3} p1 The second point of the triangle, corresponding to the barycentric y-axis.
  24680. * @param {Cartesian2|Cartesian3} p2 The third point of the triangle, corresponding to the barycentric z-axis.
  24681. * @param {Cartesian3} [result] The object onto which to store the result.
  24682. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
  24683. *
  24684. * @example
  24685. * // Returns Cartesian3.UNIT_X
  24686. * var p = new Cesium.Cartesian3(-1.0, 0.0, 0.0);
  24687. * var b = Cesium.barycentricCoordinates(p,
  24688. * new Cesium.Cartesian3(-1.0, 0.0, 0.0),
  24689. * new Cesium.Cartesian3( 1.0, 0.0, 0.0),
  24690. * new Cesium.Cartesian3( 0.0, 1.0, 1.0));
  24691. */
  24692. function barycentricCoordinates(point, p0, p1, p2, result) {
  24693. if (!defined(point) || !defined(p0) || !defined(p1) || !defined(p2)) {
  24694. throw new DeveloperError('point, p0, p1, and p2 are required.');
  24695. }
  24696. if (!defined(result)) {
  24697. result = new Cartesian3();
  24698. }
  24699. // Implementation based on http://www.blackpawn.com/texts/pointinpoly/default.html.
  24700. var v0, v1, v2;
  24701. var dot00, dot01, dot02, dot11, dot12;
  24702. if(!defined(p0.z)) {
  24703. v0 = Cartesian2.subtract(p1, p0, scratchCartesian1);
  24704. v1 = Cartesian2.subtract(p2, p0, scratchCartesian2);
  24705. v2 = Cartesian2.subtract(point, p0, scratchCartesian3);
  24706. dot00 = Cartesian2.dot(v0, v0);
  24707. dot01 = Cartesian2.dot(v0, v1);
  24708. dot02 = Cartesian2.dot(v0, v2);
  24709. dot11 = Cartesian2.dot(v1, v1);
  24710. dot12 = Cartesian2.dot(v1, v2);
  24711. } else {
  24712. v0 = Cartesian3.subtract(p1, p0, scratchCartesian1);
  24713. v1 = Cartesian3.subtract(p2, p0, scratchCartesian2);
  24714. v2 = Cartesian3.subtract(point, p0, scratchCartesian3);
  24715. dot00 = Cartesian3.dot(v0, v0);
  24716. dot01 = Cartesian3.dot(v0, v1);
  24717. dot02 = Cartesian3.dot(v0, v2);
  24718. dot11 = Cartesian3.dot(v1, v1);
  24719. dot12 = Cartesian3.dot(v1, v2);
  24720. }
  24721. var q = 1.0 / (dot00 * dot11 - dot01 * dot01);
  24722. result.y = (dot11 * dot02 - dot01 * dot12) * q;
  24723. result.z = (dot00 * dot12 - dot01 * dot02) * q;
  24724. result.x = 1.0 - result.y - result.z;
  24725. return result;
  24726. }
  24727. return barycentricCoordinates;
  24728. });
  24729. /*global define*/
  24730. define('Core/BingMapsApi',[
  24731. './Credit',
  24732. './defined'
  24733. ], function(
  24734. Credit,
  24735. defined) {
  24736. 'use strict';
  24737. /**
  24738. * Object for setting and retrieving the default BingMaps API key.
  24739. *
  24740. * @exports BingMapsApi
  24741. */
  24742. var BingMapsApi = {
  24743. };
  24744. /**
  24745. * The default Bing Maps API key to use if one is not provided to the
  24746. * constructor of an object that uses the Bing Maps API. If this property is undefined,
  24747. * Cesium's default key is used, which is only suitable for use early in development.
  24748. * Please generate your own key by visiting
  24749. * {@link https://www.bingmapsportal.com/}
  24750. * as soon as possible and prior to deployment. When Cesium's default key is used,
  24751. * a message is printed to the console the first time the Bing Maps API is used.
  24752. *
  24753. * @type {String}
  24754. */
  24755. BingMapsApi.defaultKey = undefined;
  24756. var printedBingWarning = false;
  24757. var errorCredit;
  24758. var errorString = 'This application is using Cesium\'s default Bing Maps key. Please create a new key for the application as soon as possible and prior to deployment by visiting https://www.bingmapsportal.com/, and provide your key to Cesium by setting the Cesium.BingMapsApi.defaultKey property before constructing the CesiumWidget or any other object that uses the Bing Maps API.';
  24759. BingMapsApi.getKey = function(providedKey) {
  24760. if (defined(providedKey)) {
  24761. return providedKey;
  24762. }
  24763. if (!defined(BingMapsApi.defaultKey)) {
  24764. if (!printedBingWarning) {
  24765. console.log(errorString);
  24766. printedBingWarning = true;
  24767. }
  24768. return 'AhiQlDaPOwKbStA_3nJIdimUj4PRYkp0yHwcNpvxVlLNPRo5ZJWY5oX_h6B_dMbm';
  24769. }
  24770. return BingMapsApi.defaultKey;
  24771. };
  24772. BingMapsApi.getErrorCredit = function(providedKey) {
  24773. if (defined(providedKey) || defined(BingMapsApi.defaultKey)) {
  24774. return undefined;
  24775. }
  24776. if (!defined(errorCredit)) {
  24777. errorCredit = new Credit(errorString);
  24778. }
  24779. return errorCredit;
  24780. };
  24781. return BingMapsApi;
  24782. });
  24783. /*global define*/
  24784. define('Core/BoundingRectangle',[
  24785. './Cartesian2',
  24786. './Cartographic',
  24787. './defaultValue',
  24788. './defined',
  24789. './DeveloperError',
  24790. './GeographicProjection',
  24791. './Intersect',
  24792. './Rectangle'
  24793. ], function(
  24794. Cartesian2,
  24795. Cartographic,
  24796. defaultValue,
  24797. defined,
  24798. DeveloperError,
  24799. GeographicProjection,
  24800. Intersect,
  24801. Rectangle) {
  24802. 'use strict';
  24803. /**
  24804. * A bounding rectangle given by a corner, width and height.
  24805. * @alias BoundingRectangle
  24806. * @constructor
  24807. *
  24808. * @param {Number} [x=0.0] The x coordinate of the rectangle.
  24809. * @param {Number} [y=0.0] The y coordinate of the rectangle.
  24810. * @param {Number} [width=0.0] The width of the rectangle.
  24811. * @param {Number} [height=0.0] The height of the rectangle.
  24812. *
  24813. * @see BoundingSphere
  24814. * @see Packable
  24815. */
  24816. function BoundingRectangle(x, y, width, height) {
  24817. /**
  24818. * The x coordinate of the rectangle.
  24819. * @type {Number}
  24820. * @default 0.0
  24821. */
  24822. this.x = defaultValue(x, 0.0);
  24823. /**
  24824. * The y coordinate of the rectangle.
  24825. * @type {Number}
  24826. * @default 0.0
  24827. */
  24828. this.y = defaultValue(y, 0.0);
  24829. /**
  24830. * The width of the rectangle.
  24831. * @type {Number}
  24832. * @default 0.0
  24833. */
  24834. this.width = defaultValue(width, 0.0);
  24835. /**
  24836. * The height of the rectangle.
  24837. * @type {Number}
  24838. * @default 0.0
  24839. */
  24840. this.height = defaultValue(height, 0.0);
  24841. }
  24842. /**
  24843. * The number of elements used to pack the object into an array.
  24844. * @type {Number}
  24845. */
  24846. BoundingRectangle.packedLength = 4;
  24847. /**
  24848. * Stores the provided instance into the provided array.
  24849. *
  24850. * @param {BoundingRectangle} value The value to pack.
  24851. * @param {Number[]} array The array to pack into.
  24852. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  24853. *
  24854. * @returns {Number[]} The array that was packed into
  24855. */
  24856. BoundingRectangle.pack = function(value, array, startingIndex) {
  24857. if (!defined(value)) {
  24858. throw new DeveloperError('value is required');
  24859. }
  24860. if (!defined(array)) {
  24861. throw new DeveloperError('array is required');
  24862. }
  24863. startingIndex = defaultValue(startingIndex, 0);
  24864. array[startingIndex++] = value.x;
  24865. array[startingIndex++] = value.y;
  24866. array[startingIndex++] = value.width;
  24867. array[startingIndex] = value.height;
  24868. return array;
  24869. };
  24870. /**
  24871. * Retrieves an instance from a packed array.
  24872. *
  24873. * @param {Number[]} array The packed array.
  24874. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  24875. * @param {BoundingRectangle} [result] The object into which to store the result.
  24876. * @returns {BoundingRectangle} The modified result parameter or a new BoundingRectangle instance if one was not provided.
  24877. */
  24878. BoundingRectangle.unpack = function(array, startingIndex, result) {
  24879. if (!defined(array)) {
  24880. throw new DeveloperError('array is required');
  24881. }
  24882. startingIndex = defaultValue(startingIndex, 0);
  24883. if (!defined(result)) {
  24884. result = new BoundingRectangle();
  24885. }
  24886. result.x = array[startingIndex++];
  24887. result.y = array[startingIndex++];
  24888. result.width = array[startingIndex++];
  24889. result.height = array[startingIndex];
  24890. return result;
  24891. };
  24892. /**
  24893. * Computes a bounding rectangle enclosing the list of 2D points.
  24894. * The rectangle is oriented with the corner at the bottom left.
  24895. *
  24896. * @param {Cartesian2[]} positions List of points that the bounding rectangle will enclose. Each point must have <code>x</code> and <code>y</code> properties.
  24897. * @param {BoundingRectangle} [result] The object onto which to store the result.
  24898. * @returns {BoundingRectangle} The modified result parameter or a new BoundingRectangle instance if one was not provided.
  24899. */
  24900. BoundingRectangle.fromPoints = function(positions, result) {
  24901. if (!defined(result)) {
  24902. result = new BoundingRectangle();
  24903. }
  24904. if (!defined(positions) || positions.length === 0) {
  24905. result.x = 0;
  24906. result.y = 0;
  24907. result.width = 0;
  24908. result.height = 0;
  24909. return result;
  24910. }
  24911. var length = positions.length;
  24912. var minimumX = positions[0].x;
  24913. var minimumY = positions[0].y;
  24914. var maximumX = positions[0].x;
  24915. var maximumY = positions[0].y;
  24916. for ( var i = 1; i < length; i++) {
  24917. var p = positions[i];
  24918. var x = p.x;
  24919. var y = p.y;
  24920. minimumX = Math.min(x, minimumX);
  24921. maximumX = Math.max(x, maximumX);
  24922. minimumY = Math.min(y, minimumY);
  24923. maximumY = Math.max(y, maximumY);
  24924. }
  24925. result.x = minimumX;
  24926. result.y = minimumY;
  24927. result.width = maximumX - minimumX;
  24928. result.height = maximumY - minimumY;
  24929. return result;
  24930. };
  24931. var defaultProjection = new GeographicProjection();
  24932. var fromRectangleLowerLeft = new Cartographic();
  24933. var fromRectangleUpperRight = new Cartographic();
  24934. /**
  24935. * Computes a bounding rectangle from an rectangle.
  24936. *
  24937. * @param {Rectangle} rectangle The valid rectangle used to create a bounding rectangle.
  24938. * @param {Object} [projection=GeographicProjection] The projection used to project the rectangle into 2D.
  24939. * @param {BoundingRectangle} [result] The object onto which to store the result.
  24940. * @returns {BoundingRectangle} The modified result parameter or a new BoundingRectangle instance if one was not provided.
  24941. */
  24942. BoundingRectangle.fromRectangle = function(rectangle, projection, result) {
  24943. if (!defined(result)) {
  24944. result = new BoundingRectangle();
  24945. }
  24946. if (!defined(rectangle)) {
  24947. result.x = 0;
  24948. result.y = 0;
  24949. result.width = 0;
  24950. result.height = 0;
  24951. return result;
  24952. }
  24953. projection = defaultValue(projection, defaultProjection);
  24954. var lowerLeft = projection.project(Rectangle.southwest(rectangle, fromRectangleLowerLeft));
  24955. var upperRight = projection.project(Rectangle.northeast(rectangle, fromRectangleUpperRight));
  24956. Cartesian2.subtract(upperRight, lowerLeft, upperRight);
  24957. result.x = lowerLeft.x;
  24958. result.y = lowerLeft.y;
  24959. result.width = upperRight.x;
  24960. result.height = upperRight.y;
  24961. return result;
  24962. };
  24963. /**
  24964. * Duplicates a BoundingRectangle instance.
  24965. *
  24966. * @param {BoundingRectangle} rectangle The bounding rectangle to duplicate.
  24967. * @param {BoundingRectangle} [result] The object onto which to store the result.
  24968. * @returns {BoundingRectangle} The modified result parameter or a new BoundingRectangle instance if one was not provided. (Returns undefined if rectangle is undefined)
  24969. */
  24970. BoundingRectangle.clone = function(rectangle, result) {
  24971. if (!defined(rectangle)) {
  24972. return undefined;
  24973. }
  24974. if (!defined(result)) {
  24975. return new BoundingRectangle(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
  24976. }
  24977. result.x = rectangle.x;
  24978. result.y = rectangle.y;
  24979. result.width = rectangle.width;
  24980. result.height = rectangle.height;
  24981. return result;
  24982. };
  24983. /**
  24984. * Computes a bounding rectangle that is the union of the left and right bounding rectangles.
  24985. *
  24986. * @param {BoundingRectangle} left A rectangle to enclose in bounding rectangle.
  24987. * @param {BoundingRectangle} right A rectangle to enclose in a bounding rectangle.
  24988. * @param {BoundingRectangle} [result] The object onto which to store the result.
  24989. * @returns {BoundingRectangle} The modified result parameter or a new BoundingRectangle instance if one was not provided.
  24990. */
  24991. BoundingRectangle.union = function(left, right, result) {
  24992. if (!defined(left)) {
  24993. throw new DeveloperError('left is required.');
  24994. }
  24995. if (!defined(right)) {
  24996. throw new DeveloperError('right is required.');
  24997. }
  24998. if (!defined(result)) {
  24999. result = new BoundingRectangle();
  25000. }
  25001. var lowerLeftX = Math.min(left.x, right.x);
  25002. var lowerLeftY = Math.min(left.y, right.y);
  25003. var upperRightX = Math.max(left.x + left.width, right.x + right.width);
  25004. var upperRightY = Math.max(left.y + left.height, right.y + right.height);
  25005. result.x = lowerLeftX;
  25006. result.y = lowerLeftY;
  25007. result.width = upperRightX - lowerLeftX;
  25008. result.height = upperRightY - lowerLeftY;
  25009. return result;
  25010. };
  25011. /**
  25012. * Computes a bounding rectangle by enlarging the provided rectangle until it contains the provided point.
  25013. *
  25014. * @param {BoundingRectangle} rectangle A rectangle to expand.
  25015. * @param {Cartesian2} point A point to enclose in a bounding rectangle.
  25016. * @param {BoundingRectangle} [result] The object onto which to store the result.
  25017. * @returns {BoundingRectangle} The modified result parameter or a new BoundingRectangle instance if one was not provided.
  25018. */
  25019. BoundingRectangle.expand = function(rectangle, point, result) {
  25020. if (!defined(rectangle)) {
  25021. throw new DeveloperError('rectangle is required.');
  25022. }
  25023. if (!defined(point)) {
  25024. throw new DeveloperError('point is required.');
  25025. }
  25026. result = BoundingRectangle.clone(rectangle, result);
  25027. var width = point.x - result.x;
  25028. var height = point.y - result.y;
  25029. if (width > result.width) {
  25030. result.width = width;
  25031. } else if (width < 0) {
  25032. result.width -= width;
  25033. result.x = point.x;
  25034. }
  25035. if (height > result.height) {
  25036. result.height = height;
  25037. } else if (height < 0) {
  25038. result.height -= height;
  25039. result.y = point.y;
  25040. }
  25041. return result;
  25042. };
  25043. /**
  25044. * Determines if two rectangles intersect.
  25045. *
  25046. * @param {BoundingRectangle} left A rectangle to check for intersection.
  25047. * @param {BoundingRectangle} right The other rectangle to check for intersection.
  25048. * @returns {Intersect} <code>Intersect.INTESECTING</code> if the rectangles intersect, <code>Intersect.OUTSIDE</code> otherwise.
  25049. */
  25050. BoundingRectangle.intersect = function(left, right) {
  25051. if (!defined(left)) {
  25052. throw new DeveloperError('left is required.');
  25053. }
  25054. if (!defined(right)) {
  25055. throw new DeveloperError('right is required.');
  25056. }
  25057. var leftX = left.x;
  25058. var leftY = left.y;
  25059. var rightX = right.x;
  25060. var rightY = right.y;
  25061. if (!(leftX > rightX + right.width ||
  25062. leftX + left.width < rightX ||
  25063. leftY + left.height < rightY ||
  25064. leftY > rightY + right.height)) {
  25065. return Intersect.INTERSECTING;
  25066. }
  25067. return Intersect.OUTSIDE;
  25068. };
  25069. /**
  25070. * Compares the provided BoundingRectangles componentwise and returns
  25071. * <code>true</code> if they are equal, <code>false</code> otherwise.
  25072. *
  25073. * @param {BoundingRectangle} [left] The first BoundingRectangle.
  25074. * @param {BoundingRectangle} [right] The second BoundingRectangle.
  25075. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  25076. */
  25077. BoundingRectangle.equals = function(left, right) {
  25078. return (left === right) ||
  25079. ((defined(left)) &&
  25080. (defined(right)) &&
  25081. (left.x === right.x) &&
  25082. (left.y === right.y) &&
  25083. (left.width === right.width) &&
  25084. (left.height === right.height));
  25085. };
  25086. /**
  25087. * Duplicates this BoundingRectangle instance.
  25088. *
  25089. * @param {BoundingRectangle} [result] The object onto which to store the result.
  25090. * @returns {BoundingRectangle} The modified result parameter or a new BoundingRectangle instance if one was not provided.
  25091. */
  25092. BoundingRectangle.prototype.clone = function(result) {
  25093. return BoundingRectangle.clone(this, result);
  25094. };
  25095. /**
  25096. * Determines if this rectangle intersects with another.
  25097. *
  25098. * @param {BoundingRectangle} right A rectangle to check for intersection.
  25099. * @returns {Intersect} <code>Intersect.INTESECTING</code> if the rectangles intersect, <code>Intersect.OUTSIDE</code> otherwise.
  25100. */
  25101. BoundingRectangle.prototype.intersect = function(right) {
  25102. return BoundingRectangle.intersect(this, right);
  25103. };
  25104. /**
  25105. * Compares this BoundingRectangle against the provided BoundingRectangle componentwise and returns
  25106. * <code>true</code> if they are equal, <code>false</code> otherwise.
  25107. *
  25108. * @param {BoundingRectangle} [right] The right hand side BoundingRectangle.
  25109. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  25110. */
  25111. BoundingRectangle.prototype.equals = function(right) {
  25112. return BoundingRectangle.equals(this, right);
  25113. };
  25114. return BoundingRectangle;
  25115. });
  25116. /*global define*/
  25117. define('Core/GeometryType',[
  25118. './freezeObject'
  25119. ], function(
  25120. freezeObject) {
  25121. 'use strict';
  25122. /**
  25123. * @private
  25124. */
  25125. var GeometryType = {
  25126. NONE : 0,
  25127. TRIANGLES : 1,
  25128. LINES : 2,
  25129. POLYLINES : 3
  25130. };
  25131. return freezeObject(GeometryType);
  25132. });
  25133. /*global define*/
  25134. define('Core/PrimitiveType',[
  25135. './freezeObject',
  25136. './WebGLConstants'
  25137. ], function(
  25138. freezeObject,
  25139. WebGLConstants) {
  25140. 'use strict';
  25141. /**
  25142. * The type of a geometric primitive, i.e., points, lines, and triangles.
  25143. *
  25144. * @exports PrimitiveType
  25145. */
  25146. var PrimitiveType = {
  25147. /**
  25148. * Points primitive where each vertex (or index) is a separate point.
  25149. *
  25150. * @type {Number}
  25151. * @constant
  25152. */
  25153. POINTS : WebGLConstants.POINTS,
  25154. /**
  25155. * Lines primitive where each two vertices (or indices) is a line segment. Line segments are not necessarily connected.
  25156. *
  25157. * @type {Number}
  25158. * @constant
  25159. */
  25160. LINES : WebGLConstants.LINES,
  25161. /**
  25162. * Line loop primitive where each vertex (or index) after the first connects a line to
  25163. * the previous vertex, and the last vertex implicitly connects to the first.
  25164. *
  25165. * @type {Number}
  25166. * @constant
  25167. */
  25168. LINE_LOOP : WebGLConstants.LINE_LOOP,
  25169. /**
  25170. * Line strip primitive where each vertex (or index) after the first connects a line to the previous vertex.
  25171. *
  25172. * @type {Number}
  25173. * @constant
  25174. */
  25175. LINE_STRIP : WebGLConstants.LINE_STRIP,
  25176. /**
  25177. * Triangles primitive where each three vertices (or indices) is a triangle. Triangles do not necessarily share edges.
  25178. *
  25179. * @type {Number}
  25180. * @constant
  25181. */
  25182. TRIANGLES : WebGLConstants.TRIANGLES,
  25183. /**
  25184. * Triangle strip primitive where each vertex (or index) after the first two connect to
  25185. * the previous two vertices forming a triangle. For example, this can be used to model a wall.
  25186. *
  25187. * @type {Number}
  25188. * @constant
  25189. */
  25190. TRIANGLE_STRIP : WebGLConstants.TRIANGLE_STRIP,
  25191. /**
  25192. * Triangle fan primitive where each vertex (or index) after the first two connect to
  25193. * the previous vertex and the first vertex forming a triangle. For example, this can be used
  25194. * to model a cone or circle.
  25195. *
  25196. * @type {Number}
  25197. * @constant
  25198. */
  25199. TRIANGLE_FAN : WebGLConstants.TRIANGLE_FAN,
  25200. /**
  25201. * @private
  25202. */
  25203. validate : function(primitiveType) {
  25204. return primitiveType === PrimitiveType.POINTS ||
  25205. primitiveType === PrimitiveType.LINES ||
  25206. primitiveType === PrimitiveType.LINE_LOOP ||
  25207. primitiveType === PrimitiveType.LINE_STRIP ||
  25208. primitiveType === PrimitiveType.TRIANGLES ||
  25209. primitiveType === PrimitiveType.TRIANGLE_STRIP ||
  25210. primitiveType === PrimitiveType.TRIANGLE_FAN;
  25211. }
  25212. };
  25213. return freezeObject(PrimitiveType);
  25214. });
  25215. /*global define*/
  25216. define('Core/Geometry',[
  25217. './defaultValue',
  25218. './defined',
  25219. './DeveloperError',
  25220. './GeometryType',
  25221. './PrimitiveType'
  25222. ], function(
  25223. defaultValue,
  25224. defined,
  25225. DeveloperError,
  25226. GeometryType,
  25227. PrimitiveType) {
  25228. 'use strict';
  25229. /**
  25230. * A geometry representation with attributes forming vertices and optional index data
  25231. * defining primitives. Geometries and an {@link Appearance}, which describes the shading,
  25232. * can be assigned to a {@link Primitive} for visualization. A <code>Primitive</code> can
  25233. * be created from many heterogeneous - in many cases - geometries for performance.
  25234. * <p>
  25235. * Geometries can be transformed and optimized using functions in {@link GeometryPipeline}.
  25236. * </p>
  25237. *
  25238. * @alias Geometry
  25239. * @constructor
  25240. *
  25241. * @param {Object} options Object with the following properties:
  25242. * @param {GeometryAttributes} options.attributes Attributes, which make up the geometry's vertices.
  25243. * @param {PrimitiveType} [options.primitiveType=PrimitiveType.TRIANGLES] The type of primitives in the geometry.
  25244. * @param {Uint16Array|Uint32Array} [options.indices] Optional index data that determines the primitives in the geometry.
  25245. * @param {BoundingSphere} [options.boundingSphere] An optional bounding sphere that fully enclosed the geometry.
  25246. *
  25247. * @see PolygonGeometry
  25248. * @see RectangleGeometry
  25249. * @see EllipseGeometry
  25250. * @see CircleGeometry
  25251. * @see WallGeometry
  25252. * @see SimplePolylineGeometry
  25253. * @see BoxGeometry
  25254. * @see EllipsoidGeometry
  25255. *
  25256. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Geometry%20and%20Appearances.html|Geometry and Appearances Demo}
  25257. *
  25258. * @example
  25259. * // Create geometry with a position attribute and indexed lines.
  25260. * var positions = new Float64Array([
  25261. * 0.0, 0.0, 0.0,
  25262. * 7500000.0, 0.0, 0.0,
  25263. * 0.0, 7500000.0, 0.0
  25264. * ]);
  25265. *
  25266. * var geometry = new Cesium.Geometry({
  25267. * attributes : {
  25268. * position : new Cesium.GeometryAttribute({
  25269. * componentDatatype : Cesium.ComponentDatatype.DOUBLE,
  25270. * componentsPerAttribute : 3,
  25271. * values : positions
  25272. * })
  25273. * },
  25274. * indices : new Uint16Array([0, 1, 1, 2, 2, 0]),
  25275. * primitiveType : Cesium.PrimitiveType.LINES,
  25276. * boundingSphere : Cesium.BoundingSphere.fromVertices(positions)
  25277. * });
  25278. */
  25279. function Geometry(options) {
  25280. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  25281. if (!defined(options.attributes)) {
  25282. throw new DeveloperError('options.attributes is required.');
  25283. }
  25284. /**
  25285. * Attributes, which make up the geometry's vertices. Each property in this object corresponds to a
  25286. * {@link GeometryAttribute} containing the attribute's data.
  25287. * <p>
  25288. * Attributes are always stored non-interleaved in a Geometry.
  25289. * </p>
  25290. * <p>
  25291. * There are reserved attribute names with well-known semantics. The following attributes
  25292. * are created by a Geometry (depending on the provided {@link VertexFormat}.
  25293. * <ul>
  25294. * <li><code>position</code> - 3D vertex position. 64-bit floating-point (for precision). 3 components per attribute. See {@link VertexFormat#position}.</li>
  25295. * <li><code>normal</code> - Normal (normalized), commonly used for lighting. 32-bit floating-point. 3 components per attribute. See {@link VertexFormat#normal}.</li>
  25296. * <li><code>st</code> - 2D texture coordinate. 32-bit floating-point. 2 components per attribute. See {@link VertexFormat#st}.</li>
  25297. * <li><code>binormal</code> - Binormal (normalized), used for tangent-space effects like bump mapping. 32-bit floating-point. 3 components per attribute. See {@link VertexFormat#binormal}.</li>
  25298. * <li><code>tangent</code> - Tangent (normalized), used for tangent-space effects like bump mapping. 32-bit floating-point. 3 components per attribute. See {@link VertexFormat#tangent}.</li>
  25299. * </ul>
  25300. * </p>
  25301. * <p>
  25302. * The following attribute names are generally not created by a Geometry, but are added
  25303. * to a Geometry by a {@link Primitive} or {@link GeometryPipeline} functions to prepare
  25304. * the geometry for rendering.
  25305. * <ul>
  25306. * <li><code>position3DHigh</code> - High 32 bits for encoded 64-bit position computed with {@link GeometryPipeline.encodeAttribute}. 32-bit floating-point. 4 components per attribute.</li>
  25307. * <li><code>position3DLow</code> - Low 32 bits for encoded 64-bit position computed with {@link GeometryPipeline.encodeAttribute}. 32-bit floating-point. 4 components per attribute.</li>
  25308. * <li><code>position3DHigh</code> - High 32 bits for encoded 64-bit 2D (Columbus view) position computed with {@link GeometryPipeline.encodeAttribute}. 32-bit floating-point. 4 components per attribute.</li>
  25309. * <li><code>position2DLow</code> - Low 32 bits for encoded 64-bit 2D (Columbus view) position computed with {@link GeometryPipeline.encodeAttribute}. 32-bit floating-point. 4 components per attribute.</li>
  25310. * <li><code>color</code> - RGBA color (normalized) usually from {@link GeometryInstance#color}. 32-bit floating-point. 4 components per attribute.</li>
  25311. * <li><code>pickColor</code> - RGBA color used for picking. 32-bit floating-point. 4 components per attribute.</li>
  25312. * </ul>
  25313. * </p>
  25314. *
  25315. * @type GeometryAttributes
  25316. *
  25317. * @default undefined
  25318. *
  25319. *
  25320. * @example
  25321. * geometry.attributes.position = new Cesium.GeometryAttribute({
  25322. * componentDatatype : Cesium.ComponentDatatype.FLOAT,
  25323. * componentsPerAttribute : 3,
  25324. * values : new Float32Array(0)
  25325. * });
  25326. *
  25327. * @see GeometryAttribute
  25328. * @see VertexFormat
  25329. */
  25330. this.attributes = options.attributes;
  25331. /**
  25332. * Optional index data that - along with {@link Geometry#primitiveType} -
  25333. * determines the primitives in the geometry.
  25334. *
  25335. * @type Array
  25336. *
  25337. * @default undefined
  25338. */
  25339. this.indices = options.indices;
  25340. /**
  25341. * The type of primitives in the geometry. This is most often {@link PrimitiveType.TRIANGLES},
  25342. * but can varying based on the specific geometry.
  25343. *
  25344. * @type PrimitiveType
  25345. *
  25346. * @default undefined
  25347. */
  25348. this.primitiveType = defaultValue(options.primitiveType, PrimitiveType.TRIANGLES);
  25349. /**
  25350. * An optional bounding sphere that fully encloses the geometry. This is
  25351. * commonly used for culling.
  25352. *
  25353. * @type BoundingSphere
  25354. *
  25355. * @default undefined
  25356. */
  25357. this.boundingSphere = options.boundingSphere;
  25358. /**
  25359. * @private
  25360. */
  25361. this.geometryType = defaultValue(options.geometryType, GeometryType.NONE);
  25362. /**
  25363. * @private
  25364. */
  25365. this.boundingSphereCV = options.boundingSphereCV;
  25366. }
  25367. /**
  25368. * Computes the number of vertices in a geometry. The runtime is linear with
  25369. * respect to the number of attributes in a vertex, not the number of vertices.
  25370. *
  25371. * @param {Geometry} geometry The geometry.
  25372. * @returns {Number} The number of vertices in the geometry.
  25373. *
  25374. * @example
  25375. * var numVertices = Cesium.Geometry.computeNumberOfVertices(geometry);
  25376. */
  25377. Geometry.computeNumberOfVertices = function(geometry) {
  25378. if (!defined(geometry)) {
  25379. throw new DeveloperError('geometry is required.');
  25380. }
  25381. var numberOfVertices = -1;
  25382. for ( var property in geometry.attributes) {
  25383. if (geometry.attributes.hasOwnProperty(property) &&
  25384. defined(geometry.attributes[property]) &&
  25385. defined(geometry.attributes[property].values)) {
  25386. var attribute = geometry.attributes[property];
  25387. var num = attribute.values.length / attribute.componentsPerAttribute;
  25388. if ((numberOfVertices !== num) && (numberOfVertices !== -1)) {
  25389. throw new DeveloperError('All attribute lists must have the same number of attributes.');
  25390. }
  25391. numberOfVertices = num;
  25392. }
  25393. }
  25394. return numberOfVertices;
  25395. };
  25396. return Geometry;
  25397. });
  25398. /*global define*/
  25399. define('Core/GeometryAttribute',[
  25400. './defaultValue',
  25401. './defined',
  25402. './DeveloperError'
  25403. ], function(
  25404. defaultValue,
  25405. defined,
  25406. DeveloperError) {
  25407. 'use strict';
  25408. /**
  25409. * Values and type information for geometry attributes. A {@link Geometry}
  25410. * generally contains one or more attributes. All attributes together form
  25411. * the geometry's vertices.
  25412. *
  25413. * @alias GeometryAttribute
  25414. * @constructor
  25415. *
  25416. * @param {Object} [options] Object with the following properties:
  25417. * @param {ComponentDatatype} [options.componentDatatype] The datatype of each component in the attribute, e.g., individual elements in values.
  25418. * @param {Number} [options.componentsPerAttribute] A number between 1 and 4 that defines the number of components in an attributes.
  25419. * @param {Boolean} [options.normalize=false] When <code>true</code> and <code>componentDatatype</code> is an integer format, indicate that the components should be mapped to the range [0, 1] (unsigned) or [-1, 1] (signed) when they are accessed as floating-point for rendering.
  25420. * @param {TypedArray} [options.values] The values for the attributes stored in a typed array.
  25421. *
  25422. * @exception {DeveloperError} options.componentsPerAttribute must be between 1 and 4.
  25423. *
  25424. *
  25425. * @example
  25426. * var geometry = new Cesium.Geometry({
  25427. * attributes : {
  25428. * position : new Cesium.GeometryAttribute({
  25429. * componentDatatype : Cesium.ComponentDatatype.FLOAT,
  25430. * componentsPerAttribute : 3,
  25431. * values : new Float32Array([
  25432. * 0.0, 0.0, 0.0,
  25433. * 7500000.0, 0.0, 0.0,
  25434. * 0.0, 7500000.0, 0.0
  25435. * ])
  25436. * })
  25437. * },
  25438. * primitiveType : Cesium.PrimitiveType.LINE_LOOP
  25439. * });
  25440. *
  25441. * @see Geometry
  25442. */
  25443. function GeometryAttribute(options) {
  25444. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  25445. if (!defined(options.componentDatatype)) {
  25446. throw new DeveloperError('options.componentDatatype is required.');
  25447. }
  25448. if (!defined(options.componentsPerAttribute)) {
  25449. throw new DeveloperError('options.componentsPerAttribute is required.');
  25450. }
  25451. if (options.componentsPerAttribute < 1 || options.componentsPerAttribute > 4) {
  25452. throw new DeveloperError('options.componentsPerAttribute must be between 1 and 4.');
  25453. }
  25454. if (!defined(options.values)) {
  25455. throw new DeveloperError('options.values is required.');
  25456. }
  25457. /**
  25458. * The datatype of each component in the attribute, e.g., individual elements in
  25459. * {@link GeometryAttribute#values}.
  25460. *
  25461. * @type ComponentDatatype
  25462. *
  25463. * @default undefined
  25464. */
  25465. this.componentDatatype = options.componentDatatype;
  25466. /**
  25467. * A number between 1 and 4 that defines the number of components in an attributes.
  25468. * For example, a position attribute with x, y, and z components would have 3 as
  25469. * shown in the code example.
  25470. *
  25471. * @type Number
  25472. *
  25473. * @default undefined
  25474. *
  25475. * @example
  25476. * attribute.componentDatatype = Cesium.ComponentDatatype.FLOAT;
  25477. * attribute.componentsPerAttribute = 3;
  25478. * attribute.values = new Float32Array([
  25479. * 0.0, 0.0, 0.0,
  25480. * 7500000.0, 0.0, 0.0,
  25481. * 0.0, 7500000.0, 0.0
  25482. * ]);
  25483. */
  25484. this.componentsPerAttribute = options.componentsPerAttribute;
  25485. /**
  25486. * When <code>true</code> and <code>componentDatatype</code> is an integer format,
  25487. * indicate that the components should be mapped to the range [0, 1] (unsigned)
  25488. * or [-1, 1] (signed) when they are accessed as floating-point for rendering.
  25489. * <p>
  25490. * This is commonly used when storing colors using {@link ComponentDatatype.UNSIGNED_BYTE}.
  25491. * </p>
  25492. *
  25493. * @type Boolean
  25494. *
  25495. * @default false
  25496. *
  25497. * @example
  25498. * attribute.componentDatatype = Cesium.ComponentDatatype.UNSIGNED_BYTE;
  25499. * attribute.componentsPerAttribute = 4;
  25500. * attribute.normalize = true;
  25501. * attribute.values = new Uint8Array([
  25502. * Cesium.Color.floatToByte(color.red),
  25503. * Cesium.Color.floatToByte(color.green),
  25504. * Cesium.Color.floatToByte(color.blue),
  25505. * Cesium.Color.floatToByte(color.alpha)
  25506. * ]);
  25507. */
  25508. this.normalize = defaultValue(options.normalize, false);
  25509. /**
  25510. * The values for the attributes stored in a typed array. In the code example,
  25511. * every three elements in <code>values</code> defines one attributes since
  25512. * <code>componentsPerAttribute</code> is 3.
  25513. *
  25514. * @type TypedArray
  25515. *
  25516. * @default undefined
  25517. *
  25518. * @example
  25519. * attribute.componentDatatype = Cesium.ComponentDatatype.FLOAT;
  25520. * attribute.componentsPerAttribute = 3;
  25521. * attribute.values = new Float32Array([
  25522. * 0.0, 0.0, 0.0,
  25523. * 7500000.0, 0.0, 0.0,
  25524. * 0.0, 7500000.0, 0.0
  25525. * ]);
  25526. */
  25527. this.values = options.values;
  25528. }
  25529. return GeometryAttribute;
  25530. });
  25531. /*global define*/
  25532. define('Core/GeometryAttributes',[
  25533. './defaultValue'
  25534. ], function(
  25535. defaultValue) {
  25536. 'use strict';
  25537. /**
  25538. * Attributes, which make up a geometry's vertices. Each property in this object corresponds to a
  25539. * {@link GeometryAttribute} containing the attribute's data.
  25540. * <p>
  25541. * Attributes are always stored non-interleaved in a Geometry.
  25542. * </p>
  25543. *
  25544. * @alias GeometryAttributes
  25545. * @constructor
  25546. */
  25547. function GeometryAttributes(options) {
  25548. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  25549. /**
  25550. * The 3D position attribute.
  25551. * <p>
  25552. * 64-bit floating-point (for precision). 3 components per attribute.
  25553. * </p>
  25554. *
  25555. * @type GeometryAttribute
  25556. *
  25557. * @default undefined
  25558. */
  25559. this.position = options.position;
  25560. /**
  25561. * The normal attribute (normalized), which is commonly used for lighting.
  25562. * <p>
  25563. * 32-bit floating-point. 3 components per attribute.
  25564. * </p>
  25565. *
  25566. * @type GeometryAttribute
  25567. *
  25568. * @default undefined
  25569. */
  25570. this.normal = options.normal;
  25571. /**
  25572. * The 2D texture coordinate attribute.
  25573. * <p>
  25574. * 32-bit floating-point. 2 components per attribute
  25575. * </p>
  25576. *
  25577. * @type GeometryAttribute
  25578. *
  25579. * @default undefined
  25580. */
  25581. this.st = options.st;
  25582. /**
  25583. * The binormal attribute (normalized), which is used for tangent-space effects like bump mapping.
  25584. * <p>
  25585. * 32-bit floating-point. 3 components per attribute.
  25586. * </p>
  25587. *
  25588. * @type GeometryAttribute
  25589. *
  25590. * @default undefined
  25591. */
  25592. this.binormal = options.binormal;
  25593. /**
  25594. * The tangent attribute (normalized), which is used for tangent-space effects like bump mapping.
  25595. * <p>
  25596. * 32-bit floating-point. 3 components per attribute.
  25597. * </p>
  25598. *
  25599. * @type GeometryAttribute
  25600. *
  25601. * @default undefined
  25602. */
  25603. this.tangent = options.tangent;
  25604. /**
  25605. * The color attribute.
  25606. * <p>
  25607. * 8-bit unsigned integer. 4 components per attribute.
  25608. * </p>
  25609. *
  25610. * @type GeometryAttribute
  25611. *
  25612. * @default undefined
  25613. */
  25614. this.color = options.color;
  25615. }
  25616. return GeometryAttributes;
  25617. });
  25618. /*global define*/
  25619. define('Core/VertexFormat',[
  25620. './defaultValue',
  25621. './defined',
  25622. './DeveloperError',
  25623. './freezeObject'
  25624. ], function(
  25625. defaultValue,
  25626. defined,
  25627. DeveloperError,
  25628. freezeObject) {
  25629. 'use strict';
  25630. /**
  25631. * A vertex format defines what attributes make up a vertex. A VertexFormat can be provided
  25632. * to a {@link Geometry} to request that certain properties be computed, e.g., just position,
  25633. * position and normal, etc.
  25634. *
  25635. * @param {Object} [options] An object with boolean properties corresponding to VertexFormat properties as shown in the code example.
  25636. *
  25637. * @alias VertexFormat
  25638. * @constructor
  25639. *
  25640. * @example
  25641. * // Create a vertex format with position and 2D texture coordinate attributes.
  25642. * var format = new Cesium.VertexFormat({
  25643. * position : true,
  25644. * st : true
  25645. * });
  25646. *
  25647. * @see Geometry#attributes
  25648. * @see Packable
  25649. */
  25650. function VertexFormat(options) {
  25651. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  25652. /**
  25653. * When <code>true</code>, the vertex has a 3D position attribute.
  25654. * <p>
  25655. * 64-bit floating-point (for precision). 3 components per attribute.
  25656. * </p>
  25657. *
  25658. * @type Boolean
  25659. *
  25660. * @default false
  25661. */
  25662. this.position = defaultValue(options.position, false);
  25663. /**
  25664. * When <code>true</code>, the vertex has a normal attribute (normalized), which is commonly used for lighting.
  25665. * <p>
  25666. * 32-bit floating-point. 3 components per attribute.
  25667. * </p>
  25668. *
  25669. * @type Boolean
  25670. *
  25671. * @default false
  25672. */
  25673. this.normal = defaultValue(options.normal, false);
  25674. /**
  25675. * When <code>true</code>, the vertex has a 2D texture coordinate attribute.
  25676. * <p>
  25677. * 32-bit floating-point. 2 components per attribute
  25678. * </p>
  25679. *
  25680. * @type Boolean
  25681. *
  25682. * @default false
  25683. */
  25684. this.st = defaultValue(options.st, false);
  25685. /**
  25686. * When <code>true</code>, the vertex has a binormal attribute (normalized), which is used for tangent-space effects like bump mapping.
  25687. * <p>
  25688. * 32-bit floating-point. 3 components per attribute.
  25689. * </p>
  25690. *
  25691. * @type Boolean
  25692. *
  25693. * @default false
  25694. */
  25695. this.binormal = defaultValue(options.binormal, false);
  25696. /**
  25697. * When <code>true</code>, the vertex has a tangent attribute (normalized), which is used for tangent-space effects like bump mapping.
  25698. * <p>
  25699. * 32-bit floating-point. 3 components per attribute.
  25700. * </p>
  25701. *
  25702. * @type Boolean
  25703. *
  25704. * @default false
  25705. */
  25706. this.tangent = defaultValue(options.tangent, false);
  25707. /**
  25708. * When <code>true</code>, the vertex has an RGB color attribute.
  25709. * <p>
  25710. * 8-bit unsigned byte. 3 components per attribute.
  25711. * </p>
  25712. *
  25713. * @type Boolean
  25714. *
  25715. * @default false
  25716. */
  25717. this.color = defaultValue(options.color, false);
  25718. }
  25719. /**
  25720. * An immutable vertex format with only a position attribute.
  25721. *
  25722. * @type {VertexFormat}
  25723. * @constant
  25724. *
  25725. * @see VertexFormat#position
  25726. */
  25727. VertexFormat.POSITION_ONLY = freezeObject(new VertexFormat({
  25728. position : true
  25729. }));
  25730. /**
  25731. * An immutable vertex format with position and normal attributes.
  25732. * This is compatible with per-instance color appearances like {@link PerInstanceColorAppearance}.
  25733. *
  25734. * @type {VertexFormat}
  25735. * @constant
  25736. *
  25737. * @see VertexFormat#position
  25738. * @see VertexFormat#normal
  25739. */
  25740. VertexFormat.POSITION_AND_NORMAL = freezeObject(new VertexFormat({
  25741. position : true,
  25742. normal : true
  25743. }));
  25744. /**
  25745. * An immutable vertex format with position, normal, and st attributes.
  25746. * This is compatible with {@link MaterialAppearance} when {@link MaterialAppearance#materialSupport}
  25747. * is <code>TEXTURED/code>.
  25748. *
  25749. * @type {VertexFormat}
  25750. * @constant
  25751. *
  25752. * @see VertexFormat#position
  25753. * @see VertexFormat#normal
  25754. * @see VertexFormat#st
  25755. */
  25756. VertexFormat.POSITION_NORMAL_AND_ST = freezeObject(new VertexFormat({
  25757. position : true,
  25758. normal : true,
  25759. st : true
  25760. }));
  25761. /**
  25762. * An immutable vertex format with position and st attributes.
  25763. * This is compatible with {@link EllipsoidSurfaceAppearance}.
  25764. *
  25765. * @type {VertexFormat}
  25766. * @constant
  25767. *
  25768. * @see VertexFormat#position
  25769. * @see VertexFormat#st
  25770. */
  25771. VertexFormat.POSITION_AND_ST = freezeObject(new VertexFormat({
  25772. position : true,
  25773. st : true
  25774. }));
  25775. /**
  25776. * An immutable vertex format with position and color attributes.
  25777. *
  25778. * @type {VertexFormat}
  25779. * @constant
  25780. *
  25781. * @see VertexFormat#position
  25782. * @see VertexFormat#color
  25783. */
  25784. VertexFormat.POSITION_AND_COLOR = freezeObject(new VertexFormat({
  25785. position : true,
  25786. color : true
  25787. }));
  25788. /**
  25789. * An immutable vertex format with well-known attributes: position, normal, st, binormal, and tangent.
  25790. *
  25791. * @type {VertexFormat}
  25792. * @constant
  25793. *
  25794. * @see VertexFormat#position
  25795. * @see VertexFormat#normal
  25796. * @see VertexFormat#st
  25797. * @see VertexFormat#binormal
  25798. * @see VertexFormat#tangent
  25799. */
  25800. VertexFormat.ALL = freezeObject(new VertexFormat({
  25801. position : true,
  25802. normal : true,
  25803. st : true,
  25804. binormal : true,
  25805. tangent : true
  25806. }));
  25807. /**
  25808. * An immutable vertex format with position, normal, and st attributes.
  25809. * This is compatible with most appearances and materials; however
  25810. * normal and st attributes are not always required. When this is
  25811. * known in advance, another <code>VertexFormat</code> should be used.
  25812. *
  25813. * @type {VertexFormat}
  25814. * @constant
  25815. *
  25816. * @see VertexFormat#position
  25817. * @see VertexFormat#normal
  25818. */
  25819. VertexFormat.DEFAULT = VertexFormat.POSITION_NORMAL_AND_ST;
  25820. /**
  25821. * The number of elements used to pack the object into an array.
  25822. * @type {Number}
  25823. */
  25824. VertexFormat.packedLength = 6;
  25825. /**
  25826. * Stores the provided instance into the provided array.
  25827. *
  25828. * @param {VertexFormat} value The value to pack.
  25829. * @param {Number[]} array The array to pack into.
  25830. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  25831. *
  25832. * @returns {Number[]} The array that was packed into
  25833. */
  25834. VertexFormat.pack = function(value, array, startingIndex) {
  25835. if (!defined(value)) {
  25836. throw new DeveloperError('value is required');
  25837. }
  25838. if (!defined(array)) {
  25839. throw new DeveloperError('array is required');
  25840. }
  25841. startingIndex = defaultValue(startingIndex, 0);
  25842. array[startingIndex++] = value.position ? 1.0 : 0.0;
  25843. array[startingIndex++] = value.normal ? 1.0 : 0.0;
  25844. array[startingIndex++] = value.st ? 1.0 : 0.0;
  25845. array[startingIndex++] = value.binormal ? 1.0 : 0.0;
  25846. array[startingIndex++] = value.tangent ? 1.0 : 0.0;
  25847. array[startingIndex++] = value.color ? 1.0 : 0.0;
  25848. return array;
  25849. };
  25850. /**
  25851. * Retrieves an instance from a packed array.
  25852. *
  25853. * @param {Number[]} array The packed array.
  25854. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  25855. * @param {VertexFormat} [result] The object into which to store the result.
  25856. * @returns {VertexFormat} The modified result parameter or a new VertexFormat instance if one was not provided.
  25857. */
  25858. VertexFormat.unpack = function(array, startingIndex, result) {
  25859. if (!defined(array)) {
  25860. throw new DeveloperError('array is required');
  25861. }
  25862. startingIndex = defaultValue(startingIndex, 0);
  25863. if (!defined(result)) {
  25864. result = new VertexFormat();
  25865. }
  25866. result.position = array[startingIndex++] === 1.0;
  25867. result.normal = array[startingIndex++] === 1.0;
  25868. result.st = array[startingIndex++] === 1.0;
  25869. result.binormal = array[startingIndex++] === 1.0;
  25870. result.tangent = array[startingIndex++] === 1.0;
  25871. result.color = array[startingIndex++] === 1.0;
  25872. return result;
  25873. };
  25874. /**
  25875. * Duplicates a VertexFormat instance.
  25876. *
  25877. * @param {VertexFormat} cartesian The vertex format to duplicate.
  25878. * @param {VertexFormat} [result] The object onto which to store the result.
  25879. * @returns {VertexFormat} The modified result parameter or a new VertexFormat instance if one was not provided. (Returns undefined if vertexFormat is undefined)
  25880. */
  25881. VertexFormat.clone = function(vertexFormat, result) {
  25882. if (!defined(vertexFormat)) {
  25883. return undefined;
  25884. }
  25885. if (!defined(result)) {
  25886. result = new VertexFormat();
  25887. }
  25888. result.position = vertexFormat.position;
  25889. result.normal = vertexFormat.normal;
  25890. result.st = vertexFormat.st;
  25891. result.binormal = vertexFormat.binormal;
  25892. result.tangent = vertexFormat.tangent;
  25893. result.color = vertexFormat.color;
  25894. return result;
  25895. };
  25896. return VertexFormat;
  25897. });
  25898. /*global define*/
  25899. define('Core/BoxGeometry',[
  25900. './BoundingSphere',
  25901. './Cartesian3',
  25902. './ComponentDatatype',
  25903. './defaultValue',
  25904. './defined',
  25905. './DeveloperError',
  25906. './Geometry',
  25907. './GeometryAttribute',
  25908. './GeometryAttributes',
  25909. './PrimitiveType',
  25910. './VertexFormat'
  25911. ], function(
  25912. BoundingSphere,
  25913. Cartesian3,
  25914. ComponentDatatype,
  25915. defaultValue,
  25916. defined,
  25917. DeveloperError,
  25918. Geometry,
  25919. GeometryAttribute,
  25920. GeometryAttributes,
  25921. PrimitiveType,
  25922. VertexFormat) {
  25923. 'use strict';
  25924. var diffScratch = new Cartesian3();
  25925. /**
  25926. * Describes a cube centered at the origin.
  25927. *
  25928. * @alias BoxGeometry
  25929. * @constructor
  25930. *
  25931. * @param {Object} options Object with the following properties:
  25932. * @param {Cartesian3} options.minimum The minimum x, y, and z coordinates of the box.
  25933. * @param {Cartesian3} options.maximum The maximum x, y, and z coordinates of the box.
  25934. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  25935. *
  25936. * @see BoxGeometry.fromDimensions
  25937. * @see BoxGeometry.createGeometry
  25938. * @see Packable
  25939. *
  25940. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Box.html|Cesium Sandcastle Box Demo}
  25941. *
  25942. * @example
  25943. * var box = new Cesium.BoxGeometry({
  25944. * vertexFormat : Cesium.VertexFormat.POSITION_ONLY,
  25945. * maximum : new Cesium.Cartesian3(250000.0, 250000.0, 250000.0),
  25946. * minimum : new Cesium.Cartesian3(-250000.0, -250000.0, -250000.0)
  25947. * });
  25948. * var geometry = Cesium.BoxGeometry.createGeometry(box);
  25949. */
  25950. function BoxGeometry(options) {
  25951. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  25952. var min = options.minimum;
  25953. var max = options.maximum;
  25954. if (!defined(min)) {
  25955. throw new DeveloperError('options.minimum is required.');
  25956. }
  25957. if (!defined(max)) {
  25958. throw new DeveloperError('options.maximum is required');
  25959. }
  25960. var vertexFormat = defaultValue(options.vertexFormat, VertexFormat.DEFAULT);
  25961. this._minimum = Cartesian3.clone(min);
  25962. this._maximum = Cartesian3.clone(max);
  25963. this._vertexFormat = vertexFormat;
  25964. this._workerName = 'createBoxGeometry';
  25965. }
  25966. /**
  25967. * Creates a cube centered at the origin given its dimensions.
  25968. *
  25969. * @param {Object} options Object with the following properties:
  25970. * @param {Cartesian3} options.dimensions The width, depth, and height of the box stored in the x, y, and z coordinates of the <code>Cartesian3</code>, respectively.
  25971. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  25972. * @returns {BoxGeometry}
  25973. *
  25974. * @exception {DeveloperError} All dimensions components must be greater than or equal to zero.
  25975. *
  25976. *
  25977. * @example
  25978. * var box = Cesium.BoxGeometry.fromDimensions({
  25979. * vertexFormat : Cesium.VertexFormat.POSITION_ONLY,
  25980. * dimensions : new Cesium.Cartesian3(500000.0, 500000.0, 500000.0)
  25981. * });
  25982. * var geometry = Cesium.BoxGeometry.createGeometry(box);
  25983. *
  25984. * @see BoxGeometry.createGeometry
  25985. */
  25986. BoxGeometry.fromDimensions = function(options) {
  25987. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  25988. var dimensions = options.dimensions;
  25989. if (!defined(dimensions)) {
  25990. throw new DeveloperError('options.dimensions is required.');
  25991. }
  25992. if (dimensions.x < 0 || dimensions.y < 0 || dimensions.z < 0) {
  25993. throw new DeveloperError('All dimensions components must be greater than or equal to zero.');
  25994. }
  25995. var corner = Cartesian3.multiplyByScalar(dimensions, 0.5, new Cartesian3());
  25996. return new BoxGeometry({
  25997. minimum : Cartesian3.negate(corner, new Cartesian3()),
  25998. maximum : corner,
  25999. vertexFormat : options.vertexFormat
  26000. });
  26001. };
  26002. /**
  26003. * Creates a cube from the dimensions of an AxisAlignedBoundingBox.
  26004. *
  26005. * @param {AxisAlignedBoundingBox} boundingBox A description of the AxisAlignedBoundingBox.
  26006. * @returns {BoxGeometry}
  26007. *
  26008. *
  26009. *
  26010. * @example
  26011. * var aabb = Cesium.AxisAlignedBoundingBox.fromPoints(Cesium.Cartesian3.fromDegreesArray([
  26012. * -72.0, 40.0,
  26013. * -70.0, 35.0,
  26014. * -75.0, 30.0,
  26015. * -70.0, 30.0,
  26016. * -68.0, 40.0
  26017. * ]));
  26018. * var box = Cesium.BoxGeometry.fromAxisAlignedBoundingBox(aabb);
  26019. *
  26020. * @see BoxGeometry.createGeometry
  26021. */
  26022. BoxGeometry.fromAxisAlignedBoundingBox = function (boundingBox) {
  26023. if (!defined(boundingBox)) {
  26024. throw new DeveloperError('boundingBox is required.');
  26025. }
  26026. return new BoxGeometry({
  26027. minimum : boundingBox.minimum,
  26028. maximum : boundingBox.maximum
  26029. });
  26030. };
  26031. /**
  26032. * The number of elements used to pack the object into an array.
  26033. * @type {Number}
  26034. */
  26035. BoxGeometry.packedLength = 2 * Cartesian3.packedLength + VertexFormat.packedLength;
  26036. /**
  26037. * Stores the provided instance into the provided array.
  26038. *
  26039. * @param {BoxGeometry} value The value to pack.
  26040. * @param {Number[]} array The array to pack into.
  26041. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  26042. *
  26043. * @returns {Number[]} The array that was packed into
  26044. */
  26045. BoxGeometry.pack = function(value, array, startingIndex) {
  26046. if (!defined(value)) {
  26047. throw new DeveloperError('value is required');
  26048. }
  26049. if (!defined(array)) {
  26050. throw new DeveloperError('array is required');
  26051. }
  26052. startingIndex = defaultValue(startingIndex, 0);
  26053. Cartesian3.pack(value._minimum, array, startingIndex);
  26054. Cartesian3.pack(value._maximum, array, startingIndex + Cartesian3.packedLength);
  26055. VertexFormat.pack(value._vertexFormat, array, startingIndex + 2 * Cartesian3.packedLength);
  26056. return array;
  26057. };
  26058. var scratchMin = new Cartesian3();
  26059. var scratchMax = new Cartesian3();
  26060. var scratchVertexFormat = new VertexFormat();
  26061. var scratchOptions = {
  26062. minimum: scratchMin,
  26063. maximum: scratchMax,
  26064. vertexFormat: scratchVertexFormat
  26065. };
  26066. /**
  26067. * Retrieves an instance from a packed array.
  26068. *
  26069. * @param {Number[]} array The packed array.
  26070. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  26071. * @param {BoxGeometry} [result] The object into which to store the result.
  26072. * @returns {BoxGeometry} The modified result parameter or a new BoxGeometry instance if one was not provided.
  26073. */
  26074. BoxGeometry.unpack = function(array, startingIndex, result) {
  26075. if (!defined(array)) {
  26076. throw new DeveloperError('array is required');
  26077. }
  26078. startingIndex = defaultValue(startingIndex, 0);
  26079. var min = Cartesian3.unpack(array, startingIndex, scratchMin);
  26080. var max = Cartesian3.unpack(array, startingIndex + Cartesian3.packedLength, scratchMax);
  26081. var vertexFormat = VertexFormat.unpack(array, startingIndex + 2 * Cartesian3.packedLength, scratchVertexFormat);
  26082. if (!defined(result)) {
  26083. return new BoxGeometry(scratchOptions);
  26084. }
  26085. result._minimum = Cartesian3.clone(min, result._minimum);
  26086. result._maximum = Cartesian3.clone(max, result._maximum);
  26087. result._vertexFormat = VertexFormat.clone(vertexFormat, result._vertexFormat);
  26088. return result;
  26089. };
  26090. /**
  26091. * Computes the geometric representation of a box, including its vertices, indices, and a bounding sphere.
  26092. *
  26093. * @param {BoxGeometry} boxGeometry A description of the box.
  26094. * @returns {Geometry|undefined} The computed vertices and indices.
  26095. */
  26096. BoxGeometry.createGeometry = function(boxGeometry) {
  26097. var min = boxGeometry._minimum;
  26098. var max = boxGeometry._maximum;
  26099. var vertexFormat = boxGeometry._vertexFormat;
  26100. if (Cartesian3.equals(min, max)) {
  26101. return;
  26102. }
  26103. var attributes = new GeometryAttributes();
  26104. var indices;
  26105. var positions;
  26106. if (vertexFormat.position &&
  26107. (vertexFormat.st || vertexFormat.normal || vertexFormat.binormal || vertexFormat.tangent)) {
  26108. if (vertexFormat.position) {
  26109. // 8 corner points. Duplicated 3 times each for each incident edge/face.
  26110. positions = new Float64Array(6 * 4 * 3);
  26111. // +z face
  26112. positions[0] = min.x;
  26113. positions[1] = min.y;
  26114. positions[2] = max.z;
  26115. positions[3] = max.x;
  26116. positions[4] = min.y;
  26117. positions[5] = max.z;
  26118. positions[6] = max.x;
  26119. positions[7] = max.y;
  26120. positions[8] = max.z;
  26121. positions[9] = min.x;
  26122. positions[10] = max.y;
  26123. positions[11] = max.z;
  26124. // -z face
  26125. positions[12] = min.x;
  26126. positions[13] = min.y;
  26127. positions[14] = min.z;
  26128. positions[15] = max.x;
  26129. positions[16] = min.y;
  26130. positions[17] = min.z;
  26131. positions[18] = max.x;
  26132. positions[19] = max.y;
  26133. positions[20] = min.z;
  26134. positions[21] = min.x;
  26135. positions[22] = max.y;
  26136. positions[23] = min.z;
  26137. // +x face
  26138. positions[24] = max.x;
  26139. positions[25] = min.y;
  26140. positions[26] = min.z;
  26141. positions[27] = max.x;
  26142. positions[28] = max.y;
  26143. positions[29] = min.z;
  26144. positions[30] = max.x;
  26145. positions[31] = max.y;
  26146. positions[32] = max.z;
  26147. positions[33] = max.x;
  26148. positions[34] = min.y;
  26149. positions[35] = max.z;
  26150. // -x face
  26151. positions[36] = min.x;
  26152. positions[37] = min.y;
  26153. positions[38] = min.z;
  26154. positions[39] = min.x;
  26155. positions[40] = max.y;
  26156. positions[41] = min.z;
  26157. positions[42] = min.x;
  26158. positions[43] = max.y;
  26159. positions[44] = max.z;
  26160. positions[45] = min.x;
  26161. positions[46] = min.y;
  26162. positions[47] = max.z;
  26163. // +y face
  26164. positions[48] = min.x;
  26165. positions[49] = max.y;
  26166. positions[50] = min.z;
  26167. positions[51] = max.x;
  26168. positions[52] = max.y;
  26169. positions[53] = min.z;
  26170. positions[54] = max.x;
  26171. positions[55] = max.y;
  26172. positions[56] = max.z;
  26173. positions[57] = min.x;
  26174. positions[58] = max.y;
  26175. positions[59] = max.z;
  26176. // -y face
  26177. positions[60] = min.x;
  26178. positions[61] = min.y;
  26179. positions[62] = min.z;
  26180. positions[63] = max.x;
  26181. positions[64] = min.y;
  26182. positions[65] = min.z;
  26183. positions[66] = max.x;
  26184. positions[67] = min.y;
  26185. positions[68] = max.z;
  26186. positions[69] = min.x;
  26187. positions[70] = min.y;
  26188. positions[71] = max.z;
  26189. attributes.position = new GeometryAttribute({
  26190. componentDatatype : ComponentDatatype.DOUBLE,
  26191. componentsPerAttribute : 3,
  26192. values : positions
  26193. });
  26194. }
  26195. if (vertexFormat.normal) {
  26196. var normals = new Float32Array(6 * 4 * 3);
  26197. // +z face
  26198. normals[0] = 0.0;
  26199. normals[1] = 0.0;
  26200. normals[2] = 1.0;
  26201. normals[3] = 0.0;
  26202. normals[4] = 0.0;
  26203. normals[5] = 1.0;
  26204. normals[6] = 0.0;
  26205. normals[7] = 0.0;
  26206. normals[8] = 1.0;
  26207. normals[9] = 0.0;
  26208. normals[10] = 0.0;
  26209. normals[11] = 1.0;
  26210. // -z face
  26211. normals[12] = 0.0;
  26212. normals[13] = 0.0;
  26213. normals[14] = -1.0;
  26214. normals[15] = 0.0;
  26215. normals[16] = 0.0;
  26216. normals[17] = -1.0;
  26217. normals[18] = 0.0;
  26218. normals[19] = 0.0;
  26219. normals[20] = -1.0;
  26220. normals[21] = 0.0;
  26221. normals[22] = 0.0;
  26222. normals[23] = -1.0;
  26223. // +x face
  26224. normals[24] = 1.0;
  26225. normals[25] = 0.0;
  26226. normals[26] = 0.0;
  26227. normals[27] = 1.0;
  26228. normals[28] = 0.0;
  26229. normals[29] = 0.0;
  26230. normals[30] = 1.0;
  26231. normals[31] = 0.0;
  26232. normals[32] = 0.0;
  26233. normals[33] = 1.0;
  26234. normals[34] = 0.0;
  26235. normals[35] = 0.0;
  26236. // -x face
  26237. normals[36] = -1.0;
  26238. normals[37] = 0.0;
  26239. normals[38] = 0.0;
  26240. normals[39] = -1.0;
  26241. normals[40] = 0.0;
  26242. normals[41] = 0.0;
  26243. normals[42] = -1.0;
  26244. normals[43] = 0.0;
  26245. normals[44] = 0.0;
  26246. normals[45] = -1.0;
  26247. normals[46] = 0.0;
  26248. normals[47] = 0.0;
  26249. // +y face
  26250. normals[48] = 0.0;
  26251. normals[49] = 1.0;
  26252. normals[50] = 0.0;
  26253. normals[51] = 0.0;
  26254. normals[52] = 1.0;
  26255. normals[53] = 0.0;
  26256. normals[54] = 0.0;
  26257. normals[55] = 1.0;
  26258. normals[56] = 0.0;
  26259. normals[57] = 0.0;
  26260. normals[58] = 1.0;
  26261. normals[59] = 0.0;
  26262. // -y face
  26263. normals[60] = 0.0;
  26264. normals[61] = -1.0;
  26265. normals[62] = 0.0;
  26266. normals[63] = 0.0;
  26267. normals[64] = -1.0;
  26268. normals[65] = 0.0;
  26269. normals[66] = 0.0;
  26270. normals[67] = -1.0;
  26271. normals[68] = 0.0;
  26272. normals[69] = 0.0;
  26273. normals[70] = -1.0;
  26274. normals[71] = 0.0;
  26275. attributes.normal = new GeometryAttribute({
  26276. componentDatatype : ComponentDatatype.FLOAT,
  26277. componentsPerAttribute : 3,
  26278. values : normals
  26279. });
  26280. }
  26281. if (vertexFormat.st) {
  26282. var texCoords = new Float32Array(6 * 4 * 2);
  26283. // +z face
  26284. texCoords[0] = 0.0;
  26285. texCoords[1] = 0.0;
  26286. texCoords[2] = 1.0;
  26287. texCoords[3] = 0.0;
  26288. texCoords[4] = 1.0;
  26289. texCoords[5] = 1.0;
  26290. texCoords[6] = 0.0;
  26291. texCoords[7] = 1.0;
  26292. // -z face
  26293. texCoords[8] = 1.0;
  26294. texCoords[9] = 0.0;
  26295. texCoords[10] = 0.0;
  26296. texCoords[11] = 0.0;
  26297. texCoords[12] = 0.0;
  26298. texCoords[13] = 1.0;
  26299. texCoords[14] = 1.0;
  26300. texCoords[15] = 1.0;
  26301. //+x face
  26302. texCoords[16] = 0.0;
  26303. texCoords[17] = 0.0;
  26304. texCoords[18] = 1.0;
  26305. texCoords[19] = 0.0;
  26306. texCoords[20] = 1.0;
  26307. texCoords[21] = 1.0;
  26308. texCoords[22] = 0.0;
  26309. texCoords[23] = 1.0;
  26310. // -x face
  26311. texCoords[24] = 1.0;
  26312. texCoords[25] = 0.0;
  26313. texCoords[26] = 0.0;
  26314. texCoords[27] = 0.0;
  26315. texCoords[28] = 0.0;
  26316. texCoords[29] = 1.0;
  26317. texCoords[30] = 1.0;
  26318. texCoords[31] = 1.0;
  26319. // +y face
  26320. texCoords[32] = 1.0;
  26321. texCoords[33] = 0.0;
  26322. texCoords[34] = 0.0;
  26323. texCoords[35] = 0.0;
  26324. texCoords[36] = 0.0;
  26325. texCoords[37] = 1.0;
  26326. texCoords[38] = 1.0;
  26327. texCoords[39] = 1.0;
  26328. // -y face
  26329. texCoords[40] = 0.0;
  26330. texCoords[41] = 0.0;
  26331. texCoords[42] = 1.0;
  26332. texCoords[43] = 0.0;
  26333. texCoords[44] = 1.0;
  26334. texCoords[45] = 1.0;
  26335. texCoords[46] = 0.0;
  26336. texCoords[47] = 1.0;
  26337. attributes.st = new GeometryAttribute({
  26338. componentDatatype : ComponentDatatype.FLOAT,
  26339. componentsPerAttribute : 2,
  26340. values : texCoords
  26341. });
  26342. }
  26343. if (vertexFormat.tangent) {
  26344. var tangents = new Float32Array(6 * 4 * 3);
  26345. // +z face
  26346. tangents[0] = 1.0;
  26347. tangents[1] = 0.0;
  26348. tangents[2] = 0.0;
  26349. tangents[3] = 1.0;
  26350. tangents[4] = 0.0;
  26351. tangents[5] = 0.0;
  26352. tangents[6] = 1.0;
  26353. tangents[7] = 0.0;
  26354. tangents[8] = 0.0;
  26355. tangents[9] = 1.0;
  26356. tangents[10] = 0.0;
  26357. tangents[11] = 0.0;
  26358. // -z face
  26359. tangents[12] = -1.0;
  26360. tangents[13] = 0.0;
  26361. tangents[14] = 0.0;
  26362. tangents[15] = -1.0;
  26363. tangents[16] = 0.0;
  26364. tangents[17] = 0.0;
  26365. tangents[18] = -1.0;
  26366. tangents[19] = 0.0;
  26367. tangents[20] = 0.0;
  26368. tangents[21] = -1.0;
  26369. tangents[22] = 0.0;
  26370. tangents[23] = 0.0;
  26371. // +x face
  26372. tangents[24] = 0.0;
  26373. tangents[25] = 1.0;
  26374. tangents[26] = 0.0;
  26375. tangents[27] = 0.0;
  26376. tangents[28] = 1.0;
  26377. tangents[29] = 0.0;
  26378. tangents[30] = 0.0;
  26379. tangents[31] = 1.0;
  26380. tangents[32] = 0.0;
  26381. tangents[33] = 0.0;
  26382. tangents[34] = 1.0;
  26383. tangents[35] = 0.0;
  26384. // -x face
  26385. tangents[36] = 0.0;
  26386. tangents[37] = -1.0;
  26387. tangents[38] = 0.0;
  26388. tangents[39] = 0.0;
  26389. tangents[40] = -1.0;
  26390. tangents[41] = 0.0;
  26391. tangents[42] = 0.0;
  26392. tangents[43] = -1.0;
  26393. tangents[44] = 0.0;
  26394. tangents[45] = 0.0;
  26395. tangents[46] = -1.0;
  26396. tangents[47] = 0.0;
  26397. // +y face
  26398. tangents[48] = -1.0;
  26399. tangents[49] = 0.0;
  26400. tangents[50] = 0.0;
  26401. tangents[51] = -1.0;
  26402. tangents[52] = 0.0;
  26403. tangents[53] = 0.0;
  26404. tangents[54] = -1.0;
  26405. tangents[55] = 0.0;
  26406. tangents[56] = 0.0;
  26407. tangents[57] = -1.0;
  26408. tangents[58] = 0.0;
  26409. tangents[59] = 0.0;
  26410. // -y face
  26411. tangents[60] = 1.0;
  26412. tangents[61] = 0.0;
  26413. tangents[62] = 0.0;
  26414. tangents[63] = 1.0;
  26415. tangents[64] = 0.0;
  26416. tangents[65] = 0.0;
  26417. tangents[66] = 1.0;
  26418. tangents[67] = 0.0;
  26419. tangents[68] = 0.0;
  26420. tangents[69] = 1.0;
  26421. tangents[70] = 0.0;
  26422. tangents[71] = 0.0;
  26423. attributes.tangent = new GeometryAttribute({
  26424. componentDatatype : ComponentDatatype.FLOAT,
  26425. componentsPerAttribute : 3,
  26426. values : tangents
  26427. });
  26428. }
  26429. if (vertexFormat.binormal) {
  26430. var binormals = new Float32Array(6 * 4 * 3);
  26431. // +z face
  26432. binormals[0] = 0.0;
  26433. binormals[1] = 1.0;
  26434. binormals[2] = 0.0;
  26435. binormals[3] = 0.0;
  26436. binormals[4] = 1.0;
  26437. binormals[5] = 0.0;
  26438. binormals[6] = 0.0;
  26439. binormals[7] = 1.0;
  26440. binormals[8] = 0.0;
  26441. binormals[9] = 0.0;
  26442. binormals[10] = 1.0;
  26443. binormals[11] = 0.0;
  26444. // -z face
  26445. binormals[12] = 0.0;
  26446. binormals[13] = 1.0;
  26447. binormals[14] = 0.0;
  26448. binormals[15] = 0.0;
  26449. binormals[16] = 1.0;
  26450. binormals[17] = 0.0;
  26451. binormals[18] = 0.0;
  26452. binormals[19] = 1.0;
  26453. binormals[20] = 0.0;
  26454. binormals[21] = 0.0;
  26455. binormals[22] = 1.0;
  26456. binormals[23] = 0.0;
  26457. // +x face
  26458. binormals[24] = 0.0;
  26459. binormals[25] = 0.0;
  26460. binormals[26] = 1.0;
  26461. binormals[27] = 0.0;
  26462. binormals[28] = 0.0;
  26463. binormals[29] = 1.0;
  26464. binormals[30] = 0.0;
  26465. binormals[31] = 0.0;
  26466. binormals[32] = 1.0;
  26467. binormals[33] = 0.0;
  26468. binormals[34] = 0.0;
  26469. binormals[35] = 1.0;
  26470. // -x face
  26471. binormals[36] = 0.0;
  26472. binormals[37] = 0.0;
  26473. binormals[38] = 1.0;
  26474. binormals[39] = 0.0;
  26475. binormals[40] = 0.0;
  26476. binormals[41] = 1.0;
  26477. binormals[42] = 0.0;
  26478. binormals[43] = 0.0;
  26479. binormals[44] = 1.0;
  26480. binormals[45] = 0.0;
  26481. binormals[46] = 0.0;
  26482. binormals[47] = 1.0;
  26483. // +y face
  26484. binormals[48] = 0.0;
  26485. binormals[49] = 0.0;
  26486. binormals[50] = 1.0;
  26487. binormals[51] = 0.0;
  26488. binormals[52] = 0.0;
  26489. binormals[53] = 1.0;
  26490. binormals[54] = 0.0;
  26491. binormals[55] = 0.0;
  26492. binormals[56] = 1.0;
  26493. binormals[57] = 0.0;
  26494. binormals[58] = 0.0;
  26495. binormals[59] = 1.0;
  26496. // -y face
  26497. binormals[60] = 0.0;
  26498. binormals[61] = 0.0;
  26499. binormals[62] = 1.0;
  26500. binormals[63] = 0.0;
  26501. binormals[64] = 0.0;
  26502. binormals[65] = 1.0;
  26503. binormals[66] = 0.0;
  26504. binormals[67] = 0.0;
  26505. binormals[68] = 1.0;
  26506. binormals[69] = 0.0;
  26507. binormals[70] = 0.0;
  26508. binormals[71] = 1.0;
  26509. attributes.binormal = new GeometryAttribute({
  26510. componentDatatype : ComponentDatatype.FLOAT,
  26511. componentsPerAttribute : 3,
  26512. values : binormals
  26513. });
  26514. }
  26515. // 12 triangles: 6 faces, 2 triangles each.
  26516. indices = new Uint16Array(6 * 2 * 3);
  26517. // +z face
  26518. indices[0] = 0;
  26519. indices[1] = 1;
  26520. indices[2] = 2;
  26521. indices[3] = 0;
  26522. indices[4] = 2;
  26523. indices[5] = 3;
  26524. // -z face
  26525. indices[6] = 4 + 2;
  26526. indices[7] = 4 + 1;
  26527. indices[8] = 4 + 0;
  26528. indices[9] = 4 + 3;
  26529. indices[10] = 4 + 2;
  26530. indices[11] = 4 + 0;
  26531. // +x face
  26532. indices[12] = 8 + 0;
  26533. indices[13] = 8 + 1;
  26534. indices[14] = 8 + 2;
  26535. indices[15] = 8 + 0;
  26536. indices[16] = 8 + 2;
  26537. indices[17] = 8 + 3;
  26538. // -x face
  26539. indices[18] = 12 + 2;
  26540. indices[19] = 12 + 1;
  26541. indices[20] = 12 + 0;
  26542. indices[21] = 12 + 3;
  26543. indices[22] = 12 + 2;
  26544. indices[23] = 12 + 0;
  26545. // +y face
  26546. indices[24] = 16 + 2;
  26547. indices[25] = 16 + 1;
  26548. indices[26] = 16 + 0;
  26549. indices[27] = 16 + 3;
  26550. indices[28] = 16 + 2;
  26551. indices[29] = 16 + 0;
  26552. // -y face
  26553. indices[30] = 20 + 0;
  26554. indices[31] = 20 + 1;
  26555. indices[32] = 20 + 2;
  26556. indices[33] = 20 + 0;
  26557. indices[34] = 20 + 2;
  26558. indices[35] = 20 + 3;
  26559. } else {
  26560. // Positions only - no need to duplicate corner points
  26561. positions = new Float64Array(8 * 3);
  26562. positions[0] = min.x;
  26563. positions[1] = min.y;
  26564. positions[2] = min.z;
  26565. positions[3] = max.x;
  26566. positions[4] = min.y;
  26567. positions[5] = min.z;
  26568. positions[6] = max.x;
  26569. positions[7] = max.y;
  26570. positions[8] = min.z;
  26571. positions[9] = min.x;
  26572. positions[10] = max.y;
  26573. positions[11] = min.z;
  26574. positions[12] = min.x;
  26575. positions[13] = min.y;
  26576. positions[14] = max.z;
  26577. positions[15] = max.x;
  26578. positions[16] = min.y;
  26579. positions[17] = max.z;
  26580. positions[18] = max.x;
  26581. positions[19] = max.y;
  26582. positions[20] = max.z;
  26583. positions[21] = min.x;
  26584. positions[22] = max.y;
  26585. positions[23] = max.z;
  26586. attributes.position = new GeometryAttribute({
  26587. componentDatatype : ComponentDatatype.DOUBLE,
  26588. componentsPerAttribute : 3,
  26589. values : positions
  26590. });
  26591. // 12 triangles: 6 faces, 2 triangles each.
  26592. indices = new Uint16Array(6 * 2 * 3);
  26593. // plane z = corner.Z
  26594. indices[0] = 4;
  26595. indices[1] = 5;
  26596. indices[2] = 6;
  26597. indices[3] = 4;
  26598. indices[4] = 6;
  26599. indices[5] = 7;
  26600. // plane z = -corner.Z
  26601. indices[6] = 1;
  26602. indices[7] = 0;
  26603. indices[8] = 3;
  26604. indices[9] = 1;
  26605. indices[10] = 3;
  26606. indices[11] = 2;
  26607. // plane x = corner.X
  26608. indices[12] = 1;
  26609. indices[13] = 6;
  26610. indices[14] = 5;
  26611. indices[15] = 1;
  26612. indices[16] = 2;
  26613. indices[17] = 6;
  26614. // plane y = corner.Y
  26615. indices[18] = 2;
  26616. indices[19] = 3;
  26617. indices[20] = 7;
  26618. indices[21] = 2;
  26619. indices[22] = 7;
  26620. indices[23] = 6;
  26621. // plane x = -corner.X
  26622. indices[24] = 3;
  26623. indices[25] = 0;
  26624. indices[26] = 4;
  26625. indices[27] = 3;
  26626. indices[28] = 4;
  26627. indices[29] = 7;
  26628. // plane y = -corner.Y
  26629. indices[30] = 0;
  26630. indices[31] = 1;
  26631. indices[32] = 5;
  26632. indices[33] = 0;
  26633. indices[34] = 5;
  26634. indices[35] = 4;
  26635. }
  26636. var diff = Cartesian3.subtract(max, min, diffScratch);
  26637. var radius = Cartesian3.magnitude(diff) * 0.5;
  26638. return new Geometry({
  26639. attributes : attributes,
  26640. indices : indices,
  26641. primitiveType : PrimitiveType.TRIANGLES,
  26642. boundingSphere : new BoundingSphere(Cartesian3.ZERO, radius)
  26643. });
  26644. };
  26645. return BoxGeometry;
  26646. });
  26647. /*global define*/
  26648. define('Core/BoxOutlineGeometry',[
  26649. './BoundingSphere',
  26650. './Cartesian3',
  26651. './ComponentDatatype',
  26652. './defaultValue',
  26653. './defined',
  26654. './DeveloperError',
  26655. './Geometry',
  26656. './GeometryAttribute',
  26657. './GeometryAttributes',
  26658. './PrimitiveType'
  26659. ], function(
  26660. BoundingSphere,
  26661. Cartesian3,
  26662. ComponentDatatype,
  26663. defaultValue,
  26664. defined,
  26665. DeveloperError,
  26666. Geometry,
  26667. GeometryAttribute,
  26668. GeometryAttributes,
  26669. PrimitiveType) {
  26670. 'use strict';
  26671. var diffScratch = new Cartesian3();
  26672. /**
  26673. * A description of the outline of a cube centered at the origin.
  26674. *
  26675. * @alias BoxOutlineGeometry
  26676. * @constructor
  26677. *
  26678. * @param {Object} options Object with the following properties:
  26679. * @param {Cartesian3} options.minimum The minimum x, y, and z coordinates of the box.
  26680. * @param {Cartesian3} options.maximum The maximum x, y, and z coordinates of the box.
  26681. *
  26682. * @see BoxOutlineGeometry.fromDimensions
  26683. * @see BoxOutlineGeometry.createGeometry
  26684. * @see Packable
  26685. *
  26686. * @example
  26687. * var box = new Cesium.BoxOutlineGeometry({
  26688. * maximum : new Cesium.Cartesian3(250000.0, 250000.0, 250000.0),
  26689. * minimum : new Cesium.Cartesian3(-250000.0, -250000.0, -250000.0)
  26690. * });
  26691. * var geometry = Cesium.BoxOutlineGeometry.createGeometry(box);
  26692. */
  26693. function BoxOutlineGeometry(options) {
  26694. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  26695. var min = options.minimum;
  26696. var max = options.maximum;
  26697. if (!defined(min)) {
  26698. throw new DeveloperError('options.minimum is required.');
  26699. }
  26700. if (!defined(max)) {
  26701. throw new DeveloperError('options.maximum is required');
  26702. }
  26703. this._min = Cartesian3.clone(min);
  26704. this._max = Cartesian3.clone(max);
  26705. this._workerName = 'createBoxOutlineGeometry';
  26706. }
  26707. /**
  26708. * Creates an outline of a cube centered at the origin given its dimensions.
  26709. *
  26710. * @param {Object} options Object with the following properties:
  26711. * @param {Cartesian3} options.dimensions The width, depth, and height of the box stored in the x, y, and z coordinates of the <code>Cartesian3</code>, respectively.
  26712. * @returns {BoxOutlineGeometry}
  26713. *
  26714. * @exception {DeveloperError} All dimensions components must be greater than or equal to zero.
  26715. *
  26716. *
  26717. * @example
  26718. * var box = Cesium.BoxOutlineGeometry.fromDimensions({
  26719. * dimensions : new Cesium.Cartesian3(500000.0, 500000.0, 500000.0)
  26720. * });
  26721. * var geometry = Cesium.BoxOutlineGeometry.createGeometry(box);
  26722. *
  26723. * @see BoxOutlineGeometry.createGeometry
  26724. */
  26725. BoxOutlineGeometry.fromDimensions = function(options) {
  26726. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  26727. var dimensions = options.dimensions;
  26728. if (!defined(dimensions)) {
  26729. throw new DeveloperError('options.dimensions is required.');
  26730. }
  26731. if (dimensions.x < 0 || dimensions.y < 0 || dimensions.z < 0) {
  26732. throw new DeveloperError('All dimensions components must be greater than or equal to zero.');
  26733. }
  26734. var corner = Cartesian3.multiplyByScalar(dimensions, 0.5, new Cartesian3());
  26735. return new BoxOutlineGeometry({
  26736. minimum : Cartesian3.negate(corner, new Cartesian3()),
  26737. maximum : corner
  26738. });
  26739. };
  26740. /**
  26741. * Creates an outline of a cube from the dimensions of an AxisAlignedBoundingBox.
  26742. *
  26743. * @param {AxisAlignedBoundingBox} boundingBox A description of the AxisAlignedBoundingBox.
  26744. * @returns {BoxOutlineGeometry}
  26745. *
  26746. *
  26747. *
  26748. * @example
  26749. * var aabb = Cesium.AxisAlignedBoundingBox.fromPoints(Cesium.Cartesian3.fromDegreesArray([
  26750. * -72.0, 40.0,
  26751. * -70.0, 35.0,
  26752. * -75.0, 30.0,
  26753. * -70.0, 30.0,
  26754. * -68.0, 40.0
  26755. * ]));
  26756. * var box = Cesium.BoxOutlineGeometry.fromAxisAlignedBoundingBox(aabb);
  26757. *
  26758. * @see BoxOutlineGeometry.createGeometry
  26759. */
  26760. BoxOutlineGeometry.fromAxisAlignedBoundingBox = function(boundingBox) {
  26761. if (!defined(boundingBox)) {
  26762. throw new DeveloperError('boundingBox is required.');
  26763. }
  26764. return new BoxOutlineGeometry({
  26765. minimum : boundingBox.minimum,
  26766. maximum : boundingBox.maximum
  26767. });
  26768. };
  26769. /**
  26770. * The number of elements used to pack the object into an array.
  26771. * @type {Number}
  26772. */
  26773. BoxOutlineGeometry.packedLength = 2 * Cartesian3.packedLength;
  26774. /**
  26775. * Stores the provided instance into the provided array.
  26776. *
  26777. * @param {BoxOutlineGeometry} value The value to pack.
  26778. * @param {Number[]} array The array to pack into.
  26779. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  26780. *
  26781. * @returns {Number[]} The array that was packed into
  26782. */
  26783. BoxOutlineGeometry.pack = function(value, array, startingIndex) {
  26784. if (!defined(value)) {
  26785. throw new DeveloperError('value is required');
  26786. }
  26787. if (!defined(array)) {
  26788. throw new DeveloperError('array is required');
  26789. }
  26790. startingIndex = defaultValue(startingIndex, 0);
  26791. Cartesian3.pack(value._min, array, startingIndex);
  26792. Cartesian3.pack(value._max, array, startingIndex + Cartesian3.packedLength);
  26793. return array;
  26794. };
  26795. var scratchMin = new Cartesian3();
  26796. var scratchMax = new Cartesian3();
  26797. var scratchOptions = {
  26798. minimum : scratchMin,
  26799. maximum : scratchMax
  26800. };
  26801. /**
  26802. * Retrieves an instance from a packed array.
  26803. *
  26804. * @param {Number[]} array The packed array.
  26805. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  26806. * @param {BoxOutlineGeometry} [result] The object into which to store the result.
  26807. * @returns {BoxOutlineGeometry} The modified result parameter or a new BoxOutlineGeometry instance if one was not provided.
  26808. */
  26809. BoxOutlineGeometry.unpack = function(array, startingIndex, result) {
  26810. if (!defined(array)) {
  26811. throw new DeveloperError('array is required');
  26812. }
  26813. startingIndex = defaultValue(startingIndex, 0);
  26814. var min = Cartesian3.unpack(array, startingIndex, scratchMin);
  26815. var max = Cartesian3.unpack(array, startingIndex + Cartesian3.packedLength, scratchMax);
  26816. if (!defined(result)) {
  26817. return new BoxOutlineGeometry(scratchOptions);
  26818. }
  26819. result._min = Cartesian3.clone(min, result._min);
  26820. result._max = Cartesian3.clone(max, result._max);
  26821. return result;
  26822. };
  26823. /**
  26824. * Computes the geometric representation of an outline of a box, including its vertices, indices, and a bounding sphere.
  26825. *
  26826. * @param {BoxOutlineGeometry} boxGeometry A description of the box outline.
  26827. * @returns {Geometry|undefined} The computed vertices and indices.
  26828. */
  26829. BoxOutlineGeometry.createGeometry = function(boxGeometry) {
  26830. var min = boxGeometry._min;
  26831. var max = boxGeometry._max;
  26832. if (Cartesian3.equals(min, max)) {
  26833. return;
  26834. }
  26835. var attributes = new GeometryAttributes();
  26836. var indices = new Uint16Array(12 * 2);
  26837. var positions = new Float64Array(8 * 3);
  26838. positions[0] = min.x;
  26839. positions[1] = min.y;
  26840. positions[2] = min.z;
  26841. positions[3] = max.x;
  26842. positions[4] = min.y;
  26843. positions[5] = min.z;
  26844. positions[6] = max.x;
  26845. positions[7] = max.y;
  26846. positions[8] = min.z;
  26847. positions[9] = min.x;
  26848. positions[10] = max.y;
  26849. positions[11] = min.z;
  26850. positions[12] = min.x;
  26851. positions[13] = min.y;
  26852. positions[14] = max.z;
  26853. positions[15] = max.x;
  26854. positions[16] = min.y;
  26855. positions[17] = max.z;
  26856. positions[18] = max.x;
  26857. positions[19] = max.y;
  26858. positions[20] = max.z;
  26859. positions[21] = min.x;
  26860. positions[22] = max.y;
  26861. positions[23] = max.z;
  26862. attributes.position = new GeometryAttribute({
  26863. componentDatatype : ComponentDatatype.DOUBLE,
  26864. componentsPerAttribute : 3,
  26865. values : positions
  26866. });
  26867. // top
  26868. indices[0] = 4;
  26869. indices[1] = 5;
  26870. indices[2] = 5;
  26871. indices[3] = 6;
  26872. indices[4] = 6;
  26873. indices[5] = 7;
  26874. indices[6] = 7;
  26875. indices[7] = 4;
  26876. // bottom
  26877. indices[8] = 0;
  26878. indices[9] = 1;
  26879. indices[10] = 1;
  26880. indices[11] = 2;
  26881. indices[12] = 2;
  26882. indices[13] = 3;
  26883. indices[14] = 3;
  26884. indices[15] = 0;
  26885. // left
  26886. indices[16] = 0;
  26887. indices[17] = 4;
  26888. indices[18] = 1;
  26889. indices[19] = 5;
  26890. //right
  26891. indices[20] = 2;
  26892. indices[21] = 6;
  26893. indices[22] = 3;
  26894. indices[23] = 7;
  26895. var diff = Cartesian3.subtract(max, min, diffScratch);
  26896. var radius = Cartesian3.magnitude(diff) * 0.5;
  26897. return new Geometry({
  26898. attributes : attributes,
  26899. indices : indices,
  26900. primitiveType : PrimitiveType.LINES,
  26901. boundingSphere : new BoundingSphere(Cartesian3.ZERO, radius)
  26902. });
  26903. };
  26904. return BoxOutlineGeometry;
  26905. });
  26906. /*global define*/
  26907. define('Core/cancelAnimationFrame',[
  26908. './defined'
  26909. ], function(
  26910. defined) {
  26911. 'use strict';
  26912. if (typeof window === 'undefined') {
  26913. return;
  26914. }
  26915. var implementation = window.cancelAnimationFrame;
  26916. (function() {
  26917. // look for vendor prefixed function
  26918. if (!defined(implementation)) {
  26919. var vendors = ['webkit', 'moz', 'ms', 'o'];
  26920. var i = 0;
  26921. var len = vendors.length;
  26922. while (i < len && !defined(implementation)) {
  26923. implementation = window[vendors[i] + 'CancelAnimationFrame'];
  26924. if (!defined(implementation)) {
  26925. implementation = window[vendors[i] + 'CancelRequestAnimationFrame'];
  26926. }
  26927. ++i;
  26928. }
  26929. }
  26930. // otherwise, assume requestAnimationFrame is based on setTimeout, so use clearTimeout
  26931. if (!defined(implementation)) {
  26932. implementation = clearTimeout;
  26933. }
  26934. })();
  26935. /**
  26936. * A browser-independent function to cancel an animation frame requested using {@link requestAnimationFrame}.
  26937. *
  26938. * @exports cancelAnimationFrame
  26939. *
  26940. * @param {Number} requestID The value returned by {@link requestAnimationFrame}.
  26941. *
  26942. * @see {@link http://www.w3.org/TR/animation-timing/#the-WindowAnimationTiming-interface|The WindowAnimationTiming interface}
  26943. */
  26944. function cancelAnimationFrame(requestID) {
  26945. // we need this extra wrapper function because the native cancelAnimationFrame
  26946. // functions must be invoked on the global scope (window), which is not the case
  26947. // if invoked as Cesium.cancelAnimationFrame(requestID)
  26948. implementation(requestID);
  26949. }
  26950. return cancelAnimationFrame;
  26951. });
  26952. /*global define*/
  26953. define('Core/Spline',[
  26954. './defaultValue',
  26955. './defined',
  26956. './DeveloperError'
  26957. ], function(
  26958. defaultValue,
  26959. defined,
  26960. DeveloperError) {
  26961. 'use strict';
  26962. /**
  26963. * Creates a curve parameterized and evaluated by time. This type describes an interface
  26964. * and is not intended to be instantiated directly.
  26965. *
  26966. * @alias Spline
  26967. * @constructor
  26968. *
  26969. * @see CatmullRomSpline
  26970. * @see HermiteSpline
  26971. * @see LinearSpline
  26972. * @see QuaternionSpline
  26973. */
  26974. function Spline() {
  26975. /**
  26976. * An array of times for the control points.
  26977. * @type {Number[]}
  26978. * @default undefined
  26979. */
  26980. this.times = undefined;
  26981. /**
  26982. * An array of control points.
  26983. * @type {Cartesian3[]|Quaternion[]}
  26984. * @default undefined
  26985. */
  26986. this.points = undefined;
  26987. DeveloperError.throwInstantiationError();
  26988. }
  26989. /**
  26990. * Evaluates the curve at a given time.
  26991. * @function
  26992. *
  26993. * @param {Number} time The time at which to evaluate the curve.
  26994. * @param {Cartesian3|Quaternion} [result] The object onto which to store the result.
  26995. * @returns {Cartesian3|Quaternion} The modified result parameter or a new instance of the point on the curve at the given time.
  26996. *
  26997. * @exception {DeveloperError} time must be in the range <code>[t<sub>0</sub>, t<sub>n</sub>]</code>, where <code>t<sub>0</sub></code>
  26998. * is the first element in the array <code>times</code> and <code>t<sub>n</sub></code> is the last element
  26999. * in the array <code>times</code>.
  27000. */
  27001. Spline.prototype.evaluate = DeveloperError.throwInstantiationError;
  27002. /**
  27003. * Finds an index <code>i</code> in <code>times</code> such that the parameter
  27004. * <code>time</code> is in the interval <code>[times[i], times[i + 1]]</code>.
  27005. *
  27006. * @param {Number} time The time.
  27007. * @param {Number} startIndex The index from which to start the search.
  27008. * @returns {Number} The index for the element at the start of the interval.
  27009. *
  27010. * @exception {DeveloperError} time must be in the range <code>[t<sub>0</sub>, t<sub>n</sub>]</code>, where <code>t<sub>0</sub></code>
  27011. * is the first element in the array <code>times</code> and <code>t<sub>n</sub></code> is the last element
  27012. * in the array <code>times</code>.
  27013. */
  27014. Spline.prototype.findTimeInterval = function(time, startIndex) {
  27015. var times = this.times;
  27016. var length = times.length;
  27017. if (!defined(time)) {
  27018. throw new DeveloperError('time is required.');
  27019. }
  27020. if (time < times[0] || time > times[length - 1]) {
  27021. throw new DeveloperError('time is out of range.');
  27022. }
  27023. // Take advantage of temporal coherence by checking current, next and previous intervals
  27024. // for containment of time.
  27025. startIndex = defaultValue(startIndex, 0);
  27026. if (time >= times[startIndex]) {
  27027. if (startIndex + 1 < length && time < times[startIndex + 1]) {
  27028. return startIndex;
  27029. } else if (startIndex + 2 < length && time < times[startIndex + 2]) {
  27030. return startIndex + 1;
  27031. }
  27032. } else if (startIndex - 1 >= 0 && time >= times[startIndex - 1]) {
  27033. return startIndex - 1;
  27034. }
  27035. // The above failed so do a linear search. For the use cases so far, the
  27036. // length of the list is less than 10. In the future, if there is a bottle neck,
  27037. // it might be here.
  27038. var i;
  27039. if (time > times[startIndex]) {
  27040. for (i = startIndex; i < length - 1; ++i) {
  27041. if (time >= times[i] && time < times[i + 1]) {
  27042. break;
  27043. }
  27044. }
  27045. } else {
  27046. for (i = startIndex - 1; i >= 0; --i) {
  27047. if (time >= times[i] && time < times[i + 1]) {
  27048. break;
  27049. }
  27050. }
  27051. }
  27052. if (i === length - 1) {
  27053. i = length - 2;
  27054. }
  27055. return i;
  27056. };
  27057. return Spline;
  27058. });
  27059. /*global define*/
  27060. define('Core/LinearSpline',[
  27061. './Cartesian3',
  27062. './defaultValue',
  27063. './defined',
  27064. './defineProperties',
  27065. './DeveloperError',
  27066. './Spline'
  27067. ], function(
  27068. Cartesian3,
  27069. defaultValue,
  27070. defined,
  27071. defineProperties,
  27072. DeveloperError,
  27073. Spline) {
  27074. 'use strict';
  27075. /**
  27076. * A spline that uses piecewise linear interpolation to create a curve.
  27077. *
  27078. * @alias LinearSpline
  27079. * @constructor
  27080. *
  27081. * @param {Object} options Object with the following properties:
  27082. * @param {Number[]} options.times An array of strictly increasing, unit-less, floating-point times at each point.
  27083. * The values are in no way connected to the clock time. They are the parameterization for the curve.
  27084. * @param {Cartesian3[]} options.points The array of {@link Cartesian3} control points.
  27085. *
  27086. * @exception {DeveloperError} points.length must be greater than or equal to 2.
  27087. * @exception {DeveloperError} times.length must be equal to points.length.
  27088. *
  27089. *
  27090. * @example
  27091. * var times = [ 0.0, 1.5, 3.0, 4.5, 6.0 ];
  27092. * var spline = new Cesium.LinearSpline({
  27093. * times : times,
  27094. * points : [
  27095. * new Cesium.Cartesian3(1235398.0, -4810983.0, 4146266.0),
  27096. * new Cesium.Cartesian3(1372574.0, -5345182.0, 4606657.0),
  27097. * new Cesium.Cartesian3(-757983.0, -5542796.0, 4514323.0),
  27098. * new Cesium.Cartesian3(-2821260.0, -5248423.0, 4021290.0),
  27099. * new Cesium.Cartesian3(-2539788.0, -4724797.0, 3620093.0)
  27100. * ]
  27101. * });
  27102. *
  27103. * var p0 = spline.evaluate(times[0]);
  27104. *
  27105. * @see HermiteSpline
  27106. * @see CatmullRomSpline
  27107. * @see QuaternionSpline
  27108. */
  27109. function LinearSpline(options) {
  27110. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  27111. var points = options.points;
  27112. var times = options.times;
  27113. if (!defined(points) || !defined(times)) {
  27114. throw new DeveloperError('points and times are required.');
  27115. }
  27116. if (points.length < 2) {
  27117. throw new DeveloperError('points.length must be greater than or equal to 2.');
  27118. }
  27119. if (times.length !== points.length) {
  27120. throw new DeveloperError('times.length must be equal to points.length.');
  27121. }
  27122. this._times = times;
  27123. this._points = points;
  27124. this._lastTimeIndex = 0;
  27125. }
  27126. defineProperties(LinearSpline.prototype, {
  27127. /**
  27128. * An array of times for the control points.
  27129. *
  27130. * @memberof LinearSpline.prototype
  27131. *
  27132. * @type {Number[]}
  27133. * @readonly
  27134. */
  27135. times : {
  27136. get : function() {
  27137. return this._times;
  27138. }
  27139. },
  27140. /**
  27141. * An array of {@link Cartesian3} control points.
  27142. *
  27143. * @memberof LinearSpline.prototype
  27144. *
  27145. * @type {Cartesian3[]}
  27146. * @readonly
  27147. */
  27148. points : {
  27149. get : function() {
  27150. return this._points;
  27151. }
  27152. }
  27153. });
  27154. /**
  27155. * Finds an index <code>i</code> in <code>times</code> such that the parameter
  27156. * <code>time</code> is in the interval <code>[times[i], times[i + 1]]</code>.
  27157. * @function
  27158. *
  27159. * @param {Number} time The time.
  27160. * @returns {Number} The index for the element at the start of the interval.
  27161. *
  27162. * @exception {DeveloperError} time must be in the range <code>[t<sub>0</sub>, t<sub>n</sub>]</code>, where <code>t<sub>0</sub></code>
  27163. * is the first element in the array <code>times</code> and <code>t<sub>n</sub></code> is the last element
  27164. * in the array <code>times</code>.
  27165. */
  27166. LinearSpline.prototype.findTimeInterval = Spline.prototype.findTimeInterval;
  27167. /**
  27168. * Evaluates the curve at a given time.
  27169. *
  27170. * @param {Number} time The time at which to evaluate the curve.
  27171. * @param {Cartesian3} [result] The object onto which to store the result.
  27172. * @returns {Cartesian3} The modified result parameter or a new instance of the point on the curve at the given time.
  27173. *
  27174. * @exception {DeveloperError} time must be in the range <code>[t<sub>0</sub>, t<sub>n</sub>]</code>, where <code>t<sub>0</sub></code>
  27175. * is the first element in the array <code>times</code> and <code>t<sub>n</sub></code> is the last element
  27176. * in the array <code>times</code>.
  27177. */
  27178. LinearSpline.prototype.evaluate = function(time, result) {
  27179. var points = this.points;
  27180. var times = this.times;
  27181. var i = this._lastTimeIndex = this.findTimeInterval(time, this._lastTimeIndex);
  27182. var u = (time - times[i]) / (times[i + 1] - times[i]);
  27183. if (!defined(result)) {
  27184. result = new Cartesian3();
  27185. }
  27186. return Cartesian3.lerp(points[i], points[i + 1], u, result);
  27187. };
  27188. return LinearSpline;
  27189. });
  27190. /*global define*/
  27191. define('Core/TridiagonalSystemSolver',[
  27192. './Cartesian3',
  27193. './defined',
  27194. './DeveloperError'
  27195. ], function(
  27196. Cartesian3,
  27197. defined,
  27198. DeveloperError) {
  27199. 'use strict';
  27200. /**
  27201. * Uses the Tridiagonal Matrix Algorithm, also known as the Thomas Algorithm, to solve
  27202. * a system of linear equations where the coefficient matrix is a tridiagonal matrix.
  27203. *
  27204. * @exports TridiagonalSystemSolver
  27205. */
  27206. var TridiagonalSystemSolver = {};
  27207. /**
  27208. * Solves a tridiagonal system of linear equations.
  27209. *
  27210. * @param {Number[]} diagonal An array with length <code>n</code> that contains the diagonal of the coefficient matrix.
  27211. * @param {Number[]} lower An array with length <code>n - 1</code> that contains the lower diagonal of the coefficient matrix.
  27212. * @param {Number[]} upper An array with length <code>n - 1</code> that contains the upper diagonal of the coefficient matrix.
  27213. * @param {Cartesian3[]} right An array of Cartesians with length <code>n</code> that is the right side of the system of equations.
  27214. *
  27215. * @exception {DeveloperError} diagonal and right must have the same lengths.
  27216. * @exception {DeveloperError} lower and upper must have the same lengths.
  27217. * @exception {DeveloperError} lower and upper must be one less than the length of diagonal.
  27218. *
  27219. * @performance Linear time.
  27220. *
  27221. * @example
  27222. * var lowerDiagonal = [1.0, 1.0, 1.0, 1.0];
  27223. * var diagonal = [2.0, 4.0, 4.0, 4.0, 2.0];
  27224. * var upperDiagonal = [1.0, 1.0, 1.0, 1.0];
  27225. * var rightHandSide = [
  27226. * new Cesium.Cartesian3(410757.0, -1595711.0, 1375302.0),
  27227. * new Cesium.Cartesian3(-5986705.0, -2190640.0, 1099600.0),
  27228. * new Cesium.Cartesian3(-12593180.0, 288588.0, -1755549.0),
  27229. * new Cesium.Cartesian3(-5349898.0, 2457005.0, -2685438.0),
  27230. * new Cesium.Cartesian3(845820.0, 1573488.0, -1205591.0)
  27231. * ];
  27232. *
  27233. * var solution = Cesium.TridiagonalSystemSolver.solve(lowerDiagonal, diagonal, upperDiagonal, rightHandSide);
  27234. *
  27235. * @returns {Cartesian3[]} An array of Cartesians with length <code>n</code> that is the solution to the tridiagonal system of equations.
  27236. */
  27237. TridiagonalSystemSolver.solve = function(lower, diagonal, upper, right) {
  27238. if (!defined(lower) || !(lower instanceof Array)) {
  27239. throw new DeveloperError('The array lower is required.');
  27240. }
  27241. if (!defined(diagonal) || !(diagonal instanceof Array)) {
  27242. throw new DeveloperError('The array diagonal is required.');
  27243. }
  27244. if (!defined(upper) || !(upper instanceof Array)) {
  27245. throw new DeveloperError('The array upper is required.');
  27246. }
  27247. if (!defined(right) || !(right instanceof Array)) {
  27248. throw new DeveloperError('The array right is required.');
  27249. }
  27250. if (diagonal.length !== right.length) {
  27251. throw new DeveloperError('diagonal and right must have the same lengths.');
  27252. }
  27253. if (lower.length !== upper.length) {
  27254. throw new DeveloperError('lower and upper must have the same lengths.');
  27255. } else if (lower.length !== diagonal.length - 1) {
  27256. throw new DeveloperError('lower and upper must be one less than the length of diagonal.');
  27257. }
  27258. var c = new Array(upper.length);
  27259. var d = new Array(right.length);
  27260. var x = new Array(right.length);
  27261. var i;
  27262. for (i = 0; i < d.length; i++) {
  27263. d[i] = new Cartesian3();
  27264. x[i] = new Cartesian3();
  27265. }
  27266. c[0] = upper[0] / diagonal[0];
  27267. d[0] = Cartesian3.multiplyByScalar(right[0], 1.0 / diagonal[0], d[0]);
  27268. var scalar;
  27269. for (i = 1; i < c.length; ++i) {
  27270. scalar = 1.0 / (diagonal[i] - c[i - 1] * lower[i - 1]);
  27271. c[i] = upper[i] * scalar;
  27272. d[i] = Cartesian3.subtract(right[i], Cartesian3.multiplyByScalar(d[i - 1], lower[i - 1], d[i]), d[i]);
  27273. d[i] = Cartesian3.multiplyByScalar(d[i], scalar, d[i]);
  27274. }
  27275. scalar = 1.0 / (diagonal[i] - c[i - 1] * lower[i - 1]);
  27276. d[i] = Cartesian3.subtract(right[i], Cartesian3.multiplyByScalar(d[i - 1], lower[i - 1], d[i]), d[i]);
  27277. d[i] = Cartesian3.multiplyByScalar(d[i], scalar, d[i]);
  27278. x[x.length - 1] = d[d.length - 1];
  27279. for (i = x.length - 2; i >= 0; --i) {
  27280. x[i] = Cartesian3.subtract(d[i], Cartesian3.multiplyByScalar(x[i + 1], c[i], x[i]), x[i]);
  27281. }
  27282. return x;
  27283. };
  27284. return TridiagonalSystemSolver;
  27285. });
  27286. /*global define*/
  27287. define('Core/HermiteSpline',[
  27288. './Cartesian3',
  27289. './Cartesian4',
  27290. './defaultValue',
  27291. './defined',
  27292. './defineProperties',
  27293. './DeveloperError',
  27294. './LinearSpline',
  27295. './Matrix4',
  27296. './Spline',
  27297. './TridiagonalSystemSolver'
  27298. ], function(
  27299. Cartesian3,
  27300. Cartesian4,
  27301. defaultValue,
  27302. defined,
  27303. defineProperties,
  27304. DeveloperError,
  27305. LinearSpline,
  27306. Matrix4,
  27307. Spline,
  27308. TridiagonalSystemSolver) {
  27309. 'use strict';
  27310. var scratchLower = [];
  27311. var scratchDiagonal = [];
  27312. var scratchUpper = [];
  27313. var scratchRight = [];
  27314. function generateClamped(points, firstTangent, lastTangent) {
  27315. var l = scratchLower;
  27316. var u = scratchUpper;
  27317. var d = scratchDiagonal;
  27318. var r = scratchRight;
  27319. l.length = u.length = points.length - 1;
  27320. d.length = r.length = points.length;
  27321. var i;
  27322. l[0] = d[0] = 1.0;
  27323. u[0] = 0.0;
  27324. var right = r[0];
  27325. if (!defined(right)) {
  27326. right = r[0] = new Cartesian3();
  27327. }
  27328. Cartesian3.clone(firstTangent, right);
  27329. for (i = 1; i < l.length - 1; ++i) {
  27330. l[i] = u[i] = 1.0;
  27331. d[i] = 4.0;
  27332. right = r[i];
  27333. if (!defined(right)) {
  27334. right = r[i] = new Cartesian3();
  27335. }
  27336. Cartesian3.subtract(points[i + 1], points[i - 1], right);
  27337. Cartesian3.multiplyByScalar(right, 3.0, right);
  27338. }
  27339. l[i] = 0.0;
  27340. u[i] = 1.0;
  27341. d[i] = 4.0;
  27342. right = r[i];
  27343. if (!defined(right)) {
  27344. right = r[i] = new Cartesian3();
  27345. }
  27346. Cartesian3.subtract(points[i + 1], points[i - 1], right);
  27347. Cartesian3.multiplyByScalar(right, 3.0, right);
  27348. d[i + 1] = 1.0;
  27349. right = r[i + 1];
  27350. if (!defined(right)) {
  27351. right = r[i + 1] = new Cartesian3();
  27352. }
  27353. Cartesian3.clone(lastTangent, right);
  27354. return TridiagonalSystemSolver.solve(l, d, u, r);
  27355. }
  27356. function generateNatural(points){
  27357. var l = scratchLower;
  27358. var u = scratchUpper;
  27359. var d = scratchDiagonal;
  27360. var r = scratchRight;
  27361. l.length = u.length = points.length - 1;
  27362. d.length = r.length = points.length;
  27363. var i;
  27364. l[0] = u[0] = 1.0;
  27365. d[0] = 2.0;
  27366. var right = r[0];
  27367. if (!defined(right)) {
  27368. right = r[0] = new Cartesian3();
  27369. }
  27370. Cartesian3.subtract(points[1], points[0], right);
  27371. Cartesian3.multiplyByScalar(right, 3.0, right);
  27372. for (i = 1; i < l.length; ++i) {
  27373. l[i] = u[i] = 1.0;
  27374. d[i] = 4.0;
  27375. right = r[i];
  27376. if (!defined(right)) {
  27377. right = r[i] = new Cartesian3();
  27378. }
  27379. Cartesian3.subtract(points[i + 1], points[i - 1], right);
  27380. Cartesian3.multiplyByScalar(right, 3.0, right);
  27381. }
  27382. d[i] = 2.0;
  27383. right = r[i];
  27384. if (!defined(right)) {
  27385. right = r[i] = new Cartesian3();
  27386. }
  27387. Cartesian3.subtract(points[i], points[i - 1], right);
  27388. Cartesian3.multiplyByScalar(right, 3.0, right);
  27389. return TridiagonalSystemSolver.solve(l, d, u, r);
  27390. }
  27391. /**
  27392. * A Hermite spline is a cubic interpolating spline. Points, incoming tangents, outgoing tangents, and times
  27393. * must be defined for each control point. The outgoing tangents are defined for points [0, n - 2] and the incoming
  27394. * tangents are defined for points [1, n - 1]. For example, when interpolating a segment of the curve between <code>points[i]</code> and
  27395. * <code>points[i + 1]</code>, the tangents at the points will be <code>outTangents[i]</code> and <code>inTangents[i]</code>,
  27396. * respectively.
  27397. *
  27398. * @alias HermiteSpline
  27399. * @constructor
  27400. *
  27401. * @param {Object} options Object with the following properties:
  27402. * @param {Number[]} options.times An array of strictly increasing, unit-less, floating-point times at each point.
  27403. * The values are in no way connected to the clock time. They are the parameterization for the curve.
  27404. * @param {Cartesian3[]} options.points The array of {@link Cartesian3} control points.
  27405. * @param {Cartesian3[]} options.inTangents The array of {@link Cartesian3} incoming tangents at each control point.
  27406. * @param {Cartesian3[]} options.outTangents The array of {@link Cartesian3} outgoing tangents at each control point.
  27407. *
  27408. * @exception {DeveloperError} points.length must be greater than or equal to 2.
  27409. * @exception {DeveloperError} times.length must be equal to points.length.
  27410. * @exception {DeveloperError} inTangents and outTangents must have a length equal to points.length - 1.
  27411. *
  27412. *
  27413. * @example
  27414. * // Create a G<sup>1</sup> continuous Hermite spline
  27415. * var times = [ 0.0, 1.5, 3.0, 4.5, 6.0 ];
  27416. * var spline = new Cesium.HermiteSpline({
  27417. * times : times,
  27418. * points : [
  27419. * new Cesium.Cartesian3(1235398.0, -4810983.0, 4146266.0),
  27420. * new Cesium.Cartesian3(1372574.0, -5345182.0, 4606657.0),
  27421. * new Cesium.Cartesian3(-757983.0, -5542796.0, 4514323.0),
  27422. * new Cesium.Cartesian3(-2821260.0, -5248423.0, 4021290.0),
  27423. * new Cesium.Cartesian3(-2539788.0, -4724797.0, 3620093.0)
  27424. * ],
  27425. * outTangents : [
  27426. * new Cesium.Cartesian3(1125196, -161816, 270551),
  27427. * new Cesium.Cartesian3(-996690.5, -365906.5, 184028.5),
  27428. * new Cesium.Cartesian3(-2096917, 48379.5, -292683.5),
  27429. * new Cesium.Cartesian3(-890902.5, 408999.5, -447115)
  27430. * ],
  27431. * inTangents : [
  27432. * new Cesium.Cartesian3(-1993381, -731813, 368057),
  27433. * new Cesium.Cartesian3(-4193834, 96759, -585367),
  27434. * new Cesium.Cartesian3(-1781805, 817999, -894230),
  27435. * new Cesium.Cartesian3(1165345, 112641, 47281)
  27436. * ]
  27437. * });
  27438. *
  27439. * var p0 = spline.evaluate(times[0]);
  27440. *
  27441. * @see CatmullRomSpline
  27442. * @see LinearSpline
  27443. * @see QuaternionSpline
  27444. */
  27445. function HermiteSpline(options) {
  27446. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  27447. var points = options.points;
  27448. var times = options.times;
  27449. var inTangents = options.inTangents;
  27450. var outTangents = options.outTangents;
  27451. if (!defined(points) || !defined(times) || !defined(inTangents) || !defined(outTangents)) {
  27452. throw new DeveloperError('times, points, inTangents, and outTangents are required.');
  27453. }
  27454. if (points.length < 2) {
  27455. throw new DeveloperError('points.length must be greater than or equal to 2.');
  27456. }
  27457. if (times.length !== points.length) {
  27458. throw new DeveloperError('times.length must be equal to points.length.');
  27459. }
  27460. if (inTangents.length !== outTangents.length || inTangents.length !== points.length - 1) {
  27461. throw new DeveloperError('inTangents and outTangents must have a length equal to points.length - 1.');
  27462. }
  27463. this._times = times;
  27464. this._points = points;
  27465. this._inTangents = inTangents;
  27466. this._outTangents = outTangents;
  27467. this._lastTimeIndex = 0;
  27468. }
  27469. defineProperties(HermiteSpline.prototype, {
  27470. /**
  27471. * An array of times for the control points.
  27472. *
  27473. * @memberof HermiteSpline.prototype
  27474. *
  27475. * @type {Number[]}
  27476. * @readonly
  27477. */
  27478. times : {
  27479. get : function() {
  27480. return this._times;
  27481. }
  27482. },
  27483. /**
  27484. * An array of {@link Cartesian3} control points.
  27485. *
  27486. * @memberof HermiteSpline.prototype
  27487. *
  27488. * @type {Cartesian3[]}
  27489. * @readonly
  27490. */
  27491. points : {
  27492. get : function() {
  27493. return this._points;
  27494. }
  27495. },
  27496. /**
  27497. * An array of {@link Cartesian3} incoming tangents at each control point.
  27498. *
  27499. * @memberof HermiteSpline.prototype
  27500. *
  27501. * @type {Cartesian3[]}
  27502. * @readonly
  27503. */
  27504. inTangents : {
  27505. get : function() {
  27506. return this._inTangents;
  27507. }
  27508. },
  27509. /**
  27510. * An array of {@link Cartesian3} outgoing tangents at each control point.
  27511. *
  27512. * @memberof HermiteSpline.prototype
  27513. *
  27514. * @type {Cartesian3[]}
  27515. * @readonly
  27516. */
  27517. outTangents : {
  27518. get : function() {
  27519. return this._outTangents;
  27520. }
  27521. }
  27522. });
  27523. /**
  27524. * Creates a spline where the tangents at each control point are the same.
  27525. * The curves are guaranteed to be at least in the class C<sup>1</sup>.
  27526. *
  27527. * @param {Object} options Object with the following properties:
  27528. * @param {Number[]} options.times The array of control point times.
  27529. * @param {Cartesian3[]} options.points The array of control points.
  27530. * @param {Cartesian3[]} options.tangents The array of tangents at the control points.
  27531. * @returns {HermiteSpline} A hermite spline.
  27532. *
  27533. * @exception {DeveloperError} points, times and tangents are required.
  27534. * @exception {DeveloperError} points.length must be greater than or equal to 2.
  27535. * @exception {DeveloperError} times, points and tangents must have the same length.
  27536. *
  27537. * @example
  27538. * var points = [
  27539. * new Cesium.Cartesian3(1235398.0, -4810983.0, 4146266.0),
  27540. * new Cesium.Cartesian3(1372574.0, -5345182.0, 4606657.0),
  27541. * new Cesium.Cartesian3(-757983.0, -5542796.0, 4514323.0),
  27542. * new Cesium.Cartesian3(-2821260.0, -5248423.0, 4021290.0),
  27543. * new Cesium.Cartesian3(-2539788.0, -4724797.0, 3620093.0)
  27544. * ];
  27545. *
  27546. * // Add tangents
  27547. * var tangents = new Array(points.length);
  27548. * tangents[0] = new Cesium.Cartesian3(1125196, -161816, 270551);
  27549. * var temp = new Cesium.Cartesian3();
  27550. * for (var i = 1; i < tangents.length - 1; ++i) {
  27551. * tangents[i] = Cesium.Cartesian3.multiplyByScalar(Cesium.Cartesian3.subtract(points[i + 1], points[i - 1], temp), 0.5, new Cesium.Cartesian3());
  27552. * }
  27553. * tangents[tangents.length - 1] = new Cesium.Cartesian3(1165345, 112641, 47281);
  27554. *
  27555. * var spline = Cesium.HermiteSpline.createC1({
  27556. * times : times,
  27557. * points : points,
  27558. * tangents : tangents
  27559. * });
  27560. */
  27561. HermiteSpline.createC1 = function(options) {
  27562. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  27563. var times = options.times;
  27564. var points = options.points;
  27565. var tangents = options.tangents;
  27566. if (!defined(points) || !defined(times) || !defined(tangents)) {
  27567. throw new DeveloperError('points, times and tangents are required.');
  27568. }
  27569. if (points.length < 2) {
  27570. throw new DeveloperError('points.length must be greater than or equal to 2.');
  27571. }
  27572. if (times.length !== points.length || times.length !== tangents.length) {
  27573. throw new DeveloperError('times, points and tangents must have the same length.');
  27574. }
  27575. var outTangents = tangents.slice(0, tangents.length - 1);
  27576. var inTangents = tangents.slice(1, tangents.length);
  27577. return new HermiteSpline({
  27578. times : times,
  27579. points : points,
  27580. inTangents : inTangents,
  27581. outTangents : outTangents
  27582. });
  27583. };
  27584. /**
  27585. * Creates a natural cubic spline. The tangents at the control points are generated
  27586. * to create a curve in the class C<sup>2</sup>.
  27587. *
  27588. * @param {Object} options Object with the following properties:
  27589. * @param {Number[]} options.times The array of control point times.
  27590. * @param {Cartesian3[]} options.points The array of control points.
  27591. * @returns {HermiteSpline|LinearSpline} A hermite spline or a linear spline if less than 3 control points were given.
  27592. *
  27593. * @exception {DeveloperError} points and times are required.
  27594. * @exception {DeveloperError} points.length must be greater than or equal to 2.
  27595. * @exception {DeveloperError} times.length must be equal to points.length.
  27596. *
  27597. * @example
  27598. * // Create a natural cubic spline above the earth from Philadelphia to Los Angeles.
  27599. * var spline = Cesium.HermiteSpline.createNaturalCubic({
  27600. * times : [ 0.0, 1.5, 3.0, 4.5, 6.0 ],
  27601. * points : [
  27602. * new Cesium.Cartesian3(1235398.0, -4810983.0, 4146266.0),
  27603. * new Cesium.Cartesian3(1372574.0, -5345182.0, 4606657.0),
  27604. * new Cesium.Cartesian3(-757983.0, -5542796.0, 4514323.0),
  27605. * new Cesium.Cartesian3(-2821260.0, -5248423.0, 4021290.0),
  27606. * new Cesium.Cartesian3(-2539788.0, -4724797.0, 3620093.0)
  27607. * ]
  27608. * });
  27609. */
  27610. HermiteSpline.createNaturalCubic = function(options) {
  27611. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  27612. var times = options.times;
  27613. var points = options.points;
  27614. if (!defined(points) || !defined(times)) {
  27615. throw new DeveloperError('points and times are required.');
  27616. }
  27617. if (points.length < 2) {
  27618. throw new DeveloperError('points.length must be greater than or equal to 2.');
  27619. }
  27620. if (times.length !== points.length) {
  27621. throw new DeveloperError('times.length must be equal to points.length.');
  27622. }
  27623. if (points.length < 3) {
  27624. return new LinearSpline({
  27625. points : points,
  27626. times : times
  27627. });
  27628. }
  27629. var tangents = generateNatural(points);
  27630. var outTangents = tangents.slice(0, tangents.length - 1);
  27631. var inTangents = tangents.slice(1, tangents.length);
  27632. return new HermiteSpline({
  27633. times : times,
  27634. points : points,
  27635. inTangents : inTangents,
  27636. outTangents : outTangents
  27637. });
  27638. };
  27639. /**
  27640. * Creates a clamped cubic spline. The tangents at the interior control points are generated
  27641. * to create a curve in the class C<sup>2</sup>.
  27642. *
  27643. * @param {Object} options Object with the following properties:
  27644. * @param {Number[]} options.times The array of control point times.
  27645. * @param {Cartesian3[]} options.points The array of control points.
  27646. * @param {Cartesian3} options.firstTangent The outgoing tangent of the first control point.
  27647. * @param {Cartesian3} options.lastTangent The incoming tangent of the last control point.
  27648. * @returns {HermiteSpline|LinearSpline} A hermite spline or a linear spline if less than 3 control points were given.
  27649. *
  27650. * @exception {DeveloperError} points, times, firstTangent and lastTangent are required.
  27651. * @exception {DeveloperError} points.length must be greater than or equal to 2.
  27652. * @exception {DeveloperError} times.length must be equal to points.length.
  27653. *
  27654. * @example
  27655. * // Create a clamped cubic spline above the earth from Philadelphia to Los Angeles.
  27656. * var spline = Cesium.HermiteSpline.createClampedCubic({
  27657. * times : [ 0.0, 1.5, 3.0, 4.5, 6.0 ],
  27658. * points : [
  27659. * new Cesium.Cartesian3(1235398.0, -4810983.0, 4146266.0),
  27660. * new Cesium.Cartesian3(1372574.0, -5345182.0, 4606657.0),
  27661. * new Cesium.Cartesian3(-757983.0, -5542796.0, 4514323.0),
  27662. * new Cesium.Cartesian3(-2821260.0, -5248423.0, 4021290.0),
  27663. * new Cesium.Cartesian3(-2539788.0, -4724797.0, 3620093.0)
  27664. * ],
  27665. * firstTangent : new Cesium.Cartesian3(1125196, -161816, 270551),
  27666. * lastTangent : new Cesium.Cartesian3(1165345, 112641, 47281)
  27667. * });
  27668. */
  27669. HermiteSpline.createClampedCubic = function(options) {
  27670. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  27671. var times = options.times;
  27672. var points = options.points;
  27673. var firstTangent = options.firstTangent;
  27674. var lastTangent = options.lastTangent;
  27675. if (!defined(points) || !defined(times) || !defined(firstTangent) || !defined(lastTangent)) {
  27676. throw new DeveloperError('points, times, firstTangent and lastTangent are required.');
  27677. }
  27678. if (points.length < 2) {
  27679. throw new DeveloperError('points.length must be greater than or equal to 2.');
  27680. }
  27681. if (times.length !== points.length) {
  27682. throw new DeveloperError('times.length must be equal to points.length.');
  27683. }
  27684. if (points.length < 3) {
  27685. return new LinearSpline({
  27686. points : points,
  27687. times : times
  27688. });
  27689. }
  27690. var tangents = generateClamped(points, firstTangent, lastTangent);
  27691. var outTangents = tangents.slice(0, tangents.length - 1);
  27692. var inTangents = tangents.slice(1, tangents.length);
  27693. return new HermiteSpline({
  27694. times : times,
  27695. points : points,
  27696. inTangents : inTangents,
  27697. outTangents : outTangents
  27698. });
  27699. };
  27700. HermiteSpline.hermiteCoefficientMatrix = new Matrix4(
  27701. 2.0, -3.0, 0.0, 1.0,
  27702. -2.0, 3.0, 0.0, 0.0,
  27703. 1.0, -2.0, 1.0, 0.0,
  27704. 1.0, -1.0, 0.0, 0.0);
  27705. /**
  27706. * Finds an index <code>i</code> in <code>times</code> such that the parameter
  27707. * <code>time</code> is in the interval <code>[times[i], times[i + 1]]</code>.
  27708. * @function
  27709. *
  27710. * @param {Number} time The time.
  27711. * @returns {Number} The index for the element at the start of the interval.
  27712. *
  27713. * @exception {DeveloperError} time must be in the range <code>[t<sub>0</sub>, t<sub>n</sub>]</code>, where <code>t<sub>0</sub></code>
  27714. * is the first element in the array <code>times</code> and <code>t<sub>n</sub></code> is the last element
  27715. * in the array <code>times</code>.
  27716. */
  27717. HermiteSpline.prototype.findTimeInterval = Spline.prototype.findTimeInterval;
  27718. var scratchTimeVec = new Cartesian4();
  27719. var scratchTemp = new Cartesian3();
  27720. /**
  27721. * Evaluates the curve at a given time.
  27722. *
  27723. * @param {Number} time The time at which to evaluate the curve.
  27724. * @param {Cartesian3} [result] The object onto which to store the result.
  27725. * @returns {Cartesian3} The modified result parameter or a new instance of the point on the curve at the given time.
  27726. *
  27727. * @exception {DeveloperError} time must be in the range <code>[t<sub>0</sub>, t<sub>n</sub>]</code>, where <code>t<sub>0</sub></code>
  27728. * is the first element in the array <code>times</code> and <code>t<sub>n</sub></code> is the last element
  27729. * in the array <code>times</code>.
  27730. */
  27731. HermiteSpline.prototype.evaluate = function(time, result) {
  27732. if (!defined(result)) {
  27733. result = new Cartesian3();
  27734. }
  27735. var points = this.points;
  27736. var times = this.times;
  27737. var inTangents = this.inTangents;
  27738. var outTangents = this.outTangents;
  27739. var i = this._lastTimeIndex = this.findTimeInterval(time, this._lastTimeIndex);
  27740. var u = (time - times[i]) / (times[i + 1] - times[i]);
  27741. var timeVec = scratchTimeVec;
  27742. timeVec.z = u;
  27743. timeVec.y = u * u;
  27744. timeVec.x = timeVec.y * u;
  27745. timeVec.w = 1.0;
  27746. var coefs = Matrix4.multiplyByVector(HermiteSpline.hermiteCoefficientMatrix, timeVec, timeVec);
  27747. result = Cartesian3.multiplyByScalar(points[i], coefs.x, result);
  27748. Cartesian3.multiplyByScalar(points[i + 1], coefs.y, scratchTemp);
  27749. Cartesian3.add(result, scratchTemp, result);
  27750. Cartesian3.multiplyByScalar(outTangents[i], coefs.z, scratchTemp);
  27751. Cartesian3.add(result, scratchTemp, result);
  27752. Cartesian3.multiplyByScalar(inTangents[i], coefs.w, scratchTemp);
  27753. return Cartesian3.add(result, scratchTemp, result);
  27754. };
  27755. return HermiteSpline;
  27756. });
  27757. /*global define*/
  27758. define('Core/CatmullRomSpline',[
  27759. './Cartesian3',
  27760. './Cartesian4',
  27761. './defaultValue',
  27762. './defined',
  27763. './defineProperties',
  27764. './DeveloperError',
  27765. './HermiteSpline',
  27766. './Matrix4',
  27767. './Spline'
  27768. ], function(
  27769. Cartesian3,
  27770. Cartesian4,
  27771. defaultValue,
  27772. defined,
  27773. defineProperties,
  27774. DeveloperError,
  27775. HermiteSpline,
  27776. Matrix4,
  27777. Spline) {
  27778. 'use strict';
  27779. var scratchTimeVec = new Cartesian4();
  27780. var scratchTemp0 = new Cartesian3();
  27781. var scratchTemp1 = new Cartesian3();
  27782. function createEvaluateFunction(spline) {
  27783. var points = spline.points;
  27784. var times = spline.times;
  27785. if (points.length < 3) {
  27786. var t0 = times[0];
  27787. var invSpan = 1.0 / (times[1] - t0);
  27788. var p0 = points[0];
  27789. var p1 = points[1];
  27790. return function(time, result) {
  27791. if (!defined(result)){
  27792. result = new Cartesian3();
  27793. }
  27794. var u = (time - t0) * invSpan;
  27795. return Cartesian3.lerp(p0, p1, u, result);
  27796. };
  27797. }
  27798. return function(time, result) {
  27799. if (!defined(result)) {
  27800. result = new Cartesian3();
  27801. }
  27802. var i = spline._lastTimeIndex = spline.findTimeInterval(time, spline._lastTimeIndex);
  27803. var u = (time - times[i]) / (times[i + 1] - times[i]);
  27804. var timeVec = scratchTimeVec;
  27805. timeVec.z = u;
  27806. timeVec.y = u * u;
  27807. timeVec.x = timeVec.y * u;
  27808. timeVec.w = 1.0;
  27809. var p0;
  27810. var p1;
  27811. var p2;
  27812. var p3;
  27813. var coefs;
  27814. if (i === 0) {
  27815. p0 = points[0];
  27816. p1 = points[1];
  27817. p2 = spline.firstTangent;
  27818. p3 = Cartesian3.subtract(points[2], p0, scratchTemp0);
  27819. Cartesian3.multiplyByScalar(p3, 0.5, p3);
  27820. coefs = Matrix4.multiplyByVector(HermiteSpline.hermiteCoefficientMatrix, timeVec, timeVec);
  27821. } else if (i === points.length - 2) {
  27822. p0 = points[i];
  27823. p1 = points[i + 1];
  27824. p3 = spline.lastTangent;
  27825. p2 = Cartesian3.subtract(p1, points[i - 1], scratchTemp0);
  27826. Cartesian3.multiplyByScalar(p2, 0.5, p2);
  27827. coefs = Matrix4.multiplyByVector(HermiteSpline.hermiteCoefficientMatrix, timeVec, timeVec);
  27828. } else {
  27829. p0 = points[i - 1];
  27830. p1 = points[i];
  27831. p2 = points[i + 1];
  27832. p3 = points[i + 2];
  27833. coefs = Matrix4.multiplyByVector(CatmullRomSpline.catmullRomCoefficientMatrix, timeVec, timeVec);
  27834. }
  27835. result = Cartesian3.multiplyByScalar(p0, coefs.x, result);
  27836. Cartesian3.multiplyByScalar(p1, coefs.y, scratchTemp1);
  27837. Cartesian3.add(result, scratchTemp1, result);
  27838. Cartesian3.multiplyByScalar(p2, coefs.z, scratchTemp1);
  27839. Cartesian3.add(result, scratchTemp1, result);
  27840. Cartesian3.multiplyByScalar(p3, coefs.w, scratchTemp1);
  27841. return Cartesian3.add(result, scratchTemp1, result);
  27842. };
  27843. }
  27844. var firstTangentScratch = new Cartesian3();
  27845. var lastTangentScratch = new Cartesian3();
  27846. /**
  27847. * A Catmull-Rom spline is a cubic spline where the tangent at control points,
  27848. * except the first and last, are computed using the previous and next control points.
  27849. * Catmull-Rom splines are in the class C<sup>1</sup>.
  27850. *
  27851. * @alias CatmullRomSpline
  27852. * @constructor
  27853. *
  27854. * @param {Object} options Object with the following properties:
  27855. * @param {Number[]} options.times An array of strictly increasing, unit-less, floating-point times at each point.
  27856. * The values are in no way connected to the clock time. They are the parameterization for the curve.
  27857. * @param {Cartesian3[]} options.points The array of {@link Cartesian3} control points.
  27858. * @param {Cartesian3} [options.firstTangent] The tangent of the curve at the first control point.
  27859. * If the tangent is not given, it will be estimated.
  27860. * @param {Cartesian3} [options.lastTangent] The tangent of the curve at the last control point.
  27861. * If the tangent is not given, it will be estimated.
  27862. *
  27863. * @exception {DeveloperError} points.length must be greater than or equal to 2.
  27864. * @exception {DeveloperError} times.length must be equal to points.length.
  27865. *
  27866. *
  27867. * @example
  27868. * // spline above the earth from Philadelphia to Los Angeles
  27869. * var spline = new Cesium.CatmullRomSpline({
  27870. * times : [ 0.0, 1.5, 3.0, 4.5, 6.0 ],
  27871. * points : [
  27872. * new Cesium.Cartesian3(1235398.0, -4810983.0, 4146266.0),
  27873. * new Cesium.Cartesian3(1372574.0, -5345182.0, 4606657.0),
  27874. * new Cesium.Cartesian3(-757983.0, -5542796.0, 4514323.0),
  27875. * new Cesium.Cartesian3(-2821260.0, -5248423.0, 4021290.0),
  27876. * new Cesium.Cartesian3(-2539788.0, -4724797.0, 3620093.0)
  27877. * ]
  27878. * });
  27879. *
  27880. * var p0 = spline.evaluate(times[i]); // equal to positions[i]
  27881. * var p1 = spline.evaluate(times[i] + delta); // interpolated value when delta < times[i + 1] - times[i]
  27882. *
  27883. * @see HermiteSpline
  27884. * @see LinearSpline
  27885. * @see QuaternionSpline
  27886. */
  27887. function CatmullRomSpline(options) {
  27888. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  27889. var points = options.points;
  27890. var times = options.times;
  27891. var firstTangent = options.firstTangent;
  27892. var lastTangent = options.lastTangent;
  27893. if (!defined(points) || !defined(times)) {
  27894. throw new DeveloperError('points and times are required.');
  27895. }
  27896. if (points.length < 2) {
  27897. throw new DeveloperError('points.length must be greater than or equal to 2.');
  27898. }
  27899. if (times.length !== points.length) {
  27900. throw new DeveloperError('times.length must be equal to points.length.');
  27901. }
  27902. if (points.length > 2) {
  27903. if (!defined(firstTangent)) {
  27904. firstTangent = firstTangentScratch;
  27905. Cartesian3.multiplyByScalar(points[1], 2.0, firstTangent);
  27906. Cartesian3.subtract(firstTangent, points[2], firstTangent);
  27907. Cartesian3.subtract(firstTangent, points[0], firstTangent);
  27908. Cartesian3.multiplyByScalar(firstTangent, 0.5, firstTangent);
  27909. }
  27910. if (!defined(lastTangent)) {
  27911. var n = points.length - 1;
  27912. lastTangent = lastTangentScratch;
  27913. Cartesian3.multiplyByScalar(points[n - 1], 2.0, lastTangent);
  27914. Cartesian3.subtract(points[n], lastTangent, lastTangent);
  27915. Cartesian3.add(lastTangent, points[n - 2], lastTangent);
  27916. Cartesian3.multiplyByScalar(lastTangent, 0.5, lastTangent);
  27917. }
  27918. }
  27919. this._times = times;
  27920. this._points = points;
  27921. this._firstTangent = Cartesian3.clone(firstTangent);
  27922. this._lastTangent = Cartesian3.clone(lastTangent);
  27923. this._evaluateFunction = createEvaluateFunction(this);
  27924. this._lastTimeIndex = 0;
  27925. }
  27926. defineProperties(CatmullRomSpline.prototype, {
  27927. /**
  27928. * An array of times for the control points.
  27929. *
  27930. * @memberof CatmullRomSpline.prototype
  27931. *
  27932. * @type {Number[]}
  27933. * @readonly
  27934. */
  27935. times : {
  27936. get : function() {
  27937. return this._times;
  27938. }
  27939. },
  27940. /**
  27941. * An array of {@link Cartesian3} control points.
  27942. *
  27943. * @memberof CatmullRomSpline.prototype
  27944. *
  27945. * @type {Cartesian3[]}
  27946. * @readonly
  27947. */
  27948. points : {
  27949. get : function() {
  27950. return this._points;
  27951. }
  27952. },
  27953. /**
  27954. * The tangent at the first control point.
  27955. *
  27956. * @memberof CatmullRomSpline.prototype
  27957. *
  27958. * @type {Cartesian3}
  27959. * @readonly
  27960. */
  27961. firstTangent : {
  27962. get : function() {
  27963. return this._firstTangent;
  27964. }
  27965. },
  27966. /**
  27967. * The tangent at the last control point.
  27968. *
  27969. * @memberof CatmullRomSpline.prototype
  27970. *
  27971. * @type {Cartesian3}
  27972. * @readonly
  27973. */
  27974. lastTangent : {
  27975. get : function() {
  27976. return this._lastTangent;
  27977. }
  27978. }
  27979. });
  27980. /**
  27981. * @private
  27982. */
  27983. CatmullRomSpline.catmullRomCoefficientMatrix = new Matrix4(
  27984. -0.5, 1.0, -0.5, 0.0,
  27985. 1.5, -2.5, 0.0, 1.0,
  27986. -1.5, 2.0, 0.5, 0.0,
  27987. 0.5, -0.5, 0.0, 0.0);
  27988. /**
  27989. * Finds an index <code>i</code> in <code>times</code> such that the parameter
  27990. * <code>time</code> is in the interval <code>[times[i], times[i + 1]]</code>.
  27991. * @function
  27992. *
  27993. * @param {Number} time The time.
  27994. * @returns {Number} The index for the element at the start of the interval.
  27995. *
  27996. * @exception {DeveloperError} time must be in the range <code>[t<sub>0</sub>, t<sub>n</sub>]</code>, where <code>t<sub>0</sub></code>
  27997. * is the first element in the array <code>times</code> and <code>t<sub>n</sub></code> is the last element
  27998. * in the array <code>times</code>.
  27999. */
  28000. CatmullRomSpline.prototype.findTimeInterval = Spline.prototype.findTimeInterval;
  28001. /**
  28002. * Evaluates the curve at a given time.
  28003. *
  28004. * @param {Number} time The time at which to evaluate the curve.
  28005. * @param {Cartesian3} [result] The object onto which to store the result.
  28006. * @returns {Cartesian3} The modified result parameter or a new instance of the point on the curve at the given time.
  28007. *
  28008. * @exception {DeveloperError} time must be in the range <code>[t<sub>0</sub>, t<sub>n</sub>]</code>, where <code>t<sub>0</sub></code>
  28009. * is the first element in the array <code>times</code> and <code>t<sub>n</sub></code> is the last element
  28010. * in the array <code>times</code>.
  28011. */
  28012. CatmullRomSpline.prototype.evaluate = function(time, result) {
  28013. return this._evaluateFunction(time, result);
  28014. };
  28015. return CatmullRomSpline;
  28016. });
  28017. /*global define*/
  28018. define('Core/IndexDatatype',[
  28019. './defined',
  28020. './DeveloperError',
  28021. './freezeObject',
  28022. './Math',
  28023. './WebGLConstants'
  28024. ], function(
  28025. defined,
  28026. DeveloperError,
  28027. freezeObject,
  28028. CesiumMath,
  28029. WebGLConstants) {
  28030. 'use strict';
  28031. /**
  28032. * Constants for WebGL index datatypes. These corresponds to the
  28033. * <code>type</code> parameter of {@link http://www.khronos.org/opengles/sdk/docs/man/xhtml/glDrawElements.xml|drawElements}.
  28034. *
  28035. * @exports IndexDatatype
  28036. */
  28037. var IndexDatatype = {
  28038. /**
  28039. * 8-bit unsigned byte corresponding to <code>UNSIGNED_BYTE</code> and the type
  28040. * of an element in <code>Uint8Array</code>.
  28041. *
  28042. * @type {Number}
  28043. * @constant
  28044. */
  28045. UNSIGNED_BYTE : WebGLConstants.UNSIGNED_BYTE,
  28046. /**
  28047. * 16-bit unsigned short corresponding to <code>UNSIGNED_SHORT</code> and the type
  28048. * of an element in <code>Uint16Array</code>.
  28049. *
  28050. * @type {Number}
  28051. * @constant
  28052. */
  28053. UNSIGNED_SHORT : WebGLConstants.UNSIGNED_SHORT,
  28054. /**
  28055. * 32-bit unsigned int corresponding to <code>UNSIGNED_INT</code> and the type
  28056. * of an element in <code>Uint32Array</code>.
  28057. *
  28058. * @type {Number}
  28059. * @constant
  28060. */
  28061. UNSIGNED_INT : WebGLConstants.UNSIGNED_INT
  28062. };
  28063. /**
  28064. * Returns the size, in bytes, of the corresponding datatype.
  28065. *
  28066. * @param {IndexDatatype} indexDatatype The index datatype to get the size of.
  28067. * @returns {Number} The size in bytes.
  28068. *
  28069. * @example
  28070. * // Returns 2
  28071. * var size = Cesium.IndexDatatype.getSizeInBytes(Cesium.IndexDatatype.UNSIGNED_SHORT);
  28072. */
  28073. IndexDatatype.getSizeInBytes = function(indexDatatype) {
  28074. switch(indexDatatype) {
  28075. case IndexDatatype.UNSIGNED_BYTE:
  28076. return Uint8Array.BYTES_PER_ELEMENT;
  28077. case IndexDatatype.UNSIGNED_SHORT:
  28078. return Uint16Array.BYTES_PER_ELEMENT;
  28079. case IndexDatatype.UNSIGNED_INT:
  28080. return Uint32Array.BYTES_PER_ELEMENT;
  28081. }
  28082. throw new DeveloperError('indexDatatype is required and must be a valid IndexDatatype constant.');
  28083. };
  28084. /**
  28085. * Validates that the provided index datatype is a valid {@link IndexDatatype}.
  28086. *
  28087. * @param {IndexDatatype} indexDatatype The index datatype to validate.
  28088. * @returns {Boolean} <code>true</code> if the provided index datatype is a valid value; otherwise, <code>false</code>.
  28089. *
  28090. * @example
  28091. * if (!Cesium.IndexDatatype.validate(indexDatatype)) {
  28092. * throw new Cesium.DeveloperError('indexDatatype must be a valid value.');
  28093. * }
  28094. */
  28095. IndexDatatype.validate = function(indexDatatype) {
  28096. return defined(indexDatatype) &&
  28097. (indexDatatype === IndexDatatype.UNSIGNED_BYTE ||
  28098. indexDatatype === IndexDatatype.UNSIGNED_SHORT ||
  28099. indexDatatype === IndexDatatype.UNSIGNED_INT);
  28100. };
  28101. /**
  28102. * Creates a typed array that will store indices, using either <code><Uint16Array</code>
  28103. * or <code>Uint32Array</code> depending on the number of vertices.
  28104. *
  28105. * @param {Number} numberOfVertices Number of vertices that the indices will reference.
  28106. * @param {Any} indicesLengthOrArray Passed through to the typed array constructor.
  28107. * @returns {Uint16Array|Uint32Array} A <code>Uint16Array</code> or <code>Uint32Array</code> constructed with <code>indicesLengthOrArray</code>.
  28108. *
  28109. * @example
  28110. * this.indices = Cesium.IndexDatatype.createTypedArray(positions.length / 3, numberOfIndices);
  28111. */
  28112. IndexDatatype.createTypedArray = function(numberOfVertices, indicesLengthOrArray) {
  28113. if (!defined(numberOfVertices)) {
  28114. throw new DeveloperError('numberOfVertices is required.');
  28115. }
  28116. if (numberOfVertices >= CesiumMath.SIXTY_FOUR_KILOBYTES) {
  28117. return new Uint32Array(indicesLengthOrArray);
  28118. }
  28119. return new Uint16Array(indicesLengthOrArray);
  28120. };
  28121. /**
  28122. * Creates a typed array from a source array buffer. The resulting typed array will store indices, using either <code><Uint16Array</code>
  28123. * or <code>Uint32Array</code> depending on the number of vertices.
  28124. *
  28125. * @param {Number} numberOfVertices Number of vertices that the indices will reference.
  28126. * @param {ArrayBuffer} sourceArray Passed through to the typed array constructor.
  28127. * @param {Number} byteOffset Passed through to the typed array constructor.
  28128. * @param {Number} length Passed through to the typed array constructor.
  28129. * @returns {Uint16Array|Uint32Array} A <code>Uint16Array</code> or <code>Uint32Array</code> constructed with <code>sourceArray</code>, <code>byteOffset</code>, and <code>length</code>.
  28130. *
  28131. */
  28132. IndexDatatype.createTypedArrayFromArrayBuffer = function(numberOfVertices, sourceArray, byteOffset, length) {
  28133. if (!defined(numberOfVertices)) {
  28134. throw new DeveloperError('numberOfVertices is required.');
  28135. }
  28136. if (!defined(sourceArray)) {
  28137. throw new DeveloperError('sourceArray is required.');
  28138. }
  28139. if (!defined(byteOffset)) {
  28140. throw new DeveloperError('byteOffset is required.');
  28141. }
  28142. if (numberOfVertices >= CesiumMath.SIXTY_FOUR_KILOBYTES) {
  28143. return new Uint32Array(sourceArray, byteOffset, length);
  28144. }
  28145. return new Uint16Array(sourceArray, byteOffset, length);
  28146. };
  28147. return freezeObject(IndexDatatype);
  28148. });
  28149. /*global define*/
  28150. define('Core/loadArrayBuffer',[
  28151. './loadWithXhr'
  28152. ], function(
  28153. loadWithXhr) {
  28154. 'use strict';
  28155. /**
  28156. * Asynchronously loads the given URL as raw binary data. Returns a promise that will resolve to
  28157. * an ArrayBuffer once loaded, or reject if the URL failed to load. The data is loaded
  28158. * using XMLHttpRequest, which means that in order to make requests to another origin,
  28159. * the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
  28160. *
  28161. * @exports loadArrayBuffer
  28162. *
  28163. * @param {String|Promise.<String>} url The URL of the binary data, or a promise for the URL.
  28164. * @param {Object} [headers] HTTP headers to send with the requests.
  28165. * @returns {Promise.<ArrayBuffer>} a promise that will resolve to the requested data when loaded.
  28166. *
  28167. *
  28168. * @example
  28169. * // load a single URL asynchronously
  28170. * Cesium.loadArrayBuffer('some/url').then(function(arrayBuffer) {
  28171. * // use the data
  28172. * }).otherwise(function(error) {
  28173. * // an error occurred
  28174. * });
  28175. *
  28176. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  28177. * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
  28178. */
  28179. function loadArrayBuffer(url, headers) {
  28180. return loadWithXhr({
  28181. url : url,
  28182. responseType : 'arraybuffer',
  28183. headers : headers
  28184. });
  28185. }
  28186. return loadArrayBuffer;
  28187. });
  28188. /*global define*/
  28189. define('Core/Intersections2D',[
  28190. './Cartesian3',
  28191. './defined',
  28192. './DeveloperError'
  28193. ], function(
  28194. Cartesian3,
  28195. defined,
  28196. DeveloperError) {
  28197. 'use strict';
  28198. /**
  28199. * Contains functions for operating on 2D triangles.
  28200. *
  28201. * @exports Intersections2D
  28202. */
  28203. var Intersections2D = {};
  28204. /**
  28205. * Splits a 2D triangle at given axis-aligned threshold value and returns the resulting
  28206. * polygon on a given side of the threshold. The resulting polygon may have 0, 1, 2,
  28207. * 3, or 4 vertices.
  28208. *
  28209. * @param {Number} threshold The threshold coordinate value at which to clip the triangle.
  28210. * @param {Boolean} keepAbove true to keep the portion of the triangle above the threshold, or false
  28211. * to keep the portion below.
  28212. * @param {Number} u0 The coordinate of the first vertex in the triangle, in counter-clockwise order.
  28213. * @param {Number} u1 The coordinate of the second vertex in the triangle, in counter-clockwise order.
  28214. * @param {Number} u2 The coordinate of the third vertex in the triangle, in counter-clockwise order.
  28215. * @param {Number[]} [result] The array into which to copy the result. If this parameter is not supplied,
  28216. * a new array is constructed and returned.
  28217. * @returns {Number[]} The polygon that results after the clip, specified as a list of
  28218. * vertices. The vertices are specified in counter-clockwise order.
  28219. * Each vertex is either an index from the existing list (identified as
  28220. * a 0, 1, or 2) or -1 indicating a new vertex not in the original triangle.
  28221. * For new vertices, the -1 is followed by three additional numbers: the
  28222. * index of each of the two original vertices forming the line segment that
  28223. * the new vertex lies on, and the fraction of the distance from the first
  28224. * vertex to the second one.
  28225. *
  28226. * @example
  28227. * var result = Cesium.Intersections2D.clipTriangleAtAxisAlignedThreshold(0.5, false, 0.2, 0.6, 0.4);
  28228. * // result === [2, 0, -1, 1, 0, 0.25, -1, 1, 2, 0.5]
  28229. */
  28230. Intersections2D.clipTriangleAtAxisAlignedThreshold = function(threshold, keepAbove, u0, u1, u2, result) {
  28231. if (!defined(threshold)) {
  28232. throw new DeveloperError('threshold is required.');
  28233. }
  28234. if (!defined(keepAbove)) {
  28235. throw new DeveloperError('keepAbove is required.');
  28236. }
  28237. if (!defined(u0)) {
  28238. throw new DeveloperError('u0 is required.');
  28239. }
  28240. if (!defined(u1)) {
  28241. throw new DeveloperError('u1 is required.');
  28242. }
  28243. if (!defined(u2)) {
  28244. throw new DeveloperError('u2 is required.');
  28245. }
  28246. if (!defined(result)) {
  28247. result = [];
  28248. } else {
  28249. result.length = 0;
  28250. }
  28251. var u0Behind;
  28252. var u1Behind;
  28253. var u2Behind;
  28254. if (keepAbove) {
  28255. u0Behind = u0 < threshold;
  28256. u1Behind = u1 < threshold;
  28257. u2Behind = u2 < threshold;
  28258. } else {
  28259. u0Behind = u0 > threshold;
  28260. u1Behind = u1 > threshold;
  28261. u2Behind = u2 > threshold;
  28262. }
  28263. var numBehind = u0Behind + u1Behind + u2Behind;
  28264. var u01Ratio;
  28265. var u02Ratio;
  28266. var u12Ratio;
  28267. var u10Ratio;
  28268. var u20Ratio;
  28269. var u21Ratio;
  28270. if (numBehind === 1) {
  28271. if (u0Behind) {
  28272. u01Ratio = (threshold - u0) / (u1 - u0);
  28273. u02Ratio = (threshold - u0) / (u2 - u0);
  28274. result.push(1);
  28275. result.push(2);
  28276. if (u02Ratio !== 1.0) {
  28277. result.push(-1);
  28278. result.push(0);
  28279. result.push(2);
  28280. result.push(u02Ratio);
  28281. }
  28282. if (u01Ratio !== 1.0) {
  28283. result.push(-1);
  28284. result.push(0);
  28285. result.push(1);
  28286. result.push(u01Ratio);
  28287. }
  28288. } else if (u1Behind) {
  28289. u12Ratio = (threshold - u1) / (u2 - u1);
  28290. u10Ratio = (threshold - u1) / (u0 - u1);
  28291. result.push(2);
  28292. result.push(0);
  28293. if (u10Ratio !== 1.0) {
  28294. result.push(-1);
  28295. result.push(1);
  28296. result.push(0);
  28297. result.push(u10Ratio);
  28298. }
  28299. if (u12Ratio !== 1.0) {
  28300. result.push(-1);
  28301. result.push(1);
  28302. result.push(2);
  28303. result.push(u12Ratio);
  28304. }
  28305. } else if (u2Behind) {
  28306. u20Ratio = (threshold - u2) / (u0 - u2);
  28307. u21Ratio = (threshold - u2) / (u1 - u2);
  28308. result.push(0);
  28309. result.push(1);
  28310. if (u21Ratio !== 1.0) {
  28311. result.push(-1);
  28312. result.push(2);
  28313. result.push(1);
  28314. result.push(u21Ratio);
  28315. }
  28316. if (u20Ratio !== 1.0) {
  28317. result.push(-1);
  28318. result.push(2);
  28319. result.push(0);
  28320. result.push(u20Ratio);
  28321. }
  28322. }
  28323. } else if (numBehind === 2) {
  28324. if (!u0Behind && u0 !== threshold) {
  28325. u10Ratio = (threshold - u1) / (u0 - u1);
  28326. u20Ratio = (threshold - u2) / (u0 - u2);
  28327. result.push(0);
  28328. result.push(-1);
  28329. result.push(1);
  28330. result.push(0);
  28331. result.push(u10Ratio);
  28332. result.push(-1);
  28333. result.push(2);
  28334. result.push(0);
  28335. result.push(u20Ratio);
  28336. } else if (!u1Behind && u1 !== threshold) {
  28337. u21Ratio = (threshold - u2) / (u1 - u2);
  28338. u01Ratio = (threshold - u0) / (u1 - u0);
  28339. result.push(1);
  28340. result.push(-1);
  28341. result.push(2);
  28342. result.push(1);
  28343. result.push(u21Ratio);
  28344. result.push(-1);
  28345. result.push(0);
  28346. result.push(1);
  28347. result.push(u01Ratio);
  28348. } else if (!u2Behind && u2 !== threshold) {
  28349. u02Ratio = (threshold - u0) / (u2 - u0);
  28350. u12Ratio = (threshold - u1) / (u2 - u1);
  28351. result.push(2);
  28352. result.push(-1);
  28353. result.push(0);
  28354. result.push(2);
  28355. result.push(u02Ratio);
  28356. result.push(-1);
  28357. result.push(1);
  28358. result.push(2);
  28359. result.push(u12Ratio);
  28360. }
  28361. } else if (numBehind !== 3) {
  28362. // Completely in front of threshold
  28363. result.push(0);
  28364. result.push(1);
  28365. result.push(2);
  28366. }
  28367. // else Completely behind threshold
  28368. return result;
  28369. };
  28370. /**
  28371. * Compute the barycentric coordinates of a 2D position within a 2D triangle.
  28372. *
  28373. * @param {Number} x The x coordinate of the position for which to find the barycentric coordinates.
  28374. * @param {Number} y The y coordinate of the position for which to find the barycentric coordinates.
  28375. * @param {Number} x1 The x coordinate of the triangle's first vertex.
  28376. * @param {Number} y1 The y coordinate of the triangle's first vertex.
  28377. * @param {Number} x2 The x coordinate of the triangle's second vertex.
  28378. * @param {Number} y2 The y coordinate of the triangle's second vertex.
  28379. * @param {Number} x3 The x coordinate of the triangle's third vertex.
  28380. * @param {Number} y3 The y coordinate of the triangle's third vertex.
  28381. * @param {Cartesian3} [result] The instance into to which to copy the result. If this parameter
  28382. * is undefined, a new instance is created and returned.
  28383. * @returns {Cartesian3} The barycentric coordinates of the position within the triangle.
  28384. *
  28385. * @example
  28386. * var result = Cesium.Intersections2D.computeBarycentricCoordinates(0.0, 0.0, 0.0, 1.0, -1, -0.5, 1, -0.5);
  28387. * // result === new Cesium.Cartesian3(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0);
  28388. */
  28389. Intersections2D.computeBarycentricCoordinates = function(x, y, x1, y1, x2, y2, x3, y3, result) {
  28390. if (!defined(x)) {
  28391. throw new DeveloperError('x is required.');
  28392. }
  28393. if (!defined(y)) {
  28394. throw new DeveloperError('y is required.');
  28395. }
  28396. if (!defined(x1)) {
  28397. throw new DeveloperError('x1 is required.');
  28398. }
  28399. if (!defined(y1)) {
  28400. throw new DeveloperError('y1 is required.');
  28401. }
  28402. if (!defined(x2)) {
  28403. throw new DeveloperError('x2 is required.');
  28404. }
  28405. if (!defined(y2)) {
  28406. throw new DeveloperError('y2 is required.');
  28407. }
  28408. if (!defined(x3)) {
  28409. throw new DeveloperError('x3 is required.');
  28410. }
  28411. if (!defined(y3)) {
  28412. throw new DeveloperError('y3 is required.');
  28413. }
  28414. var x1mx3 = x1 - x3;
  28415. var x3mx2 = x3 - x2;
  28416. var y2my3 = y2 - y3;
  28417. var y1my3 = y1 - y3;
  28418. var inverseDeterminant = 1.0 / (y2my3 * x1mx3 + x3mx2 * y1my3);
  28419. var ymy3 = y - y3;
  28420. var xmx3 = x - x3;
  28421. var l1 = (y2my3 * xmx3 + x3mx2 * ymy3) * inverseDeterminant;
  28422. var l2 = (-y1my3 * xmx3 + x1mx3 * ymy3) * inverseDeterminant;
  28423. var l3 = 1.0 - l1 - l2;
  28424. if (defined(result)) {
  28425. result.x = l1;
  28426. result.y = l2;
  28427. result.z = l3;
  28428. return result;
  28429. } else {
  28430. return new Cartesian3(l1, l2, l3);
  28431. }
  28432. };
  28433. return Intersections2D;
  28434. });
  28435. /*global define*/
  28436. define('Core/QuantizedMeshTerrainData',[
  28437. '../ThirdParty/when',
  28438. './BoundingSphere',
  28439. './Cartesian2',
  28440. './Cartesian3',
  28441. './defaultValue',
  28442. './defined',
  28443. './defineProperties',
  28444. './DeveloperError',
  28445. './IndexDatatype',
  28446. './Intersections2D',
  28447. './Math',
  28448. './OrientedBoundingBox',
  28449. './TaskProcessor',
  28450. './TerrainEncoding',
  28451. './TerrainMesh'
  28452. ], function(
  28453. when,
  28454. BoundingSphere,
  28455. Cartesian2,
  28456. Cartesian3,
  28457. defaultValue,
  28458. defined,
  28459. defineProperties,
  28460. DeveloperError,
  28461. IndexDatatype,
  28462. Intersections2D,
  28463. CesiumMath,
  28464. OrientedBoundingBox,
  28465. TaskProcessor,
  28466. TerrainEncoding,
  28467. TerrainMesh) {
  28468. 'use strict';
  28469. /**
  28470. * Terrain data for a single tile where the terrain data is represented as a quantized mesh. A quantized
  28471. * mesh consists of three vertex attributes, longitude, latitude, and height. All attributes are expressed
  28472. * as 16-bit values in the range 0 to 32767. Longitude and latitude are zero at the southwest corner
  28473. * of the tile and 32767 at the northeast corner. Height is zero at the minimum height in the tile
  28474. * and 32767 at the maximum height in the tile.
  28475. *
  28476. * @alias QuantizedMeshTerrainData
  28477. * @constructor
  28478. *
  28479. * @param {Object} options Object with the following properties:
  28480. * @param {Uint16Array} options.quantizedVertices The buffer containing the quantized mesh.
  28481. * @param {Uint16Array|Uint32Array} options.indices The indices specifying how the quantized vertices are linked
  28482. * together into triangles. Each three indices specifies one triangle.
  28483. * @param {Number} options.minimumHeight The minimum terrain height within the tile, in meters above the ellipsoid.
  28484. * @param {Number} options.maximumHeight The maximum terrain height within the tile, in meters above the ellipsoid.
  28485. * @param {BoundingSphere} options.boundingSphere A sphere bounding all of the vertices in the mesh.
  28486. * @param {OrientedBoundingBox} [options.orientedBoundingBox] An OrientedBoundingBox bounding all of the vertices in the mesh.
  28487. * @param {Cartesian3} options.horizonOcclusionPoint The horizon occlusion point of the mesh. If this point
  28488. * is below the horizon, the entire tile is assumed to be below the horizon as well.
  28489. * The point is expressed in ellipsoid-scaled coordinates.
  28490. * @param {Number[]} options.westIndices The indices of the vertices on the western edge of the tile.
  28491. * @param {Number[]} options.southIndices The indices of the vertices on the southern edge of the tile.
  28492. * @param {Number[]} options.eastIndices The indices of the vertices on the eastern edge of the tile.
  28493. * @param {Number[]} options.northIndices The indices of the vertices on the northern edge of the tile.
  28494. * @param {Number} options.westSkirtHeight The height of the skirt to add on the western edge of the tile.
  28495. * @param {Number} options.southSkirtHeight The height of the skirt to add on the southern edge of the tile.
  28496. * @param {Number} options.eastSkirtHeight The height of the skirt to add on the eastern edge of the tile.
  28497. * @param {Number} options.northSkirtHeight The height of the skirt to add on the northern edge of the tile.
  28498. * @param {Number} [options.childTileMask=15] A bit mask indicating which of this tile's four children exist.
  28499. * If a child's bit is set, geometry will be requested for that tile as well when it
  28500. * is needed. If the bit is cleared, the child tile is not requested and geometry is
  28501. * instead upsampled from the parent. The bit values are as follows:
  28502. * <table>
  28503. * <tr><th>Bit Position</th><th>Bit Value</th><th>Child Tile</th></tr>
  28504. * <tr><td>0</td><td>1</td><td>Southwest</td></tr>
  28505. * <tr><td>1</td><td>2</td><td>Southeast</td></tr>
  28506. * <tr><td>2</td><td>4</td><td>Northwest</td></tr>
  28507. * <tr><td>3</td><td>8</td><td>Northeast</td></tr>
  28508. * </table>
  28509. * @param {Boolean} [options.createdByUpsampling=false] True if this instance was created by upsampling another instance;
  28510. * otherwise, false.
  28511. * @param {Uint8Array} [options.encodedNormals] The buffer containing per vertex normals, encoded using 'oct' encoding
  28512. * @param {Uint8Array} [options.waterMask] The buffer containing the watermask.
  28513. *
  28514. *
  28515. * @example
  28516. * var data = new Cesium.QuantizedMeshTerrainData({
  28517. * minimumHeight : -100,
  28518. * maximumHeight : 2101,
  28519. * quantizedVertices : new Uint16Array([// order is SW NW SE NE
  28520. * // longitude
  28521. * 0, 0, 32767, 32767,
  28522. * // latitude
  28523. * 0, 32767, 0, 32767,
  28524. * // heights
  28525. * 16384, 0, 32767, 16384]),
  28526. * indices : new Uint16Array([0, 3, 1,
  28527. * 0, 2, 3]),
  28528. * boundingSphere : new Cesium.BoundingSphere(new Cesium.Cartesian3(1.0, 2.0, 3.0), 10000),
  28529. * orientedBoundingBox : new Cesium.OrientedBoundingBox(new Cesium.Cartesian3(1.0, 2.0, 3.0), Cesium.Matrix3.fromRotationX(Cesium.Math.PI, new Cesium.Matrix3())),
  28530. * horizonOcclusionPoint : new Cesium.Cartesian3(3.0, 2.0, 1.0),
  28531. * westIndices : [0, 1],
  28532. * southIndices : [0, 1],
  28533. * eastIndices : [2, 3],
  28534. * northIndices : [1, 3],
  28535. * westSkirtHeight : 1.0,
  28536. * southSkirtHeight : 1.0,
  28537. * eastSkirtHeight : 1.0,
  28538. * northSkirtHeight : 1.0
  28539. * });
  28540. *
  28541. * @see TerrainData
  28542. * @see HeightmapTerrainData
  28543. */
  28544. function QuantizedMeshTerrainData(options) {
  28545. if (!defined(options) || !defined(options.quantizedVertices)) {
  28546. throw new DeveloperError('options.quantizedVertices is required.');
  28547. }
  28548. if (!defined(options.indices)) {
  28549. throw new DeveloperError('options.indices is required.');
  28550. }
  28551. if (!defined(options.minimumHeight)) {
  28552. throw new DeveloperError('options.minimumHeight is required.');
  28553. }
  28554. if (!defined(options.maximumHeight)) {
  28555. throw new DeveloperError('options.maximumHeight is required.');
  28556. }
  28557. if (!defined(options.maximumHeight)) {
  28558. throw new DeveloperError('options.maximumHeight is required.');
  28559. }
  28560. if (!defined(options.boundingSphere)) {
  28561. throw new DeveloperError('options.boundingSphere is required.');
  28562. }
  28563. if (!defined(options.horizonOcclusionPoint)) {
  28564. throw new DeveloperError('options.horizonOcclusionPoint is required.');
  28565. }
  28566. if (!defined(options.westIndices)) {
  28567. throw new DeveloperError('options.westIndices is required.');
  28568. }
  28569. if (!defined(options.southIndices)) {
  28570. throw new DeveloperError('options.southIndices is required.');
  28571. }
  28572. if (!defined(options.eastIndices)) {
  28573. throw new DeveloperError('options.eastIndices is required.');
  28574. }
  28575. if (!defined(options.northIndices)) {
  28576. throw new DeveloperError('options.northIndices is required.');
  28577. }
  28578. if (!defined(options.westSkirtHeight)) {
  28579. throw new DeveloperError('options.westSkirtHeight is required.');
  28580. }
  28581. if (!defined(options.southSkirtHeight)) {
  28582. throw new DeveloperError('options.southSkirtHeight is required.');
  28583. }
  28584. if (!defined(options.eastSkirtHeight)) {
  28585. throw new DeveloperError('options.eastSkirtHeight is required.');
  28586. }
  28587. if (!defined(options.northSkirtHeight)) {
  28588. throw new DeveloperError('options.northSkirtHeight is required.');
  28589. }
  28590. this._quantizedVertices = options.quantizedVertices;
  28591. this._encodedNormals = options.encodedNormals;
  28592. this._indices = options.indices;
  28593. this._minimumHeight = options.minimumHeight;
  28594. this._maximumHeight = options.maximumHeight;
  28595. this._boundingSphere = options.boundingSphere;
  28596. this._orientedBoundingBox = options.orientedBoundingBox;
  28597. this._horizonOcclusionPoint = options.horizonOcclusionPoint;
  28598. var vertexCount = this._quantizedVertices.length / 3;
  28599. var uValues = this._uValues = this._quantizedVertices.subarray(0, vertexCount);
  28600. var vValues = this._vValues = this._quantizedVertices.subarray(vertexCount, 2 * vertexCount);
  28601. this._heightValues = this._quantizedVertices.subarray(2 * vertexCount, 3 * vertexCount);
  28602. // We don't assume that we can count on the edge vertices being sorted by u or v.
  28603. function sortByV(a, b) {
  28604. return vValues[a] - vValues[b];
  28605. }
  28606. function sortByU(a, b) {
  28607. return uValues[a] - uValues[b];
  28608. }
  28609. this._westIndices = sortIndicesIfNecessary(options.westIndices, sortByV, vertexCount);
  28610. this._southIndices = sortIndicesIfNecessary(options.southIndices, sortByU, vertexCount);
  28611. this._eastIndices = sortIndicesIfNecessary(options.eastIndices, sortByV, vertexCount);
  28612. this._northIndices = sortIndicesIfNecessary(options.northIndices, sortByU, vertexCount);
  28613. this._westSkirtHeight = options.westSkirtHeight;
  28614. this._southSkirtHeight = options.southSkirtHeight;
  28615. this._eastSkirtHeight = options.eastSkirtHeight;
  28616. this._northSkirtHeight = options.northSkirtHeight;
  28617. this._childTileMask = defaultValue(options.childTileMask, 15);
  28618. this._createdByUpsampling = defaultValue(options.createdByUpsampling, false);
  28619. this._waterMask = options.waterMask;
  28620. this._mesh = undefined;
  28621. }
  28622. defineProperties(QuantizedMeshTerrainData.prototype, {
  28623. /**
  28624. * The water mask included in this terrain data, if any. A water mask is a rectangular
  28625. * Uint8Array or image where a value of 255 indicates water and a value of 0 indicates land.
  28626. * Values in between 0 and 255 are allowed as well to smoothly blend between land and water.
  28627. * @memberof QuantizedMeshTerrainData.prototype
  28628. * @type {Uint8Array|Image|Canvas}
  28629. */
  28630. waterMask : {
  28631. get : function() {
  28632. return this._waterMask;
  28633. }
  28634. }
  28635. });
  28636. var arrayScratch = [];
  28637. function sortIndicesIfNecessary(indices, sortFunction, vertexCount) {
  28638. arrayScratch.length = indices.length;
  28639. var needsSort = false;
  28640. for (var i = 0, len = indices.length; i < len; ++i) {
  28641. arrayScratch[i] = indices[i];
  28642. needsSort = needsSort || (i > 0 && sortFunction(indices[i - 1], indices[i]) > 0);
  28643. }
  28644. if (needsSort) {
  28645. arrayScratch.sort(sortFunction);
  28646. return IndexDatatype.createTypedArray(vertexCount, arrayScratch);
  28647. } else {
  28648. return indices;
  28649. }
  28650. }
  28651. var createMeshTaskProcessor = new TaskProcessor('createVerticesFromQuantizedTerrainMesh');
  28652. /**
  28653. * Creates a {@link TerrainMesh} from this terrain data.
  28654. *
  28655. * @private
  28656. *
  28657. * @param {TilingScheme} tilingScheme The tiling scheme to which this tile belongs.
  28658. * @param {Number} x The X coordinate of the tile for which to create the terrain data.
  28659. * @param {Number} y The Y coordinate of the tile for which to create the terrain data.
  28660. * @param {Number} level The level of the tile for which to create the terrain data.
  28661. * @param {Number} [exaggeration=1.0] The scale used to exaggerate the terrain.
  28662. * @returns {Promise.<TerrainMesh>|undefined} A promise for the terrain mesh, or undefined if too many
  28663. * asynchronous mesh creations are already in progress and the operation should
  28664. * be retried later.
  28665. */
  28666. QuantizedMeshTerrainData.prototype.createMesh = function(tilingScheme, x, y, level, exaggeration) {
  28667. if (!defined(tilingScheme)) {
  28668. throw new DeveloperError('tilingScheme is required.');
  28669. }
  28670. if (!defined(x)) {
  28671. throw new DeveloperError('x is required.');
  28672. }
  28673. if (!defined(y)) {
  28674. throw new DeveloperError('y is required.');
  28675. }
  28676. if (!defined(level)) {
  28677. throw new DeveloperError('level is required.');
  28678. }
  28679. var ellipsoid = tilingScheme.ellipsoid;
  28680. var rectangle = tilingScheme.tileXYToRectangle(x, y, level);
  28681. exaggeration = defaultValue(exaggeration, 1.0);
  28682. var verticesPromise = createMeshTaskProcessor.scheduleTask({
  28683. minimumHeight : this._minimumHeight,
  28684. maximumHeight : this._maximumHeight,
  28685. quantizedVertices : this._quantizedVertices,
  28686. octEncodedNormals : this._encodedNormals,
  28687. includeWebMercatorT : true,
  28688. indices : this._indices,
  28689. westIndices : this._westIndices,
  28690. southIndices : this._southIndices,
  28691. eastIndices : this._eastIndices,
  28692. northIndices : this._northIndices,
  28693. westSkirtHeight : this._westSkirtHeight,
  28694. southSkirtHeight : this._southSkirtHeight,
  28695. eastSkirtHeight : this._eastSkirtHeight,
  28696. northSkirtHeight : this._northSkirtHeight,
  28697. rectangle : rectangle,
  28698. relativeToCenter : this._boundingSphere.center,
  28699. ellipsoid : ellipsoid,
  28700. exaggeration : exaggeration
  28701. });
  28702. if (!defined(verticesPromise)) {
  28703. // Postponed
  28704. return undefined;
  28705. }
  28706. var that = this;
  28707. return when(verticesPromise, function(result) {
  28708. var vertexCount = that._quantizedVertices.length / 3;
  28709. vertexCount += that._westIndices.length + that._southIndices.length + that._eastIndices.length + that._northIndices.length;
  28710. var indicesTypedArray = IndexDatatype.createTypedArray(vertexCount, result.indices);
  28711. var vertices = new Float32Array(result.vertices);
  28712. var rtc = result.center;
  28713. var minimumHeight = result.minimumHeight;
  28714. var maximumHeight = result.maximumHeight;
  28715. var boundingSphere = defaultValue(result.boundingSphere, that._boundingSphere);
  28716. var obb = defaultValue(result.orientedBoundingBox, that._orientedBoundingBox);
  28717. var occlusionPoint = that._horizonOcclusionPoint;
  28718. var stride = result.vertexStride;
  28719. var terrainEncoding = TerrainEncoding.clone(result.encoding);
  28720. that._skirtIndex = result.skirtIndex;
  28721. that._vertexCountWithoutSkirts = that._quantizedVertices.length / 3;
  28722. that._mesh = new TerrainMesh(
  28723. rtc,
  28724. vertices,
  28725. indicesTypedArray,
  28726. minimumHeight,
  28727. maximumHeight,
  28728. boundingSphere,
  28729. occlusionPoint,
  28730. stride,
  28731. obb,
  28732. terrainEncoding,
  28733. exaggeration);
  28734. // Free memory received from server after mesh is created.
  28735. that._quantizedVertices = undefined;
  28736. that._encodedNormals = undefined;
  28737. that._indices = undefined;
  28738. that._uValues = undefined;
  28739. that._vValues = undefined;
  28740. that._heightValues = undefined;
  28741. that._westIndices = undefined;
  28742. that._southIndices = undefined;
  28743. that._eastIndices = undefined;
  28744. that._northIndices = undefined;
  28745. return that._mesh;
  28746. });
  28747. };
  28748. var upsampleTaskProcessor = new TaskProcessor('upsampleQuantizedTerrainMesh');
  28749. /**
  28750. * Upsamples this terrain data for use by a descendant tile. The resulting instance will contain a subset of the
  28751. * vertices in this instance, interpolated if necessary.
  28752. *
  28753. * @param {TilingScheme} tilingScheme The tiling scheme of this terrain data.
  28754. * @param {Number} thisX The X coordinate of this tile in the tiling scheme.
  28755. * @param {Number} thisY The Y coordinate of this tile in the tiling scheme.
  28756. * @param {Number} thisLevel The level of this tile in the tiling scheme.
  28757. * @param {Number} descendantX The X coordinate within the tiling scheme of the descendant tile for which we are upsampling.
  28758. * @param {Number} descendantY The Y coordinate within the tiling scheme of the descendant tile for which we are upsampling.
  28759. * @param {Number} descendantLevel The level within the tiling scheme of the descendant tile for which we are upsampling.
  28760. * @returns {Promise.<QuantizedMeshTerrainData>|undefined} A promise for upsampled heightmap terrain data for the descendant tile,
  28761. * or undefined if too many asynchronous upsample operations are in progress and the request has been
  28762. * deferred.
  28763. */
  28764. QuantizedMeshTerrainData.prototype.upsample = function(tilingScheme, thisX, thisY, thisLevel, descendantX, descendantY, descendantLevel) {
  28765. if (!defined(tilingScheme)) {
  28766. throw new DeveloperError('tilingScheme is required.');
  28767. }
  28768. if (!defined(thisX)) {
  28769. throw new DeveloperError('thisX is required.');
  28770. }
  28771. if (!defined(thisY)) {
  28772. throw new DeveloperError('thisY is required.');
  28773. }
  28774. if (!defined(thisLevel)) {
  28775. throw new DeveloperError('thisLevel is required.');
  28776. }
  28777. if (!defined(descendantX)) {
  28778. throw new DeveloperError('descendantX is required.');
  28779. }
  28780. if (!defined(descendantY)) {
  28781. throw new DeveloperError('descendantY is required.');
  28782. }
  28783. if (!defined(descendantLevel)) {
  28784. throw new DeveloperError('descendantLevel is required.');
  28785. }
  28786. var levelDifference = descendantLevel - thisLevel;
  28787. if (levelDifference > 1) {
  28788. throw new DeveloperError('Upsampling through more than one level at a time is not currently supported.');
  28789. }
  28790. var mesh = this._mesh;
  28791. if (!defined(this._mesh)) {
  28792. return undefined;
  28793. }
  28794. var isEastChild = thisX * 2 !== descendantX;
  28795. var isNorthChild = thisY * 2 === descendantY;
  28796. var ellipsoid = tilingScheme.ellipsoid;
  28797. var childRectangle = tilingScheme.tileXYToRectangle(descendantX, descendantY, descendantLevel);
  28798. var upsamplePromise = upsampleTaskProcessor.scheduleTask({
  28799. vertices : mesh.vertices,
  28800. vertexCountWithoutSkirts : this._vertexCountWithoutSkirts,
  28801. indices : mesh.indices,
  28802. skirtIndex : this._skirtIndex,
  28803. encoding : mesh.encoding,
  28804. minimumHeight : this._minimumHeight,
  28805. maximumHeight : this._maximumHeight,
  28806. isEastChild : isEastChild,
  28807. isNorthChild : isNorthChild,
  28808. childRectangle : childRectangle,
  28809. ellipsoid : ellipsoid,
  28810. exaggeration : mesh.exaggeration
  28811. });
  28812. if (!defined(upsamplePromise)) {
  28813. // Postponed
  28814. return undefined;
  28815. }
  28816. var shortestSkirt = Math.min(this._westSkirtHeight, this._eastSkirtHeight);
  28817. shortestSkirt = Math.min(shortestSkirt, this._southSkirtHeight);
  28818. shortestSkirt = Math.min(shortestSkirt, this._northSkirtHeight);
  28819. var westSkirtHeight = isEastChild ? (shortestSkirt * 0.5) : this._westSkirtHeight;
  28820. var southSkirtHeight = isNorthChild ? (shortestSkirt * 0.5) : this._southSkirtHeight;
  28821. var eastSkirtHeight = isEastChild ? this._eastSkirtHeight : (shortestSkirt * 0.5);
  28822. var northSkirtHeight = isNorthChild ? this._northSkirtHeight : (shortestSkirt * 0.5);
  28823. return when(upsamplePromise, function(result) {
  28824. var quantizedVertices = new Uint16Array(result.vertices);
  28825. var indicesTypedArray = IndexDatatype.createTypedArray(quantizedVertices.length / 3, result.indices);
  28826. var encodedNormals;
  28827. if (defined(result.encodedNormals)) {
  28828. encodedNormals = new Uint8Array(result.encodedNormals);
  28829. }
  28830. return new QuantizedMeshTerrainData({
  28831. quantizedVertices : quantizedVertices,
  28832. indices : indicesTypedArray,
  28833. encodedNormals : encodedNormals,
  28834. minimumHeight : result.minimumHeight,
  28835. maximumHeight : result.maximumHeight,
  28836. boundingSphere : BoundingSphere.clone(result.boundingSphere),
  28837. orientedBoundingBox : OrientedBoundingBox.clone(result.orientedBoundingBox),
  28838. horizonOcclusionPoint : Cartesian3.clone(result.horizonOcclusionPoint),
  28839. westIndices : result.westIndices,
  28840. southIndices : result.southIndices,
  28841. eastIndices : result.eastIndices,
  28842. northIndices : result.northIndices,
  28843. westSkirtHeight : westSkirtHeight,
  28844. southSkirtHeight : southSkirtHeight,
  28845. eastSkirtHeight : eastSkirtHeight,
  28846. northSkirtHeight : northSkirtHeight,
  28847. childTileMask : 0,
  28848. createdByUpsampling : true
  28849. });
  28850. });
  28851. };
  28852. var maxShort = 32767;
  28853. var barycentricCoordinateScratch = new Cartesian3();
  28854. /**
  28855. * Computes the terrain height at a specified longitude and latitude.
  28856. *
  28857. * @param {Rectangle} rectangle The rectangle covered by this terrain data.
  28858. * @param {Number} longitude The longitude in radians.
  28859. * @param {Number} latitude The latitude in radians.
  28860. * @returns {Number} The terrain height at the specified position. The position is clamped to
  28861. * the rectangle, so expect incorrect results for positions far outside the rectangle.
  28862. */
  28863. QuantizedMeshTerrainData.prototype.interpolateHeight = function(rectangle, longitude, latitude) {
  28864. var u = CesiumMath.clamp((longitude - rectangle.west) / rectangle.width, 0.0, 1.0);
  28865. u *= maxShort;
  28866. var v = CesiumMath.clamp((latitude - rectangle.south) / rectangle.height, 0.0, 1.0);
  28867. v *= maxShort;
  28868. if (!defined(this._mesh)) {
  28869. return interpolateHeight(this, u, v);
  28870. }
  28871. interpolateMeshHeight(this, u, v);
  28872. };
  28873. var texCoordScratch0 = new Cartesian2();
  28874. var texCoordScratch1 = new Cartesian2();
  28875. var texCoordScratch2 = new Cartesian2();
  28876. function interpolateMeshHeight(terrainData, u, v) {
  28877. var mesh = terrainData._mesh;
  28878. var vertices = mesh.vertices;
  28879. var encoding = mesh.encoding;
  28880. var indices = mesh.indices;
  28881. for (var i = 0, len = indices.length; i < len; i += 3) {
  28882. var i0 = indices[i];
  28883. var i1 = indices[i + 1];
  28884. var i2 = indices[i + 2];
  28885. var uv0 = encoding.decodeTextureCoordinates(vertices, i0, texCoordScratch0);
  28886. var uv1 = encoding.decodeTextureCoordinates(vertices, i1, texCoordScratch1);
  28887. var uv2 = encoding.decodeTextureCoordinates(vertices, i2, texCoordScratch2);
  28888. var barycentric = Intersections2D.computeBarycentricCoordinates(u, v, uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y, barycentricCoordinateScratch);
  28889. if (barycentric.x >= -1e-15 && barycentric.y >= -1e-15 && barycentric.z >= -1e-15) {
  28890. var h0 = encoding.decodeHeight(vertices, i0);
  28891. var h1 = encoding.decodeHeight(vertices, i1);
  28892. var h2 = encoding.decodeHeight(vertices, i2);
  28893. return barycentric.x * h0 + barycentric.y * h1 + barycentric.z * h2;
  28894. }
  28895. }
  28896. // Position does not lie in any triangle in this mesh.
  28897. return undefined;
  28898. }
  28899. function interpolateHeight(terrainData, u, v) {
  28900. var uBuffer = terrainData._uValues;
  28901. var vBuffer = terrainData._vValues;
  28902. var heightBuffer = terrainData._heightValues;
  28903. var indices = terrainData._indices;
  28904. for (var i = 0, len = indices.length; i < len; i += 3) {
  28905. var i0 = indices[i];
  28906. var i1 = indices[i + 1];
  28907. var i2 = indices[i + 2];
  28908. var u0 = uBuffer[i0];
  28909. var u1 = uBuffer[i1];
  28910. var u2 = uBuffer[i2];
  28911. var v0 = vBuffer[i0];
  28912. var v1 = vBuffer[i1];
  28913. var v2 = vBuffer[i2];
  28914. var barycentric = Intersections2D.computeBarycentricCoordinates(u, v, u0, v0, u1, v1, u2, v2, barycentricCoordinateScratch);
  28915. if (barycentric.x >= -1e-15 && barycentric.y >= -1e-15 && barycentric.z >= -1e-15) {
  28916. var quantizedHeight = barycentric.x * heightBuffer[i0] +
  28917. barycentric.y * heightBuffer[i1] +
  28918. barycentric.z * heightBuffer[i2];
  28919. return CesiumMath.lerp(terrainData._minimumHeight, terrainData._maximumHeight, quantizedHeight / maxShort);
  28920. }
  28921. }
  28922. // Position does not lie in any triangle in this mesh.
  28923. return undefined;
  28924. }
  28925. /**
  28926. * Determines if a given child tile is available, based on the
  28927. * {@link HeightmapTerrainData.childTileMask}. The given child tile coordinates are assumed
  28928. * to be one of the four children of this tile. If non-child tile coordinates are
  28929. * given, the availability of the southeast child tile is returned.
  28930. *
  28931. * @param {Number} thisX The tile X coordinate of this (the parent) tile.
  28932. * @param {Number} thisY The tile Y coordinate of this (the parent) tile.
  28933. * @param {Number} childX The tile X coordinate of the child tile to check for availability.
  28934. * @param {Number} childY The tile Y coordinate of the child tile to check for availability.
  28935. * @returns {Boolean} True if the child tile is available; otherwise, false.
  28936. */
  28937. QuantizedMeshTerrainData.prototype.isChildAvailable = function(thisX, thisY, childX, childY) {
  28938. if (!defined(thisX)) {
  28939. throw new DeveloperError('thisX is required.');
  28940. }
  28941. if (!defined(thisY)) {
  28942. throw new DeveloperError('thisY is required.');
  28943. }
  28944. if (!defined(childX)) {
  28945. throw new DeveloperError('childX is required.');
  28946. }
  28947. if (!defined(childY)) {
  28948. throw new DeveloperError('childY is required.');
  28949. }
  28950. var bitNumber = 2; // northwest child
  28951. if (childX !== thisX * 2) {
  28952. ++bitNumber; // east child
  28953. }
  28954. if (childY !== thisY * 2) {
  28955. bitNumber -= 2; // south child
  28956. }
  28957. return (this._childTileMask & (1 << bitNumber)) !== 0;
  28958. };
  28959. /**
  28960. * Gets a value indicating whether or not this terrain data was created by upsampling lower resolution
  28961. * terrain data. If this value is false, the data was obtained from some other source, such
  28962. * as by downloading it from a remote server. This method should return true for instances
  28963. * returned from a call to {@link HeightmapTerrainData#upsample}.
  28964. *
  28965. * @returns {Boolean} True if this instance was created by upsampling; otherwise, false.
  28966. */
  28967. QuantizedMeshTerrainData.prototype.wasCreatedByUpsampling = function() {
  28968. return this._createdByUpsampling;
  28969. };
  28970. return QuantizedMeshTerrainData;
  28971. });
  28972. /*global define*/
  28973. define('Core/formatError',[
  28974. './defined'
  28975. ], function(
  28976. defined) {
  28977. 'use strict';
  28978. /**
  28979. * Formats an error object into a String. If available, uses name, message, and stack
  28980. * properties, otherwise, falls back on toString().
  28981. *
  28982. * @exports formatError
  28983. *
  28984. * @param {Object} object The item to find in the array.
  28985. * @returns {String} A string containing the formatted error.
  28986. */
  28987. function formatError(object) {
  28988. var result;
  28989. var name = object.name;
  28990. var message = object.message;
  28991. if (defined(name) && defined(message)) {
  28992. result = name + ': ' + message;
  28993. } else {
  28994. result = object.toString();
  28995. }
  28996. var stack = object.stack;
  28997. if (defined(stack)) {
  28998. result += '\n' + stack;
  28999. }
  29000. return result;
  29001. }
  29002. return formatError;
  29003. });
  29004. /*global define*/
  29005. define('Core/TileProviderError',[
  29006. './defaultValue',
  29007. './defined',
  29008. './formatError'
  29009. ], function(
  29010. defaultValue,
  29011. defined,
  29012. formatError) {
  29013. 'use strict';
  29014. /**
  29015. * Provides details about an error that occurred in an {@link ImageryProvider} or a {@link TerrainProvider}.
  29016. *
  29017. * @alias TileProviderError
  29018. * @constructor
  29019. *
  29020. * @param {ImageryProvider|TerrainProvider} provider The imagery or terrain provider that experienced the error.
  29021. * @param {String} message A message describing the error.
  29022. * @param {Number} [x] The X coordinate of the tile that experienced the error, or undefined if the error
  29023. * is not specific to a particular tile.
  29024. * @param {Number} [y] The Y coordinate of the tile that experienced the error, or undefined if the error
  29025. * is not specific to a particular tile.
  29026. * @param {Number} [level] The level of the tile that experienced the error, or undefined if the error
  29027. * is not specific to a particular tile.
  29028. * @param {Number} [timesRetried=0] The number of times this operation has been retried.
  29029. * @param {Error} [error] The error or exception that occurred, if any.
  29030. */
  29031. function TileProviderError(provider, message, x, y, level, timesRetried, error) {
  29032. /**
  29033. * The {@link ImageryProvider} or {@link TerrainProvider} that experienced the error.
  29034. * @type {ImageryProvider|TerrainProvider}
  29035. */
  29036. this.provider = provider;
  29037. /**
  29038. * The message describing the error.
  29039. * @type {String}
  29040. */
  29041. this.message = message;
  29042. /**
  29043. * The X coordinate of the tile that experienced the error. If the error is not specific
  29044. * to a particular tile, this property will be undefined.
  29045. * @type {Number}
  29046. */
  29047. this.x = x;
  29048. /**
  29049. * The Y coordinate of the tile that experienced the error. If the error is not specific
  29050. * to a particular tile, this property will be undefined.
  29051. * @type {Number}
  29052. */
  29053. this.y = y;
  29054. /**
  29055. * The level-of-detail of the tile that experienced the error. If the error is not specific
  29056. * to a particular tile, this property will be undefined.
  29057. * @type {Number}
  29058. */
  29059. this.level = level;
  29060. /**
  29061. * The number of times this operation has been retried.
  29062. * @type {Number}
  29063. * @default 0
  29064. */
  29065. this.timesRetried = defaultValue(timesRetried, 0);
  29066. /**
  29067. * True if the failed operation should be retried; otherwise, false. The imagery or terrain provider
  29068. * will set the initial value of this property before raising the event, but any listeners
  29069. * can change it. The value after the last listener is invoked will be acted upon.
  29070. * @type {Boolean}
  29071. * @default false
  29072. */
  29073. this.retry = false;
  29074. /**
  29075. * The error or exception that occurred, if any.
  29076. * @type {Error}
  29077. */
  29078. this.error = error;
  29079. }
  29080. /**
  29081. * Handles an error in an {@link ImageryProvider} or {@link TerrainProvider} by raising an event if it has any listeners, or by
  29082. * logging the error to the console if the event has no listeners. This method also tracks the number
  29083. * of times the operation has been retried and will automatically retry if requested to do so by the
  29084. * event listeners.
  29085. *
  29086. * @param {TileProviderError} previousError The error instance returned by this function the last
  29087. * time it was called for this error, or undefined if this is the first time this error has
  29088. * occurred.
  29089. * @param {ImageryProvider|TerrainProvider} provider The imagery or terrain provider that encountered the error.
  29090. * @param {Event} event The event to raise to inform listeners of the error.
  29091. * @param {String} message The message describing the error.
  29092. * @param {Number} x The X coordinate of the tile that experienced the error, or undefined if the
  29093. * error is not specific to a particular tile.
  29094. * @param {Number} y The Y coordinate of the tile that experienced the error, or undefined if the
  29095. * error is not specific to a particular tile.
  29096. * @param {Number} level The level-of-detail of the tile that experienced the error, or undefined if the
  29097. * error is not specific to a particular tile.
  29098. * @param {TileProviderError~RetryFunction} retryFunction The function to call to retry the operation. If undefined, the
  29099. * operation will not be retried.
  29100. * @param {Error} [errorDetails] The error or exception that occurred, if any.
  29101. * @returns {TileProviderError} The error instance that was passed to the event listeners and that
  29102. * should be passed to this function the next time it is called for the same error in order
  29103. * to track retry counts.
  29104. */
  29105. TileProviderError.handleError = function(previousError, provider, event, message, x, y, level, retryFunction, errorDetails) {
  29106. var error = previousError;
  29107. if (!defined(previousError)) {
  29108. error = new TileProviderError(provider, message, x, y, level, 0, errorDetails);
  29109. } else {
  29110. error.provider = provider;
  29111. error.message = message;
  29112. error.x = x;
  29113. error.y = y;
  29114. error.level = level;
  29115. error.retry = false;
  29116. error.error = errorDetails;
  29117. ++error.timesRetried;
  29118. }
  29119. if (event.numberOfListeners > 0) {
  29120. event.raiseEvent(error);
  29121. } else {
  29122. console.log('An error occurred in "' + provider.constructor.name + '": ' + formatError(message));
  29123. }
  29124. if (error.retry && defined(retryFunction)) {
  29125. retryFunction();
  29126. }
  29127. return error;
  29128. };
  29129. /**
  29130. * Handles success of an operation by resetting the retry count of a previous error, if any. This way,
  29131. * if the error occurs again in the future, the listeners will be informed that it has not yet been retried.
  29132. *
  29133. * @param {TileProviderError} previousError The previous error, or undefined if this operation has
  29134. * not previously resulted in an error.
  29135. */
  29136. TileProviderError.handleSuccess = function(previousError) {
  29137. if (defined(previousError)) {
  29138. previousError.timesRetried = -1;
  29139. }
  29140. };
  29141. /**
  29142. * A function that will be called to retry the operation.
  29143. * @callback TileProviderError~RetryFunction
  29144. */
  29145. return TileProviderError;
  29146. });
  29147. /*global define*/
  29148. define('Core/CesiumTerrainProvider',[
  29149. '../ThirdParty/Uri',
  29150. '../ThirdParty/when',
  29151. './BoundingSphere',
  29152. './Cartesian3',
  29153. './Credit',
  29154. './defaultValue',
  29155. './defined',
  29156. './defineProperties',
  29157. './DeveloperError',
  29158. './Event',
  29159. './GeographicTilingScheme',
  29160. './HeightmapTerrainData',
  29161. './IndexDatatype',
  29162. './joinUrls',
  29163. './loadArrayBuffer',
  29164. './loadJson',
  29165. './Math',
  29166. './OrientedBoundingBox',
  29167. './QuantizedMeshTerrainData',
  29168. './TerrainProvider',
  29169. './throttleRequestByServer',
  29170. './TileProviderError'
  29171. ], function(
  29172. Uri,
  29173. when,
  29174. BoundingSphere,
  29175. Cartesian3,
  29176. Credit,
  29177. defaultValue,
  29178. defined,
  29179. defineProperties,
  29180. DeveloperError,
  29181. Event,
  29182. GeographicTilingScheme,
  29183. HeightmapTerrainData,
  29184. IndexDatatype,
  29185. joinUrls,
  29186. loadArrayBuffer,
  29187. loadJson,
  29188. CesiumMath,
  29189. OrientedBoundingBox,
  29190. QuantizedMeshTerrainData,
  29191. TerrainProvider,
  29192. throttleRequestByServer,
  29193. TileProviderError) {
  29194. 'use strict';
  29195. /**
  29196. * A {@link TerrainProvider} that access terrain data in a Cesium terrain format.
  29197. * The format is described on the
  29198. * {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Cesium-Terrain-Server|Cesium wiki}.
  29199. *
  29200. * @alias CesiumTerrainProvider
  29201. * @constructor
  29202. *
  29203. * @param {Object} options Object with the following properties:
  29204. * @param {String} options.url The URL of the Cesium terrain server.
  29205. * @param {Proxy} [options.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL, if needed.
  29206. * @param {Boolean} [options.requestVertexNormals=false] Flag that indicates if the client should request additional lighting information from the server, in the form of per vertex normals if available.
  29207. * @param {Boolean} [options.requestWaterMask=false] Flag that indicates if the client should request per tile water masks from the server, if available.
  29208. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If not specified, the WGS84 ellipsoid is used.
  29209. * @param {Credit|String} [options.credit] A credit for the data source, which is displayed on the canvas.
  29210. *
  29211. *
  29212. * @example
  29213. * // Construct a terrain provider that uses per vertex normals for lighting
  29214. * // to add shading detail to an imagery provider.
  29215. * var terrainProvider = new Cesium.CesiumTerrainProvider({
  29216. * url : 'https://assets.agi.com/stk-terrain/world',
  29217. * requestVertexNormals : true
  29218. * });
  29219. *
  29220. * // Terrain geometry near the surface of the globe is difficult to view when using NaturalEarthII imagery,
  29221. * // unless the TerrainProvider provides additional lighting information to shade the terrain (as shown above).
  29222. * var imageryProvider = Cesium.createTileMapServiceImageryProvider({
  29223. * url : 'http://localhost:8080/Source/Assets/Textures/NaturalEarthII',
  29224. * fileExtension : 'jpg'
  29225. * });
  29226. *
  29227. * var viewer = new Cesium.Viewer('cesiumContainer', {
  29228. * imageryProvider : imageryProvider,
  29229. * baseLayerPicker : false,
  29230. * terrainProvider : terrainProvider
  29231. * });
  29232. *
  29233. * // The globe must enable lighting to make use of the terrain's vertex normals
  29234. * viewer.scene.globe.enableLighting = true;
  29235. *
  29236. * @see TerrainProvider
  29237. */
  29238. function CesiumTerrainProvider(options) {
  29239. if (!defined(options) || !defined(options.url)) {
  29240. throw new DeveloperError('options.url is required.');
  29241. }
  29242. this._url = options.url;
  29243. this._proxy = options.proxy;
  29244. this._tilingScheme = new GeographicTilingScheme({
  29245. numberOfLevelZeroTilesX : 2,
  29246. numberOfLevelZeroTilesY : 1,
  29247. ellipsoid : options.ellipsoid
  29248. });
  29249. this._heightmapWidth = 65;
  29250. this._levelZeroMaximumGeometricError = TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(this._tilingScheme.ellipsoid, this._heightmapWidth, this._tilingScheme.getNumberOfXTilesAtLevel(0));
  29251. this._heightmapStructure = undefined;
  29252. this._hasWaterMask = false;
  29253. /**
  29254. * Boolean flag that indicates if the Terrain Server can provide vertex normals.
  29255. * @type {Boolean}
  29256. * @default false
  29257. * @private
  29258. */
  29259. this._hasVertexNormals = false;
  29260. /**
  29261. * Boolean flag that indicates if the client should request vertex normals from the server.
  29262. * @type {Boolean}
  29263. * @default false
  29264. * @private
  29265. */
  29266. this._requestVertexNormals = defaultValue(options.requestVertexNormals, false);
  29267. this._littleEndianExtensionSize = true;
  29268. /**
  29269. * Boolean flag that indicates if the client should request tile watermasks from the server.
  29270. * @type {Boolean}
  29271. * @default false
  29272. * @private
  29273. */
  29274. this._requestWaterMask = defaultValue(options.requestWaterMask, false);
  29275. this._errorEvent = new Event();
  29276. var credit = options.credit;
  29277. if (typeof credit === 'string') {
  29278. credit = new Credit(credit);
  29279. }
  29280. this._credit = credit;
  29281. this._ready = false;
  29282. this._readyPromise = when.defer();
  29283. var metadataUrl = joinUrls(this._url, 'layer.json');
  29284. if (defined(this._proxy)) {
  29285. metadataUrl = this._proxy.getURL(metadataUrl);
  29286. }
  29287. var that = this;
  29288. var metadataError;
  29289. function metadataSuccess(data) {
  29290. var message;
  29291. if (!data.format) {
  29292. message = 'The tile format is not specified in the layer.json file.';
  29293. metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
  29294. return;
  29295. }
  29296. if (!data.tiles || data.tiles.length === 0) {
  29297. message = 'The layer.json file does not specify any tile URL templates.';
  29298. metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
  29299. return;
  29300. }
  29301. if (data.format === 'heightmap-1.0') {
  29302. that._heightmapStructure = {
  29303. heightScale : 1.0 / 5.0,
  29304. heightOffset : -1000.0,
  29305. elementsPerHeight : 1,
  29306. stride : 1,
  29307. elementMultiplier : 256.0,
  29308. isBigEndian : false,
  29309. lowestEncodedHeight : 0,
  29310. highestEncodedHeight : 256 * 256 - 1
  29311. };
  29312. that._hasWaterMask = true;
  29313. that._requestWaterMask = true;
  29314. } else if (data.format.indexOf('quantized-mesh-1.') !== 0) {
  29315. message = 'The tile format "' + data.format + '" is invalid or not supported.';
  29316. metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
  29317. return;
  29318. }
  29319. that._tileUrlTemplates = data.tiles;
  29320. for (var i = 0; i < that._tileUrlTemplates.length; ++i) {
  29321. var template = new Uri(that._tileUrlTemplates[i]);
  29322. var baseUri = new Uri(that._url);
  29323. if (template.authority && !baseUri.authority) {
  29324. baseUri.authority = template.authority;
  29325. baseUri.scheme = template.scheme;
  29326. }
  29327. that._tileUrlTemplates[i] = joinUrls(baseUri, template).toString().replace('{version}', data.version);
  29328. }
  29329. that._availableTiles = data.available;
  29330. if (!defined(that._credit) && defined(data.attribution) && data.attribution !== null) {
  29331. that._credit = new Credit(data.attribution);
  29332. }
  29333. // The vertex normals defined in the 'octvertexnormals' extension is identical to the original
  29334. // contents of the original 'vertexnormals' extension. 'vertexnormals' extension is now
  29335. // deprecated, as the extensionLength for this extension was incorrectly using big endian.
  29336. // We maintain backwards compatibility with the legacy 'vertexnormal' implementation
  29337. // by setting the _littleEndianExtensionSize to false. Always prefer 'octvertexnormals'
  29338. // over 'vertexnormals' if both extensions are supported by the server.
  29339. if (defined(data.extensions) && data.extensions.indexOf('octvertexnormals') !== -1) {
  29340. that._hasVertexNormals = true;
  29341. } else if (defined(data.extensions) && data.extensions.indexOf('vertexnormals') !== -1) {
  29342. that._hasVertexNormals = true;
  29343. that._littleEndianExtensionSize = false;
  29344. }
  29345. if (defined(data.extensions) && data.extensions.indexOf('watermask') !== -1) {
  29346. that._hasWaterMask = true;
  29347. }
  29348. that._ready = true;
  29349. that._readyPromise.resolve(true);
  29350. }
  29351. function metadataFailure(data) {
  29352. // If the metadata is not found, assume this is a pre-metadata heightmap tileset.
  29353. if (defined(data) && data.statusCode === 404) {
  29354. metadataSuccess({
  29355. tilejson: '2.1.0',
  29356. format : 'heightmap-1.0',
  29357. version : '1.0.0',
  29358. scheme : 'tms',
  29359. tiles : [
  29360. '{z}/{x}/{y}.terrain?v={version}'
  29361. ]
  29362. });
  29363. return;
  29364. }
  29365. var message = 'An error occurred while accessing ' + metadataUrl + '.';
  29366. metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
  29367. }
  29368. function requestMetadata() {
  29369. var metadata = loadJson(metadataUrl);
  29370. when(metadata, metadataSuccess, metadataFailure);
  29371. }
  29372. requestMetadata();
  29373. }
  29374. /**
  29375. * When using the Quantized-Mesh format, a tile may be returned that includes additional extensions, such as PerVertexNormals, watermask, etc.
  29376. * This enumeration defines the unique identifiers for each type of extension data that has been appended to the standard mesh data.
  29377. *
  29378. * @exports QuantizedMeshExtensionIds
  29379. * @see CesiumTerrainProvider
  29380. * @private
  29381. */
  29382. var QuantizedMeshExtensionIds = {
  29383. /**
  29384. * Oct-Encoded Per-Vertex Normals are included as an extension to the tile mesh
  29385. *
  29386. * @type {Number}
  29387. * @constant
  29388. * @default 1
  29389. */
  29390. OCT_VERTEX_NORMALS: 1,
  29391. /**
  29392. * A watermask is included as an extension to the tile mesh
  29393. *
  29394. * @type {Number}
  29395. * @constant
  29396. * @default 2
  29397. */
  29398. WATER_MASK: 2
  29399. };
  29400. function getRequestHeader(extensionsList) {
  29401. if (!defined(extensionsList) || extensionsList.length === 0) {
  29402. return {
  29403. Accept : 'application/vnd.quantized-mesh,application/octet-stream;q=0.9,*/*;q=0.01'
  29404. };
  29405. } else {
  29406. var extensions = extensionsList.join('-');
  29407. return {
  29408. Accept : 'application/vnd.quantized-mesh;extensions=' + extensions + ',application/octet-stream;q=0.9,*/*;q=0.01'
  29409. };
  29410. }
  29411. }
  29412. function createHeightmapTerrainData(provider, buffer, level, x, y, tmsY) {
  29413. var heightBuffer = new Uint16Array(buffer, 0, provider._heightmapWidth * provider._heightmapWidth);
  29414. return new HeightmapTerrainData({
  29415. buffer : heightBuffer,
  29416. childTileMask : new Uint8Array(buffer, heightBuffer.byteLength, 1)[0],
  29417. waterMask : new Uint8Array(buffer, heightBuffer.byteLength + 1, buffer.byteLength - heightBuffer.byteLength - 1),
  29418. width : provider._heightmapWidth,
  29419. height : provider._heightmapWidth,
  29420. structure : provider._heightmapStructure
  29421. });
  29422. }
  29423. function createQuantizedMeshTerrainData(provider, buffer, level, x, y, tmsY) {
  29424. var pos = 0;
  29425. var cartesian3Elements = 3;
  29426. var boundingSphereElements = cartesian3Elements + 1;
  29427. var cartesian3Length = Float64Array.BYTES_PER_ELEMENT * cartesian3Elements;
  29428. var boundingSphereLength = Float64Array.BYTES_PER_ELEMENT * boundingSphereElements;
  29429. var encodedVertexElements = 3;
  29430. var encodedVertexLength = Uint16Array.BYTES_PER_ELEMENT * encodedVertexElements;
  29431. var triangleElements = 3;
  29432. var bytesPerIndex = Uint16Array.BYTES_PER_ELEMENT;
  29433. var triangleLength = bytesPerIndex * triangleElements;
  29434. var view = new DataView(buffer);
  29435. var center = new Cartesian3(view.getFloat64(pos, true), view.getFloat64(pos + 8, true), view.getFloat64(pos + 16, true));
  29436. pos += cartesian3Length;
  29437. var minimumHeight = view.getFloat32(pos, true);
  29438. pos += Float32Array.BYTES_PER_ELEMENT;
  29439. var maximumHeight = view.getFloat32(pos, true);
  29440. pos += Float32Array.BYTES_PER_ELEMENT;
  29441. var boundingSphere = new BoundingSphere(
  29442. new Cartesian3(view.getFloat64(pos, true), view.getFloat64(pos + 8, true), view.getFloat64(pos + 16, true)),
  29443. view.getFloat64(pos + cartesian3Length, true));
  29444. pos += boundingSphereLength;
  29445. var horizonOcclusionPoint = new Cartesian3(view.getFloat64(pos, true), view.getFloat64(pos + 8, true), view.getFloat64(pos + 16, true));
  29446. pos += cartesian3Length;
  29447. var vertexCount = view.getUint32(pos, true);
  29448. pos += Uint32Array.BYTES_PER_ELEMENT;
  29449. var encodedVertexBuffer = new Uint16Array(buffer, pos, vertexCount * 3);
  29450. pos += vertexCount * encodedVertexLength;
  29451. if (vertexCount > 64 * 1024) {
  29452. // More than 64k vertices, so indices are 32-bit.
  29453. bytesPerIndex = Uint32Array.BYTES_PER_ELEMENT;
  29454. triangleLength = bytesPerIndex * triangleElements;
  29455. }
  29456. // Decode the vertex buffer.
  29457. var uBuffer = encodedVertexBuffer.subarray(0, vertexCount);
  29458. var vBuffer = encodedVertexBuffer.subarray(vertexCount, 2 * vertexCount);
  29459. var heightBuffer = encodedVertexBuffer.subarray(vertexCount * 2, 3 * vertexCount);
  29460. var i;
  29461. var u = 0;
  29462. var v = 0;
  29463. var height = 0;
  29464. function zigZagDecode(value) {
  29465. return (value >> 1) ^ (-(value & 1));
  29466. }
  29467. for (i = 0; i < vertexCount; ++i) {
  29468. u += zigZagDecode(uBuffer[i]);
  29469. v += zigZagDecode(vBuffer[i]);
  29470. height += zigZagDecode(heightBuffer[i]);
  29471. uBuffer[i] = u;
  29472. vBuffer[i] = v;
  29473. heightBuffer[i] = height;
  29474. }
  29475. // skip over any additional padding that was added for 2/4 byte alignment
  29476. if (pos % bytesPerIndex !== 0) {
  29477. pos += (bytesPerIndex - (pos % bytesPerIndex));
  29478. }
  29479. var triangleCount = view.getUint32(pos, true);
  29480. pos += Uint32Array.BYTES_PER_ELEMENT;
  29481. var indices = IndexDatatype.createTypedArrayFromArrayBuffer(vertexCount, buffer, pos, triangleCount * triangleElements);
  29482. pos += triangleCount * triangleLength;
  29483. // High water mark decoding based on decompressIndices_ in webgl-loader's loader.js.
  29484. // https://code.google.com/p/webgl-loader/source/browse/trunk/samples/loader.js?r=99#55
  29485. // Copyright 2012 Google Inc., Apache 2.0 license.
  29486. var highest = 0;
  29487. for (i = 0; i < indices.length; ++i) {
  29488. var code = indices[i];
  29489. indices[i] = highest - code;
  29490. if (code === 0) {
  29491. ++highest;
  29492. }
  29493. }
  29494. var westVertexCount = view.getUint32(pos, true);
  29495. pos += Uint32Array.BYTES_PER_ELEMENT;
  29496. var westIndices = IndexDatatype.createTypedArrayFromArrayBuffer(vertexCount, buffer, pos, westVertexCount);
  29497. pos += westVertexCount * bytesPerIndex;
  29498. var southVertexCount = view.getUint32(pos, true);
  29499. pos += Uint32Array.BYTES_PER_ELEMENT;
  29500. var southIndices = IndexDatatype.createTypedArrayFromArrayBuffer(vertexCount, buffer, pos, southVertexCount);
  29501. pos += southVertexCount * bytesPerIndex;
  29502. var eastVertexCount = view.getUint32(pos, true);
  29503. pos += Uint32Array.BYTES_PER_ELEMENT;
  29504. var eastIndices = IndexDatatype.createTypedArrayFromArrayBuffer(vertexCount, buffer, pos, eastVertexCount);
  29505. pos += eastVertexCount * bytesPerIndex;
  29506. var northVertexCount = view.getUint32(pos, true);
  29507. pos += Uint32Array.BYTES_PER_ELEMENT;
  29508. var northIndices = IndexDatatype.createTypedArrayFromArrayBuffer(vertexCount, buffer, pos, northVertexCount);
  29509. pos += northVertexCount * bytesPerIndex;
  29510. var encodedNormalBuffer;
  29511. var waterMaskBuffer;
  29512. while (pos < view.byteLength) {
  29513. var extensionId = view.getUint8(pos, true);
  29514. pos += Uint8Array.BYTES_PER_ELEMENT;
  29515. var extensionLength = view.getUint32(pos, provider._littleEndianExtensionSize);
  29516. pos += Uint32Array.BYTES_PER_ELEMENT;
  29517. if (extensionId === QuantizedMeshExtensionIds.OCT_VERTEX_NORMALS && provider._requestVertexNormals) {
  29518. encodedNormalBuffer = new Uint8Array(buffer, pos, vertexCount * 2);
  29519. } else if (extensionId === QuantizedMeshExtensionIds.WATER_MASK && provider._requestWaterMask) {
  29520. waterMaskBuffer = new Uint8Array(buffer, pos, extensionLength);
  29521. }
  29522. pos += extensionLength;
  29523. }
  29524. var skirtHeight = provider.getLevelMaximumGeometricError(level) * 5.0;
  29525. var rectangle = provider._tilingScheme.tileXYToRectangle(x, y, level);
  29526. var orientedBoundingBox;
  29527. if (rectangle.width < CesiumMath.PI_OVER_TWO + CesiumMath.EPSILON5) {
  29528. // Here, rectangle.width < pi/2, and rectangle.height < pi
  29529. // (though it would still work with rectangle.width up to pi)
  29530. // The skirt is not included in the OBB computation. If this ever
  29531. // causes any rendering artifacts (cracks), they are expected to be
  29532. // minor and in the corners of the screen. It's possible that this
  29533. // might need to be changed - just change to `minimumHeight - skirtHeight`
  29534. // A similar change might also be needed in `upsampleQuantizedTerrainMesh.js`.
  29535. orientedBoundingBox = OrientedBoundingBox.fromRectangle(rectangle, minimumHeight, maximumHeight, provider._tilingScheme.ellipsoid);
  29536. }
  29537. return new QuantizedMeshTerrainData({
  29538. center : center,
  29539. minimumHeight : minimumHeight,
  29540. maximumHeight : maximumHeight,
  29541. boundingSphere : boundingSphere,
  29542. orientedBoundingBox : orientedBoundingBox,
  29543. horizonOcclusionPoint : horizonOcclusionPoint,
  29544. quantizedVertices : encodedVertexBuffer,
  29545. encodedNormals : encodedNormalBuffer,
  29546. indices : indices,
  29547. westIndices : westIndices,
  29548. southIndices : southIndices,
  29549. eastIndices : eastIndices,
  29550. northIndices : northIndices,
  29551. westSkirtHeight : skirtHeight,
  29552. southSkirtHeight : skirtHeight,
  29553. eastSkirtHeight : skirtHeight,
  29554. northSkirtHeight : skirtHeight,
  29555. childTileMask: getChildMaskForTile(provider, level, x, tmsY),
  29556. waterMask: waterMaskBuffer
  29557. });
  29558. }
  29559. /**
  29560. * Requests the geometry for a given tile. This function should not be called before
  29561. * {@link CesiumTerrainProvider#ready} returns true. The result must include terrain data and
  29562. * may optionally include a water mask and an indication of which child tiles are available.
  29563. *
  29564. * @param {Number} x The X coordinate of the tile for which to request geometry.
  29565. * @param {Number} y The Y coordinate of the tile for which to request geometry.
  29566. * @param {Number} level The level of the tile for which to request geometry.
  29567. * @param {Boolean} [throttleRequests=true] True if the number of simultaneous requests should be limited,
  29568. * or false if the request should be initiated regardless of the number of requests
  29569. * already in progress.
  29570. * @returns {Promise.<TerrainData>|undefined} A promise for the requested geometry. If this method
  29571. * returns undefined instead of a promise, it is an indication that too many requests are already
  29572. * pending and the request will be retried later.
  29573. *
  29574. * @exception {DeveloperError} This function must not be called before {@link CesiumTerrainProvider#ready}
  29575. * returns true.
  29576. */
  29577. CesiumTerrainProvider.prototype.requestTileGeometry = function(x, y, level, throttleRequests) {
  29578. if (!this._ready) {
  29579. throw new DeveloperError('requestTileGeometry must not be called before the terrain provider is ready.');
  29580. }
  29581. var urlTemplates = this._tileUrlTemplates;
  29582. if (urlTemplates.length === 0) {
  29583. return undefined;
  29584. }
  29585. var yTiles = this._tilingScheme.getNumberOfYTilesAtLevel(level);
  29586. var tmsY = (yTiles - y - 1);
  29587. var url = urlTemplates[(x + tmsY + level) % urlTemplates.length].replace('{z}', level).replace('{x}', x).replace('{y}', tmsY);
  29588. var proxy = this._proxy;
  29589. if (defined(proxy)) {
  29590. url = proxy.getURL(url);
  29591. }
  29592. var promise;
  29593. var extensionList = [];
  29594. if (this._requestVertexNormals && this._hasVertexNormals) {
  29595. extensionList.push(this._littleEndianExtensionSize ? "octvertexnormals" : "vertexnormals");
  29596. }
  29597. if (this._requestWaterMask && this._hasWaterMask) {
  29598. extensionList.push("watermask");
  29599. }
  29600. function tileLoader(tileUrl) {
  29601. return loadArrayBuffer(tileUrl, getRequestHeader(extensionList));
  29602. }
  29603. throttleRequests = defaultValue(throttleRequests, true);
  29604. if (throttleRequests) {
  29605. promise = throttleRequestByServer(url, tileLoader);
  29606. if (!defined(promise)) {
  29607. return undefined;
  29608. }
  29609. } else {
  29610. promise = tileLoader(url);
  29611. }
  29612. var that = this;
  29613. return when(promise, function(buffer) {
  29614. if (defined(that._heightmapStructure)) {
  29615. return createHeightmapTerrainData(that, buffer, level, x, y, tmsY);
  29616. } else {
  29617. return createQuantizedMeshTerrainData(that, buffer, level, x, y, tmsY);
  29618. }
  29619. });
  29620. };
  29621. defineProperties(CesiumTerrainProvider.prototype, {
  29622. /**
  29623. * Gets an event that is raised when the terrain provider encounters an asynchronous error. By subscribing
  29624. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  29625. * are passed an instance of {@link TileProviderError}.
  29626. * @memberof CesiumTerrainProvider.prototype
  29627. * @type {Event}
  29628. */
  29629. errorEvent : {
  29630. get : function() {
  29631. return this._errorEvent;
  29632. }
  29633. },
  29634. /**
  29635. * Gets the credit to display when this terrain provider is active. Typically this is used to credit
  29636. * the source of the terrain. This function should not be called before {@link CesiumTerrainProvider#ready} returns true.
  29637. * @memberof CesiumTerrainProvider.prototype
  29638. * @type {Credit}
  29639. */
  29640. credit : {
  29641. get : function() {
  29642. if (!this._ready) {
  29643. throw new DeveloperError('credit must not be called before the terrain provider is ready.');
  29644. }
  29645. return this._credit;
  29646. }
  29647. },
  29648. /**
  29649. * Gets the tiling scheme used by this provider. This function should
  29650. * not be called before {@link CesiumTerrainProvider#ready} returns true.
  29651. * @memberof CesiumTerrainProvider.prototype
  29652. * @type {GeographicTilingScheme}
  29653. */
  29654. tilingScheme : {
  29655. get : function() {
  29656. if (!this._ready) {
  29657. throw new DeveloperError('tilingScheme must not be called before the terrain provider is ready.');
  29658. }
  29659. return this._tilingScheme;
  29660. }
  29661. },
  29662. /**
  29663. * Gets a value indicating whether or not the provider is ready for use.
  29664. * @memberof CesiumTerrainProvider.prototype
  29665. * @type {Boolean}
  29666. */
  29667. ready : {
  29668. get : function() {
  29669. return this._ready;
  29670. }
  29671. },
  29672. /**
  29673. * Gets a promise that resolves to true when the provider is ready for use.
  29674. * @memberof CesiumTerrainProvider.prototype
  29675. * @type {Promise.<Boolean>}
  29676. * @readonly
  29677. */
  29678. readyPromise : {
  29679. get : function() {
  29680. return this._readyPromise.promise;
  29681. }
  29682. },
  29683. /**
  29684. * Gets a value indicating whether or not the provider includes a water mask. The water mask
  29685. * indicates which areas of the globe are water rather than land, so they can be rendered
  29686. * as a reflective surface with animated waves. This function should not be
  29687. * called before {@link CesiumTerrainProvider#ready} returns true.
  29688. * @memberof CesiumTerrainProvider.prototype
  29689. * @type {Boolean}
  29690. * @exception {DeveloperError} This property must not be called before {@link CesiumTerrainProvider#ready}
  29691. */
  29692. hasWaterMask : {
  29693. get : function() {
  29694. if (!this._ready) {
  29695. throw new DeveloperError('hasWaterMask must not be called before the terrain provider is ready.');
  29696. }
  29697. return this._hasWaterMask && this._requestWaterMask;
  29698. }
  29699. },
  29700. /**
  29701. * Gets a value indicating whether or not the requested tiles include vertex normals.
  29702. * This function should not be called before {@link CesiumTerrainProvider#ready} returns true.
  29703. * @memberof CesiumTerrainProvider.prototype
  29704. * @type {Boolean}
  29705. * @exception {DeveloperError} This property must not be called before {@link CesiumTerrainProvider#ready}
  29706. */
  29707. hasVertexNormals : {
  29708. get : function() {
  29709. if (!this._ready) {
  29710. throw new DeveloperError('hasVertexNormals must not be called before the terrain provider is ready.');
  29711. }
  29712. // returns true if we can request vertex normals from the server
  29713. return this._hasVertexNormals && this._requestVertexNormals;
  29714. }
  29715. },
  29716. /**
  29717. * Boolean flag that indicates if the client should request vertex normals from the server.
  29718. * Vertex normals data is appended to the standard tile mesh data only if the client requests the vertex normals and
  29719. * if the server provides vertex normals.
  29720. * @memberof CesiumTerrainProvider.prototype
  29721. * @type {Boolean}
  29722. */
  29723. requestVertexNormals : {
  29724. get : function() {
  29725. return this._requestVertexNormals;
  29726. }
  29727. },
  29728. /**
  29729. * Boolean flag that indicates if the client should request a watermask from the server.
  29730. * Watermask data is appended to the standard tile mesh data only if the client requests the watermask and
  29731. * if the server provides a watermask.
  29732. * @memberof CesiumTerrainProvider.prototype
  29733. * @type {Boolean}
  29734. */
  29735. requestWaterMask : {
  29736. get : function() {
  29737. return this._requestWaterMask;
  29738. }
  29739. }
  29740. });
  29741. /**
  29742. * Gets the maximum geometric error allowed in a tile at a given level.
  29743. *
  29744. * @param {Number} level The tile level for which to get the maximum geometric error.
  29745. * @returns {Number} The maximum geometric error.
  29746. */
  29747. CesiumTerrainProvider.prototype.getLevelMaximumGeometricError = function(level) {
  29748. return this._levelZeroMaximumGeometricError / (1 << level);
  29749. };
  29750. function getChildMaskForTile(terrainProvider, level, x, y) {
  29751. var available = terrainProvider._availableTiles;
  29752. if (!available || available.length === 0) {
  29753. return 15;
  29754. }
  29755. var childLevel = level + 1;
  29756. if (childLevel >= available.length) {
  29757. return 0;
  29758. }
  29759. var levelAvailable = available[childLevel];
  29760. var mask = 0;
  29761. mask |= isTileInRange(levelAvailable, 2 * x, 2 * y) ? 1 : 0;
  29762. mask |= isTileInRange(levelAvailable, 2 * x + 1, 2 * y) ? 2 : 0;
  29763. mask |= isTileInRange(levelAvailable, 2 * x, 2 * y + 1) ? 4 : 0;
  29764. mask |= isTileInRange(levelAvailable, 2 * x + 1, 2 * y + 1) ? 8 : 0;
  29765. return mask;
  29766. }
  29767. function isTileInRange(levelAvailable, x, y) {
  29768. for (var i = 0, len = levelAvailable.length; i < len; ++i) {
  29769. var range = levelAvailable[i];
  29770. if (x >= range.startX && x <= range.endX && y >= range.startY && y <= range.endY) {
  29771. return true;
  29772. }
  29773. }
  29774. return false;
  29775. }
  29776. /**
  29777. * Determines whether data for a tile is available to be loaded.
  29778. *
  29779. * @param {Number} x The X coordinate of the tile for which to request geometry.
  29780. * @param {Number} y The Y coordinate of the tile for which to request geometry.
  29781. * @param {Number} level The level of the tile for which to request geometry.
  29782. * @returns {Boolean} Undefined if not supported, otherwise true or false.
  29783. */
  29784. CesiumTerrainProvider.prototype.getTileDataAvailable = function(x, y, level) {
  29785. var available = this._availableTiles;
  29786. if (!available || available.length === 0) {
  29787. return undefined;
  29788. } else {
  29789. if (level >= available.length) {
  29790. return false;
  29791. }
  29792. var levelAvailable = available[level];
  29793. var yTiles = this._tilingScheme.getNumberOfYTilesAtLevel(level);
  29794. var tmsY = (yTiles - y - 1);
  29795. return isTileInRange(levelAvailable, x, tmsY);
  29796. }
  29797. };
  29798. return CesiumTerrainProvider;
  29799. });
  29800. /*global define*/
  29801. define('Core/EllipseGeometryLibrary',[
  29802. './Cartesian3',
  29803. './Math',
  29804. './Matrix3',
  29805. './Quaternion'
  29806. ], function(
  29807. Cartesian3,
  29808. CesiumMath,
  29809. Matrix3,
  29810. Quaternion) {
  29811. 'use strict';
  29812. var EllipseGeometryLibrary = {};
  29813. var rotAxis = new Cartesian3();
  29814. var tempVec = new Cartesian3();
  29815. var unitQuat = new Quaternion();
  29816. var rotMtx = new Matrix3();
  29817. function pointOnEllipsoid(theta, rotation, northVec, eastVec, aSqr, ab, bSqr, mag, unitPos, result) {
  29818. var azimuth = theta + rotation;
  29819. Cartesian3.multiplyByScalar(eastVec, Math.cos(azimuth), rotAxis);
  29820. Cartesian3.multiplyByScalar(northVec, Math.sin(azimuth), tempVec);
  29821. Cartesian3.add(rotAxis, tempVec, rotAxis);
  29822. var cosThetaSquared = Math.cos(theta);
  29823. cosThetaSquared = cosThetaSquared * cosThetaSquared;
  29824. var sinThetaSquared = Math.sin(theta);
  29825. sinThetaSquared = sinThetaSquared * sinThetaSquared;
  29826. var radius = ab / Math.sqrt(bSqr * cosThetaSquared + aSqr * sinThetaSquared);
  29827. var angle = radius / mag;
  29828. // Create the quaternion to rotate the position vector to the boundary of the ellipse.
  29829. Quaternion.fromAxisAngle(rotAxis, angle, unitQuat);
  29830. Matrix3.fromQuaternion(unitQuat, rotMtx);
  29831. Matrix3.multiplyByVector(rotMtx, unitPos, result);
  29832. Cartesian3.normalize(result, result);
  29833. Cartesian3.multiplyByScalar(result, mag, result);
  29834. return result;
  29835. }
  29836. var scratchCartesian1 = new Cartesian3();
  29837. var scratchCartesian2 = new Cartesian3();
  29838. var scratchCartesian3 = new Cartesian3();
  29839. var scratchNormal = new Cartesian3();
  29840. /**
  29841. * Returns the positions raised to the given heights
  29842. * @private
  29843. */
  29844. EllipseGeometryLibrary.raisePositionsToHeight = function(positions, options, extrude) {
  29845. var ellipsoid = options.ellipsoid;
  29846. var height = options.height;
  29847. var extrudedHeight = options.extrudedHeight;
  29848. var size = (extrude) ? positions.length / 3 * 2 : positions.length / 3;
  29849. var finalPositions = new Float64Array(size * 3);
  29850. var length = positions.length;
  29851. var bottomOffset = (extrude) ? length : 0;
  29852. for (var i = 0; i < length; i += 3) {
  29853. var i1 = i + 1;
  29854. var i2 = i + 2;
  29855. var position = Cartesian3.fromArray(positions, i, scratchCartesian1);
  29856. ellipsoid.scaleToGeodeticSurface(position, position);
  29857. var extrudedPosition = Cartesian3.clone(position, scratchCartesian2);
  29858. var normal = ellipsoid.geodeticSurfaceNormal(position, scratchNormal);
  29859. var scaledNormal = Cartesian3.multiplyByScalar(normal, height, scratchCartesian3);
  29860. Cartesian3.add(position, scaledNormal, position);
  29861. if (extrude) {
  29862. Cartesian3.multiplyByScalar(normal, extrudedHeight, scaledNormal);
  29863. Cartesian3.add(extrudedPosition, scaledNormal, extrudedPosition);
  29864. finalPositions[i + bottomOffset] = extrudedPosition.x;
  29865. finalPositions[i1 + bottomOffset] = extrudedPosition.y;
  29866. finalPositions[i2 + bottomOffset] = extrudedPosition.z;
  29867. }
  29868. finalPositions[i] = position.x;
  29869. finalPositions[i1] = position.y;
  29870. finalPositions[i2] = position.z;
  29871. }
  29872. return finalPositions;
  29873. };
  29874. var unitPosScratch = new Cartesian3();
  29875. var eastVecScratch = new Cartesian3();
  29876. var northVecScratch = new Cartesian3();
  29877. /**
  29878. * Returns an array of positions that make up the ellipse.
  29879. * @private
  29880. */
  29881. EllipseGeometryLibrary.computeEllipsePositions = function(options, addFillPositions, addEdgePositions) {
  29882. var semiMinorAxis = options.semiMinorAxis;
  29883. var semiMajorAxis = options.semiMajorAxis;
  29884. var rotation = options.rotation;
  29885. var center = options.center;
  29886. // Computing the arc-length of the ellipse is too expensive to be practical. Estimating it using the
  29887. // arc length of the sphere is too inaccurate and creates sharp edges when either the semi-major or
  29888. // semi-minor axis is much bigger than the other. Instead, scale the angle delta to make
  29889. // the distance along the ellipse boundary more closely match the granularity.
  29890. var granularity = options.granularity * 8.0;
  29891. var aSqr = semiMinorAxis * semiMinorAxis;
  29892. var bSqr = semiMajorAxis * semiMajorAxis;
  29893. var ab = semiMajorAxis * semiMinorAxis;
  29894. var mag = Cartesian3.magnitude(center);
  29895. var unitPos = Cartesian3.normalize(center, unitPosScratch);
  29896. var eastVec = Cartesian3.cross(Cartesian3.UNIT_Z, center, eastVecScratch);
  29897. eastVec = Cartesian3.normalize(eastVec, eastVec);
  29898. var northVec = Cartesian3.cross(unitPos, eastVec, northVecScratch);
  29899. // The number of points in the first quadrant
  29900. var numPts = 1 + Math.ceil(CesiumMath.PI_OVER_TWO / granularity);
  29901. var deltaTheta = CesiumMath.PI_OVER_TWO / (numPts - 1);
  29902. var theta = CesiumMath.PI_OVER_TWO - numPts * deltaTheta;
  29903. if (theta < 0.0) {
  29904. numPts -= Math.ceil(Math.abs(theta) / deltaTheta);
  29905. }
  29906. // If the number of points were three, the ellipse
  29907. // would be tessellated like below:
  29908. //
  29909. // *---*
  29910. // / | \ | \
  29911. // *---*---*---*
  29912. // / | \ | \ | \ | \
  29913. // / .*---*---*---*. \
  29914. // * ` | \ | \ | \ | `*
  29915. // \`.*---*---*---*.`/
  29916. // \ | \ | \ | \ | /
  29917. // *---*---*---*
  29918. // \ | \ | /
  29919. // *---*
  29920. // The first and last column have one position and fan to connect to the adjacent column.
  29921. // Each other vertical column contains an even number of positions.
  29922. var size = 2 * (numPts * (numPts + 2));
  29923. var positions = (addFillPositions) ? new Array(size * 3) : undefined;
  29924. var positionIndex = 0;
  29925. var position = scratchCartesian1;
  29926. var reflectedPosition = scratchCartesian2;
  29927. var outerPositionsLength = (numPts * 4) * 3;
  29928. var outerRightIndex = outerPositionsLength - 1;
  29929. var outerLeftIndex = 0;
  29930. var outerPositions = (addEdgePositions) ? new Array(outerPositionsLength) : undefined;
  29931. var i;
  29932. var j;
  29933. var numInterior;
  29934. var t;
  29935. var interiorPosition;
  29936. // Compute points in the 'eastern' half of the ellipse
  29937. theta = CesiumMath.PI_OVER_TWO;
  29938. position = pointOnEllipsoid(theta, rotation, northVec, eastVec, aSqr, ab, bSqr, mag, unitPos, position);
  29939. if (addFillPositions) {
  29940. positions[positionIndex++] = position.x;
  29941. positions[positionIndex++] = position.y;
  29942. positions[positionIndex++] = position.z;
  29943. }
  29944. if (addEdgePositions) {
  29945. outerPositions[outerRightIndex--] = position.z;
  29946. outerPositions[outerRightIndex--] = position.y;
  29947. outerPositions[outerRightIndex--] = position.x;
  29948. }
  29949. theta = CesiumMath.PI_OVER_TWO - deltaTheta;
  29950. for (i = 1; i < numPts + 1; ++i) {
  29951. position = pointOnEllipsoid(theta, rotation, northVec, eastVec, aSqr, ab, bSqr, mag, unitPos, position);
  29952. reflectedPosition = pointOnEllipsoid(Math.PI - theta, rotation, northVec, eastVec, aSqr, ab, bSqr, mag, unitPos, reflectedPosition);
  29953. if (addFillPositions) {
  29954. positions[positionIndex++] = position.x;
  29955. positions[positionIndex++] = position.y;
  29956. positions[positionIndex++] = position.z;
  29957. numInterior = 2 * i + 2;
  29958. for (j = 1; j < numInterior - 1; ++j) {
  29959. t = j / (numInterior - 1);
  29960. interiorPosition = Cartesian3.lerp(position, reflectedPosition, t, scratchCartesian3);
  29961. positions[positionIndex++] = interiorPosition.x;
  29962. positions[positionIndex++] = interiorPosition.y;
  29963. positions[positionIndex++] = interiorPosition.z;
  29964. }
  29965. positions[positionIndex++] = reflectedPosition.x;
  29966. positions[positionIndex++] = reflectedPosition.y;
  29967. positions[positionIndex++] = reflectedPosition.z;
  29968. }
  29969. if (addEdgePositions) {
  29970. outerPositions[outerRightIndex--] = position.z;
  29971. outerPositions[outerRightIndex--] = position.y;
  29972. outerPositions[outerRightIndex--] = position.x;
  29973. outerPositions[outerLeftIndex++] = reflectedPosition.x;
  29974. outerPositions[outerLeftIndex++] = reflectedPosition.y;
  29975. outerPositions[outerLeftIndex++] = reflectedPosition.z;
  29976. }
  29977. theta = CesiumMath.PI_OVER_TWO - (i + 1) * deltaTheta;
  29978. }
  29979. // Compute points in the 'western' half of the ellipse
  29980. for (i = numPts; i > 1; --i) {
  29981. theta = CesiumMath.PI_OVER_TWO - (i - 1) * deltaTheta;
  29982. position = pointOnEllipsoid(-theta, rotation, northVec, eastVec, aSqr, ab, bSqr, mag, unitPos, position);
  29983. reflectedPosition = pointOnEllipsoid(theta + Math.PI, rotation, northVec, eastVec, aSqr, ab, bSqr, mag, unitPos, reflectedPosition);
  29984. if (addFillPositions) {
  29985. positions[positionIndex++] = position.x;
  29986. positions[positionIndex++] = position.y;
  29987. positions[positionIndex++] = position.z;
  29988. numInterior = 2 * (i - 1) + 2;
  29989. for (j = 1; j < numInterior - 1; ++j) {
  29990. t = j / (numInterior - 1);
  29991. interiorPosition = Cartesian3.lerp(position, reflectedPosition, t, scratchCartesian3);
  29992. positions[positionIndex++] = interiorPosition.x;
  29993. positions[positionIndex++] = interiorPosition.y;
  29994. positions[positionIndex++] = interiorPosition.z;
  29995. }
  29996. positions[positionIndex++] = reflectedPosition.x;
  29997. positions[positionIndex++] = reflectedPosition.y;
  29998. positions[positionIndex++] = reflectedPosition.z;
  29999. }
  30000. if (addEdgePositions) {
  30001. outerPositions[outerRightIndex--] = position.z;
  30002. outerPositions[outerRightIndex--] = position.y;
  30003. outerPositions[outerRightIndex--] = position.x;
  30004. outerPositions[outerLeftIndex++] = reflectedPosition.x;
  30005. outerPositions[outerLeftIndex++] = reflectedPosition.y;
  30006. outerPositions[outerLeftIndex++] = reflectedPosition.z;
  30007. }
  30008. }
  30009. theta = CesiumMath.PI_OVER_TWO;
  30010. position = pointOnEllipsoid(-theta, rotation, northVec, eastVec, aSqr, ab, bSqr, mag, unitPos, position);
  30011. var r = {};
  30012. if (addFillPositions) {
  30013. positions[positionIndex++] = position.x;
  30014. positions[positionIndex++] = position.y;
  30015. positions[positionIndex++] = position.z;
  30016. r.positions = positions;
  30017. r.numPts = numPts;
  30018. }
  30019. if (addEdgePositions) {
  30020. outerPositions[outerRightIndex--] = position.z;
  30021. outerPositions[outerRightIndex--] = position.y;
  30022. outerPositions[outerRightIndex--] = position.x;
  30023. r.outerPositions = outerPositions;
  30024. }
  30025. return r;
  30026. };
  30027. return EllipseGeometryLibrary;
  30028. });
  30029. /*global define*/
  30030. define('Core/GeometryInstance',[
  30031. './defaultValue',
  30032. './defined',
  30033. './DeveloperError',
  30034. './Matrix4'
  30035. ], function(
  30036. defaultValue,
  30037. defined,
  30038. DeveloperError,
  30039. Matrix4) {
  30040. 'use strict';
  30041. /**
  30042. * Geometry instancing allows one {@link Geometry} object to be positions in several
  30043. * different locations and colored uniquely. For example, one {@link BoxGeometry} can
  30044. * be instanced several times, each with a different <code>modelMatrix</code> to change
  30045. * its position, rotation, and scale.
  30046. *
  30047. * @alias GeometryInstance
  30048. * @constructor
  30049. *
  30050. * @param {Object} options Object with the following properties:
  30051. * @param {Geometry} options.geometry The geometry to instance.
  30052. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The model matrix that transforms to transform the geometry from model to world coordinates.
  30053. * @param {Object} [options.id] A user-defined object to return when the instance is picked with {@link Scene#pick} or get/set per-instance attributes with {@link Primitive#getGeometryInstanceAttributes}.
  30054. * @param {Object} [options.attributes] Per-instance attributes like a show or color attribute shown in the example below.
  30055. *
  30056. *
  30057. * @example
  30058. * // Create geometry for a box, and two instances that refer to it.
  30059. * // One instance positions the box on the bottom and colored aqua.
  30060. * // The other instance positions the box on the top and color white.
  30061. * var geometry = Cesium.BoxGeometry.fromDimensions({
  30062. * vertexFormat : Cesium.VertexFormat.POSITION_AND_NORMAL,
  30063. * dimensions : new Cesium.Cartesian3(1000000.0, 1000000.0, 500000.0)
  30064. * });
  30065. * var instanceBottom = new Cesium.GeometryInstance({
  30066. * geometry : geometry,
  30067. * modelMatrix : Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(
  30068. * Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883)), new Cesium.Cartesian3(0.0, 0.0, 1000000.0), new Cesium.Matrix4()),
  30069. * attributes : {
  30070. * color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.AQUA)
  30071. * },
  30072. * id : 'bottom'
  30073. * });
  30074. * var instanceTop = new Cesium.GeometryInstance({
  30075. * geometry : geometry,
  30076. * modelMatrix : Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(
  30077. * Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883)), new Cesium.Cartesian3(0.0, 0.0, 3000000.0), new Cesium.Matrix4()),
  30078. * attributes : {
  30079. * color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.AQUA)
  30080. * },
  30081. * id : 'top'
  30082. * });
  30083. *
  30084. * @see Geometry
  30085. */
  30086. function GeometryInstance(options) {
  30087. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  30088. if (!defined(options.geometry)) {
  30089. throw new DeveloperError('options.geometry is required.');
  30090. }
  30091. /**
  30092. * The geometry being instanced.
  30093. *
  30094. * @type Geometry
  30095. *
  30096. * @default undefined
  30097. */
  30098. this.geometry = options.geometry;
  30099. /**
  30100. * The 4x4 transformation matrix that transforms the geometry from model to world coordinates.
  30101. * When this is the identity matrix, the geometry is drawn in world coordinates, i.e., Earth's WGS84 coordinates.
  30102. * Local reference frames can be used by providing a different transformation matrix, like that returned
  30103. * by {@link Transforms.eastNorthUpToFixedFrame}.
  30104. *
  30105. * @type Matrix4
  30106. *
  30107. * @default Matrix4.IDENTITY
  30108. */
  30109. this.modelMatrix = Matrix4.clone(defaultValue(options.modelMatrix, Matrix4.IDENTITY));
  30110. /**
  30111. * User-defined object returned when the instance is picked or used to get/set per-instance attributes.
  30112. *
  30113. * @type Object
  30114. *
  30115. * @default undefined
  30116. *
  30117. * @see Scene#pick
  30118. * @see Primitive#getGeometryInstanceAttributes
  30119. */
  30120. this.id = options.id;
  30121. /**
  30122. * Used for picking primitives that wrap geometry instances.
  30123. *
  30124. * @private
  30125. */
  30126. this.pickPrimitive = options.pickPrimitive;
  30127. /**
  30128. * Per-instance attributes like {@link ColorGeometryInstanceAttribute} or {@link ShowGeometryInstanceAttribute}.
  30129. * {@link Geometry} attributes varying per vertex; these attributes are constant for the entire instance.
  30130. *
  30131. * @type Object
  30132. *
  30133. * @default undefined
  30134. */
  30135. this.attributes = defaultValue(options.attributes, {});
  30136. /**
  30137. * @private
  30138. */
  30139. this.westHemisphereGeometry = undefined;
  30140. /**
  30141. * @private
  30142. */
  30143. this.eastHemisphereGeometry = undefined;
  30144. }
  30145. return GeometryInstance;
  30146. });
  30147. /*global define*/
  30148. define('Core/EncodedCartesian3',[
  30149. './Cartesian3',
  30150. './defined',
  30151. './DeveloperError'
  30152. ], function(
  30153. Cartesian3,
  30154. defined,
  30155. DeveloperError) {
  30156. 'use strict';
  30157. /**
  30158. * A fixed-point encoding of a {@link Cartesian3} with 64-bit floating-point components, as two {@link Cartesian3}
  30159. * values that, when converted to 32-bit floating-point and added, approximate the original input.
  30160. * <p>
  30161. * This is used to encode positions in vertex buffers for rendering without jittering artifacts
  30162. * as described in {@link http://blogs.agi.com/insight3d/index.php/2008/09/03/precisions-precisions/|Precisions, Precisions}.
  30163. * </p>
  30164. *
  30165. * @alias EncodedCartesian3
  30166. * @constructor
  30167. *
  30168. * @private
  30169. */
  30170. function EncodedCartesian3() {
  30171. /**
  30172. * The high bits for each component. Bits 0 to 22 store the whole value. Bits 23 to 31 are not used.
  30173. *
  30174. * @type {Cartesian3}
  30175. * @default {@link Cartesian3.ZERO}
  30176. */
  30177. this.high = Cartesian3.clone(Cartesian3.ZERO);
  30178. /**
  30179. * The low bits for each component. Bits 7 to 22 store the whole value, and bits 0 to 6 store the fraction. Bits 23 to 31 are not used.
  30180. *
  30181. * @type {Cartesian3}
  30182. * @default {@link Cartesian3.ZERO}
  30183. */
  30184. this.low = Cartesian3.clone(Cartesian3.ZERO);
  30185. }
  30186. /**
  30187. * Encodes a 64-bit floating-point value as two floating-point values that, when converted to
  30188. * 32-bit floating-point and added, approximate the original input. The returned object
  30189. * has <code>high</code> and <code>low</code> properties for the high and low bits, respectively.
  30190. * <p>
  30191. * The fixed-point encoding follows {@link http://blogs.agi.com/insight3d/index.php/2008/09/03/precisions-precisions/|Precisions, Precisions}.
  30192. * </p>
  30193. *
  30194. * @param {Number} value The floating-point value to encode.
  30195. * @param {Object} [result] The object onto which to store the result.
  30196. * @returns {Object} The modified result parameter or a new instance if one was not provided.
  30197. *
  30198. * @example
  30199. * var value = 1234567.1234567;
  30200. * var splitValue = Cesium.EncodedCartesian3.encode(value);
  30201. */
  30202. EncodedCartesian3.encode = function(value, result) {
  30203. if (!defined(value)) {
  30204. throw new DeveloperError('value is required');
  30205. }
  30206. if (!defined(result)) {
  30207. result = {
  30208. high : 0.0,
  30209. low : 0.0
  30210. };
  30211. }
  30212. var doubleHigh;
  30213. if (value >= 0.0) {
  30214. doubleHigh = Math.floor(value / 65536.0) * 65536.0;
  30215. result.high = doubleHigh;
  30216. result.low = value - doubleHigh;
  30217. } else {
  30218. doubleHigh = Math.floor(-value / 65536.0) * 65536.0;
  30219. result.high = -doubleHigh;
  30220. result.low = value + doubleHigh;
  30221. }
  30222. return result;
  30223. };
  30224. var scratchEncode = {
  30225. high : 0.0,
  30226. low : 0.0
  30227. };
  30228. /**
  30229. * Encodes a {@link Cartesian3} with 64-bit floating-point components as two {@link Cartesian3}
  30230. * values that, when converted to 32-bit floating-point and added, approximate the original input.
  30231. * <p>
  30232. * The fixed-point encoding follows {@link http://blogs.agi.com/insight3d/index.php/2008/09/03/precisions-precisions/|Precisions, Precisions}.
  30233. * </p>
  30234. *
  30235. * @param {Cartesian3} cartesian The cartesian to encode.
  30236. * @param {EncodedCartesian3} [result] The object onto which to store the result.
  30237. * @returns {EncodedCartesian3} The modified result parameter or a new EncodedCartesian3 instance if one was not provided.
  30238. *
  30239. * @example
  30240. * var cart = new Cesium.Cartesian3(-10000000.0, 0.0, 10000000.0);
  30241. * var encoded = Cesium.EncodedCartesian3.fromCartesian(cart);
  30242. */
  30243. EncodedCartesian3.fromCartesian = function(cartesian, result) {
  30244. if (!defined(cartesian)) {
  30245. throw new DeveloperError('cartesian is required');
  30246. }
  30247. if (!defined(result)) {
  30248. result = new EncodedCartesian3();
  30249. }
  30250. var high = result.high;
  30251. var low = result.low;
  30252. EncodedCartesian3.encode(cartesian.x, scratchEncode);
  30253. high.x = scratchEncode.high;
  30254. low.x = scratchEncode.low;
  30255. EncodedCartesian3.encode(cartesian.y, scratchEncode);
  30256. high.y = scratchEncode.high;
  30257. low.y = scratchEncode.low;
  30258. EncodedCartesian3.encode(cartesian.z, scratchEncode);
  30259. high.z = scratchEncode.high;
  30260. low.z = scratchEncode.low;
  30261. return result;
  30262. };
  30263. var encodedP = new EncodedCartesian3();
  30264. /**
  30265. * Encodes the provided <code>cartesian</code>, and writes it to an array with <code>high</code>
  30266. * components followed by <code>low</code> components, i.e. <code>[high.x, high.y, high.z, low.x, low.y, low.z]</code>.
  30267. * <p>
  30268. * This is used to create interleaved high-precision position vertex attributes.
  30269. * </p>
  30270. *
  30271. * @param {Cartesian3} cartesian The cartesian to encode.
  30272. * @param {Number[]} cartesianArray The array to write to.
  30273. * @param {Number} index The index into the array to start writing. Six elements will be written.
  30274. *
  30275. * @exception {DeveloperError} index must be a number greater than or equal to 0.
  30276. *
  30277. * @example
  30278. * var positions = [
  30279. * new Cesium.Cartesian3(),
  30280. * // ...
  30281. * ];
  30282. * var encodedPositions = new Float32Array(2 * 3 * positions.length);
  30283. * var j = 0;
  30284. * for (var i = 0; i < positions.length; ++i) {
  30285. * Cesium.EncodedCartesian3.writeElement(positions[i], encodedPositions, j);
  30286. * j += 6;
  30287. * }
  30288. */
  30289. EncodedCartesian3.writeElements = function(cartesian, cartesianArray, index) {
  30290. if (!defined(cartesian)) {
  30291. throw new DeveloperError('cartesian is required');
  30292. }
  30293. if (!defined(cartesianArray)) {
  30294. throw new DeveloperError('cartesianArray is required');
  30295. }
  30296. if (typeof index !== 'number' || index < 0) {
  30297. throw new DeveloperError('index must be a number greater than or equal to 0.');
  30298. }
  30299. EncodedCartesian3.fromCartesian(cartesian, encodedP);
  30300. var high = encodedP.high;
  30301. var low = encodedP.low;
  30302. cartesianArray[index] = high.x;
  30303. cartesianArray[index + 1] = high.y;
  30304. cartesianArray[index + 2] = high.z;
  30305. cartesianArray[index + 3] = low.x;
  30306. cartesianArray[index + 4] = low.y;
  30307. cartesianArray[index + 5] = low.z;
  30308. };
  30309. return EncodedCartesian3;
  30310. });
  30311. /*global define*/
  30312. define('Core/Tipsify',[
  30313. './defaultValue',
  30314. './defined',
  30315. './DeveloperError'
  30316. ], function(
  30317. defaultValue,
  30318. defined,
  30319. DeveloperError) {
  30320. 'use strict';
  30321. /**
  30322. * Encapsulates an algorithm to optimize triangles for the post
  30323. * vertex-shader cache. This is based on the 2007 SIGGRAPH paper
  30324. * 'Fast Triangle Reordering for Vertex Locality and Reduced Overdraw.'
  30325. * The runtime is linear but several passes are made.
  30326. *
  30327. * @exports Tipsify
  30328. *
  30329. * @see <a href='http://gfx.cs.princeton.edu/pubs/Sander_2007_%3ETR/tipsy.pdf'>
  30330. * Fast Triangle Reordering for Vertex Locality and Reduced Overdraw</a>
  30331. * by Sander, Nehab, and Barczak
  30332. *
  30333. * @private
  30334. */
  30335. var Tipsify = {};
  30336. /**
  30337. * Calculates the average cache miss ratio (ACMR) for a given set of indices.
  30338. *
  30339. * @param {Object} options Object with the following properties:
  30340. * @param {Number[]} options.indices Lists triads of numbers corresponding to the indices of the vertices
  30341. * in the vertex buffer that define the geometry's triangles.
  30342. * @param {Number} [options.maximumIndex] The maximum value of the elements in <code>args.indices</code>.
  30343. * If not supplied, this value will be computed.
  30344. * @param {Number} [options.cacheSize=24] The number of vertices that can be stored in the cache at any one time.
  30345. * @returns {Number} The average cache miss ratio (ACMR).
  30346. *
  30347. * @exception {DeveloperError} indices length must be a multiple of three.
  30348. * @exception {DeveloperError} cacheSize must be greater than two.
  30349. *
  30350. * @example
  30351. * var indices = [0, 1, 2, 3, 4, 5];
  30352. * var maxIndex = 5;
  30353. * var cacheSize = 3;
  30354. * var acmr = Cesium.Tipsify.calculateACMR({indices : indices, maxIndex : maxIndex, cacheSize : cacheSize});
  30355. */
  30356. Tipsify.calculateACMR = function(options) {
  30357. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  30358. var indices = options.indices;
  30359. var maximumIndex = options.maximumIndex;
  30360. var cacheSize = defaultValue(options.cacheSize, 24);
  30361. if (!defined(indices)) {
  30362. throw new DeveloperError('indices is required.');
  30363. }
  30364. var numIndices = indices.length;
  30365. if (numIndices < 3 || numIndices % 3 !== 0) {
  30366. throw new DeveloperError('indices length must be a multiple of three.');
  30367. }
  30368. if (maximumIndex <= 0) {
  30369. throw new DeveloperError('maximumIndex must be greater than zero.');
  30370. }
  30371. if (cacheSize < 3) {
  30372. throw new DeveloperError('cacheSize must be greater than two.');
  30373. }
  30374. // Compute the maximumIndex if not given
  30375. if (!defined(maximumIndex)) {
  30376. maximumIndex = 0;
  30377. var currentIndex = 0;
  30378. var intoIndices = indices[currentIndex];
  30379. while (currentIndex < numIndices) {
  30380. if (intoIndices > maximumIndex) {
  30381. maximumIndex = intoIndices;
  30382. }
  30383. ++currentIndex;
  30384. intoIndices = indices[currentIndex];
  30385. }
  30386. }
  30387. // Vertex time stamps
  30388. var vertexTimeStamps = [];
  30389. for ( var i = 0; i < maximumIndex + 1; i++) {
  30390. vertexTimeStamps[i] = 0;
  30391. }
  30392. // Cache processing
  30393. var s = cacheSize + 1;
  30394. for ( var j = 0; j < numIndices; ++j) {
  30395. if ((s - vertexTimeStamps[indices[j]]) > cacheSize) {
  30396. vertexTimeStamps[indices[j]] = s;
  30397. ++s;
  30398. }
  30399. }
  30400. return (s - cacheSize + 1) / (numIndices / 3);
  30401. };
  30402. /**
  30403. * Optimizes triangles for the post-vertex shader cache.
  30404. *
  30405. * @param {Number[]} options.indices Lists triads of numbers corresponding to the indices of the vertices
  30406. * in the vertex buffer that define the geometry's triangles.
  30407. * @param {Number} [options.maximumIndex] The maximum value of the elements in <code>args.indices</code>.
  30408. * If not supplied, this value will be computed.
  30409. * @param {Number} [options.cacheSize=24] The number of vertices that can be stored in the cache at any one time.
  30410. * @returns {Number[]} A list of the input indices in an optimized order.
  30411. *
  30412. * @exception {DeveloperError} indices length must be a multiple of three.
  30413. * @exception {DeveloperError} cacheSize must be greater than two.
  30414. *
  30415. * @example
  30416. * var indices = [0, 1, 2, 3, 4, 5];
  30417. * var maxIndex = 5;
  30418. * var cacheSize = 3;
  30419. * var reorderedIndices = Cesium.Tipsify.tipsify({indices : indices, maxIndex : maxIndex, cacheSize : cacheSize});
  30420. */
  30421. Tipsify.tipsify = function(options) {
  30422. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  30423. var indices = options.indices;
  30424. var maximumIndex = options.maximumIndex;
  30425. var cacheSize = defaultValue(options.cacheSize, 24);
  30426. var cursor;
  30427. function skipDeadEnd(vertices, deadEnd, indices, maximumIndexPlusOne) {
  30428. while (deadEnd.length >= 1) {
  30429. // while the stack is not empty
  30430. var d = deadEnd[deadEnd.length - 1]; // top of the stack
  30431. deadEnd.splice(deadEnd.length - 1, 1); // pop the stack
  30432. if (vertices[d].numLiveTriangles > 0) {
  30433. return d;
  30434. }
  30435. }
  30436. while (cursor < maximumIndexPlusOne) {
  30437. if (vertices[cursor].numLiveTriangles > 0) {
  30438. ++cursor;
  30439. return cursor - 1;
  30440. }
  30441. ++cursor;
  30442. }
  30443. return -1;
  30444. }
  30445. function getNextVertex(indices, cacheSize, oneRing, vertices, s, deadEnd, maximumIndexPlusOne) {
  30446. var n = -1;
  30447. var p;
  30448. var m = -1;
  30449. var itOneRing = 0;
  30450. while (itOneRing < oneRing.length) {
  30451. var index = oneRing[itOneRing];
  30452. if (vertices[index].numLiveTriangles) {
  30453. p = 0;
  30454. if ((s - vertices[index].timeStamp + (2 * vertices[index].numLiveTriangles)) <= cacheSize) {
  30455. p = s - vertices[index].timeStamp;
  30456. }
  30457. if ((p > m) || (m === -1)) {
  30458. m = p;
  30459. n = index;
  30460. }
  30461. }
  30462. ++itOneRing;
  30463. }
  30464. if (n === -1) {
  30465. return skipDeadEnd(vertices, deadEnd, indices, maximumIndexPlusOne);
  30466. }
  30467. return n;
  30468. }
  30469. if (!defined(indices)) {
  30470. throw new DeveloperError('indices is required.');
  30471. }
  30472. var numIndices = indices.length;
  30473. if (numIndices < 3 || numIndices % 3 !== 0) {
  30474. throw new DeveloperError('indices length must be a multiple of three.');
  30475. }
  30476. if (maximumIndex <= 0) {
  30477. throw new DeveloperError('maximumIndex must be greater than zero.');
  30478. }
  30479. if (cacheSize < 3) {
  30480. throw new DeveloperError('cacheSize must be greater than two.');
  30481. }
  30482. // Determine maximum index
  30483. var maximumIndexPlusOne = 0;
  30484. var currentIndex = 0;
  30485. var intoIndices = indices[currentIndex];
  30486. var endIndex = numIndices;
  30487. if (defined(maximumIndex)) {
  30488. maximumIndexPlusOne = maximumIndex + 1;
  30489. } else {
  30490. while (currentIndex < endIndex) {
  30491. if (intoIndices > maximumIndexPlusOne) {
  30492. maximumIndexPlusOne = intoIndices;
  30493. }
  30494. ++currentIndex;
  30495. intoIndices = indices[currentIndex];
  30496. }
  30497. if (maximumIndexPlusOne === -1) {
  30498. return 0;
  30499. }
  30500. ++maximumIndexPlusOne;
  30501. }
  30502. // Vertices
  30503. var vertices = [];
  30504. for ( var i = 0; i < maximumIndexPlusOne; i++) {
  30505. vertices[i] = {
  30506. numLiveTriangles : 0,
  30507. timeStamp : 0,
  30508. vertexTriangles : []
  30509. };
  30510. }
  30511. currentIndex = 0;
  30512. var triangle = 0;
  30513. while (currentIndex < endIndex) {
  30514. vertices[indices[currentIndex]].vertexTriangles.push(triangle);
  30515. ++(vertices[indices[currentIndex]]).numLiveTriangles;
  30516. vertices[indices[currentIndex + 1]].vertexTriangles.push(triangle);
  30517. ++(vertices[indices[currentIndex + 1]]).numLiveTriangles;
  30518. vertices[indices[currentIndex + 2]].vertexTriangles.push(triangle);
  30519. ++(vertices[indices[currentIndex + 2]]).numLiveTriangles;
  30520. ++triangle;
  30521. currentIndex += 3;
  30522. }
  30523. // Starting index
  30524. var f = 0;
  30525. // Time Stamp
  30526. var s = cacheSize + 1;
  30527. cursor = 1;
  30528. // Process
  30529. var oneRing = [];
  30530. var deadEnd = []; //Stack
  30531. var vertex;
  30532. var intoVertices;
  30533. var currentOutputIndex = 0;
  30534. var outputIndices = [];
  30535. var numTriangles = numIndices / 3;
  30536. var triangleEmitted = [];
  30537. for (i = 0; i < numTriangles; i++) {
  30538. triangleEmitted[i] = false;
  30539. }
  30540. var index;
  30541. var limit;
  30542. while (f !== -1) {
  30543. oneRing = [];
  30544. intoVertices = vertices[f];
  30545. limit = intoVertices.vertexTriangles.length;
  30546. for ( var k = 0; k < limit; ++k) {
  30547. triangle = intoVertices.vertexTriangles[k];
  30548. if (!triangleEmitted[triangle]) {
  30549. triangleEmitted[triangle] = true;
  30550. currentIndex = triangle + triangle + triangle;
  30551. for ( var j = 0; j < 3; ++j) {
  30552. // Set this index as a possible next index
  30553. index = indices[currentIndex];
  30554. oneRing.push(index);
  30555. deadEnd.push(index);
  30556. // Output index
  30557. outputIndices[currentOutputIndex] = index;
  30558. ++currentOutputIndex;
  30559. // Cache processing
  30560. vertex = vertices[index];
  30561. --vertex.numLiveTriangles;
  30562. if ((s - vertex.timeStamp) > cacheSize) {
  30563. vertex.timeStamp = s;
  30564. ++s;
  30565. }
  30566. ++currentIndex;
  30567. }
  30568. }
  30569. }
  30570. f = getNextVertex(indices, cacheSize, oneRing, vertices, s, deadEnd, maximumIndexPlusOne);
  30571. }
  30572. return outputIndices;
  30573. };
  30574. return Tipsify;
  30575. });
  30576. /*global define*/
  30577. define('Core/GeometryPipeline',[
  30578. './AttributeCompression',
  30579. './barycentricCoordinates',
  30580. './BoundingSphere',
  30581. './Cartesian2',
  30582. './Cartesian3',
  30583. './Cartesian4',
  30584. './Cartographic',
  30585. './ComponentDatatype',
  30586. './defaultValue',
  30587. './defined',
  30588. './DeveloperError',
  30589. './EncodedCartesian3',
  30590. './GeographicProjection',
  30591. './Geometry',
  30592. './GeometryAttribute',
  30593. './GeometryType',
  30594. './IndexDatatype',
  30595. './Intersect',
  30596. './IntersectionTests',
  30597. './Math',
  30598. './Matrix3',
  30599. './Matrix4',
  30600. './Plane',
  30601. './PrimitiveType',
  30602. './Tipsify'
  30603. ], function(
  30604. AttributeCompression,
  30605. barycentricCoordinates,
  30606. BoundingSphere,
  30607. Cartesian2,
  30608. Cartesian3,
  30609. Cartesian4,
  30610. Cartographic,
  30611. ComponentDatatype,
  30612. defaultValue,
  30613. defined,
  30614. DeveloperError,
  30615. EncodedCartesian3,
  30616. GeographicProjection,
  30617. Geometry,
  30618. GeometryAttribute,
  30619. GeometryType,
  30620. IndexDatatype,
  30621. Intersect,
  30622. IntersectionTests,
  30623. CesiumMath,
  30624. Matrix3,
  30625. Matrix4,
  30626. Plane,
  30627. PrimitiveType,
  30628. Tipsify) {
  30629. 'use strict';
  30630. /**
  30631. * Content pipeline functions for geometries.
  30632. *
  30633. * @exports GeometryPipeline
  30634. *
  30635. * @see Geometry
  30636. */
  30637. var GeometryPipeline = {};
  30638. function addTriangle(lines, index, i0, i1, i2) {
  30639. lines[index++] = i0;
  30640. lines[index++] = i1;
  30641. lines[index++] = i1;
  30642. lines[index++] = i2;
  30643. lines[index++] = i2;
  30644. lines[index] = i0;
  30645. }
  30646. function trianglesToLines(triangles) {
  30647. var count = triangles.length;
  30648. var size = (count / 3) * 6;
  30649. var lines = IndexDatatype.createTypedArray(count, size);
  30650. var index = 0;
  30651. for ( var i = 0; i < count; i += 3, index += 6) {
  30652. addTriangle(lines, index, triangles[i], triangles[i + 1], triangles[i + 2]);
  30653. }
  30654. return lines;
  30655. }
  30656. function triangleStripToLines(triangles) {
  30657. var count = triangles.length;
  30658. if (count >= 3) {
  30659. var size = (count - 2) * 6;
  30660. var lines = IndexDatatype.createTypedArray(count, size);
  30661. addTriangle(lines, 0, triangles[0], triangles[1], triangles[2]);
  30662. var index = 6;
  30663. for ( var i = 3; i < count; ++i, index += 6) {
  30664. addTriangle(lines, index, triangles[i - 1], triangles[i], triangles[i - 2]);
  30665. }
  30666. return lines;
  30667. }
  30668. return new Uint16Array();
  30669. }
  30670. function triangleFanToLines(triangles) {
  30671. if (triangles.length > 0) {
  30672. var count = triangles.length - 1;
  30673. var size = (count - 1) * 6;
  30674. var lines = IndexDatatype.createTypedArray(count, size);
  30675. var base = triangles[0];
  30676. var index = 0;
  30677. for ( var i = 1; i < count; ++i, index += 6) {
  30678. addTriangle(lines, index, base, triangles[i], triangles[i + 1]);
  30679. }
  30680. return lines;
  30681. }
  30682. return new Uint16Array();
  30683. }
  30684. /**
  30685. * Converts a geometry's triangle indices to line indices. If the geometry has an <code>indices</code>
  30686. * and its <code>primitiveType</code> is <code>TRIANGLES</code>, <code>TRIANGLE_STRIP</code>,
  30687. * <code>TRIANGLE_FAN</code>, it is converted to <code>LINES</code>; otherwise, the geometry is not changed.
  30688. * <p>
  30689. * This is commonly used to create a wireframe geometry for visual debugging.
  30690. * </p>
  30691. *
  30692. * @param {Geometry} geometry The geometry to modify.
  30693. * @returns {Geometry} The modified <code>geometry</code> argument, with its triangle indices converted to lines.
  30694. *
  30695. * @exception {DeveloperError} geometry.primitiveType must be TRIANGLES, TRIANGLE_STRIP, or TRIANGLE_FAN.
  30696. *
  30697. * @example
  30698. * geometry = Cesium.GeometryPipeline.toWireframe(geometry);
  30699. */
  30700. GeometryPipeline.toWireframe = function(geometry) {
  30701. if (!defined(geometry)) {
  30702. throw new DeveloperError('geometry is required.');
  30703. }
  30704. var indices = geometry.indices;
  30705. if (defined(indices)) {
  30706. switch (geometry.primitiveType) {
  30707. case PrimitiveType.TRIANGLES:
  30708. geometry.indices = trianglesToLines(indices);
  30709. break;
  30710. case PrimitiveType.TRIANGLE_STRIP:
  30711. geometry.indices = triangleStripToLines(indices);
  30712. break;
  30713. case PrimitiveType.TRIANGLE_FAN:
  30714. geometry.indices = triangleFanToLines(indices);
  30715. break;
  30716. default:
  30717. throw new DeveloperError('geometry.primitiveType must be TRIANGLES, TRIANGLE_STRIP, or TRIANGLE_FAN.');
  30718. }
  30719. geometry.primitiveType = PrimitiveType.LINES;
  30720. }
  30721. return geometry;
  30722. };
  30723. /**
  30724. * Creates a new {@link Geometry} with <code>LINES</code> representing the provided
  30725. * attribute (<code>attributeName</code>) for the provided geometry. This is used to
  30726. * visualize vector attributes like normals, binormals, and tangents.
  30727. *
  30728. * @param {Geometry} geometry The <code>Geometry</code> instance with the attribute.
  30729. * @param {String} [attributeName='normal'] The name of the attribute.
  30730. * @param {Number} [length=10000.0] The length of each line segment in meters. This can be negative to point the vector in the opposite direction.
  30731. * @returns {Geometry} A new <code>Geometry</code> instance with line segments for the vector.
  30732. *
  30733. * @exception {DeveloperError} geometry.attributes must have an attribute with the same name as the attributeName parameter.
  30734. *
  30735. * @example
  30736. * var geometry = Cesium.GeometryPipeline.createLineSegmentsForVectors(instance.geometry, 'binormal', 100000.0);
  30737. */
  30738. GeometryPipeline.createLineSegmentsForVectors = function(geometry, attributeName, length) {
  30739. attributeName = defaultValue(attributeName, 'normal');
  30740. if (!defined(geometry)) {
  30741. throw new DeveloperError('geometry is required.');
  30742. }
  30743. if (!defined(geometry.attributes.position)) {
  30744. throw new DeveloperError('geometry.attributes.position is required.');
  30745. }
  30746. if (!defined(geometry.attributes[attributeName])) {
  30747. throw new DeveloperError('geometry.attributes must have an attribute with the same name as the attributeName parameter, ' + attributeName + '.');
  30748. }
  30749. length = defaultValue(length, 10000.0);
  30750. var positions = geometry.attributes.position.values;
  30751. var vectors = geometry.attributes[attributeName].values;
  30752. var positionsLength = positions.length;
  30753. var newPositions = new Float64Array(2 * positionsLength);
  30754. var j = 0;
  30755. for (var i = 0; i < positionsLength; i += 3) {
  30756. newPositions[j++] = positions[i];
  30757. newPositions[j++] = positions[i + 1];
  30758. newPositions[j++] = positions[i + 2];
  30759. newPositions[j++] = positions[i] + (vectors[i] * length);
  30760. newPositions[j++] = positions[i + 1] + (vectors[i + 1] * length);
  30761. newPositions[j++] = positions[i + 2] + (vectors[i + 2] * length);
  30762. }
  30763. var newBoundingSphere;
  30764. var bs = geometry.boundingSphere;
  30765. if (defined(bs)) {
  30766. newBoundingSphere = new BoundingSphere(bs.center, bs.radius + length);
  30767. }
  30768. return new Geometry({
  30769. attributes : {
  30770. position : new GeometryAttribute({
  30771. componentDatatype : ComponentDatatype.DOUBLE,
  30772. componentsPerAttribute : 3,
  30773. values : newPositions
  30774. })
  30775. },
  30776. primitiveType : PrimitiveType.LINES,
  30777. boundingSphere : newBoundingSphere
  30778. });
  30779. };
  30780. /**
  30781. * Creates an object that maps attribute names to unique locations (indices)
  30782. * for matching vertex attributes and shader programs.
  30783. *
  30784. * @param {Geometry} geometry The geometry, which is not modified, to create the object for.
  30785. * @returns {Object} An object with attribute name / index pairs.
  30786. *
  30787. * @example
  30788. * var attributeLocations = Cesium.GeometryPipeline.createAttributeLocations(geometry);
  30789. * // Example output
  30790. * // {
  30791. * // 'position' : 0,
  30792. * // 'normal' : 1
  30793. * // }
  30794. */
  30795. GeometryPipeline.createAttributeLocations = function(geometry) {
  30796. if (!defined(geometry)) {
  30797. throw new DeveloperError('geometry is required.');
  30798. }
  30799. // There can be a WebGL performance hit when attribute 0 is disabled, so
  30800. // assign attribute locations to well-known attributes.
  30801. var semantics = [
  30802. 'position',
  30803. 'positionHigh',
  30804. 'positionLow',
  30805. // From VertexFormat.position - after 2D projection and high-precision encoding
  30806. 'position3DHigh',
  30807. 'position3DLow',
  30808. 'position2DHigh',
  30809. 'position2DLow',
  30810. // From Primitive
  30811. 'pickColor',
  30812. // From VertexFormat
  30813. 'normal',
  30814. 'st',
  30815. 'binormal',
  30816. 'tangent',
  30817. // From compressing texture coordinates and normals
  30818. 'compressedAttributes'
  30819. ];
  30820. var attributes = geometry.attributes;
  30821. var indices = {};
  30822. var j = 0;
  30823. var i;
  30824. var len = semantics.length;
  30825. // Attribute locations for well-known attributes
  30826. for (i = 0; i < len; ++i) {
  30827. var semantic = semantics[i];
  30828. if (defined(attributes[semantic])) {
  30829. indices[semantic] = j++;
  30830. }
  30831. }
  30832. // Locations for custom attributes
  30833. for (var name in attributes) {
  30834. if (attributes.hasOwnProperty(name) && (!defined(indices[name]))) {
  30835. indices[name] = j++;
  30836. }
  30837. }
  30838. return indices;
  30839. };
  30840. /**
  30841. * Reorders a geometry's attributes and <code>indices</code> to achieve better performance from the GPU's pre-vertex-shader cache.
  30842. *
  30843. * @param {Geometry} geometry The geometry to modify.
  30844. * @returns {Geometry} The modified <code>geometry</code> argument, with its attributes and indices reordered for the GPU's pre-vertex-shader cache.
  30845. *
  30846. * @exception {DeveloperError} Each attribute array in geometry.attributes must have the same number of attributes.
  30847. *
  30848. *
  30849. * @example
  30850. * geometry = Cesium.GeometryPipeline.reorderForPreVertexCache(geometry);
  30851. *
  30852. * @see GeometryPipeline.reorderForPostVertexCache
  30853. */
  30854. GeometryPipeline.reorderForPreVertexCache = function(geometry) {
  30855. if (!defined(geometry)) {
  30856. throw new DeveloperError('geometry is required.');
  30857. }
  30858. var numVertices = Geometry.computeNumberOfVertices(geometry);
  30859. var indices = geometry.indices;
  30860. if (defined(indices)) {
  30861. var indexCrossReferenceOldToNew = new Int32Array(numVertices);
  30862. for ( var i = 0; i < numVertices; i++) {
  30863. indexCrossReferenceOldToNew[i] = -1;
  30864. }
  30865. // Construct cross reference and reorder indices
  30866. var indicesIn = indices;
  30867. var numIndices = indicesIn.length;
  30868. var indicesOut = IndexDatatype.createTypedArray(numVertices, numIndices);
  30869. var intoIndicesIn = 0;
  30870. var intoIndicesOut = 0;
  30871. var nextIndex = 0;
  30872. var tempIndex;
  30873. while (intoIndicesIn < numIndices) {
  30874. tempIndex = indexCrossReferenceOldToNew[indicesIn[intoIndicesIn]];
  30875. if (tempIndex !== -1) {
  30876. indicesOut[intoIndicesOut] = tempIndex;
  30877. } else {
  30878. tempIndex = indicesIn[intoIndicesIn];
  30879. indexCrossReferenceOldToNew[tempIndex] = nextIndex;
  30880. indicesOut[intoIndicesOut] = nextIndex;
  30881. ++nextIndex;
  30882. }
  30883. ++intoIndicesIn;
  30884. ++intoIndicesOut;
  30885. }
  30886. geometry.indices = indicesOut;
  30887. // Reorder attributes
  30888. var attributes = geometry.attributes;
  30889. for ( var property in attributes) {
  30890. if (attributes.hasOwnProperty(property) &&
  30891. defined(attributes[property]) &&
  30892. defined(attributes[property].values)) {
  30893. var attribute = attributes[property];
  30894. var elementsIn = attribute.values;
  30895. var intoElementsIn = 0;
  30896. var numComponents = attribute.componentsPerAttribute;
  30897. var elementsOut = ComponentDatatype.createTypedArray(attribute.componentDatatype, nextIndex * numComponents);
  30898. while (intoElementsIn < numVertices) {
  30899. var temp = indexCrossReferenceOldToNew[intoElementsIn];
  30900. if (temp !== -1) {
  30901. for (i = 0; i < numComponents; i++) {
  30902. elementsOut[numComponents * temp + i] = elementsIn[numComponents * intoElementsIn + i];
  30903. }
  30904. }
  30905. ++intoElementsIn;
  30906. }
  30907. attribute.values = elementsOut;
  30908. }
  30909. }
  30910. }
  30911. return geometry;
  30912. };
  30913. /**
  30914. * Reorders a geometry's <code>indices</code> to achieve better performance from the GPU's
  30915. * post vertex-shader cache by using the Tipsify algorithm. If the geometry <code>primitiveType</code>
  30916. * is not <code>TRIANGLES</code> or the geometry does not have an <code>indices</code>, this function has no effect.
  30917. *
  30918. * @param {Geometry} geometry The geometry to modify.
  30919. * @param {Number} [cacheCapacity=24] The number of vertices that can be held in the GPU's vertex cache.
  30920. * @returns {Geometry} The modified <code>geometry</code> argument, with its indices reordered for the post-vertex-shader cache.
  30921. *
  30922. * @exception {DeveloperError} cacheCapacity must be greater than two.
  30923. *
  30924. *
  30925. * @example
  30926. * geometry = Cesium.GeometryPipeline.reorderForPostVertexCache(geometry);
  30927. *
  30928. * @see GeometryPipeline.reorderForPreVertexCache
  30929. * @see {@link http://gfx.cs.princ0eton.edu/pubs/Sander_2007_%3ETR/tipsy.pdf|Fast Triangle Reordering for Vertex Locality and Reduced Overdraw}
  30930. * by Sander, Nehab, and Barczak
  30931. */
  30932. GeometryPipeline.reorderForPostVertexCache = function(geometry, cacheCapacity) {
  30933. if (!defined(geometry)) {
  30934. throw new DeveloperError('geometry is required.');
  30935. }
  30936. var indices = geometry.indices;
  30937. if ((geometry.primitiveType === PrimitiveType.TRIANGLES) && (defined(indices))) {
  30938. var numIndices = indices.length;
  30939. var maximumIndex = 0;
  30940. for ( var j = 0; j < numIndices; j++) {
  30941. if (indices[j] > maximumIndex) {
  30942. maximumIndex = indices[j];
  30943. }
  30944. }
  30945. geometry.indices = Tipsify.tipsify({
  30946. indices : indices,
  30947. maximumIndex : maximumIndex,
  30948. cacheSize : cacheCapacity
  30949. });
  30950. }
  30951. return geometry;
  30952. };
  30953. function copyAttributesDescriptions(attributes) {
  30954. var newAttributes = {};
  30955. for ( var attribute in attributes) {
  30956. if (attributes.hasOwnProperty(attribute) &&
  30957. defined(attributes[attribute]) &&
  30958. defined(attributes[attribute].values)) {
  30959. var attr = attributes[attribute];
  30960. newAttributes[attribute] = new GeometryAttribute({
  30961. componentDatatype : attr.componentDatatype,
  30962. componentsPerAttribute : attr.componentsPerAttribute,
  30963. normalize : attr.normalize,
  30964. values : []
  30965. });
  30966. }
  30967. }
  30968. return newAttributes;
  30969. }
  30970. function copyVertex(destinationAttributes, sourceAttributes, index) {
  30971. for ( var attribute in sourceAttributes) {
  30972. if (sourceAttributes.hasOwnProperty(attribute) &&
  30973. defined(sourceAttributes[attribute]) &&
  30974. defined(sourceAttributes[attribute].values)) {
  30975. var attr = sourceAttributes[attribute];
  30976. for ( var k = 0; k < attr.componentsPerAttribute; ++k) {
  30977. destinationAttributes[attribute].values.push(attr.values[(index * attr.componentsPerAttribute) + k]);
  30978. }
  30979. }
  30980. }
  30981. }
  30982. /**
  30983. * Splits a geometry into multiple geometries, if necessary, to ensure that indices in the
  30984. * <code>indices</code> fit into unsigned shorts. This is used to meet the WebGL requirements
  30985. * when unsigned int indices are not supported.
  30986. * <p>
  30987. * If the geometry does not have any <code>indices</code>, this function has no effect.
  30988. * </p>
  30989. *
  30990. * @param {Geometry} geometry The geometry to be split into multiple geometries.
  30991. * @returns {Geometry[]} An array of geometries, each with indices that fit into unsigned shorts.
  30992. *
  30993. * @exception {DeveloperError} geometry.primitiveType must equal to PrimitiveType.TRIANGLES, PrimitiveType.LINES, or PrimitiveType.POINTS
  30994. * @exception {DeveloperError} All geometry attribute lists must have the same number of attributes.
  30995. *
  30996. * @example
  30997. * var geometries = Cesium.GeometryPipeline.fitToUnsignedShortIndices(geometry);
  30998. */
  30999. GeometryPipeline.fitToUnsignedShortIndices = function(geometry) {
  31000. if (!defined(geometry)) {
  31001. throw new DeveloperError('geometry is required.');
  31002. }
  31003. if ((defined(geometry.indices)) &&
  31004. ((geometry.primitiveType !== PrimitiveType.TRIANGLES) &&
  31005. (geometry.primitiveType !== PrimitiveType.LINES) &&
  31006. (geometry.primitiveType !== PrimitiveType.POINTS))) {
  31007. throw new DeveloperError('geometry.primitiveType must equal to PrimitiveType.TRIANGLES, PrimitiveType.LINES, or PrimitiveType.POINTS.');
  31008. }
  31009. var geometries = [];
  31010. // If there's an index list and more than 64K attributes, it is possible that
  31011. // some indices are outside the range of unsigned short [0, 64K - 1]
  31012. var numberOfVertices = Geometry.computeNumberOfVertices(geometry);
  31013. if (defined(geometry.indices) && (numberOfVertices >= CesiumMath.SIXTY_FOUR_KILOBYTES)) {
  31014. var oldToNewIndex = [];
  31015. var newIndices = [];
  31016. var currentIndex = 0;
  31017. var newAttributes = copyAttributesDescriptions(geometry.attributes);
  31018. var originalIndices = geometry.indices;
  31019. var numberOfIndices = originalIndices.length;
  31020. var indicesPerPrimitive;
  31021. if (geometry.primitiveType === PrimitiveType.TRIANGLES) {
  31022. indicesPerPrimitive = 3;
  31023. } else if (geometry.primitiveType === PrimitiveType.LINES) {
  31024. indicesPerPrimitive = 2;
  31025. } else if (geometry.primitiveType === PrimitiveType.POINTS) {
  31026. indicesPerPrimitive = 1;
  31027. }
  31028. for ( var j = 0; j < numberOfIndices; j += indicesPerPrimitive) {
  31029. for (var k = 0; k < indicesPerPrimitive; ++k) {
  31030. var x = originalIndices[j + k];
  31031. var i = oldToNewIndex[x];
  31032. if (!defined(i)) {
  31033. i = currentIndex++;
  31034. oldToNewIndex[x] = i;
  31035. copyVertex(newAttributes, geometry.attributes, x);
  31036. }
  31037. newIndices.push(i);
  31038. }
  31039. if (currentIndex + indicesPerPrimitive >= CesiumMath.SIXTY_FOUR_KILOBYTES) {
  31040. geometries.push(new Geometry({
  31041. attributes : newAttributes,
  31042. indices : newIndices,
  31043. primitiveType : geometry.primitiveType,
  31044. boundingSphere : geometry.boundingSphere,
  31045. boundingSphereCV : geometry.boundingSphereCV
  31046. }));
  31047. // Reset for next vertex-array
  31048. oldToNewIndex = [];
  31049. newIndices = [];
  31050. currentIndex = 0;
  31051. newAttributes = copyAttributesDescriptions(geometry.attributes);
  31052. }
  31053. }
  31054. if (newIndices.length !== 0) {
  31055. geometries.push(new Geometry({
  31056. attributes : newAttributes,
  31057. indices : newIndices,
  31058. primitiveType : geometry.primitiveType,
  31059. boundingSphere : geometry.boundingSphere,
  31060. boundingSphereCV : geometry.boundingSphereCV
  31061. }));
  31062. }
  31063. } else {
  31064. // No need to split into multiple geometries
  31065. geometries.push(geometry);
  31066. }
  31067. return geometries;
  31068. };
  31069. var scratchProjectTo2DCartesian3 = new Cartesian3();
  31070. var scratchProjectTo2DCartographic = new Cartographic();
  31071. /**
  31072. * Projects a geometry's 3D <code>position</code> attribute to 2D, replacing the <code>position</code>
  31073. * attribute with separate <code>position3D</code> and <code>position2D</code> attributes.
  31074. * <p>
  31075. * If the geometry does not have a <code>position</code>, this function has no effect.
  31076. * </p>
  31077. *
  31078. * @param {Geometry} geometry The geometry to modify.
  31079. * @param {String} attributeName The name of the attribute.
  31080. * @param {String} attributeName3D The name of the attribute in 3D.
  31081. * @param {String} attributeName2D The name of the attribute in 2D.
  31082. * @param {Object} [projection=new GeographicProjection()] The projection to use.
  31083. * @returns {Geometry} The modified <code>geometry</code> argument with <code>position3D</code> and <code>position2D</code> attributes.
  31084. *
  31085. * @exception {DeveloperError} geometry must have attribute matching the attributeName argument.
  31086. * @exception {DeveloperError} The attribute componentDatatype must be ComponentDatatype.DOUBLE.
  31087. * @exception {DeveloperError} Could not project a point to 2D.
  31088. *
  31089. * @example
  31090. * geometry = Cesium.GeometryPipeline.projectTo2D(geometry, 'position', 'position3D', 'position2D');
  31091. */
  31092. GeometryPipeline.projectTo2D = function(geometry, attributeName, attributeName3D, attributeName2D, projection) {
  31093. if (!defined(geometry)) {
  31094. throw new DeveloperError('geometry is required.');
  31095. }
  31096. if (!defined(attributeName)) {
  31097. throw new DeveloperError('attributeName is required.');
  31098. }
  31099. if (!defined(attributeName3D)) {
  31100. throw new DeveloperError('attributeName3D is required.');
  31101. }
  31102. if (!defined(attributeName2D)) {
  31103. throw new DeveloperError('attributeName2D is required.');
  31104. }
  31105. if (!defined(geometry.attributes[attributeName])) {
  31106. throw new DeveloperError('geometry must have attribute matching the attributeName argument: ' + attributeName + '.');
  31107. }
  31108. if (geometry.attributes[attributeName].componentDatatype !== ComponentDatatype.DOUBLE) {
  31109. throw new DeveloperError('The attribute componentDatatype must be ComponentDatatype.DOUBLE.');
  31110. }
  31111. var attribute = geometry.attributes[attributeName];
  31112. projection = (defined(projection)) ? projection : new GeographicProjection();
  31113. var ellipsoid = projection.ellipsoid;
  31114. // Project original values to 2D.
  31115. var values3D = attribute.values;
  31116. var projectedValues = new Float64Array(values3D.length);
  31117. var index = 0;
  31118. for ( var i = 0; i < values3D.length; i += 3) {
  31119. var value = Cartesian3.fromArray(values3D, i, scratchProjectTo2DCartesian3);
  31120. var lonLat = ellipsoid.cartesianToCartographic(value, scratchProjectTo2DCartographic);
  31121. if (!defined(lonLat)) {
  31122. throw new DeveloperError('Could not project point (' + value.x + ', ' + value.y + ', ' + value.z + ') to 2D.');
  31123. }
  31124. var projectedLonLat = projection.project(lonLat, scratchProjectTo2DCartesian3);
  31125. projectedValues[index++] = projectedLonLat.x;
  31126. projectedValues[index++] = projectedLonLat.y;
  31127. projectedValues[index++] = projectedLonLat.z;
  31128. }
  31129. // Rename original cartesians to WGS84 cartesians.
  31130. geometry.attributes[attributeName3D] = attribute;
  31131. // Replace original cartesians with 2D projected cartesians
  31132. geometry.attributes[attributeName2D] = new GeometryAttribute({
  31133. componentDatatype : ComponentDatatype.DOUBLE,
  31134. componentsPerAttribute : 3,
  31135. values : projectedValues
  31136. });
  31137. delete geometry.attributes[attributeName];
  31138. return geometry;
  31139. };
  31140. var encodedResult = {
  31141. high : 0.0,
  31142. low : 0.0
  31143. };
  31144. /**
  31145. * Encodes floating-point geometry attribute values as two separate attributes to improve
  31146. * rendering precision.
  31147. * <p>
  31148. * This is commonly used to create high-precision position vertex attributes.
  31149. * </p>
  31150. *
  31151. * @param {Geometry} geometry The geometry to modify.
  31152. * @param {String} attributeName The name of the attribute.
  31153. * @param {String} attributeHighName The name of the attribute for the encoded high bits.
  31154. * @param {String} attributeLowName The name of the attribute for the encoded low bits.
  31155. * @returns {Geometry} The modified <code>geometry</code> argument, with its encoded attribute.
  31156. *
  31157. * @exception {DeveloperError} geometry must have attribute matching the attributeName argument.
  31158. * @exception {DeveloperError} The attribute componentDatatype must be ComponentDatatype.DOUBLE.
  31159. *
  31160. * @example
  31161. * geometry = Cesium.GeometryPipeline.encodeAttribute(geometry, 'position3D', 'position3DHigh', 'position3DLow');
  31162. */
  31163. GeometryPipeline.encodeAttribute = function(geometry, attributeName, attributeHighName, attributeLowName) {
  31164. if (!defined(geometry)) {
  31165. throw new DeveloperError('geometry is required.');
  31166. }
  31167. if (!defined(attributeName)) {
  31168. throw new DeveloperError('attributeName is required.');
  31169. }
  31170. if (!defined(attributeHighName)) {
  31171. throw new DeveloperError('attributeHighName is required.');
  31172. }
  31173. if (!defined(attributeLowName)) {
  31174. throw new DeveloperError('attributeLowName is required.');
  31175. }
  31176. if (!defined(geometry.attributes[attributeName])) {
  31177. throw new DeveloperError('geometry must have attribute matching the attributeName argument: ' + attributeName + '.');
  31178. }
  31179. if (geometry.attributes[attributeName].componentDatatype !== ComponentDatatype.DOUBLE) {
  31180. throw new DeveloperError('The attribute componentDatatype must be ComponentDatatype.DOUBLE.');
  31181. }
  31182. var attribute = geometry.attributes[attributeName];
  31183. var values = attribute.values;
  31184. var length = values.length;
  31185. var highValues = new Float32Array(length);
  31186. var lowValues = new Float32Array(length);
  31187. for (var i = 0; i < length; ++i) {
  31188. EncodedCartesian3.encode(values[i], encodedResult);
  31189. highValues[i] = encodedResult.high;
  31190. lowValues[i] = encodedResult.low;
  31191. }
  31192. var componentsPerAttribute = attribute.componentsPerAttribute;
  31193. geometry.attributes[attributeHighName] = new GeometryAttribute({
  31194. componentDatatype : ComponentDatatype.FLOAT,
  31195. componentsPerAttribute : componentsPerAttribute,
  31196. values : highValues
  31197. });
  31198. geometry.attributes[attributeLowName] = new GeometryAttribute({
  31199. componentDatatype : ComponentDatatype.FLOAT,
  31200. componentsPerAttribute : componentsPerAttribute,
  31201. values : lowValues
  31202. });
  31203. delete geometry.attributes[attributeName];
  31204. return geometry;
  31205. };
  31206. var scratchCartesian3 = new Cartesian3();
  31207. function transformPoint(matrix, attribute) {
  31208. if (defined(attribute)) {
  31209. var values = attribute.values;
  31210. var length = values.length;
  31211. for (var i = 0; i < length; i += 3) {
  31212. Cartesian3.unpack(values, i, scratchCartesian3);
  31213. Matrix4.multiplyByPoint(matrix, scratchCartesian3, scratchCartesian3);
  31214. Cartesian3.pack(scratchCartesian3, values, i);
  31215. }
  31216. }
  31217. }
  31218. function transformVector(matrix, attribute) {
  31219. if (defined(attribute)) {
  31220. var values = attribute.values;
  31221. var length = values.length;
  31222. for (var i = 0; i < length; i += 3) {
  31223. Cartesian3.unpack(values, i, scratchCartesian3);
  31224. Matrix3.multiplyByVector(matrix, scratchCartesian3, scratchCartesian3);
  31225. scratchCartesian3 = Cartesian3.normalize(scratchCartesian3, scratchCartesian3);
  31226. Cartesian3.pack(scratchCartesian3, values, i);
  31227. }
  31228. }
  31229. }
  31230. var inverseTranspose = new Matrix4();
  31231. var normalMatrix = new Matrix3();
  31232. /**
  31233. * Transforms a geometry instance to world coordinates. This changes
  31234. * the instance's <code>modelMatrix</code> to {@link Matrix4.IDENTITY} and transforms the
  31235. * following attributes if they are present: <code>position</code>, <code>normal</code>,
  31236. * <code>binormal</code>, and <code>tangent</code>.
  31237. *
  31238. * @param {GeometryInstance} instance The geometry instance to modify.
  31239. * @returns {GeometryInstance} The modified <code>instance</code> argument, with its attributes transforms to world coordinates.
  31240. *
  31241. * @example
  31242. * Cesium.GeometryPipeline.transformToWorldCoordinates(instance);
  31243. */
  31244. GeometryPipeline.transformToWorldCoordinates = function(instance) {
  31245. if (!defined(instance)) {
  31246. throw new DeveloperError('instance is required.');
  31247. }
  31248. var modelMatrix = instance.modelMatrix;
  31249. if (Matrix4.equals(modelMatrix, Matrix4.IDENTITY)) {
  31250. // Already in world coordinates
  31251. return instance;
  31252. }
  31253. var attributes = instance.geometry.attributes;
  31254. // Transform attributes in known vertex formats
  31255. transformPoint(modelMatrix, attributes.position);
  31256. transformPoint(modelMatrix, attributes.prevPosition);
  31257. transformPoint(modelMatrix, attributes.nextPosition);
  31258. if ((defined(attributes.normal)) ||
  31259. (defined(attributes.binormal)) ||
  31260. (defined(attributes.tangent))) {
  31261. Matrix4.inverse(modelMatrix, inverseTranspose);
  31262. Matrix4.transpose(inverseTranspose, inverseTranspose);
  31263. Matrix4.getRotation(inverseTranspose, normalMatrix);
  31264. transformVector(normalMatrix, attributes.normal);
  31265. transformVector(normalMatrix, attributes.binormal);
  31266. transformVector(normalMatrix, attributes.tangent);
  31267. }
  31268. var boundingSphere = instance.geometry.boundingSphere;
  31269. if (defined(boundingSphere)) {
  31270. instance.geometry.boundingSphere = BoundingSphere.transform(boundingSphere, modelMatrix, boundingSphere);
  31271. }
  31272. instance.modelMatrix = Matrix4.clone(Matrix4.IDENTITY);
  31273. return instance;
  31274. };
  31275. function findAttributesInAllGeometries(instances, propertyName) {
  31276. var length = instances.length;
  31277. var attributesInAllGeometries = {};
  31278. var attributes0 = instances[0][propertyName].attributes;
  31279. var name;
  31280. for (name in attributes0) {
  31281. if (attributes0.hasOwnProperty(name) &&
  31282. defined(attributes0[name]) &&
  31283. defined(attributes0[name].values)) {
  31284. var attribute = attributes0[name];
  31285. var numberOfComponents = attribute.values.length;
  31286. var inAllGeometries = true;
  31287. // Does this same attribute exist in all geometries?
  31288. for (var i = 1; i < length; ++i) {
  31289. var otherAttribute = instances[i][propertyName].attributes[name];
  31290. if ((!defined(otherAttribute)) ||
  31291. (attribute.componentDatatype !== otherAttribute.componentDatatype) ||
  31292. (attribute.componentsPerAttribute !== otherAttribute.componentsPerAttribute) ||
  31293. (attribute.normalize !== otherAttribute.normalize)) {
  31294. inAllGeometries = false;
  31295. break;
  31296. }
  31297. numberOfComponents += otherAttribute.values.length;
  31298. }
  31299. if (inAllGeometries) {
  31300. attributesInAllGeometries[name] = new GeometryAttribute({
  31301. componentDatatype : attribute.componentDatatype,
  31302. componentsPerAttribute : attribute.componentsPerAttribute,
  31303. normalize : attribute.normalize,
  31304. values : ComponentDatatype.createTypedArray(attribute.componentDatatype, numberOfComponents)
  31305. });
  31306. }
  31307. }
  31308. }
  31309. return attributesInAllGeometries;
  31310. }
  31311. var tempScratch = new Cartesian3();
  31312. function combineGeometries(instances, propertyName) {
  31313. var length = instances.length;
  31314. var name;
  31315. var i;
  31316. var j;
  31317. var k;
  31318. var m = instances[0].modelMatrix;
  31319. var haveIndices = (defined(instances[0][propertyName].indices));
  31320. var primitiveType = instances[0][propertyName].primitiveType;
  31321. for (i = 1; i < length; ++i) {
  31322. if (!Matrix4.equals(instances[i].modelMatrix, m)) {
  31323. throw new DeveloperError('All instances must have the same modelMatrix.');
  31324. }
  31325. if ((defined(instances[i][propertyName].indices)) !== haveIndices) {
  31326. throw new DeveloperError('All instance geometries must have an indices or not have one.');
  31327. }
  31328. if (instances[i][propertyName].primitiveType !== primitiveType) {
  31329. throw new DeveloperError('All instance geometries must have the same primitiveType.');
  31330. }
  31331. }
  31332. // Find subset of attributes in all geometries
  31333. var attributes = findAttributesInAllGeometries(instances, propertyName);
  31334. var values;
  31335. var sourceValues;
  31336. var sourceValuesLength;
  31337. // Combine attributes from each geometry into a single typed array
  31338. for (name in attributes) {
  31339. if (attributes.hasOwnProperty(name)) {
  31340. values = attributes[name].values;
  31341. k = 0;
  31342. for (i = 0; i < length; ++i) {
  31343. sourceValues = instances[i][propertyName].attributes[name].values;
  31344. sourceValuesLength = sourceValues.length;
  31345. for (j = 0; j < sourceValuesLength; ++j) {
  31346. values[k++] = sourceValues[j];
  31347. }
  31348. }
  31349. }
  31350. }
  31351. // Combine index lists
  31352. var indices;
  31353. if (haveIndices) {
  31354. var numberOfIndices = 0;
  31355. for (i = 0; i < length; ++i) {
  31356. numberOfIndices += instances[i][propertyName].indices.length;
  31357. }
  31358. var numberOfVertices = Geometry.computeNumberOfVertices(new Geometry({
  31359. attributes : attributes,
  31360. primitiveType : PrimitiveType.POINTS
  31361. }));
  31362. var destIndices = IndexDatatype.createTypedArray(numberOfVertices, numberOfIndices);
  31363. var destOffset = 0;
  31364. var offset = 0;
  31365. for (i = 0; i < length; ++i) {
  31366. var sourceIndices = instances[i][propertyName].indices;
  31367. var sourceIndicesLen = sourceIndices.length;
  31368. for (k = 0; k < sourceIndicesLen; ++k) {
  31369. destIndices[destOffset++] = offset + sourceIndices[k];
  31370. }
  31371. offset += Geometry.computeNumberOfVertices(instances[i][propertyName]);
  31372. }
  31373. indices = destIndices;
  31374. }
  31375. // Create bounding sphere that includes all instances
  31376. var center = new Cartesian3();
  31377. var radius = 0.0;
  31378. var bs;
  31379. for (i = 0; i < length; ++i) {
  31380. bs = instances[i][propertyName].boundingSphere;
  31381. if (!defined(bs)) {
  31382. // If any geometries have an undefined bounding sphere, then so does the combined geometry
  31383. center = undefined;
  31384. break;
  31385. }
  31386. Cartesian3.add(bs.center, center, center);
  31387. }
  31388. if (defined(center)) {
  31389. Cartesian3.divideByScalar(center, length, center);
  31390. for (i = 0; i < length; ++i) {
  31391. bs = instances[i][propertyName].boundingSphere;
  31392. var tempRadius = Cartesian3.magnitude(Cartesian3.subtract(bs.center, center, tempScratch)) + bs.radius;
  31393. if (tempRadius > radius) {
  31394. radius = tempRadius;
  31395. }
  31396. }
  31397. }
  31398. return new Geometry({
  31399. attributes : attributes,
  31400. indices : indices,
  31401. primitiveType : primitiveType,
  31402. boundingSphere : (defined(center)) ? new BoundingSphere(center, radius) : undefined
  31403. });
  31404. }
  31405. /**
  31406. * Combines geometry from several {@link GeometryInstance} objects into one geometry.
  31407. * This concatenates the attributes, concatenates and adjusts the indices, and creates
  31408. * a bounding sphere encompassing all instances.
  31409. * <p>
  31410. * If the instances do not have the same attributes, a subset of attributes common
  31411. * to all instances is used, and the others are ignored.
  31412. * </p>
  31413. * <p>
  31414. * This is used by {@link Primitive} to efficiently render a large amount of static data.
  31415. * </p>
  31416. *
  31417. * @private
  31418. *
  31419. * @param {GeometryInstance[]} [instances] The array of {@link GeometryInstance} objects whose geometry will be combined.
  31420. * @returns {Geometry} A single geometry created from the provided geometry instances.
  31421. *
  31422. * @exception {DeveloperError} All instances must have the same modelMatrix.
  31423. * @exception {DeveloperError} All instance geometries must have an indices or not have one.
  31424. * @exception {DeveloperError} All instance geometries must have the same primitiveType.
  31425. *
  31426. *
  31427. * @example
  31428. * for (var i = 0; i < instances.length; ++i) {
  31429. * Cesium.GeometryPipeline.transformToWorldCoordinates(instances[i]);
  31430. * }
  31431. * var geometries = Cesium.GeometryPipeline.combineInstances(instances);
  31432. *
  31433. * @see GeometryPipeline.transformToWorldCoordinates
  31434. */
  31435. GeometryPipeline.combineInstances = function(instances) {
  31436. if ((!defined(instances)) || (instances.length < 1)) {
  31437. throw new DeveloperError('instances is required and must have length greater than zero.');
  31438. }
  31439. var instanceGeometry = [];
  31440. var instanceSplitGeometry = [];
  31441. var length = instances.length;
  31442. for (var i = 0; i < length; ++i) {
  31443. var instance = instances[i];
  31444. if (defined(instance.geometry)) {
  31445. instanceGeometry.push(instance);
  31446. } else if (defined(instance.westHemisphereGeometry) && defined(instance.eastHemisphereGeometry)) {
  31447. instanceSplitGeometry.push(instance);
  31448. }
  31449. }
  31450. var geometries = [];
  31451. if (instanceGeometry.length > 0) {
  31452. geometries.push(combineGeometries(instanceGeometry, 'geometry'));
  31453. }
  31454. if (instanceSplitGeometry.length > 0) {
  31455. geometries.push(combineGeometries(instanceSplitGeometry, 'westHemisphereGeometry'));
  31456. geometries.push(combineGeometries(instanceSplitGeometry, 'eastHemisphereGeometry'));
  31457. }
  31458. return geometries;
  31459. };
  31460. var normal = new Cartesian3();
  31461. var v0 = new Cartesian3();
  31462. var v1 = new Cartesian3();
  31463. var v2 = new Cartesian3();
  31464. /**
  31465. * Computes per-vertex normals for a geometry containing <code>TRIANGLES</code> by averaging the normals of
  31466. * all triangles incident to the vertex. The result is a new <code>normal</code> attribute added to the geometry.
  31467. * This assumes a counter-clockwise winding order.
  31468. *
  31469. * @param {Geometry} geometry The geometry to modify.
  31470. * @returns {Geometry} The modified <code>geometry</code> argument with the computed <code>normal</code> attribute.
  31471. *
  31472. * @exception {DeveloperError} geometry.indices length must be greater than 0 and be a multiple of 3.
  31473. * @exception {DeveloperError} geometry.primitiveType must be {@link PrimitiveType.TRIANGLES}.
  31474. *
  31475. * @example
  31476. * Cesium.GeometryPipeline.computeNormal(geometry);
  31477. */
  31478. GeometryPipeline.computeNormal = function(geometry) {
  31479. if (!defined(geometry)) {
  31480. throw new DeveloperError('geometry is required.');
  31481. }
  31482. if (!defined(geometry.attributes.position) || !defined(geometry.attributes.position.values)) {
  31483. throw new DeveloperError('geometry.attributes.position.values is required.');
  31484. }
  31485. if (!defined(geometry.indices)) {
  31486. throw new DeveloperError('geometry.indices is required.');
  31487. }
  31488. if (geometry.indices.length < 2 || geometry.indices.length % 3 !== 0) {
  31489. throw new DeveloperError('geometry.indices length must be greater than 0 and be a multiple of 3.');
  31490. }
  31491. if (geometry.primitiveType !== PrimitiveType.TRIANGLES) {
  31492. throw new DeveloperError('geometry.primitiveType must be PrimitiveType.TRIANGLES.');
  31493. }
  31494. var indices = geometry.indices;
  31495. var attributes = geometry.attributes;
  31496. var vertices = attributes.position.values;
  31497. var numVertices = attributes.position.values.length / 3;
  31498. var numIndices = indices.length;
  31499. var normalsPerVertex = new Array(numVertices);
  31500. var normalsPerTriangle = new Array(numIndices / 3);
  31501. var normalIndices = new Array(numIndices);
  31502. for ( var i = 0; i < numVertices; i++) {
  31503. normalsPerVertex[i] = {
  31504. indexOffset : 0,
  31505. count : 0,
  31506. currentCount : 0
  31507. };
  31508. }
  31509. var j = 0;
  31510. for (i = 0; i < numIndices; i += 3) {
  31511. var i0 = indices[i];
  31512. var i1 = indices[i + 1];
  31513. var i2 = indices[i + 2];
  31514. var i03 = i0 * 3;
  31515. var i13 = i1 * 3;
  31516. var i23 = i2 * 3;
  31517. v0.x = vertices[i03];
  31518. v0.y = vertices[i03 + 1];
  31519. v0.z = vertices[i03 + 2];
  31520. v1.x = vertices[i13];
  31521. v1.y = vertices[i13 + 1];
  31522. v1.z = vertices[i13 + 2];
  31523. v2.x = vertices[i23];
  31524. v2.y = vertices[i23 + 1];
  31525. v2.z = vertices[i23 + 2];
  31526. normalsPerVertex[i0].count++;
  31527. normalsPerVertex[i1].count++;
  31528. normalsPerVertex[i2].count++;
  31529. Cartesian3.subtract(v1, v0, v1);
  31530. Cartesian3.subtract(v2, v0, v2);
  31531. normalsPerTriangle[j] = Cartesian3.cross(v1, v2, new Cartesian3());
  31532. j++;
  31533. }
  31534. var indexOffset = 0;
  31535. for (i = 0; i < numVertices; i++) {
  31536. normalsPerVertex[i].indexOffset += indexOffset;
  31537. indexOffset += normalsPerVertex[i].count;
  31538. }
  31539. j = 0;
  31540. var vertexNormalData;
  31541. for (i = 0; i < numIndices; i += 3) {
  31542. vertexNormalData = normalsPerVertex[indices[i]];
  31543. var index = vertexNormalData.indexOffset + vertexNormalData.currentCount;
  31544. normalIndices[index] = j;
  31545. vertexNormalData.currentCount++;
  31546. vertexNormalData = normalsPerVertex[indices[i + 1]];
  31547. index = vertexNormalData.indexOffset + vertexNormalData.currentCount;
  31548. normalIndices[index] = j;
  31549. vertexNormalData.currentCount++;
  31550. vertexNormalData = normalsPerVertex[indices[i + 2]];
  31551. index = vertexNormalData.indexOffset + vertexNormalData.currentCount;
  31552. normalIndices[index] = j;
  31553. vertexNormalData.currentCount++;
  31554. j++;
  31555. }
  31556. var normalValues = new Float32Array(numVertices * 3);
  31557. for (i = 0; i < numVertices; i++) {
  31558. var i3 = i * 3;
  31559. vertexNormalData = normalsPerVertex[i];
  31560. if (vertexNormalData.count > 0) {
  31561. Cartesian3.clone(Cartesian3.ZERO, normal);
  31562. for (j = 0; j < vertexNormalData.count; j++) {
  31563. Cartesian3.add(normal, normalsPerTriangle[normalIndices[vertexNormalData.indexOffset + j]], normal);
  31564. }
  31565. Cartesian3.normalize(normal, normal);
  31566. normalValues[i3] = normal.x;
  31567. normalValues[i3 + 1] = normal.y;
  31568. normalValues[i3 + 2] = normal.z;
  31569. } else {
  31570. normalValues[i3] = 0.0;
  31571. normalValues[i3 + 1] = 0.0;
  31572. normalValues[i3 + 2] = 1.0;
  31573. }
  31574. }
  31575. geometry.attributes.normal = new GeometryAttribute({
  31576. componentDatatype : ComponentDatatype.FLOAT,
  31577. componentsPerAttribute : 3,
  31578. values : normalValues
  31579. });
  31580. return geometry;
  31581. };
  31582. var normalScratch = new Cartesian3();
  31583. var normalScale = new Cartesian3();
  31584. var tScratch = new Cartesian3();
  31585. /**
  31586. * Computes per-vertex binormals and tangents for a geometry containing <code>TRIANGLES</code>.
  31587. * The result is new <code>binormal</code> and <code>tangent</code> attributes added to the geometry.
  31588. * This assumes a counter-clockwise winding order.
  31589. * <p>
  31590. * Based on <a href="http://www.terathon.com/code/tangent.html">Computing Tangent Space Basis Vectors
  31591. * for an Arbitrary Mesh</a> by Eric Lengyel.
  31592. * </p>
  31593. *
  31594. * @param {Geometry} geometry The geometry to modify.
  31595. * @returns {Geometry} The modified <code>geometry</code> argument with the computed <code>binormal</code> and <code>tangent</code> attributes.
  31596. *
  31597. * @exception {DeveloperError} geometry.indices length must be greater than 0 and be a multiple of 3.
  31598. * @exception {DeveloperError} geometry.primitiveType must be {@link PrimitiveType.TRIANGLES}.
  31599. *
  31600. * @example
  31601. * Cesium.GeometryPipeline.computeBinormalAndTangent(geometry);
  31602. */
  31603. GeometryPipeline.computeBinormalAndTangent = function(geometry) {
  31604. if (!defined(geometry)) {
  31605. throw new DeveloperError('geometry is required.');
  31606. }
  31607. var attributes = geometry.attributes;
  31608. var indices = geometry.indices;
  31609. if (!defined(attributes.position) || !defined(attributes.position.values)) {
  31610. throw new DeveloperError('geometry.attributes.position.values is required.');
  31611. }
  31612. if (!defined(attributes.normal) || !defined(attributes.normal.values)) {
  31613. throw new DeveloperError('geometry.attributes.normal.values is required.');
  31614. }
  31615. if (!defined(attributes.st) || !defined(attributes.st.values)) {
  31616. throw new DeveloperError('geometry.attributes.st.values is required.');
  31617. }
  31618. if (!defined(indices)) {
  31619. throw new DeveloperError('geometry.indices is required.');
  31620. }
  31621. if (indices.length < 2 || indices.length % 3 !== 0) {
  31622. throw new DeveloperError('geometry.indices length must be greater than 0 and be a multiple of 3.');
  31623. }
  31624. if (geometry.primitiveType !== PrimitiveType.TRIANGLES) {
  31625. throw new DeveloperError('geometry.primitiveType must be PrimitiveType.TRIANGLES.');
  31626. }
  31627. var vertices = geometry.attributes.position.values;
  31628. var normals = geometry.attributes.normal.values;
  31629. var st = geometry.attributes.st.values;
  31630. var numVertices = geometry.attributes.position.values.length / 3;
  31631. var numIndices = indices.length;
  31632. var tan1 = new Array(numVertices * 3);
  31633. for ( var i = 0; i < tan1.length; i++) {
  31634. tan1[i] = 0;
  31635. }
  31636. var i03;
  31637. var i13;
  31638. var i23;
  31639. for (i = 0; i < numIndices; i += 3) {
  31640. var i0 = indices[i];
  31641. var i1 = indices[i + 1];
  31642. var i2 = indices[i + 2];
  31643. i03 = i0 * 3;
  31644. i13 = i1 * 3;
  31645. i23 = i2 * 3;
  31646. var i02 = i0 * 2;
  31647. var i12 = i1 * 2;
  31648. var i22 = i2 * 2;
  31649. var ux = vertices[i03];
  31650. var uy = vertices[i03 + 1];
  31651. var uz = vertices[i03 + 2];
  31652. var wx = st[i02];
  31653. var wy = st[i02 + 1];
  31654. var t1 = st[i12 + 1] - wy;
  31655. var t2 = st[i22 + 1] - wy;
  31656. var r = 1.0 / ((st[i12] - wx) * t2 - (st[i22] - wx) * t1);
  31657. var sdirx = (t2 * (vertices[i13] - ux) - t1 * (vertices[i23] - ux)) * r;
  31658. var sdiry = (t2 * (vertices[i13 + 1] - uy) - t1 * (vertices[i23 + 1] - uy)) * r;
  31659. var sdirz = (t2 * (vertices[i13 + 2] - uz) - t1 * (vertices[i23 + 2] - uz)) * r;
  31660. tan1[i03] += sdirx;
  31661. tan1[i03 + 1] += sdiry;
  31662. tan1[i03 + 2] += sdirz;
  31663. tan1[i13] += sdirx;
  31664. tan1[i13 + 1] += sdiry;
  31665. tan1[i13 + 2] += sdirz;
  31666. tan1[i23] += sdirx;
  31667. tan1[i23 + 1] += sdiry;
  31668. tan1[i23 + 2] += sdirz;
  31669. }
  31670. var binormalValues = new Float32Array(numVertices * 3);
  31671. var tangentValues = new Float32Array(numVertices * 3);
  31672. for (i = 0; i < numVertices; i++) {
  31673. i03 = i * 3;
  31674. i13 = i03 + 1;
  31675. i23 = i03 + 2;
  31676. var n = Cartesian3.fromArray(normals, i03, normalScratch);
  31677. var t = Cartesian3.fromArray(tan1, i03, tScratch);
  31678. var scalar = Cartesian3.dot(n, t);
  31679. Cartesian3.multiplyByScalar(n, scalar, normalScale);
  31680. Cartesian3.normalize(Cartesian3.subtract(t, normalScale, t), t);
  31681. tangentValues[i03] = t.x;
  31682. tangentValues[i13] = t.y;
  31683. tangentValues[i23] = t.z;
  31684. Cartesian3.normalize(Cartesian3.cross(n, t, t), t);
  31685. binormalValues[i03] = t.x;
  31686. binormalValues[i13] = t.y;
  31687. binormalValues[i23] = t.z;
  31688. }
  31689. geometry.attributes.tangent = new GeometryAttribute({
  31690. componentDatatype : ComponentDatatype.FLOAT,
  31691. componentsPerAttribute : 3,
  31692. values : tangentValues
  31693. });
  31694. geometry.attributes.binormal = new GeometryAttribute({
  31695. componentDatatype : ComponentDatatype.FLOAT,
  31696. componentsPerAttribute : 3,
  31697. values : binormalValues
  31698. });
  31699. return geometry;
  31700. };
  31701. var scratchCartesian2 = new Cartesian2();
  31702. var toEncode1 = new Cartesian3();
  31703. var toEncode2 = new Cartesian3();
  31704. var toEncode3 = new Cartesian3();
  31705. /**
  31706. * Compresses and packs geometry normal attribute values to save memory.
  31707. *
  31708. * @param {Geometry} geometry The geometry to modify.
  31709. * @returns {Geometry} The modified <code>geometry</code> argument, with its normals compressed and packed.
  31710. *
  31711. * @example
  31712. * geometry = Cesium.GeometryPipeline.compressVertices(geometry);
  31713. */
  31714. GeometryPipeline.compressVertices = function(geometry) {
  31715. if (!defined(geometry)) {
  31716. throw new DeveloperError('geometry is required.');
  31717. }
  31718. var normalAttribute = geometry.attributes.normal;
  31719. var stAttribute = geometry.attributes.st;
  31720. if (!defined(normalAttribute) && !defined(stAttribute)) {
  31721. return geometry;
  31722. }
  31723. var tangentAttribute = geometry.attributes.tangent;
  31724. var binormalAttribute = geometry.attributes.binormal;
  31725. var normals;
  31726. var st;
  31727. var tangents;
  31728. var binormals;
  31729. if (defined(normalAttribute)) {
  31730. normals = normalAttribute.values;
  31731. }
  31732. if (defined(stAttribute)) {
  31733. st = stAttribute.values;
  31734. }
  31735. if (defined(tangentAttribute)) {
  31736. tangents = tangentAttribute.values;
  31737. }
  31738. if (binormalAttribute) {
  31739. binormals = binormalAttribute.values;
  31740. }
  31741. var length = defined(normals) ? normals.length : st.length;
  31742. var numComponents = defined(normals) ? 3.0 : 2.0;
  31743. var numVertices = length / numComponents;
  31744. var compressedLength = numVertices;
  31745. var numCompressedComponents = defined(st) && defined(normals) ? 2.0 : 1.0;
  31746. numCompressedComponents += defined(tangents) || defined(binormals) ? 1.0 : 0.0;
  31747. compressedLength *= numCompressedComponents;
  31748. var compressedAttributes = new Float32Array(compressedLength);
  31749. var normalIndex = 0;
  31750. for (var i = 0; i < numVertices; ++i) {
  31751. if (defined(st)) {
  31752. Cartesian2.fromArray(st, i * 2.0, scratchCartesian2);
  31753. compressedAttributes[normalIndex++] = AttributeCompression.compressTextureCoordinates(scratchCartesian2);
  31754. }
  31755. var index = i * 3.0;
  31756. if (defined(normals) && defined(tangents) && defined(binormals)) {
  31757. Cartesian3.fromArray(normals, index, toEncode1);
  31758. Cartesian3.fromArray(tangents, index, toEncode2);
  31759. Cartesian3.fromArray(binormals, index, toEncode3);
  31760. AttributeCompression.octPack(toEncode1, toEncode2, toEncode3, scratchCartesian2);
  31761. compressedAttributes[normalIndex++] = scratchCartesian2.x;
  31762. compressedAttributes[normalIndex++] = scratchCartesian2.y;
  31763. } else {
  31764. if (defined(normals)) {
  31765. Cartesian3.fromArray(normals, index, toEncode1);
  31766. compressedAttributes[normalIndex++] = AttributeCompression.octEncodeFloat(toEncode1);
  31767. }
  31768. if (defined(tangents)) {
  31769. Cartesian3.fromArray(tangents, index, toEncode1);
  31770. compressedAttributes[normalIndex++] = AttributeCompression.octEncodeFloat(toEncode1);
  31771. }
  31772. if (defined(binormals)) {
  31773. Cartesian3.fromArray(binormals, index, toEncode1);
  31774. compressedAttributes[normalIndex++] = AttributeCompression.octEncodeFloat(toEncode1);
  31775. }
  31776. }
  31777. }
  31778. geometry.attributes.compressedAttributes = new GeometryAttribute({
  31779. componentDatatype : ComponentDatatype.FLOAT,
  31780. componentsPerAttribute : numCompressedComponents,
  31781. values : compressedAttributes
  31782. });
  31783. if (defined(normals)) {
  31784. delete geometry.attributes.normal;
  31785. }
  31786. if (defined(st)) {
  31787. delete geometry.attributes.st;
  31788. }
  31789. if (defined(tangents)) {
  31790. delete geometry.attributes.tangent;
  31791. }
  31792. if (defined(binormals)) {
  31793. delete geometry.attributes.binormal;
  31794. }
  31795. return geometry;
  31796. };
  31797. function indexTriangles(geometry) {
  31798. if (defined(geometry.indices)) {
  31799. return geometry;
  31800. }
  31801. var numberOfVertices = Geometry.computeNumberOfVertices(geometry);
  31802. if (numberOfVertices < 3) {
  31803. throw new DeveloperError('The number of vertices must be at least three.');
  31804. }
  31805. if (numberOfVertices % 3 !== 0) {
  31806. throw new DeveloperError('The number of vertices must be a multiple of three.');
  31807. }
  31808. var indices = IndexDatatype.createTypedArray(numberOfVertices, numberOfVertices);
  31809. for (var i = 0; i < numberOfVertices; ++i) {
  31810. indices[i] = i;
  31811. }
  31812. geometry.indices = indices;
  31813. return geometry;
  31814. }
  31815. function indexTriangleFan(geometry) {
  31816. var numberOfVertices = Geometry.computeNumberOfVertices(geometry);
  31817. if (numberOfVertices < 3) {
  31818. throw new DeveloperError('The number of vertices must be at least three.');
  31819. }
  31820. var indices = IndexDatatype.createTypedArray(numberOfVertices, (numberOfVertices - 2) * 3);
  31821. indices[0] = 1;
  31822. indices[1] = 0;
  31823. indices[2] = 2;
  31824. var indicesIndex = 3;
  31825. for (var i = 3; i < numberOfVertices; ++i) {
  31826. indices[indicesIndex++] = i - 1;
  31827. indices[indicesIndex++] = 0;
  31828. indices[indicesIndex++] = i;
  31829. }
  31830. geometry.indices = indices;
  31831. geometry.primitiveType = PrimitiveType.TRIANGLES;
  31832. return geometry;
  31833. }
  31834. function indexTriangleStrip(geometry) {
  31835. var numberOfVertices = Geometry.computeNumberOfVertices(geometry);
  31836. if (numberOfVertices < 3) {
  31837. throw new DeveloperError('The number of vertices must be at least 3.');
  31838. }
  31839. var indices = IndexDatatype.createTypedArray(numberOfVertices, (numberOfVertices - 2) * 3);
  31840. indices[0] = 0;
  31841. indices[1] = 1;
  31842. indices[2] = 2;
  31843. if (numberOfVertices > 3) {
  31844. indices[3] = 0;
  31845. indices[4] = 2;
  31846. indices[5] = 3;
  31847. }
  31848. var indicesIndex = 6;
  31849. for (var i = 3; i < numberOfVertices - 1; i += 2) {
  31850. indices[indicesIndex++] = i;
  31851. indices[indicesIndex++] = i - 1;
  31852. indices[indicesIndex++] = i + 1;
  31853. if (i + 2 < numberOfVertices) {
  31854. indices[indicesIndex++] = i;
  31855. indices[indicesIndex++] = i + 1;
  31856. indices[indicesIndex++] = i + 2;
  31857. }
  31858. }
  31859. geometry.indices = indices;
  31860. geometry.primitiveType = PrimitiveType.TRIANGLES;
  31861. return geometry;
  31862. }
  31863. function indexLines(geometry) {
  31864. if (defined(geometry.indices)) {
  31865. return geometry;
  31866. }
  31867. var numberOfVertices = Geometry.computeNumberOfVertices(geometry);
  31868. if (numberOfVertices < 2) {
  31869. throw new DeveloperError('The number of vertices must be at least two.');
  31870. }
  31871. if (numberOfVertices % 2 !== 0) {
  31872. throw new DeveloperError('The number of vertices must be a multiple of 2.');
  31873. }
  31874. var indices = IndexDatatype.createTypedArray(numberOfVertices, numberOfVertices);
  31875. for (var i = 0; i < numberOfVertices; ++i) {
  31876. indices[i] = i;
  31877. }
  31878. geometry.indices = indices;
  31879. return geometry;
  31880. }
  31881. function indexLineStrip(geometry) {
  31882. var numberOfVertices = Geometry.computeNumberOfVertices(geometry);
  31883. if (numberOfVertices < 2) {
  31884. throw new DeveloperError('The number of vertices must be at least two.');
  31885. }
  31886. var indices = IndexDatatype.createTypedArray(numberOfVertices, (numberOfVertices - 1) * 2);
  31887. indices[0] = 0;
  31888. indices[1] = 1;
  31889. var indicesIndex = 2;
  31890. for (var i = 2; i < numberOfVertices; ++i) {
  31891. indices[indicesIndex++] = i - 1;
  31892. indices[indicesIndex++] = i;
  31893. }
  31894. geometry.indices = indices;
  31895. geometry.primitiveType = PrimitiveType.LINES;
  31896. return geometry;
  31897. }
  31898. function indexLineLoop(geometry) {
  31899. var numberOfVertices = Geometry.computeNumberOfVertices(geometry);
  31900. if (numberOfVertices < 2) {
  31901. throw new DeveloperError('The number of vertices must be at least two.');
  31902. }
  31903. var indices = IndexDatatype.createTypedArray(numberOfVertices, numberOfVertices * 2);
  31904. indices[0] = 0;
  31905. indices[1] = 1;
  31906. var indicesIndex = 2;
  31907. for (var i = 2; i < numberOfVertices; ++i) {
  31908. indices[indicesIndex++] = i - 1;
  31909. indices[indicesIndex++] = i;
  31910. }
  31911. indices[indicesIndex++] = numberOfVertices - 1;
  31912. indices[indicesIndex] = 0;
  31913. geometry.indices = indices;
  31914. geometry.primitiveType = PrimitiveType.LINES;
  31915. return geometry;
  31916. }
  31917. function indexPrimitive(geometry) {
  31918. switch (geometry.primitiveType) {
  31919. case PrimitiveType.TRIANGLE_FAN:
  31920. return indexTriangleFan(geometry);
  31921. case PrimitiveType.TRIANGLE_STRIP:
  31922. return indexTriangleStrip(geometry);
  31923. case PrimitiveType.TRIANGLES:
  31924. return indexTriangles(geometry);
  31925. case PrimitiveType.LINE_STRIP:
  31926. return indexLineStrip(geometry);
  31927. case PrimitiveType.LINE_LOOP:
  31928. return indexLineLoop(geometry);
  31929. case PrimitiveType.LINES:
  31930. return indexLines(geometry);
  31931. }
  31932. return geometry;
  31933. }
  31934. function offsetPointFromXZPlane(p, isBehind) {
  31935. if (Math.abs(p.y) < CesiumMath.EPSILON6){
  31936. if (isBehind) {
  31937. p.y = -CesiumMath.EPSILON6;
  31938. } else {
  31939. p.y = CesiumMath.EPSILON6;
  31940. }
  31941. }
  31942. }
  31943. function offsetTriangleFromXZPlane(p0, p1, p2) {
  31944. if (p0.y !== 0.0 && p1.y !== 0.0 && p2.y !== 0.0) {
  31945. offsetPointFromXZPlane(p0, p0.y < 0.0);
  31946. offsetPointFromXZPlane(p1, p1.y < 0.0);
  31947. offsetPointFromXZPlane(p2, p2.y < 0.0);
  31948. return;
  31949. }
  31950. var p0y = Math.abs(p0.y);
  31951. var p1y = Math.abs(p1.y);
  31952. var p2y = Math.abs(p2.y);
  31953. var sign;
  31954. if (p0y > p1y) {
  31955. if (p0y > p2y) {
  31956. sign = CesiumMath.sign(p0.y);
  31957. } else {
  31958. sign = CesiumMath.sign(p2.y);
  31959. }
  31960. } else if (p1y > p2y) {
  31961. sign = CesiumMath.sign(p1.y);
  31962. } else {
  31963. sign = CesiumMath.sign(p2.y);
  31964. }
  31965. var isBehind = sign < 0.0;
  31966. offsetPointFromXZPlane(p0, isBehind);
  31967. offsetPointFromXZPlane(p1, isBehind);
  31968. offsetPointFromXZPlane(p2, isBehind);
  31969. }
  31970. var c3 = new Cartesian3();
  31971. function getXZIntersectionOffsetPoints(p, p1, u1, v1) {
  31972. Cartesian3.add(p, Cartesian3.multiplyByScalar(Cartesian3.subtract(p1, p, c3), p.y/(p.y-p1.y), c3), u1);
  31973. Cartesian3.clone(u1, v1);
  31974. offsetPointFromXZPlane(u1, true);
  31975. offsetPointFromXZPlane(v1, false);
  31976. }
  31977. var u1 = new Cartesian3();
  31978. var u2 = new Cartesian3();
  31979. var q1 = new Cartesian3();
  31980. var q2 = new Cartesian3();
  31981. var splitTriangleResult = {
  31982. positions : new Array(7),
  31983. indices : new Array(3 * 3)
  31984. };
  31985. function splitTriangle(p0, p1, p2) {
  31986. // In WGS84 coordinates, for a triangle approximately on the
  31987. // ellipsoid to cross the IDL, first it needs to be on the
  31988. // negative side of the plane x = 0.
  31989. if ((p0.x >= 0.0) || (p1.x >= 0.0) || (p2.x >= 0.0)) {
  31990. return undefined;
  31991. }
  31992. offsetTriangleFromXZPlane(p0, p1, p2);
  31993. var p0Behind = p0.y < 0.0;
  31994. var p1Behind = p1.y < 0.0;
  31995. var p2Behind = p2.y < 0.0;
  31996. var numBehind = 0;
  31997. numBehind += p0Behind ? 1 : 0;
  31998. numBehind += p1Behind ? 1 : 0;
  31999. numBehind += p2Behind ? 1 : 0;
  32000. var indices = splitTriangleResult.indices;
  32001. if (numBehind === 1) {
  32002. indices[1] = 3;
  32003. indices[2] = 4;
  32004. indices[5] = 6;
  32005. indices[7] = 6;
  32006. indices[8] = 5;
  32007. if (p0Behind) {
  32008. getXZIntersectionOffsetPoints(p0, p1, u1, q1);
  32009. getXZIntersectionOffsetPoints(p0, p2, u2, q2);
  32010. indices[0] = 0;
  32011. indices[3] = 1;
  32012. indices[4] = 2;
  32013. indices[6] = 1;
  32014. } else if (p1Behind) {
  32015. getXZIntersectionOffsetPoints(p1, p2, u1, q1);
  32016. getXZIntersectionOffsetPoints(p1, p0, u2, q2);
  32017. indices[0] = 1;
  32018. indices[3] = 2;
  32019. indices[4] = 0;
  32020. indices[6] = 2;
  32021. } else if (p2Behind) {
  32022. getXZIntersectionOffsetPoints(p2, p0, u1, q1);
  32023. getXZIntersectionOffsetPoints(p2, p1, u2, q2);
  32024. indices[0] = 2;
  32025. indices[3] = 0;
  32026. indices[4] = 1;
  32027. indices[6] = 0;
  32028. }
  32029. } else if (numBehind === 2) {
  32030. indices[2] = 4;
  32031. indices[4] = 4;
  32032. indices[5] = 3;
  32033. indices[7] = 5;
  32034. indices[8] = 6;
  32035. if (!p0Behind) {
  32036. getXZIntersectionOffsetPoints(p0, p1, u1, q1);
  32037. getXZIntersectionOffsetPoints(p0, p2, u2, q2);
  32038. indices[0] = 1;
  32039. indices[1] = 2;
  32040. indices[3] = 1;
  32041. indices[6] = 0;
  32042. } else if (!p1Behind) {
  32043. getXZIntersectionOffsetPoints(p1, p2, u1, q1);
  32044. getXZIntersectionOffsetPoints(p1, p0, u2, q2);
  32045. indices[0] = 2;
  32046. indices[1] = 0;
  32047. indices[3] = 2;
  32048. indices[6] = 1;
  32049. } else if (!p2Behind) {
  32050. getXZIntersectionOffsetPoints(p2, p0, u1, q1);
  32051. getXZIntersectionOffsetPoints(p2, p1, u2, q2);
  32052. indices[0] = 0;
  32053. indices[1] = 1;
  32054. indices[3] = 0;
  32055. indices[6] = 2;
  32056. }
  32057. }
  32058. var positions = splitTriangleResult.positions;
  32059. positions[0] = p0;
  32060. positions[1] = p1;
  32061. positions[2] = p2;
  32062. positions.length = 3;
  32063. if (numBehind === 1 || numBehind === 2) {
  32064. positions[3] = u1;
  32065. positions[4] = u2;
  32066. positions[5] = q1;
  32067. positions[6] = q2;
  32068. positions.length = 7;
  32069. }
  32070. return splitTriangleResult;
  32071. }
  32072. function updateGeometryAfterSplit(geometry, computeBoundingSphere) {
  32073. var attributes = geometry.attributes;
  32074. if (attributes.position.values.length === 0) {
  32075. return undefined;
  32076. }
  32077. for (var property in attributes) {
  32078. if (attributes.hasOwnProperty(property) &&
  32079. defined(attributes[property]) &&
  32080. defined(attributes[property].values)) {
  32081. var attribute = attributes[property];
  32082. attribute.values = ComponentDatatype.createTypedArray(attribute.componentDatatype, attribute.values);
  32083. }
  32084. }
  32085. var numberOfVertices = Geometry.computeNumberOfVertices(geometry);
  32086. geometry.indices = IndexDatatype.createTypedArray(numberOfVertices, geometry.indices);
  32087. if (computeBoundingSphere) {
  32088. geometry.boundingSphere = BoundingSphere.fromVertices(attributes.position.values);
  32089. }
  32090. return geometry;
  32091. }
  32092. function copyGeometryForSplit(geometry) {
  32093. var attributes = geometry.attributes;
  32094. var copiedAttributes = {};
  32095. for (var property in attributes) {
  32096. if (attributes.hasOwnProperty(property) &&
  32097. defined(attributes[property]) &&
  32098. defined(attributes[property].values)) {
  32099. var attribute = attributes[property];
  32100. copiedAttributes[property] = new GeometryAttribute({
  32101. componentDatatype : attribute.componentDatatype,
  32102. componentsPerAttribute : attribute.componentsPerAttribute,
  32103. normalize : attribute.normalize,
  32104. values : []
  32105. });
  32106. }
  32107. }
  32108. return new Geometry({
  32109. attributes : copiedAttributes,
  32110. indices : [],
  32111. primitiveType : geometry.primitiveType
  32112. });
  32113. }
  32114. function updateInstanceAfterSplit(instance, westGeometry, eastGeometry) {
  32115. var computeBoundingSphere = defined(instance.geometry.boundingSphere);
  32116. westGeometry = updateGeometryAfterSplit(westGeometry, computeBoundingSphere);
  32117. eastGeometry = updateGeometryAfterSplit(eastGeometry, computeBoundingSphere);
  32118. if (defined(eastGeometry) && !defined(westGeometry)) {
  32119. instance.geometry = eastGeometry;
  32120. } else if (!defined(eastGeometry) && defined(westGeometry)) {
  32121. instance.geometry = westGeometry;
  32122. } else {
  32123. instance.westHemisphereGeometry = westGeometry;
  32124. instance.eastHemisphereGeometry = eastGeometry;
  32125. instance.geometry = undefined;
  32126. }
  32127. }
  32128. var p0Scratch = new Cartesian3();
  32129. var p1Scratch = new Cartesian3();
  32130. var p2Scratch = new Cartesian3();
  32131. var barycentricScratch = new Cartesian3();
  32132. var s0Scratch = new Cartesian2();
  32133. var s1Scratch = new Cartesian2();
  32134. var s2Scratch = new Cartesian2();
  32135. function computeTriangleAttributes(i0, i1, i2, point, positions, normals, binormals, tangents, texCoords, currentAttributes, insertedIndex) {
  32136. if (!defined(normals) && !defined(binormals) && !defined(tangents) && !defined(texCoords)) {
  32137. return;
  32138. }
  32139. var p0 = Cartesian3.fromArray(positions, i0 * 3, p0Scratch);
  32140. var p1 = Cartesian3.fromArray(positions, i1 * 3, p1Scratch);
  32141. var p2 = Cartesian3.fromArray(positions, i2 * 3, p2Scratch);
  32142. var coords = barycentricCoordinates(point, p0, p1, p2, barycentricScratch);
  32143. if (defined(normals)) {
  32144. var n0 = Cartesian3.fromArray(normals, i0 * 3, p0Scratch);
  32145. var n1 = Cartesian3.fromArray(normals, i1 * 3, p1Scratch);
  32146. var n2 = Cartesian3.fromArray(normals, i2 * 3, p2Scratch);
  32147. Cartesian3.multiplyByScalar(n0, coords.x, n0);
  32148. Cartesian3.multiplyByScalar(n1, coords.y, n1);
  32149. Cartesian3.multiplyByScalar(n2, coords.z, n2);
  32150. var normal = Cartesian3.add(n0, n1, n0);
  32151. Cartesian3.add(normal, n2, normal);
  32152. Cartesian3.normalize(normal, normal);
  32153. Cartesian3.pack(normal, currentAttributes.normal.values, insertedIndex * 3);
  32154. }
  32155. if (defined(binormals)) {
  32156. var b0 = Cartesian3.fromArray(binormals, i0 * 3, p0Scratch);
  32157. var b1 = Cartesian3.fromArray(binormals, i1 * 3, p1Scratch);
  32158. var b2 = Cartesian3.fromArray(binormals, i2 * 3, p2Scratch);
  32159. Cartesian3.multiplyByScalar(b0, coords.x, b0);
  32160. Cartesian3.multiplyByScalar(b1, coords.y, b1);
  32161. Cartesian3.multiplyByScalar(b2, coords.z, b2);
  32162. var binormal = Cartesian3.add(b0, b1, b0);
  32163. Cartesian3.add(binormal, b2, binormal);
  32164. Cartesian3.normalize(binormal, binormal);
  32165. Cartesian3.pack(binormal, currentAttributes.binormal.values, insertedIndex * 3);
  32166. }
  32167. if (defined(tangents)) {
  32168. var t0 = Cartesian3.fromArray(tangents, i0 * 3, p0Scratch);
  32169. var t1 = Cartesian3.fromArray(tangents, i1 * 3, p1Scratch);
  32170. var t2 = Cartesian3.fromArray(tangents, i2 * 3, p2Scratch);
  32171. Cartesian3.multiplyByScalar(t0, coords.x, t0);
  32172. Cartesian3.multiplyByScalar(t1, coords.y, t1);
  32173. Cartesian3.multiplyByScalar(t2, coords.z, t2);
  32174. var tangent = Cartesian3.add(t0, t1, t0);
  32175. Cartesian3.add(tangent, t2, tangent);
  32176. Cartesian3.normalize(tangent, tangent);
  32177. Cartesian3.pack(tangent, currentAttributes.tangent.values, insertedIndex * 3);
  32178. }
  32179. if (defined(texCoords)) {
  32180. var s0 = Cartesian2.fromArray(texCoords, i0 * 2, s0Scratch);
  32181. var s1 = Cartesian2.fromArray(texCoords, i1 * 2, s1Scratch);
  32182. var s2 = Cartesian2.fromArray(texCoords, i2 * 2, s2Scratch);
  32183. Cartesian2.multiplyByScalar(s0, coords.x, s0);
  32184. Cartesian2.multiplyByScalar(s1, coords.y, s1);
  32185. Cartesian2.multiplyByScalar(s2, coords.z, s2);
  32186. var texCoord = Cartesian2.add(s0, s1, s0);
  32187. Cartesian2.add(texCoord, s2, texCoord);
  32188. Cartesian2.pack(texCoord, currentAttributes.st.values, insertedIndex * 2);
  32189. }
  32190. }
  32191. function insertSplitPoint(currentAttributes, currentIndices, currentIndexMap, indices, currentIndex, point) {
  32192. var insertIndex = currentAttributes.position.values.length / 3;
  32193. if (currentIndex !== -1) {
  32194. var prevIndex = indices[currentIndex];
  32195. var newIndex = currentIndexMap[prevIndex];
  32196. if (newIndex === -1) {
  32197. currentIndexMap[prevIndex] = insertIndex;
  32198. currentAttributes.position.values.push(point.x, point.y, point.z);
  32199. currentIndices.push(insertIndex);
  32200. return insertIndex;
  32201. }
  32202. currentIndices.push(newIndex);
  32203. return newIndex;
  32204. }
  32205. currentAttributes.position.values.push(point.x, point.y, point.z);
  32206. currentIndices.push(insertIndex);
  32207. return insertIndex;
  32208. }
  32209. function splitLongitudeTriangles(instance) {
  32210. var geometry = instance.geometry;
  32211. var attributes = geometry.attributes;
  32212. var positions = attributes.position.values;
  32213. var normals = (defined(attributes.normal)) ? attributes.normal.values : undefined;
  32214. var binormals = (defined(attributes.binormal)) ? attributes.binormal.values : undefined;
  32215. var tangents = (defined(attributes.tangent)) ? attributes.tangent.values : undefined;
  32216. var texCoords = (defined(attributes.st)) ? attributes.st.values : undefined;
  32217. var indices = geometry.indices;
  32218. var eastGeometry = copyGeometryForSplit(geometry);
  32219. var westGeometry = copyGeometryForSplit(geometry);
  32220. var currentAttributes;
  32221. var currentIndices;
  32222. var currentIndexMap;
  32223. var insertedIndex;
  32224. var i;
  32225. var westGeometryIndexMap = [];
  32226. westGeometryIndexMap.length = positions.length / 3;
  32227. var eastGeometryIndexMap = [];
  32228. eastGeometryIndexMap.length = positions.length / 3;
  32229. for (i = 0; i < westGeometryIndexMap.length; ++i) {
  32230. westGeometryIndexMap[i] = -1;
  32231. eastGeometryIndexMap[i] = -1;
  32232. }
  32233. var len = indices.length;
  32234. for (i = 0; i < len; i += 3) {
  32235. var i0 = indices[i];
  32236. var i1 = indices[i + 1];
  32237. var i2 = indices[i + 2];
  32238. var p0 = Cartesian3.fromArray(positions, i0 * 3);
  32239. var p1 = Cartesian3.fromArray(positions, i1 * 3);
  32240. var p2 = Cartesian3.fromArray(positions, i2 * 3);
  32241. var result = splitTriangle(p0, p1, p2);
  32242. if (defined(result) && result.positions.length > 3) {
  32243. var resultPositions = result.positions;
  32244. var resultIndices = result.indices;
  32245. var resultLength = resultIndices.length;
  32246. for (var j = 0; j < resultLength; ++j) {
  32247. var resultIndex = resultIndices[j];
  32248. var point = resultPositions[resultIndex];
  32249. if (point.y < 0.0) {
  32250. currentAttributes = westGeometry.attributes;
  32251. currentIndices = westGeometry.indices;
  32252. currentIndexMap = westGeometryIndexMap;
  32253. } else {
  32254. currentAttributes = eastGeometry.attributes;
  32255. currentIndices = eastGeometry.indices;
  32256. currentIndexMap = eastGeometryIndexMap;
  32257. }
  32258. insertedIndex = insertSplitPoint(currentAttributes, currentIndices, currentIndexMap, indices, resultIndex < 3 ? i + resultIndex : -1, point);
  32259. computeTriangleAttributes(i0, i1, i2, point, positions, normals, binormals, tangents, texCoords, currentAttributes, insertedIndex);
  32260. }
  32261. } else {
  32262. if (defined(result)) {
  32263. p0 = result.positions[0];
  32264. p1 = result.positions[1];
  32265. p2 = result.positions[2];
  32266. }
  32267. if (p0.y < 0.0) {
  32268. currentAttributes = westGeometry.attributes;
  32269. currentIndices = westGeometry.indices;
  32270. currentIndexMap = westGeometryIndexMap;
  32271. } else {
  32272. currentAttributes = eastGeometry.attributes;
  32273. currentIndices = eastGeometry.indices;
  32274. currentIndexMap = eastGeometryIndexMap;
  32275. }
  32276. insertedIndex = insertSplitPoint(currentAttributes, currentIndices, currentIndexMap, indices, i, p0);
  32277. computeTriangleAttributes(i0, i1, i2, p0, positions, normals, binormals, tangents, texCoords, currentAttributes, insertedIndex);
  32278. insertedIndex = insertSplitPoint(currentAttributes, currentIndices, currentIndexMap, indices, i + 1, p1);
  32279. computeTriangleAttributes(i0, i1, i2, p1, positions, normals, binormals, tangents, texCoords, currentAttributes, insertedIndex);
  32280. insertedIndex = insertSplitPoint(currentAttributes, currentIndices, currentIndexMap, indices, i + 2, p2);
  32281. computeTriangleAttributes(i0, i1, i2, p2, positions, normals, binormals, tangents, texCoords, currentAttributes, insertedIndex);
  32282. }
  32283. }
  32284. updateInstanceAfterSplit(instance, westGeometry, eastGeometry);
  32285. }
  32286. var xzPlane = Plane.fromPointNormal(Cartesian3.ZERO, Cartesian3.UNIT_Y);
  32287. var offsetScratch = new Cartesian3();
  32288. var offsetPointScratch = new Cartesian3();
  32289. function splitLongitudeLines(instance) {
  32290. var geometry = instance.geometry;
  32291. var attributes = geometry.attributes;
  32292. var positions = attributes.position.values;
  32293. var indices = geometry.indices;
  32294. var eastGeometry = copyGeometryForSplit(geometry);
  32295. var westGeometry = copyGeometryForSplit(geometry);
  32296. var i;
  32297. var length = indices.length;
  32298. var westGeometryIndexMap = [];
  32299. westGeometryIndexMap.length = positions.length / 3;
  32300. var eastGeometryIndexMap = [];
  32301. eastGeometryIndexMap.length = positions.length / 3;
  32302. for (i = 0; i < westGeometryIndexMap.length; ++i) {
  32303. westGeometryIndexMap[i] = -1;
  32304. eastGeometryIndexMap[i] = -1;
  32305. }
  32306. for (i = 0; i < length; i += 2) {
  32307. var i0 = indices[i];
  32308. var i1 = indices[i + 1];
  32309. var p0 = Cartesian3.fromArray(positions, i0 * 3, p0Scratch);
  32310. var p1 = Cartesian3.fromArray(positions, i1 * 3, p1Scratch);
  32311. if (Math.abs(p0.y) < CesiumMath.EPSILON6){
  32312. if (p0.y < 0.0) {
  32313. p0.y = -CesiumMath.EPSILON6;
  32314. } else {
  32315. p0.y = CesiumMath.EPSILON6;
  32316. }
  32317. }
  32318. if (Math.abs(p1.y) < CesiumMath.EPSILON6){
  32319. if (p1.y < 0.0) {
  32320. p1.y = -CesiumMath.EPSILON6;
  32321. } else {
  32322. p1.y = CesiumMath.EPSILON6;
  32323. }
  32324. }
  32325. var p0Attributes = eastGeometry.attributes;
  32326. var p0Indices = eastGeometry.indices;
  32327. var p0IndexMap = eastGeometryIndexMap;
  32328. var p1Attributes = westGeometry.attributes;
  32329. var p1Indices = westGeometry.indices;
  32330. var p1IndexMap = westGeometryIndexMap;
  32331. var intersection = IntersectionTests.lineSegmentPlane(p0, p1, xzPlane, p2Scratch);
  32332. if (defined(intersection)) {
  32333. // move point on the xz-plane slightly away from the plane
  32334. var offset = Cartesian3.multiplyByScalar(Cartesian3.UNIT_Y, 5.0 * CesiumMath.EPSILON9, offsetScratch);
  32335. if (p0.y < 0.0) {
  32336. Cartesian3.negate(offset, offset);
  32337. p0Attributes = westGeometry.attributes;
  32338. p0Indices = westGeometry.indices;
  32339. p0IndexMap = westGeometryIndexMap;
  32340. p1Attributes = eastGeometry.attributes;
  32341. p1Indices = eastGeometry.indices;
  32342. p1IndexMap = eastGeometryIndexMap;
  32343. }
  32344. var offsetPoint = Cartesian3.add(intersection, offset, offsetPointScratch);
  32345. insertSplitPoint(p0Attributes, p0Indices, p0IndexMap, indices, i, p0);
  32346. insertSplitPoint(p0Attributes, p0Indices, p0IndexMap, indices, -1, offsetPoint);
  32347. Cartesian3.negate(offset, offset);
  32348. Cartesian3.add(intersection, offset, offsetPoint);
  32349. insertSplitPoint(p1Attributes, p1Indices, p1IndexMap, indices, -1, offsetPoint);
  32350. insertSplitPoint(p1Attributes, p1Indices, p1IndexMap, indices, i + 1, p1);
  32351. } else {
  32352. var currentAttributes;
  32353. var currentIndices;
  32354. var currentIndexMap;
  32355. if (p0.y < 0.0) {
  32356. currentAttributes = westGeometry.attributes;
  32357. currentIndices = westGeometry.indices;
  32358. currentIndexMap = westGeometryIndexMap;
  32359. } else {
  32360. currentAttributes = eastGeometry.attributes;
  32361. currentIndices = eastGeometry.indices;
  32362. currentIndexMap = eastGeometryIndexMap;
  32363. }
  32364. insertSplitPoint(currentAttributes, currentIndices, currentIndexMap, indices, i, p0);
  32365. insertSplitPoint(currentAttributes, currentIndices, currentIndexMap, indices, i + 1, p1);
  32366. }
  32367. }
  32368. updateInstanceAfterSplit(instance, westGeometry, eastGeometry);
  32369. }
  32370. var cartesian2Scratch0 = new Cartesian2();
  32371. var cartesian2Scratch1 = new Cartesian2();
  32372. var cartesian3Scratch0 = new Cartesian3();
  32373. var cartesian3Scratch2 = new Cartesian3();
  32374. var cartesian3Scratch3 = new Cartesian3();
  32375. var cartesian3Scratch4 = new Cartesian3();
  32376. var cartesian3Scratch5 = new Cartesian3();
  32377. var cartesian3Scratch6 = new Cartesian3();
  32378. var cartesian4Scratch0 = new Cartesian4();
  32379. function updateAdjacencyAfterSplit(geometry) {
  32380. var attributes = geometry.attributes;
  32381. var positions = attributes.position.values;
  32382. var prevPositions = attributes.prevPosition.values;
  32383. var nextPositions = attributes.nextPosition.values;
  32384. var length = positions.length;
  32385. for (var j = 0; j < length; j += 3) {
  32386. var position = Cartesian3.unpack(positions, j, cartesian3Scratch0);
  32387. if (position.x > 0.0) {
  32388. continue;
  32389. }
  32390. var prevPosition = Cartesian3.unpack(prevPositions, j, cartesian3Scratch2);
  32391. if ((position.y < 0.0 && prevPosition.y > 0.0) || (position.y > 0.0 && prevPosition.y < 0.0)) {
  32392. if (j - 3 > 0) {
  32393. prevPositions[j] = positions[j - 3];
  32394. prevPositions[j + 1] = positions[j - 2];
  32395. prevPositions[j + 2] = positions[j - 1];
  32396. } else {
  32397. Cartesian3.pack(position, prevPositions, j);
  32398. }
  32399. }
  32400. var nextPosition = Cartesian3.unpack(nextPositions, j, cartesian3Scratch3);
  32401. if ((position.y < 0.0 && nextPosition.y > 0.0) || (position.y > 0.0 && nextPosition.y < 0.0)) {
  32402. if (j + 3 < length) {
  32403. nextPositions[j] = positions[j + 3];
  32404. nextPositions[j + 1] = positions[j + 4];
  32405. nextPositions[j + 2] = positions[j + 5];
  32406. } else {
  32407. Cartesian3.pack(position, nextPositions, j);
  32408. }
  32409. }
  32410. }
  32411. }
  32412. var offsetScalar = 5.0 * CesiumMath.EPSILON9;
  32413. var coplanarOffset = CesiumMath.EPSILON6;
  32414. function splitLongitudePolyline(instance) {
  32415. var geometry = instance.geometry;
  32416. var attributes = geometry.attributes;
  32417. var positions = attributes.position.values;
  32418. var prevPositions = attributes.prevPosition.values;
  32419. var nextPositions = attributes.nextPosition.values;
  32420. var expandAndWidths = attributes.expandAndWidth.values;
  32421. var texCoords = (defined(attributes.st)) ? attributes.st.values : undefined;
  32422. var colors = (defined(attributes.color)) ? attributes.color.values : undefined;
  32423. var eastGeometry = copyGeometryForSplit(geometry);
  32424. var westGeometry = copyGeometryForSplit(geometry);
  32425. var i;
  32426. var j;
  32427. var index;
  32428. var intersectionFound = false;
  32429. var length = positions.length / 3;
  32430. for (i = 0; i < length; i += 4) {
  32431. var i0 = i;
  32432. var i2 = i + 2;
  32433. var p0 = Cartesian3.fromArray(positions, i0 * 3, cartesian3Scratch0);
  32434. var p2 = Cartesian3.fromArray(positions, i2 * 3, cartesian3Scratch2);
  32435. // Offset points that are close to the 180 longitude and change the previous/next point
  32436. // to be the same offset point so it can be projected to 2D. There is special handling in the
  32437. // shader for when position == prevPosition || position == nextPosition.
  32438. if (Math.abs(p0.y) < coplanarOffset) {
  32439. p0.y = coplanarOffset * (p2.y < 0.0 ? -1.0 : 1.0);
  32440. positions[i * 3 + 1] = p0.y;
  32441. positions[(i + 1) * 3 + 1] = p0.y;
  32442. for (j = i0 * 3; j < i0 * 3 + 4 * 3; j += 3) {
  32443. prevPositions[j] = positions[i * 3];
  32444. prevPositions[j + 1] = positions[i * 3 + 1];
  32445. prevPositions[j + 2] = positions[i * 3 + 2];
  32446. }
  32447. }
  32448. // Do the same but for when the line crosses 180 longitude in the opposite direction.
  32449. if (Math.abs(p2.y) < coplanarOffset) {
  32450. p2.y = coplanarOffset * (p0.y < 0.0 ? -1.0 : 1.0);
  32451. positions[(i + 2) * 3 + 1] = p2.y;
  32452. positions[(i + 3) * 3 + 1] = p2.y;
  32453. for (j = i0 * 3; j < i0 * 3 + 4 * 3; j += 3) {
  32454. nextPositions[j] = positions[(i + 2) * 3];
  32455. nextPositions[j + 1] = positions[(i + 2) * 3 + 1];
  32456. nextPositions[j + 2] = positions[(i + 2) * 3 + 2];
  32457. }
  32458. }
  32459. var p0Attributes = eastGeometry.attributes;
  32460. var p0Indices = eastGeometry.indices;
  32461. var p2Attributes = westGeometry.attributes;
  32462. var p2Indices = westGeometry.indices;
  32463. var intersection = IntersectionTests.lineSegmentPlane(p0, p2, xzPlane, cartesian3Scratch4);
  32464. if (defined(intersection)) {
  32465. intersectionFound = true;
  32466. // move point on the xz-plane slightly away from the plane
  32467. var offset = Cartesian3.multiplyByScalar(Cartesian3.UNIT_Y, offsetScalar, cartesian3Scratch5);
  32468. if (p0.y < 0.0) {
  32469. Cartesian3.negate(offset, offset);
  32470. p0Attributes = westGeometry.attributes;
  32471. p0Indices = westGeometry.indices;
  32472. p2Attributes = eastGeometry.attributes;
  32473. p2Indices = eastGeometry.indices;
  32474. }
  32475. var offsetPoint = Cartesian3.add(intersection, offset, cartesian3Scratch6);
  32476. p0Attributes.position.values.push(p0.x, p0.y, p0.z, p0.x, p0.y, p0.z);
  32477. p0Attributes.position.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  32478. p0Attributes.position.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  32479. p0Attributes.prevPosition.values.push(prevPositions[i0 * 3], prevPositions[i0 * 3 + 1], prevPositions[i0 * 3 + 2]);
  32480. p0Attributes.prevPosition.values.push(prevPositions[i0 * 3 + 3], prevPositions[i0 * 3 + 4], prevPositions[i0 * 3 + 5]);
  32481. p0Attributes.prevPosition.values.push(p0.x, p0.y, p0.z, p0.x, p0.y, p0.z);
  32482. p0Attributes.nextPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  32483. p0Attributes.nextPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  32484. p0Attributes.nextPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  32485. p0Attributes.nextPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  32486. Cartesian3.negate(offset, offset);
  32487. Cartesian3.add(intersection, offset, offsetPoint);
  32488. p2Attributes.position.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  32489. p2Attributes.position.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  32490. p2Attributes.position.values.push(p2.x, p2.y, p2.z, p2.x, p2.y, p2.z);
  32491. p2Attributes.prevPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  32492. p2Attributes.prevPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  32493. p2Attributes.prevPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  32494. p2Attributes.prevPosition.values.push(offsetPoint.x, offsetPoint.y, offsetPoint.z);
  32495. p2Attributes.nextPosition.values.push(p2.x, p2.y, p2.z, p2.x, p2.y, p2.z);
  32496. p2Attributes.nextPosition.values.push(nextPositions[i2 * 3], nextPositions[i2 * 3 + 1], nextPositions[i2 * 3 + 2]);
  32497. p2Attributes.nextPosition.values.push(nextPositions[i2 * 3 + 3], nextPositions[i2 * 3 + 4], nextPositions[i2 * 3 + 5]);
  32498. var ew0 = Cartesian2.fromArray(expandAndWidths, i0 * 2, cartesian2Scratch0);
  32499. var width = Math.abs(ew0.y);
  32500. p0Attributes.expandAndWidth.values.push(-1, width, 1, width);
  32501. p0Attributes.expandAndWidth.values.push(-1, -width, 1, -width);
  32502. p2Attributes.expandAndWidth.values.push(-1, width, 1, width);
  32503. p2Attributes.expandAndWidth.values.push(-1, -width, 1, -width);
  32504. var t = Cartesian3.magnitudeSquared(Cartesian3.subtract(intersection, p0, cartesian3Scratch3));
  32505. t /= Cartesian3.magnitudeSquared(Cartesian3.subtract(p2, p0, cartesian3Scratch3));
  32506. if (defined(colors)) {
  32507. var c0 = Cartesian4.fromArray(colors, i0 * 4, cartesian4Scratch0);
  32508. var c2 = Cartesian4.fromArray(colors, i2 * 4, cartesian4Scratch0);
  32509. var r = CesiumMath.lerp(c0.x, c2.x, t);
  32510. var g = CesiumMath.lerp(c0.y, c2.y, t);
  32511. var b = CesiumMath.lerp(c0.z, c2.z, t);
  32512. var a = CesiumMath.lerp(c0.w, c2.w, t);
  32513. for (j = i0 * 4; j < i0 * 4 + 2 * 4; ++j) {
  32514. p0Attributes.color.values.push(colors[j]);
  32515. }
  32516. p0Attributes.color.values.push(r, g, b, a);
  32517. p0Attributes.color.values.push(r, g, b, a);
  32518. p2Attributes.color.values.push(r, g, b, a);
  32519. p2Attributes.color.values.push(r, g, b, a);
  32520. for (j = i2 * 4; j < i2 * 4 + 2 * 4; ++j) {
  32521. p2Attributes.color.values.push(colors[j]);
  32522. }
  32523. }
  32524. if (defined(texCoords)) {
  32525. var s0 = Cartesian2.fromArray(texCoords, i0 * 2, cartesian2Scratch0);
  32526. var s3 = Cartesian2.fromArray(texCoords, (i + 3) * 2, cartesian2Scratch1);
  32527. var sx = CesiumMath.lerp(s0.x, s3.x, t);
  32528. for (j = i0 * 2; j < i0 * 2 + 2 * 2; ++j) {
  32529. p0Attributes.st.values.push(texCoords[j]);
  32530. }
  32531. p0Attributes.st.values.push(sx, s0.y);
  32532. p0Attributes.st.values.push(sx, s3.y);
  32533. p2Attributes.st.values.push(sx, s0.y);
  32534. p2Attributes.st.values.push(sx, s3.y);
  32535. for (j = i2 * 2; j < i2 * 2 + 2 * 2; ++j) {
  32536. p2Attributes.st.values.push(texCoords[j]);
  32537. }
  32538. }
  32539. index = p0Attributes.position.values.length / 3 - 4;
  32540. p0Indices.push(index, index + 2, index + 1);
  32541. p0Indices.push(index + 1, index + 2, index + 3);
  32542. index = p2Attributes.position.values.length / 3 - 4;
  32543. p2Indices.push(index, index + 2, index + 1);
  32544. p2Indices.push(index + 1, index + 2, index + 3);
  32545. } else {
  32546. var currentAttributes;
  32547. var currentIndices;
  32548. if (p0.y < 0.0) {
  32549. currentAttributes = westGeometry.attributes;
  32550. currentIndices = westGeometry.indices;
  32551. } else {
  32552. currentAttributes = eastGeometry.attributes;
  32553. currentIndices = eastGeometry.indices;
  32554. }
  32555. currentAttributes.position.values.push(p0.x, p0.y, p0.z);
  32556. currentAttributes.position.values.push(p0.x, p0.y, p0.z);
  32557. currentAttributes.position.values.push(p2.x, p2.y, p2.z);
  32558. currentAttributes.position.values.push(p2.x, p2.y, p2.z);
  32559. for (j = i * 3; j < i * 3 + 4 * 3; ++j) {
  32560. currentAttributes.prevPosition.values.push(prevPositions[j]);
  32561. currentAttributes.nextPosition.values.push(nextPositions[j]);
  32562. }
  32563. for (j = i * 2; j < i * 2 + 4 * 2; ++j) {
  32564. currentAttributes.expandAndWidth.values.push(expandAndWidths[j]);
  32565. if (defined(texCoords)) {
  32566. currentAttributes.st.values.push(texCoords[j]);
  32567. }
  32568. }
  32569. if (defined(colors)) {
  32570. for (j = i * 4; j < i * 4 + 4 * 4; ++j) {
  32571. currentAttributes.color.values.push(colors[j]);
  32572. }
  32573. }
  32574. index = currentAttributes.position.values.length / 3 - 4;
  32575. currentIndices.push(index, index + 2, index + 1);
  32576. currentIndices.push(index + 1, index + 2, index + 3);
  32577. }
  32578. }
  32579. if (intersectionFound) {
  32580. updateAdjacencyAfterSplit(westGeometry);
  32581. updateAdjacencyAfterSplit(eastGeometry);
  32582. }
  32583. updateInstanceAfterSplit(instance, westGeometry, eastGeometry);
  32584. }
  32585. /**
  32586. * Splits the instances's geometry, by introducing new vertices and indices,that
  32587. * intersect the International Date Line and Prime Meridian so that no primitives cross longitude
  32588. * -180/180 degrees. This is not required for 3D drawing, but is required for
  32589. * correcting drawing in 2D and Columbus view.
  32590. *
  32591. * @private
  32592. *
  32593. * @param {GeometryInstance} instance The instance to modify.
  32594. * @returns {GeometryInstance} The modified <code>instance</code> argument, with it's geometry split at the International Date Line.
  32595. *
  32596. * @example
  32597. * instance = Cesium.GeometryPipeline.splitLongitude(instance);
  32598. */
  32599. GeometryPipeline.splitLongitude = function(instance) {
  32600. if (!defined(instance)) {
  32601. throw new DeveloperError('instance is required.');
  32602. }
  32603. var geometry = instance.geometry;
  32604. var boundingSphere = geometry.boundingSphere;
  32605. if (defined(boundingSphere)) {
  32606. var minX = boundingSphere.center.x - boundingSphere.radius;
  32607. if (minX > 0 || BoundingSphere.intersectPlane(boundingSphere, Plane.ORIGIN_ZX_PLANE) !== Intersect.INTERSECTING) {
  32608. return instance;
  32609. }
  32610. }
  32611. if (geometry.geometryType !== GeometryType.NONE) {
  32612. switch (geometry.geometryType) {
  32613. case GeometryType.POLYLINES:
  32614. splitLongitudePolyline(instance);
  32615. break;
  32616. case GeometryType.TRIANGLES:
  32617. splitLongitudeTriangles(instance);
  32618. break;
  32619. case GeometryType.LINES:
  32620. splitLongitudeLines(instance);
  32621. break;
  32622. }
  32623. } else {
  32624. indexPrimitive(geometry);
  32625. if (geometry.primitiveType === PrimitiveType.TRIANGLES) {
  32626. splitLongitudeTriangles(instance);
  32627. } else if (geometry.primitiveType === PrimitiveType.LINES) {
  32628. splitLongitudeLines(instance);
  32629. }
  32630. }
  32631. return instance;
  32632. };
  32633. return GeometryPipeline;
  32634. });
  32635. /*global define*/
  32636. define('Core/EllipseGeometry',[
  32637. './BoundingSphere',
  32638. './Cartesian2',
  32639. './Cartesian3',
  32640. './Cartographic',
  32641. './ComponentDatatype',
  32642. './defaultValue',
  32643. './defined',
  32644. './defineProperties',
  32645. './DeveloperError',
  32646. './EllipseGeometryLibrary',
  32647. './Ellipsoid',
  32648. './GeographicProjection',
  32649. './Geometry',
  32650. './GeometryAttribute',
  32651. './GeometryAttributes',
  32652. './GeometryInstance',
  32653. './GeometryPipeline',
  32654. './IndexDatatype',
  32655. './Math',
  32656. './Matrix3',
  32657. './Matrix4',
  32658. './PrimitiveType',
  32659. './Quaternion',
  32660. './Rectangle',
  32661. './Transforms',
  32662. './VertexFormat'
  32663. ], function(
  32664. BoundingSphere,
  32665. Cartesian2,
  32666. Cartesian3,
  32667. Cartographic,
  32668. ComponentDatatype,
  32669. defaultValue,
  32670. defined,
  32671. defineProperties,
  32672. DeveloperError,
  32673. EllipseGeometryLibrary,
  32674. Ellipsoid,
  32675. GeographicProjection,
  32676. Geometry,
  32677. GeometryAttribute,
  32678. GeometryAttributes,
  32679. GeometryInstance,
  32680. GeometryPipeline,
  32681. IndexDatatype,
  32682. CesiumMath,
  32683. Matrix3,
  32684. Matrix4,
  32685. PrimitiveType,
  32686. Quaternion,
  32687. Rectangle,
  32688. Transforms,
  32689. VertexFormat) {
  32690. 'use strict';
  32691. var scratchCartesian1 = new Cartesian3();
  32692. var scratchCartesian2 = new Cartesian3();
  32693. var scratchCartesian3 = new Cartesian3();
  32694. var scratchCartesian4 = new Cartesian3();
  32695. var texCoordScratch = new Cartesian2();
  32696. var textureMatrixScratch = new Matrix3();
  32697. var quaternionScratch = new Quaternion();
  32698. var scratchNormal = new Cartesian3();
  32699. var scratchTangent = new Cartesian3();
  32700. var scratchBinormal = new Cartesian3();
  32701. var scratchCartographic = new Cartographic();
  32702. var projectedCenterScratch = new Cartesian3();
  32703. var scratchMinTexCoord = new Cartesian2();
  32704. var scratchMaxTexCoord = new Cartesian2();
  32705. function computeTopBottomAttributes(positions, options, extrude) {
  32706. var vertexFormat = options.vertexFormat;
  32707. var center = options.center;
  32708. var semiMajorAxis = options.semiMajorAxis;
  32709. var semiMinorAxis = options.semiMinorAxis;
  32710. var ellipsoid = options.ellipsoid;
  32711. var stRotation = options.stRotation;
  32712. var size = (extrude) ? positions.length / 3 * 2 : positions.length / 3;
  32713. var textureCoordinates = (vertexFormat.st) ? new Float32Array(size * 2) : undefined;
  32714. var normals = (vertexFormat.normal) ? new Float32Array(size * 3) : undefined;
  32715. var tangents = (vertexFormat.tangent) ? new Float32Array(size * 3) : undefined;
  32716. var binormals = (vertexFormat.binormal) ? new Float32Array(size * 3) : undefined;
  32717. var textureCoordIndex = 0;
  32718. // Raise positions to a height above the ellipsoid and compute the
  32719. // texture coordinates, normals, tangents, and binormals.
  32720. var normal = scratchNormal;
  32721. var tangent = scratchTangent;
  32722. var binormal = scratchBinormal;
  32723. var projection = new GeographicProjection(ellipsoid);
  32724. var projectedCenter = projection.project(ellipsoid.cartesianToCartographic(center, scratchCartographic), projectedCenterScratch);
  32725. var geodeticNormal = ellipsoid.scaleToGeodeticSurface(center, scratchCartesian1);
  32726. ellipsoid.geodeticSurfaceNormal(geodeticNormal, geodeticNormal);
  32727. var rotation = Quaternion.fromAxisAngle(geodeticNormal, stRotation, quaternionScratch);
  32728. var textureMatrix = Matrix3.fromQuaternion(rotation, textureMatrixScratch);
  32729. var minTexCoord = Cartesian2.fromElements(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, scratchMinTexCoord);
  32730. var maxTexCoord = Cartesian2.fromElements(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, scratchMaxTexCoord);
  32731. var length = positions.length;
  32732. var bottomOffset = (extrude) ? length : 0;
  32733. var stOffset = bottomOffset / 3 * 2;
  32734. for (var i = 0; i < length; i += 3) {
  32735. var i1 = i + 1;
  32736. var i2 = i + 2;
  32737. var position = Cartesian3.fromArray(positions, i, scratchCartesian1);
  32738. if (vertexFormat.st) {
  32739. var rotatedPoint = Matrix3.multiplyByVector(textureMatrix, position, scratchCartesian2);
  32740. var projectedPoint = projection.project(ellipsoid.cartesianToCartographic(rotatedPoint, scratchCartographic), scratchCartesian3);
  32741. Cartesian3.subtract(projectedPoint, projectedCenter, projectedPoint);
  32742. texCoordScratch.x = (projectedPoint.x + semiMajorAxis) / (2.0 * semiMajorAxis);
  32743. texCoordScratch.y = (projectedPoint.y + semiMinorAxis) / (2.0 * semiMinorAxis);
  32744. minTexCoord.x = Math.min(texCoordScratch.x, minTexCoord.x);
  32745. minTexCoord.y = Math.min(texCoordScratch.y, minTexCoord.y);
  32746. maxTexCoord.x = Math.max(texCoordScratch.x, maxTexCoord.x);
  32747. maxTexCoord.y = Math.max(texCoordScratch.y, maxTexCoord.y);
  32748. if (extrude) {
  32749. textureCoordinates[textureCoordIndex + stOffset] = texCoordScratch.x;
  32750. textureCoordinates[textureCoordIndex + 1 + stOffset] = texCoordScratch.y;
  32751. }
  32752. textureCoordinates[textureCoordIndex++] = texCoordScratch.x;
  32753. textureCoordinates[textureCoordIndex++] = texCoordScratch.y;
  32754. }
  32755. normal = ellipsoid.geodeticSurfaceNormal(position, normal);
  32756. if (vertexFormat.normal || vertexFormat.tangent || vertexFormat.binormal) {
  32757. if (vertexFormat.tangent || vertexFormat.binormal) {
  32758. tangent = Cartesian3.normalize(Cartesian3.cross(Cartesian3.UNIT_Z, normal, tangent), tangent);
  32759. Matrix3.multiplyByVector(textureMatrix, tangent, tangent);
  32760. }
  32761. if (vertexFormat.normal) {
  32762. normals[i] = normal.x;
  32763. normals[i1] = normal.y;
  32764. normals[i2] = normal.z;
  32765. if (extrude) {
  32766. normals[i + bottomOffset] = -normal.x;
  32767. normals[i1 + bottomOffset] = -normal.y;
  32768. normals[i2 + bottomOffset] = -normal.z;
  32769. }
  32770. }
  32771. if (vertexFormat.tangent) {
  32772. tangents[i] = tangent.x;
  32773. tangents[i1] = tangent.y;
  32774. tangents[i2] = tangent.z;
  32775. if (extrude) {
  32776. tangents[i + bottomOffset] = -tangent.x;
  32777. tangents[i1 + bottomOffset] = -tangent.y;
  32778. tangents[i2 + bottomOffset] = -tangent.z;
  32779. }
  32780. }
  32781. if (vertexFormat.binormal) {
  32782. binormal = Cartesian3.normalize(Cartesian3.cross(normal, tangent, binormal), binormal);
  32783. binormals[i] = binormal.x;
  32784. binormals[i1] = binormal.y;
  32785. binormals[i2] = binormal.z;
  32786. if (extrude) {
  32787. binormals[i + bottomOffset] = binormal.x;
  32788. binormals[i1 + bottomOffset] = binormal.y;
  32789. binormals[i2 + bottomOffset] = binormal.z;
  32790. }
  32791. }
  32792. }
  32793. }
  32794. if (vertexFormat.st) {
  32795. length = textureCoordinates.length;
  32796. for (var k = 0; k < length; k += 2) {
  32797. textureCoordinates[k] = (textureCoordinates[k] - minTexCoord.x) / (maxTexCoord.x - minTexCoord.x);
  32798. textureCoordinates[k + 1] = (textureCoordinates[k + 1] - minTexCoord.y) / (maxTexCoord.y - minTexCoord.y);
  32799. }
  32800. }
  32801. var attributes = new GeometryAttributes();
  32802. if (vertexFormat.position) {
  32803. var finalPositions = EllipseGeometryLibrary.raisePositionsToHeight(positions, options, extrude);
  32804. attributes.position = new GeometryAttribute({
  32805. componentDatatype : ComponentDatatype.DOUBLE,
  32806. componentsPerAttribute : 3,
  32807. values : finalPositions
  32808. });
  32809. }
  32810. if (vertexFormat.st) {
  32811. attributes.st = new GeometryAttribute({
  32812. componentDatatype : ComponentDatatype.FLOAT,
  32813. componentsPerAttribute : 2,
  32814. values : textureCoordinates
  32815. });
  32816. }
  32817. if (vertexFormat.normal) {
  32818. attributes.normal = new GeometryAttribute({
  32819. componentDatatype : ComponentDatatype.FLOAT,
  32820. componentsPerAttribute : 3,
  32821. values : normals
  32822. });
  32823. }
  32824. if (vertexFormat.tangent) {
  32825. attributes.tangent = new GeometryAttribute({
  32826. componentDatatype : ComponentDatatype.FLOAT,
  32827. componentsPerAttribute : 3,
  32828. values : tangents
  32829. });
  32830. }
  32831. if (vertexFormat.binormal) {
  32832. attributes.binormal = new GeometryAttribute({
  32833. componentDatatype : ComponentDatatype.FLOAT,
  32834. componentsPerAttribute : 3,
  32835. values : binormals
  32836. });
  32837. }
  32838. return attributes;
  32839. }
  32840. function topIndices(numPts) {
  32841. // numTriangles in half = 3 + 8 + 12 + ... = -1 + 4 + (4 + 4) + (4 + 4 + 4) + ... = -1 + 4 * (1 + 2 + 3 + ...)
  32842. // = -1 + 4 * ((n * ( n + 1)) / 2)
  32843. // total triangles = 2 * numTrangles in half
  32844. // indices = total triangles * 3;
  32845. // Substitute numPts for n above
  32846. var indices = new Array(12 * (numPts * ( numPts + 1)) - 6);
  32847. var indicesIndex = 0;
  32848. var prevIndex;
  32849. var numInterior;
  32850. var positionIndex;
  32851. var i;
  32852. var j;
  32853. // Indices triangles to the 'right' of the north vector
  32854. prevIndex = 0;
  32855. positionIndex = 1;
  32856. for (i = 0; i < 3; i++) {
  32857. indices[indicesIndex++] = positionIndex++;
  32858. indices[indicesIndex++] = prevIndex;
  32859. indices[indicesIndex++] = positionIndex;
  32860. }
  32861. for (i = 2; i < numPts + 1; ++i) {
  32862. positionIndex = i * (i + 1) - 1;
  32863. prevIndex = (i - 1) * i - 1;
  32864. indices[indicesIndex++] = positionIndex++;
  32865. indices[indicesIndex++] = prevIndex;
  32866. indices[indicesIndex++] = positionIndex;
  32867. numInterior = 2 * i;
  32868. for (j = 0; j < numInterior - 1; ++j) {
  32869. indices[indicesIndex++] = positionIndex;
  32870. indices[indicesIndex++] = prevIndex++;
  32871. indices[indicesIndex++] = prevIndex;
  32872. indices[indicesIndex++] = positionIndex++;
  32873. indices[indicesIndex++] = prevIndex;
  32874. indices[indicesIndex++] = positionIndex;
  32875. }
  32876. indices[indicesIndex++] = positionIndex++;
  32877. indices[indicesIndex++] = prevIndex;
  32878. indices[indicesIndex++] = positionIndex;
  32879. }
  32880. // Indices for center column of triangles
  32881. numInterior = numPts * 2;
  32882. ++positionIndex;
  32883. ++prevIndex;
  32884. for (i = 0; i < numInterior - 1; ++i) {
  32885. indices[indicesIndex++] = positionIndex;
  32886. indices[indicesIndex++] = prevIndex++;
  32887. indices[indicesIndex++] = prevIndex;
  32888. indices[indicesIndex++] = positionIndex++;
  32889. indices[indicesIndex++] = prevIndex;
  32890. indices[indicesIndex++] = positionIndex;
  32891. }
  32892. indices[indicesIndex++] = positionIndex;
  32893. indices[indicesIndex++] = prevIndex++;
  32894. indices[indicesIndex++] = prevIndex;
  32895. indices[indicesIndex++] = positionIndex++;
  32896. indices[indicesIndex++] = prevIndex++;
  32897. indices[indicesIndex++] = prevIndex;
  32898. // Reverse the process creating indices to the 'left' of the north vector
  32899. ++prevIndex;
  32900. for (i = numPts - 1; i > 1; --i) {
  32901. indices[indicesIndex++] = prevIndex++;
  32902. indices[indicesIndex++] = prevIndex;
  32903. indices[indicesIndex++] = positionIndex;
  32904. numInterior = 2 * i;
  32905. for (j = 0; j < numInterior - 1; ++j) {
  32906. indices[indicesIndex++] = positionIndex;
  32907. indices[indicesIndex++] = prevIndex++;
  32908. indices[indicesIndex++] = prevIndex;
  32909. indices[indicesIndex++] = positionIndex++;
  32910. indices[indicesIndex++] = prevIndex;
  32911. indices[indicesIndex++] = positionIndex;
  32912. }
  32913. indices[indicesIndex++] = prevIndex++;
  32914. indices[indicesIndex++] = prevIndex++;
  32915. indices[indicesIndex++] = positionIndex++;
  32916. }
  32917. for (i = 0; i < 3; i++) {
  32918. indices[indicesIndex++] = prevIndex++;
  32919. indices[indicesIndex++] = prevIndex;
  32920. indices[indicesIndex++] = positionIndex;
  32921. }
  32922. return indices;
  32923. }
  32924. var boundingSphereCenter = new Cartesian3();
  32925. function computeEllipse(options) {
  32926. var center = options.center;
  32927. boundingSphereCenter = Cartesian3.multiplyByScalar(options.ellipsoid.geodeticSurfaceNormal(center, boundingSphereCenter), options.height, boundingSphereCenter);
  32928. boundingSphereCenter = Cartesian3.add(center, boundingSphereCenter, boundingSphereCenter);
  32929. var boundingSphere = new BoundingSphere(boundingSphereCenter, options.semiMajorAxis);
  32930. var cep = EllipseGeometryLibrary.computeEllipsePositions(options, true, false);
  32931. var positions = cep.positions;
  32932. var numPts = cep.numPts;
  32933. var attributes = computeTopBottomAttributes(positions, options, false);
  32934. var indices = topIndices(numPts);
  32935. indices = IndexDatatype.createTypedArray(positions.length / 3, indices);
  32936. return {
  32937. boundingSphere : boundingSphere,
  32938. attributes : attributes,
  32939. indices : indices
  32940. };
  32941. }
  32942. function computeWallAttributes(positions, options) {
  32943. var vertexFormat = options.vertexFormat;
  32944. var center = options.center;
  32945. var semiMajorAxis = options.semiMajorAxis;
  32946. var semiMinorAxis = options.semiMinorAxis;
  32947. var ellipsoid = options.ellipsoid;
  32948. var height = options.height;
  32949. var extrudedHeight = options.extrudedHeight;
  32950. var stRotation = options.stRotation;
  32951. var size = positions.length / 3 * 2;
  32952. var finalPositions = new Float64Array(size * 3);
  32953. var textureCoordinates = (vertexFormat.st) ? new Float32Array(size * 2) : undefined;
  32954. var normals = (vertexFormat.normal) ? new Float32Array(size * 3) : undefined;
  32955. var tangents = (vertexFormat.tangent) ? new Float32Array(size * 3) : undefined;
  32956. var binormals = (vertexFormat.binormal) ? new Float32Array(size * 3) : undefined;
  32957. var textureCoordIndex = 0;
  32958. // Raise positions to a height above the ellipsoid and compute the
  32959. // texture coordinates, normals, tangents, and binormals.
  32960. var normal = scratchNormal;
  32961. var tangent = scratchTangent;
  32962. var binormal = scratchBinormal;
  32963. var projection = new GeographicProjection(ellipsoid);
  32964. var projectedCenter = projection.project(ellipsoid.cartesianToCartographic(center, scratchCartographic), projectedCenterScratch);
  32965. var geodeticNormal = ellipsoid.scaleToGeodeticSurface(center, scratchCartesian1);
  32966. ellipsoid.geodeticSurfaceNormal(geodeticNormal, geodeticNormal);
  32967. var rotation = Quaternion.fromAxisAngle(geodeticNormal, stRotation, quaternionScratch);
  32968. var textureMatrix = Matrix3.fromQuaternion(rotation, textureMatrixScratch);
  32969. var minTexCoord = Cartesian2.fromElements(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, scratchMinTexCoord);
  32970. var maxTexCoord = Cartesian2.fromElements(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, scratchMaxTexCoord);
  32971. var length = positions.length;
  32972. var stOffset = length / 3 * 2;
  32973. for (var i = 0; i < length; i += 3) {
  32974. var i1 = i + 1;
  32975. var i2 = i + 2;
  32976. var position = Cartesian3.fromArray(positions, i, scratchCartesian1);
  32977. var extrudedPosition;
  32978. if (vertexFormat.st) {
  32979. var rotatedPoint = Matrix3.multiplyByVector(textureMatrix, position, scratchCartesian2);
  32980. var projectedPoint = projection.project(ellipsoid.cartesianToCartographic(rotatedPoint, scratchCartographic), scratchCartesian3);
  32981. Cartesian3.subtract(projectedPoint, projectedCenter, projectedPoint);
  32982. texCoordScratch.x = (projectedPoint.x + semiMajorAxis) / (2.0 * semiMajorAxis);
  32983. texCoordScratch.y = (projectedPoint.y + semiMinorAxis) / (2.0 * semiMinorAxis);
  32984. minTexCoord.x = Math.min(texCoordScratch.x, minTexCoord.x);
  32985. minTexCoord.y = Math.min(texCoordScratch.y, minTexCoord.y);
  32986. maxTexCoord.x = Math.max(texCoordScratch.x, maxTexCoord.x);
  32987. maxTexCoord.y = Math.max(texCoordScratch.y, maxTexCoord.y);
  32988. textureCoordinates[textureCoordIndex + stOffset] = texCoordScratch.x;
  32989. textureCoordinates[textureCoordIndex + 1 + stOffset] = texCoordScratch.y;
  32990. textureCoordinates[textureCoordIndex++] = texCoordScratch.x;
  32991. textureCoordinates[textureCoordIndex++] = texCoordScratch.y;
  32992. }
  32993. position = ellipsoid.scaleToGeodeticSurface(position, position);
  32994. extrudedPosition = Cartesian3.clone(position, scratchCartesian2);
  32995. normal = ellipsoid.geodeticSurfaceNormal(position, normal);
  32996. var scaledNormal = Cartesian3.multiplyByScalar(normal, height, scratchCartesian4);
  32997. position = Cartesian3.add(position, scaledNormal, position);
  32998. scaledNormal = Cartesian3.multiplyByScalar(normal, extrudedHeight, scaledNormal);
  32999. extrudedPosition = Cartesian3.add(extrudedPosition, scaledNormal, extrudedPosition);
  33000. if (vertexFormat.position) {
  33001. finalPositions[i + length] = extrudedPosition.x;
  33002. finalPositions[i1 + length] = extrudedPosition.y;
  33003. finalPositions[i2 + length] = extrudedPosition.z;
  33004. finalPositions[i] = position.x;
  33005. finalPositions[i1] = position.y;
  33006. finalPositions[i2] = position.z;
  33007. }
  33008. if (vertexFormat.normal || vertexFormat.tangent || vertexFormat.binormal) {
  33009. binormal = Cartesian3.clone(normal, binormal);
  33010. var next = Cartesian3.fromArray(positions, (i + 3) % length, scratchCartesian4);
  33011. Cartesian3.subtract(next, position, next);
  33012. var bottom = Cartesian3.subtract(extrudedPosition, position, scratchCartesian3);
  33013. normal = Cartesian3.normalize(Cartesian3.cross(bottom, next, normal), normal);
  33014. if (vertexFormat.normal) {
  33015. normals[i] = normal.x;
  33016. normals[i1] = normal.y;
  33017. normals[i2] = normal.z;
  33018. normals[i + length] = normal.x;
  33019. normals[i1 + length] = normal.y;
  33020. normals[i2 + length] = normal.z;
  33021. }
  33022. if (vertexFormat.tangent) {
  33023. tangent = Cartesian3.normalize(Cartesian3.cross(binormal, normal, tangent), tangent);
  33024. tangents[i] = tangent.x;
  33025. tangents[i1] = tangent.y;
  33026. tangents[i2] = tangent.z;
  33027. tangents[i + length] = tangent.x;
  33028. tangents[i + 1 + length] = tangent.y;
  33029. tangents[i + 2 + length] = tangent.z;
  33030. }
  33031. if (vertexFormat.binormal) {
  33032. binormals[i] = binormal.x;
  33033. binormals[i1] = binormal.y;
  33034. binormals[i2] = binormal.z;
  33035. binormals[i + length] = binormal.x;
  33036. binormals[i1 + length] = binormal.y;
  33037. binormals[i2 + length] = binormal.z;
  33038. }
  33039. }
  33040. }
  33041. if (vertexFormat.st) {
  33042. length = textureCoordinates.length;
  33043. for (var k = 0; k < length; k += 2) {
  33044. textureCoordinates[k] = (textureCoordinates[k] - minTexCoord.x) / (maxTexCoord.x - minTexCoord.x);
  33045. textureCoordinates[k + 1] = (textureCoordinates[k + 1] - minTexCoord.y) / (maxTexCoord.y - minTexCoord.y);
  33046. }
  33047. }
  33048. var attributes = new GeometryAttributes();
  33049. if (vertexFormat.position) {
  33050. attributes.position = new GeometryAttribute({
  33051. componentDatatype : ComponentDatatype.DOUBLE,
  33052. componentsPerAttribute : 3,
  33053. values : finalPositions
  33054. });
  33055. }
  33056. if (vertexFormat.st) {
  33057. attributes.st = new GeometryAttribute({
  33058. componentDatatype : ComponentDatatype.FLOAT,
  33059. componentsPerAttribute : 2,
  33060. values : textureCoordinates
  33061. });
  33062. }
  33063. if (vertexFormat.normal) {
  33064. attributes.normal = new GeometryAttribute({
  33065. componentDatatype : ComponentDatatype.FLOAT,
  33066. componentsPerAttribute : 3,
  33067. values : normals
  33068. });
  33069. }
  33070. if (vertexFormat.tangent) {
  33071. attributes.tangent = new GeometryAttribute({
  33072. componentDatatype : ComponentDatatype.FLOAT,
  33073. componentsPerAttribute : 3,
  33074. values : tangents
  33075. });
  33076. }
  33077. if (vertexFormat.binormal) {
  33078. attributes.binormal = new GeometryAttribute({
  33079. componentDatatype : ComponentDatatype.FLOAT,
  33080. componentsPerAttribute : 3,
  33081. values : binormals
  33082. });
  33083. }
  33084. return attributes;
  33085. }
  33086. function computeWallIndices(positions) {
  33087. var length = positions.length / 3;
  33088. var indices = IndexDatatype.createTypedArray(length, length * 6);
  33089. var index = 0;
  33090. for (var i = 0; i < length; i++) {
  33091. var UL = i;
  33092. var LL = i + length;
  33093. var UR = (UL + 1) % length;
  33094. var LR = UR + length;
  33095. indices[index++] = UL;
  33096. indices[index++] = LL;
  33097. indices[index++] = UR;
  33098. indices[index++] = UR;
  33099. indices[index++] = LL;
  33100. indices[index++] = LR;
  33101. }
  33102. return indices;
  33103. }
  33104. var topBoundingSphere = new BoundingSphere();
  33105. var bottomBoundingSphere = new BoundingSphere();
  33106. function computeExtrudedEllipse(options) {
  33107. var center = options.center;
  33108. var ellipsoid = options.ellipsoid;
  33109. var semiMajorAxis = options.semiMajorAxis;
  33110. var scaledNormal = Cartesian3.multiplyByScalar(ellipsoid.geodeticSurfaceNormal(center, scratchCartesian1), options.height, scratchCartesian1);
  33111. topBoundingSphere.center = Cartesian3.add(center, scaledNormal, topBoundingSphere.center);
  33112. topBoundingSphere.radius = semiMajorAxis;
  33113. scaledNormal = Cartesian3.multiplyByScalar(ellipsoid.geodeticSurfaceNormal(center, scaledNormal), options.extrudedHeight, scaledNormal);
  33114. bottomBoundingSphere.center = Cartesian3.add(center, scaledNormal, bottomBoundingSphere.center);
  33115. bottomBoundingSphere.radius = semiMajorAxis;
  33116. var cep = EllipseGeometryLibrary.computeEllipsePositions(options, true, true);
  33117. var positions = cep.positions;
  33118. var numPts = cep.numPts;
  33119. var outerPositions = cep.outerPositions;
  33120. var boundingSphere = BoundingSphere.union(topBoundingSphere, bottomBoundingSphere);
  33121. var topBottomAttributes = computeTopBottomAttributes(positions, options, true);
  33122. var indices = topIndices(numPts);
  33123. var length = indices.length;
  33124. indices.length = length * 2;
  33125. var posLength = positions.length / 3;
  33126. for (var i = 0; i < length; i += 3) {
  33127. indices[i + length] = indices[i + 2] + posLength;
  33128. indices[i + 1 + length] = indices[i + 1] + posLength;
  33129. indices[i + 2 + length] = indices[i] + posLength;
  33130. }
  33131. var topBottomIndices = IndexDatatype.createTypedArray(posLength * 2 / 3, indices);
  33132. var topBottomGeo = new Geometry({
  33133. attributes : topBottomAttributes,
  33134. indices : topBottomIndices,
  33135. primitiveType : PrimitiveType.TRIANGLES
  33136. });
  33137. var wallAttributes = computeWallAttributes(outerPositions, options);
  33138. indices = computeWallIndices(outerPositions);
  33139. var wallIndices = IndexDatatype.createTypedArray(outerPositions.length * 2 / 3, indices);
  33140. var wallGeo = new Geometry({
  33141. attributes : wallAttributes,
  33142. indices : wallIndices,
  33143. primitiveType : PrimitiveType.TRIANGLES
  33144. });
  33145. var geo = GeometryPipeline.combineInstances([
  33146. new GeometryInstance({
  33147. geometry : topBottomGeo
  33148. }),
  33149. new GeometryInstance({
  33150. geometry : wallGeo
  33151. })
  33152. ]);
  33153. return {
  33154. boundingSphere : boundingSphere,
  33155. attributes : geo[0].attributes,
  33156. indices : geo[0].indices
  33157. };
  33158. }
  33159. var scratchEnuToFixedMatrix = new Matrix4();
  33160. var scratchFixedToEnuMatrix = new Matrix4();
  33161. var scratchRotationMatrix = new Matrix3();
  33162. var scratchRectanglePoints = [new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3()];
  33163. var scratchCartographicPoints = [new Cartographic(), new Cartographic(), new Cartographic(), new Cartographic()];
  33164. function computeRectangle(center, ellipsoid, semiMajorAxis, semiMinorAxis, rotation) {
  33165. Transforms.eastNorthUpToFixedFrame(center, ellipsoid, scratchEnuToFixedMatrix);
  33166. Matrix4.inverseTransformation(scratchEnuToFixedMatrix, scratchFixedToEnuMatrix);
  33167. // Find the 4 extreme points of the ellipse in ENU
  33168. for (var i = 0; i < 4; ++i) {
  33169. Cartesian3.clone(Cartesian3.ZERO, scratchRectanglePoints[i]);
  33170. }
  33171. scratchRectanglePoints[0].x += semiMajorAxis;
  33172. scratchRectanglePoints[1].x -= semiMajorAxis;
  33173. scratchRectanglePoints[2].y += semiMinorAxis;
  33174. scratchRectanglePoints[3].y -= semiMinorAxis;
  33175. Matrix3.fromRotationZ(rotation, scratchRotationMatrix);
  33176. for (i = 0; i < 4; ++i) {
  33177. // Apply the rotation
  33178. Matrix3.multiplyByVector(scratchRotationMatrix, scratchRectanglePoints[i], scratchRectanglePoints[i]);
  33179. // Convert back to fixed and then to cartographic
  33180. Matrix4.multiplyByPoint(scratchEnuToFixedMatrix, scratchRectanglePoints[i], scratchRectanglePoints[i]);
  33181. ellipsoid.cartesianToCartographic(scratchRectanglePoints[i], scratchCartographicPoints[i]);
  33182. }
  33183. return Rectangle.fromCartographicArray(scratchCartographicPoints);
  33184. }
  33185. /**
  33186. * A description of an ellipse on an ellipsoid. Ellipse geometry can be rendered with both {@link Primitive} and {@link GroundPrimitive}.
  33187. *
  33188. * @alias EllipseGeometry
  33189. * @constructor
  33190. *
  33191. * @param {Object} options Object with the following properties:
  33192. * @param {Cartesian3} options.center The ellipse's center point in the fixed frame.
  33193. * @param {Number} options.semiMajorAxis The length of the ellipse's semi-major axis in meters.
  33194. * @param {Number} options.semiMinorAxis The length of the ellipse's semi-minor axis in meters.
  33195. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid the ellipse will be on.
  33196. * @param {Number} [options.height=0.0] The distance in meters between the ellipse and the ellipsoid surface.
  33197. * @param {Number} [options.extrudedHeight] The distance in meters between the ellipse's extruded face and the ellipsoid surface.
  33198. * @param {Number} [options.rotation=0.0] The angle of rotation counter-clockwise from north.
  33199. * @param {Number} [options.stRotation=0.0] The rotation of the texture coordinates counter-clockwise from north.
  33200. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The angular distance between points on the ellipse in radians.
  33201. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  33202. *
  33203. * @exception {DeveloperError} semiMajorAxis and semiMinorAxis must be greater than zero.
  33204. * @exception {DeveloperError} semiMajorAxis must be greater than or equal to the semiMinorAxis.
  33205. * @exception {DeveloperError} granularity must be greater than zero.
  33206. *
  33207. *
  33208. * @example
  33209. * // Create an ellipse.
  33210. * var ellipse = new Cesium.EllipseGeometry({
  33211. * center : Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
  33212. * semiMajorAxis : 500000.0,
  33213. * semiMinorAxis : 300000.0,
  33214. * rotation : Cesium.Math.toRadians(60.0)
  33215. * });
  33216. * var geometry = Cesium.EllipseGeometry.createGeometry(ellipse);
  33217. *
  33218. * @see EllipseGeometry.createGeometry
  33219. */
  33220. function EllipseGeometry(options) {
  33221. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  33222. var center = options.center;
  33223. var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  33224. var semiMajorAxis = options.semiMajorAxis;
  33225. var semiMinorAxis = options.semiMinorAxis;
  33226. var granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  33227. var height = defaultValue(options.height, 0.0);
  33228. var extrudedHeight = options.extrudedHeight;
  33229. var extrude = (defined(extrudedHeight) && Math.abs(height - extrudedHeight) > 1.0);
  33230. var vertexFormat = defaultValue(options.vertexFormat, VertexFormat.DEFAULT);
  33231. if (!defined(center)) {
  33232. throw new DeveloperError('center is required.');
  33233. }
  33234. if (!defined(semiMajorAxis)) {
  33235. throw new DeveloperError('semiMajorAxis is required.');
  33236. }
  33237. if (!defined(semiMinorAxis)) {
  33238. throw new DeveloperError('semiMinorAxis is required.');
  33239. }
  33240. if (semiMajorAxis < semiMinorAxis) {
  33241. throw new DeveloperError('semiMajorAxis must be greater than or equal to the semiMinorAxis.');
  33242. }
  33243. if (granularity <= 0.0) {
  33244. throw new DeveloperError('granularity must be greater than zero.');
  33245. }
  33246. this._center = Cartesian3.clone(center);
  33247. this._semiMajorAxis = semiMajorAxis;
  33248. this._semiMinorAxis = semiMinorAxis;
  33249. this._ellipsoid = Ellipsoid.clone(ellipsoid);
  33250. this._rotation = defaultValue(options.rotation, 0.0);
  33251. this._stRotation = defaultValue(options.stRotation, 0.0);
  33252. this._height = height;
  33253. this._granularity = granularity;
  33254. this._vertexFormat = VertexFormat.clone(vertexFormat);
  33255. this._extrudedHeight = defaultValue(extrudedHeight, height);
  33256. this._extrude = extrude;
  33257. this._workerName = 'createEllipseGeometry';
  33258. this._rectangle = computeRectangle(this._center, this._ellipsoid, semiMajorAxis, semiMinorAxis, this._rotation);
  33259. }
  33260. /**
  33261. * The number of elements used to pack the object into an array.
  33262. * @type {Number}
  33263. */
  33264. EllipseGeometry.packedLength = Cartesian3.packedLength + Ellipsoid.packedLength + VertexFormat.packedLength + Rectangle.packedLength + 8;
  33265. /**
  33266. * Stores the provided instance into the provided array.
  33267. *
  33268. * @param {EllipseGeometry} value The value to pack.
  33269. * @param {Number[]} array The array to pack into.
  33270. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  33271. *
  33272. * @returns {Number[]} The array that was packed into
  33273. */
  33274. EllipseGeometry.pack = function(value, array, startingIndex) {
  33275. if (!defined(value)) {
  33276. throw new DeveloperError('value is required');
  33277. }
  33278. if (!defined(array)) {
  33279. throw new DeveloperError('array is required');
  33280. }
  33281. startingIndex = defaultValue(startingIndex, 0);
  33282. Cartesian3.pack(value._center, array, startingIndex);
  33283. startingIndex += Cartesian3.packedLength;
  33284. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  33285. startingIndex += Ellipsoid.packedLength;
  33286. VertexFormat.pack(value._vertexFormat, array, startingIndex);
  33287. startingIndex += VertexFormat.packedLength;
  33288. Rectangle.pack(value._rectangle, array, startingIndex);
  33289. startingIndex += Rectangle.packedLength;
  33290. array[startingIndex++] = value._semiMajorAxis;
  33291. array[startingIndex++] = value._semiMinorAxis;
  33292. array[startingIndex++] = value._rotation;
  33293. array[startingIndex++] = value._stRotation;
  33294. array[startingIndex++] = value._height;
  33295. array[startingIndex++] = value._granularity;
  33296. array[startingIndex++] = value._extrudedHeight;
  33297. array[startingIndex] = value._extrude ? 1.0 : 0.0;
  33298. return array;
  33299. };
  33300. var scratchCenter = new Cartesian3();
  33301. var scratchEllipsoid = new Ellipsoid();
  33302. var scratchVertexFormat = new VertexFormat();
  33303. var scratchRectangle = new Rectangle();
  33304. var scratchOptions = {
  33305. center : scratchCenter,
  33306. ellipsoid : scratchEllipsoid,
  33307. vertexFormat : scratchVertexFormat,
  33308. semiMajorAxis : undefined,
  33309. semiMinorAxis : undefined,
  33310. rotation : undefined,
  33311. stRotation : undefined,
  33312. height : undefined,
  33313. granularity : undefined,
  33314. extrudedHeight : undefined
  33315. };
  33316. /**
  33317. * Retrieves an instance from a packed array.
  33318. *
  33319. * @param {Number[]} array The packed array.
  33320. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  33321. * @param {EllipseGeometry} [result] The object into which to store the result.
  33322. * @returns {EllipseGeometry} The modified result parameter or a new EllipseGeometry instance if one was not provided.
  33323. */
  33324. EllipseGeometry.unpack = function(array, startingIndex, result) {
  33325. if (!defined(array)) {
  33326. throw new DeveloperError('array is required');
  33327. }
  33328. startingIndex = defaultValue(startingIndex, 0);
  33329. var center = Cartesian3.unpack(array, startingIndex, scratchCenter);
  33330. startingIndex += Cartesian3.packedLength;
  33331. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  33332. startingIndex += Ellipsoid.packedLength;
  33333. var vertexFormat = VertexFormat.unpack(array, startingIndex, scratchVertexFormat);
  33334. startingIndex += VertexFormat.packedLength;
  33335. var rectangle = Rectangle.unpack(array, startingIndex, scratchRectangle);
  33336. startingIndex += Rectangle.packedLength;
  33337. var semiMajorAxis = array[startingIndex++];
  33338. var semiMinorAxis = array[startingIndex++];
  33339. var rotation = array[startingIndex++];
  33340. var stRotation = array[startingIndex++];
  33341. var height = array[startingIndex++];
  33342. var granularity = array[startingIndex++];
  33343. var extrudedHeight = array[startingIndex++];
  33344. var extrude = array[startingIndex] === 1.0;
  33345. if (!defined(result)) {
  33346. scratchOptions.height = height;
  33347. scratchOptions.extrudedHeight = extrudedHeight;
  33348. scratchOptions.granularity = granularity;
  33349. scratchOptions.stRotation = stRotation;
  33350. scratchOptions.rotation = rotation;
  33351. scratchOptions.semiMajorAxis = semiMajorAxis;
  33352. scratchOptions.semiMinorAxis = semiMinorAxis;
  33353. return new EllipseGeometry(scratchOptions);
  33354. }
  33355. result._center = Cartesian3.clone(center, result._center);
  33356. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  33357. result._vertexFormat = VertexFormat.clone(vertexFormat, result._vertexFormat);
  33358. result._semiMajorAxis = semiMajorAxis;
  33359. result._semiMinorAxis = semiMinorAxis;
  33360. result._rotation = rotation;
  33361. result._stRotation = stRotation;
  33362. result._height = height;
  33363. result._granularity = granularity;
  33364. result._extrudedHeight = extrudedHeight;
  33365. result._extrude = extrude;
  33366. result._rectangle = Rectangle.clone(rectangle);
  33367. return result;
  33368. };
  33369. /**
  33370. * Computes the geometric representation of a ellipse on an ellipsoid, including its vertices, indices, and a bounding sphere.
  33371. *
  33372. * @param {EllipseGeometry} ellipseGeometry A description of the ellipse.
  33373. * @returns {Geometry|undefined} The computed vertices and indices.
  33374. */
  33375. EllipseGeometry.createGeometry = function(ellipseGeometry) {
  33376. if ((ellipseGeometry._semiMajorAxis <= 0.0) || (ellipseGeometry._semiMinorAxis <= 0.0)) {
  33377. return;
  33378. }
  33379. ellipseGeometry._center = ellipseGeometry._ellipsoid.scaleToGeodeticSurface(ellipseGeometry._center, ellipseGeometry._center);
  33380. var options = {
  33381. center : ellipseGeometry._center,
  33382. semiMajorAxis : ellipseGeometry._semiMajorAxis,
  33383. semiMinorAxis : ellipseGeometry._semiMinorAxis,
  33384. ellipsoid : ellipseGeometry._ellipsoid,
  33385. rotation : ellipseGeometry._rotation,
  33386. height : ellipseGeometry._height,
  33387. extrudedHeight : ellipseGeometry._extrudedHeight,
  33388. granularity : ellipseGeometry._granularity,
  33389. vertexFormat : ellipseGeometry._vertexFormat,
  33390. stRotation : ellipseGeometry._stRotation
  33391. };
  33392. var geometry;
  33393. if (ellipseGeometry._extrude) {
  33394. options.extrudedHeight = Math.min(ellipseGeometry._extrudedHeight, ellipseGeometry._height);
  33395. options.height = Math.max(ellipseGeometry._extrudedHeight, ellipseGeometry._height);
  33396. geometry = computeExtrudedEllipse(options);
  33397. } else {
  33398. geometry = computeEllipse(options);
  33399. }
  33400. return new Geometry({
  33401. attributes : geometry.attributes,
  33402. indices : geometry.indices,
  33403. primitiveType : PrimitiveType.TRIANGLES,
  33404. boundingSphere : geometry.boundingSphere
  33405. });
  33406. };
  33407. /**
  33408. * @private
  33409. */
  33410. EllipseGeometry.createShadowVolume = function(ellipseGeometry, minHeightFunc, maxHeightFunc) {
  33411. var granularity = ellipseGeometry._granularity;
  33412. var ellipsoid = ellipseGeometry._ellipsoid;
  33413. var minHeight = minHeightFunc(granularity, ellipsoid);
  33414. var maxHeight = maxHeightFunc(granularity, ellipsoid);
  33415. return new EllipseGeometry({
  33416. center : ellipseGeometry._center,
  33417. semiMajorAxis : ellipseGeometry._semiMajorAxis,
  33418. semiMinorAxis : ellipseGeometry._semiMinorAxis,
  33419. ellipsoid : ellipsoid,
  33420. rotation : ellipseGeometry._rotation,
  33421. stRotation : ellipseGeometry._stRotation,
  33422. granularity : granularity,
  33423. extrudedHeight : minHeight,
  33424. height : maxHeight,
  33425. vertexFormat : VertexFormat.POSITION_ONLY
  33426. });
  33427. };
  33428. defineProperties(EllipseGeometry.prototype, {
  33429. /**
  33430. * @private
  33431. */
  33432. rectangle : {
  33433. get : function() {
  33434. return this._rectangle;
  33435. }
  33436. }
  33437. });
  33438. return EllipseGeometry;
  33439. });
  33440. /*global define*/
  33441. define('Core/CircleGeometry',[
  33442. './Cartesian3',
  33443. './defaultValue',
  33444. './defined',
  33445. './defineProperties',
  33446. './DeveloperError',
  33447. './EllipseGeometry',
  33448. './Ellipsoid',
  33449. './VertexFormat'
  33450. ], function(
  33451. Cartesian3,
  33452. defaultValue,
  33453. defined,
  33454. defineProperties,
  33455. DeveloperError,
  33456. EllipseGeometry,
  33457. Ellipsoid,
  33458. VertexFormat) {
  33459. 'use strict';
  33460. /**
  33461. * A description of a circle on the ellipsoid. Circle geometry can be rendered with both {@link Primitive} and {@link GroundPrimitive}.
  33462. *
  33463. * @alias CircleGeometry
  33464. * @constructor
  33465. *
  33466. * @param {Object} options Object with the following properties:
  33467. * @param {Cartesian3} options.center The circle's center point in the fixed frame.
  33468. * @param {Number} options.radius The radius in meters.
  33469. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid the circle will be on.
  33470. * @param {Number} [options.height=0.0] The distance in meters between the circle and the ellipsoid surface.
  33471. * @param {Number} [options.granularity=0.02] The angular distance between points on the circle in radians.
  33472. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  33473. * @param {Number} [options.extrudedHeight=0.0] The distance in meters between the circle's extruded face and the ellipsoid surface.
  33474. * @param {Number} [options.stRotation=0.0] The rotation of the texture coordinates, in radians. A positive rotation is counter-clockwise.
  33475. *
  33476. * @exception {DeveloperError} radius must be greater than zero.
  33477. * @exception {DeveloperError} granularity must be greater than zero.
  33478. *
  33479. * @see CircleGeometry.createGeometry
  33480. * @see Packable
  33481. *
  33482. * @example
  33483. * // Create a circle.
  33484. * var circle = new Cesium.CircleGeometry({
  33485. * center : Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
  33486. * radius : 100000.0
  33487. * });
  33488. * var geometry = Cesium.CircleGeometry.createGeometry(circle);
  33489. */
  33490. function CircleGeometry(options) {
  33491. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  33492. var radius = options.radius;
  33493. if (!defined(radius)) {
  33494. throw new DeveloperError('radius is required.');
  33495. }
  33496. var ellipseGeometryOptions = {
  33497. center : options.center,
  33498. semiMajorAxis : radius,
  33499. semiMinorAxis : radius,
  33500. ellipsoid : options.ellipsoid,
  33501. height : options.height,
  33502. extrudedHeight : options.extrudedHeight,
  33503. granularity : options.granularity,
  33504. vertexFormat : options.vertexFormat,
  33505. stRotation : options.stRotation
  33506. };
  33507. this._ellipseGeometry = new EllipseGeometry(ellipseGeometryOptions);
  33508. this._workerName = 'createCircleGeometry';
  33509. }
  33510. /**
  33511. * The number of elements used to pack the object into an array.
  33512. * @type {Number}
  33513. */
  33514. CircleGeometry.packedLength = EllipseGeometry.packedLength;
  33515. /**
  33516. * Stores the provided instance into the provided array.
  33517. *
  33518. * @param {CircleGeometry} value The value to pack.
  33519. * @param {Number[]} array The array to pack into.
  33520. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  33521. *
  33522. * @returns {Number[]} The array that was packed into
  33523. */
  33524. CircleGeometry.pack = function(value, array, startingIndex) {
  33525. if (!defined(value)) {
  33526. throw new DeveloperError('value is required');
  33527. }
  33528. return EllipseGeometry.pack(value._ellipseGeometry, array, startingIndex);
  33529. };
  33530. var scratchEllipseGeometry = new EllipseGeometry({
  33531. center : new Cartesian3(),
  33532. semiMajorAxis : 1.0,
  33533. semiMinorAxis : 1.0
  33534. });
  33535. var scratchOptions = {
  33536. center : new Cartesian3(),
  33537. radius : undefined,
  33538. ellipsoid : Ellipsoid.clone(Ellipsoid.UNIT_SPHERE),
  33539. height : undefined,
  33540. extrudedHeight : undefined,
  33541. granularity : undefined,
  33542. vertexFormat : new VertexFormat(),
  33543. stRotation : undefined,
  33544. semiMajorAxis : undefined,
  33545. semiMinorAxis : undefined
  33546. };
  33547. /**
  33548. * Retrieves an instance from a packed array.
  33549. *
  33550. * @param {Number[]} array The packed array.
  33551. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  33552. * @param {CircleGeometry} [result] The object into which to store the result.
  33553. * @returns {CircleGeometry} The modified result parameter or a new CircleGeometry instance if one was not provided.
  33554. */
  33555. CircleGeometry.unpack = function(array, startingIndex, result) {
  33556. var ellipseGeometry = EllipseGeometry.unpack(array, startingIndex, scratchEllipseGeometry);
  33557. scratchOptions.center = Cartesian3.clone(ellipseGeometry._center, scratchOptions.center);
  33558. scratchOptions.ellipsoid = Ellipsoid.clone(ellipseGeometry._ellipsoid, scratchOptions.ellipsoid);
  33559. scratchOptions.height = ellipseGeometry._height;
  33560. scratchOptions.extrudedHeight = ellipseGeometry._extrudedHeight;
  33561. scratchOptions.granularity = ellipseGeometry._granularity;
  33562. scratchOptions.vertexFormat = VertexFormat.clone(ellipseGeometry._vertexFormat, scratchOptions.vertexFormat);
  33563. scratchOptions.stRotation = ellipseGeometry._stRotation;
  33564. if (!defined(result)) {
  33565. scratchOptions.radius = ellipseGeometry._semiMajorAxis;
  33566. return new CircleGeometry(scratchOptions);
  33567. }
  33568. scratchOptions.semiMajorAxis = ellipseGeometry._semiMajorAxis;
  33569. scratchOptions.semiMinorAxis = ellipseGeometry._semiMinorAxis;
  33570. result._ellipseGeometry = new EllipseGeometry(scratchOptions);
  33571. return result;
  33572. };
  33573. /**
  33574. * Computes the geometric representation of a circle on an ellipsoid, including its vertices, indices, and a bounding sphere.
  33575. *
  33576. * @param {CircleGeometry} circleGeometry A description of the circle.
  33577. * @returns {Geometry|undefined} The computed vertices and indices.
  33578. */
  33579. CircleGeometry.createGeometry = function(circleGeometry) {
  33580. return EllipseGeometry.createGeometry(circleGeometry._ellipseGeometry);
  33581. };
  33582. /**
  33583. * @private
  33584. */
  33585. CircleGeometry.createShadowVolume = function(circleGeometry, minHeightFunc, maxHeightFunc) {
  33586. var granularity = circleGeometry._ellipseGeometry._granularity;
  33587. var ellipsoid = circleGeometry._ellipseGeometry._ellipsoid;
  33588. var minHeight = minHeightFunc(granularity, ellipsoid);
  33589. var maxHeight = maxHeightFunc(granularity, ellipsoid);
  33590. return new CircleGeometry({
  33591. center : circleGeometry._ellipseGeometry._center,
  33592. radius : circleGeometry._ellipseGeometry._semiMajorAxis,
  33593. ellipsoid : ellipsoid,
  33594. stRotation : circleGeometry._ellipseGeometry._stRotation,
  33595. granularity : granularity,
  33596. extrudedHeight : minHeight,
  33597. height : maxHeight,
  33598. vertexFormat : VertexFormat.POSITION_ONLY
  33599. });
  33600. };
  33601. defineProperties(CircleGeometry.prototype, {
  33602. /**
  33603. * @private
  33604. */
  33605. rectangle : {
  33606. get : function() {
  33607. return this._ellipseGeometry.rectangle;
  33608. }
  33609. }
  33610. });
  33611. return CircleGeometry;
  33612. });
  33613. /*global define*/
  33614. define('Core/EllipseOutlineGeometry',[
  33615. './BoundingSphere',
  33616. './Cartesian3',
  33617. './ComponentDatatype',
  33618. './defaultValue',
  33619. './defined',
  33620. './DeveloperError',
  33621. './EllipseGeometryLibrary',
  33622. './Ellipsoid',
  33623. './Geometry',
  33624. './GeometryAttribute',
  33625. './GeometryAttributes',
  33626. './IndexDatatype',
  33627. './Math',
  33628. './PrimitiveType'
  33629. ], function(
  33630. BoundingSphere,
  33631. Cartesian3,
  33632. ComponentDatatype,
  33633. defaultValue,
  33634. defined,
  33635. DeveloperError,
  33636. EllipseGeometryLibrary,
  33637. Ellipsoid,
  33638. Geometry,
  33639. GeometryAttribute,
  33640. GeometryAttributes,
  33641. IndexDatatype,
  33642. CesiumMath,
  33643. PrimitiveType) {
  33644. 'use strict';
  33645. var scratchCartesian1 = new Cartesian3();
  33646. var boundingSphereCenter = new Cartesian3();
  33647. function computeEllipse(options) {
  33648. var center = options.center;
  33649. boundingSphereCenter = Cartesian3.multiplyByScalar(options.ellipsoid.geodeticSurfaceNormal(center, boundingSphereCenter), options.height, boundingSphereCenter);
  33650. boundingSphereCenter = Cartesian3.add(center, boundingSphereCenter, boundingSphereCenter);
  33651. var boundingSphere = new BoundingSphere(boundingSphereCenter, options.semiMajorAxis);
  33652. var positions = EllipseGeometryLibrary.computeEllipsePositions(options, false, true).outerPositions;
  33653. var attributes = new GeometryAttributes({
  33654. position: new GeometryAttribute({
  33655. componentDatatype : ComponentDatatype.DOUBLE,
  33656. componentsPerAttribute : 3,
  33657. values : EllipseGeometryLibrary.raisePositionsToHeight(positions, options, false)
  33658. })
  33659. });
  33660. var length = positions.length / 3;
  33661. var indices = IndexDatatype.createTypedArray(length, length * 2);
  33662. var index = 0;
  33663. for ( var i = 0; i < length; ++i) {
  33664. indices[index++] = i;
  33665. indices[index++] = (i + 1) % length;
  33666. }
  33667. return {
  33668. boundingSphere : boundingSphere,
  33669. attributes : attributes,
  33670. indices : indices
  33671. };
  33672. }
  33673. var topBoundingSphere = new BoundingSphere();
  33674. var bottomBoundingSphere = new BoundingSphere();
  33675. function computeExtrudedEllipse(options) {
  33676. var center = options.center;
  33677. var ellipsoid = options.ellipsoid;
  33678. var semiMajorAxis = options.semiMajorAxis;
  33679. var scaledNormal = Cartesian3.multiplyByScalar(ellipsoid.geodeticSurfaceNormal(center, scratchCartesian1), options.height, scratchCartesian1);
  33680. topBoundingSphere.center = Cartesian3.add(center, scaledNormal, topBoundingSphere.center);
  33681. topBoundingSphere.radius = semiMajorAxis;
  33682. scaledNormal = Cartesian3.multiplyByScalar(ellipsoid.geodeticSurfaceNormal(center, scaledNormal), options.extrudedHeight, scaledNormal);
  33683. bottomBoundingSphere.center = Cartesian3.add(center, scaledNormal, bottomBoundingSphere.center);
  33684. bottomBoundingSphere.radius = semiMajorAxis;
  33685. var positions = EllipseGeometryLibrary.computeEllipsePositions(options, false, true).outerPositions;
  33686. var attributes = new GeometryAttributes({
  33687. position: new GeometryAttribute({
  33688. componentDatatype : ComponentDatatype.DOUBLE,
  33689. componentsPerAttribute : 3,
  33690. values : EllipseGeometryLibrary.raisePositionsToHeight(positions, options, true)
  33691. })
  33692. });
  33693. positions = attributes.position.values;
  33694. var boundingSphere = BoundingSphere.union(topBoundingSphere, bottomBoundingSphere);
  33695. var length = positions.length/3;
  33696. var numberOfVerticalLines = defaultValue(options.numberOfVerticalLines, 16);
  33697. numberOfVerticalLines = CesiumMath.clamp(numberOfVerticalLines, 0, length/2);
  33698. var indices = IndexDatatype.createTypedArray(length, length * 2 + numberOfVerticalLines * 2);
  33699. length /= 2;
  33700. var index = 0;
  33701. var i;
  33702. for (i = 0; i < length; ++i) {
  33703. indices[index++] = i;
  33704. indices[index++] = (i + 1) % length;
  33705. indices[index++] = i + length;
  33706. indices[index++] = ((i + 1) % length) + length;
  33707. }
  33708. var numSide;
  33709. if (numberOfVerticalLines > 0) {
  33710. var numSideLines = Math.min(numberOfVerticalLines, length);
  33711. numSide = Math.round(length / numSideLines);
  33712. var maxI = Math.min(numSide * numberOfVerticalLines, length);
  33713. for (i = 0; i < maxI; i += numSide) {
  33714. indices[index++] = i;
  33715. indices[index++] = i + length;
  33716. }
  33717. }
  33718. return {
  33719. boundingSphere : boundingSphere,
  33720. attributes : attributes,
  33721. indices : indices
  33722. };
  33723. }
  33724. /**
  33725. * A description of the outline of an ellipse on an ellipsoid.
  33726. *
  33727. * @alias EllipseOutlineGeometry
  33728. * @constructor
  33729. *
  33730. * @param {Object} options Object with the following properties:
  33731. * @param {Cartesian3} options.center The ellipse's center point in the fixed frame.
  33732. * @param {Number} options.semiMajorAxis The length of the ellipse's semi-major axis in meters.
  33733. * @param {Number} options.semiMinorAxis The length of the ellipse's semi-minor axis in meters.
  33734. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid the ellipse will be on.
  33735. * @param {Number} [options.height=0.0] The distance in meters between the ellipse and the ellipsoid surface.
  33736. * @param {Number} [options.extrudedHeight] The distance in meters between the ellipse's extruded face and the ellipsoid surface.
  33737. * @param {Number} [options.rotation=0.0] The angle from north (counter-clockwise) in radians.
  33738. * @param {Number} [options.granularity=0.02] The angular distance between points on the ellipse in radians.
  33739. * @param {Number} [options.numberOfVerticalLines=16] Number of lines to draw between the top and bottom surface of an extruded ellipse.
  33740. *
  33741. * @exception {DeveloperError} semiMajorAxis and semiMinorAxis must be greater than zero.
  33742. * @exception {DeveloperError} semiMajorAxis must be greater than or equal to the semiMinorAxis.
  33743. * @exception {DeveloperError} granularity must be greater than zero.
  33744. *
  33745. * @see EllipseOutlineGeometry.createGeometry
  33746. *
  33747. * @example
  33748. * var ellipse = new Cesium.EllipseOutlineGeometry({
  33749. * center : Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
  33750. * semiMajorAxis : 500000.0,
  33751. * semiMinorAxis : 300000.0,
  33752. * rotation : Cesium.Math.toRadians(60.0)
  33753. * });
  33754. * var geometry = Cesium.EllipseOutlineGeometry.createGeometry(ellipse);
  33755. */
  33756. function EllipseOutlineGeometry(options) {
  33757. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  33758. var center = options.center;
  33759. var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  33760. var semiMajorAxis = options.semiMajorAxis;
  33761. var semiMinorAxis = options.semiMinorAxis;
  33762. var granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  33763. var height = defaultValue(options.height, 0.0);
  33764. var extrudedHeight = options.extrudedHeight;
  33765. var extrude = (defined(extrudedHeight) && Math.abs(height - extrudedHeight) > 1.0);
  33766. if (!defined(center)) {
  33767. throw new DeveloperError('center is required.');
  33768. }
  33769. if (!defined(semiMajorAxis)) {
  33770. throw new DeveloperError('semiMajorAxis is required.');
  33771. }
  33772. if (!defined(semiMinorAxis)) {
  33773. throw new DeveloperError('semiMinorAxis is required.');
  33774. }
  33775. if (semiMajorAxis < semiMinorAxis) {
  33776. throw new DeveloperError('semiMajorAxis must be greater than or equal to the semiMinorAxis.');
  33777. }
  33778. if (granularity <= 0.0) {
  33779. throw new DeveloperError('granularity must be greater than zero.');
  33780. }
  33781. this._center = Cartesian3.clone(center);
  33782. this._semiMajorAxis = semiMajorAxis;
  33783. this._semiMinorAxis = semiMinorAxis;
  33784. this._ellipsoid = Ellipsoid.clone(ellipsoid);
  33785. this._rotation = defaultValue(options.rotation, 0.0);
  33786. this._height = height;
  33787. this._granularity = granularity;
  33788. this._extrudedHeight = extrudedHeight;
  33789. this._extrude = extrude;
  33790. this._numberOfVerticalLines = Math.max(defaultValue(options.numberOfVerticalLines, 16), 0);
  33791. this._workerName = 'createEllipseOutlineGeometry';
  33792. }
  33793. /**
  33794. * The number of elements used to pack the object into an array.
  33795. * @type {Number}
  33796. */
  33797. EllipseOutlineGeometry.packedLength = Cartesian3.packedLength + Ellipsoid.packedLength + 9;
  33798. /**
  33799. * Stores the provided instance into the provided array.
  33800. *
  33801. * @param {EllipseOutlineGeometry} value The value to pack.
  33802. * @param {Number[]} array The array to pack into.
  33803. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  33804. *
  33805. * @returns {Number[]} The array that was packed into
  33806. */
  33807. EllipseOutlineGeometry.pack = function(value, array, startingIndex) {
  33808. if (!defined(value)) {
  33809. throw new DeveloperError('value is required');
  33810. }
  33811. if (!defined(array)) {
  33812. throw new DeveloperError('array is required');
  33813. }
  33814. startingIndex = defaultValue(startingIndex, 0);
  33815. Cartesian3.pack(value._center, array, startingIndex);
  33816. startingIndex += Cartesian3.packedLength;
  33817. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  33818. startingIndex += Ellipsoid.packedLength;
  33819. array[startingIndex++] = value._semiMajorAxis;
  33820. array[startingIndex++] = value._semiMinorAxis;
  33821. array[startingIndex++] = value._rotation;
  33822. array[startingIndex++] = value._height;
  33823. array[startingIndex++] = value._granularity;
  33824. array[startingIndex++] = defined(value._extrudedHeight) ? 1.0 : 0.0;
  33825. array[startingIndex++] = defaultValue(value._extrudedHeight, 0.0);
  33826. array[startingIndex++] = value._extrude ? 1.0 : 0.0;
  33827. array[startingIndex] = value._numberOfVerticalLines;
  33828. return array;
  33829. };
  33830. var scratchCenter = new Cartesian3();
  33831. var scratchEllipsoid = new Ellipsoid();
  33832. var scratchOptions = {
  33833. center : scratchCenter,
  33834. ellipsoid : scratchEllipsoid,
  33835. semiMajorAxis : undefined,
  33836. semiMinorAxis : undefined,
  33837. rotation : undefined,
  33838. height : undefined,
  33839. granularity : undefined,
  33840. extrudedHeight : undefined,
  33841. numberOfVerticalLines : undefined
  33842. };
  33843. /**
  33844. * Retrieves an instance from a packed array.
  33845. *
  33846. * @param {Number[]} array The packed array.
  33847. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  33848. * @param {EllipseOutlineGeometry} [result] The object into which to store the result.
  33849. * @returns {EllipseOutlineGeometry} The modified result parameter or a new EllipseOutlineGeometry instance if one was not provided.
  33850. */
  33851. EllipseOutlineGeometry.unpack = function(array, startingIndex, result) {
  33852. if (!defined(array)) {
  33853. throw new DeveloperError('array is required');
  33854. }
  33855. startingIndex = defaultValue(startingIndex, 0);
  33856. var center = Cartesian3.unpack(array, startingIndex, scratchCenter);
  33857. startingIndex += Cartesian3.packedLength;
  33858. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  33859. startingIndex += Ellipsoid.packedLength;
  33860. var semiMajorAxis = array[startingIndex++];
  33861. var semiMinorAxis = array[startingIndex++];
  33862. var rotation = array[startingIndex++];
  33863. var height = array[startingIndex++];
  33864. var granularity = array[startingIndex++];
  33865. var hasExtrudedHeight = array[startingIndex++];
  33866. var extrudedHeight = array[startingIndex++];
  33867. var extrude = array[startingIndex++] === 1.0;
  33868. var numberOfVerticalLines = array[startingIndex];
  33869. if (!defined(result)) {
  33870. scratchOptions.height = height;
  33871. scratchOptions.extrudedHeight = hasExtrudedHeight ? extrudedHeight : undefined;
  33872. scratchOptions.granularity = granularity;
  33873. scratchOptions.rotation = rotation;
  33874. scratchOptions.semiMajorAxis = semiMajorAxis;
  33875. scratchOptions.semiMinorAxis = semiMinorAxis;
  33876. scratchOptions.numberOfVerticalLines = numberOfVerticalLines;
  33877. return new EllipseOutlineGeometry(scratchOptions);
  33878. }
  33879. result._center = Cartesian3.clone(center, result._center);
  33880. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  33881. result._semiMajorAxis = semiMajorAxis;
  33882. result._semiMinorAxis = semiMinorAxis;
  33883. result._rotation = rotation;
  33884. result._height = height;
  33885. result._granularity = granularity;
  33886. result._extrudedHeight = hasExtrudedHeight ? extrudedHeight : undefined;
  33887. result._extrude = extrude;
  33888. result._numberOfVerticalLines = numberOfVerticalLines;
  33889. return result;
  33890. };
  33891. /**
  33892. * Computes the geometric representation of an outline of an ellipse on an ellipsoid, including its vertices, indices, and a bounding sphere.
  33893. *
  33894. * @param {EllipseOutlineGeometry} ellipseGeometry A description of the ellipse.
  33895. * @returns {Geometry|undefined} The computed vertices and indices.
  33896. */
  33897. EllipseOutlineGeometry.createGeometry = function(ellipseGeometry) {
  33898. if ((ellipseGeometry._semiMajorAxis <= 0.0) || (ellipseGeometry._semiMinorAxis <= 0.0)) {
  33899. return;
  33900. }
  33901. ellipseGeometry._center = ellipseGeometry._ellipsoid.scaleToGeodeticSurface(ellipseGeometry._center, ellipseGeometry._center);
  33902. var options = {
  33903. center : ellipseGeometry._center,
  33904. semiMajorAxis : ellipseGeometry._semiMajorAxis,
  33905. semiMinorAxis : ellipseGeometry._semiMinorAxis,
  33906. ellipsoid : ellipseGeometry._ellipsoid,
  33907. rotation : ellipseGeometry._rotation,
  33908. height : ellipseGeometry._height,
  33909. extrudedHeight : ellipseGeometry._extrudedHeight,
  33910. granularity : ellipseGeometry._granularity,
  33911. numberOfVerticalLines : ellipseGeometry._numberOfVerticalLines
  33912. };
  33913. var geometry;
  33914. if (ellipseGeometry._extrude) {
  33915. options.extrudedHeight = Math.min(ellipseGeometry._extrudedHeight, ellipseGeometry._height);
  33916. options.height = Math.max(ellipseGeometry._extrudedHeight, ellipseGeometry._height);
  33917. geometry = computeExtrudedEllipse(options);
  33918. } else {
  33919. geometry = computeEllipse(options);
  33920. }
  33921. return new Geometry({
  33922. attributes : geometry.attributes,
  33923. indices : geometry.indices,
  33924. primitiveType : PrimitiveType.LINES,
  33925. boundingSphere : geometry.boundingSphere
  33926. });
  33927. };
  33928. return EllipseOutlineGeometry;
  33929. });
  33930. /*global define*/
  33931. define('Core/CircleOutlineGeometry',[
  33932. './Cartesian3',
  33933. './defaultValue',
  33934. './defined',
  33935. './DeveloperError',
  33936. './EllipseOutlineGeometry',
  33937. './Ellipsoid'
  33938. ], function(
  33939. Cartesian3,
  33940. defaultValue,
  33941. defined,
  33942. DeveloperError,
  33943. EllipseOutlineGeometry,
  33944. Ellipsoid) {
  33945. 'use strict';
  33946. /**
  33947. * A description of the outline of a circle on the ellipsoid.
  33948. *
  33949. * @alias CircleOutlineGeometry
  33950. * @constructor
  33951. *
  33952. * @param {Object} options Object with the following properties:
  33953. * @param {Cartesian3} options.center The circle's center point in the fixed frame.
  33954. * @param {Number} options.radius The radius in meters.
  33955. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid the circle will be on.
  33956. * @param {Number} [options.height=0.0] The distance in meters between the circle and the ellipsoid surface.
  33957. * @param {Number} [options.granularity=0.02] The angular distance between points on the circle in radians.
  33958. * @param {Number} [options.extrudedHeight=0.0] The distance in meters between the circle's extruded face and the ellipsoid surface.
  33959. * @param {Number} [options.numberOfVerticalLines=16] Number of lines to draw between the top and bottom of an extruded circle.
  33960. *
  33961. * @exception {DeveloperError} radius must be greater than zero.
  33962. * @exception {DeveloperError} granularity must be greater than zero.
  33963. *
  33964. * @see CircleOutlineGeometry.createGeometry
  33965. * @see Packable
  33966. *
  33967. * @example
  33968. * // Create a circle.
  33969. * var circle = new Cesium.CircleOutlineGeometry({
  33970. * center : Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
  33971. * radius : 100000.0
  33972. * });
  33973. * var geometry = Cesium.CircleOutlineGeometry.createGeometry(circle);
  33974. */
  33975. function CircleOutlineGeometry(options) {
  33976. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  33977. var radius = options.radius;
  33978. if (!defined(radius)) {
  33979. throw new DeveloperError('radius is required.');
  33980. }
  33981. var ellipseGeometryOptions = {
  33982. center : options.center,
  33983. semiMajorAxis : radius,
  33984. semiMinorAxis : radius,
  33985. ellipsoid : options.ellipsoid,
  33986. height : options.height,
  33987. extrudedHeight : options.extrudedHeight,
  33988. granularity : options.granularity,
  33989. numberOfVerticalLines : options.numberOfVerticalLines
  33990. };
  33991. this._ellipseGeometry = new EllipseOutlineGeometry(ellipseGeometryOptions);
  33992. this._workerName = 'createCircleOutlineGeometry';
  33993. }
  33994. /**
  33995. * The number of elements used to pack the object into an array.
  33996. * @type {Number}
  33997. */
  33998. CircleOutlineGeometry.packedLength = EllipseOutlineGeometry.packedLength;
  33999. /**
  34000. * Stores the provided instance into the provided array.
  34001. *
  34002. * @param {CircleOutlineGeometry} value The value to pack.
  34003. * @param {Number[]} array The array to pack into.
  34004. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  34005. *
  34006. * @returns {Number[]} The array that was packed into
  34007. */
  34008. CircleOutlineGeometry.pack = function(value, array, startingIndex) {
  34009. if (!defined(value)) {
  34010. throw new DeveloperError('value is required');
  34011. }
  34012. return EllipseOutlineGeometry.pack(value._ellipseGeometry, array, startingIndex);
  34013. };
  34014. var scratchEllipseGeometry = new EllipseOutlineGeometry({
  34015. center : new Cartesian3(),
  34016. semiMajorAxis : 1.0,
  34017. semiMinorAxis : 1.0
  34018. });
  34019. var scratchOptions = {
  34020. center : new Cartesian3(),
  34021. radius : undefined,
  34022. ellipsoid : Ellipsoid.clone(Ellipsoid.UNIT_SPHERE),
  34023. height : undefined,
  34024. extrudedHeight : undefined,
  34025. granularity : undefined,
  34026. numberOfVerticalLines : undefined,
  34027. semiMajorAxis : undefined,
  34028. semiMinorAxis : undefined
  34029. };
  34030. /**
  34031. * Retrieves an instance from a packed array.
  34032. *
  34033. * @param {Number[]} array The packed array.
  34034. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  34035. * @param {CircleOutlineGeometry} [result] The object into which to store the result.
  34036. * @returns {CircleOutlineGeometry} The modified result parameter or a new CircleOutlineGeometry instance if one was not provided.
  34037. */
  34038. CircleOutlineGeometry.unpack = function(array, startingIndex, result) {
  34039. var ellipseGeometry = EllipseOutlineGeometry.unpack(array, startingIndex, scratchEllipseGeometry);
  34040. scratchOptions.center = Cartesian3.clone(ellipseGeometry._center, scratchOptions.center);
  34041. scratchOptions.ellipsoid = Ellipsoid.clone(ellipseGeometry._ellipsoid, scratchOptions.ellipsoid);
  34042. scratchOptions.height = ellipseGeometry._height;
  34043. scratchOptions.extrudedHeight = ellipseGeometry._extrudedHeight;
  34044. scratchOptions.granularity = ellipseGeometry._granularity;
  34045. scratchOptions.numberOfVerticalLines = ellipseGeometry._numberOfVerticalLines;
  34046. if (!defined(result)) {
  34047. scratchOptions.radius = ellipseGeometry._semiMajorAxis;
  34048. return new CircleOutlineGeometry(scratchOptions);
  34049. }
  34050. scratchOptions.semiMajorAxis = ellipseGeometry._semiMajorAxis;
  34051. scratchOptions.semiMinorAxis = ellipseGeometry._semiMinorAxis;
  34052. result._ellipseGeometry = new EllipseOutlineGeometry(scratchOptions);
  34053. return result;
  34054. };
  34055. /**
  34056. * Computes the geometric representation of an outline of a circle on an ellipsoid, including its vertices, indices, and a bounding sphere.
  34057. *
  34058. * @param {CircleOutlineGeometry} circleGeometry A description of the circle.
  34059. * @returns {Geometry|undefined} The computed vertices and indices.
  34060. */
  34061. CircleOutlineGeometry.createGeometry = function(circleGeometry) {
  34062. return EllipseOutlineGeometry.createGeometry(circleGeometry._ellipseGeometry);
  34063. };
  34064. return CircleOutlineGeometry;
  34065. });
  34066. /*global define*/
  34067. define('Core/ClockRange',[
  34068. './freezeObject'
  34069. ], function(
  34070. freezeObject) {
  34071. 'use strict';
  34072. /**
  34073. * Constants used by {@link Clock#tick} to determine behavior
  34074. * when {@link Clock#startTime} or {@link Clock#stopTime} is reached.
  34075. *
  34076. * @exports ClockRange
  34077. *
  34078. * @see Clock
  34079. * @see ClockStep
  34080. */
  34081. var ClockRange = {
  34082. /**
  34083. * {@link Clock#tick} will always advances the clock in its current direction.
  34084. *
  34085. * @type {Number}
  34086. * @constant
  34087. */
  34088. UNBOUNDED : 0,
  34089. /**
  34090. * When {@link Clock#startTime} or {@link Clock#stopTime} is reached,
  34091. * {@link Clock#tick} will not advance {@link Clock#currentTime} any further.
  34092. *
  34093. * @type {Number}
  34094. * @constant
  34095. */
  34096. CLAMPED : 1,
  34097. /**
  34098. * When {@link Clock#stopTime} is reached, {@link Clock#tick} will advance
  34099. * {@link Clock#currentTime} to the opposite end of the interval. When
  34100. * time is moving backwards, {@link Clock#tick} will not advance past
  34101. * {@link Clock#startTime}
  34102. *
  34103. * @type {Number}
  34104. * @constant
  34105. */
  34106. LOOP_STOP : 2
  34107. };
  34108. return freezeObject(ClockRange);
  34109. });
  34110. /*global define*/
  34111. define('Core/ClockStep',[
  34112. './freezeObject'
  34113. ], function(
  34114. freezeObject) {
  34115. 'use strict';
  34116. /**
  34117. * Constants to determine how much time advances with each call
  34118. * to {@link Clock#tick}.
  34119. *
  34120. * @exports ClockStep
  34121. *
  34122. * @see Clock
  34123. * @see ClockRange
  34124. */
  34125. var ClockStep = {
  34126. /**
  34127. * {@link Clock#tick} advances the current time by a fixed step,
  34128. * which is the number of seconds specified by {@link Clock#multiplier}.
  34129. *
  34130. * @type {Number}
  34131. * @constant
  34132. */
  34133. TICK_DEPENDENT : 0,
  34134. /**
  34135. * {@link Clock#tick} advances the current time by the amount of system
  34136. * time elapsed since the previous call multiplied by {@link Clock#multiplier}.
  34137. *
  34138. * @type {Number}
  34139. * @constant
  34140. */
  34141. SYSTEM_CLOCK_MULTIPLIER : 1,
  34142. /**
  34143. * {@link Clock#tick} sets the clock to the current system time;
  34144. * ignoring all other settings.
  34145. *
  34146. * @type {Number}
  34147. * @constant
  34148. */
  34149. SYSTEM_CLOCK : 2
  34150. };
  34151. return freezeObject(ClockStep);
  34152. });
  34153. /*global define*/
  34154. define('Core/getTimestamp',[
  34155. './defined'
  34156. ], function(
  34157. defined) {
  34158. 'use strict';
  34159. /*global performance*/
  34160. /**
  34161. * Gets a timestamp that can be used in measuring the time between events. Timestamps
  34162. * are expressed in milliseconds, but it is not specified what the milliseconds are
  34163. * measured from. This function uses performance.now() if it is available, or Date.now()
  34164. * otherwise.
  34165. *
  34166. * @exports getTimestamp
  34167. *
  34168. * @returns {Number} The timestamp in milliseconds since some unspecified reference time.
  34169. */
  34170. var getTimestamp;
  34171. if (typeof performance !== 'undefined' && defined(performance.now)) {
  34172. getTimestamp = function() {
  34173. return performance.now();
  34174. };
  34175. } else {
  34176. getTimestamp = function() {
  34177. return Date.now();
  34178. };
  34179. }
  34180. return getTimestamp;
  34181. });
  34182. /*global define*/
  34183. define('Core/Clock',[
  34184. './ClockRange',
  34185. './ClockStep',
  34186. './defaultValue',
  34187. './defined',
  34188. './defineProperties',
  34189. './DeveloperError',
  34190. './Event',
  34191. './getTimestamp',
  34192. './JulianDate'
  34193. ], function(
  34194. ClockRange,
  34195. ClockStep,
  34196. defaultValue,
  34197. defined,
  34198. defineProperties,
  34199. DeveloperError,
  34200. Event,
  34201. getTimestamp,
  34202. JulianDate) {
  34203. 'use strict';
  34204. /**
  34205. * A simple clock for keeping track of simulated time.
  34206. *
  34207. * @alias Clock
  34208. * @constructor
  34209. *
  34210. * @param {Object} [options] Object with the following properties:
  34211. * @param {JulianDate} [options.startTime] The start time of the clock.
  34212. * @param {JulianDate} [options.stopTime] The stop time of the clock.
  34213. * @param {JulianDate} [options.currentTime] The current time.
  34214. * @param {Number} [options.multiplier=1.0] Determines how much time advances when {@link Clock#tick} is called, negative values allow for advancing backwards.
  34215. * @param {ClockStep} [options.clockStep=ClockStep.SYSTEM_CLOCK_MULTIPLIER] Determines if calls to {@link Clock#tick} are frame dependent or system clock dependent.
  34216. * @param {ClockRange} [options.clockRange=ClockRange.UNBOUNDED] Determines how the clock should behave when {@link Clock#startTime} or {@link Clock#stopTime} is reached.
  34217. * @param {Boolean} [options.canAnimate=true] Indicates whether {@link Clock#tick} can advance time. This could be false if data is being buffered, for example. The clock will only tick when both {@link Clock#canAnimate} and {@link Clock#shouldAnimate} are true.
  34218. * @param {Boolean} [options.shouldAnimate=true] Indicates whether {@link Clock#tick} should attempt to advance time. The clock will only tick when both {@link Clock#canAnimate} and {@link Clock#shouldAnimate} are true.
  34219. *
  34220. * @exception {DeveloperError} startTime must come before stopTime.
  34221. *
  34222. *
  34223. * @example
  34224. * // Create a clock that loops on Christmas day 2013 and runs in real-time.
  34225. * var clock = new Cesium.Clock({
  34226. * startTime : Cesium.JulianDate.fromIso8601("2013-12-25"),
  34227. * currentTime : Cesium.JulianDate.fromIso8601("2013-12-25"),
  34228. * stopTime : Cesium.JulianDate.fromIso8601("2013-12-26"),
  34229. * clockRange : Cesium.ClockRange.LOOP_STOP,
  34230. * clockStep : Cesium.ClockStep.SYSTEM_CLOCK_MULTIPLIER
  34231. * });
  34232. *
  34233. * @see ClockStep
  34234. * @see ClockRange
  34235. * @see JulianDate
  34236. */
  34237. function Clock(options) {
  34238. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  34239. var currentTime = options.currentTime;
  34240. var startTime = options.startTime;
  34241. var stopTime = options.stopTime;
  34242. if (!defined(currentTime)) {
  34243. // if not specified, current time is the start time,
  34244. // or if that is not specified, 1 day before the stop time,
  34245. // or if that is not specified, then now.
  34246. if (defined(startTime)) {
  34247. currentTime = JulianDate.clone(startTime);
  34248. } else if (defined(stopTime)) {
  34249. currentTime = JulianDate.addDays(stopTime, -1.0, new JulianDate());
  34250. } else {
  34251. currentTime = JulianDate.now();
  34252. }
  34253. } else {
  34254. currentTime = JulianDate.clone(currentTime);
  34255. }
  34256. if (!defined(startTime)) {
  34257. // if not specified, start time is the current time
  34258. // (as determined above)
  34259. startTime = JulianDate.clone(currentTime);
  34260. } else {
  34261. startTime = JulianDate.clone(startTime);
  34262. }
  34263. if (!defined(stopTime)) {
  34264. // if not specified, stop time is 1 day after the start time
  34265. // (as determined above)
  34266. stopTime = JulianDate.addDays(startTime, 1.0, new JulianDate());
  34267. } else {
  34268. stopTime = JulianDate.clone(stopTime);
  34269. }
  34270. if (JulianDate.greaterThan(startTime, stopTime)) {
  34271. throw new DeveloperError('startTime must come before stopTime.');
  34272. }
  34273. /**
  34274. * The start time of the clock.
  34275. * @type {JulianDate}
  34276. */
  34277. this.startTime = startTime;
  34278. /**
  34279. * The stop time of the clock.
  34280. * @type {JulianDate}
  34281. */
  34282. this.stopTime = stopTime;
  34283. /**
  34284. * Determines how the clock should behave when
  34285. * {@link Clock#startTime} or {@link Clock#stopTime}
  34286. * is reached.
  34287. * @type {ClockRange}
  34288. * @default {@link ClockRange.UNBOUNDED}
  34289. */
  34290. this.clockRange = defaultValue(options.clockRange, ClockRange.UNBOUNDED);
  34291. /**
  34292. * Indicates whether {@link Clock#tick} can advance time. This could be false if data is being buffered,
  34293. * for example. The clock will only advance time when both
  34294. * {@link Clock#canAnimate} and {@link Clock#shouldAnimate} are true.
  34295. * @type {Boolean}
  34296. * @default true
  34297. */
  34298. this.canAnimate = defaultValue(options.canAnimate, true);
  34299. /**
  34300. * An {@link Event} that is fired whenever {@link Clock#tick} is called.
  34301. * @type {Event}
  34302. */
  34303. this.onTick = new Event();
  34304. this._currentTime = undefined;
  34305. this._multiplier = undefined;
  34306. this._clockStep = undefined;
  34307. this._shouldAnimate = undefined;
  34308. this._lastSystemTime = getTimestamp();
  34309. // set values using the property setters to
  34310. // make values consistent.
  34311. this.currentTime = currentTime;
  34312. this.multiplier = defaultValue(options.multiplier, 1.0);
  34313. this.clockStep = defaultValue(options.clockStep, ClockStep.SYSTEM_CLOCK_MULTIPLIER);
  34314. this.shouldAnimate = defaultValue(options.shouldAnimate, true);
  34315. }
  34316. defineProperties(Clock.prototype, {
  34317. /**
  34318. * The current time.
  34319. * Changing this property will change
  34320. * {@link Clock#clockStep} from {@link ClockStep.SYSTEM_CLOCK} to
  34321. * {@link ClockStep.SYSTEM_CLOCK_MULTIPLIER}.
  34322. * @memberof Clock.prototype
  34323. * @type {JulianDate}
  34324. */
  34325. currentTime : {
  34326. get : function() {
  34327. return this._currentTime;
  34328. },
  34329. set : function(value) {
  34330. if (JulianDate.equals(this._currentTime, value)) {
  34331. return;
  34332. }
  34333. if (this._clockStep === ClockStep.SYSTEM_CLOCK) {
  34334. this._clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER;
  34335. }
  34336. this._currentTime = value;
  34337. }
  34338. },
  34339. /**
  34340. * Gets or sets how much time advances when {@link Clock#tick} is called. Negative values allow for advancing backwards.
  34341. * If {@link Clock#clockStep} is set to {@link ClockStep.TICK_DEPENDENT}, this is the number of seconds to advance.
  34342. * If {@link Clock#clockStep} is set to {@link ClockStep.SYSTEM_CLOCK_MULTIPLIER}, this value is multiplied by the
  34343. * elapsed system time since the last call to {@link Clock#tick}.
  34344. * Changing this property will change
  34345. * {@link Clock#clockStep} from {@link ClockStep.SYSTEM_CLOCK} to
  34346. * {@link ClockStep.SYSTEM_CLOCK_MULTIPLIER}.
  34347. * @memberof Clock.prototype
  34348. * @type {Number}
  34349. * @default 1.0
  34350. */
  34351. multiplier : {
  34352. get : function() {
  34353. return this._multiplier;
  34354. },
  34355. set : function(value) {
  34356. if (this._multiplier === value) {
  34357. return;
  34358. }
  34359. if (this._clockStep === ClockStep.SYSTEM_CLOCK) {
  34360. this._clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER;
  34361. }
  34362. this._multiplier = value;
  34363. }
  34364. },
  34365. /**
  34366. * Determines if calls to {@link Clock#tick} are frame dependent or system clock dependent.
  34367. * Changing this property to {@link ClockStep.SYSTEM_CLOCK} will set
  34368. * {@link Clock#multiplier} to 1.0, {@link Clock#shouldAnimate} to true, and
  34369. * {@link Clock#currentTime} to the current system clock time.
  34370. * @memberof Clock.prototype
  34371. * @type ClockStep
  34372. * @default {@link ClockStep.SYSTEM_CLOCK_MULTIPLIER}
  34373. */
  34374. clockStep : {
  34375. get : function() {
  34376. return this._clockStep;
  34377. },
  34378. set : function(value) {
  34379. if (value === ClockStep.SYSTEM_CLOCK) {
  34380. this._multiplier = 1.0;
  34381. this._shouldAnimate = true;
  34382. this._currentTime = JulianDate.now();
  34383. }
  34384. this._clockStep = value;
  34385. }
  34386. },
  34387. /**
  34388. * Indicates whether {@link Clock#tick} should attempt to advance time.
  34389. * The clock will only advance time when both
  34390. * {@link Clock#canAnimate} and {@link Clock#shouldAnimate} are true.
  34391. * Changing this property will change
  34392. * {@link Clock#clockStep} from {@link ClockStep.SYSTEM_CLOCK} to
  34393. * {@link ClockStep.SYSTEM_CLOCK_MULTIPLIER}.
  34394. * @memberof Clock.prototype
  34395. * @type {Boolean}
  34396. * @default true
  34397. */
  34398. shouldAnimate : {
  34399. get : function() {
  34400. return this._shouldAnimate;
  34401. },
  34402. set : function(value) {
  34403. if (this._shouldAnimate === value) {
  34404. return;
  34405. }
  34406. if (this._clockStep === ClockStep.SYSTEM_CLOCK) {
  34407. this._clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER;
  34408. }
  34409. this._shouldAnimate = value;
  34410. }
  34411. }
  34412. });
  34413. /**
  34414. * Advances the clock from the current time based on the current configuration options.
  34415. * tick should be called every frame, regardless of whether animation is taking place
  34416. * or not. To control animation, use the {@link Clock#shouldAnimate} property.
  34417. *
  34418. * @returns {JulianDate} The new value of the {@link Clock#currentTime} property.
  34419. */
  34420. Clock.prototype.tick = function() {
  34421. var currentSystemTime = getTimestamp();
  34422. var currentTime = JulianDate.clone(this._currentTime);
  34423. if (this.canAnimate && this._shouldAnimate) {
  34424. var clockStep = this._clockStep;
  34425. if (clockStep === ClockStep.SYSTEM_CLOCK) {
  34426. currentTime = JulianDate.now(currentTime);
  34427. } else {
  34428. var multiplier = this._multiplier;
  34429. if (clockStep === ClockStep.TICK_DEPENDENT) {
  34430. currentTime = JulianDate.addSeconds(currentTime, multiplier, currentTime);
  34431. } else {
  34432. var milliseconds = currentSystemTime - this._lastSystemTime;
  34433. currentTime = JulianDate.addSeconds(currentTime, multiplier * (milliseconds / 1000.0), currentTime);
  34434. }
  34435. var clockRange = this.clockRange;
  34436. var startTime = this.startTime;
  34437. var stopTime = this.stopTime;
  34438. if (clockRange === ClockRange.CLAMPED) {
  34439. if (JulianDate.lessThan(currentTime, startTime)) {
  34440. currentTime = JulianDate.clone(startTime, currentTime);
  34441. } else if (JulianDate.greaterThan(currentTime, stopTime)) {
  34442. currentTime = JulianDate.clone(stopTime, currentTime);
  34443. }
  34444. } else if (clockRange === ClockRange.LOOP_STOP) {
  34445. if (JulianDate.lessThan(currentTime, startTime)) {
  34446. currentTime = JulianDate.clone(startTime, currentTime);
  34447. }
  34448. while (JulianDate.greaterThan(currentTime, stopTime)) {
  34449. currentTime = JulianDate.addSeconds(startTime, JulianDate.secondsDifference(currentTime, stopTime), currentTime);
  34450. }
  34451. }
  34452. }
  34453. }
  34454. this._currentTime = currentTime;
  34455. this._lastSystemTime = currentSystemTime;
  34456. this.onTick.raiseEvent(this);
  34457. return currentTime;
  34458. };
  34459. return Clock;
  34460. });
  34461. /*global define*/
  34462. define('Core/Color',[
  34463. './defaultValue',
  34464. './defined',
  34465. './DeveloperError',
  34466. './FeatureDetection',
  34467. './freezeObject',
  34468. './Math'
  34469. ], function(
  34470. defaultValue,
  34471. defined,
  34472. DeveloperError,
  34473. FeatureDetection,
  34474. freezeObject,
  34475. CesiumMath) {
  34476. 'use strict';
  34477. function hue2rgb(m1, m2, h) {
  34478. if (h < 0) {
  34479. h += 1;
  34480. }
  34481. if (h > 1) {
  34482. h -= 1;
  34483. }
  34484. if (h * 6 < 1) {
  34485. return m1 + (m2 - m1) * 6 * h;
  34486. }
  34487. if (h * 2 < 1) {
  34488. return m2;
  34489. }
  34490. if (h * 3 < 2) {
  34491. return m1 + (m2 - m1) * (2 / 3 - h) * 6;
  34492. }
  34493. return m1;
  34494. }
  34495. /**
  34496. * A color, specified using red, green, blue, and alpha values,
  34497. * which range from <code>0</code> (no intensity) to <code>1.0</code> (full intensity).
  34498. * @param {Number} [red=1.0] The red component.
  34499. * @param {Number} [green=1.0] The green component.
  34500. * @param {Number} [blue=1.0] The blue component.
  34501. * @param {Number} [alpha=1.0] The alpha component.
  34502. *
  34503. * @constructor
  34504. * @alias Color
  34505. *
  34506. * @see Packable
  34507. */
  34508. function Color(red, green, blue, alpha) {
  34509. /**
  34510. * The red component.
  34511. * @type {Number}
  34512. * @default 1.0
  34513. */
  34514. this.red = defaultValue(red, 1.0);
  34515. /**
  34516. * The green component.
  34517. * @type {Number}
  34518. * @default 1.0
  34519. */
  34520. this.green = defaultValue(green, 1.0);
  34521. /**
  34522. * The blue component.
  34523. * @type {Number}
  34524. * @default 1.0
  34525. */
  34526. this.blue = defaultValue(blue, 1.0);
  34527. /**
  34528. * The alpha component.
  34529. * @type {Number}
  34530. * @default 1.0
  34531. */
  34532. this.alpha = defaultValue(alpha, 1.0);
  34533. }
  34534. /**
  34535. * Creates a Color instance from a {@link Cartesian4}. <code>x</code>, <code>y</code>, <code>z</code>,
  34536. * and <code>w</code> map to <code>red</code>, <code>green</code>, <code>blue</code>, and <code>alpha</code>, respectively.
  34537. *
  34538. * @param {Cartesian4} cartesian The source cartesian.
  34539. * @param {Color} [result] The object onto which to store the result.
  34540. * @returns {Color} The modified result parameter or a new Color instance if one was not provided.
  34541. */
  34542. Color.fromCartesian4 = function(cartesian, result) {
  34543. if (!defined(cartesian)) {
  34544. throw new DeveloperError('cartesian is required');
  34545. }
  34546. if (!defined(result)) {
  34547. return new Color(cartesian.x, cartesian.y, cartesian.z, cartesian.w);
  34548. }
  34549. result.red = cartesian.x;
  34550. result.green = cartesian.y;
  34551. result.blue = cartesian.z;
  34552. result.alpha = cartesian.w;
  34553. return result;
  34554. };
  34555. /**
  34556. * Creates a new Color specified using red, green, blue, and alpha values
  34557. * that are in the range of 0 to 255, converting them internally to a range of 0.0 to 1.0.
  34558. *
  34559. * @param {Number} [red=255] The red component.
  34560. * @param {Number} [green=255] The green component.
  34561. * @param {Number} [blue=255] The blue component.
  34562. * @param {Number} [alpha=255] The alpha component.
  34563. * @param {Color} [result] The object onto which to store the result.
  34564. * @returns {Color} The modified result parameter or a new Color instance if one was not provided.
  34565. */
  34566. Color.fromBytes = function(red, green, blue, alpha, result) {
  34567. red = Color.byteToFloat(defaultValue(red, 255.0));
  34568. green = Color.byteToFloat(defaultValue(green, 255.0));
  34569. blue = Color.byteToFloat(defaultValue(blue, 255.0));
  34570. alpha = Color.byteToFloat(defaultValue(alpha, 255.0));
  34571. if (!defined(result)) {
  34572. return new Color(red, green, blue, alpha);
  34573. }
  34574. result.red = red;
  34575. result.green = green;
  34576. result.blue = blue;
  34577. result.alpha = alpha;
  34578. return result;
  34579. };
  34580. /**
  34581. * Creates a new Color that has the same red, green, and blue components
  34582. * of the specified color, but with the specified alpha value.
  34583. *
  34584. * @param {Color} color The base color
  34585. * @param {Number} alpha The new alpha component.
  34586. * @param {Color} [result] The object onto which to store the result.
  34587. * @returns {Color} The modified result parameter or a new Color instance if one was not provided.
  34588. *
  34589. * @example var translucentRed = Cesium.Color.fromAlpha(Cesium.Color.RED, 0.9);
  34590. */
  34591. Color.fromAlpha = function(color, alpha, result) {
  34592. if (!defined(color)) {
  34593. throw new DeveloperError('color is required');
  34594. }
  34595. if (!defined(alpha)) {
  34596. throw new DeveloperError('alpha is required');
  34597. }
  34598. if (!defined(result)) {
  34599. return new Color(color.red, color.green, color.blue, alpha);
  34600. }
  34601. result.red = color.red;
  34602. result.green = color.green;
  34603. result.blue = color.blue;
  34604. result.alpha = alpha;
  34605. return result;
  34606. };
  34607. var scratchArrayBuffer;
  34608. var scratchUint32Array;
  34609. var scratchUint8Array;
  34610. if (FeatureDetection.supportsTypedArrays()) {
  34611. scratchArrayBuffer = new ArrayBuffer(4);
  34612. scratchUint32Array = new Uint32Array(scratchArrayBuffer);
  34613. scratchUint8Array = new Uint8Array(scratchArrayBuffer);
  34614. }
  34615. /**
  34616. * Creates a new Color from a single numeric unsigned 32-bit RGBA value, using the endianness
  34617. * of the system.
  34618. *
  34619. * @param {Number} rgba A single numeric unsigned 32-bit RGBA value.
  34620. * @param {Color} [result] The object to store the result in, if undefined a new instance will be created.
  34621. * @returns {Color} The color object.
  34622. *
  34623. * @example
  34624. * var color = Cesium.Color.fromRgba(0x67ADDFFF);
  34625. *
  34626. * @see Color#toRgba
  34627. */
  34628. Color.fromRgba = function(rgba, result) {
  34629. // scratchUint32Array and scratchUint8Array share an underlying array buffer
  34630. scratchUint32Array[0] = rgba;
  34631. return Color.fromBytes(scratchUint8Array[0], scratchUint8Array[1], scratchUint8Array[2], scratchUint8Array[3], result);
  34632. };
  34633. /**
  34634. * Creates a Color instance from hue, saturation, and lightness.
  34635. *
  34636. * @param {Number} [hue=0] The hue angle 0...1
  34637. * @param {Number} [saturation=0] The saturation value 0...1
  34638. * @param {Number} [lightness=0] The lightness value 0...1
  34639. * @param {Number} [alpha=1.0] The alpha component 0...1
  34640. * @param {Color} [result] The object to store the result in, if undefined a new instance will be created.
  34641. * @returns {Color} The color object.
  34642. *
  34643. * @see {@link http://www.w3.org/TR/css3-color/#hsl-color|CSS color values}
  34644. */
  34645. Color.fromHsl = function(hue, saturation, lightness, alpha, result) {
  34646. hue = defaultValue(hue, 0.0) % 1.0;
  34647. saturation = defaultValue(saturation, 0.0);
  34648. lightness = defaultValue(lightness, 0.0);
  34649. alpha = defaultValue(alpha, 1.0);
  34650. var red = lightness;
  34651. var green = lightness;
  34652. var blue = lightness;
  34653. if (saturation !== 0) {
  34654. var m2;
  34655. if (lightness < 0.5) {
  34656. m2 = lightness * (1 + saturation);
  34657. } else {
  34658. m2 = lightness + saturation - lightness * saturation;
  34659. }
  34660. var m1 = 2.0 * lightness - m2;
  34661. red = hue2rgb(m1, m2, hue + 1 / 3);
  34662. green = hue2rgb(m1, m2, hue);
  34663. blue = hue2rgb(m1, m2, hue - 1 / 3);
  34664. }
  34665. if (!defined(result)) {
  34666. return new Color(red, green, blue, alpha);
  34667. }
  34668. result.red = red;
  34669. result.green = green;
  34670. result.blue = blue;
  34671. result.alpha = alpha;
  34672. return result;
  34673. };
  34674. /**
  34675. * Creates a random color using the provided options. For reproducible random colors, you should
  34676. * call {@link CesiumMath#setRandomNumberSeed} once at the beginning of your application.
  34677. *
  34678. * @param {Object} [options] Object with the following properties:
  34679. * @param {Number} [options.red] If specified, the red component to use instead of a randomized value.
  34680. * @param {Number} [options.minimumRed=0.0] The maximum red value to generate if none was specified.
  34681. * @param {Number} [options.maximumRed=1.0] The minimum red value to generate if none was specified.
  34682. * @param {Number} [options.green] If specified, the green component to use instead of a randomized value.
  34683. * @param {Number} [options.minimumGreen=0.0] The maximum green value to generate if none was specified.
  34684. * @param {Number} [options.maximumGreen=1.0] The minimum green value to generate if none was specified.
  34685. * @param {Number} [options.blue] If specified, the blue component to use instead of a randomized value.
  34686. * @param {Number} [options.minimumBlue=0.0] The maximum blue value to generate if none was specified.
  34687. * @param {Number} [options.maximumBlue=1.0] The minimum blue value to generate if none was specified.
  34688. * @param {Number} [options.alpha] If specified, the alpha component to use instead of a randomized value.
  34689. * @param {Number} [options.minimumAlpha=0.0] The maximum alpha value to generate if none was specified.
  34690. * @param {Number} [options.maximumAlpha=1.0] The minimum alpha value to generate if none was specified.
  34691. * @param {Color} [result] The object to store the result in, if undefined a new instance will be created.
  34692. * @returns {Color} The modified result parameter or a new instance if result was undefined.
  34693. *
  34694. * @exception {DeveloperError} minimumRed must be less than or equal to maximumRed.
  34695. * @exception {DeveloperError} minimumGreen must be less than or equal to maximumGreen.
  34696. * @exception {DeveloperError} minimumBlue must be less than or equal to maximumBlue.
  34697. * @exception {DeveloperError} minimumAlpha must be less than or equal to maximumAlpha.
  34698. *
  34699. * @example
  34700. * //Create a completely random color
  34701. * var color = Cesium.Color.fromRandom();
  34702. *
  34703. * //Create a random shade of yellow.
  34704. * var color = Cesium.Color.fromRandom({
  34705. * red : 1.0,
  34706. * green : 1.0,
  34707. * alpha : 1.0
  34708. * });
  34709. *
  34710. * //Create a random bright color.
  34711. * var color = Cesium.Color.fromRandom({
  34712. * minimumRed : 0.75,
  34713. * minimumGreen : 0.75,
  34714. * minimumBlue : 0.75,
  34715. * alpha : 1.0
  34716. * });
  34717. */
  34718. Color.fromRandom = function(options, result) {
  34719. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  34720. var red = options.red;
  34721. if (!defined(red)) {
  34722. var minimumRed = defaultValue(options.minimumRed, 0);
  34723. var maximumRed = defaultValue(options.maximumRed, 1.0);
  34724. if (minimumRed > maximumRed) {
  34725. throw new DeveloperError("minimumRed must be less than or equal to maximumRed");
  34726. }
  34727. red = minimumRed + (CesiumMath.nextRandomNumber() * (maximumRed - minimumRed));
  34728. }
  34729. var green = options.green;
  34730. if (!defined(green)) {
  34731. var minimumGreen = defaultValue(options.minimumGreen, 0);
  34732. var maximumGreen = defaultValue(options.maximumGreen, 1.0);
  34733. if (minimumGreen > maximumGreen) {
  34734. throw new DeveloperError("minimumGreen must be less than or equal to maximumGreen");
  34735. }
  34736. green = minimumGreen + (CesiumMath.nextRandomNumber() * (maximumGreen - minimumGreen));
  34737. }
  34738. var blue = options.blue;
  34739. if (!defined(blue)) {
  34740. var minimumBlue = defaultValue(options.minimumBlue, 0);
  34741. var maximumBlue = defaultValue(options.maximumBlue, 1.0);
  34742. if (minimumBlue > maximumBlue) {
  34743. throw new DeveloperError("minimumBlue must be less than or equal to maximumBlue");
  34744. }
  34745. blue = minimumBlue + (CesiumMath.nextRandomNumber() * (maximumBlue - minimumBlue));
  34746. }
  34747. var alpha = options.alpha;
  34748. if (!defined(alpha)) {
  34749. var minimumAlpha = defaultValue(options.minimumAlpha, 0);
  34750. var maximumAlpha = defaultValue(options.maximumAlpha, 1.0);
  34751. if (minimumAlpha > maximumAlpha) {
  34752. throw new DeveloperError("minimumAlpha must be less than or equal to maximumAlpha");
  34753. }
  34754. alpha = minimumAlpha + (CesiumMath.nextRandomNumber() * (maximumAlpha - minimumAlpha));
  34755. }
  34756. if (!defined(result)) {
  34757. return new Color(red, green, blue, alpha);
  34758. }
  34759. result.red = red;
  34760. result.green = green;
  34761. result.blue = blue;
  34762. result.alpha = alpha;
  34763. return result;
  34764. };
  34765. //#rgb
  34766. var rgbMatcher = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i;
  34767. //#rrggbb
  34768. var rrggbbMatcher = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i;
  34769. //rgb(), rgba(), or rgb%()
  34770. var rgbParenthesesMatcher = /^rgba?\(\s*([0-9.]+%?)\s*,\s*([0-9.]+%?)\s*,\s*([0-9.]+%?)(?:\s*,\s*([0-9.]+))?\s*\)$/i;
  34771. //hsl(), hsla(), or hsl%()
  34772. var hslParenthesesMatcher = /^hsla?\(\s*([0-9.]+)\s*,\s*([0-9.]+%)\s*,\s*([0-9.]+%)(?:\s*,\s*([0-9.]+))?\s*\)$/i;
  34773. /**
  34774. * Creates a Color instance from a CSS color value.
  34775. *
  34776. * @param {String} color The CSS color value in #rgb, #rrggbb, rgb(), rgba(), hsl(), or hsla() format.
  34777. * @param {Color} [result] The object to store the result in, if undefined a new instance will be created.
  34778. * @returns {Color} The color object, or undefined if the string was not a valid CSS color.
  34779. *
  34780. *
  34781. * @example
  34782. * var cesiumBlue = Cesium.Color.fromCssColorString('#67ADDF');
  34783. * var green = Cesium.Color.fromCssColorString('green');
  34784. *
  34785. * @see {@link http://www.w3.org/TR/css3-color|CSS color values}
  34786. */
  34787. Color.fromCssColorString = function(color, result) {
  34788. if (!defined(color)) {
  34789. throw new DeveloperError('color is required');
  34790. }
  34791. if (!defined(result)) {
  34792. result = new Color();
  34793. }
  34794. var namedColor = Color[color.toUpperCase()];
  34795. if (defined(namedColor)) {
  34796. Color.clone(namedColor, result);
  34797. return result;
  34798. }
  34799. var matches = rgbMatcher.exec(color);
  34800. if (matches !== null) {
  34801. result.red = parseInt(matches[1], 16) / 15;
  34802. result.green = parseInt(matches[2], 16) / 15.0;
  34803. result.blue = parseInt(matches[3], 16) / 15.0;
  34804. result.alpha = 1.0;
  34805. return result;
  34806. }
  34807. matches = rrggbbMatcher.exec(color);
  34808. if (matches !== null) {
  34809. result.red = parseInt(matches[1], 16) / 255.0;
  34810. result.green = parseInt(matches[2], 16) / 255.0;
  34811. result.blue = parseInt(matches[3], 16) / 255.0;
  34812. result.alpha = 1.0;
  34813. return result;
  34814. }
  34815. matches = rgbParenthesesMatcher.exec(color);
  34816. if (matches !== null) {
  34817. result.red = parseFloat(matches[1]) / ('%' === matches[1].substr(-1) ? 100.0 : 255.0);
  34818. result.green = parseFloat(matches[2]) / ('%' === matches[2].substr(-1) ? 100.0 : 255.0);
  34819. result.blue = parseFloat(matches[3]) / ('%' === matches[3].substr(-1) ? 100.0 : 255.0);
  34820. result.alpha = parseFloat(defaultValue(matches[4], '1.0'));
  34821. return result;
  34822. }
  34823. matches = hslParenthesesMatcher.exec(color);
  34824. if (matches !== null) {
  34825. return Color.fromHsl(parseFloat(matches[1]) / 360.0,
  34826. parseFloat(matches[2]) / 100.0,
  34827. parseFloat(matches[3]) / 100.0,
  34828. parseFloat(defaultValue(matches[4], '1.0')), result);
  34829. }
  34830. result = undefined;
  34831. return result;
  34832. };
  34833. /**
  34834. * The number of elements used to pack the object into an array.
  34835. * @type {Number}
  34836. */
  34837. Color.packedLength = 4;
  34838. /**
  34839. * Stores the provided instance into the provided array.
  34840. *
  34841. * @param {Color} value The value to pack.
  34842. * @param {Number[]} array The array to pack into.
  34843. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  34844. *
  34845. * @returns {Number[]} The array that was packed into
  34846. */
  34847. Color.pack = function(value, array, startingIndex) {
  34848. if (!defined(value)) {
  34849. throw new DeveloperError('value is required');
  34850. }
  34851. if (!defined(array)) {
  34852. throw new DeveloperError('array is required');
  34853. }
  34854. startingIndex = defaultValue(startingIndex, 0);
  34855. array[startingIndex++] = value.red;
  34856. array[startingIndex++] = value.green;
  34857. array[startingIndex++] = value.blue;
  34858. array[startingIndex] = value.alpha;
  34859. return array;
  34860. };
  34861. /**
  34862. * Retrieves an instance from a packed array.
  34863. *
  34864. * @param {Number[]} array The packed array.
  34865. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  34866. * @param {Color} [result] The object into which to store the result.
  34867. * @returns {Color} The modified result parameter or a new Color instance if one was not provided.
  34868. */
  34869. Color.unpack = function(array, startingIndex, result) {
  34870. if (!defined(array)) {
  34871. throw new DeveloperError('array is required');
  34872. }
  34873. startingIndex = defaultValue(startingIndex, 0);
  34874. if (!defined(result)) {
  34875. result = new Color();
  34876. }
  34877. result.red = array[startingIndex++];
  34878. result.green = array[startingIndex++];
  34879. result.blue = array[startingIndex++];
  34880. result.alpha = array[startingIndex];
  34881. return result;
  34882. };
  34883. /**
  34884. * Converts a 'byte' color component in the range of 0 to 255 into
  34885. * a 'float' color component in the range of 0 to 1.0.
  34886. *
  34887. * @param {Number} number The number to be converted.
  34888. * @returns {Number} The converted number.
  34889. */
  34890. Color.byteToFloat = function(number) {
  34891. return number / 255.0;
  34892. };
  34893. /**
  34894. * Converts a 'float' color component in the range of 0 to 1.0 into
  34895. * a 'byte' color component in the range of 0 to 255.
  34896. *
  34897. * @param {Number} number The number to be converted.
  34898. * @returns {Number} The converted number.
  34899. */
  34900. Color.floatToByte = function(number) {
  34901. return number === 1.0 ? 255.0 : (number * 256.0) | 0;
  34902. };
  34903. /**
  34904. * Duplicates a Color.
  34905. *
  34906. * @param {Color} color The Color to duplicate.
  34907. * @param {Color} [result] The object to store the result in, if undefined a new instance will be created.
  34908. * @returns {Color} The modified result parameter or a new instance if result was undefined. (Returns undefined if color is undefined)
  34909. */
  34910. Color.clone = function(color, result) {
  34911. if (!defined(color)) {
  34912. return undefined;
  34913. }
  34914. if (!defined(result)) {
  34915. return new Color(color.red, color.green, color.blue, color.alpha);
  34916. }
  34917. result.red = color.red;
  34918. result.green = color.green;
  34919. result.blue = color.blue;
  34920. result.alpha = color.alpha;
  34921. return result;
  34922. };
  34923. /**
  34924. * Returns true if the first Color equals the second color.
  34925. *
  34926. * @param {Color} left The first Color to compare for equality.
  34927. * @param {Color} right The second Color to compare for equality.
  34928. * @returns {Boolean} <code>true</code> if the Colors are equal; otherwise, <code>false</code>.
  34929. */
  34930. Color.equals = function(left, right) {
  34931. return (left === right) || //
  34932. (defined(left) && //
  34933. defined(right) && //
  34934. left.red === right.red && //
  34935. left.green === right.green && //
  34936. left.blue === right.blue && //
  34937. left.alpha === right.alpha);
  34938. };
  34939. /**
  34940. * @private
  34941. */
  34942. Color.equalsArray = function(color, array, offset) {
  34943. return color.red === array[offset] &&
  34944. color.green === array[offset + 1] &&
  34945. color.blue === array[offset + 2] &&
  34946. color.alpha === array[offset + 3];
  34947. };
  34948. /**
  34949. * Returns a duplicate of a Color instance.
  34950. *
  34951. * @param {Color} [result] The object to store the result in, if undefined a new instance will be created.
  34952. * @returns {Color} The modified result parameter or a new instance if result was undefined.
  34953. */
  34954. Color.prototype.clone = function(result) {
  34955. return Color.clone(this, result);
  34956. };
  34957. /**
  34958. * Returns true if this Color equals other.
  34959. *
  34960. * @param {Color} other The Color to compare for equality.
  34961. * @returns {Boolean} <code>true</code> if the Colors are equal; otherwise, <code>false</code>.
  34962. */
  34963. Color.prototype.equals = function(other) {
  34964. return Color.equals(this, other);
  34965. };
  34966. /**
  34967. * Returns <code>true</code> if this Color equals other componentwise within the specified epsilon.
  34968. *
  34969. * @param {Color} other The Color to compare for equality.
  34970. * @param {Number} [epsilon=0.0] The epsilon to use for equality testing.
  34971. * @returns {Boolean} <code>true</code> if the Colors are equal within the specified epsilon; otherwise, <code>false</code>.
  34972. */
  34973. Color.prototype.equalsEpsilon = function(other, epsilon) {
  34974. return (this === other) || //
  34975. ((defined(other)) && //
  34976. (Math.abs(this.red - other.red) <= epsilon) && //
  34977. (Math.abs(this.green - other.green) <= epsilon) && //
  34978. (Math.abs(this.blue - other.blue) <= epsilon) && //
  34979. (Math.abs(this.alpha - other.alpha) <= epsilon));
  34980. };
  34981. /**
  34982. * Creates a string representing this Color in the format '(red, green, blue, alpha)'.
  34983. *
  34984. * @returns {String} A string representing this Color in the format '(red, green, blue, alpha)'.
  34985. */
  34986. Color.prototype.toString = function() {
  34987. return '(' + this.red + ', ' + this.green + ', ' + this.blue + ', ' + this.alpha + ')';
  34988. };
  34989. /**
  34990. * Creates a string containing the CSS color value for this color.
  34991. *
  34992. * @returns {String} The CSS equivalent of this color.
  34993. *
  34994. * @see {@link http://www.w3.org/TR/css3-color/#rgba-color|CSS RGB or RGBA color values}
  34995. */
  34996. Color.prototype.toCssColorString = function() {
  34997. var red = Color.floatToByte(this.red);
  34998. var green = Color.floatToByte(this.green);
  34999. var blue = Color.floatToByte(this.blue);
  35000. if (this.alpha === 1) {
  35001. return 'rgb(' + red + ',' + green + ',' + blue + ')';
  35002. }
  35003. return 'rgba(' + red + ',' + green + ',' + blue + ',' + this.alpha + ')';
  35004. };
  35005. /**
  35006. * Converts this color to an array of red, green, blue, and alpha values
  35007. * that are in the range of 0 to 255.
  35008. *
  35009. * @param {Number[]} [result] The array to store the result in, if undefined a new instance will be created.
  35010. * @returns {Number[]} The modified result parameter or a new instance if result was undefined.
  35011. */
  35012. Color.prototype.toBytes = function(result) {
  35013. var red = Color.floatToByte(this.red);
  35014. var green = Color.floatToByte(this.green);
  35015. var blue = Color.floatToByte(this.blue);
  35016. var alpha = Color.floatToByte(this.alpha);
  35017. if (!defined(result)) {
  35018. return [red, green, blue, alpha];
  35019. }
  35020. result[0] = red;
  35021. result[1] = green;
  35022. result[2] = blue;
  35023. result[3] = alpha;
  35024. return result;
  35025. };
  35026. /**
  35027. * Converts this color to a single numeric unsigned 32-bit RGBA value, using the endianness
  35028. * of the system.
  35029. *
  35030. * @returns {Number} A single numeric unsigned 32-bit RGBA value.
  35031. *
  35032. *
  35033. * @example
  35034. * var rgba = Cesium.Color.BLUE.toRgba();
  35035. *
  35036. * @see Color.fromRgba
  35037. */
  35038. Color.prototype.toRgba = function() {
  35039. // scratchUint32Array and scratchUint8Array share an underlying array buffer
  35040. scratchUint8Array[0] = Color.floatToByte(this.red);
  35041. scratchUint8Array[1] = Color.floatToByte(this.green);
  35042. scratchUint8Array[2] = Color.floatToByte(this.blue);
  35043. scratchUint8Array[3] = Color.floatToByte(this.alpha);
  35044. return scratchUint32Array[0];
  35045. };
  35046. /**
  35047. * Brightens this color by the provided magnitude.
  35048. *
  35049. * @param {Number} magnitude A positive number indicating the amount to brighten.
  35050. * @param {Color} result The object onto which to store the result.
  35051. * @returns {Color} The modified result parameter.
  35052. *
  35053. * @example
  35054. * var brightBlue = Cesium.Color.BLUE.brighten(0.5, new Cesium.Color());
  35055. */
  35056. Color.prototype.brighten = function(magnitude, result) {
  35057. if (!defined(magnitude)) {
  35058. throw new DeveloperError('magnitude is required.');
  35059. }
  35060. if (magnitude < 0.0) {
  35061. throw new DeveloperError('magnitude must be positive.');
  35062. }
  35063. if (!defined(result)) {
  35064. throw new DeveloperError('result is required.');
  35065. }
  35066. magnitude = (1.0 - magnitude);
  35067. result.red = 1.0 - ((1.0 - this.red) * magnitude);
  35068. result.green = 1.0 - ((1.0 - this.green) * magnitude);
  35069. result.blue = 1.0 - ((1.0 - this.blue) * magnitude);
  35070. result.alpha = this.alpha;
  35071. return result;
  35072. };
  35073. /**
  35074. * Darkens this color by the provided magnitude.
  35075. *
  35076. * @param {Number} magnitude A positive number indicating the amount to darken.
  35077. * @param {Color} result The object onto which to store the result.
  35078. * @returns {Color} The modified result parameter.
  35079. *
  35080. * @example
  35081. * var darkBlue = Cesium.Color.BLUE.darken(0.5, new Cesium.Color());
  35082. */
  35083. Color.prototype.darken = function(magnitude, result) {
  35084. if (!defined(magnitude)) {
  35085. throw new DeveloperError('magnitude is required.');
  35086. }
  35087. if (magnitude < 0.0) {
  35088. throw new DeveloperError('magnitude must be positive.');
  35089. }
  35090. if (!defined(result)) {
  35091. throw new DeveloperError('result is required.');
  35092. }
  35093. magnitude = (1.0 - magnitude);
  35094. result.red = this.red * magnitude;
  35095. result.green = this.green * magnitude;
  35096. result.blue = this.blue * magnitude;
  35097. result.alpha = this.alpha;
  35098. return result;
  35099. };
  35100. /**
  35101. * Creates a new Color that has the same red, green, and blue components
  35102. * as this Color, but with the specified alpha value.
  35103. *
  35104. * @param {Number} alpha The new alpha component.
  35105. * @param {Color} [result] The object onto which to store the result.
  35106. * @returns {Color} The modified result parameter or a new Color instance if one was not provided.
  35107. *
  35108. * @example var translucentRed = Cesium.Color.RED.withAlpha(0.9);
  35109. */
  35110. Color.prototype.withAlpha = function(alpha, result) {
  35111. return Color.fromAlpha(this, alpha, result);
  35112. };
  35113. /**
  35114. * Computes the componentwise sum of two Colors.
  35115. *
  35116. * @param {Color} left The first Color.
  35117. * @param {Color} right The second Color.
  35118. * @param {Color} result The object onto which to store the result.
  35119. * @returns {Color} The modified result parameter.
  35120. */
  35121. Color.add = function(left, right, result) {
  35122. if (!defined(left)) {
  35123. throw new DeveloperError('left is required');
  35124. }
  35125. if (!defined(right)) {
  35126. throw new DeveloperError('right is required');
  35127. }
  35128. if (!defined(result)) {
  35129. throw new DeveloperError('result is required');
  35130. }
  35131. result.red = left.red + right.red;
  35132. result.green = left.green + right.green;
  35133. result.blue = left.blue + right.blue;
  35134. result.alpha = left.alpha + right.alpha;
  35135. return result;
  35136. };
  35137. /**
  35138. * Computes the componentwise difference of two Colors.
  35139. *
  35140. * @param {Color} left The first Color.
  35141. * @param {Color} right The second Color.
  35142. * @param {Color} result The object onto which to store the result.
  35143. * @returns {Color} The modified result parameter.
  35144. */
  35145. Color.subtract = function(left, right, result) {
  35146. if (!defined(left)) {
  35147. throw new DeveloperError('left is required');
  35148. }
  35149. if (!defined(right)) {
  35150. throw new DeveloperError('right is required');
  35151. }
  35152. if (!defined(result)) {
  35153. throw new DeveloperError('result is required');
  35154. }
  35155. result.red = left.red - right.red;
  35156. result.green = left.green - right.green;
  35157. result.blue = left.blue - right.blue;
  35158. result.alpha = left.alpha - right.alpha;
  35159. return result;
  35160. };
  35161. /**
  35162. * Computes the componentwise product of two Colors.
  35163. *
  35164. * @param {Color} left The first Color.
  35165. * @param {Color} right The second Color.
  35166. * @param {Color} result The object onto which to store the result.
  35167. * @returns {Color} The modified result parameter.
  35168. */
  35169. Color.multiply = function(left, right, result) {
  35170. if (!defined(left)) {
  35171. throw new DeveloperError('left is required');
  35172. }
  35173. if (!defined(right)) {
  35174. throw new DeveloperError('right is required');
  35175. }
  35176. if (!defined(result)) {
  35177. throw new DeveloperError('result is required');
  35178. }
  35179. result.red = left.red * right.red;
  35180. result.green = left.green * right.green;
  35181. result.blue = left.blue * right.blue;
  35182. result.alpha = left.alpha * right.alpha;
  35183. return result;
  35184. };
  35185. /**
  35186. * Computes the componentwise quotient of two Colors.
  35187. *
  35188. * @param {Color} left The first Color.
  35189. * @param {Color} right The second Color.
  35190. * @param {Color} result The object onto which to store the result.
  35191. * @returns {Color} The modified result parameter.
  35192. */
  35193. Color.divide = function(left, right, result) {
  35194. if (!defined(left)) {
  35195. throw new DeveloperError('left is required');
  35196. }
  35197. if (!defined(right)) {
  35198. throw new DeveloperError('right is required');
  35199. }
  35200. if (!defined(result)) {
  35201. throw new DeveloperError('result is required');
  35202. }
  35203. result.red = left.red / right.red;
  35204. result.green = left.green / right.green;
  35205. result.blue = left.blue / right.blue;
  35206. result.alpha = left.alpha / right.alpha;
  35207. return result;
  35208. };
  35209. /**
  35210. * Computes the componentwise modulus of two Colors.
  35211. *
  35212. * @param {Color} left The first Color.
  35213. * @param {Color} right The second Color.
  35214. * @param {Color} result The object onto which to store the result.
  35215. * @returns {Color} The modified result parameter.
  35216. */
  35217. Color.mod = function(left, right, result) {
  35218. if (!defined(left)) {
  35219. throw new DeveloperError('left is required');
  35220. }
  35221. if (!defined(right)) {
  35222. throw new DeveloperError('right is required');
  35223. }
  35224. if (!defined(result)) {
  35225. throw new DeveloperError('result is required');
  35226. }
  35227. result.red = left.red % right.red;
  35228. result.green = left.green % right.green;
  35229. result.blue = left.blue % right.blue;
  35230. result.alpha = left.alpha % right.alpha;
  35231. return result;
  35232. };
  35233. /**
  35234. * Multiplies the provided Color componentwise by the provided scalar.
  35235. *
  35236. * @param {Color} color The Color to be scaled.
  35237. * @param {Number} scalar The scalar to multiply with.
  35238. * @param {Color} result The object onto which to store the result.
  35239. * @returns {Color} The modified result parameter.
  35240. */
  35241. Color.multiplyByScalar = function(color, scalar, result) {
  35242. if (!defined(color)) {
  35243. throw new DeveloperError('cartesian is required');
  35244. }
  35245. if (typeof scalar !== 'number') {
  35246. throw new DeveloperError('scalar is required and must be a number.');
  35247. }
  35248. if (!defined(result)) {
  35249. throw new DeveloperError('result is required');
  35250. }
  35251. result.red = color.red * scalar;
  35252. result.green = color.green * scalar;
  35253. result.blue = color.blue * scalar;
  35254. result.alpha = color.alpha * scalar;
  35255. return result;
  35256. };
  35257. /**
  35258. * Divides the provided Color componentwise by the provided scalar.
  35259. *
  35260. * @param {Color} color The Color to be divided.
  35261. * @param {Number} scalar The scalar to divide with.
  35262. * @param {Color} result The object onto which to store the result.
  35263. * @returns {Color} The modified result parameter.
  35264. */
  35265. Color.divideByScalar = function(color, scalar, result) {
  35266. if (!defined(color)) {
  35267. throw new DeveloperError('cartesian is required');
  35268. }
  35269. if (typeof scalar !== 'number') {
  35270. throw new DeveloperError('scalar is required and must be a number.');
  35271. }
  35272. if (!defined(result)) {
  35273. throw new DeveloperError('result is required');
  35274. }
  35275. result.red = color.red / scalar;
  35276. result.green = color.green / scalar;
  35277. result.blue = color.blue / scalar;
  35278. result.alpha = color.alpha / scalar;
  35279. return result;
  35280. };
  35281. /**
  35282. * An immutable Color instance initialized to CSS color #F0F8FF
  35283. * <span class="colorSwath" style="background: #F0F8FF;"></span>
  35284. *
  35285. * @constant
  35286. * @type {Color}
  35287. */
  35288. Color.ALICEBLUE = freezeObject(Color.fromCssColorString('#F0F8FF'));
  35289. /**
  35290. * An immutable Color instance initialized to CSS color #FAEBD7
  35291. * <span class="colorSwath" style="background: #FAEBD7;"></span>
  35292. *
  35293. * @constant
  35294. * @type {Color}
  35295. */
  35296. Color.ANTIQUEWHITE = freezeObject(Color.fromCssColorString('#FAEBD7'));
  35297. /**
  35298. * An immutable Color instance initialized to CSS color #00FFFF
  35299. * <span class="colorSwath" style="background: #00FFFF;"></span>
  35300. *
  35301. * @constant
  35302. * @type {Color}
  35303. */
  35304. Color.AQUA = freezeObject(Color.fromCssColorString('#00FFFF'));
  35305. /**
  35306. * An immutable Color instance initialized to CSS color #7FFFD4
  35307. * <span class="colorSwath" style="background: #7FFFD4;"></span>
  35308. *
  35309. * @constant
  35310. * @type {Color}
  35311. */
  35312. Color.AQUAMARINE = freezeObject(Color.fromCssColorString('#7FFFD4'));
  35313. /**
  35314. * An immutable Color instance initialized to CSS color #F0FFFF
  35315. * <span class="colorSwath" style="background: #F0FFFF;"></span>
  35316. *
  35317. * @constant
  35318. * @type {Color}
  35319. */
  35320. Color.AZURE = freezeObject(Color.fromCssColorString('#F0FFFF'));
  35321. /**
  35322. * An immutable Color instance initialized to CSS color #F5F5DC
  35323. * <span class="colorSwath" style="background: #F5F5DC;"></span>
  35324. *
  35325. * @constant
  35326. * @type {Color}
  35327. */
  35328. Color.BEIGE = freezeObject(Color.fromCssColorString('#F5F5DC'));
  35329. /**
  35330. * An immutable Color instance initialized to CSS color #FFE4C4
  35331. * <span class="colorSwath" style="background: #FFE4C4;"></span>
  35332. *
  35333. * @constant
  35334. * @type {Color}
  35335. */
  35336. Color.BISQUE = freezeObject(Color.fromCssColorString('#FFE4C4'));
  35337. /**
  35338. * An immutable Color instance initialized to CSS color #000000
  35339. * <span class="colorSwath" style="background: #000000;"></span>
  35340. *
  35341. * @constant
  35342. * @type {Color}
  35343. */
  35344. Color.BLACK = freezeObject(Color.fromCssColorString('#000000'));
  35345. /**
  35346. * An immutable Color instance initialized to CSS color #FFEBCD
  35347. * <span class="colorSwath" style="background: #FFEBCD;"></span>
  35348. *
  35349. * @constant
  35350. * @type {Color}
  35351. */
  35352. Color.BLANCHEDALMOND = freezeObject(Color.fromCssColorString('#FFEBCD'));
  35353. /**
  35354. * An immutable Color instance initialized to CSS color #0000FF
  35355. * <span class="colorSwath" style="background: #0000FF;"></span>
  35356. *
  35357. * @constant
  35358. * @type {Color}
  35359. */
  35360. Color.BLUE = freezeObject(Color.fromCssColorString('#0000FF'));
  35361. /**
  35362. * An immutable Color instance initialized to CSS color #8A2BE2
  35363. * <span class="colorSwath" style="background: #8A2BE2;"></span>
  35364. *
  35365. * @constant
  35366. * @type {Color}
  35367. */
  35368. Color.BLUEVIOLET = freezeObject(Color.fromCssColorString('#8A2BE2'));
  35369. /**
  35370. * An immutable Color instance initialized to CSS color #A52A2A
  35371. * <span class="colorSwath" style="background: #A52A2A;"></span>
  35372. *
  35373. * @constant
  35374. * @type {Color}
  35375. */
  35376. Color.BROWN = freezeObject(Color.fromCssColorString('#A52A2A'));
  35377. /**
  35378. * An immutable Color instance initialized to CSS color #DEB887
  35379. * <span class="colorSwath" style="background: #DEB887;"></span>
  35380. *
  35381. * @constant
  35382. * @type {Color}
  35383. */
  35384. Color.BURLYWOOD = freezeObject(Color.fromCssColorString('#DEB887'));
  35385. /**
  35386. * An immutable Color instance initialized to CSS color #5F9EA0
  35387. * <span class="colorSwath" style="background: #5F9EA0;"></span>
  35388. *
  35389. * @constant
  35390. * @type {Color}
  35391. */
  35392. Color.CADETBLUE = freezeObject(Color.fromCssColorString('#5F9EA0'));
  35393. /**
  35394. * An immutable Color instance initialized to CSS color #7FFF00
  35395. * <span class="colorSwath" style="background: #7FFF00;"></span>
  35396. *
  35397. * @constant
  35398. * @type {Color}
  35399. */
  35400. Color.CHARTREUSE = freezeObject(Color.fromCssColorString('#7FFF00'));
  35401. /**
  35402. * An immutable Color instance initialized to CSS color #D2691E
  35403. * <span class="colorSwath" style="background: #D2691E;"></span>
  35404. *
  35405. * @constant
  35406. * @type {Color}
  35407. */
  35408. Color.CHOCOLATE = freezeObject(Color.fromCssColorString('#D2691E'));
  35409. /**
  35410. * An immutable Color instance initialized to CSS color #FF7F50
  35411. * <span class="colorSwath" style="background: #FF7F50;"></span>
  35412. *
  35413. * @constant
  35414. * @type {Color}
  35415. */
  35416. Color.CORAL = freezeObject(Color.fromCssColorString('#FF7F50'));
  35417. /**
  35418. * An immutable Color instance initialized to CSS color #6495ED
  35419. * <span class="colorSwath" style="background: #6495ED;"></span>
  35420. *
  35421. * @constant
  35422. * @type {Color}
  35423. */
  35424. Color.CORNFLOWERBLUE = freezeObject(Color.fromCssColorString('#6495ED'));
  35425. /**
  35426. * An immutable Color instance initialized to CSS color #FFF8DC
  35427. * <span class="colorSwath" style="background: #FFF8DC;"></span>
  35428. *
  35429. * @constant
  35430. * @type {Color}
  35431. */
  35432. Color.CORNSILK = freezeObject(Color.fromCssColorString('#FFF8DC'));
  35433. /**
  35434. * An immutable Color instance initialized to CSS color #DC143C
  35435. * <span class="colorSwath" style="background: #DC143C;"></span>
  35436. *
  35437. * @constant
  35438. * @type {Color}
  35439. */
  35440. Color.CRIMSON = freezeObject(Color.fromCssColorString('#DC143C'));
  35441. /**
  35442. * An immutable Color instance initialized to CSS color #00FFFF
  35443. * <span class="colorSwath" style="background: #00FFFF;"></span>
  35444. *
  35445. * @constant
  35446. * @type {Color}
  35447. */
  35448. Color.CYAN = freezeObject(Color.fromCssColorString('#00FFFF'));
  35449. /**
  35450. * An immutable Color instance initialized to CSS color #00008B
  35451. * <span class="colorSwath" style="background: #00008B;"></span>
  35452. *
  35453. * @constant
  35454. * @type {Color}
  35455. */
  35456. Color.DARKBLUE = freezeObject(Color.fromCssColorString('#00008B'));
  35457. /**
  35458. * An immutable Color instance initialized to CSS color #008B8B
  35459. * <span class="colorSwath" style="background: #008B8B;"></span>
  35460. *
  35461. * @constant
  35462. * @type {Color}
  35463. */
  35464. Color.DARKCYAN = freezeObject(Color.fromCssColorString('#008B8B'));
  35465. /**
  35466. * An immutable Color instance initialized to CSS color #B8860B
  35467. * <span class="colorSwath" style="background: #B8860B;"></span>
  35468. *
  35469. * @constant
  35470. * @type {Color}
  35471. */
  35472. Color.DARKGOLDENROD = freezeObject(Color.fromCssColorString('#B8860B'));
  35473. /**
  35474. * An immutable Color instance initialized to CSS color #A9A9A9
  35475. * <span class="colorSwath" style="background: #A9A9A9;"></span>
  35476. *
  35477. * @constant
  35478. * @type {Color}
  35479. */
  35480. Color.DARKGRAY = freezeObject(Color.fromCssColorString('#A9A9A9'));
  35481. /**
  35482. * An immutable Color instance initialized to CSS color #006400
  35483. * <span class="colorSwath" style="background: #006400;"></span>
  35484. *
  35485. * @constant
  35486. * @type {Color}
  35487. */
  35488. Color.DARKGREEN = freezeObject(Color.fromCssColorString('#006400'));
  35489. /**
  35490. * An immutable Color instance initialized to CSS color #A9A9A9
  35491. * <span class="colorSwath" style="background: #A9A9A9;"></span>
  35492. *
  35493. * @constant
  35494. * @type {Color}
  35495. */
  35496. Color.DARKGREY = Color.DARKGRAY;
  35497. /**
  35498. * An immutable Color instance initialized to CSS color #BDB76B
  35499. * <span class="colorSwath" style="background: #BDB76B;"></span>
  35500. *
  35501. * @constant
  35502. * @type {Color}
  35503. */
  35504. Color.DARKKHAKI = freezeObject(Color.fromCssColorString('#BDB76B'));
  35505. /**
  35506. * An immutable Color instance initialized to CSS color #8B008B
  35507. * <span class="colorSwath" style="background: #8B008B;"></span>
  35508. *
  35509. * @constant
  35510. * @type {Color}
  35511. */
  35512. Color.DARKMAGENTA = freezeObject(Color.fromCssColorString('#8B008B'));
  35513. /**
  35514. * An immutable Color instance initialized to CSS color #556B2F
  35515. * <span class="colorSwath" style="background: #556B2F;"></span>
  35516. *
  35517. * @constant
  35518. * @type {Color}
  35519. */
  35520. Color.DARKOLIVEGREEN = freezeObject(Color.fromCssColorString('#556B2F'));
  35521. /**
  35522. * An immutable Color instance initialized to CSS color #FF8C00
  35523. * <span class="colorSwath" style="background: #FF8C00;"></span>
  35524. *
  35525. * @constant
  35526. * @type {Color}
  35527. */
  35528. Color.DARKORANGE = freezeObject(Color.fromCssColorString('#FF8C00'));
  35529. /**
  35530. * An immutable Color instance initialized to CSS color #9932CC
  35531. * <span class="colorSwath" style="background: #9932CC;"></span>
  35532. *
  35533. * @constant
  35534. * @type {Color}
  35535. */
  35536. Color.DARKORCHID = freezeObject(Color.fromCssColorString('#9932CC'));
  35537. /**
  35538. * An immutable Color instance initialized to CSS color #8B0000
  35539. * <span class="colorSwath" style="background: #8B0000;"></span>
  35540. *
  35541. * @constant
  35542. * @type {Color}
  35543. */
  35544. Color.DARKRED = freezeObject(Color.fromCssColorString('#8B0000'));
  35545. /**
  35546. * An immutable Color instance initialized to CSS color #E9967A
  35547. * <span class="colorSwath" style="background: #E9967A;"></span>
  35548. *
  35549. * @constant
  35550. * @type {Color}
  35551. */
  35552. Color.DARKSALMON = freezeObject(Color.fromCssColorString('#E9967A'));
  35553. /**
  35554. * An immutable Color instance initialized to CSS color #8FBC8F
  35555. * <span class="colorSwath" style="background: #8FBC8F;"></span>
  35556. *
  35557. * @constant
  35558. * @type {Color}
  35559. */
  35560. Color.DARKSEAGREEN = freezeObject(Color.fromCssColorString('#8FBC8F'));
  35561. /**
  35562. * An immutable Color instance initialized to CSS color #483D8B
  35563. * <span class="colorSwath" style="background: #483D8B;"></span>
  35564. *
  35565. * @constant
  35566. * @type {Color}
  35567. */
  35568. Color.DARKSLATEBLUE = freezeObject(Color.fromCssColorString('#483D8B'));
  35569. /**
  35570. * An immutable Color instance initialized to CSS color #2F4F4F
  35571. * <span class="colorSwath" style="background: #2F4F4F;"></span>
  35572. *
  35573. * @constant
  35574. * @type {Color}
  35575. */
  35576. Color.DARKSLATEGRAY = freezeObject(Color.fromCssColorString('#2F4F4F'));
  35577. /**
  35578. * An immutable Color instance initialized to CSS color #2F4F4F
  35579. * <span class="colorSwath" style="background: #2F4F4F;"></span>
  35580. *
  35581. * @constant
  35582. * @type {Color}
  35583. */
  35584. Color.DARKSLATEGREY = Color.DARKSLATEGRAY;
  35585. /**
  35586. * An immutable Color instance initialized to CSS color #00CED1
  35587. * <span class="colorSwath" style="background: #00CED1;"></span>
  35588. *
  35589. * @constant
  35590. * @type {Color}
  35591. */
  35592. Color.DARKTURQUOISE = freezeObject(Color.fromCssColorString('#00CED1'));
  35593. /**
  35594. * An immutable Color instance initialized to CSS color #9400D3
  35595. * <span class="colorSwath" style="background: #9400D3;"></span>
  35596. *
  35597. * @constant
  35598. * @type {Color}
  35599. */
  35600. Color.DARKVIOLET = freezeObject(Color.fromCssColorString('#9400D3'));
  35601. /**
  35602. * An immutable Color instance initialized to CSS color #FF1493
  35603. * <span class="colorSwath" style="background: #FF1493;"></span>
  35604. *
  35605. * @constant
  35606. * @type {Color}
  35607. */
  35608. Color.DEEPPINK = freezeObject(Color.fromCssColorString('#FF1493'));
  35609. /**
  35610. * An immutable Color instance initialized to CSS color #00BFFF
  35611. * <span class="colorSwath" style="background: #00BFFF;"></span>
  35612. *
  35613. * @constant
  35614. * @type {Color}
  35615. */
  35616. Color.DEEPSKYBLUE = freezeObject(Color.fromCssColorString('#00BFFF'));
  35617. /**
  35618. * An immutable Color instance initialized to CSS color #696969
  35619. * <span class="colorSwath" style="background: #696969;"></span>
  35620. *
  35621. * @constant
  35622. * @type {Color}
  35623. */
  35624. Color.DIMGRAY = freezeObject(Color.fromCssColorString('#696969'));
  35625. /**
  35626. * An immutable Color instance initialized to CSS color #696969
  35627. * <span class="colorSwath" style="background: #696969;"></span>
  35628. *
  35629. * @constant
  35630. * @type {Color}
  35631. */
  35632. Color.DIMGREY = Color.DIMGRAY;
  35633. /**
  35634. * An immutable Color instance initialized to CSS color #1E90FF
  35635. * <span class="colorSwath" style="background: #1E90FF;"></span>
  35636. *
  35637. * @constant
  35638. * @type {Color}
  35639. */
  35640. Color.DODGERBLUE = freezeObject(Color.fromCssColorString('#1E90FF'));
  35641. /**
  35642. * An immutable Color instance initialized to CSS color #B22222
  35643. * <span class="colorSwath" style="background: #B22222;"></span>
  35644. *
  35645. * @constant
  35646. * @type {Color}
  35647. */
  35648. Color.FIREBRICK = freezeObject(Color.fromCssColorString('#B22222'));
  35649. /**
  35650. * An immutable Color instance initialized to CSS color #FFFAF0
  35651. * <span class="colorSwath" style="background: #FFFAF0;"></span>
  35652. *
  35653. * @constant
  35654. * @type {Color}
  35655. */
  35656. Color.FLORALWHITE = freezeObject(Color.fromCssColorString('#FFFAF0'));
  35657. /**
  35658. * An immutable Color instance initialized to CSS color #228B22
  35659. * <span class="colorSwath" style="background: #228B22;"></span>
  35660. *
  35661. * @constant
  35662. * @type {Color}
  35663. */
  35664. Color.FORESTGREEN = freezeObject(Color.fromCssColorString('#228B22'));
  35665. /**
  35666. * An immutable Color instance initialized to CSS color #FF00FF
  35667. * <span class="colorSwath" style="background: #FF00FF;"></span>
  35668. *
  35669. * @constant
  35670. * @type {Color}
  35671. */
  35672. Color.FUSCHIA = freezeObject(Color.fromCssColorString('#FF00FF'));
  35673. /**
  35674. * An immutable Color instance initialized to CSS color #DCDCDC
  35675. * <span class="colorSwath" style="background: #DCDCDC;"></span>
  35676. *
  35677. * @constant
  35678. * @type {Color}
  35679. */
  35680. Color.GAINSBORO = freezeObject(Color.fromCssColorString('#DCDCDC'));
  35681. /**
  35682. * An immutable Color instance initialized to CSS color #F8F8FF
  35683. * <span class="colorSwath" style="background: #F8F8FF;"></span>
  35684. *
  35685. * @constant
  35686. * @type {Color}
  35687. */
  35688. Color.GHOSTWHITE = freezeObject(Color.fromCssColorString('#F8F8FF'));
  35689. /**
  35690. * An immutable Color instance initialized to CSS color #FFD700
  35691. * <span class="colorSwath" style="background: #FFD700;"></span>
  35692. *
  35693. * @constant
  35694. * @type {Color}
  35695. */
  35696. Color.GOLD = freezeObject(Color.fromCssColorString('#FFD700'));
  35697. /**
  35698. * An immutable Color instance initialized to CSS color #DAA520
  35699. * <span class="colorSwath" style="background: #DAA520;"></span>
  35700. *
  35701. * @constant
  35702. * @type {Color}
  35703. */
  35704. Color.GOLDENROD = freezeObject(Color.fromCssColorString('#DAA520'));
  35705. /**
  35706. * An immutable Color instance initialized to CSS color #808080
  35707. * <span class="colorSwath" style="background: #808080;"></span>
  35708. *
  35709. * @constant
  35710. * @type {Color}
  35711. */
  35712. Color.GRAY = freezeObject(Color.fromCssColorString('#808080'));
  35713. /**
  35714. * An immutable Color instance initialized to CSS color #008000
  35715. * <span class="colorSwath" style="background: #008000;"></span>
  35716. *
  35717. * @constant
  35718. * @type {Color}
  35719. */
  35720. Color.GREEN = freezeObject(Color.fromCssColorString('#008000'));
  35721. /**
  35722. * An immutable Color instance initialized to CSS color #ADFF2F
  35723. * <span class="colorSwath" style="background: #ADFF2F;"></span>
  35724. *
  35725. * @constant
  35726. * @type {Color}
  35727. */
  35728. Color.GREENYELLOW = freezeObject(Color.fromCssColorString('#ADFF2F'));
  35729. /**
  35730. * An immutable Color instance initialized to CSS color #808080
  35731. * <span class="colorSwath" style="background: #808080;"></span>
  35732. *
  35733. * @constant
  35734. * @type {Color}
  35735. */
  35736. Color.GREY = Color.GRAY;
  35737. /**
  35738. * An immutable Color instance initialized to CSS color #F0FFF0
  35739. * <span class="colorSwath" style="background: #F0FFF0;"></span>
  35740. *
  35741. * @constant
  35742. * @type {Color}
  35743. */
  35744. Color.HONEYDEW = freezeObject(Color.fromCssColorString('#F0FFF0'));
  35745. /**
  35746. * An immutable Color instance initialized to CSS color #FF69B4
  35747. * <span class="colorSwath" style="background: #FF69B4;"></span>
  35748. *
  35749. * @constant
  35750. * @type {Color}
  35751. */
  35752. Color.HOTPINK = freezeObject(Color.fromCssColorString('#FF69B4'));
  35753. /**
  35754. * An immutable Color instance initialized to CSS color #CD5C5C
  35755. * <span class="colorSwath" style="background: #CD5C5C;"></span>
  35756. *
  35757. * @constant
  35758. * @type {Color}
  35759. */
  35760. Color.INDIANRED = freezeObject(Color.fromCssColorString('#CD5C5C'));
  35761. /**
  35762. * An immutable Color instance initialized to CSS color #4B0082
  35763. * <span class="colorSwath" style="background: #4B0082;"></span>
  35764. *
  35765. * @constant
  35766. * @type {Color}
  35767. */
  35768. Color.INDIGO = freezeObject(Color.fromCssColorString('#4B0082'));
  35769. /**
  35770. * An immutable Color instance initialized to CSS color #FFFFF0
  35771. * <span class="colorSwath" style="background: #FFFFF0;"></span>
  35772. *
  35773. * @constant
  35774. * @type {Color}
  35775. */
  35776. Color.IVORY = freezeObject(Color.fromCssColorString('#FFFFF0'));
  35777. /**
  35778. * An immutable Color instance initialized to CSS color #F0E68C
  35779. * <span class="colorSwath" style="background: #F0E68C;"></span>
  35780. *
  35781. * @constant
  35782. * @type {Color}
  35783. */
  35784. Color.KHAKI = freezeObject(Color.fromCssColorString('#F0E68C'));
  35785. /**
  35786. * An immutable Color instance initialized to CSS color #E6E6FA
  35787. * <span class="colorSwath" style="background: #E6E6FA;"></span>
  35788. *
  35789. * @constant
  35790. * @type {Color}
  35791. */
  35792. Color.LAVENDER = freezeObject(Color.fromCssColorString('#E6E6FA'));
  35793. /**
  35794. * An immutable Color instance initialized to CSS color #FFF0F5
  35795. * <span class="colorSwath" style="background: #FFF0F5;"></span>
  35796. *
  35797. * @constant
  35798. * @type {Color}
  35799. */
  35800. Color.LAVENDAR_BLUSH = freezeObject(Color.fromCssColorString('#FFF0F5'));
  35801. /**
  35802. * An immutable Color instance initialized to CSS color #7CFC00
  35803. * <span class="colorSwath" style="background: #7CFC00;"></span>
  35804. *
  35805. * @constant
  35806. * @type {Color}
  35807. */
  35808. Color.LAWNGREEN = freezeObject(Color.fromCssColorString('#7CFC00'));
  35809. /**
  35810. * An immutable Color instance initialized to CSS color #FFFACD
  35811. * <span class="colorSwath" style="background: #FFFACD;"></span>
  35812. *
  35813. * @constant
  35814. * @type {Color}
  35815. */
  35816. Color.LEMONCHIFFON = freezeObject(Color.fromCssColorString('#FFFACD'));
  35817. /**
  35818. * An immutable Color instance initialized to CSS color #ADD8E6
  35819. * <span class="colorSwath" style="background: #ADD8E6;"></span>
  35820. *
  35821. * @constant
  35822. * @type {Color}
  35823. */
  35824. Color.LIGHTBLUE = freezeObject(Color.fromCssColorString('#ADD8E6'));
  35825. /**
  35826. * An immutable Color instance initialized to CSS color #F08080
  35827. * <span class="colorSwath" style="background: #F08080;"></span>
  35828. *
  35829. * @constant
  35830. * @type {Color}
  35831. */
  35832. Color.LIGHTCORAL = freezeObject(Color.fromCssColorString('#F08080'));
  35833. /**
  35834. * An immutable Color instance initialized to CSS color #E0FFFF
  35835. * <span class="colorSwath" style="background: #E0FFFF;"></span>
  35836. *
  35837. * @constant
  35838. * @type {Color}
  35839. */
  35840. Color.LIGHTCYAN = freezeObject(Color.fromCssColorString('#E0FFFF'));
  35841. /**
  35842. * An immutable Color instance initialized to CSS color #FAFAD2
  35843. * <span class="colorSwath" style="background: #FAFAD2;"></span>
  35844. *
  35845. * @constant
  35846. * @type {Color}
  35847. */
  35848. Color.LIGHTGOLDENRODYELLOW = freezeObject(Color.fromCssColorString('#FAFAD2'));
  35849. /**
  35850. * An immutable Color instance initialized to CSS color #D3D3D3
  35851. * <span class="colorSwath" style="background: #D3D3D3;"></span>
  35852. *
  35853. * @constant
  35854. * @type {Color}
  35855. */
  35856. Color.LIGHTGRAY = freezeObject(Color.fromCssColorString('#D3D3D3'));
  35857. /**
  35858. * An immutable Color instance initialized to CSS color #90EE90
  35859. * <span class="colorSwath" style="background: #90EE90;"></span>
  35860. *
  35861. * @constant
  35862. * @type {Color}
  35863. */
  35864. Color.LIGHTGREEN = freezeObject(Color.fromCssColorString('#90EE90'));
  35865. /**
  35866. * An immutable Color instance initialized to CSS color #D3D3D3
  35867. * <span class="colorSwath" style="background: #D3D3D3;"></span>
  35868. *
  35869. * @constant
  35870. * @type {Color}
  35871. */
  35872. Color.LIGHTGREY = Color.LIGHTGRAY;
  35873. /**
  35874. * An immutable Color instance initialized to CSS color #FFB6C1
  35875. * <span class="colorSwath" style="background: #FFB6C1;"></span>
  35876. *
  35877. * @constant
  35878. * @type {Color}
  35879. */
  35880. Color.LIGHTPINK = freezeObject(Color.fromCssColorString('#FFB6C1'));
  35881. /**
  35882. * An immutable Color instance initialized to CSS color #20B2AA
  35883. * <span class="colorSwath" style="background: #20B2AA;"></span>
  35884. *
  35885. * @constant
  35886. * @type {Color}
  35887. */
  35888. Color.LIGHTSEAGREEN = freezeObject(Color.fromCssColorString('#20B2AA'));
  35889. /**
  35890. * An immutable Color instance initialized to CSS color #87CEFA
  35891. * <span class="colorSwath" style="background: #87CEFA;"></span>
  35892. *
  35893. * @constant
  35894. * @type {Color}
  35895. */
  35896. Color.LIGHTSKYBLUE = freezeObject(Color.fromCssColorString('#87CEFA'));
  35897. /**
  35898. * An immutable Color instance initialized to CSS color #778899
  35899. * <span class="colorSwath" style="background: #778899;"></span>
  35900. *
  35901. * @constant
  35902. * @type {Color}
  35903. */
  35904. Color.LIGHTSLATEGRAY = freezeObject(Color.fromCssColorString('#778899'));
  35905. /**
  35906. * An immutable Color instance initialized to CSS color #778899
  35907. * <span class="colorSwath" style="background: #778899;"></span>
  35908. *
  35909. * @constant
  35910. * @type {Color}
  35911. */
  35912. Color.LIGHTSLATEGREY = Color.LIGHTSLATEGRAY;
  35913. /**
  35914. * An immutable Color instance initialized to CSS color #B0C4DE
  35915. * <span class="colorSwath" style="background: #B0C4DE;"></span>
  35916. *
  35917. * @constant
  35918. * @type {Color}
  35919. */
  35920. Color.LIGHTSTEELBLUE = freezeObject(Color.fromCssColorString('#B0C4DE'));
  35921. /**
  35922. * An immutable Color instance initialized to CSS color #FFFFE0
  35923. * <span class="colorSwath" style="background: #FFFFE0;"></span>
  35924. *
  35925. * @constant
  35926. * @type {Color}
  35927. */
  35928. Color.LIGHTYELLOW = freezeObject(Color.fromCssColorString('#FFFFE0'));
  35929. /**
  35930. * An immutable Color instance initialized to CSS color #00FF00
  35931. * <span class="colorSwath" style="background: #00FF00;"></span>
  35932. *
  35933. * @constant
  35934. * @type {Color}
  35935. */
  35936. Color.LIME = freezeObject(Color.fromCssColorString('#00FF00'));
  35937. /**
  35938. * An immutable Color instance initialized to CSS color #32CD32
  35939. * <span class="colorSwath" style="background: #32CD32;"></span>
  35940. *
  35941. * @constant
  35942. * @type {Color}
  35943. */
  35944. Color.LIMEGREEN = freezeObject(Color.fromCssColorString('#32CD32'));
  35945. /**
  35946. * An immutable Color instance initialized to CSS color #FAF0E6
  35947. * <span class="colorSwath" style="background: #FAF0E6;"></span>
  35948. *
  35949. * @constant
  35950. * @type {Color}
  35951. */
  35952. Color.LINEN = freezeObject(Color.fromCssColorString('#FAF0E6'));
  35953. /**
  35954. * An immutable Color instance initialized to CSS color #FF00FF
  35955. * <span class="colorSwath" style="background: #FF00FF;"></span>
  35956. *
  35957. * @constant
  35958. * @type {Color}
  35959. */
  35960. Color.MAGENTA = freezeObject(Color.fromCssColorString('#FF00FF'));
  35961. /**
  35962. * An immutable Color instance initialized to CSS color #800000
  35963. * <span class="colorSwath" style="background: #800000;"></span>
  35964. *
  35965. * @constant
  35966. * @type {Color}
  35967. */
  35968. Color.MAROON = freezeObject(Color.fromCssColorString('#800000'));
  35969. /**
  35970. * An immutable Color instance initialized to CSS color #66CDAA
  35971. * <span class="colorSwath" style="background: #66CDAA;"></span>
  35972. *
  35973. * @constant
  35974. * @type {Color}
  35975. */
  35976. Color.MEDIUMAQUAMARINE = freezeObject(Color.fromCssColorString('#66CDAA'));
  35977. /**
  35978. * An immutable Color instance initialized to CSS color #0000CD
  35979. * <span class="colorSwath" style="background: #0000CD;"></span>
  35980. *
  35981. * @constant
  35982. * @type {Color}
  35983. */
  35984. Color.MEDIUMBLUE = freezeObject(Color.fromCssColorString('#0000CD'));
  35985. /**
  35986. * An immutable Color instance initialized to CSS color #BA55D3
  35987. * <span class="colorSwath" style="background: #BA55D3;"></span>
  35988. *
  35989. * @constant
  35990. * @type {Color}
  35991. */
  35992. Color.MEDIUMORCHID = freezeObject(Color.fromCssColorString('#BA55D3'));
  35993. /**
  35994. * An immutable Color instance initialized to CSS color #9370DB
  35995. * <span class="colorSwath" style="background: #9370DB;"></span>
  35996. *
  35997. * @constant
  35998. * @type {Color}
  35999. */
  36000. Color.MEDIUMPURPLE = freezeObject(Color.fromCssColorString('#9370DB'));
  36001. /**
  36002. * An immutable Color instance initialized to CSS color #3CB371
  36003. * <span class="colorSwath" style="background: #3CB371;"></span>
  36004. *
  36005. * @constant
  36006. * @type {Color}
  36007. */
  36008. Color.MEDIUMSEAGREEN = freezeObject(Color.fromCssColorString('#3CB371'));
  36009. /**
  36010. * An immutable Color instance initialized to CSS color #7B68EE
  36011. * <span class="colorSwath" style="background: #7B68EE;"></span>
  36012. *
  36013. * @constant
  36014. * @type {Color}
  36015. */
  36016. Color.MEDIUMSLATEBLUE = freezeObject(Color.fromCssColorString('#7B68EE'));
  36017. /**
  36018. * An immutable Color instance initialized to CSS color #00FA9A
  36019. * <span class="colorSwath" style="background: #00FA9A;"></span>
  36020. *
  36021. * @constant
  36022. * @type {Color}
  36023. */
  36024. Color.MEDIUMSPRINGGREEN = freezeObject(Color.fromCssColorString('#00FA9A'));
  36025. /**
  36026. * An immutable Color instance initialized to CSS color #48D1CC
  36027. * <span class="colorSwath" style="background: #48D1CC;"></span>
  36028. *
  36029. * @constant
  36030. * @type {Color}
  36031. */
  36032. Color.MEDIUMTURQUOISE = freezeObject(Color.fromCssColorString('#48D1CC'));
  36033. /**
  36034. * An immutable Color instance initialized to CSS color #C71585
  36035. * <span class="colorSwath" style="background: #C71585;"></span>
  36036. *
  36037. * @constant
  36038. * @type {Color}
  36039. */
  36040. Color.MEDIUMVIOLETRED = freezeObject(Color.fromCssColorString('#C71585'));
  36041. /**
  36042. * An immutable Color instance initialized to CSS color #191970
  36043. * <span class="colorSwath" style="background: #191970;"></span>
  36044. *
  36045. * @constant
  36046. * @type {Color}
  36047. */
  36048. Color.MIDNIGHTBLUE = freezeObject(Color.fromCssColorString('#191970'));
  36049. /**
  36050. * An immutable Color instance initialized to CSS color #F5FFFA
  36051. * <span class="colorSwath" style="background: #F5FFFA;"></span>
  36052. *
  36053. * @constant
  36054. * @type {Color}
  36055. */
  36056. Color.MINTCREAM = freezeObject(Color.fromCssColorString('#F5FFFA'));
  36057. /**
  36058. * An immutable Color instance initialized to CSS color #FFE4E1
  36059. * <span class="colorSwath" style="background: #FFE4E1;"></span>
  36060. *
  36061. * @constant
  36062. * @type {Color}
  36063. */
  36064. Color.MISTYROSE = freezeObject(Color.fromCssColorString('#FFE4E1'));
  36065. /**
  36066. * An immutable Color instance initialized to CSS color #FFE4B5
  36067. * <span class="colorSwath" style="background: #FFE4B5;"></span>
  36068. *
  36069. * @constant
  36070. * @type {Color}
  36071. */
  36072. Color.MOCCASIN = freezeObject(Color.fromCssColorString('#FFE4B5'));
  36073. /**
  36074. * An immutable Color instance initialized to CSS color #FFDEAD
  36075. * <span class="colorSwath" style="background: #FFDEAD;"></span>
  36076. *
  36077. * @constant
  36078. * @type {Color}
  36079. */
  36080. Color.NAVAJOWHITE = freezeObject(Color.fromCssColorString('#FFDEAD'));
  36081. /**
  36082. * An immutable Color instance initialized to CSS color #000080
  36083. * <span class="colorSwath" style="background: #000080;"></span>
  36084. *
  36085. * @constant
  36086. * @type {Color}
  36087. */
  36088. Color.NAVY = freezeObject(Color.fromCssColorString('#000080'));
  36089. /**
  36090. * An immutable Color instance initialized to CSS color #FDF5E6
  36091. * <span class="colorSwath" style="background: #FDF5E6;"></span>
  36092. *
  36093. * @constant
  36094. * @type {Color}
  36095. */
  36096. Color.OLDLACE = freezeObject(Color.fromCssColorString('#FDF5E6'));
  36097. /**
  36098. * An immutable Color instance initialized to CSS color #808000
  36099. * <span class="colorSwath" style="background: #808000;"></span>
  36100. *
  36101. * @constant
  36102. * @type {Color}
  36103. */
  36104. Color.OLIVE = freezeObject(Color.fromCssColorString('#808000'));
  36105. /**
  36106. * An immutable Color instance initialized to CSS color #6B8E23
  36107. * <span class="colorSwath" style="background: #6B8E23;"></span>
  36108. *
  36109. * @constant
  36110. * @type {Color}
  36111. */
  36112. Color.OLIVEDRAB = freezeObject(Color.fromCssColorString('#6B8E23'));
  36113. /**
  36114. * An immutable Color instance initialized to CSS color #FFA500
  36115. * <span class="colorSwath" style="background: #FFA500;"></span>
  36116. *
  36117. * @constant
  36118. * @type {Color}
  36119. */
  36120. Color.ORANGE = freezeObject(Color.fromCssColorString('#FFA500'));
  36121. /**
  36122. * An immutable Color instance initialized to CSS color #FF4500
  36123. * <span class="colorSwath" style="background: #FF4500;"></span>
  36124. *
  36125. * @constant
  36126. * @type {Color}
  36127. */
  36128. Color.ORANGERED = freezeObject(Color.fromCssColorString('#FF4500'));
  36129. /**
  36130. * An immutable Color instance initialized to CSS color #DA70D6
  36131. * <span class="colorSwath" style="background: #DA70D6;"></span>
  36132. *
  36133. * @constant
  36134. * @type {Color}
  36135. */
  36136. Color.ORCHID = freezeObject(Color.fromCssColorString('#DA70D6'));
  36137. /**
  36138. * An immutable Color instance initialized to CSS color #EEE8AA
  36139. * <span class="colorSwath" style="background: #EEE8AA;"></span>
  36140. *
  36141. * @constant
  36142. * @type {Color}
  36143. */
  36144. Color.PALEGOLDENROD = freezeObject(Color.fromCssColorString('#EEE8AA'));
  36145. /**
  36146. * An immutable Color instance initialized to CSS color #98FB98
  36147. * <span class="colorSwath" style="background: #98FB98;"></span>
  36148. *
  36149. * @constant
  36150. * @type {Color}
  36151. */
  36152. Color.PALEGREEN = freezeObject(Color.fromCssColorString('#98FB98'));
  36153. /**
  36154. * An immutable Color instance initialized to CSS color #AFEEEE
  36155. * <span class="colorSwath" style="background: #AFEEEE;"></span>
  36156. *
  36157. * @constant
  36158. * @type {Color}
  36159. */
  36160. Color.PALETURQUOISE = freezeObject(Color.fromCssColorString('#AFEEEE'));
  36161. /**
  36162. * An immutable Color instance initialized to CSS color #DB7093
  36163. * <span class="colorSwath" style="background: #DB7093;"></span>
  36164. *
  36165. * @constant
  36166. * @type {Color}
  36167. */
  36168. Color.PALEVIOLETRED = freezeObject(Color.fromCssColorString('#DB7093'));
  36169. /**
  36170. * An immutable Color instance initialized to CSS color #FFEFD5
  36171. * <span class="colorSwath" style="background: #FFEFD5;"></span>
  36172. *
  36173. * @constant
  36174. * @type {Color}
  36175. */
  36176. Color.PAPAYAWHIP = freezeObject(Color.fromCssColorString('#FFEFD5'));
  36177. /**
  36178. * An immutable Color instance initialized to CSS color #FFDAB9
  36179. * <span class="colorSwath" style="background: #FFDAB9;"></span>
  36180. *
  36181. * @constant
  36182. * @type {Color}
  36183. */
  36184. Color.PEACHPUFF = freezeObject(Color.fromCssColorString('#FFDAB9'));
  36185. /**
  36186. * An immutable Color instance initialized to CSS color #CD853F
  36187. * <span class="colorSwath" style="background: #CD853F;"></span>
  36188. *
  36189. * @constant
  36190. * @type {Color}
  36191. */
  36192. Color.PERU = freezeObject(Color.fromCssColorString('#CD853F'));
  36193. /**
  36194. * An immutable Color instance initialized to CSS color #FFC0CB
  36195. * <span class="colorSwath" style="background: #FFC0CB;"></span>
  36196. *
  36197. * @constant
  36198. * @type {Color}
  36199. */
  36200. Color.PINK = freezeObject(Color.fromCssColorString('#FFC0CB'));
  36201. /**
  36202. * An immutable Color instance initialized to CSS color #DDA0DD
  36203. * <span class="colorSwath" style="background: #DDA0DD;"></span>
  36204. *
  36205. * @constant
  36206. * @type {Color}
  36207. */
  36208. Color.PLUM = freezeObject(Color.fromCssColorString('#DDA0DD'));
  36209. /**
  36210. * An immutable Color instance initialized to CSS color #B0E0E6
  36211. * <span class="colorSwath" style="background: #B0E0E6;"></span>
  36212. *
  36213. * @constant
  36214. * @type {Color}
  36215. */
  36216. Color.POWDERBLUE = freezeObject(Color.fromCssColorString('#B0E0E6'));
  36217. /**
  36218. * An immutable Color instance initialized to CSS color #800080
  36219. * <span class="colorSwath" style="background: #800080;"></span>
  36220. *
  36221. * @constant
  36222. * @type {Color}
  36223. */
  36224. Color.PURPLE = freezeObject(Color.fromCssColorString('#800080'));
  36225. /**
  36226. * An immutable Color instance initialized to CSS color #FF0000
  36227. * <span class="colorSwath" style="background: #FF0000;"></span>
  36228. *
  36229. * @constant
  36230. * @type {Color}
  36231. */
  36232. Color.RED = freezeObject(Color.fromCssColorString('#FF0000'));
  36233. /**
  36234. * An immutable Color instance initialized to CSS color #BC8F8F
  36235. * <span class="colorSwath" style="background: #BC8F8F;"></span>
  36236. *
  36237. * @constant
  36238. * @type {Color}
  36239. */
  36240. Color.ROSYBROWN = freezeObject(Color.fromCssColorString('#BC8F8F'));
  36241. /**
  36242. * An immutable Color instance initialized to CSS color #4169E1
  36243. * <span class="colorSwath" style="background: #4169E1;"></span>
  36244. *
  36245. * @constant
  36246. * @type {Color}
  36247. */
  36248. Color.ROYALBLUE = freezeObject(Color.fromCssColorString('#4169E1'));
  36249. /**
  36250. * An immutable Color instance initialized to CSS color #8B4513
  36251. * <span class="colorSwath" style="background: #8B4513;"></span>
  36252. *
  36253. * @constant
  36254. * @type {Color}
  36255. */
  36256. Color.SADDLEBROWN = freezeObject(Color.fromCssColorString('#8B4513'));
  36257. /**
  36258. * An immutable Color instance initialized to CSS color #FA8072
  36259. * <span class="colorSwath" style="background: #FA8072;"></span>
  36260. *
  36261. * @constant
  36262. * @type {Color}
  36263. */
  36264. Color.SALMON = freezeObject(Color.fromCssColorString('#FA8072'));
  36265. /**
  36266. * An immutable Color instance initialized to CSS color #F4A460
  36267. * <span class="colorSwath" style="background: #F4A460;"></span>
  36268. *
  36269. * @constant
  36270. * @type {Color}
  36271. */
  36272. Color.SANDYBROWN = freezeObject(Color.fromCssColorString('#F4A460'));
  36273. /**
  36274. * An immutable Color instance initialized to CSS color #2E8B57
  36275. * <span class="colorSwath" style="background: #2E8B57;"></span>
  36276. *
  36277. * @constant
  36278. * @type {Color}
  36279. */
  36280. Color.SEAGREEN = freezeObject(Color.fromCssColorString('#2E8B57'));
  36281. /**
  36282. * An immutable Color instance initialized to CSS color #FFF5EE
  36283. * <span class="colorSwath" style="background: #FFF5EE;"></span>
  36284. *
  36285. * @constant
  36286. * @type {Color}
  36287. */
  36288. Color.SEASHELL = freezeObject(Color.fromCssColorString('#FFF5EE'));
  36289. /**
  36290. * An immutable Color instance initialized to CSS color #A0522D
  36291. * <span class="colorSwath" style="background: #A0522D;"></span>
  36292. *
  36293. * @constant
  36294. * @type {Color}
  36295. */
  36296. Color.SIENNA = freezeObject(Color.fromCssColorString('#A0522D'));
  36297. /**
  36298. * An immutable Color instance initialized to CSS color #C0C0C0
  36299. * <span class="colorSwath" style="background: #C0C0C0;"></span>
  36300. *
  36301. * @constant
  36302. * @type {Color}
  36303. */
  36304. Color.SILVER = freezeObject(Color.fromCssColorString('#C0C0C0'));
  36305. /**
  36306. * An immutable Color instance initialized to CSS color #87CEEB
  36307. * <span class="colorSwath" style="background: #87CEEB;"></span>
  36308. *
  36309. * @constant
  36310. * @type {Color}
  36311. */
  36312. Color.SKYBLUE = freezeObject(Color.fromCssColorString('#87CEEB'));
  36313. /**
  36314. * An immutable Color instance initialized to CSS color #6A5ACD
  36315. * <span class="colorSwath" style="background: #6A5ACD;"></span>
  36316. *
  36317. * @constant
  36318. * @type {Color}
  36319. */
  36320. Color.SLATEBLUE = freezeObject(Color.fromCssColorString('#6A5ACD'));
  36321. /**
  36322. * An immutable Color instance initialized to CSS color #708090
  36323. * <span class="colorSwath" style="background: #708090;"></span>
  36324. *
  36325. * @constant
  36326. * @type {Color}
  36327. */
  36328. Color.SLATEGRAY = freezeObject(Color.fromCssColorString('#708090'));
  36329. /**
  36330. * An immutable Color instance initialized to CSS color #708090
  36331. * <span class="colorSwath" style="background: #708090;"></span>
  36332. *
  36333. * @constant
  36334. * @type {Color}
  36335. */
  36336. Color.SLATEGREY = Color.SLATEGRAY;
  36337. /**
  36338. * An immutable Color instance initialized to CSS color #FFFAFA
  36339. * <span class="colorSwath" style="background: #FFFAFA;"></span>
  36340. *
  36341. * @constant
  36342. * @type {Color}
  36343. */
  36344. Color.SNOW = freezeObject(Color.fromCssColorString('#FFFAFA'));
  36345. /**
  36346. * An immutable Color instance initialized to CSS color #00FF7F
  36347. * <span class="colorSwath" style="background: #00FF7F;"></span>
  36348. *
  36349. * @constant
  36350. * @type {Color}
  36351. */
  36352. Color.SPRINGGREEN = freezeObject(Color.fromCssColorString('#00FF7F'));
  36353. /**
  36354. * An immutable Color instance initialized to CSS color #4682B4
  36355. * <span class="colorSwath" style="background: #4682B4;"></span>
  36356. *
  36357. * @constant
  36358. * @type {Color}
  36359. */
  36360. Color.STEELBLUE = freezeObject(Color.fromCssColorString('#4682B4'));
  36361. /**
  36362. * An immutable Color instance initialized to CSS color #D2B48C
  36363. * <span class="colorSwath" style="background: #D2B48C;"></span>
  36364. *
  36365. * @constant
  36366. * @type {Color}
  36367. */
  36368. Color.TAN = freezeObject(Color.fromCssColorString('#D2B48C'));
  36369. /**
  36370. * An immutable Color instance initialized to CSS color #008080
  36371. * <span class="colorSwath" style="background: #008080;"></span>
  36372. *
  36373. * @constant
  36374. * @type {Color}
  36375. */
  36376. Color.TEAL = freezeObject(Color.fromCssColorString('#008080'));
  36377. /**
  36378. * An immutable Color instance initialized to CSS color #D8BFD8
  36379. * <span class="colorSwath" style="background: #D8BFD8;"></span>
  36380. *
  36381. * @constant
  36382. * @type {Color}
  36383. */
  36384. Color.THISTLE = freezeObject(Color.fromCssColorString('#D8BFD8'));
  36385. /**
  36386. * An immutable Color instance initialized to CSS color #FF6347
  36387. * <span class="colorSwath" style="background: #FF6347;"></span>
  36388. *
  36389. * @constant
  36390. * @type {Color}
  36391. */
  36392. Color.TOMATO = freezeObject(Color.fromCssColorString('#FF6347'));
  36393. /**
  36394. * An immutable Color instance initialized to CSS color #40E0D0
  36395. * <span class="colorSwath" style="background: #40E0D0;"></span>
  36396. *
  36397. * @constant
  36398. * @type {Color}
  36399. */
  36400. Color.TURQUOISE = freezeObject(Color.fromCssColorString('#40E0D0'));
  36401. /**
  36402. * An immutable Color instance initialized to CSS color #EE82EE
  36403. * <span class="colorSwath" style="background: #EE82EE;"></span>
  36404. *
  36405. * @constant
  36406. * @type {Color}
  36407. */
  36408. Color.VIOLET = freezeObject(Color.fromCssColorString('#EE82EE'));
  36409. /**
  36410. * An immutable Color instance initialized to CSS color #F5DEB3
  36411. * <span class="colorSwath" style="background: #F5DEB3;"></span>
  36412. *
  36413. * @constant
  36414. * @type {Color}
  36415. */
  36416. Color.WHEAT = freezeObject(Color.fromCssColorString('#F5DEB3'));
  36417. /**
  36418. * An immutable Color instance initialized to CSS color #FFFFFF
  36419. * <span class="colorSwath" style="background: #FFFFFF;"></span>
  36420. *
  36421. * @constant
  36422. * @type {Color}
  36423. */
  36424. Color.WHITE = freezeObject(Color.fromCssColorString('#FFFFFF'));
  36425. /**
  36426. * An immutable Color instance initialized to CSS color #F5F5F5
  36427. * <span class="colorSwath" style="background: #F5F5F5;"></span>
  36428. *
  36429. * @constant
  36430. * @type {Color}
  36431. */
  36432. Color.WHITESMOKE = freezeObject(Color.fromCssColorString('#F5F5F5'));
  36433. /**
  36434. * An immutable Color instance initialized to CSS color #FFFF00
  36435. * <span class="colorSwath" style="background: #FFFF00;"></span>
  36436. *
  36437. * @constant
  36438. * @type {Color}
  36439. */
  36440. Color.YELLOW = freezeObject(Color.fromCssColorString('#FFFF00'));
  36441. /**
  36442. * An immutable Color instance initialized to CSS color #9ACD32
  36443. * <span class="colorSwath" style="background: #9ACD32;"></span>
  36444. *
  36445. * @constant
  36446. * @type {Color}
  36447. */
  36448. Color.YELLOWGREEN = freezeObject(Color.fromCssColorString('#9ACD32'));
  36449. /**
  36450. * An immutable Color instance initialized to CSS transparent.
  36451. * <span class="colorSwath" style="background: transparent;"></span>
  36452. *
  36453. * @constant
  36454. * @type {Color}
  36455. */
  36456. Color.TRANSPARENT = freezeObject(new Color(0, 0, 0, 0));
  36457. return Color;
  36458. });
  36459. /*global define*/
  36460. define('Core/ColorGeometryInstanceAttribute',[
  36461. './Color',
  36462. './ComponentDatatype',
  36463. './defaultValue',
  36464. './defined',
  36465. './defineProperties',
  36466. './DeveloperError'
  36467. ], function(
  36468. Color,
  36469. ComponentDatatype,
  36470. defaultValue,
  36471. defined,
  36472. defineProperties,
  36473. DeveloperError) {
  36474. 'use strict';
  36475. /**
  36476. * Value and type information for per-instance geometry color.
  36477. *
  36478. * @alias ColorGeometryInstanceAttribute
  36479. * @constructor
  36480. *
  36481. * @param {Number} [red=1.0] The red component.
  36482. * @param {Number} [green=1.0] The green component.
  36483. * @param {Number} [blue=1.0] The blue component.
  36484. * @param {Number} [alpha=1.0] The alpha component.
  36485. *
  36486. *
  36487. * @example
  36488. * var instance = new Cesium.GeometryInstance({
  36489. * geometry : Cesium.BoxGeometry.fromDimensions({
  36490. * dimensions : new Cesium.Cartesian3(1000000.0, 1000000.0, 500000.0)
  36491. * }),
  36492. * modelMatrix : Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(
  36493. * Cesium.Cartesian3.fromDegrees(0.0, 0.0)), new Cesium.Cartesian3(0.0, 0.0, 1000000.0), new Cesium.Matrix4()),
  36494. * id : 'box',
  36495. * attributes : {
  36496. * color : new Cesium.ColorGeometryInstanceAttribute(red, green, blue, alpha)
  36497. * }
  36498. * });
  36499. *
  36500. * @see GeometryInstance
  36501. * @see GeometryInstanceAttribute
  36502. */
  36503. function ColorGeometryInstanceAttribute(red, green, blue, alpha) {
  36504. red = defaultValue(red, 1.0);
  36505. green = defaultValue(green, 1.0);
  36506. blue = defaultValue(blue, 1.0);
  36507. alpha = defaultValue(alpha, 1.0);
  36508. /**
  36509. * The values for the attributes stored in a typed array.
  36510. *
  36511. * @type Uint8Array
  36512. *
  36513. * @default [255, 255, 255, 255]
  36514. */
  36515. this.value = new Uint8Array([
  36516. Color.floatToByte(red),
  36517. Color.floatToByte(green),
  36518. Color.floatToByte(blue),
  36519. Color.floatToByte(alpha)
  36520. ]);
  36521. }
  36522. defineProperties(ColorGeometryInstanceAttribute.prototype, {
  36523. /**
  36524. * The datatype of each component in the attribute, e.g., individual elements in
  36525. * {@link ColorGeometryInstanceAttribute#value}.
  36526. *
  36527. * @memberof ColorGeometryInstanceAttribute.prototype
  36528. *
  36529. * @type {ComponentDatatype}
  36530. * @readonly
  36531. *
  36532. * @default {@link ComponentDatatype.UNSIGNED_BYTE}
  36533. */
  36534. componentDatatype : {
  36535. get : function() {
  36536. return ComponentDatatype.UNSIGNED_BYTE;
  36537. }
  36538. },
  36539. /**
  36540. * The number of components in the attributes, i.e., {@link ColorGeometryInstanceAttribute#value}.
  36541. *
  36542. * @memberof ColorGeometryInstanceAttribute.prototype
  36543. *
  36544. * @type {Number}
  36545. * @readonly
  36546. *
  36547. * @default 4
  36548. */
  36549. componentsPerAttribute : {
  36550. get : function() {
  36551. return 4;
  36552. }
  36553. },
  36554. /**
  36555. * When <code>true</code> and <code>componentDatatype</code> is an integer format,
  36556. * indicate that the components should be mapped to the range [0, 1] (unsigned)
  36557. * or [-1, 1] (signed) when they are accessed as floating-point for rendering.
  36558. *
  36559. * @memberof ColorGeometryInstanceAttribute.prototype
  36560. *
  36561. * @type {Boolean}
  36562. * @readonly
  36563. *
  36564. * @default true
  36565. */
  36566. normalize : {
  36567. get : function() {
  36568. return true;
  36569. }
  36570. }
  36571. });
  36572. /**
  36573. * Creates a new {@link ColorGeometryInstanceAttribute} instance given the provided {@link Color}.
  36574. *
  36575. * @param {Color} color The color.
  36576. * @returns {ColorGeometryInstanceAttribute} The new {@link ColorGeometryInstanceAttribute} instance.
  36577. *
  36578. * @example
  36579. * var instance = new Cesium.GeometryInstance({
  36580. * geometry : geometry,
  36581. * attributes : {
  36582. * color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.CORNFLOWERBLUE),
  36583. * }
  36584. * });
  36585. */
  36586. ColorGeometryInstanceAttribute.fromColor = function(color) {
  36587. if (!defined(color)) {
  36588. throw new DeveloperError('color is required.');
  36589. }
  36590. return new ColorGeometryInstanceAttribute(color.red, color.green, color.blue, color.alpha);
  36591. };
  36592. /**
  36593. * Converts a color to a typed array that can be used to assign a color attribute.
  36594. *
  36595. * @param {Color} color The color.
  36596. * @param {Uint8Array} [result] The array to store the result in, if undefined a new instance will be created.
  36597. *
  36598. * @returns {Uint8Array} The modified result parameter or a new instance if result was undefined.
  36599. *
  36600. * @example
  36601. * var attributes = primitive.getGeometryInstanceAttributes('an id');
  36602. * attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.AQUA, attributes.color);
  36603. */
  36604. ColorGeometryInstanceAttribute.toValue = function(color, result) {
  36605. if (!defined(color)) {
  36606. throw new DeveloperError('color is required.');
  36607. }
  36608. if (!defined(result)) {
  36609. return new Uint8Array(color.toBytes());
  36610. }
  36611. return color.toBytes(result);
  36612. };
  36613. /**
  36614. * Compares the provided ColorGeometryInstanceAttributes and returns
  36615. * <code>true</code> if they are equal, <code>false</code> otherwise.
  36616. *
  36617. * @param {ColorGeometryInstanceAttribute} [left] The first ColorGeometryInstanceAttribute.
  36618. * @param {ColorGeometryInstanceAttribute} [right] The second ColorGeometryInstanceAttribute.
  36619. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  36620. */
  36621. ColorGeometryInstanceAttribute.equals = function(left, right) {
  36622. return (left === right) ||
  36623. (defined(left) &&
  36624. defined(right) &&
  36625. left.value[0] === right.value[0] &&
  36626. left.value[1] === right.value[1] &&
  36627. left.value[2] === right.value[2] &&
  36628. left.value[3] === right.value[3]);
  36629. };
  36630. return ColorGeometryInstanceAttribute;
  36631. });
  36632. /*global define*/
  36633. define('Core/combine',[
  36634. './defaultValue',
  36635. './defined'
  36636. ], function(
  36637. defaultValue,
  36638. defined) {
  36639. 'use strict';
  36640. /**
  36641. * Merges two objects, copying their properties onto a new combined object. When two objects have the same
  36642. * property, the value of the property on the first object is used. If either object is undefined,
  36643. * it will be treated as an empty object.
  36644. *
  36645. * @example
  36646. * var object1 = {
  36647. * propOne : 1,
  36648. * propTwo : {
  36649. * value1 : 10
  36650. * }
  36651. * }
  36652. * var object2 = {
  36653. * propTwo : 2
  36654. * }
  36655. * var final = Cesium.combine(object1, object2);
  36656. *
  36657. * // final === {
  36658. * // propOne : 1,
  36659. * // propTwo : {
  36660. * // value1 : 10
  36661. * // }
  36662. * // }
  36663. *
  36664. * @param {Object} [object1] The first object to merge.
  36665. * @param {Object} [object2] The second object to merge.
  36666. * @param {Boolean} [deep=false] Perform a recursive merge.
  36667. * @returns {Object} The combined object containing all properties from both objects.
  36668. *
  36669. * @exports combine
  36670. */
  36671. function combine(object1, object2, deep) {
  36672. deep = defaultValue(deep, false);
  36673. var result = {};
  36674. var object1Defined = defined(object1);
  36675. var object2Defined = defined(object2);
  36676. var property;
  36677. var object1Value;
  36678. var object2Value;
  36679. if (object1Defined) {
  36680. for (property in object1) {
  36681. if (object1.hasOwnProperty(property)) {
  36682. object1Value = object1[property];
  36683. if (object2Defined && deep && typeof object1Value === 'object' && object2.hasOwnProperty(property)) {
  36684. object2Value = object2[property];
  36685. if (typeof object2Value === 'object') {
  36686. result[property] = combine(object1Value, object2Value, deep);
  36687. } else {
  36688. result[property] = object1Value;
  36689. }
  36690. } else {
  36691. result[property] = object1Value;
  36692. }
  36693. }
  36694. }
  36695. }
  36696. if (object2Defined) {
  36697. for (property in object2) {
  36698. if (object2.hasOwnProperty(property) && !result.hasOwnProperty(property)) {
  36699. object2Value = object2[property];
  36700. result[property] = object2Value;
  36701. }
  36702. }
  36703. }
  36704. return result;
  36705. }
  36706. return combine;
  36707. });
  36708. /*global define*/
  36709. define('Core/CornerType',[
  36710. './freezeObject'
  36711. ], function(
  36712. freezeObject) {
  36713. 'use strict';
  36714. /**
  36715. * Style options for corners.
  36716. *
  36717. * @demo The {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Corridor.html&label=Geometries|Corridor Demo}
  36718. * demonstrates the three corner types, as used by {@link CorridorGraphics}.
  36719. *
  36720. * @exports CornerType
  36721. */
  36722. var CornerType = {
  36723. /**
  36724. * <img src="images/CornerTypeRounded.png" style="vertical-align: middle;" width="186" height="189" />
  36725. *
  36726. * Corner has a smooth edge.
  36727. * @type {Number}
  36728. * @constant
  36729. */
  36730. ROUNDED : 0,
  36731. /**
  36732. * <img src="images/CornerTypeMitered.png" style="vertical-align: middle;" width="186" height="189" />
  36733. *
  36734. * Corner point is the intersection of adjacent edges.
  36735. * @type {Number}
  36736. * @constant
  36737. */
  36738. MITERED : 1,
  36739. /**
  36740. * <img src="images/CornerTypeBeveled.png" style="vertical-align: middle;" width="186" height="189" />
  36741. *
  36742. * Corner is clipped.
  36743. * @type {Number}
  36744. * @constant
  36745. */
  36746. BEVELED : 2
  36747. };
  36748. return freezeObject(CornerType);
  36749. });
  36750. /*global define*/
  36751. define('Core/EllipsoidGeodesic',[
  36752. './Cartesian3',
  36753. './Cartographic',
  36754. './defaultValue',
  36755. './defined',
  36756. './defineProperties',
  36757. './DeveloperError',
  36758. './Ellipsoid',
  36759. './Math'
  36760. ], function(
  36761. Cartesian3,
  36762. Cartographic,
  36763. defaultValue,
  36764. defined,
  36765. defineProperties,
  36766. DeveloperError,
  36767. Ellipsoid,
  36768. CesiumMath) {
  36769. 'use strict';
  36770. function setConstants(ellipsoidGeodesic) {
  36771. var uSquared = ellipsoidGeodesic._uSquared;
  36772. var a = ellipsoidGeodesic._ellipsoid.maximumRadius;
  36773. var b = ellipsoidGeodesic._ellipsoid.minimumRadius;
  36774. var f = (a - b) / a;
  36775. var cosineHeading = Math.cos(ellipsoidGeodesic._startHeading);
  36776. var sineHeading = Math.sin(ellipsoidGeodesic._startHeading);
  36777. var tanU = (1 - f) * Math.tan(ellipsoidGeodesic._start.latitude);
  36778. var cosineU = 1.0 / Math.sqrt(1.0 + tanU * tanU);
  36779. var sineU = cosineU * tanU;
  36780. var sigma = Math.atan2(tanU, cosineHeading);
  36781. var sineAlpha = cosineU * sineHeading;
  36782. var sineSquaredAlpha = sineAlpha * sineAlpha;
  36783. var cosineSquaredAlpha = 1.0 - sineSquaredAlpha;
  36784. var cosineAlpha = Math.sqrt(cosineSquaredAlpha);
  36785. var u2Over4 = uSquared / 4.0;
  36786. var u4Over16 = u2Over4 * u2Over4;
  36787. var u6Over64 = u4Over16 * u2Over4;
  36788. var u8Over256 = u4Over16 * u4Over16;
  36789. var a0 = (1.0 + u2Over4 - 3.0 * u4Over16 / 4.0 + 5.0 * u6Over64 / 4.0 - 175.0 * u8Over256 / 64.0);
  36790. var a1 = (1.0 - u2Over4 + 15.0 * u4Over16 / 8.0 - 35.0 * u6Over64 / 8.0);
  36791. var a2 = (1.0 - 3.0 * u2Over4 + 35.0 * u4Over16 / 4.0);
  36792. var a3 = (1.0 - 5.0 * u2Over4);
  36793. var distanceRatio = a0 * sigma - a1 * Math.sin(2.0 * sigma) * u2Over4 / 2.0 - a2 * Math.sin(4.0 * sigma) * u4Over16 / 16.0 -
  36794. a3 * Math.sin(6.0 * sigma) * u6Over64 / 48.0 - Math.sin(8.0 * sigma) * 5.0 * u8Over256 / 512;
  36795. var constants = ellipsoidGeodesic._constants;
  36796. constants.a = a;
  36797. constants.b = b;
  36798. constants.f = f;
  36799. constants.cosineHeading = cosineHeading;
  36800. constants.sineHeading = sineHeading;
  36801. constants.tanU = tanU;
  36802. constants.cosineU = cosineU;
  36803. constants.sineU = sineU;
  36804. constants.sigma = sigma;
  36805. constants.sineAlpha = sineAlpha;
  36806. constants.sineSquaredAlpha = sineSquaredAlpha;
  36807. constants.cosineSquaredAlpha = cosineSquaredAlpha;
  36808. constants.cosineAlpha = cosineAlpha;
  36809. constants.u2Over4 = u2Over4;
  36810. constants.u4Over16 = u4Over16;
  36811. constants.u6Over64 = u6Over64;
  36812. constants.u8Over256 = u8Over256;
  36813. constants.a0 = a0;
  36814. constants.a1 = a1;
  36815. constants.a2 = a2;
  36816. constants.a3 = a3;
  36817. constants.distanceRatio = distanceRatio;
  36818. }
  36819. function computeC(f, cosineSquaredAlpha) {
  36820. return f * cosineSquaredAlpha * (4.0 + f * (4.0 - 3.0 * cosineSquaredAlpha)) / 16.0;
  36821. }
  36822. function computeDeltaLambda(f, sineAlpha, cosineSquaredAlpha, sigma, sineSigma, cosineSigma, cosineTwiceSigmaMidpoint) {
  36823. var C = computeC(f, cosineSquaredAlpha);
  36824. return (1.0 - C) * f * sineAlpha * (sigma + C * sineSigma * (cosineTwiceSigmaMidpoint +
  36825. C * cosineSigma * (2.0 * cosineTwiceSigmaMidpoint * cosineTwiceSigmaMidpoint - 1.0)));
  36826. }
  36827. function vincentyInverseFormula(ellipsoidGeodesic, major, minor, firstLongitude, firstLatitude, secondLongitude, secondLatitude) {
  36828. var eff = (major - minor) / major;
  36829. var l = secondLongitude - firstLongitude;
  36830. var u1 = Math.atan((1 - eff) * Math.tan(firstLatitude));
  36831. var u2 = Math.atan((1 - eff) * Math.tan(secondLatitude));
  36832. var cosineU1 = Math.cos(u1);
  36833. var sineU1 = Math.sin(u1);
  36834. var cosineU2 = Math.cos(u2);
  36835. var sineU2 = Math.sin(u2);
  36836. var cc = cosineU1 * cosineU2;
  36837. var cs = cosineU1 * sineU2;
  36838. var ss = sineU1 * sineU2;
  36839. var sc = sineU1 * cosineU2;
  36840. var lambda = l;
  36841. var lambdaDot = CesiumMath.TWO_PI;
  36842. var cosineLambda = Math.cos(lambda);
  36843. var sineLambda = Math.sin(lambda);
  36844. var sigma;
  36845. var cosineSigma;
  36846. var sineSigma;
  36847. var cosineSquaredAlpha;
  36848. var cosineTwiceSigmaMidpoint;
  36849. do {
  36850. cosineLambda = Math.cos(lambda);
  36851. sineLambda = Math.sin(lambda);
  36852. var temp = cs - sc * cosineLambda;
  36853. sineSigma = Math.sqrt(cosineU2 * cosineU2 * sineLambda * sineLambda + temp * temp);
  36854. cosineSigma = ss + cc * cosineLambda;
  36855. sigma = Math.atan2(sineSigma, cosineSigma);
  36856. var sineAlpha;
  36857. if (sineSigma === 0.0) {
  36858. sineAlpha = 0.0;
  36859. cosineSquaredAlpha = 1.0;
  36860. } else {
  36861. sineAlpha = cc * sineLambda / sineSigma;
  36862. cosineSquaredAlpha = 1.0 - sineAlpha * sineAlpha;
  36863. }
  36864. lambdaDot = lambda;
  36865. cosineTwiceSigmaMidpoint = cosineSigma - 2.0 * ss / cosineSquaredAlpha;
  36866. if (isNaN(cosineTwiceSigmaMidpoint)) {
  36867. cosineTwiceSigmaMidpoint = 0.0;
  36868. }
  36869. lambda = l + computeDeltaLambda(eff, sineAlpha, cosineSquaredAlpha,
  36870. sigma, sineSigma, cosineSigma, cosineTwiceSigmaMidpoint);
  36871. } while (Math.abs(lambda - lambdaDot) > CesiumMath.EPSILON12);
  36872. var uSquared = cosineSquaredAlpha * (major * major - minor * minor) / (minor * minor);
  36873. var A = 1.0 + uSquared * (4096.0 + uSquared * (uSquared * (320.0 - 175.0 * uSquared) - 768.0)) / 16384.0;
  36874. var B = uSquared * (256.0 + uSquared * (uSquared * (74.0 - 47.0 * uSquared) - 128.0)) / 1024.0;
  36875. var cosineSquaredTwiceSigmaMidpoint = cosineTwiceSigmaMidpoint * cosineTwiceSigmaMidpoint;
  36876. var deltaSigma = B * sineSigma * (cosineTwiceSigmaMidpoint + B * (cosineSigma *
  36877. (2.0 * cosineSquaredTwiceSigmaMidpoint - 1.0) - B * cosineTwiceSigmaMidpoint *
  36878. (4.0 * sineSigma * sineSigma - 3.0) * (4.0 * cosineSquaredTwiceSigmaMidpoint - 3.0) / 6.0) / 4.0);
  36879. var distance = minor * A * (sigma - deltaSigma);
  36880. var startHeading = Math.atan2(cosineU2 * sineLambda, cs - sc * cosineLambda);
  36881. var endHeading = Math.atan2(cosineU1 * sineLambda, cs * cosineLambda - sc);
  36882. ellipsoidGeodesic._distance = distance;
  36883. ellipsoidGeodesic._startHeading = startHeading;
  36884. ellipsoidGeodesic._endHeading = endHeading;
  36885. ellipsoidGeodesic._uSquared = uSquared;
  36886. }
  36887. function computeProperties(ellipsoidGeodesic, start, end, ellipsoid) {
  36888. var firstCartesian = Cartesian3.normalize(ellipsoid.cartographicToCartesian(start, scratchCart2), scratchCart1);
  36889. var lastCartesian = Cartesian3.normalize(ellipsoid.cartographicToCartesian(end, scratchCart2), scratchCart2);
  36890. if (Math.abs(Math.abs(Cartesian3.angleBetween(firstCartesian, lastCartesian)) - Math.PI) < 0.0125) {
  36891. throw new DeveloperError('geodesic position is not unique');
  36892. }
  36893. vincentyInverseFormula(ellipsoidGeodesic, ellipsoid.maximumRadius, ellipsoid.minimumRadius,
  36894. start.longitude, start.latitude, end.longitude, end.latitude);
  36895. ellipsoidGeodesic._start = Cartographic.clone(start, ellipsoidGeodesic._start);
  36896. ellipsoidGeodesic._end = Cartographic.clone(end, ellipsoidGeodesic._end);
  36897. ellipsoidGeodesic._start.height = 0;
  36898. ellipsoidGeodesic._end.height = 0;
  36899. setConstants(ellipsoidGeodesic);
  36900. }
  36901. var scratchCart1 = new Cartesian3();
  36902. var scratchCart2 = new Cartesian3();
  36903. /**
  36904. * Initializes a geodesic on the ellipsoid connecting the two provided planetodetic points.
  36905. *
  36906. * @alias EllipsoidGeodesic
  36907. * @constructor
  36908. *
  36909. * @param {Cartographic} [start] The initial planetodetic point on the path.
  36910. * @param {Cartographic} [end] The final planetodetic point on the path.
  36911. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the geodesic lies.
  36912. */
  36913. function EllipsoidGeodesic(start, end, ellipsoid) {
  36914. var e = defaultValue(ellipsoid, Ellipsoid.WGS84);
  36915. this._ellipsoid = e;
  36916. this._start = new Cartographic();
  36917. this._end = new Cartographic();
  36918. this._constants = {};
  36919. this._startHeading = undefined;
  36920. this._endHeading = undefined;
  36921. this._distance = undefined;
  36922. this._uSquared = undefined;
  36923. if (defined(start) && defined(end)) {
  36924. computeProperties(this, start, end, e);
  36925. }
  36926. }
  36927. defineProperties(EllipsoidGeodesic.prototype, {
  36928. /**
  36929. * Gets the ellipsoid.
  36930. * @memberof EllipsoidGeodesic.prototype
  36931. * @type {Ellipsoid}
  36932. * @readonly
  36933. */
  36934. ellipsoid : {
  36935. get : function() {
  36936. return this._ellipsoid;
  36937. }
  36938. },
  36939. /**
  36940. * Gets the surface distance between the start and end point
  36941. * @memberof EllipsoidGeodesic.prototype
  36942. * @type {Number}
  36943. * @readonly
  36944. */
  36945. surfaceDistance : {
  36946. get : function() {
  36947. if (!defined(this._distance)) {
  36948. throw new DeveloperError('set end positions before getting surfaceDistance');
  36949. }
  36950. return this._distance;
  36951. }
  36952. },
  36953. /**
  36954. * Gets the initial planetodetic point on the path.
  36955. * @memberof EllipsoidGeodesic.prototype
  36956. * @type {Cartographic}
  36957. * @readonly
  36958. */
  36959. start : {
  36960. get : function() {
  36961. return this._start;
  36962. }
  36963. },
  36964. /**
  36965. * Gets the final planetodetic point on the path.
  36966. * @memberof EllipsoidGeodesic.prototype
  36967. * @type {Cartographic}
  36968. * @readonly
  36969. */
  36970. end : {
  36971. get : function() {
  36972. return this._end;
  36973. }
  36974. },
  36975. /**
  36976. * Gets the heading at the initial point.
  36977. * @memberof EllipsoidGeodesic.prototype
  36978. * @type {Number}
  36979. * @readonly
  36980. */
  36981. startHeading : {
  36982. get : function() {
  36983. if (!defined(this._distance)) {
  36984. throw new DeveloperError('set end positions before getting startHeading');
  36985. }
  36986. return this._startHeading;
  36987. }
  36988. },
  36989. /**
  36990. * Gets the heading at the final point.
  36991. * @memberof EllipsoidGeodesic.prototype
  36992. * @type {Number}
  36993. * @readonly
  36994. */
  36995. endHeading : {
  36996. get : function() {
  36997. if (!defined(this._distance)) {
  36998. throw new DeveloperError('set end positions before getting endHeading');
  36999. }
  37000. return this._endHeading;
  37001. }
  37002. }
  37003. });
  37004. /**
  37005. * Sets the start and end points of the geodesic
  37006. *
  37007. * @param {Cartographic} start The initial planetodetic point on the path.
  37008. * @param {Cartographic} end The final planetodetic point on the path.
  37009. */
  37010. EllipsoidGeodesic.prototype.setEndPoints = function(start, end) {
  37011. if (!defined(start)) {
  37012. throw new DeveloperError('start cartographic position is required');
  37013. }
  37014. if (!defined(end)) {
  37015. throw new DeveloperError('end cartgraphic position is required');
  37016. }
  37017. computeProperties(this, start, end, this._ellipsoid);
  37018. };
  37019. /**
  37020. * Provides the location of a point at the indicated portion along the geodesic.
  37021. *
  37022. * @param {Number} fraction The portion of the distance between the initial and final points.
  37023. * @returns {Cartographic} The location of the point along the geodesic.
  37024. */
  37025. EllipsoidGeodesic.prototype.interpolateUsingFraction = function(fraction, result) {
  37026. return this.interpolateUsingSurfaceDistance(this._distance * fraction, result);
  37027. };
  37028. /**
  37029. * Provides the location of a point at the indicated distance along the geodesic.
  37030. *
  37031. * @param {Number} distance The distance from the inital point to the point of interest along the geodesic
  37032. * @returns {Cartographic} The location of the point along the geodesic.
  37033. *
  37034. * @exception {DeveloperError} start and end must be set before calling function interpolateUsingSurfaceDistance
  37035. */
  37036. EllipsoidGeodesic.prototype.interpolateUsingSurfaceDistance = function(distance, result) {
  37037. if (!defined(this._distance)) {
  37038. throw new DeveloperError('start and end must be set before calling function interpolateUsingSurfaceDistance');
  37039. }
  37040. var constants = this._constants;
  37041. var s = constants.distanceRatio + distance / constants.b;
  37042. var cosine2S = Math.cos(2.0 * s);
  37043. var cosine4S = Math.cos(4.0 * s);
  37044. var cosine6S = Math.cos(6.0 * s);
  37045. var sine2S = Math.sin(2.0 * s);
  37046. var sine4S = Math.sin(4.0 * s);
  37047. var sine6S = Math.sin(6.0 * s);
  37048. var sine8S = Math.sin(8.0 * s);
  37049. var s2 = s * s;
  37050. var s3 = s * s2;
  37051. var u8Over256 = constants.u8Over256;
  37052. var u2Over4 = constants.u2Over4;
  37053. var u6Over64 = constants.u6Over64;
  37054. var u4Over16 = constants.u4Over16;
  37055. var sigma = 2.0 * s3 * u8Over256 * cosine2S / 3.0 +
  37056. s * (1.0 - u2Over4 + 7.0 * u4Over16 / 4.0 - 15.0 * u6Over64 / 4.0 + 579.0 * u8Over256 / 64.0 -
  37057. (u4Over16 - 15.0 * u6Over64 / 4.0 + 187.0 * u8Over256 / 16.0) * cosine2S -
  37058. (5.0 * u6Over64 / 4.0 - 115.0 * u8Over256 / 16.0) * cosine4S -
  37059. 29.0 * u8Over256 * cosine6S / 16.0) +
  37060. (u2Over4 / 2.0 - u4Over16 + 71.0 * u6Over64 / 32.0 - 85.0 * u8Over256 / 16.0) * sine2S +
  37061. (5.0 * u4Over16 / 16.0 - 5.0 * u6Over64 / 4.0 + 383.0 * u8Over256 / 96.0) * sine4S -
  37062. s2 * ((u6Over64 - 11.0 * u8Over256 / 2.0) * sine2S + 5.0 * u8Over256 * sine4S / 2.0) +
  37063. (29.0 * u6Over64 / 96.0 - 29.0 * u8Over256 / 16.0) * sine6S +
  37064. 539.0 * u8Over256 * sine8S / 1536.0;
  37065. var theta = Math.asin(Math.sin(sigma) * constants.cosineAlpha);
  37066. var latitude = Math.atan(constants.a / constants.b * Math.tan(theta));
  37067. // Redefine in terms of relative argument of latitude.
  37068. sigma = sigma - constants.sigma;
  37069. var cosineTwiceSigmaMidpoint = Math.cos(2.0 * constants.sigma + sigma);
  37070. var sineSigma = Math.sin(sigma);
  37071. var cosineSigma = Math.cos(sigma);
  37072. var cc = constants.cosineU * cosineSigma;
  37073. var ss = constants.sineU * sineSigma;
  37074. var lambda = Math.atan2(sineSigma * constants.sineHeading, cc - ss * constants.cosineHeading);
  37075. var l = lambda - computeDeltaLambda(constants.f, constants.sineAlpha, constants.cosineSquaredAlpha,
  37076. sigma, sineSigma, cosineSigma, cosineTwiceSigmaMidpoint);
  37077. if (defined(result)) {
  37078. result.longitude = this._start.longitude + l;
  37079. result.latitude = latitude;
  37080. result.height = 0.0;
  37081. return result;
  37082. }
  37083. return new Cartographic(this._start.longitude + l, latitude, 0.0);
  37084. };
  37085. return EllipsoidGeodesic;
  37086. });
  37087. /*global define*/
  37088. define('Core/PolylinePipeline',[
  37089. './Cartesian3',
  37090. './Cartographic',
  37091. './defaultValue',
  37092. './defined',
  37093. './DeveloperError',
  37094. './Ellipsoid',
  37095. './EllipsoidGeodesic',
  37096. './IntersectionTests',
  37097. './isArray',
  37098. './Math',
  37099. './Matrix4',
  37100. './Plane'
  37101. ], function(
  37102. Cartesian3,
  37103. Cartographic,
  37104. defaultValue,
  37105. defined,
  37106. DeveloperError,
  37107. Ellipsoid,
  37108. EllipsoidGeodesic,
  37109. IntersectionTests,
  37110. isArray,
  37111. CesiumMath,
  37112. Matrix4,
  37113. Plane) {
  37114. 'use strict';
  37115. /**
  37116. * @private
  37117. */
  37118. var PolylinePipeline = {};
  37119. PolylinePipeline.numberOfPoints = function(p0, p1, minDistance) {
  37120. var distance = Cartesian3.distance(p0, p1);
  37121. return Math.ceil(distance / minDistance);
  37122. };
  37123. var cartoScratch = new Cartographic();
  37124. PolylinePipeline.extractHeights = function(positions, ellipsoid) {
  37125. var length = positions.length;
  37126. var heights = new Array(length);
  37127. for (var i = 0; i < length; i++) {
  37128. var p = positions[i];
  37129. heights[i] = ellipsoid.cartesianToCartographic(p, cartoScratch).height;
  37130. }
  37131. return heights;
  37132. };
  37133. var wrapLongitudeInversMatrix = new Matrix4();
  37134. var wrapLongitudeOrigin = new Cartesian3();
  37135. var wrapLongitudeXZNormal = new Cartesian3();
  37136. var wrapLongitudeXZPlane = new Plane(Cartesian3.ZERO, 0.0);
  37137. var wrapLongitudeYZNormal = new Cartesian3();
  37138. var wrapLongitudeYZPlane = new Plane(Cartesian3.ZERO, 0.0);
  37139. var wrapLongitudeIntersection = new Cartesian3();
  37140. var wrapLongitudeOffset = new Cartesian3();
  37141. var subdivideHeightsScratchArray = [];
  37142. function subdivideHeights(numPoints, h0, h1) {
  37143. var heights = subdivideHeightsScratchArray;
  37144. heights.length = numPoints;
  37145. var i;
  37146. if (h0 === h1) {
  37147. for (i = 0; i < numPoints; i++) {
  37148. heights[i] = h0;
  37149. }
  37150. return heights;
  37151. }
  37152. var dHeight = h1 - h0;
  37153. var heightPerVertex = dHeight / numPoints;
  37154. for (i = 0; i < numPoints; i++) {
  37155. var h = h0 + i*heightPerVertex;
  37156. heights[i] = h;
  37157. }
  37158. return heights;
  37159. }
  37160. var carto1 = new Cartographic();
  37161. var carto2 = new Cartographic();
  37162. var cartesian = new Cartesian3();
  37163. var scaleFirst = new Cartesian3();
  37164. var scaleLast = new Cartesian3();
  37165. var ellipsoidGeodesic = new EllipsoidGeodesic();
  37166. //Returns subdivided line scaled to ellipsoid surface starting at p1 and ending at p2.
  37167. //Result includes p1, but not include p2. This function is called for a sequence of line segments,
  37168. //and this prevents duplication of end point.
  37169. function generateCartesianArc(p0, p1, minDistance, ellipsoid, h0, h1, array, offset) {
  37170. var first = ellipsoid.scaleToGeodeticSurface(p0, scaleFirst);
  37171. var last = ellipsoid.scaleToGeodeticSurface(p1, scaleLast);
  37172. var numPoints = PolylinePipeline.numberOfPoints(p0, p1, minDistance);
  37173. var start = ellipsoid.cartesianToCartographic(first, carto1);
  37174. var end = ellipsoid.cartesianToCartographic(last, carto2);
  37175. var heights = subdivideHeights(numPoints, h0, h1);
  37176. ellipsoidGeodesic.setEndPoints(start, end);
  37177. var surfaceDistanceBetweenPoints = ellipsoidGeodesic.surfaceDistance / numPoints;
  37178. var index = offset;
  37179. start.height = h0;
  37180. var cart = ellipsoid.cartographicToCartesian(start, cartesian);
  37181. Cartesian3.pack(cart, array, index);
  37182. index += 3;
  37183. for (var i = 1; i < numPoints; i++) {
  37184. var carto = ellipsoidGeodesic.interpolateUsingSurfaceDistance(i * surfaceDistanceBetweenPoints, carto2);
  37185. carto.height = heights[i];
  37186. cart = ellipsoid.cartographicToCartesian(carto, cartesian);
  37187. Cartesian3.pack(cart, array, index);
  37188. index += 3;
  37189. }
  37190. return index;
  37191. }
  37192. /**
  37193. * Breaks a {@link Polyline} into segments such that it does not cross the &plusmn;180 degree meridian of an ellipsoid.
  37194. *
  37195. * @param {Cartesian3[]} positions The polyline's Cartesian positions.
  37196. * @param {Matrix4} [modelMatrix=Matrix4.IDENTITY] The polyline's model matrix. Assumed to be an affine
  37197. * transformation matrix, where the upper left 3x3 elements are a rotation matrix, and
  37198. * the upper three elements in the fourth column are the translation. The bottom row is assumed to be [0, 0, 0, 1].
  37199. * The matrix is not verified to be in the proper form.
  37200. * @returns {Object} An object with a <code>positions</code> property that is an array of positions and a
  37201. * <code>segments</code> property.
  37202. *
  37203. *
  37204. * @example
  37205. * var polylines = new Cesium.PolylineCollection();
  37206. * var polyline = polylines.add(...);
  37207. * var positions = polyline.positions;
  37208. * var modelMatrix = polylines.modelMatrix;
  37209. * var segments = Cesium.PolylinePipeline.wrapLongitude(positions, modelMatrix);
  37210. *
  37211. * @see PolygonPipeline.wrapLongitude
  37212. * @see Polyline
  37213. * @see PolylineCollection
  37214. */
  37215. PolylinePipeline.wrapLongitude = function(positions, modelMatrix) {
  37216. var cartesians = [];
  37217. var segments = [];
  37218. if (defined(positions) && positions.length > 0) {
  37219. modelMatrix = defaultValue(modelMatrix, Matrix4.IDENTITY);
  37220. var inverseModelMatrix = Matrix4.inverseTransformation(modelMatrix, wrapLongitudeInversMatrix);
  37221. var origin = Matrix4.multiplyByPoint(inverseModelMatrix, Cartesian3.ZERO, wrapLongitudeOrigin);
  37222. var xzNormal = Matrix4.multiplyByPointAsVector(inverseModelMatrix, Cartesian3.UNIT_Y, wrapLongitudeXZNormal);
  37223. var xzPlane = Plane.fromPointNormal(origin, xzNormal, wrapLongitudeXZPlane);
  37224. var yzNormal = Matrix4.multiplyByPointAsVector(inverseModelMatrix, Cartesian3.UNIT_X, wrapLongitudeYZNormal);
  37225. var yzPlane = Plane.fromPointNormal(origin, yzNormal, wrapLongitudeYZPlane);
  37226. var count = 1;
  37227. cartesians.push(Cartesian3.clone(positions[0]));
  37228. var prev = cartesians[0];
  37229. var length = positions.length;
  37230. for (var i = 1; i < length; ++i) {
  37231. var cur = positions[i];
  37232. // intersects the IDL if either endpoint is on the negative side of the yz-plane
  37233. if (Plane.getPointDistance(yzPlane, prev) < 0.0 || Plane.getPointDistance(yzPlane, cur) < 0.0) {
  37234. // and intersects the xz-plane
  37235. var intersection = IntersectionTests.lineSegmentPlane(prev, cur, xzPlane, wrapLongitudeIntersection);
  37236. if (defined(intersection)) {
  37237. // move point on the xz-plane slightly away from the plane
  37238. var offset = Cartesian3.multiplyByScalar(xzNormal, 5.0e-9, wrapLongitudeOffset);
  37239. if (Plane.getPointDistance(xzPlane, prev) < 0.0) {
  37240. Cartesian3.negate(offset, offset);
  37241. }
  37242. cartesians.push(Cartesian3.add(intersection, offset, new Cartesian3()));
  37243. segments.push(count + 1);
  37244. Cartesian3.negate(offset, offset);
  37245. cartesians.push(Cartesian3.add(intersection, offset, new Cartesian3()));
  37246. count = 1;
  37247. }
  37248. }
  37249. cartesians.push(Cartesian3.clone(positions[i]));
  37250. count++;
  37251. prev = cur;
  37252. }
  37253. segments.push(count);
  37254. }
  37255. return {
  37256. positions : cartesians,
  37257. lengths : segments
  37258. };
  37259. };
  37260. /**
  37261. * Subdivides polyline and raises all points to the specified height. Returns an array of numbers to represent the positions.
  37262. * @param {Cartesian3[]} positions The array of type {Cartesian3} representing positions.
  37263. * @param {Number|Number[]} [height=0.0] A number or array of numbers representing the heights of each position.
  37264. * @param {Number} [granularity = CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  37265. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the positions lie.
  37266. * @returns {Number[]} A new array of positions of type {Number} that have been subdivided and raised to the surface of the ellipsoid.
  37267. *
  37268. * @example
  37269. * var positions = Cesium.Cartesian3.fromDegreesArray([
  37270. * -105.0, 40.0,
  37271. * -100.0, 38.0,
  37272. * -105.0, 35.0,
  37273. * -100.0, 32.0
  37274. * ]);
  37275. * var surfacePositions = Cesium.PolylinePipeline.generateArc({
  37276. * positons: positions
  37277. * });
  37278. */
  37279. PolylinePipeline.generateArc = function(options) {
  37280. if (!defined(options)) {
  37281. options = {};
  37282. }
  37283. var positions = options.positions;
  37284. if (!defined(positions)) {
  37285. throw new DeveloperError('options.positions is required.');
  37286. }
  37287. var length = positions.length;
  37288. var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  37289. var height = defaultValue(options.height, 0);
  37290. var hasHeightArray = isArray(height);
  37291. if (length < 1) {
  37292. return [];
  37293. } else if (length === 1) {
  37294. var p = ellipsoid.scaleToGeodeticSurface(positions[0], scaleFirst);
  37295. height = hasHeightArray ? height[0] : height;
  37296. if (height !== 0) {
  37297. var n = ellipsoid.geodeticSurfaceNormal(p, cartesian);
  37298. Cartesian3.multiplyByScalar(n, height, n);
  37299. Cartesian3.add(p, n, p);
  37300. }
  37301. return [p.x, p.y, p.z];
  37302. }
  37303. var minDistance = options.minDistance;
  37304. if (!defined(minDistance)) {
  37305. var granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  37306. minDistance = CesiumMath.chordLength(granularity, ellipsoid.maximumRadius);
  37307. }
  37308. var numPoints = 0;
  37309. var i;
  37310. for (i = 0; i < length -1; i++) {
  37311. numPoints += PolylinePipeline.numberOfPoints(positions[i], positions[i+1], minDistance);
  37312. }
  37313. var arrayLength = (numPoints + 1) * 3;
  37314. var newPositions = new Array(arrayLength);
  37315. var offset = 0;
  37316. for (i = 0; i < length - 1; i++) {
  37317. var p0 = positions[i];
  37318. var p1 = positions[i + 1];
  37319. var h0 = hasHeightArray ? height[i] : height;
  37320. var h1 = hasHeightArray ? height[i + 1] : height;
  37321. offset = generateCartesianArc(p0, p1, minDistance, ellipsoid, h0, h1, newPositions, offset);
  37322. }
  37323. subdivideHeightsScratchArray.length = 0;
  37324. var lastPoint = positions[length - 1];
  37325. var carto = ellipsoid.cartesianToCartographic(lastPoint, carto1);
  37326. carto.height = hasHeightArray ? height[length - 1] : height;
  37327. var cart = ellipsoid.cartographicToCartesian(carto, cartesian);
  37328. Cartesian3.pack(cart, newPositions, arrayLength - 3);
  37329. return newPositions;
  37330. };
  37331. /**
  37332. * Subdivides polyline and raises all points to the specified height. Returns an array of new {Cartesian3} positions.
  37333. * @param {Cartesian3[]} positions The array of type {Cartesian3} representing positions.
  37334. * @param {Number|Number[]} [height=0.0] A number or array of numbers representing the heights of each position.
  37335. * @param {Number} [granularity = CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  37336. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the positions lie.
  37337. * @returns {Cartesian3[]} A new array of cartesian3 positions that have been subdivided and raised to the surface of the ellipsoid.
  37338. *
  37339. * @example
  37340. * var positions = Cesium.Cartesian3.fromDegreesArray([
  37341. * -105.0, 40.0,
  37342. * -100.0, 38.0,
  37343. * -105.0, 35.0,
  37344. * -100.0, 32.0
  37345. * ]);
  37346. * var surfacePositions = Cesium.PolylinePipeline.generateCartesianArc({
  37347. * positons: positions
  37348. * });
  37349. */
  37350. PolylinePipeline.generateCartesianArc = function(options) {
  37351. var numberArray = PolylinePipeline.generateArc(options);
  37352. var size = numberArray.length/3;
  37353. var newPositions = new Array(size);
  37354. for (var i = 0; i < size; i++) {
  37355. newPositions[i] = Cartesian3.unpack(numberArray, i*3);
  37356. }
  37357. return newPositions;
  37358. };
  37359. return PolylinePipeline;
  37360. });
  37361. /*global define*/
  37362. define('Core/PolylineVolumeGeometryLibrary',[
  37363. './Cartesian2',
  37364. './Cartesian3',
  37365. './Cartesian4',
  37366. './Cartographic',
  37367. './CornerType',
  37368. './EllipsoidTangentPlane',
  37369. './Math',
  37370. './Matrix3',
  37371. './Matrix4',
  37372. './PolylinePipeline',
  37373. './Quaternion',
  37374. './Transforms'
  37375. ], function(
  37376. Cartesian2,
  37377. Cartesian3,
  37378. Cartesian4,
  37379. Cartographic,
  37380. CornerType,
  37381. EllipsoidTangentPlane,
  37382. CesiumMath,
  37383. Matrix3,
  37384. Matrix4,
  37385. PolylinePipeline,
  37386. Quaternion,
  37387. Transforms) {
  37388. 'use strict';
  37389. var scratch2Array = [new Cartesian3(), new Cartesian3()];
  37390. var scratchCartesian1 = new Cartesian3();
  37391. var scratchCartesian2 = new Cartesian3();
  37392. var scratchCartesian3 = new Cartesian3();
  37393. var scratchCartesian4 = new Cartesian3();
  37394. var scratchCartesian5 = new Cartesian3();
  37395. var scratchCartesian6 = new Cartesian3();
  37396. var scratchCartesian7 = new Cartesian3();
  37397. var scratchCartesian8 = new Cartesian3();
  37398. var scratchCartesian9 = new Cartesian3();
  37399. var scratch1 = new Cartesian3();
  37400. var scratch2 = new Cartesian3();
  37401. /**
  37402. * @private
  37403. */
  37404. var PolylineVolumeGeometryLibrary = {};
  37405. var cartographic = new Cartographic();
  37406. function scaleToSurface(positions, ellipsoid) {
  37407. var heights = new Array(positions.length);
  37408. for (var i = 0; i < positions.length; i++) {
  37409. var pos = positions[i];
  37410. cartographic = ellipsoid.cartesianToCartographic(pos, cartographic);
  37411. heights[i] = cartographic.height;
  37412. positions[i] = ellipsoid.scaleToGeodeticSurface(pos, pos);
  37413. }
  37414. return heights;
  37415. }
  37416. function subdivideHeights(points, h0, h1, granularity) {
  37417. var p0 = points[0];
  37418. var p1 = points[1];
  37419. var angleBetween = Cartesian3.angleBetween(p0, p1);
  37420. var numPoints = Math.ceil(angleBetween / granularity);
  37421. var heights = new Array(numPoints);
  37422. var i;
  37423. if (h0 === h1) {
  37424. for (i = 0; i < numPoints; i++) {
  37425. heights[i] = h0;
  37426. }
  37427. heights.push(h1);
  37428. return heights;
  37429. }
  37430. var dHeight = h1 - h0;
  37431. var heightPerVertex = dHeight / (numPoints);
  37432. for (i = 1; i < numPoints; i++) {
  37433. var h = h0 + i * heightPerVertex;
  37434. heights[i] = h;
  37435. }
  37436. heights[0] = h0;
  37437. heights.push(h1);
  37438. return heights;
  37439. }
  37440. function computeRotationAngle(start, end, position, ellipsoid) {
  37441. var tangentPlane = new EllipsoidTangentPlane(position, ellipsoid);
  37442. var next = tangentPlane.projectPointOntoPlane(Cartesian3.add(position, start, nextScratch), nextScratch);
  37443. var prev = tangentPlane.projectPointOntoPlane(Cartesian3.add(position, end, prevScratch), prevScratch);
  37444. var angle = Cartesian2.angleBetween(next, prev);
  37445. return (prev.x * next.y - prev.y * next.x >= 0.0) ? -angle : angle;
  37446. }
  37447. var negativeX = new Cartesian3(-1, 0, 0);
  37448. var transform = new Matrix4();
  37449. var translation = new Matrix4();
  37450. var rotationZ = new Matrix3();
  37451. var scaleMatrix = Matrix3.IDENTITY.clone();
  37452. var westScratch = new Cartesian3();
  37453. var finalPosScratch = new Cartesian4();
  37454. var heightCartesian = new Cartesian3();
  37455. function addPosition(center, left, shape, finalPositions, ellipsoid, height, xScalar, repeat) {
  37456. var west = westScratch;
  37457. var finalPosition = finalPosScratch;
  37458. transform = Transforms.eastNorthUpToFixedFrame(center, ellipsoid, transform);
  37459. west = Matrix4.multiplyByPointAsVector(transform, negativeX, west);
  37460. west = Cartesian3.normalize(west, west);
  37461. var angle = computeRotationAngle(west, left, center, ellipsoid);
  37462. rotationZ = Matrix3.fromRotationZ(angle, rotationZ);
  37463. heightCartesian.z = height;
  37464. transform = Matrix4.multiplyTransformation(transform, Matrix4.fromRotationTranslation(rotationZ, heightCartesian, translation), transform);
  37465. var scale = scaleMatrix;
  37466. scale[0] = xScalar;
  37467. for (var j = 0; j < repeat; j++) {
  37468. for (var i = 0; i < shape.length; i += 3) {
  37469. finalPosition = Cartesian3.fromArray(shape, i, finalPosition);
  37470. finalPosition = Matrix3.multiplyByVector(scale, finalPosition, finalPosition);
  37471. finalPosition = Matrix4.multiplyByPoint(transform, finalPosition, finalPosition);
  37472. finalPositions.push(finalPosition.x, finalPosition.y, finalPosition.z);
  37473. }
  37474. }
  37475. return finalPositions;
  37476. }
  37477. var centerScratch = new Cartesian3();
  37478. function addPositions(centers, left, shape, finalPositions, ellipsoid, heights, xScalar) {
  37479. for (var i = 0; i < centers.length; i += 3) {
  37480. var center = Cartesian3.fromArray(centers, i, centerScratch);
  37481. finalPositions = addPosition(center, left, shape, finalPositions, ellipsoid, heights[i / 3], xScalar, 1);
  37482. }
  37483. return finalPositions;
  37484. }
  37485. function convertShapeTo3DDuplicate(shape2D, boundingRectangle) { //orientate 2D shape to XZ plane center at (0, 0, 0), duplicate points
  37486. var length = shape2D.length;
  37487. var shape = new Array(length * 6);
  37488. var index = 0;
  37489. var xOffset = boundingRectangle.x + boundingRectangle.width / 2;
  37490. var yOffset = boundingRectangle.y + boundingRectangle.height / 2;
  37491. var point = shape2D[0];
  37492. shape[index++] = point.x - xOffset;
  37493. shape[index++] = 0.0;
  37494. shape[index++] = point.y - yOffset;
  37495. for (var i = 1; i < length; i++) {
  37496. point = shape2D[i];
  37497. var x = point.x - xOffset;
  37498. var z = point.y - yOffset;
  37499. shape[index++] = x;
  37500. shape[index++] = 0.0;
  37501. shape[index++] = z;
  37502. shape[index++] = x;
  37503. shape[index++] = 0.0;
  37504. shape[index++] = z;
  37505. }
  37506. point = shape2D[0];
  37507. shape[index++] = point.x - xOffset;
  37508. shape[index++] = 0.0;
  37509. shape[index++] = point.y - yOffset;
  37510. return shape;
  37511. }
  37512. function convertShapeTo3D(shape2D, boundingRectangle) { //orientate 2D shape to XZ plane center at (0, 0, 0)
  37513. var length = shape2D.length;
  37514. var shape = new Array(length * 3);
  37515. var index = 0;
  37516. var xOffset = boundingRectangle.x + boundingRectangle.width / 2;
  37517. var yOffset = boundingRectangle.y + boundingRectangle.height / 2;
  37518. for (var i = 0; i < length; i++) {
  37519. shape[index++] = shape2D[i].x - xOffset;
  37520. shape[index++] = 0;
  37521. shape[index++] = shape2D[i].y - yOffset;
  37522. }
  37523. return shape;
  37524. }
  37525. var quaterion = new Quaternion();
  37526. var startPointScratch = new Cartesian3();
  37527. var rotMatrix = new Matrix3();
  37528. function computeRoundCorner(pivot, startPoint, endPoint, cornerType, leftIsOutside, ellipsoid, finalPositions, shape, height, duplicatePoints) {
  37529. var angle = Cartesian3.angleBetween(Cartesian3.subtract(startPoint, pivot, scratch1), Cartesian3.subtract(endPoint, pivot, scratch2));
  37530. var granularity = (cornerType === CornerType.BEVELED) ? 0 : Math.ceil(angle / CesiumMath.toRadians(5));
  37531. var m;
  37532. if (leftIsOutside) {
  37533. m = Matrix3.fromQuaternion(Quaternion.fromAxisAngle(Cartesian3.negate(pivot, scratch1), angle / (granularity + 1), quaterion), rotMatrix);
  37534. } else {
  37535. m = Matrix3.fromQuaternion(Quaternion.fromAxisAngle(pivot, angle / (granularity + 1), quaterion), rotMatrix);
  37536. }
  37537. var left;
  37538. var surfacePoint;
  37539. startPoint = Cartesian3.clone(startPoint, startPointScratch);
  37540. if (granularity > 0) {
  37541. var repeat = duplicatePoints ? 2 : 1;
  37542. for (var i = 0; i < granularity; i++) {
  37543. startPoint = Matrix3.multiplyByVector(m, startPoint, startPoint);
  37544. left = Cartesian3.subtract(startPoint, pivot, scratch1);
  37545. left = Cartesian3.normalize(left, left);
  37546. if (!leftIsOutside) {
  37547. left = Cartesian3.negate(left, left);
  37548. }
  37549. surfacePoint = ellipsoid.scaleToGeodeticSurface(startPoint, scratch2);
  37550. finalPositions = addPosition(surfacePoint, left, shape, finalPositions, ellipsoid, height, 1, repeat);
  37551. }
  37552. } else {
  37553. left = Cartesian3.subtract(startPoint, pivot, scratch1);
  37554. left = Cartesian3.normalize(left, left);
  37555. if (!leftIsOutside) {
  37556. left = Cartesian3.negate(left, left);
  37557. }
  37558. surfacePoint = ellipsoid.scaleToGeodeticSurface(startPoint, scratch2);
  37559. finalPositions = addPosition(surfacePoint, left, shape, finalPositions, ellipsoid, height, 1, 1);
  37560. endPoint = Cartesian3.clone(endPoint, startPointScratch);
  37561. left = Cartesian3.subtract(endPoint, pivot, scratch1);
  37562. left = Cartesian3.normalize(left, left);
  37563. if (!leftIsOutside) {
  37564. left = Cartesian3.negate(left, left);
  37565. }
  37566. surfacePoint = ellipsoid.scaleToGeodeticSurface(endPoint, scratch2);
  37567. finalPositions = addPosition(surfacePoint, left, shape, finalPositions, ellipsoid, height, 1, 1);
  37568. }
  37569. return finalPositions;
  37570. }
  37571. PolylineVolumeGeometryLibrary.removeDuplicatesFromShape = function(shapePositions) {
  37572. var length = shapePositions.length;
  37573. var cleanedPositions = [];
  37574. for (var i0 = length - 1, i1 = 0; i1 < length; i0 = i1++) {
  37575. var v0 = shapePositions[i0];
  37576. var v1 = shapePositions[i1];
  37577. if (!Cartesian2.equals(v0, v1)) {
  37578. cleanedPositions.push(v1); // Shallow copy!
  37579. }
  37580. }
  37581. return cleanedPositions;
  37582. };
  37583. var nextScratch = new Cartesian3();
  37584. var prevScratch = new Cartesian3();
  37585. PolylineVolumeGeometryLibrary.angleIsGreaterThanPi = function(forward, backward, position, ellipsoid) {
  37586. var tangentPlane = new EllipsoidTangentPlane(position, ellipsoid);
  37587. var next = tangentPlane.projectPointOntoPlane(Cartesian3.add(position, forward, nextScratch), nextScratch);
  37588. var prev = tangentPlane.projectPointOntoPlane(Cartesian3.add(position, backward, prevScratch), prevScratch);
  37589. return ((prev.x * next.y) - (prev.y * next.x)) >= 0.0;
  37590. };
  37591. var scratchForwardProjection = new Cartesian3();
  37592. var scratchBackwardProjection = new Cartesian3();
  37593. PolylineVolumeGeometryLibrary.computePositions = function(positions, shape2D, boundingRectangle, geometry, duplicatePoints) {
  37594. var ellipsoid = geometry._ellipsoid;
  37595. var heights = scaleToSurface(positions, ellipsoid);
  37596. var granularity = geometry._granularity;
  37597. var cornerType = geometry._cornerType;
  37598. var shapeForSides = duplicatePoints ? convertShapeTo3DDuplicate(shape2D, boundingRectangle) : convertShapeTo3D(shape2D, boundingRectangle);
  37599. var shapeForEnds = duplicatePoints ? convertShapeTo3D(shape2D, boundingRectangle) : undefined;
  37600. var heightOffset = boundingRectangle.height / 2;
  37601. var width = boundingRectangle.width / 2;
  37602. var length = positions.length;
  37603. var finalPositions = [];
  37604. var ends = duplicatePoints ? [] : undefined;
  37605. var forward = scratchCartesian1;
  37606. var backward = scratchCartesian2;
  37607. var cornerDirection = scratchCartesian3;
  37608. var surfaceNormal = scratchCartesian4;
  37609. var pivot = scratchCartesian5;
  37610. var start = scratchCartesian6;
  37611. var end = scratchCartesian7;
  37612. var left = scratchCartesian8;
  37613. var previousPosition = scratchCartesian9;
  37614. var position = positions[0];
  37615. var nextPosition = positions[1];
  37616. surfaceNormal = ellipsoid.geodeticSurfaceNormal(position, surfaceNormal);
  37617. forward = Cartesian3.subtract(nextPosition, position, forward);
  37618. forward = Cartesian3.normalize(forward, forward);
  37619. left = Cartesian3.cross(surfaceNormal, forward, left);
  37620. left = Cartesian3.normalize(left, left);
  37621. var h0 = heights[0];
  37622. var h1 = heights[1];
  37623. if (duplicatePoints) {
  37624. ends = addPosition(position, left, shapeForEnds, ends, ellipsoid, h0 + heightOffset, 1, 1);
  37625. }
  37626. previousPosition = Cartesian3.clone(position, previousPosition);
  37627. position = nextPosition;
  37628. backward = Cartesian3.negate(forward, backward);
  37629. var subdividedHeights;
  37630. var subdividedPositions;
  37631. for (var i = 1; i < length - 1; i++) {
  37632. var repeat = duplicatePoints ? 2 : 1;
  37633. nextPosition = positions[i + 1];
  37634. forward = Cartesian3.subtract(nextPosition, position, forward);
  37635. forward = Cartesian3.normalize(forward, forward);
  37636. cornerDirection = Cartesian3.add(forward, backward, cornerDirection);
  37637. cornerDirection = Cartesian3.normalize(cornerDirection, cornerDirection);
  37638. surfaceNormal = ellipsoid.geodeticSurfaceNormal(position, surfaceNormal);
  37639. var forwardProjection = Cartesian3.multiplyByScalar(surfaceNormal, Cartesian3.dot(forward, surfaceNormal), scratchForwardProjection);
  37640. Cartesian3.subtract(forward, forwardProjection, forwardProjection);
  37641. Cartesian3.normalize(forwardProjection, forwardProjection);
  37642. var backwardProjection = Cartesian3.multiplyByScalar(surfaceNormal, Cartesian3.dot(backward, surfaceNormal), scratchBackwardProjection);
  37643. Cartesian3.subtract(backward, backwardProjection, backwardProjection);
  37644. Cartesian3.normalize(backwardProjection, backwardProjection);
  37645. var doCorner = !CesiumMath.equalsEpsilon(Math.abs(Cartesian3.dot(forwardProjection, backwardProjection)), 1.0, CesiumMath.EPSILON7);
  37646. if (doCorner) {
  37647. cornerDirection = Cartesian3.cross(cornerDirection, surfaceNormal, cornerDirection);
  37648. cornerDirection = Cartesian3.cross(surfaceNormal, cornerDirection, cornerDirection);
  37649. cornerDirection = Cartesian3.normalize(cornerDirection, cornerDirection);
  37650. var scalar = 1 / Math.max(0.25, (Cartesian3.magnitude(Cartesian3.cross(cornerDirection, backward, scratch1))));
  37651. var leftIsOutside = PolylineVolumeGeometryLibrary.angleIsGreaterThanPi(forward, backward, position, ellipsoid);
  37652. if (leftIsOutside) {
  37653. pivot = Cartesian3.add(position, Cartesian3.multiplyByScalar(cornerDirection, scalar * width, cornerDirection), pivot);
  37654. start = Cartesian3.add(pivot, Cartesian3.multiplyByScalar(left, width, start), start);
  37655. scratch2Array[0] = Cartesian3.clone(previousPosition, scratch2Array[0]);
  37656. scratch2Array[1] = Cartesian3.clone(start, scratch2Array[1]);
  37657. subdividedHeights = subdivideHeights(scratch2Array, h0 + heightOffset, h1 + heightOffset, granularity);
  37658. subdividedPositions = PolylinePipeline.generateArc({
  37659. positions: scratch2Array,
  37660. granularity: granularity,
  37661. ellipsoid: ellipsoid
  37662. });
  37663. finalPositions = addPositions(subdividedPositions, left, shapeForSides, finalPositions, ellipsoid, subdividedHeights, 1);
  37664. left = Cartesian3.cross(surfaceNormal, forward, left);
  37665. left = Cartesian3.normalize(left, left);
  37666. end = Cartesian3.add(pivot, Cartesian3.multiplyByScalar(left, width, end), end);
  37667. if (cornerType === CornerType.ROUNDED || cornerType === CornerType.BEVELED) {
  37668. computeRoundCorner(pivot, start, end, cornerType, leftIsOutside, ellipsoid, finalPositions, shapeForSides, h1 + heightOffset, duplicatePoints);
  37669. } else {
  37670. cornerDirection = Cartesian3.negate(cornerDirection, cornerDirection);
  37671. finalPositions = addPosition(position, cornerDirection, shapeForSides, finalPositions, ellipsoid, h1 + heightOffset, scalar, repeat);
  37672. }
  37673. previousPosition = Cartesian3.clone(end, previousPosition);
  37674. } else {
  37675. pivot = Cartesian3.add(position, Cartesian3.multiplyByScalar(cornerDirection, scalar * width, cornerDirection), pivot);
  37676. start = Cartesian3.add(pivot, Cartesian3.multiplyByScalar(left, -width, start), start);
  37677. scratch2Array[0] = Cartesian3.clone(previousPosition, scratch2Array[0]);
  37678. scratch2Array[1] = Cartesian3.clone(start, scratch2Array[1]);
  37679. subdividedHeights = subdivideHeights(scratch2Array, h0 + heightOffset, h1 + heightOffset, granularity);
  37680. subdividedPositions = PolylinePipeline.generateArc({
  37681. positions: scratch2Array,
  37682. granularity: granularity,
  37683. ellipsoid: ellipsoid
  37684. });
  37685. finalPositions = addPositions(subdividedPositions, left, shapeForSides, finalPositions, ellipsoid, subdividedHeights, 1);
  37686. left = Cartesian3.cross(surfaceNormal, forward, left);
  37687. left = Cartesian3.normalize(left, left);
  37688. end = Cartesian3.add(pivot, Cartesian3.multiplyByScalar(left, -width, end), end);
  37689. if (cornerType === CornerType.ROUNDED || cornerType === CornerType.BEVELED) {
  37690. computeRoundCorner(pivot, start, end, cornerType, leftIsOutside, ellipsoid, finalPositions, shapeForSides, h1 + heightOffset, duplicatePoints);
  37691. } else {
  37692. finalPositions = addPosition(position, cornerDirection, shapeForSides, finalPositions, ellipsoid, h1 + heightOffset, scalar, repeat);
  37693. }
  37694. previousPosition = Cartesian3.clone(end, previousPosition);
  37695. }
  37696. backward = Cartesian3.negate(forward, backward);
  37697. } else {
  37698. finalPositions = addPosition(previousPosition, left, shapeForSides, finalPositions, ellipsoid, h0 + heightOffset, 1, 1);
  37699. previousPosition = position;
  37700. }
  37701. h0 = h1;
  37702. h1 = heights[i + 1];
  37703. position = nextPosition;
  37704. }
  37705. scratch2Array[0] = Cartesian3.clone(previousPosition, scratch2Array[0]);
  37706. scratch2Array[1] = Cartesian3.clone(position, scratch2Array[1]);
  37707. subdividedHeights = subdivideHeights(scratch2Array, h0 + heightOffset, h1 + heightOffset, granularity);
  37708. subdividedPositions = PolylinePipeline.generateArc({
  37709. positions: scratch2Array,
  37710. granularity: granularity,
  37711. ellipsoid: ellipsoid
  37712. });
  37713. finalPositions = addPositions(subdividedPositions, left, shapeForSides, finalPositions, ellipsoid, subdividedHeights, 1);
  37714. if (duplicatePoints) {
  37715. ends = addPosition(position, left, shapeForEnds, ends, ellipsoid, h1 + heightOffset, 1, 1);
  37716. }
  37717. length = finalPositions.length;
  37718. var posLength = duplicatePoints ? length + ends.length : length;
  37719. var combinedPositions = new Float64Array(posLength);
  37720. combinedPositions.set(finalPositions);
  37721. if (duplicatePoints) {
  37722. combinedPositions.set(ends, length);
  37723. }
  37724. return combinedPositions;
  37725. };
  37726. return PolylineVolumeGeometryLibrary;
  37727. });
  37728. /*global define*/
  37729. define('Core/CorridorGeometryLibrary',[
  37730. './Cartesian3',
  37731. './CornerType',
  37732. './defined',
  37733. './Math',
  37734. './Matrix3',
  37735. './PolylinePipeline',
  37736. './PolylineVolumeGeometryLibrary',
  37737. './Quaternion'
  37738. ], function(
  37739. Cartesian3,
  37740. CornerType,
  37741. defined,
  37742. CesiumMath,
  37743. Matrix3,
  37744. PolylinePipeline,
  37745. PolylineVolumeGeometryLibrary,
  37746. Quaternion) {
  37747. 'use strict';
  37748. /**
  37749. * @private
  37750. */
  37751. var CorridorGeometryLibrary = {};
  37752. var scratch1 = new Cartesian3();
  37753. var scratch2 = new Cartesian3();
  37754. var scratch3 = new Cartesian3();
  37755. var scratch4 = new Cartesian3();
  37756. var scaleArray2 = [new Cartesian3(), new Cartesian3()];
  37757. var cartesian1 = new Cartesian3();
  37758. var cartesian2 = new Cartesian3();
  37759. var cartesian3 = new Cartesian3();
  37760. var cartesian4 = new Cartesian3();
  37761. var cartesian5 = new Cartesian3();
  37762. var cartesian6 = new Cartesian3();
  37763. var cartesian7 = new Cartesian3();
  37764. var cartesian8 = new Cartesian3();
  37765. var cartesian9 = new Cartesian3();
  37766. var cartesian10 = new Cartesian3();
  37767. var quaterion = new Quaternion();
  37768. var rotMatrix = new Matrix3();
  37769. function computeRoundCorner(cornerPoint, startPoint, endPoint, cornerType, leftIsOutside) {
  37770. var angle = Cartesian3.angleBetween(Cartesian3.subtract(startPoint, cornerPoint, scratch1), Cartesian3.subtract(endPoint, cornerPoint, scratch2));
  37771. var granularity = (cornerType === CornerType.BEVELED) ? 1 : Math.ceil(angle / CesiumMath.toRadians(5)) + 1;
  37772. var size = granularity * 3;
  37773. var array = new Array(size);
  37774. array[size - 3] = endPoint.x;
  37775. array[size - 2] = endPoint.y;
  37776. array[size - 1] = endPoint.z;
  37777. var m;
  37778. if (leftIsOutside) {
  37779. m = Matrix3.fromQuaternion(Quaternion.fromAxisAngle(Cartesian3.negate(cornerPoint, scratch1), angle / granularity, quaterion), rotMatrix);
  37780. } else {
  37781. m = Matrix3.fromQuaternion(Quaternion.fromAxisAngle(cornerPoint, angle / granularity, quaterion), rotMatrix);
  37782. }
  37783. var index = 0;
  37784. startPoint = Cartesian3.clone(startPoint, scratch1);
  37785. for (var i = 0; i < granularity; i++) {
  37786. startPoint = Matrix3.multiplyByVector(m, startPoint, startPoint);
  37787. array[index++] = startPoint.x;
  37788. array[index++] = startPoint.y;
  37789. array[index++] = startPoint.z;
  37790. }
  37791. return array;
  37792. }
  37793. function addEndCaps(calculatedPositions) {
  37794. var cornerPoint = cartesian1;
  37795. var startPoint = cartesian2;
  37796. var endPoint = cartesian3;
  37797. var leftEdge = calculatedPositions[1];
  37798. startPoint = Cartesian3.fromArray(calculatedPositions[1], leftEdge.length - 3, startPoint);
  37799. endPoint = Cartesian3.fromArray(calculatedPositions[0], 0, endPoint);
  37800. cornerPoint = Cartesian3.multiplyByScalar(Cartesian3.add(startPoint, endPoint, cornerPoint), 0.5, cornerPoint);
  37801. var firstEndCap = computeRoundCorner(cornerPoint, startPoint, endPoint, CornerType.ROUNDED, false);
  37802. var length = calculatedPositions.length - 1;
  37803. var rightEdge = calculatedPositions[length - 1];
  37804. leftEdge = calculatedPositions[length];
  37805. startPoint = Cartesian3.fromArray(rightEdge, rightEdge.length - 3, startPoint);
  37806. endPoint = Cartesian3.fromArray(leftEdge, 0, endPoint);
  37807. cornerPoint = Cartesian3.multiplyByScalar(Cartesian3.add(startPoint, endPoint, cornerPoint), 0.5, cornerPoint);
  37808. var lastEndCap = computeRoundCorner(cornerPoint, startPoint, endPoint, CornerType.ROUNDED, false);
  37809. return [firstEndCap, lastEndCap];
  37810. }
  37811. function computeMiteredCorner(position, leftCornerDirection, lastPoint, leftIsOutside) {
  37812. var cornerPoint = scratch1;
  37813. if (leftIsOutside) {
  37814. cornerPoint = Cartesian3.add(position, leftCornerDirection, cornerPoint);
  37815. } else {
  37816. leftCornerDirection = Cartesian3.negate(leftCornerDirection, leftCornerDirection);
  37817. cornerPoint = Cartesian3.add(position, leftCornerDirection, cornerPoint);
  37818. }
  37819. return [cornerPoint.x, cornerPoint.y, cornerPoint.z, lastPoint.x, lastPoint.y, lastPoint.z];
  37820. }
  37821. function addShiftedPositions(positions, left, scalar, calculatedPositions) {
  37822. var rightPositions = new Array(positions.length);
  37823. var leftPositions = new Array(positions.length);
  37824. var scaledLeft = Cartesian3.multiplyByScalar(left, scalar, scratch1);
  37825. var scaledRight = Cartesian3.negate(scaledLeft, scratch2);
  37826. var rightIndex = 0;
  37827. var leftIndex = positions.length - 1;
  37828. for (var i = 0; i < positions.length; i += 3) {
  37829. var pos = Cartesian3.fromArray(positions, i, scratch3);
  37830. var rightPos = Cartesian3.add(pos, scaledRight, scratch4);
  37831. rightPositions[rightIndex++] = rightPos.x;
  37832. rightPositions[rightIndex++] = rightPos.y;
  37833. rightPositions[rightIndex++] = rightPos.z;
  37834. var leftPos = Cartesian3.add(pos, scaledLeft, scratch4);
  37835. leftPositions[leftIndex--] = leftPos.z;
  37836. leftPositions[leftIndex--] = leftPos.y;
  37837. leftPositions[leftIndex--] = leftPos.x;
  37838. }
  37839. calculatedPositions.push(rightPositions, leftPositions);
  37840. return calculatedPositions;
  37841. }
  37842. /**
  37843. * @private
  37844. */
  37845. CorridorGeometryLibrary.addAttribute = function(attribute, value, front, back) {
  37846. var x = value.x;
  37847. var y = value.y;
  37848. var z = value.z;
  37849. if (defined(front)) {
  37850. attribute[front] = x;
  37851. attribute[front + 1] = y;
  37852. attribute[front + 2] = z;
  37853. }
  37854. if (defined(back)) {
  37855. attribute[back] = z;
  37856. attribute[back - 1] = y;
  37857. attribute[back - 2] = x;
  37858. }
  37859. };
  37860. function scaleToSurface(positions, ellipsoid) {
  37861. for (var i = 0; i < positions.length; i++) {
  37862. positions[i] = ellipsoid.scaleToGeodeticSurface(positions[i], positions[i]);
  37863. }
  37864. return positions;
  37865. }
  37866. var scratchForwardProjection = new Cartesian3();
  37867. var scratchBackwardProjection = new Cartesian3();
  37868. /**
  37869. * @private
  37870. */
  37871. CorridorGeometryLibrary.computePositions = function(params) {
  37872. var granularity = params.granularity;
  37873. var positions = params.positions;
  37874. var ellipsoid = params.ellipsoid;
  37875. positions = scaleToSurface(positions, ellipsoid);
  37876. var width = params.width / 2;
  37877. var cornerType = params.cornerType;
  37878. var saveAttributes = params.saveAttributes;
  37879. var normal = cartesian1;
  37880. var forward = cartesian2;
  37881. var backward = cartesian3;
  37882. var left = cartesian4;
  37883. var cornerDirection = cartesian5;
  37884. var startPoint = cartesian6;
  37885. var previousPos = cartesian7;
  37886. var rightPos = cartesian8;
  37887. var leftPos = cartesian9;
  37888. var center = cartesian10;
  37889. var calculatedPositions = [];
  37890. var calculatedLefts = (saveAttributes) ? [] : undefined;
  37891. var calculatedNormals = (saveAttributes) ? [] : undefined;
  37892. var position = positions[0]; //add first point
  37893. var nextPosition = positions[1];
  37894. forward = Cartesian3.normalize(Cartesian3.subtract(nextPosition, position, forward), forward);
  37895. normal = ellipsoid.geodeticSurfaceNormal(position, normal);
  37896. left = Cartesian3.normalize(Cartesian3.cross(normal, forward, left), left);
  37897. if (saveAttributes) {
  37898. calculatedLefts.push(left.x, left.y, left.z);
  37899. calculatedNormals.push(normal.x, normal.y, normal.z);
  37900. }
  37901. previousPos = Cartesian3.clone(position, previousPos);
  37902. position = nextPosition;
  37903. backward = Cartesian3.negate(forward, backward);
  37904. var subdividedPositions;
  37905. var corners = [];
  37906. var i;
  37907. var length = positions.length;
  37908. for (i = 1; i < length - 1; i++) { // add middle points and corners
  37909. normal = ellipsoid.geodeticSurfaceNormal(position, normal);
  37910. nextPosition = positions[i + 1];
  37911. forward = Cartesian3.normalize(Cartesian3.subtract(nextPosition, position, forward), forward);
  37912. cornerDirection = Cartesian3.normalize(Cartesian3.add(forward, backward, cornerDirection), cornerDirection);
  37913. var forwardProjection = Cartesian3.multiplyByScalar(normal, Cartesian3.dot(forward, normal), scratchForwardProjection);
  37914. Cartesian3.subtract(forward, forwardProjection, forwardProjection);
  37915. Cartesian3.normalize(forwardProjection, forwardProjection);
  37916. var backwardProjection = Cartesian3.multiplyByScalar(normal, Cartesian3.dot(backward, normal), scratchBackwardProjection);
  37917. Cartesian3.subtract(backward, backwardProjection, backwardProjection);
  37918. Cartesian3.normalize(backwardProjection, backwardProjection);
  37919. var doCorner = !CesiumMath.equalsEpsilon(Math.abs(Cartesian3.dot(forwardProjection, backwardProjection)), 1.0, CesiumMath.EPSILON7);
  37920. if (doCorner) {
  37921. cornerDirection = Cartesian3.cross(cornerDirection, normal, cornerDirection);
  37922. cornerDirection = Cartesian3.cross(normal, cornerDirection, cornerDirection);
  37923. cornerDirection = Cartesian3.normalize(cornerDirection, cornerDirection);
  37924. var scalar = width / Math.max(0.25, Cartesian3.magnitude(Cartesian3.cross(cornerDirection, backward, scratch1)));
  37925. var leftIsOutside = PolylineVolumeGeometryLibrary.angleIsGreaterThanPi(forward, backward, position, ellipsoid);
  37926. cornerDirection = Cartesian3.multiplyByScalar(cornerDirection, scalar, cornerDirection);
  37927. if (leftIsOutside) {
  37928. rightPos = Cartesian3.add(position, cornerDirection, rightPos);
  37929. center = Cartesian3.add(rightPos, Cartesian3.multiplyByScalar(left, width, center), center);
  37930. leftPos = Cartesian3.add(rightPos, Cartesian3.multiplyByScalar(left, width * 2, leftPos), leftPos);
  37931. scaleArray2[0] = Cartesian3.clone(previousPos, scaleArray2[0]);
  37932. scaleArray2[1] = Cartesian3.clone(center, scaleArray2[1]);
  37933. subdividedPositions = PolylinePipeline.generateArc({
  37934. positions: scaleArray2,
  37935. granularity: granularity,
  37936. ellipsoid: ellipsoid
  37937. });
  37938. calculatedPositions = addShiftedPositions(subdividedPositions, left, width, calculatedPositions);
  37939. if (saveAttributes) {
  37940. calculatedLefts.push(left.x, left.y, left.z);
  37941. calculatedNormals.push(normal.x, normal.y, normal.z);
  37942. }
  37943. startPoint = Cartesian3.clone(leftPos, startPoint);
  37944. left = Cartesian3.normalize(Cartesian3.cross(normal, forward, left), left);
  37945. leftPos = Cartesian3.add(rightPos, Cartesian3.multiplyByScalar(left, width * 2, leftPos), leftPos);
  37946. previousPos = Cartesian3.add(rightPos, Cartesian3.multiplyByScalar(left, width, previousPos), previousPos);
  37947. if (cornerType === CornerType.ROUNDED || cornerType === CornerType.BEVELED) {
  37948. corners.push({
  37949. leftPositions : computeRoundCorner(rightPos, startPoint, leftPos, cornerType, leftIsOutside)
  37950. });
  37951. } else {
  37952. corners.push({
  37953. leftPositions : computeMiteredCorner(position, Cartesian3.negate(cornerDirection, cornerDirection), leftPos, leftIsOutside)
  37954. });
  37955. }
  37956. } else {
  37957. leftPos = Cartesian3.add(position, cornerDirection, leftPos);
  37958. center = Cartesian3.add(leftPos, Cartesian3.negate(Cartesian3.multiplyByScalar(left, width, center), center), center);
  37959. rightPos = Cartesian3.add(leftPos, Cartesian3.negate(Cartesian3.multiplyByScalar(left, width * 2, rightPos), rightPos), rightPos);
  37960. scaleArray2[0] = Cartesian3.clone(previousPos, scaleArray2[0]);
  37961. scaleArray2[1] = Cartesian3.clone(center, scaleArray2[1]);
  37962. subdividedPositions = PolylinePipeline.generateArc({
  37963. positions: scaleArray2,
  37964. granularity: granularity,
  37965. ellipsoid: ellipsoid
  37966. });
  37967. calculatedPositions = addShiftedPositions(subdividedPositions, left, width, calculatedPositions);
  37968. if (saveAttributes) {
  37969. calculatedLefts.push(left.x, left.y, left.z);
  37970. calculatedNormals.push(normal.x, normal.y, normal.z);
  37971. }
  37972. startPoint = Cartesian3.clone(rightPos, startPoint);
  37973. left = Cartesian3.normalize(Cartesian3.cross(normal, forward, left), left);
  37974. rightPos = Cartesian3.add(leftPos, Cartesian3.negate(Cartesian3.multiplyByScalar(left, width * 2, rightPos), rightPos), rightPos);
  37975. previousPos = Cartesian3.add(leftPos, Cartesian3.negate(Cartesian3.multiplyByScalar(left, width, previousPos), previousPos), previousPos);
  37976. if (cornerType === CornerType.ROUNDED || cornerType === CornerType.BEVELED) {
  37977. corners.push({
  37978. rightPositions : computeRoundCorner(leftPos, startPoint, rightPos, cornerType, leftIsOutside)
  37979. });
  37980. } else {
  37981. corners.push({
  37982. rightPositions : computeMiteredCorner(position, cornerDirection, rightPos, leftIsOutside)
  37983. });
  37984. }
  37985. }
  37986. backward = Cartesian3.negate(forward, backward);
  37987. }
  37988. position = nextPosition;
  37989. }
  37990. normal = ellipsoid.geodeticSurfaceNormal(position, normal);
  37991. scaleArray2[0] = Cartesian3.clone(previousPos, scaleArray2[0]);
  37992. scaleArray2[1] = Cartesian3.clone(position, scaleArray2[1]);
  37993. subdividedPositions = PolylinePipeline.generateArc({
  37994. positions: scaleArray2,
  37995. granularity: granularity,
  37996. ellipsoid: ellipsoid
  37997. });
  37998. calculatedPositions = addShiftedPositions(subdividedPositions, left, width, calculatedPositions);
  37999. if (saveAttributes) {
  38000. calculatedLefts.push(left.x, left.y, left.z);
  38001. calculatedNormals.push(normal.x, normal.y, normal.z);
  38002. }
  38003. var endPositions;
  38004. if (cornerType === CornerType.ROUNDED) {
  38005. endPositions = addEndCaps(calculatedPositions);
  38006. }
  38007. return {
  38008. positions : calculatedPositions,
  38009. corners : corners,
  38010. lefts : calculatedLefts,
  38011. normals : calculatedNormals,
  38012. endPositions : endPositions
  38013. };
  38014. };
  38015. return CorridorGeometryLibrary;
  38016. });
  38017. /*global define*/
  38018. define('ThirdParty/earcut-2.1.1',[], function() {
  38019. 'use strict';
  38020. function earcut(data, holeIndices, dim) {
  38021. dim = dim || 2;
  38022. var hasHoles = holeIndices && holeIndices.length,
  38023. outerLen = hasHoles ? holeIndices[0] * dim : data.length,
  38024. outerNode = linkedList(data, 0, outerLen, dim, true),
  38025. triangles = [];
  38026. if (!outerNode) return triangles;
  38027. var minX, minY, maxX, maxY, x, y, size;
  38028. if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
  38029. // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
  38030. if (data.length > 80 * dim) {
  38031. minX = maxX = data[0];
  38032. minY = maxY = data[1];
  38033. for (var i = dim; i < outerLen; i += dim) {
  38034. x = data[i];
  38035. y = data[i + 1];
  38036. if (x < minX) minX = x;
  38037. if (y < minY) minY = y;
  38038. if (x > maxX) maxX = x;
  38039. if (y > maxY) maxY = y;
  38040. }
  38041. // minX, minY and size are later used to transform coords into integers for z-order calculation
  38042. size = Math.max(maxX - minX, maxY - minY);
  38043. }
  38044. earcutLinked(outerNode, triangles, dim, minX, minY, size);
  38045. return triangles;
  38046. }
  38047. // create a circular doubly linked list from polygon points in the specified winding order
  38048. function linkedList(data, start, end, dim, clockwise) {
  38049. var i, last;
  38050. if (clockwise === (signedArea(data, start, end, dim) > 0)) {
  38051. for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last);
  38052. } else {
  38053. for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last);
  38054. }
  38055. if (last && equals(last, last.next)) {
  38056. removeNode(last);
  38057. last = last.next;
  38058. }
  38059. return last;
  38060. }
  38061. // eliminate colinear or duplicate points
  38062. function filterPoints(start, end) {
  38063. if (!start) return start;
  38064. if (!end) end = start;
  38065. var p = start,
  38066. again;
  38067. do {
  38068. again = false;
  38069. if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
  38070. removeNode(p);
  38071. p = end = p.prev;
  38072. if (p === p.next) return null;
  38073. again = true;
  38074. } else {
  38075. p = p.next;
  38076. }
  38077. } while (again || p !== end);
  38078. return end;
  38079. }
  38080. // main ear slicing loop which triangulates a polygon (given as a linked list)
  38081. function earcutLinked(ear, triangles, dim, minX, minY, size, pass) {
  38082. if (!ear) return;
  38083. // interlink polygon nodes in z-order
  38084. if (!pass && size) indexCurve(ear, minX, minY, size);
  38085. var stop = ear,
  38086. prev, next;
  38087. // iterate through ears, slicing them one by one
  38088. while (ear.prev !== ear.next) {
  38089. prev = ear.prev;
  38090. next = ear.next;
  38091. if (size ? isEarHashed(ear, minX, minY, size) : isEar(ear)) {
  38092. // cut off the triangle
  38093. triangles.push(prev.i / dim);
  38094. triangles.push(ear.i / dim);
  38095. triangles.push(next.i / dim);
  38096. removeNode(ear);
  38097. // skipping the next vertice leads to less sliver triangles
  38098. ear = next.next;
  38099. stop = next.next;
  38100. continue;
  38101. }
  38102. ear = next;
  38103. // if we looped through the whole remaining polygon and can't find any more ears
  38104. if (ear === stop) {
  38105. // try filtering points and slicing again
  38106. if (!pass) {
  38107. earcutLinked(filterPoints(ear), triangles, dim, minX, minY, size, 1);
  38108. // if this didn't work, try curing all small self-intersections locally
  38109. } else if (pass === 1) {
  38110. ear = cureLocalIntersections(ear, triangles, dim);
  38111. earcutLinked(ear, triangles, dim, minX, minY, size, 2);
  38112. // as a last resort, try splitting the remaining polygon into two
  38113. } else if (pass === 2) {
  38114. splitEarcut(ear, triangles, dim, minX, minY, size);
  38115. }
  38116. break;
  38117. }
  38118. }
  38119. }
  38120. // check whether a polygon node forms a valid ear with adjacent nodes
  38121. function isEar(ear) {
  38122. var a = ear.prev,
  38123. b = ear,
  38124. c = ear.next;
  38125. if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
  38126. // now make sure we don't have other points inside the potential ear
  38127. var p = ear.next.next;
  38128. while (p !== ear.prev) {
  38129. if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
  38130. area(p.prev, p, p.next) >= 0) return false;
  38131. p = p.next;
  38132. }
  38133. return true;
  38134. }
  38135. function isEarHashed(ear, minX, minY, size) {
  38136. var a = ear.prev,
  38137. b = ear,
  38138. c = ear.next;
  38139. if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
  38140. // triangle bbox; min & max are calculated like this for speed
  38141. var minTX = a.x < b.x ? (a.x < c.x ? a.x : c.x) : (b.x < c.x ? b.x : c.x),
  38142. minTY = a.y < b.y ? (a.y < c.y ? a.y : c.y) : (b.y < c.y ? b.y : c.y),
  38143. maxTX = a.x > b.x ? (a.x > c.x ? a.x : c.x) : (b.x > c.x ? b.x : c.x),
  38144. maxTY = a.y > b.y ? (a.y > c.y ? a.y : c.y) : (b.y > c.y ? b.y : c.y);
  38145. // z-order range for the current triangle bbox;
  38146. var minZ = zOrder(minTX, minTY, minX, minY, size),
  38147. maxZ = zOrder(maxTX, maxTY, minX, minY, size);
  38148. // first look for points inside the triangle in increasing z-order
  38149. var p = ear.nextZ;
  38150. while (p && p.z <= maxZ) {
  38151. if (p !== ear.prev && p !== ear.next &&
  38152. pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
  38153. area(p.prev, p, p.next) >= 0) return false;
  38154. p = p.nextZ;
  38155. }
  38156. // then look for points in decreasing z-order
  38157. p = ear.prevZ;
  38158. while (p && p.z >= minZ) {
  38159. if (p !== ear.prev && p !== ear.next &&
  38160. pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
  38161. area(p.prev, p, p.next) >= 0) return false;
  38162. p = p.prevZ;
  38163. }
  38164. return true;
  38165. }
  38166. // go through all polygon nodes and cure small local self-intersections
  38167. function cureLocalIntersections(start, triangles, dim) {
  38168. var p = start;
  38169. do {
  38170. var a = p.prev,
  38171. b = p.next.next;
  38172. if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
  38173. triangles.push(a.i / dim);
  38174. triangles.push(p.i / dim);
  38175. triangles.push(b.i / dim);
  38176. // remove two nodes involved
  38177. removeNode(p);
  38178. removeNode(p.next);
  38179. p = start = b;
  38180. }
  38181. p = p.next;
  38182. } while (p !== start);
  38183. return p;
  38184. }
  38185. // try splitting polygon into two and triangulate them independently
  38186. function splitEarcut(start, triangles, dim, minX, minY, size) {
  38187. // look for a valid diagonal that divides the polygon into two
  38188. var a = start;
  38189. do {
  38190. var b = a.next.next;
  38191. while (b !== a.prev) {
  38192. if (a.i !== b.i && isValidDiagonal(a, b)) {
  38193. // split the polygon in two by the diagonal
  38194. var c = splitPolygon(a, b);
  38195. // filter colinear points around the cuts
  38196. a = filterPoints(a, a.next);
  38197. c = filterPoints(c, c.next);
  38198. // run earcut on each half
  38199. earcutLinked(a, triangles, dim, minX, minY, size);
  38200. earcutLinked(c, triangles, dim, minX, minY, size);
  38201. return;
  38202. }
  38203. b = b.next;
  38204. }
  38205. a = a.next;
  38206. } while (a !== start);
  38207. }
  38208. // link every hole into the outer loop, producing a single-ring polygon without holes
  38209. function eliminateHoles(data, holeIndices, outerNode, dim) {
  38210. var queue = [],
  38211. i, len, start, end, list;
  38212. for (i = 0, len = holeIndices.length; i < len; i++) {
  38213. start = holeIndices[i] * dim;
  38214. end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
  38215. list = linkedList(data, start, end, dim, false);
  38216. if (list === list.next) list.steiner = true;
  38217. queue.push(getLeftmost(list));
  38218. }
  38219. queue.sort(compareX);
  38220. // process holes from left to right
  38221. for (i = 0; i < queue.length; i++) {
  38222. eliminateHole(queue[i], outerNode);
  38223. outerNode = filterPoints(outerNode, outerNode.next);
  38224. }
  38225. return outerNode;
  38226. }
  38227. function compareX(a, b) {
  38228. return a.x - b.x;
  38229. }
  38230. // find a bridge between vertices that connects hole with an outer ring and and link it
  38231. function eliminateHole(hole, outerNode) {
  38232. outerNode = findHoleBridge(hole, outerNode);
  38233. if (outerNode) {
  38234. var b = splitPolygon(outerNode, hole);
  38235. filterPoints(b, b.next);
  38236. }
  38237. }
  38238. // David Eberly's algorithm for finding a bridge between hole and outer polygon
  38239. function findHoleBridge(hole, outerNode) {
  38240. var p = outerNode,
  38241. hx = hole.x,
  38242. hy = hole.y,
  38243. qx = -Infinity,
  38244. m;
  38245. // find a segment intersected by a ray from the hole's leftmost point to the left;
  38246. // segment's endpoint with lesser x will be potential connection point
  38247. do {
  38248. if (hy <= p.y && hy >= p.next.y) {
  38249. var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
  38250. if (x <= hx && x > qx) {
  38251. qx = x;
  38252. if (x === hx) {
  38253. if (hy === p.y) return p;
  38254. if (hy === p.next.y) return p.next;
  38255. }
  38256. m = p.x < p.next.x ? p : p.next;
  38257. }
  38258. }
  38259. p = p.next;
  38260. } while (p !== outerNode);
  38261. if (!m) return null;
  38262. if (hx === qx) return m.prev; // hole touches outer segment; pick lower endpoint
  38263. // look for points inside the triangle of hole point, segment intersection and endpoint;
  38264. // if there are no points found, we have a valid connection;
  38265. // otherwise choose the point of the minimum angle with the ray as connection point
  38266. var stop = m,
  38267. mx = m.x,
  38268. my = m.y,
  38269. tanMin = Infinity,
  38270. tan;
  38271. p = m.next;
  38272. while (p !== stop) {
  38273. if (hx >= p.x && p.x >= mx &&
  38274. pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
  38275. tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
  38276. if ((tan < tanMin || (tan === tanMin && p.x > m.x)) && locallyInside(p, hole)) {
  38277. m = p;
  38278. tanMin = tan;
  38279. }
  38280. }
  38281. p = p.next;
  38282. }
  38283. return m;
  38284. }
  38285. // interlink polygon nodes in z-order
  38286. function indexCurve(start, minX, minY, size) {
  38287. var p = start;
  38288. do {
  38289. if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, size);
  38290. p.prevZ = p.prev;
  38291. p.nextZ = p.next;
  38292. p = p.next;
  38293. } while (p !== start);
  38294. p.prevZ.nextZ = null;
  38295. p.prevZ = null;
  38296. sortLinked(p);
  38297. }
  38298. // Simon Tatham's linked list merge sort algorithm
  38299. // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
  38300. function sortLinked(list) {
  38301. var i, p, q, e, tail, numMerges, pSize, qSize,
  38302. inSize = 1;
  38303. do {
  38304. p = list;
  38305. list = null;
  38306. tail = null;
  38307. numMerges = 0;
  38308. while (p) {
  38309. numMerges++;
  38310. q = p;
  38311. pSize = 0;
  38312. for (i = 0; i < inSize; i++) {
  38313. pSize++;
  38314. q = q.nextZ;
  38315. if (!q) break;
  38316. }
  38317. qSize = inSize;
  38318. while (pSize > 0 || (qSize > 0 && q)) {
  38319. if (pSize === 0) {
  38320. e = q;
  38321. q = q.nextZ;
  38322. qSize--;
  38323. } else if (qSize === 0 || !q) {
  38324. e = p;
  38325. p = p.nextZ;
  38326. pSize--;
  38327. } else if (p.z <= q.z) {
  38328. e = p;
  38329. p = p.nextZ;
  38330. pSize--;
  38331. } else {
  38332. e = q;
  38333. q = q.nextZ;
  38334. qSize--;
  38335. }
  38336. if (tail) tail.nextZ = e;
  38337. else list = e;
  38338. e.prevZ = tail;
  38339. tail = e;
  38340. }
  38341. p = q;
  38342. }
  38343. tail.nextZ = null;
  38344. inSize *= 2;
  38345. } while (numMerges > 1);
  38346. return list;
  38347. }
  38348. // z-order of a point given coords and size of the data bounding box
  38349. function zOrder(x, y, minX, minY, size) {
  38350. // coords are transformed into non-negative 15-bit integer range
  38351. x = 32767 * (x - minX) / size;
  38352. y = 32767 * (y - minY) / size;
  38353. x = (x | (x << 8)) & 0x00FF00FF;
  38354. x = (x | (x << 4)) & 0x0F0F0F0F;
  38355. x = (x | (x << 2)) & 0x33333333;
  38356. x = (x | (x << 1)) & 0x55555555;
  38357. y = (y | (y << 8)) & 0x00FF00FF;
  38358. y = (y | (y << 4)) & 0x0F0F0F0F;
  38359. y = (y | (y << 2)) & 0x33333333;
  38360. y = (y | (y << 1)) & 0x55555555;
  38361. return x | (y << 1);
  38362. }
  38363. // find the leftmost node of a polygon ring
  38364. function getLeftmost(start) {
  38365. var p = start,
  38366. leftmost = start;
  38367. do {
  38368. if (p.x < leftmost.x) leftmost = p;
  38369. p = p.next;
  38370. } while (p !== start);
  38371. return leftmost;
  38372. }
  38373. // check if a point lies within a convex triangle
  38374. function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
  38375. return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 &&
  38376. (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 &&
  38377. (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
  38378. }
  38379. // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
  38380. function isValidDiagonal(a, b) {
  38381. return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) &&
  38382. locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b);
  38383. }
  38384. // signed area of a triangle
  38385. function area(p, q, r) {
  38386. return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
  38387. }
  38388. // check if two points are equal
  38389. function equals(p1, p2) {
  38390. return p1.x === p2.x && p1.y === p2.y;
  38391. }
  38392. // check if two segments intersect
  38393. function intersects(p1, q1, p2, q2) {
  38394. if ((equals(p1, q1) && equals(p2, q2)) ||
  38395. (equals(p1, q2) && equals(p2, q1))) return true;
  38396. return area(p1, q1, p2) > 0 !== area(p1, q1, q2) > 0 &&
  38397. area(p2, q2, p1) > 0 !== area(p2, q2, q1) > 0;
  38398. }
  38399. // check if a polygon diagonal intersects any polygon segments
  38400. function intersectsPolygon(a, b) {
  38401. var p = a;
  38402. do {
  38403. if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
  38404. intersects(p, p.next, a, b)) return true;
  38405. p = p.next;
  38406. } while (p !== a);
  38407. return false;
  38408. }
  38409. // check if a polygon diagonal is locally inside the polygon
  38410. function locallyInside(a, b) {
  38411. return area(a.prev, a, a.next) < 0 ?
  38412. area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 :
  38413. area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
  38414. }
  38415. // check if the middle point of a polygon diagonal is inside the polygon
  38416. function middleInside(a, b) {
  38417. var p = a,
  38418. inside = false,
  38419. px = (a.x + b.x) / 2,
  38420. py = (a.y + b.y) / 2;
  38421. do {
  38422. if (((p.y > py) !== (p.next.y > py)) && (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x))
  38423. inside = !inside;
  38424. p = p.next;
  38425. } while (p !== a);
  38426. return inside;
  38427. }
  38428. // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
  38429. // if one belongs to the outer ring and another to a hole, it merges it into a single ring
  38430. function splitPolygon(a, b) {
  38431. var a2 = new Node(a.i, a.x, a.y),
  38432. b2 = new Node(b.i, b.x, b.y),
  38433. an = a.next,
  38434. bp = b.prev;
  38435. a.next = b;
  38436. b.prev = a;
  38437. a2.next = an;
  38438. an.prev = a2;
  38439. b2.next = a2;
  38440. a2.prev = b2;
  38441. bp.next = b2;
  38442. b2.prev = bp;
  38443. return b2;
  38444. }
  38445. // create a node and optionally link it with previous one (in a circular doubly linked list)
  38446. function insertNode(i, x, y, last) {
  38447. var p = new Node(i, x, y);
  38448. if (!last) {
  38449. p.prev = p;
  38450. p.next = p;
  38451. } else {
  38452. p.next = last.next;
  38453. p.prev = last;
  38454. last.next.prev = p;
  38455. last.next = p;
  38456. }
  38457. return p;
  38458. }
  38459. function removeNode(p) {
  38460. p.next.prev = p.prev;
  38461. p.prev.next = p.next;
  38462. if (p.prevZ) p.prevZ.nextZ = p.nextZ;
  38463. if (p.nextZ) p.nextZ.prevZ = p.prevZ;
  38464. }
  38465. function Node(i, x, y) {
  38466. // vertice index in coordinates array
  38467. this.i = i;
  38468. // vertex coordinates
  38469. this.x = x;
  38470. this.y = y;
  38471. // previous and next vertice nodes in a polygon ring
  38472. this.prev = null;
  38473. this.next = null;
  38474. // z-order curve value
  38475. this.z = null;
  38476. // previous and next nodes in z-order
  38477. this.prevZ = null;
  38478. this.nextZ = null;
  38479. // indicates whether this is a steiner point
  38480. this.steiner = false;
  38481. }
  38482. // return a percentage difference between the polygon area and its triangulation area;
  38483. // used to verify correctness of triangulation
  38484. earcut.deviation = function (data, holeIndices, dim, triangles) {
  38485. var hasHoles = holeIndices && holeIndices.length;
  38486. var outerLen = hasHoles ? holeIndices[0] * dim : data.length;
  38487. var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim));
  38488. if (hasHoles) {
  38489. for (var i = 0, len = holeIndices.length; i < len; i++) {
  38490. var start = holeIndices[i] * dim;
  38491. var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
  38492. polygonArea -= Math.abs(signedArea(data, start, end, dim));
  38493. }
  38494. }
  38495. var trianglesArea = 0;
  38496. for (i = 0; i < triangles.length; i += 3) {
  38497. var a = triangles[i] * dim;
  38498. var b = triangles[i + 1] * dim;
  38499. var c = triangles[i + 2] * dim;
  38500. trianglesArea += Math.abs(
  38501. (data[a] - data[c]) * (data[b + 1] - data[a + 1]) -
  38502. (data[a] - data[b]) * (data[c + 1] - data[a + 1]));
  38503. }
  38504. return polygonArea === 0 && trianglesArea === 0 ? 0 :
  38505. Math.abs((trianglesArea - polygonArea) / polygonArea);
  38506. };
  38507. function signedArea(data, start, end, dim) {
  38508. var sum = 0;
  38509. for (var i = start, j = end - dim; i < end; i += dim) {
  38510. sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
  38511. j = i;
  38512. }
  38513. return sum;
  38514. }
  38515. // turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts
  38516. earcut.flatten = function (data) {
  38517. var dim = data[0][0].length,
  38518. result = {vertices: [], holes: [], dimensions: dim},
  38519. holeIndex = 0;
  38520. for (var i = 0; i < data.length; i++) {
  38521. for (var j = 0; j < data[i].length; j++) {
  38522. for (var d = 0; d < dim; d++) result.vertices.push(data[i][j][d]);
  38523. }
  38524. if (i > 0) {
  38525. holeIndex += data[i - 1].length;
  38526. result.holes.push(holeIndex);
  38527. }
  38528. }
  38529. return result;
  38530. };
  38531. return earcut;
  38532. });
  38533. /*global define*/
  38534. define('Core/WindingOrder',[
  38535. './freezeObject',
  38536. './WebGLConstants'
  38537. ], function(
  38538. freezeObject,
  38539. WebGLConstants) {
  38540. 'use strict';
  38541. /**
  38542. * Winding order defines the order of vertices for a triangle to be considered front-facing.
  38543. *
  38544. * @exports WindingOrder
  38545. */
  38546. var WindingOrder = {
  38547. /**
  38548. * Vertices are in clockwise order.
  38549. *
  38550. * @type {Number}
  38551. * @constant
  38552. */
  38553. CLOCKWISE : WebGLConstants.CW,
  38554. /**
  38555. * Vertices are in counter-clockwise order.
  38556. *
  38557. * @type {Number}
  38558. * @constant
  38559. */
  38560. COUNTER_CLOCKWISE : WebGLConstants.CCW,
  38561. /**
  38562. * @private
  38563. */
  38564. validate : function(windingOrder) {
  38565. return windingOrder === WindingOrder.CLOCKWISE ||
  38566. windingOrder === WindingOrder.COUNTER_CLOCKWISE;
  38567. }
  38568. };
  38569. return freezeObject(WindingOrder);
  38570. });
  38571. /*global define*/
  38572. define('Core/PolygonPipeline',[
  38573. '../ThirdParty/earcut-2.1.1',
  38574. './Cartesian2',
  38575. './Cartesian3',
  38576. './ComponentDatatype',
  38577. './defaultValue',
  38578. './defined',
  38579. './DeveloperError',
  38580. './Ellipsoid',
  38581. './Geometry',
  38582. './GeometryAttribute',
  38583. './Math',
  38584. './PrimitiveType',
  38585. './WindingOrder'
  38586. ], function(
  38587. earcut,
  38588. Cartesian2,
  38589. Cartesian3,
  38590. ComponentDatatype,
  38591. defaultValue,
  38592. defined,
  38593. DeveloperError,
  38594. Ellipsoid,
  38595. Geometry,
  38596. GeometryAttribute,
  38597. CesiumMath,
  38598. PrimitiveType,
  38599. WindingOrder) {
  38600. 'use strict';
  38601. var scaleToGeodeticHeightN = new Cartesian3();
  38602. var scaleToGeodeticHeightP = new Cartesian3();
  38603. /**
  38604. * @private
  38605. */
  38606. var PolygonPipeline = {};
  38607. /**
  38608. * @exception {DeveloperError} At least three positions are required.
  38609. */
  38610. PolygonPipeline.computeArea2D = function(positions) {
  38611. if (!defined(positions)) {
  38612. throw new DeveloperError('positions is required.');
  38613. }
  38614. if (positions.length < 3) {
  38615. throw new DeveloperError('At least three positions are required.');
  38616. }
  38617. var length = positions.length;
  38618. var area = 0.0;
  38619. for ( var i0 = length - 1, i1 = 0; i1 < length; i0 = i1++) {
  38620. var v0 = positions[i0];
  38621. var v1 = positions[i1];
  38622. area += (v0.x * v1.y) - (v1.x * v0.y);
  38623. }
  38624. return area * 0.5;
  38625. };
  38626. /**
  38627. * @returns {WindingOrder} The winding order.
  38628. *
  38629. * @exception {DeveloperError} At least three positions are required.
  38630. */
  38631. PolygonPipeline.computeWindingOrder2D = function(positions) {
  38632. var area = PolygonPipeline.computeArea2D(positions);
  38633. return (area > 0.0) ? WindingOrder.COUNTER_CLOCKWISE : WindingOrder.CLOCKWISE;
  38634. };
  38635. /**
  38636. * Triangulate a polygon.
  38637. *
  38638. * @param {Cartesian2[]} positions Cartesian2 array containing the vertices of the polygon
  38639. * @param {Number[]} [holes] An array of the staring indices of the holes.
  38640. * @returns {Number[]} Index array representing triangles that fill the polygon
  38641. */
  38642. PolygonPipeline.triangulate = function(positions, holes) {
  38643. if (!defined(positions)) {
  38644. throw new DeveloperError('positions is required.');
  38645. }
  38646. var flattenedPositions = Cartesian2.packArray(positions);
  38647. return earcut(flattenedPositions, holes, 2);
  38648. };
  38649. var subdivisionV0Scratch = new Cartesian3();
  38650. var subdivisionV1Scratch = new Cartesian3();
  38651. var subdivisionV2Scratch = new Cartesian3();
  38652. var subdivisionS0Scratch = new Cartesian3();
  38653. var subdivisionS1Scratch = new Cartesian3();
  38654. var subdivisionS2Scratch = new Cartesian3();
  38655. var subdivisionMidScratch = new Cartesian3();
  38656. /**
  38657. * Subdivides positions and raises points to the surface of the ellipsoid.
  38658. *
  38659. * @param {Ellipsoid} ellipsoid The ellipsoid the polygon in on.
  38660. * @param {Cartesian3[]} positions An array of {@link Cartesian3} positions of the polygon.
  38661. * @param {Number[]} indices An array of indices that determines the triangles in the polygon.
  38662. * @param {Number} [granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  38663. *
  38664. * @exception {DeveloperError} At least three indices are required.
  38665. * @exception {DeveloperError} The number of indices must be divisable by three.
  38666. * @exception {DeveloperError} Granularity must be greater than zero.
  38667. */
  38668. PolygonPipeline.computeSubdivision = function(ellipsoid, positions, indices, granularity) {
  38669. granularity = defaultValue(granularity, CesiumMath.RADIANS_PER_DEGREE);
  38670. if (!defined(ellipsoid)) {
  38671. throw new DeveloperError('ellipsoid is required.');
  38672. }
  38673. if (!defined(positions)) {
  38674. throw new DeveloperError('positions is required.');
  38675. }
  38676. if (!defined(indices)) {
  38677. throw new DeveloperError('indices is required.');
  38678. }
  38679. if (indices.length < 3) {
  38680. throw new DeveloperError('At least three indices are required.');
  38681. }
  38682. if (indices.length % 3 !== 0) {
  38683. throw new DeveloperError('The number of indices must be divisable by three.');
  38684. }
  38685. if (granularity <= 0.0) {
  38686. throw new DeveloperError('granularity must be greater than zero.');
  38687. }
  38688. // triangles that need (or might need) to be subdivided.
  38689. var triangles = indices.slice(0);
  38690. // New positions due to edge splits are appended to the positions list.
  38691. var i;
  38692. var length = positions.length;
  38693. var subdividedPositions = new Array(length * 3);
  38694. var q = 0;
  38695. for (i = 0; i < length; i++) {
  38696. var item = positions[i];
  38697. subdividedPositions[q++] = item.x;
  38698. subdividedPositions[q++] = item.y;
  38699. subdividedPositions[q++] = item.z;
  38700. }
  38701. var subdividedIndices = [];
  38702. // Used to make sure shared edges are not split more than once.
  38703. var edges = {};
  38704. var radius = ellipsoid.maximumRadius;
  38705. var minDistance = CesiumMath.chordLength(granularity, radius);
  38706. var minDistanceSqrd = minDistance * minDistance;
  38707. while (triangles.length > 0) {
  38708. var i2 = triangles.pop();
  38709. var i1 = triangles.pop();
  38710. var i0 = triangles.pop();
  38711. var v0 = Cartesian3.fromArray(subdividedPositions, i0 * 3, subdivisionV0Scratch);
  38712. var v1 = Cartesian3.fromArray(subdividedPositions, i1 * 3, subdivisionV1Scratch);
  38713. var v2 = Cartesian3.fromArray(subdividedPositions, i2 * 3, subdivisionV2Scratch);
  38714. var s0 = Cartesian3.multiplyByScalar(Cartesian3.normalize(v0, subdivisionS0Scratch), radius, subdivisionS0Scratch);
  38715. var s1 = Cartesian3.multiplyByScalar(Cartesian3.normalize(v1, subdivisionS1Scratch), radius, subdivisionS1Scratch);
  38716. var s2 = Cartesian3.multiplyByScalar(Cartesian3.normalize(v2, subdivisionS2Scratch), radius, subdivisionS2Scratch);
  38717. var g0 = Cartesian3.magnitudeSquared(Cartesian3.subtract(s0, s1, subdivisionMidScratch));
  38718. var g1 = Cartesian3.magnitudeSquared(Cartesian3.subtract(s1, s2, subdivisionMidScratch));
  38719. var g2 = Cartesian3.magnitudeSquared(Cartesian3.subtract(s2, s0, subdivisionMidScratch));
  38720. var max = Math.max(g0, g1, g2);
  38721. var edge;
  38722. var mid;
  38723. // if the max length squared of a triangle edge is greater than the chord length of squared
  38724. // of the granularity, subdivide the triangle
  38725. if (max > minDistanceSqrd) {
  38726. if (g0 === max) {
  38727. edge = Math.min(i0, i1) + ' ' + Math.max(i0, i1);
  38728. i = edges[edge];
  38729. if (!defined(i)) {
  38730. mid = Cartesian3.add(v0, v1, subdivisionMidScratch);
  38731. Cartesian3.multiplyByScalar(mid, 0.5, mid);
  38732. subdividedPositions.push(mid.x, mid.y, mid.z);
  38733. i = subdividedPositions.length / 3 - 1;
  38734. edges[edge] = i;
  38735. }
  38736. triangles.push(i0, i, i2);
  38737. triangles.push(i, i1, i2);
  38738. } else if (g1 === max) {
  38739. edge = Math.min(i1, i2) + ' ' + Math.max(i1, i2);
  38740. i = edges[edge];
  38741. if (!defined(i)) {
  38742. mid = Cartesian3.add(v1, v2, subdivisionMidScratch);
  38743. Cartesian3.multiplyByScalar(mid, 0.5, mid);
  38744. subdividedPositions.push(mid.x, mid.y, mid.z);
  38745. i = subdividedPositions.length / 3 - 1;
  38746. edges[edge] = i;
  38747. }
  38748. triangles.push(i1, i, i0);
  38749. triangles.push(i, i2, i0);
  38750. } else if (g2 === max) {
  38751. edge = Math.min(i2, i0) + ' ' + Math.max(i2, i0);
  38752. i = edges[edge];
  38753. if (!defined(i)) {
  38754. mid = Cartesian3.add(v2, v0, subdivisionMidScratch);
  38755. Cartesian3.multiplyByScalar(mid, 0.5, mid);
  38756. subdividedPositions.push(mid.x, mid.y, mid.z);
  38757. i = subdividedPositions.length / 3 - 1;
  38758. edges[edge] = i;
  38759. }
  38760. triangles.push(i2, i, i1);
  38761. triangles.push(i, i0, i1);
  38762. }
  38763. } else {
  38764. subdividedIndices.push(i0);
  38765. subdividedIndices.push(i1);
  38766. subdividedIndices.push(i2);
  38767. }
  38768. }
  38769. return new Geometry({
  38770. attributes : {
  38771. position : new GeometryAttribute({
  38772. componentDatatype : ComponentDatatype.DOUBLE,
  38773. componentsPerAttribute : 3,
  38774. values : subdividedPositions
  38775. })
  38776. },
  38777. indices : subdividedIndices,
  38778. primitiveType : PrimitiveType.TRIANGLES
  38779. });
  38780. };
  38781. /**
  38782. * Scales each position of a geometry's position attribute to a height, in place.
  38783. *
  38784. * @param {Number[]} positions The array of numbers representing the positions to be scaled
  38785. * @param {Number} [height=0.0] The desired height to add to the positions
  38786. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the positions lie.
  38787. * @param {Boolean} [scaleToSurface=true] <code>true</code> if the positions need to be scaled to the surface before the height is added.
  38788. * @returns {Number[]} The input array of positions, scaled to height
  38789. */
  38790. PolygonPipeline.scaleToGeodeticHeight = function(positions, height, ellipsoid, scaleToSurface) {
  38791. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  38792. var n = scaleToGeodeticHeightN;
  38793. var p = scaleToGeodeticHeightP;
  38794. height = defaultValue(height, 0.0);
  38795. scaleToSurface = defaultValue(scaleToSurface, true);
  38796. if (defined(positions)) {
  38797. var length = positions.length;
  38798. for ( var i = 0; i < length; i += 3) {
  38799. Cartesian3.fromArray(positions, i, p);
  38800. if (scaleToSurface) {
  38801. p = ellipsoid.scaleToGeodeticSurface(p, p);
  38802. }
  38803. if (height !== 0) {
  38804. n = ellipsoid.geodeticSurfaceNormal(p, n);
  38805. Cartesian3.multiplyByScalar(n, height, n);
  38806. Cartesian3.add(p, n, p);
  38807. }
  38808. positions[i] = p.x;
  38809. positions[i + 1] = p.y;
  38810. positions[i + 2] = p.z;
  38811. }
  38812. }
  38813. return positions;
  38814. };
  38815. return PolygonPipeline;
  38816. });
  38817. /*global define*/
  38818. define('Core/CorridorGeometry',[
  38819. './arrayRemoveDuplicates',
  38820. './BoundingSphere',
  38821. './Cartesian3',
  38822. './Cartographic',
  38823. './ComponentDatatype',
  38824. './CornerType',
  38825. './CorridorGeometryLibrary',
  38826. './defaultValue',
  38827. './defined',
  38828. './defineProperties',
  38829. './DeveloperError',
  38830. './Ellipsoid',
  38831. './Geometry',
  38832. './GeometryAttribute',
  38833. './GeometryAttributes',
  38834. './IndexDatatype',
  38835. './Math',
  38836. './PolygonPipeline',
  38837. './PrimitiveType',
  38838. './Rectangle',
  38839. './VertexFormat'
  38840. ], function(
  38841. arrayRemoveDuplicates,
  38842. BoundingSphere,
  38843. Cartesian3,
  38844. Cartographic,
  38845. ComponentDatatype,
  38846. CornerType,
  38847. CorridorGeometryLibrary,
  38848. defaultValue,
  38849. defined,
  38850. defineProperties,
  38851. DeveloperError,
  38852. Ellipsoid,
  38853. Geometry,
  38854. GeometryAttribute,
  38855. GeometryAttributes,
  38856. IndexDatatype,
  38857. CesiumMath,
  38858. PolygonPipeline,
  38859. PrimitiveType,
  38860. Rectangle,
  38861. VertexFormat) {
  38862. 'use strict';
  38863. var cartesian1 = new Cartesian3();
  38864. var cartesian2 = new Cartesian3();
  38865. var cartesian3 = new Cartesian3();
  38866. var cartesian4 = new Cartesian3();
  38867. var cartesian5 = new Cartesian3();
  38868. var cartesian6 = new Cartesian3();
  38869. var scratch1 = new Cartesian3();
  38870. var scratch2 = new Cartesian3();
  38871. function addNormals(attr, normal, left, front, back, vertexFormat) {
  38872. var normals = attr.normals;
  38873. var tangents = attr.tangents;
  38874. var binormals = attr.binormals;
  38875. var forward = Cartesian3.normalize(Cartesian3.cross(left, normal, scratch1), scratch1);
  38876. if (vertexFormat.normal) {
  38877. CorridorGeometryLibrary.addAttribute(normals, normal, front, back);
  38878. }
  38879. if (vertexFormat.binormal) {
  38880. CorridorGeometryLibrary.addAttribute(binormals, left, front, back);
  38881. }
  38882. if (vertexFormat.tangent) {
  38883. CorridorGeometryLibrary.addAttribute(tangents, forward, front, back);
  38884. }
  38885. }
  38886. function combine(computedPositions, vertexFormat, ellipsoid) {
  38887. var positions = computedPositions.positions;
  38888. var corners = computedPositions.corners;
  38889. var endPositions = computedPositions.endPositions;
  38890. var computedLefts = computedPositions.lefts;
  38891. var computedNormals = computedPositions.normals;
  38892. var attributes = new GeometryAttributes();
  38893. var corner;
  38894. var leftCount = 0;
  38895. var rightCount = 0;
  38896. var i;
  38897. var indicesLength = 0;
  38898. var length;
  38899. for (i = 0; i < positions.length; i += 2) {
  38900. length = positions[i].length - 3;
  38901. leftCount += length; //subtracting 3 to account for duplicate points at corners
  38902. indicesLength += length*2;
  38903. rightCount += positions[i + 1].length - 3;
  38904. }
  38905. leftCount += 3; //add back count for end positions
  38906. rightCount += 3;
  38907. for (i = 0; i < corners.length; i++) {
  38908. corner = corners[i];
  38909. var leftSide = corners[i].leftPositions;
  38910. if (defined(leftSide)) {
  38911. length = leftSide.length;
  38912. leftCount += length;
  38913. indicesLength += length;
  38914. } else {
  38915. length = corners[i].rightPositions.length;
  38916. rightCount += length;
  38917. indicesLength += length;
  38918. }
  38919. }
  38920. var addEndPositions = defined(endPositions);
  38921. var endPositionLength;
  38922. if (addEndPositions) {
  38923. endPositionLength = endPositions[0].length - 3;
  38924. leftCount += endPositionLength;
  38925. rightCount += endPositionLength;
  38926. endPositionLength /= 3;
  38927. indicesLength += endPositionLength * 6;
  38928. }
  38929. var size = leftCount + rightCount;
  38930. var finalPositions = new Float64Array(size);
  38931. var normals = (vertexFormat.normal) ? new Float32Array(size) : undefined;
  38932. var tangents = (vertexFormat.tangent) ? new Float32Array(size) : undefined;
  38933. var binormals = (vertexFormat.binormal) ? new Float32Array(size) : undefined;
  38934. var attr = {
  38935. normals : normals,
  38936. tangents : tangents,
  38937. binormals : binormals
  38938. };
  38939. var front = 0;
  38940. var back = size - 1;
  38941. var UL, LL, UR, LR;
  38942. var normal = cartesian1;
  38943. var left = cartesian2;
  38944. var rightPos, leftPos;
  38945. var halfLength = endPositionLength / 2;
  38946. var indices = IndexDatatype.createTypedArray(size / 3, indicesLength);
  38947. var index = 0;
  38948. if (addEndPositions) { // add rounded end
  38949. leftPos = cartesian3;
  38950. rightPos = cartesian4;
  38951. var firstEndPositions = endPositions[0];
  38952. normal = Cartesian3.fromArray(computedNormals, 0, normal);
  38953. left = Cartesian3.fromArray(computedLefts, 0, left);
  38954. for (i = 0; i < halfLength; i++) {
  38955. leftPos = Cartesian3.fromArray(firstEndPositions, (halfLength - 1 - i) * 3, leftPos);
  38956. rightPos = Cartesian3.fromArray(firstEndPositions, (halfLength + i) * 3, rightPos);
  38957. CorridorGeometryLibrary.addAttribute(finalPositions, rightPos, front);
  38958. CorridorGeometryLibrary.addAttribute(finalPositions, leftPos, undefined, back);
  38959. addNormals(attr, normal, left, front, back, vertexFormat);
  38960. LL = front / 3;
  38961. LR = LL + 1;
  38962. UL = (back - 2) / 3;
  38963. UR = UL - 1;
  38964. indices[index++] = UL;
  38965. indices[index++] = LL;
  38966. indices[index++] = UR;
  38967. indices[index++] = UR;
  38968. indices[index++] = LL;
  38969. indices[index++] = LR;
  38970. front += 3;
  38971. back -= 3;
  38972. }
  38973. }
  38974. var posIndex = 0;
  38975. var compIndex = 0;
  38976. var rightEdge = positions[posIndex++]; //add first two edges
  38977. var leftEdge = positions[posIndex++];
  38978. finalPositions.set(rightEdge, front);
  38979. finalPositions.set(leftEdge, back - leftEdge.length + 1);
  38980. left = Cartesian3.fromArray(computedLefts, compIndex, left);
  38981. var rightNormal;
  38982. var leftNormal;
  38983. length = leftEdge.length - 3;
  38984. for (i = 0; i < length; i += 3) {
  38985. rightNormal = ellipsoid.geodeticSurfaceNormal(Cartesian3.fromArray(rightEdge, i, scratch1), scratch1);
  38986. leftNormal = ellipsoid.geodeticSurfaceNormal(Cartesian3.fromArray(leftEdge, length - i, scratch2), scratch2);
  38987. normal = Cartesian3.normalize(Cartesian3.add(rightNormal, leftNormal, normal), normal);
  38988. addNormals(attr, normal, left, front, back, vertexFormat);
  38989. LL = front / 3;
  38990. LR = LL + 1;
  38991. UL = (back - 2) / 3;
  38992. UR = UL - 1;
  38993. indices[index++] = UL;
  38994. indices[index++] = LL;
  38995. indices[index++] = UR;
  38996. indices[index++] = UR;
  38997. indices[index++] = LL;
  38998. indices[index++] = LR;
  38999. front += 3;
  39000. back -= 3;
  39001. }
  39002. rightNormal = ellipsoid.geodeticSurfaceNormal(Cartesian3.fromArray(rightEdge, length, scratch1), scratch1);
  39003. leftNormal = ellipsoid.geodeticSurfaceNormal(Cartesian3.fromArray(leftEdge, length, scratch2), scratch2);
  39004. normal = Cartesian3.normalize(Cartesian3.add(rightNormal, leftNormal, normal), normal);
  39005. compIndex += 3;
  39006. for (i = 0; i < corners.length; i++) {
  39007. var j;
  39008. corner = corners[i];
  39009. var l = corner.leftPositions;
  39010. var r = corner.rightPositions;
  39011. var pivot;
  39012. var start;
  39013. var outsidePoint = cartesian6;
  39014. var previousPoint = cartesian3;
  39015. var nextPoint = cartesian4;
  39016. normal = Cartesian3.fromArray(computedNormals, compIndex, normal);
  39017. if (defined(l)) {
  39018. addNormals(attr, normal, left, undefined, back, vertexFormat);
  39019. back -= 3;
  39020. pivot = LR;
  39021. start = UR;
  39022. for (j = 0; j < l.length / 3; j++) {
  39023. outsidePoint = Cartesian3.fromArray(l, j * 3, outsidePoint);
  39024. indices[index++] = pivot;
  39025. indices[index++] = start - j - 1;
  39026. indices[index++] = start - j;
  39027. CorridorGeometryLibrary.addAttribute(finalPositions, outsidePoint, undefined, back);
  39028. previousPoint = Cartesian3.fromArray(finalPositions, (start - j - 1) * 3, previousPoint);
  39029. nextPoint = Cartesian3.fromArray(finalPositions, pivot * 3, nextPoint);
  39030. left = Cartesian3.normalize(Cartesian3.subtract(previousPoint, nextPoint, left), left);
  39031. addNormals(attr, normal, left, undefined, back, vertexFormat);
  39032. back -= 3;
  39033. }
  39034. outsidePoint = Cartesian3.fromArray(finalPositions, pivot * 3, outsidePoint);
  39035. previousPoint = Cartesian3.subtract(Cartesian3.fromArray(finalPositions, (start) * 3, previousPoint), outsidePoint, previousPoint);
  39036. nextPoint = Cartesian3.subtract(Cartesian3.fromArray(finalPositions, (start - j) * 3, nextPoint), outsidePoint, nextPoint);
  39037. left = Cartesian3.normalize(Cartesian3.add(previousPoint, nextPoint, left), left);
  39038. addNormals(attr, normal, left, front, undefined, vertexFormat);
  39039. front += 3;
  39040. } else {
  39041. addNormals(attr, normal, left, front, undefined, vertexFormat);
  39042. front += 3;
  39043. pivot = UR;
  39044. start = LR;
  39045. for (j = 0; j < r.length / 3; j++) {
  39046. outsidePoint = Cartesian3.fromArray(r, j * 3, outsidePoint);
  39047. indices[index++] = pivot;
  39048. indices[index++] = start + j;
  39049. indices[index++] = start + j + 1;
  39050. CorridorGeometryLibrary.addAttribute(finalPositions, outsidePoint, front);
  39051. previousPoint = Cartesian3.fromArray(finalPositions, pivot * 3, previousPoint);
  39052. nextPoint = Cartesian3.fromArray(finalPositions, (start + j) * 3, nextPoint);
  39053. left = Cartesian3.normalize(Cartesian3.subtract(previousPoint, nextPoint, left), left);
  39054. addNormals(attr, normal, left, front, undefined, vertexFormat);
  39055. front += 3;
  39056. }
  39057. outsidePoint = Cartesian3.fromArray(finalPositions, pivot * 3, outsidePoint);
  39058. previousPoint = Cartesian3.subtract(Cartesian3.fromArray(finalPositions, (start + j) * 3, previousPoint), outsidePoint, previousPoint);
  39059. nextPoint = Cartesian3.subtract(Cartesian3.fromArray(finalPositions, start * 3, nextPoint), outsidePoint, nextPoint);
  39060. left = Cartesian3.normalize(Cartesian3.negate(Cartesian3.add(nextPoint, previousPoint, left), left), left);
  39061. addNormals(attr, normal, left, undefined, back, vertexFormat);
  39062. back -= 3;
  39063. }
  39064. rightEdge = positions[posIndex++];
  39065. leftEdge = positions[posIndex++];
  39066. rightEdge.splice(0, 3); //remove duplicate points added by corner
  39067. leftEdge.splice(leftEdge.length - 3, 3);
  39068. finalPositions.set(rightEdge, front);
  39069. finalPositions.set(leftEdge, back - leftEdge.length + 1);
  39070. length = leftEdge.length - 3;
  39071. compIndex += 3;
  39072. left = Cartesian3.fromArray(computedLefts, compIndex, left);
  39073. for (j = 0; j < leftEdge.length; j += 3) {
  39074. rightNormal = ellipsoid.geodeticSurfaceNormal(Cartesian3.fromArray(rightEdge, j, scratch1), scratch1);
  39075. leftNormal = ellipsoid.geodeticSurfaceNormal(Cartesian3.fromArray(leftEdge, length - j, scratch2), scratch2);
  39076. normal = Cartesian3.normalize(Cartesian3.add(rightNormal, leftNormal, normal), normal);
  39077. addNormals(attr, normal, left, front, back, vertexFormat);
  39078. LR = front / 3;
  39079. LL = LR - 1;
  39080. UR = (back - 2) / 3;
  39081. UL = UR + 1;
  39082. indices[index++] = UL;
  39083. indices[index++] = LL;
  39084. indices[index++] = UR;
  39085. indices[index++] = UR;
  39086. indices[index++] = LL;
  39087. indices[index++] = LR;
  39088. front += 3;
  39089. back -= 3;
  39090. }
  39091. front -= 3;
  39092. back += 3;
  39093. }
  39094. normal = Cartesian3.fromArray(computedNormals, computedNormals.length - 3, normal);
  39095. addNormals(attr, normal, left, front, back, vertexFormat);
  39096. if (addEndPositions) { // add rounded end
  39097. front += 3;
  39098. back -= 3;
  39099. leftPos = cartesian3;
  39100. rightPos = cartesian4;
  39101. var lastEndPositions = endPositions[1];
  39102. for (i = 0; i < halfLength; i++) {
  39103. leftPos = Cartesian3.fromArray(lastEndPositions, (endPositionLength - i - 1) * 3, leftPos);
  39104. rightPos = Cartesian3.fromArray(lastEndPositions, i * 3, rightPos);
  39105. CorridorGeometryLibrary.addAttribute(finalPositions, leftPos, undefined, back);
  39106. CorridorGeometryLibrary.addAttribute(finalPositions, rightPos, front);
  39107. addNormals(attr, normal, left, front, back, vertexFormat);
  39108. LR = front / 3;
  39109. LL = LR - 1;
  39110. UR = (back - 2) / 3;
  39111. UL = UR + 1;
  39112. indices[index++] = UL;
  39113. indices[index++] = LL;
  39114. indices[index++] = UR;
  39115. indices[index++] = UR;
  39116. indices[index++] = LL;
  39117. indices[index++] = LR;
  39118. front += 3;
  39119. back -= 3;
  39120. }
  39121. }
  39122. attributes.position = new GeometryAttribute({
  39123. componentDatatype : ComponentDatatype.DOUBLE,
  39124. componentsPerAttribute : 3,
  39125. values : finalPositions
  39126. });
  39127. if (vertexFormat.st) {
  39128. var st = new Float32Array(size / 3 * 2);
  39129. var rightSt;
  39130. var leftSt;
  39131. var stIndex = 0;
  39132. if (addEndPositions) {
  39133. leftCount /= 3;
  39134. rightCount /= 3;
  39135. var theta = Math.PI / (endPositionLength + 1);
  39136. leftSt = 1 / (leftCount - endPositionLength + 1);
  39137. rightSt = 1 / (rightCount - endPositionLength + 1);
  39138. var a;
  39139. var halfEndPos = endPositionLength / 2;
  39140. for (i = halfEndPos + 1; i < endPositionLength + 1; i++) { // lower left rounded end
  39141. a = CesiumMath.PI_OVER_TWO + theta * i;
  39142. st[stIndex++] = rightSt * (1 + Math.cos(a));
  39143. st[stIndex++] = 0.5 * (1 + Math.sin(a));
  39144. }
  39145. for (i = 1; i < rightCount - endPositionLength + 1; i++) { // bottom edge
  39146. st[stIndex++] = i * rightSt;
  39147. st[stIndex++] = 0;
  39148. }
  39149. for (i = endPositionLength; i > halfEndPos; i--) { // lower right rounded end
  39150. a = CesiumMath.PI_OVER_TWO - i * theta;
  39151. st[stIndex++] = 1 - rightSt * (1 + Math.cos(a));
  39152. st[stIndex++] = 0.5 * (1 + Math.sin(a));
  39153. }
  39154. for (i = halfEndPos; i > 0; i--) { // upper right rounded end
  39155. a = CesiumMath.PI_OVER_TWO - theta * i;
  39156. st[stIndex++] = 1 - leftSt * (1 + Math.cos(a));
  39157. st[stIndex++] = 0.5 * (1 + Math.sin(a));
  39158. }
  39159. for (i = leftCount - endPositionLength; i > 0; i--) { // top edge
  39160. st[stIndex++] = i * leftSt;
  39161. st[stIndex++] = 1;
  39162. }
  39163. for (i = 1; i < halfEndPos + 1; i++) { // upper left rounded end
  39164. a = CesiumMath.PI_OVER_TWO + theta * i;
  39165. st[stIndex++] = leftSt * (1 + Math.cos(a));
  39166. st[stIndex++] = 0.5 * (1 + Math.sin(a));
  39167. }
  39168. } else {
  39169. leftCount /= 3;
  39170. rightCount /= 3;
  39171. leftSt = 1 / (leftCount - 1);
  39172. rightSt = 1 / (rightCount - 1);
  39173. for (i = 0; i < rightCount; i++) { // bottom edge
  39174. st[stIndex++] = i * rightSt;
  39175. st[stIndex++] = 0;
  39176. }
  39177. for (i = leftCount; i > 0; i--) { // top edge
  39178. st[stIndex++] = (i - 1) * leftSt;
  39179. st[stIndex++] = 1;
  39180. }
  39181. }
  39182. attributes.st = new GeometryAttribute({
  39183. componentDatatype : ComponentDatatype.FLOAT,
  39184. componentsPerAttribute : 2,
  39185. values : st
  39186. });
  39187. }
  39188. if (vertexFormat.normal) {
  39189. attributes.normal = new GeometryAttribute({
  39190. componentDatatype : ComponentDatatype.FLOAT,
  39191. componentsPerAttribute : 3,
  39192. values : attr.normals
  39193. });
  39194. }
  39195. if (vertexFormat.tangent) {
  39196. attributes.tangent = new GeometryAttribute({
  39197. componentDatatype : ComponentDatatype.FLOAT,
  39198. componentsPerAttribute : 3,
  39199. values : attr.tangents
  39200. });
  39201. }
  39202. if (vertexFormat.binormal) {
  39203. attributes.binormal = new GeometryAttribute({
  39204. componentDatatype : ComponentDatatype.FLOAT,
  39205. componentsPerAttribute : 3,
  39206. values : attr.binormals
  39207. });
  39208. }
  39209. return {
  39210. attributes : attributes,
  39211. indices : indices
  39212. };
  39213. }
  39214. function extrudedAttributes(attributes, vertexFormat) {
  39215. if (!vertexFormat.normal && !vertexFormat.binormal && !vertexFormat.tangent && !vertexFormat.st) {
  39216. return attributes;
  39217. }
  39218. var positions = attributes.position.values;
  39219. var topNormals;
  39220. var topBinormals;
  39221. if (vertexFormat.normal || vertexFormat.binormal) {
  39222. topNormals = attributes.normal.values;
  39223. topBinormals = attributes.binormal.values;
  39224. }
  39225. var size = attributes.position.values.length / 18;
  39226. var threeSize = size * 3;
  39227. var twoSize = size * 2;
  39228. var sixSize = threeSize * 2;
  39229. var i;
  39230. if (vertexFormat.normal || vertexFormat.binormal || vertexFormat.tangent) {
  39231. var normals = (vertexFormat.normal) ? new Float32Array(threeSize * 6) : undefined;
  39232. var binormals = (vertexFormat.binormal) ? new Float32Array(threeSize * 6) : undefined;
  39233. var tangents = (vertexFormat.tangent) ? new Float32Array(threeSize * 6) : undefined;
  39234. var topPosition = cartesian1;
  39235. var bottomPosition = cartesian2;
  39236. var previousPosition = cartesian3;
  39237. var normal = cartesian4;
  39238. var tangent = cartesian5;
  39239. var binormal = cartesian6;
  39240. var attrIndex = sixSize;
  39241. for (i = 0; i < threeSize; i += 3) {
  39242. var attrIndexOffset = attrIndex + sixSize;
  39243. topPosition = Cartesian3.fromArray(positions, i, topPosition);
  39244. bottomPosition = Cartesian3.fromArray(positions, i + threeSize, bottomPosition);
  39245. previousPosition = Cartesian3.fromArray(positions, (i + 3) % threeSize, previousPosition);
  39246. bottomPosition = Cartesian3.subtract(bottomPosition, topPosition, bottomPosition);
  39247. previousPosition = Cartesian3.subtract(previousPosition, topPosition, previousPosition);
  39248. normal = Cartesian3.normalize(Cartesian3.cross(bottomPosition, previousPosition, normal), normal);
  39249. if (vertexFormat.normal) {
  39250. CorridorGeometryLibrary.addAttribute(normals, normal, attrIndexOffset);
  39251. CorridorGeometryLibrary.addAttribute(normals, normal, attrIndexOffset + 3);
  39252. CorridorGeometryLibrary.addAttribute(normals, normal, attrIndex);
  39253. CorridorGeometryLibrary.addAttribute(normals, normal, attrIndex + 3);
  39254. }
  39255. if (vertexFormat.tangent || vertexFormat.binormal) {
  39256. binormal = Cartesian3.fromArray(topNormals, i, binormal);
  39257. if (vertexFormat.binormal) {
  39258. CorridorGeometryLibrary.addAttribute(binormals, binormal, attrIndexOffset);
  39259. CorridorGeometryLibrary.addAttribute(binormals, binormal, attrIndexOffset + 3);
  39260. CorridorGeometryLibrary.addAttribute(binormals, binormal, attrIndex);
  39261. CorridorGeometryLibrary.addAttribute(binormals, binormal, attrIndex + 3);
  39262. }
  39263. if (vertexFormat.tangent) {
  39264. tangent = Cartesian3.normalize(Cartesian3.cross(binormal, normal, tangent), tangent);
  39265. CorridorGeometryLibrary.addAttribute(tangents, tangent, attrIndexOffset);
  39266. CorridorGeometryLibrary.addAttribute(tangents, tangent, attrIndexOffset + 3);
  39267. CorridorGeometryLibrary.addAttribute(tangents, tangent, attrIndex);
  39268. CorridorGeometryLibrary.addAttribute(tangents, tangent, attrIndex + 3);
  39269. }
  39270. }
  39271. attrIndex += 6;
  39272. }
  39273. if (vertexFormat.normal) {
  39274. normals.set(topNormals); //top
  39275. for (i = 0; i < threeSize; i += 3) { //bottom normals
  39276. normals[i + threeSize] = -topNormals[i];
  39277. normals[i + threeSize + 1] = -topNormals[i + 1];
  39278. normals[i + threeSize + 2] = -topNormals[i + 2];
  39279. }
  39280. attributes.normal.values = normals;
  39281. } else {
  39282. attributes.normal = undefined;
  39283. }
  39284. if (vertexFormat.binormal) {
  39285. binormals.set(topBinormals); //top
  39286. binormals.set(topBinormals, threeSize); //bottom
  39287. attributes.binormal.values = binormals;
  39288. } else {
  39289. attributes.binormal = undefined;
  39290. }
  39291. if (vertexFormat.tangent) {
  39292. var topTangents = attributes.tangent.values;
  39293. tangents.set(topTangents); //top
  39294. tangents.set(topTangents, threeSize); //bottom
  39295. attributes.tangent.values = tangents;
  39296. }
  39297. }
  39298. if (vertexFormat.st) {
  39299. var topSt = attributes.st.values;
  39300. var st = new Float32Array(twoSize * 6);
  39301. st.set(topSt); //top
  39302. st.set(topSt, twoSize); //bottom
  39303. var index = twoSize * 2;
  39304. for ( var j = 0; j < 2; j++) {
  39305. st[index++] = topSt[0];
  39306. st[index++] = topSt[1];
  39307. for (i = 2; i < twoSize; i += 2) {
  39308. var s = topSt[i];
  39309. var t = topSt[i + 1];
  39310. st[index++] = s;
  39311. st[index++] = t;
  39312. st[index++] = s;
  39313. st[index++] = t;
  39314. }
  39315. st[index++] = topSt[0];
  39316. st[index++] = topSt[1];
  39317. }
  39318. attributes.st.values = st;
  39319. }
  39320. return attributes;
  39321. }
  39322. function addWallPositions(positions, index, wallPositions) {
  39323. wallPositions[index++] = positions[0];
  39324. wallPositions[index++] = positions[1];
  39325. wallPositions[index++] = positions[2];
  39326. for ( var i = 3; i < positions.length; i += 3) {
  39327. var x = positions[i];
  39328. var y = positions[i + 1];
  39329. var z = positions[i + 2];
  39330. wallPositions[index++] = x;
  39331. wallPositions[index++] = y;
  39332. wallPositions[index++] = z;
  39333. wallPositions[index++] = x;
  39334. wallPositions[index++] = y;
  39335. wallPositions[index++] = z;
  39336. }
  39337. wallPositions[index++] = positions[0];
  39338. wallPositions[index++] = positions[1];
  39339. wallPositions[index++] = positions[2];
  39340. return wallPositions;
  39341. }
  39342. function computePositionsExtruded(params, vertexFormat) {
  39343. var topVertexFormat = new VertexFormat({
  39344. position : vertexFormat.positon,
  39345. normal : (vertexFormat.normal || vertexFormat.binormal),
  39346. tangent : vertexFormat.tangent,
  39347. binormal : (vertexFormat.normal || vertexFormat.binormal),
  39348. st : vertexFormat.st
  39349. });
  39350. var ellipsoid = params.ellipsoid;
  39351. var computedPositions = CorridorGeometryLibrary.computePositions(params);
  39352. var attr = combine(computedPositions, topVertexFormat, ellipsoid);
  39353. var height = params.height;
  39354. var extrudedHeight = params.extrudedHeight;
  39355. var attributes = attr.attributes;
  39356. var indices = attr.indices;
  39357. var positions = attributes.position.values;
  39358. var length = positions.length;
  39359. var newPositions = new Float64Array(length * 6);
  39360. var extrudedPositions = new Float64Array(length);
  39361. extrudedPositions.set(positions);
  39362. var wallPositions = new Float64Array(length * 4);
  39363. positions = PolygonPipeline.scaleToGeodeticHeight(positions, height, ellipsoid);
  39364. wallPositions = addWallPositions(positions, 0, wallPositions);
  39365. extrudedPositions = PolygonPipeline.scaleToGeodeticHeight(extrudedPositions, extrudedHeight, ellipsoid);
  39366. wallPositions = addWallPositions(extrudedPositions, length * 2, wallPositions);
  39367. newPositions.set(positions);
  39368. newPositions.set(extrudedPositions, length);
  39369. newPositions.set(wallPositions, length * 2);
  39370. attributes.position.values = newPositions;
  39371. length /= 3;
  39372. var i;
  39373. var iLength = indices.length;
  39374. var twoLength = length + length;
  39375. var newIndices = IndexDatatype.createTypedArray(newPositions.length / 3, iLength * 2 + twoLength * 3);
  39376. newIndices.set(indices);
  39377. var index = iLength;
  39378. for (i = 0; i < iLength; i += 3) { // bottom indices
  39379. var v0 = indices[i];
  39380. var v1 = indices[i + 1];
  39381. var v2 = indices[i + 2];
  39382. newIndices[index++] = v2 + length;
  39383. newIndices[index++] = v1 + length;
  39384. newIndices[index++] = v0 + length;
  39385. }
  39386. attributes = extrudedAttributes(attributes, vertexFormat);
  39387. var UL, LL, UR, LR;
  39388. for (i = 0; i < twoLength; i += 2) { //wall indices
  39389. UL = i + twoLength;
  39390. LL = UL + twoLength;
  39391. UR = UL + 1;
  39392. LR = LL + 1;
  39393. newIndices[index++] = UL;
  39394. newIndices[index++] = LL;
  39395. newIndices[index++] = UR;
  39396. newIndices[index++] = UR;
  39397. newIndices[index++] = LL;
  39398. newIndices[index++] = LR;
  39399. }
  39400. return {
  39401. attributes : attributes,
  39402. indices : newIndices
  39403. };
  39404. }
  39405. var scratchCartesian1 = new Cartesian3();
  39406. var scratchCartesian2 = new Cartesian3();
  39407. var scratchCartographic = new Cartographic();
  39408. function computeOffsetPoints(position1, position2, ellipsoid, halfWidth, min, max) {
  39409. // Compute direction of offset the point
  39410. var direction = Cartesian3.subtract(position2, position1, scratchCartesian1);
  39411. Cartesian3.normalize(direction, direction);
  39412. var normal = ellipsoid.geodeticSurfaceNormal(position1, scratchCartesian2);
  39413. var offsetDirection = Cartesian3.cross(direction, normal, scratchCartesian1);
  39414. Cartesian3.multiplyByScalar(offsetDirection, halfWidth, offsetDirection);
  39415. var minLat = min.latitude;
  39416. var minLon = min.longitude;
  39417. var maxLat = max.latitude;
  39418. var maxLon = max.longitude;
  39419. // Compute 2 offset points
  39420. Cartesian3.add(position1, offsetDirection, scratchCartesian2);
  39421. ellipsoid.cartesianToCartographic(scratchCartesian2, scratchCartographic);
  39422. var lat = scratchCartographic.latitude;
  39423. var lon = scratchCartographic.longitude;
  39424. minLat = Math.min(minLat, lat);
  39425. minLon = Math.min(minLon, lon);
  39426. maxLat = Math.max(maxLat, lat);
  39427. maxLon = Math.max(maxLon, lon);
  39428. Cartesian3.subtract(position1, offsetDirection, scratchCartesian2);
  39429. ellipsoid.cartesianToCartographic(scratchCartesian2, scratchCartographic);
  39430. lat = scratchCartographic.latitude;
  39431. lon = scratchCartographic.longitude;
  39432. minLat = Math.min(minLat, lat);
  39433. minLon = Math.min(minLon, lon);
  39434. maxLat = Math.max(maxLat, lat);
  39435. maxLon = Math.max(maxLon, lon);
  39436. min.latitude = minLat;
  39437. min.longitude = minLon;
  39438. max.latitude = maxLat;
  39439. max.longitude = maxLon;
  39440. }
  39441. var scratchCartesianOffset = new Cartesian3();
  39442. var scratchCartesianEnds = new Cartesian3();
  39443. var scratchCartographicMin = new Cartographic();
  39444. var scratchCartographicMax = new Cartographic();
  39445. function computeRectangle(positions, ellipsoid, width, cornerType) {
  39446. var cleanPositions = arrayRemoveDuplicates(positions, Cartesian3.equalsEpsilon);
  39447. var length = cleanPositions.length;
  39448. if (length < 2 || width <= 0) {
  39449. return new Rectangle();
  39450. }
  39451. var halfWidth = width * 0.5;
  39452. scratchCartographicMin.latitude = Number.POSITIVE_INFINITY;
  39453. scratchCartographicMin.longitude = Number.POSITIVE_INFINITY;
  39454. scratchCartographicMax.latitude = Number.NEGATIVE_INFINITY;
  39455. scratchCartographicMax.longitude = Number.NEGATIVE_INFINITY;
  39456. var lat, lon;
  39457. if (cornerType === CornerType.ROUNDED) {
  39458. // Compute start cap
  39459. var first = cleanPositions[0];
  39460. Cartesian3.subtract(first, cleanPositions[1], scratchCartesianOffset);
  39461. Cartesian3.normalize(scratchCartesianOffset, scratchCartesianOffset);
  39462. Cartesian3.multiplyByScalar(scratchCartesianOffset, halfWidth, scratchCartesianOffset);
  39463. Cartesian3.add(first, scratchCartesianOffset, scratchCartesianEnds);
  39464. ellipsoid.cartesianToCartographic(scratchCartesianEnds, scratchCartographic);
  39465. lat = scratchCartographic.latitude;
  39466. lon = scratchCartographic.longitude;
  39467. scratchCartographicMin.latitude = Math.min(scratchCartographicMin.latitude, lat);
  39468. scratchCartographicMin.longitude = Math.min(scratchCartographicMin.longitude, lon);
  39469. scratchCartographicMax.latitude = Math.max(scratchCartographicMax.latitude, lat);
  39470. scratchCartographicMax.longitude = Math.max(scratchCartographicMax.longitude, lon);
  39471. }
  39472. // Compute the rest
  39473. for (var i = 0; i < length-1; ++i) {
  39474. computeOffsetPoints(cleanPositions[i], cleanPositions[i+1], ellipsoid, halfWidth,
  39475. scratchCartographicMin, scratchCartographicMax);
  39476. }
  39477. // Compute ending point
  39478. var last = cleanPositions[length-1];
  39479. Cartesian3.subtract(last, cleanPositions[length-2], scratchCartesianOffset);
  39480. Cartesian3.normalize(scratchCartesianOffset, scratchCartesianOffset);
  39481. Cartesian3.multiplyByScalar(scratchCartesianOffset, halfWidth, scratchCartesianOffset);
  39482. Cartesian3.add(last, scratchCartesianOffset, scratchCartesianEnds);
  39483. computeOffsetPoints(last, scratchCartesianEnds, ellipsoid, halfWidth,
  39484. scratchCartographicMin, scratchCartographicMax);
  39485. if (cornerType === CornerType.ROUNDED) {
  39486. // Compute end cap
  39487. ellipsoid.cartesianToCartographic(scratchCartesianEnds, scratchCartographic);
  39488. lat = scratchCartographic.latitude;
  39489. lon = scratchCartographic.longitude;
  39490. scratchCartographicMin.latitude = Math.min(scratchCartographicMin.latitude, lat);
  39491. scratchCartographicMin.longitude = Math.min(scratchCartographicMin.longitude, lon);
  39492. scratchCartographicMax.latitude = Math.max(scratchCartographicMax.latitude, lat);
  39493. scratchCartographicMax.longitude = Math.max(scratchCartographicMax.longitude, lon);
  39494. }
  39495. var rectangle = new Rectangle();
  39496. rectangle.north = scratchCartographicMax.latitude;
  39497. rectangle.south = scratchCartographicMin.latitude;
  39498. rectangle.east = scratchCartographicMax.longitude;
  39499. rectangle.west = scratchCartographicMin.longitude;
  39500. return rectangle;
  39501. }
  39502. /**
  39503. * A description of a corridor. Corridor geometry can be rendered with both {@link Primitive} and {@link GroundPrimitive}.
  39504. *
  39505. * @alias CorridorGeometry
  39506. * @constructor
  39507. *
  39508. * @param {Object} options Object with the following properties:
  39509. * @param {Cartesian3[]} options.positions An array of positions that define the center of the corridor.
  39510. * @param {Number} options.width The distance between the edges of the corridor in meters.
  39511. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
  39512. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  39513. * @param {Number} [options.height=0] The distance in meters between the ellipsoid surface and the positions.
  39514. * @param {Number} [options.extrudedHeight] The distance in meters between the ellipsoid surface and the extruded face.
  39515. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  39516. * @param {CornerType} [options.cornerType=CornerType.ROUNDED] Determines the style of the corners.
  39517. *
  39518. * @see CorridorGeometry.createGeometry
  39519. * @see Packable
  39520. *
  39521. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Corridor.html|Cesium Sandcastle Corridor Demo}
  39522. *
  39523. * @example
  39524. * var corridor = new Cesium.CorridorGeometry({
  39525. * vertexFormat : Cesium.VertexFormat.POSITION_ONLY,
  39526. * positions : Cesium.Cartesian3.fromDegreesArray([-72.0, 40.0, -70.0, 35.0]),
  39527. * width : 100000
  39528. * });
  39529. */
  39530. function CorridorGeometry(options) {
  39531. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  39532. var positions = options.positions;
  39533. var width = options.width;
  39534. if (!defined(positions)) {
  39535. throw new DeveloperError('options.positions is required.');
  39536. }
  39537. if (!defined(width)) {
  39538. throw new DeveloperError('options.width is required.');
  39539. }
  39540. this._positions = positions;
  39541. this._ellipsoid = Ellipsoid.clone(defaultValue(options.ellipsoid, Ellipsoid.WGS84));
  39542. this._vertexFormat = VertexFormat.clone(defaultValue(options.vertexFormat, VertexFormat.DEFAULT));
  39543. this._width = width;
  39544. this._height = defaultValue(options.height, 0);
  39545. this._extrudedHeight = defaultValue(options.extrudedHeight, this._height);
  39546. this._cornerType = defaultValue(options.cornerType, CornerType.ROUNDED);
  39547. this._granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  39548. this._workerName = 'createCorridorGeometry';
  39549. this._rectangle = computeRectangle(positions, this._ellipsoid, width, this._cornerType);
  39550. /**
  39551. * The number of elements used to pack the object into an array.
  39552. * @type {Number}
  39553. */
  39554. this.packedLength = 1 + positions.length * Cartesian3.packedLength + Ellipsoid.packedLength + VertexFormat.packedLength + Rectangle.packedLength + 5;
  39555. }
  39556. /**
  39557. * Stores the provided instance into the provided array.
  39558. *
  39559. * @param {CorridorGeometry} value The value to pack.
  39560. * @param {Number[]} array The array to pack into.
  39561. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  39562. *
  39563. * @returns {Number[]} The array that was packed into
  39564. */
  39565. CorridorGeometry.pack = function(value, array, startingIndex) {
  39566. if (!defined(value)) {
  39567. throw new DeveloperError('value is required');
  39568. }
  39569. if (!defined(array)) {
  39570. throw new DeveloperError('array is required');
  39571. }
  39572. startingIndex = defaultValue(startingIndex, 0);
  39573. var positions = value._positions;
  39574. var length = positions.length;
  39575. array[startingIndex++] = length;
  39576. for (var i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  39577. Cartesian3.pack(positions[i], array, startingIndex);
  39578. }
  39579. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  39580. startingIndex += Ellipsoid.packedLength;
  39581. VertexFormat.pack(value._vertexFormat, array, startingIndex);
  39582. startingIndex += VertexFormat.packedLength;
  39583. Rectangle.pack(value._rectangle, array, startingIndex);
  39584. startingIndex += Rectangle.packedLength;
  39585. array[startingIndex++] = value._width;
  39586. array[startingIndex++] = value._height;
  39587. array[startingIndex++] = value._extrudedHeight;
  39588. array[startingIndex++] = value._cornerType;
  39589. array[startingIndex] = value._granularity;
  39590. return array;
  39591. };
  39592. var scratchEllipsoid = Ellipsoid.clone(Ellipsoid.UNIT_SPHERE);
  39593. var scratchVertexFormat = new VertexFormat();
  39594. var scratchRectangle = new Rectangle();
  39595. var scratchOptions = {
  39596. positions : undefined,
  39597. ellipsoid : scratchEllipsoid,
  39598. vertexFormat : scratchVertexFormat,
  39599. width : undefined,
  39600. height : undefined,
  39601. extrudedHeight : undefined,
  39602. cornerType : undefined,
  39603. granularity : undefined
  39604. };
  39605. /**
  39606. * Retrieves an instance from a packed array.
  39607. *
  39608. * @param {Number[]} array The packed array.
  39609. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  39610. * @param {CorridorGeometry} [result] The object into which to store the result.
  39611. * @returns {CorridorGeometry} The modified result parameter or a new CorridorGeometry instance if one was not provided.
  39612. */
  39613. CorridorGeometry.unpack = function(array, startingIndex, result) {
  39614. if (!defined(array)) {
  39615. throw new DeveloperError('array is required');
  39616. }
  39617. startingIndex = defaultValue(startingIndex, 0);
  39618. var length = array[startingIndex++];
  39619. var positions = new Array(length);
  39620. for (var i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  39621. positions[i] = Cartesian3.unpack(array, startingIndex);
  39622. }
  39623. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  39624. startingIndex += Ellipsoid.packedLength;
  39625. var vertexFormat = VertexFormat.unpack(array, startingIndex, scratchVertexFormat);
  39626. startingIndex += VertexFormat.packedLength;
  39627. var rectangle = Rectangle.unpack(array, startingIndex, scratchRectangle);
  39628. startingIndex += Rectangle.packedLength;
  39629. var width = array[startingIndex++];
  39630. var height = array[startingIndex++];
  39631. var extrudedHeight = array[startingIndex++];
  39632. var cornerType = array[startingIndex++];
  39633. var granularity = array[startingIndex];
  39634. if (!defined(result)) {
  39635. scratchOptions.positions = positions;
  39636. scratchOptions.width = width;
  39637. scratchOptions.height = height;
  39638. scratchOptions.extrudedHeight = extrudedHeight;
  39639. scratchOptions.cornerType = cornerType;
  39640. scratchOptions.granularity = granularity;
  39641. return new CorridorGeometry(scratchOptions);
  39642. }
  39643. result._positions = positions;
  39644. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  39645. result._vertexFormat = VertexFormat.clone(vertexFormat, result._vertexFormat);
  39646. result._width = width;
  39647. result._height = height;
  39648. result._extrudedHeight = extrudedHeight;
  39649. result._cornerType = cornerType;
  39650. result._granularity = granularity;
  39651. result._rectangle = Rectangle.clone(rectangle);
  39652. return result;
  39653. };
  39654. /**
  39655. * Computes the geometric representation of a corridor, including its vertices, indices, and a bounding sphere.
  39656. *
  39657. * @param {CorridorGeometry} corridorGeometry A description of the corridor.
  39658. * @returns {Geometry|undefined} The computed vertices and indices.
  39659. */
  39660. CorridorGeometry.createGeometry = function(corridorGeometry) {
  39661. var positions = corridorGeometry._positions;
  39662. var height = corridorGeometry._height;
  39663. var width = corridorGeometry._width;
  39664. var extrudedHeight = corridorGeometry._extrudedHeight;
  39665. var extrude = (height !== extrudedHeight);
  39666. var cleanPositions = arrayRemoveDuplicates(positions, Cartesian3.equalsEpsilon);
  39667. if ((cleanPositions.length < 2) || (width <= 0)) {
  39668. return;
  39669. }
  39670. var ellipsoid = corridorGeometry._ellipsoid;
  39671. var vertexFormat = corridorGeometry._vertexFormat;
  39672. var params = {
  39673. ellipsoid : ellipsoid,
  39674. positions : cleanPositions,
  39675. width : width,
  39676. cornerType : corridorGeometry._cornerType,
  39677. granularity : corridorGeometry._granularity,
  39678. saveAttributes: true
  39679. };
  39680. var attr;
  39681. if (extrude) {
  39682. var h = Math.max(height, extrudedHeight);
  39683. extrudedHeight = Math.min(height, extrudedHeight);
  39684. height = h;
  39685. params.height = height;
  39686. params.extrudedHeight = extrudedHeight;
  39687. attr = computePositionsExtruded(params, vertexFormat);
  39688. } else {
  39689. var computedPositions = CorridorGeometryLibrary.computePositions(params);
  39690. attr = combine(computedPositions, vertexFormat, ellipsoid);
  39691. attr.attributes.position.values = PolygonPipeline.scaleToGeodeticHeight(attr.attributes.position.values, height, ellipsoid);
  39692. }
  39693. var attributes = attr.attributes;
  39694. var boundingSphere = BoundingSphere.fromVertices(attributes.position.values, undefined, 3);
  39695. if (!vertexFormat.position) {
  39696. attr.attributes.position.values = undefined;
  39697. }
  39698. return new Geometry({
  39699. attributes : attributes,
  39700. indices : attr.indices,
  39701. primitiveType : PrimitiveType.TRIANGLES,
  39702. boundingSphere : boundingSphere
  39703. });
  39704. };
  39705. /**
  39706. * @private
  39707. */
  39708. CorridorGeometry.createShadowVolume = function(corridorGeometry, minHeightFunc, maxHeightFunc) {
  39709. var granularity = corridorGeometry._granularity;
  39710. var ellipsoid = corridorGeometry._ellipsoid;
  39711. var minHeight = minHeightFunc(granularity, ellipsoid);
  39712. var maxHeight = maxHeightFunc(granularity, ellipsoid);
  39713. return new CorridorGeometry({
  39714. positions : corridorGeometry._positions,
  39715. width : corridorGeometry._width,
  39716. cornerType : corridorGeometry._cornerType,
  39717. ellipsoid : ellipsoid,
  39718. granularity : granularity,
  39719. extrudedHeight : minHeight,
  39720. height : maxHeight,
  39721. vertexFormat : VertexFormat.POSITION_ONLY
  39722. });
  39723. };
  39724. defineProperties(CorridorGeometry.prototype, {
  39725. /**
  39726. * @private
  39727. */
  39728. rectangle : {
  39729. get : function() {
  39730. return this._rectangle;
  39731. }
  39732. }
  39733. });
  39734. return CorridorGeometry;
  39735. });
  39736. /*global define*/
  39737. define('Core/CorridorOutlineGeometry',[
  39738. './arrayRemoveDuplicates',
  39739. './BoundingSphere',
  39740. './Cartesian3',
  39741. './ComponentDatatype',
  39742. './CornerType',
  39743. './CorridorGeometryLibrary',
  39744. './defaultValue',
  39745. './defined',
  39746. './DeveloperError',
  39747. './Ellipsoid',
  39748. './Geometry',
  39749. './GeometryAttribute',
  39750. './GeometryAttributes',
  39751. './IndexDatatype',
  39752. './Math',
  39753. './PolygonPipeline',
  39754. './PrimitiveType'
  39755. ], function(
  39756. arrayRemoveDuplicates,
  39757. BoundingSphere,
  39758. Cartesian3,
  39759. ComponentDatatype,
  39760. CornerType,
  39761. CorridorGeometryLibrary,
  39762. defaultValue,
  39763. defined,
  39764. DeveloperError,
  39765. Ellipsoid,
  39766. Geometry,
  39767. GeometryAttribute,
  39768. GeometryAttributes,
  39769. IndexDatatype,
  39770. CesiumMath,
  39771. PolygonPipeline,
  39772. PrimitiveType) {
  39773. 'use strict';
  39774. var cartesian1 = new Cartesian3();
  39775. var cartesian2 = new Cartesian3();
  39776. var cartesian3 = new Cartesian3();
  39777. function combine(computedPositions, cornerType) {
  39778. var wallIndices = [];
  39779. var positions = computedPositions.positions;
  39780. var corners = computedPositions.corners;
  39781. var endPositions = computedPositions.endPositions;
  39782. var attributes = new GeometryAttributes();
  39783. var corner;
  39784. var leftCount = 0;
  39785. var rightCount = 0;
  39786. var i;
  39787. var indicesLength = 0;
  39788. var length;
  39789. for (i = 0; i < positions.length; i += 2) {
  39790. length = positions[i].length - 3;
  39791. leftCount += length; //subtracting 3 to account for duplicate points at corners
  39792. indicesLength += length / 3 * 4;
  39793. rightCount += positions[i + 1].length - 3;
  39794. }
  39795. leftCount += 3; //add back count for end positions
  39796. rightCount += 3;
  39797. for (i = 0; i < corners.length; i++) {
  39798. corner = corners[i];
  39799. var leftSide = corners[i].leftPositions;
  39800. if (defined(leftSide)) {
  39801. length = leftSide.length;
  39802. leftCount += length;
  39803. indicesLength += length / 3 * 2;
  39804. } else {
  39805. length = corners[i].rightPositions.length;
  39806. rightCount += length;
  39807. indicesLength += length / 3 * 2;
  39808. }
  39809. }
  39810. var addEndPositions = defined(endPositions);
  39811. var endPositionLength;
  39812. if (addEndPositions) {
  39813. endPositionLength = endPositions[0].length - 3;
  39814. leftCount += endPositionLength;
  39815. rightCount += endPositionLength;
  39816. endPositionLength /= 3;
  39817. indicesLength += endPositionLength * 4;
  39818. }
  39819. var size = leftCount + rightCount;
  39820. var finalPositions = new Float64Array(size);
  39821. var front = 0;
  39822. var back = size - 1;
  39823. var UL, LL, UR, LR;
  39824. var rightPos, leftPos;
  39825. var halfLength = endPositionLength / 2;
  39826. var indices = IndexDatatype.createTypedArray(size / 3, indicesLength + 4);
  39827. var index = 0;
  39828. indices[index++] = front / 3;
  39829. indices[index++] = (back - 2) / 3;
  39830. if (addEndPositions) { // add rounded end
  39831. wallIndices.push(front / 3);
  39832. leftPos = cartesian1;
  39833. rightPos = cartesian2;
  39834. var firstEndPositions = endPositions[0];
  39835. for (i = 0; i < halfLength; i++) {
  39836. leftPos = Cartesian3.fromArray(firstEndPositions, (halfLength - 1 - i) * 3, leftPos);
  39837. rightPos = Cartesian3.fromArray(firstEndPositions, (halfLength + i) * 3, rightPos);
  39838. CorridorGeometryLibrary.addAttribute(finalPositions, rightPos, front);
  39839. CorridorGeometryLibrary.addAttribute(finalPositions, leftPos, undefined, back);
  39840. LL = front / 3;
  39841. LR = LL + 1;
  39842. UL = (back - 2) / 3;
  39843. UR = UL - 1;
  39844. indices[index++] = UL;
  39845. indices[index++] = UR;
  39846. indices[index++] = LL;
  39847. indices[index++] = LR;
  39848. front += 3;
  39849. back -= 3;
  39850. }
  39851. }
  39852. var posIndex = 0;
  39853. var rightEdge = positions[posIndex++]; //add first two edges
  39854. var leftEdge = positions[posIndex++];
  39855. finalPositions.set(rightEdge, front);
  39856. finalPositions.set(leftEdge, back - leftEdge.length + 1);
  39857. length = leftEdge.length - 3;
  39858. wallIndices.push(front / 3, (back - 2) / 3);
  39859. for (i = 0; i < length; i += 3) {
  39860. LL = front / 3;
  39861. LR = LL + 1;
  39862. UL = (back - 2) / 3;
  39863. UR = UL - 1;
  39864. indices[index++] = UL;
  39865. indices[index++] = UR;
  39866. indices[index++] = LL;
  39867. indices[index++] = LR;
  39868. front += 3;
  39869. back -= 3;
  39870. }
  39871. for (i = 0; i < corners.length; i++) {
  39872. var j;
  39873. corner = corners[i];
  39874. var l = corner.leftPositions;
  39875. var r = corner.rightPositions;
  39876. var start;
  39877. var outsidePoint = cartesian3;
  39878. if (defined(l)) {
  39879. back -= 3;
  39880. start = UR;
  39881. wallIndices.push(LR);
  39882. for (j = 0; j < l.length / 3; j++) {
  39883. outsidePoint = Cartesian3.fromArray(l, j * 3, outsidePoint);
  39884. indices[index++] = start - j - 1;
  39885. indices[index++] = start - j;
  39886. CorridorGeometryLibrary.addAttribute(finalPositions, outsidePoint, undefined, back);
  39887. back -= 3;
  39888. }
  39889. wallIndices.push(start - Math.floor(l.length / 6));
  39890. if (cornerType === CornerType.BEVELED) {
  39891. wallIndices.push((back - 2) / 3 + 1);
  39892. }
  39893. front += 3;
  39894. } else {
  39895. front += 3;
  39896. start = LR;
  39897. wallIndices.push(UR);
  39898. for (j = 0; j < r.length / 3; j++) {
  39899. outsidePoint = Cartesian3.fromArray(r, j * 3, outsidePoint);
  39900. indices[index++] = start + j;
  39901. indices[index++] = start + j + 1;
  39902. CorridorGeometryLibrary.addAttribute(finalPositions, outsidePoint, front);
  39903. front += 3;
  39904. }
  39905. wallIndices.push(start + Math.floor(r.length / 6));
  39906. if (cornerType === CornerType.BEVELED) {
  39907. wallIndices.push(front / 3 - 1);
  39908. }
  39909. back -= 3;
  39910. }
  39911. rightEdge = positions[posIndex++];
  39912. leftEdge = positions[posIndex++];
  39913. rightEdge.splice(0, 3); //remove duplicate points added by corner
  39914. leftEdge.splice(leftEdge.length - 3, 3);
  39915. finalPositions.set(rightEdge, front);
  39916. finalPositions.set(leftEdge, back - leftEdge.length + 1);
  39917. length = leftEdge.length - 3;
  39918. for (j = 0; j < leftEdge.length; j += 3) {
  39919. LR = front / 3;
  39920. LL = LR - 1;
  39921. UR = (back - 2) / 3;
  39922. UL = UR + 1;
  39923. indices[index++] = UL;
  39924. indices[index++] = UR;
  39925. indices[index++] = LL;
  39926. indices[index++] = LR;
  39927. front += 3;
  39928. back -= 3;
  39929. }
  39930. front -= 3;
  39931. back += 3;
  39932. wallIndices.push(front / 3, (back - 2) / 3);
  39933. }
  39934. if (addEndPositions) { // add rounded end
  39935. front += 3;
  39936. back -= 3;
  39937. leftPos = cartesian1;
  39938. rightPos = cartesian2;
  39939. var lastEndPositions = endPositions[1];
  39940. for (i = 0; i < halfLength; i++) {
  39941. leftPos = Cartesian3.fromArray(lastEndPositions, (endPositionLength - i - 1) * 3, leftPos);
  39942. rightPos = Cartesian3.fromArray(lastEndPositions, i * 3, rightPos);
  39943. CorridorGeometryLibrary.addAttribute(finalPositions, leftPos, undefined, back);
  39944. CorridorGeometryLibrary.addAttribute(finalPositions, rightPos, front);
  39945. LR = front / 3;
  39946. LL = LR - 1;
  39947. UR = (back - 2) / 3;
  39948. UL = UR + 1;
  39949. indices[index++] = UL;
  39950. indices[index++] = UR;
  39951. indices[index++] = LL;
  39952. indices[index++] = LR;
  39953. front += 3;
  39954. back -= 3;
  39955. }
  39956. wallIndices.push(front / 3);
  39957. } else {
  39958. wallIndices.push(front / 3, (back - 2) / 3);
  39959. }
  39960. indices[index++] = front / 3;
  39961. indices[index++] = (back - 2) / 3;
  39962. attributes.position = new GeometryAttribute({
  39963. componentDatatype : ComponentDatatype.DOUBLE,
  39964. componentsPerAttribute : 3,
  39965. values : finalPositions
  39966. });
  39967. return {
  39968. attributes : attributes,
  39969. indices : indices,
  39970. wallIndices : wallIndices
  39971. };
  39972. }
  39973. function computePositionsExtruded(params) {
  39974. var ellipsoid = params.ellipsoid;
  39975. var computedPositions = CorridorGeometryLibrary.computePositions(params);
  39976. var attr = combine(computedPositions, params.cornerType);
  39977. var wallIndices = attr.wallIndices;
  39978. var height = params.height;
  39979. var extrudedHeight = params.extrudedHeight;
  39980. var attributes = attr.attributes;
  39981. var indices = attr.indices;
  39982. var positions = attributes.position.values;
  39983. var length = positions.length;
  39984. var extrudedPositions = new Float64Array(length);
  39985. extrudedPositions.set(positions);
  39986. var newPositions = new Float64Array(length * 2);
  39987. positions = PolygonPipeline.scaleToGeodeticHeight(positions, height, ellipsoid);
  39988. extrudedPositions = PolygonPipeline.scaleToGeodeticHeight(extrudedPositions, extrudedHeight, ellipsoid);
  39989. newPositions.set(positions);
  39990. newPositions.set(extrudedPositions, length);
  39991. attributes.position.values = newPositions;
  39992. length /= 3;
  39993. var i;
  39994. var iLength = indices.length;
  39995. var newIndices = IndexDatatype.createTypedArray(newPositions.length / 3, (iLength + wallIndices.length) * 2);
  39996. newIndices.set(indices);
  39997. var index = iLength;
  39998. for (i = 0; i < iLength; i += 2) { // bottom indices
  39999. var v0 = indices[i];
  40000. var v1 = indices[i + 1];
  40001. newIndices[index++] = v0 + length;
  40002. newIndices[index++] = v1 + length;
  40003. }
  40004. var UL, LL;
  40005. for (i = 0; i < wallIndices.length; i++) { //wall indices
  40006. UL = wallIndices[i];
  40007. LL = UL + length;
  40008. newIndices[index++] = UL;
  40009. newIndices[index++] = LL;
  40010. }
  40011. return {
  40012. attributes : attributes,
  40013. indices : newIndices
  40014. };
  40015. }
  40016. /**
  40017. * A description of a corridor outline.
  40018. *
  40019. * @alias CorridorOutlineGeometry
  40020. * @constructor
  40021. *
  40022. * @param {Object} options Object with the following properties:
  40023. * @param {Cartesian3[]} options.positions An array of positions that define the center of the corridor outline.
  40024. * @param {Number} options.width The distance between the edges of the corridor outline.
  40025. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
  40026. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  40027. * @param {Number} [options.height=0] The distance in meters between the positions and the ellipsoid surface.
  40028. * @param {Number} [options.extrudedHeight] The distance in meters between the extruded face and the ellipsoid surface.
  40029. * @param {CornerType} [options.cornerType=CornerType.ROUNDED] Determines the style of the corners.
  40030. *
  40031. * @see CorridorOutlineGeometry.createGeometry
  40032. *
  40033. * @example
  40034. * var corridor = new Cesium.CorridorOutlineGeometry({
  40035. * positions : Cesium.Cartesian3.fromDegreesArray([-72.0, 40.0, -70.0, 35.0]),
  40036. * width : 100000
  40037. * });
  40038. */
  40039. function CorridorOutlineGeometry(options) {
  40040. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  40041. var positions = options.positions;
  40042. var width = options.width;
  40043. if (!defined(positions)) {
  40044. throw new DeveloperError('options.positions is required.');
  40045. }
  40046. if (!defined(width)) {
  40047. throw new DeveloperError('options.width is required.');
  40048. }
  40049. this._positions = positions;
  40050. this._ellipsoid = Ellipsoid.clone(defaultValue(options.ellipsoid, Ellipsoid.WGS84));
  40051. this._width = width;
  40052. this._height = defaultValue(options.height, 0);
  40053. this._extrudedHeight = defaultValue(options.extrudedHeight, this._height);
  40054. this._cornerType = defaultValue(options.cornerType, CornerType.ROUNDED);
  40055. this._granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  40056. this._workerName = 'createCorridorOutlineGeometry';
  40057. /**
  40058. * The number of elements used to pack the object into an array.
  40059. * @type {Number}
  40060. */
  40061. this.packedLength = 1 + positions.length * Cartesian3.packedLength + Ellipsoid.packedLength + 5;
  40062. }
  40063. /**
  40064. * Stores the provided instance into the provided array.
  40065. *
  40066. * @param {CorridorOutlineGeometry} value The value to pack.
  40067. * @param {Number[]} array The array to pack into.
  40068. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  40069. *
  40070. * @returns {Number[]} The array that was packed into
  40071. */
  40072. CorridorOutlineGeometry.pack = function(value, array, startingIndex) {
  40073. if (!defined(value)) {
  40074. throw new DeveloperError('value is required');
  40075. }
  40076. if (!defined(array)) {
  40077. throw new DeveloperError('array is required');
  40078. }
  40079. startingIndex = defaultValue(startingIndex, 0);
  40080. var positions = value._positions;
  40081. var length = positions.length;
  40082. array[startingIndex++] = length;
  40083. for (var i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  40084. Cartesian3.pack(positions[i], array, startingIndex);
  40085. }
  40086. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  40087. startingIndex += Ellipsoid.packedLength;
  40088. array[startingIndex++] = value._width;
  40089. array[startingIndex++] = value._height;
  40090. array[startingIndex++] = value._extrudedHeight;
  40091. array[startingIndex++] = value._cornerType;
  40092. array[startingIndex] = value._granularity;
  40093. return array;
  40094. };
  40095. var scratchEllipsoid = Ellipsoid.clone(Ellipsoid.UNIT_SPHERE);
  40096. var scratchOptions = {
  40097. positions : undefined,
  40098. ellipsoid : scratchEllipsoid,
  40099. width : undefined,
  40100. height : undefined,
  40101. extrudedHeight : undefined,
  40102. cornerType : undefined,
  40103. granularity : undefined
  40104. };
  40105. /**
  40106. * Retrieves an instance from a packed array.
  40107. *
  40108. * @param {Number[]} array The packed array.
  40109. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  40110. * @param {CorridorOutlineGeometry} [result] The object into which to store the result.
  40111. * @returns {CorridorOutlineGeometry} The modified result parameter or a new CorridorOutlineGeometry instance if one was not provided.
  40112. */
  40113. CorridorOutlineGeometry.unpack = function(array, startingIndex, result) {
  40114. if (!defined(array)) {
  40115. throw new DeveloperError('array is required');
  40116. }
  40117. startingIndex = defaultValue(startingIndex, 0);
  40118. var length = array[startingIndex++];
  40119. var positions = new Array(length);
  40120. for (var i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  40121. positions[i] = Cartesian3.unpack(array, startingIndex);
  40122. }
  40123. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  40124. startingIndex += Ellipsoid.packedLength;
  40125. var width = array[startingIndex++];
  40126. var height = array[startingIndex++];
  40127. var extrudedHeight = array[startingIndex++];
  40128. var cornerType = array[startingIndex++];
  40129. var granularity = array[startingIndex];
  40130. if (!defined(result)) {
  40131. scratchOptions.positions = positions;
  40132. scratchOptions.width = width;
  40133. scratchOptions.height = height;
  40134. scratchOptions.extrudedHeight = extrudedHeight;
  40135. scratchOptions.cornerType = cornerType;
  40136. scratchOptions.granularity = granularity;
  40137. return new CorridorOutlineGeometry(scratchOptions);
  40138. }
  40139. result._positions = positions;
  40140. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  40141. result._width = width;
  40142. result._height = height;
  40143. result._extrudedHeight = extrudedHeight;
  40144. result._cornerType = cornerType;
  40145. result._granularity = granularity;
  40146. return result;
  40147. };
  40148. /**
  40149. * Computes the geometric representation of a corridor, including its vertices, indices, and a bounding sphere.
  40150. *
  40151. * @param {CorridorOutlineGeometry} corridorOutlineGeometry A description of the corridor.
  40152. * @returns {Geometry|undefined} The computed vertices and indices.
  40153. */
  40154. CorridorOutlineGeometry.createGeometry = function(corridorOutlineGeometry) {
  40155. var positions = corridorOutlineGeometry._positions;
  40156. var height = corridorOutlineGeometry._height;
  40157. var width = corridorOutlineGeometry._width;
  40158. var extrudedHeight = corridorOutlineGeometry._extrudedHeight;
  40159. var extrude = (height !== extrudedHeight);
  40160. var cleanPositions = arrayRemoveDuplicates(positions, Cartesian3.equalsEpsilon);
  40161. if ((cleanPositions.length < 2) || (width <= 0)) {
  40162. return;
  40163. }
  40164. var ellipsoid = corridorOutlineGeometry._ellipsoid;
  40165. var params = {
  40166. ellipsoid : ellipsoid,
  40167. positions : cleanPositions,
  40168. width : width,
  40169. cornerType : corridorOutlineGeometry._cornerType,
  40170. granularity : corridorOutlineGeometry._granularity,
  40171. saveAttributes : false
  40172. };
  40173. var attr;
  40174. if (extrude) {
  40175. var h = Math.max(height, extrudedHeight);
  40176. extrudedHeight = Math.min(height, extrudedHeight);
  40177. height = h;
  40178. params.height = height;
  40179. params.extrudedHeight = extrudedHeight;
  40180. attr = computePositionsExtruded(params);
  40181. } else {
  40182. var computedPositions = CorridorGeometryLibrary.computePositions(params);
  40183. attr = combine(computedPositions, params.cornerType);
  40184. attr.attributes.position.values = PolygonPipeline.scaleToGeodeticHeight(attr.attributes.position.values, height, ellipsoid);
  40185. }
  40186. var attributes = attr.attributes;
  40187. var boundingSphere = BoundingSphere.fromVertices(attributes.position.values, undefined, 3);
  40188. return new Geometry({
  40189. attributes : attributes,
  40190. indices : attr.indices,
  40191. primitiveType : PrimitiveType.LINES,
  40192. boundingSphere : boundingSphere
  40193. });
  40194. };
  40195. return CorridorOutlineGeometry;
  40196. });
  40197. /*global define*/
  40198. define('Core/createGuid',[],function() {
  40199. 'use strict';
  40200. /**
  40201. * Creates a Globally unique identifier (GUID) string. A GUID is 128 bits long, and can guarantee uniqueness across space and time.
  40202. *
  40203. * @exports createGuid
  40204. *
  40205. * @returns {String}
  40206. *
  40207. *
  40208. * @example
  40209. * this.guid = Cesium.createGuid();
  40210. *
  40211. * @see {@link http://www.ietf.org/rfc/rfc4122.txt|RFC 4122 A Universally Unique IDentifier (UUID) URN Namespace}
  40212. */
  40213. function createGuid() {
  40214. // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
  40215. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
  40216. var r = Math.random() * 16 | 0;
  40217. var v = c === 'x' ? r : (r & 0x3 | 0x8);
  40218. return v.toString(16);
  40219. });
  40220. }
  40221. return createGuid;
  40222. });
  40223. /*global define*/
  40224. define('Core/CylinderGeometryLibrary',[
  40225. './Math'
  40226. ], function(
  40227. CesiumMath) {
  40228. 'use strict';
  40229. /**
  40230. * @private
  40231. */
  40232. var CylinderGeometryLibrary = {};
  40233. /**
  40234. * @private
  40235. */
  40236. CylinderGeometryLibrary.computePositions = function(length, topRadius, bottomRadius, slices, fill){
  40237. var topZ = length * 0.5;
  40238. var bottomZ = -topZ;
  40239. var twoSlice = slices + slices;
  40240. var size = (fill) ? 2 * twoSlice : twoSlice;
  40241. var positions = new Float64Array(size*3);
  40242. var i;
  40243. var index = 0;
  40244. var tbIndex = 0;
  40245. var bottomOffset = (fill) ? twoSlice*3 : 0;
  40246. var topOffset = (fill) ? (twoSlice + slices)*3 : slices*3;
  40247. for (i = 0; i < slices; i++) {
  40248. var angle = i / slices * CesiumMath.TWO_PI;
  40249. var x = Math.cos(angle);
  40250. var y = Math.sin(angle);
  40251. var bottomX = x * bottomRadius;
  40252. var bottomY = y * bottomRadius;
  40253. var topX = x * topRadius;
  40254. var topY = y * topRadius;
  40255. positions[tbIndex + bottomOffset] = bottomX;
  40256. positions[tbIndex + bottomOffset + 1] = bottomY;
  40257. positions[tbIndex + bottomOffset + 2] = bottomZ;
  40258. positions[tbIndex + topOffset] = topX;
  40259. positions[tbIndex + topOffset + 1] = topY;
  40260. positions[tbIndex + topOffset + 2] = topZ;
  40261. tbIndex += 3;
  40262. if (fill) {
  40263. positions[index++] = bottomX;
  40264. positions[index++] = bottomY;
  40265. positions[index++] = bottomZ;
  40266. positions[index++] = topX;
  40267. positions[index++] = topY;
  40268. positions[index++] = topZ;
  40269. }
  40270. }
  40271. return positions;
  40272. };
  40273. return CylinderGeometryLibrary;
  40274. });
  40275. /*global define*/
  40276. define('Core/CylinderGeometry',[
  40277. './BoundingSphere',
  40278. './Cartesian2',
  40279. './Cartesian3',
  40280. './ComponentDatatype',
  40281. './CylinderGeometryLibrary',
  40282. './defaultValue',
  40283. './defined',
  40284. './DeveloperError',
  40285. './Geometry',
  40286. './GeometryAttribute',
  40287. './GeometryAttributes',
  40288. './IndexDatatype',
  40289. './Math',
  40290. './PrimitiveType',
  40291. './VertexFormat'
  40292. ], function(
  40293. BoundingSphere,
  40294. Cartesian2,
  40295. Cartesian3,
  40296. ComponentDatatype,
  40297. CylinderGeometryLibrary,
  40298. defaultValue,
  40299. defined,
  40300. DeveloperError,
  40301. Geometry,
  40302. GeometryAttribute,
  40303. GeometryAttributes,
  40304. IndexDatatype,
  40305. CesiumMath,
  40306. PrimitiveType,
  40307. VertexFormat) {
  40308. 'use strict';
  40309. var radiusScratch = new Cartesian2();
  40310. var normalScratch = new Cartesian3();
  40311. var binormalScratch = new Cartesian3();
  40312. var tangentScratch = new Cartesian3();
  40313. var positionScratch = new Cartesian3();
  40314. /**
  40315. * A description of a cylinder.
  40316. *
  40317. * @alias CylinderGeometry
  40318. * @constructor
  40319. *
  40320. * @param {Object} options Object with the following properties:
  40321. * @param {Number} options.length The length of the cylinder.
  40322. * @param {Number} options.topRadius The radius of the top of the cylinder.
  40323. * @param {Number} options.bottomRadius The radius of the bottom of the cylinder.
  40324. * @param {Number} [options.slices=128] The number of edges around the perimeter of the cylinder.
  40325. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  40326. *
  40327. * @exception {DeveloperError} options.length must be greater than 0.
  40328. * @exception {DeveloperError} options.topRadius must be greater than 0.
  40329. * @exception {DeveloperError} options.bottomRadius must be greater than 0.
  40330. * @exception {DeveloperError} bottomRadius and topRadius cannot both equal 0.
  40331. * @exception {DeveloperError} options.slices must be greater than or equal to 3.
  40332. *
  40333. * @see CylinderGeometry.createGeometry
  40334. *
  40335. * @example
  40336. * // create cylinder geometry
  40337. * var cylinder = new Cesium.CylinderGeometry({
  40338. * length: 200000,
  40339. * topRadius: 80000,
  40340. * bottomRadius: 200000,
  40341. * });
  40342. * var geometry = Cesium.CylinderGeometry.createGeometry(cylinder);
  40343. */
  40344. function CylinderGeometry(options) {
  40345. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  40346. var length = options.length;
  40347. var topRadius = options.topRadius;
  40348. var bottomRadius = options.bottomRadius;
  40349. var vertexFormat = defaultValue(options.vertexFormat, VertexFormat.DEFAULT);
  40350. var slices = defaultValue(options.slices, 128);
  40351. if (!defined(length)) {
  40352. throw new DeveloperError('options.length must be defined.');
  40353. }
  40354. if (!defined(topRadius)) {
  40355. throw new DeveloperError('options.topRadius must be defined.');
  40356. }
  40357. if (!defined(bottomRadius)) {
  40358. throw new DeveloperError('options.bottomRadius must be defined.');
  40359. }
  40360. if (slices < 3) {
  40361. throw new DeveloperError('options.slices must be greater than or equal to 3.');
  40362. }
  40363. this._length = length;
  40364. this._topRadius = topRadius;
  40365. this._bottomRadius = bottomRadius;
  40366. this._vertexFormat = VertexFormat.clone(vertexFormat);
  40367. this._slices = slices;
  40368. this._workerName = 'createCylinderGeometry';
  40369. }
  40370. /**
  40371. * The number of elements used to pack the object into an array.
  40372. * @type {Number}
  40373. */
  40374. CylinderGeometry.packedLength = VertexFormat.packedLength + 4;
  40375. /**
  40376. * Stores the provided instance into the provided array.
  40377. *
  40378. * @param {CylinderGeometry} value The value to pack.
  40379. * @param {Number[]} array The array to pack into.
  40380. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  40381. *
  40382. * @returns {Number[]} The array that was packed into
  40383. */
  40384. CylinderGeometry.pack = function(value, array, startingIndex) {
  40385. if (!defined(value)) {
  40386. throw new DeveloperError('value is required');
  40387. }
  40388. if (!defined(array)) {
  40389. throw new DeveloperError('array is required');
  40390. }
  40391. startingIndex = defaultValue(startingIndex, 0);
  40392. VertexFormat.pack(value._vertexFormat, array, startingIndex);
  40393. startingIndex += VertexFormat.packedLength;
  40394. array[startingIndex++] = value._length;
  40395. array[startingIndex++] = value._topRadius;
  40396. array[startingIndex++] = value._bottomRadius;
  40397. array[startingIndex] = value._slices;
  40398. return array;
  40399. };
  40400. var scratchVertexFormat = new VertexFormat();
  40401. var scratchOptions = {
  40402. vertexFormat : scratchVertexFormat,
  40403. length : undefined,
  40404. topRadius : undefined,
  40405. bottomRadius : undefined,
  40406. slices : undefined
  40407. };
  40408. /**
  40409. * Retrieves an instance from a packed array.
  40410. *
  40411. * @param {Number[]} array The packed array.
  40412. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  40413. * @param {CylinderGeometry} [result] The object into which to store the result.
  40414. * @returns {CylinderGeometry} The modified result parameter or a new CylinderGeometry instance if one was not provided.
  40415. */
  40416. CylinderGeometry.unpack = function(array, startingIndex, result) {
  40417. if (!defined(array)) {
  40418. throw new DeveloperError('array is required');
  40419. }
  40420. startingIndex = defaultValue(startingIndex, 0);
  40421. var vertexFormat = VertexFormat.unpack(array, startingIndex, scratchVertexFormat);
  40422. startingIndex += VertexFormat.packedLength;
  40423. var length = array[startingIndex++];
  40424. var topRadius = array[startingIndex++];
  40425. var bottomRadius = array[startingIndex++];
  40426. var slices = array[startingIndex];
  40427. if (!defined(result)) {
  40428. scratchOptions.length = length;
  40429. scratchOptions.topRadius = topRadius;
  40430. scratchOptions.bottomRadius = bottomRadius;
  40431. scratchOptions.slices = slices;
  40432. return new CylinderGeometry(scratchOptions);
  40433. }
  40434. result._vertexFormat = VertexFormat.clone(vertexFormat, result._vertexFormat);
  40435. result._length = length;
  40436. result._topRadius = topRadius;
  40437. result._bottomRadius = bottomRadius;
  40438. result._slices = slices;
  40439. return result;
  40440. };
  40441. /**
  40442. * Computes the geometric representation of a cylinder, including its vertices, indices, and a bounding sphere.
  40443. *
  40444. * @param {CylinderGeometry} cylinderGeometry A description of the cylinder.
  40445. * @returns {Geometry|undefined} The computed vertices and indices.
  40446. */
  40447. CylinderGeometry.createGeometry = function(cylinderGeometry) {
  40448. var length = cylinderGeometry._length;
  40449. var topRadius = cylinderGeometry._topRadius;
  40450. var bottomRadius = cylinderGeometry._bottomRadius;
  40451. var vertexFormat = cylinderGeometry._vertexFormat;
  40452. var slices = cylinderGeometry._slices;
  40453. if ((length <= 0) || (topRadius < 0) || (bottomRadius < 0) || ((topRadius === 0) && (bottomRadius === 0))) {
  40454. return;
  40455. }
  40456. var twoSlices = slices + slices;
  40457. var threeSlices = slices + twoSlices;
  40458. var numVertices = twoSlices + twoSlices;
  40459. var positions = CylinderGeometryLibrary.computePositions(length, topRadius, bottomRadius, slices, true);
  40460. var st = (vertexFormat.st) ? new Float32Array(numVertices * 2) : undefined;
  40461. var normals = (vertexFormat.normal) ? new Float32Array(numVertices * 3) : undefined;
  40462. var tangents = (vertexFormat.tangent) ? new Float32Array(numVertices * 3) : undefined;
  40463. var binormals = (vertexFormat.binormal) ? new Float32Array(numVertices * 3) : undefined;
  40464. var i;
  40465. var computeNormal = (vertexFormat.normal || vertexFormat.tangent || vertexFormat.binormal);
  40466. if (computeNormal) {
  40467. var computeTangent = (vertexFormat.tangent || vertexFormat.binormal);
  40468. var normalIndex = 0;
  40469. var tangentIndex = 0;
  40470. var binormalIndex = 0;
  40471. var normal = normalScratch;
  40472. normal.z = 0;
  40473. var tangent = tangentScratch;
  40474. var binormal = binormalScratch;
  40475. for (i = 0; i < slices; i++) {
  40476. var angle = i / slices * CesiumMath.TWO_PI;
  40477. var x = Math.cos(angle);
  40478. var y = Math.sin(angle);
  40479. if (computeNormal) {
  40480. normal.x = x;
  40481. normal.y = y;
  40482. if (computeTangent) {
  40483. tangent = Cartesian3.normalize(Cartesian3.cross(Cartesian3.UNIT_Z, normal, tangent), tangent);
  40484. }
  40485. if (vertexFormat.normal) {
  40486. normals[normalIndex++] = x;
  40487. normals[normalIndex++] = y;
  40488. normals[normalIndex++] = 0;
  40489. normals[normalIndex++] = x;
  40490. normals[normalIndex++] = y;
  40491. normals[normalIndex++] = 0;
  40492. }
  40493. if (vertexFormat.tangent) {
  40494. tangents[tangentIndex++] = tangent.x;
  40495. tangents[tangentIndex++] = tangent.y;
  40496. tangents[tangentIndex++] = tangent.z;
  40497. tangents[tangentIndex++] = tangent.x;
  40498. tangents[tangentIndex++] = tangent.y;
  40499. tangents[tangentIndex++] = tangent.z;
  40500. }
  40501. if (vertexFormat.binormal) {
  40502. binormal = Cartesian3.normalize(Cartesian3.cross(normal, tangent, binormal), binormal);
  40503. binormals[binormalIndex++] = binormal.x;
  40504. binormals[binormalIndex++] = binormal.y;
  40505. binormals[binormalIndex++] = binormal.z;
  40506. binormals[binormalIndex++] = binormal.x;
  40507. binormals[binormalIndex++] = binormal.y;
  40508. binormals[binormalIndex++] = binormal.z;
  40509. }
  40510. }
  40511. }
  40512. for (i = 0; i < slices; i++) {
  40513. if (vertexFormat.normal) {
  40514. normals[normalIndex++] = 0;
  40515. normals[normalIndex++] = 0;
  40516. normals[normalIndex++] = -1;
  40517. }
  40518. if (vertexFormat.tangent) {
  40519. tangents[tangentIndex++] = 1;
  40520. tangents[tangentIndex++] = 0;
  40521. tangents[tangentIndex++] = 0;
  40522. }
  40523. if (vertexFormat.binormal) {
  40524. binormals[binormalIndex++] = 0;
  40525. binormals[binormalIndex++] = -1;
  40526. binormals[binormalIndex++] = 0;
  40527. }
  40528. }
  40529. for (i = 0; i < slices; i++) {
  40530. if (vertexFormat.normal) {
  40531. normals[normalIndex++] = 0;
  40532. normals[normalIndex++] = 0;
  40533. normals[normalIndex++] = 1;
  40534. }
  40535. if (vertexFormat.tangent) {
  40536. tangents[tangentIndex++] = 1;
  40537. tangents[tangentIndex++] = 0;
  40538. tangents[tangentIndex++] = 0;
  40539. }
  40540. if (vertexFormat.binormal) {
  40541. binormals[binormalIndex++] = 0;
  40542. binormals[binormalIndex++] = 1;
  40543. binormals[binormalIndex++] = 0;
  40544. }
  40545. }
  40546. }
  40547. var numIndices = 12 * slices - 12;
  40548. var indices = IndexDatatype.createTypedArray(numVertices, numIndices);
  40549. var index = 0;
  40550. var j = 0;
  40551. for (i = 0; i < slices - 1; i++) {
  40552. indices[index++] = j;
  40553. indices[index++] = j + 2;
  40554. indices[index++] = j + 3;
  40555. indices[index++] = j;
  40556. indices[index++] = j + 3;
  40557. indices[index++] = j + 1;
  40558. j += 2;
  40559. }
  40560. indices[index++] = twoSlices - 2;
  40561. indices[index++] = 0;
  40562. indices[index++] = 1;
  40563. indices[index++] = twoSlices - 2;
  40564. indices[index++] = 1;
  40565. indices[index++] = twoSlices - 1;
  40566. for (i = 1; i < slices - 1; i++) {
  40567. indices[index++] = twoSlices + i + 1;
  40568. indices[index++] = twoSlices + i;
  40569. indices[index++] = twoSlices;
  40570. }
  40571. for (i = 1; i < slices - 1; i++) {
  40572. indices[index++] = threeSlices;
  40573. indices[index++] = threeSlices + i;
  40574. indices[index++] = threeSlices + i + 1;
  40575. }
  40576. var textureCoordIndex = 0;
  40577. if (vertexFormat.st) {
  40578. var rad = Math.max(topRadius, bottomRadius);
  40579. for (i = 0; i < numVertices; i++) {
  40580. var position = Cartesian3.fromArray(positions, i * 3, positionScratch);
  40581. st[textureCoordIndex++] = (position.x + rad) / (2.0 * rad);
  40582. st[textureCoordIndex++] = (position.y + rad) / (2.0 * rad);
  40583. }
  40584. }
  40585. var attributes = new GeometryAttributes();
  40586. if (vertexFormat.position) {
  40587. attributes.position = new GeometryAttribute({
  40588. componentDatatype: ComponentDatatype.DOUBLE,
  40589. componentsPerAttribute: 3,
  40590. values: positions
  40591. });
  40592. }
  40593. if (vertexFormat.normal) {
  40594. attributes.normal = new GeometryAttribute({
  40595. componentDatatype : ComponentDatatype.FLOAT,
  40596. componentsPerAttribute : 3,
  40597. values : normals
  40598. });
  40599. }
  40600. if (vertexFormat.tangent) {
  40601. attributes.tangent = new GeometryAttribute({
  40602. componentDatatype : ComponentDatatype.FLOAT,
  40603. componentsPerAttribute : 3,
  40604. values : tangents
  40605. });
  40606. }
  40607. if (vertexFormat.binormal) {
  40608. attributes.binormal = new GeometryAttribute({
  40609. componentDatatype : ComponentDatatype.FLOAT,
  40610. componentsPerAttribute : 3,
  40611. values : binormals
  40612. });
  40613. }
  40614. if (vertexFormat.st) {
  40615. attributes.st = new GeometryAttribute({
  40616. componentDatatype : ComponentDatatype.FLOAT,
  40617. componentsPerAttribute : 2,
  40618. values : st
  40619. });
  40620. }
  40621. radiusScratch.x = length * 0.5;
  40622. radiusScratch.y = Math.max(bottomRadius, topRadius);
  40623. var boundingSphere = new BoundingSphere(Cartesian3.ZERO, Cartesian2.magnitude(radiusScratch));
  40624. return new Geometry({
  40625. attributes : attributes,
  40626. indices : indices,
  40627. primitiveType : PrimitiveType.TRIANGLES,
  40628. boundingSphere : boundingSphere
  40629. });
  40630. };
  40631. return CylinderGeometry;
  40632. });
  40633. /*global define*/
  40634. define('Core/CylinderOutlineGeometry',[
  40635. './BoundingSphere',
  40636. './Cartesian2',
  40637. './Cartesian3',
  40638. './ComponentDatatype',
  40639. './CylinderGeometryLibrary',
  40640. './defaultValue',
  40641. './defined',
  40642. './DeveloperError',
  40643. './Geometry',
  40644. './GeometryAttribute',
  40645. './GeometryAttributes',
  40646. './IndexDatatype',
  40647. './PrimitiveType'
  40648. ], function(
  40649. BoundingSphere,
  40650. Cartesian2,
  40651. Cartesian3,
  40652. ComponentDatatype,
  40653. CylinderGeometryLibrary,
  40654. defaultValue,
  40655. defined,
  40656. DeveloperError,
  40657. Geometry,
  40658. GeometryAttribute,
  40659. GeometryAttributes,
  40660. IndexDatatype,
  40661. PrimitiveType) {
  40662. 'use strict';
  40663. var radiusScratch = new Cartesian2();
  40664. /**
  40665. * A description of the outline of a cylinder.
  40666. *
  40667. * @alias CylinderOutlineGeometry
  40668. * @constructor
  40669. *
  40670. * @param {Object} options Object with the following properties:
  40671. * @param {Number} options.length The length of the cylinder.
  40672. * @param {Number} options.topRadius The radius of the top of the cylinder.
  40673. * @param {Number} options.bottomRadius The radius of the bottom of the cylinder.
  40674. * @param {Number} [options.slices=128] The number of edges around the perimeter of the cylinder.
  40675. * @param {Number} [options.numberOfVerticalLines=16] Number of lines to draw between the top and bottom surfaces of the cylinder.
  40676. *
  40677. * @exception {DeveloperError} options.length must be greater than 0.
  40678. * @exception {DeveloperError} options.topRadius must be greater than 0.
  40679. * @exception {DeveloperError} options.bottomRadius must be greater than 0.
  40680. * @exception {DeveloperError} bottomRadius and topRadius cannot both equal 0.
  40681. * @exception {DeveloperError} options.slices must be greater than or equal to 3.
  40682. *
  40683. * @see CylinderOutlineGeometry.createGeometry
  40684. *
  40685. * @example
  40686. * // create cylinder geometry
  40687. * var cylinder = new Cesium.CylinderOutlineGeometry({
  40688. * length: 200000,
  40689. * topRadius: 80000,
  40690. * bottomRadius: 200000,
  40691. * });
  40692. * var geometry = Cesium.CylinderOutlineGeometry.createGeometry(cylinder);
  40693. */
  40694. function CylinderOutlineGeometry(options) {
  40695. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  40696. var length = options.length;
  40697. var topRadius = options.topRadius;
  40698. var bottomRadius = options.bottomRadius;
  40699. var slices = defaultValue(options.slices, 128);
  40700. var numberOfVerticalLines = Math.max(defaultValue(options.numberOfVerticalLines, 16), 0);
  40701. if (!defined(length)) {
  40702. throw new DeveloperError('options.length must be defined.');
  40703. }
  40704. if (!defined(topRadius)) {
  40705. throw new DeveloperError('options.topRadius must be defined.');
  40706. }
  40707. if (!defined(bottomRadius)) {
  40708. throw new DeveloperError('options.bottomRadius must be defined.');
  40709. }
  40710. if (slices < 3) {
  40711. throw new DeveloperError('options.slices must be greater than or equal to 3.');
  40712. }
  40713. this._length = length;
  40714. this._topRadius = topRadius;
  40715. this._bottomRadius = bottomRadius;
  40716. this._slices = slices;
  40717. this._numberOfVerticalLines = numberOfVerticalLines;
  40718. this._workerName = 'createCylinderOutlineGeometry';
  40719. }
  40720. /**
  40721. * The number of elements used to pack the object into an array.
  40722. * @type {Number}
  40723. */
  40724. CylinderOutlineGeometry.packedLength = 5;
  40725. /**
  40726. * Stores the provided instance into the provided array.
  40727. *
  40728. * @param {CylinderOutlineGeometry} value The value to pack.
  40729. * @param {Number[]} array The array to pack into.
  40730. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  40731. *
  40732. * @returns {Number[]} The array that was packed into
  40733. */
  40734. CylinderOutlineGeometry.pack = function(value, array, startingIndex) {
  40735. if (!defined(value)) {
  40736. throw new DeveloperError('value is required');
  40737. }
  40738. if (!defined(array)) {
  40739. throw new DeveloperError('array is required');
  40740. }
  40741. startingIndex = defaultValue(startingIndex, 0);
  40742. array[startingIndex++] = value._length;
  40743. array[startingIndex++] = value._topRadius;
  40744. array[startingIndex++] = value._bottomRadius;
  40745. array[startingIndex++] = value._slices;
  40746. array[startingIndex] = value._numberOfVerticalLines;
  40747. return array;
  40748. };
  40749. var scratchOptions = {
  40750. length : undefined,
  40751. topRadius : undefined,
  40752. bottomRadius : undefined,
  40753. slices : undefined,
  40754. numberOfVerticalLines : undefined
  40755. };
  40756. /**
  40757. * Retrieves an instance from a packed array.
  40758. *
  40759. * @param {Number[]} array The packed array.
  40760. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  40761. * @param {CylinderOutlineGeometry} [result] The object into which to store the result.
  40762. * @returns {CylinderOutlineGeometry} The modified result parameter or a new CylinderOutlineGeometry instance if one was not provided.
  40763. */
  40764. CylinderOutlineGeometry.unpack = function(array, startingIndex, result) {
  40765. if (!defined(array)) {
  40766. throw new DeveloperError('array is required');
  40767. }
  40768. startingIndex = defaultValue(startingIndex, 0);
  40769. var length = array[startingIndex++];
  40770. var topRadius = array[startingIndex++];
  40771. var bottomRadius = array[startingIndex++];
  40772. var slices = array[startingIndex++];
  40773. var numberOfVerticalLines = array[startingIndex];
  40774. if (!defined(result)) {
  40775. scratchOptions.length = length;
  40776. scratchOptions.topRadius = topRadius;
  40777. scratchOptions.bottomRadius = bottomRadius;
  40778. scratchOptions.slices = slices;
  40779. scratchOptions.numberOfVerticalLines = numberOfVerticalLines;
  40780. return new CylinderOutlineGeometry(scratchOptions);
  40781. }
  40782. result._length = length;
  40783. result._topRadius = topRadius;
  40784. result._bottomRadius = bottomRadius;
  40785. result._slices = slices;
  40786. result._numberOfVerticalLines = numberOfVerticalLines;
  40787. return result;
  40788. };
  40789. /**
  40790. * Computes the geometric representation of an outline of a cylinder, including its vertices, indices, and a bounding sphere.
  40791. *
  40792. * @param {CylinderOutlineGeometry} cylinderGeometry A description of the cylinder outline.
  40793. * @returns {Geometry|undefined} The computed vertices and indices.
  40794. */
  40795. CylinderOutlineGeometry.createGeometry = function(cylinderGeometry) {
  40796. var length = cylinderGeometry._length;
  40797. var topRadius = cylinderGeometry._topRadius;
  40798. var bottomRadius = cylinderGeometry._bottomRadius;
  40799. var slices = cylinderGeometry._slices;
  40800. var numberOfVerticalLines = cylinderGeometry._numberOfVerticalLines;
  40801. if ((length <= 0) || (topRadius < 0) || (bottomRadius < 0) || ((topRadius === 0) && (bottomRadius === 0))) {
  40802. return;
  40803. }
  40804. var numVertices = slices * 2;
  40805. var positions = CylinderGeometryLibrary.computePositions(length, topRadius, bottomRadius, slices, false);
  40806. var numIndices = slices * 2;
  40807. var numSide;
  40808. if (numberOfVerticalLines > 0) {
  40809. var numSideLines = Math.min(numberOfVerticalLines, slices);
  40810. numSide = Math.round(slices / numSideLines);
  40811. numIndices += numSideLines;
  40812. }
  40813. var indices = IndexDatatype.createTypedArray(numVertices, numIndices * 2);
  40814. var index = 0;
  40815. for (var i = 0; i < slices - 1; i++) {
  40816. indices[index++] = i;
  40817. indices[index++] = i + 1;
  40818. indices[index++] = i + slices;
  40819. indices[index++] = i + 1 + slices;
  40820. }
  40821. indices[index++] = slices - 1;
  40822. indices[index++] = 0;
  40823. indices[index++] = slices + slices - 1;
  40824. indices[index++] = slices;
  40825. if (numberOfVerticalLines > 0) {
  40826. for (i = 0; i < slices; i += numSide) {
  40827. indices[index++] = i;
  40828. indices[index++] = i + slices;
  40829. }
  40830. }
  40831. var attributes = new GeometryAttributes();
  40832. attributes.position = new GeometryAttribute({
  40833. componentDatatype : ComponentDatatype.DOUBLE,
  40834. componentsPerAttribute : 3,
  40835. values : positions
  40836. });
  40837. radiusScratch.x = length * 0.5;
  40838. radiusScratch.y = Math.max(bottomRadius, topRadius);
  40839. var boundingSphere = new BoundingSphere(Cartesian3.ZERO, Cartesian2.magnitude(radiusScratch));
  40840. return new Geometry({
  40841. attributes : attributes,
  40842. indices : indices,
  40843. primitiveType : PrimitiveType.LINES,
  40844. boundingSphere : boundingSphere
  40845. });
  40846. };
  40847. return CylinderOutlineGeometry;
  40848. });
  40849. /*global define*/
  40850. define('Core/DefaultProxy',[],function() {
  40851. 'use strict';
  40852. /**
  40853. * A simple proxy that appends the desired resource as the sole query parameter
  40854. * to the given proxy URL.
  40855. *
  40856. * @alias DefaultProxy
  40857. * @constructor
  40858. *
  40859. * @param {String} proxy The proxy URL that will be used to requests all resources.
  40860. */
  40861. function DefaultProxy(proxy) {
  40862. this.proxy = proxy;
  40863. }
  40864. /**
  40865. * Get the final URL to use to request a given resource.
  40866. *
  40867. * @param {String} resource The resource to request.
  40868. * @returns {String} proxied resource
  40869. */
  40870. DefaultProxy.prototype.getURL = function(resource) {
  40871. var prefix = this.proxy.indexOf('?') === -1 ? '?' : '';
  40872. return this.proxy + prefix + encodeURIComponent(resource);
  40873. };
  40874. return DefaultProxy;
  40875. });
  40876. /*global define*/
  40877. define('Core/DistanceDisplayCondition',[
  40878. './defaultValue',
  40879. './defined',
  40880. './defineProperties'
  40881. ], function(
  40882. defaultValue,
  40883. defined,
  40884. defineProperties) {
  40885. 'use strict';
  40886. /**
  40887. * Determines visibility based on the distance to the camera.
  40888. *
  40889. * @alias DistanceDisplayCondition
  40890. * @constructor
  40891. *
  40892. * @param {Number} [near=0.0] The smallest distance in the interval where the object is visible.
  40893. * @param {Number} [far=Number.MAX_VALUE] The largest distance in the interval where the object is visible.
  40894. *
  40895. * @example
  40896. * // Make a billboard that is only visible when the distance to the camera is between 10 and 20 meters.
  40897. * billboard.distanceDisplayCondition = new DistanceDisplayCondition(10.0 20.0);
  40898. */
  40899. function DistanceDisplayCondition(near, far) {
  40900. near = defaultValue(near, 0.0);
  40901. this._near = near;
  40902. far = defaultValue(far, Number.MAX_VALUE);
  40903. this._far = far;
  40904. }
  40905. defineProperties(DistanceDisplayCondition.prototype, {
  40906. /**
  40907. * The smallest distance in the interval where the object is visible.
  40908. * @memberof DistanceDisplayCondition.prototype
  40909. * @type {Number}
  40910. * @default 0.0
  40911. */
  40912. near : {
  40913. get : function() {
  40914. return this._near;
  40915. },
  40916. set : function(value) {
  40917. this._near = value;
  40918. }
  40919. },
  40920. /**
  40921. * The largest distance in the interval where the object is visible.
  40922. * @memberof DistanceDisplayCondition.prototype
  40923. * @type {Number}
  40924. * @default Number.MAX_VALUE
  40925. */
  40926. far : {
  40927. get : function() {
  40928. return this._far;
  40929. },
  40930. set : function(value) {
  40931. this._far = value;
  40932. }
  40933. }
  40934. });
  40935. /**
  40936. * Determines if two distance display conditions are equal.
  40937. *
  40938. * @param {DistanceDisplayCondition} left A distance display condition.
  40939. * @param {DistanceDisplayCondition} right Another distance display condition.
  40940. * @return {Boolean} Whether the two distance display conditions are equal.
  40941. */
  40942. DistanceDisplayCondition.equals = function(left, right) {
  40943. return left === right ||
  40944. (defined(left) &&
  40945. defined(right) &&
  40946. left.near === right.near &&
  40947. left.far === right.far);
  40948. };
  40949. /**
  40950. * Duplicates a distance display condition instance.
  40951. *
  40952. * @param {DistanceDisplayCondition} [value] The distance display condition to duplicate.
  40953. * @param {DistanceDisplayCondition} [result] The result onto which to store the result.
  40954. * @return {DistanceDisplayCondition} The duplicated instance.
  40955. */
  40956. DistanceDisplayCondition.clone = function(value, result) {
  40957. if (!defined(value)) {
  40958. return undefined;
  40959. }
  40960. if (!defined(result)) {
  40961. result = new DistanceDisplayCondition();
  40962. }
  40963. result.near = value.near;
  40964. result.far = value.far;
  40965. return result;
  40966. };
  40967. /**
  40968. * Duplicates this instance.
  40969. *
  40970. * @param {DistanceDisplayCondition} [result] The result onto which to store the result.
  40971. * @return {DistanceDisplayCondition} The duplicated instance.
  40972. */
  40973. DistanceDisplayCondition.prototype.clone = function(result) {
  40974. return DistanceDisplayCondition.clone(this, result);
  40975. };
  40976. /**
  40977. * Determines if this distance display condition is equal to another.
  40978. *
  40979. * @param {DistanceDisplayCondition} other Another distance display condition.
  40980. * @return {Boolean} Whether this distance display condition is equal to the other.
  40981. */
  40982. DistanceDisplayCondition.prototype.equals = function(other) {
  40983. return DistanceDisplayCondition.equals(this, other);
  40984. };
  40985. return DistanceDisplayCondition;
  40986. });
  40987. /*global define*/
  40988. define('Core/DistanceDisplayConditionGeometryInstanceAttribute',[
  40989. './ComponentDatatype',
  40990. './defaultValue',
  40991. './defined',
  40992. './defineProperties',
  40993. './DeveloperError'
  40994. ], function(
  40995. ComponentDatatype,
  40996. defaultValue,
  40997. defined,
  40998. defineProperties,
  40999. DeveloperError) {
  41000. 'use strict';
  41001. /**
  41002. * Value and type information for per-instance geometry attribute that determines if the geometry instance has a distance display condition.
  41003. *
  41004. * @alias DistanceDisplayConditionGeometryInstanceAttribute
  41005. * @constructor
  41006. *
  41007. * @param {Number} [near=0.0] The near distance.
  41008. * @param {Number} [far=Number.MAX_VALUE] The far distance.
  41009. *
  41010. * @exception {DeveloperError} far must be greater than near.
  41011. *
  41012. * @example
  41013. * var instance = new Cesium.GeometryInstance({
  41014. * geometry : new Cesium.BoxGeometry({
  41015. * vertexFormat : Cesium.VertexFormat.POSITION_AND_NORMAL,
  41016. * minimum : new Cesium.Cartesian3(-250000.0, -250000.0, -250000.0),
  41017. * maximum : new Cesium.Cartesian3(250000.0, 250000.0, 250000.0)
  41018. * }),
  41019. * modelMatrix : Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(
  41020. * Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883)), new Cesium.Cartesian3(0.0, 0.0, 1000000.0), new Cesium.Matrix4()),
  41021. * id : 'box',
  41022. * attributes : {
  41023. * show : new Cesium.DistanceDisplayConditionGeometryInstanceAttribute(100.0, 10000.0)
  41024. * }
  41025. * });
  41026. *
  41027. * @see GeometryInstance
  41028. * @see GeometryInstanceAttribute
  41029. */
  41030. function DistanceDisplayConditionGeometryInstanceAttribute(near, far) {
  41031. near = defaultValue(near, 0.0);
  41032. far = defaultValue(far, Number.MAX_VALUE);
  41033. if (far <= near) {
  41034. throw new DeveloperError('far distance must be greater than near distance.');
  41035. }
  41036. /**
  41037. * The values for the attributes stored in a typed array.
  41038. *
  41039. * @type Float32Array
  41040. *
  41041. * @default [0.0, 0.0, Number.MAX_VALUE]
  41042. */
  41043. this.value = new Float32Array([near, far]);
  41044. }
  41045. defineProperties(DistanceDisplayConditionGeometryInstanceAttribute.prototype, {
  41046. /**
  41047. * The datatype of each component in the attribute, e.g., individual elements in
  41048. * {@link DistanceDisplayConditionGeometryInstanceAttribute#value}.
  41049. *
  41050. * @memberof DistanceDisplayConditionGeometryInstanceAttribute.prototype
  41051. *
  41052. * @type {ComponentDatatype}
  41053. * @readonly
  41054. *
  41055. * @default {@link ComponentDatatype.FLOAT}
  41056. */
  41057. componentDatatype : {
  41058. get : function() {
  41059. return ComponentDatatype.FLOAT;
  41060. }
  41061. },
  41062. /**
  41063. * The number of components in the attributes, i.e., {@link DistanceDisplayConditionGeometryInstanceAttribute#value}.
  41064. *
  41065. * @memberof DistanceDisplayConditionGeometryInstanceAttribute.prototype
  41066. *
  41067. * @type {Number}
  41068. * @readonly
  41069. *
  41070. * @default 3
  41071. */
  41072. componentsPerAttribute : {
  41073. get : function() {
  41074. return 2;
  41075. }
  41076. },
  41077. /**
  41078. * When <code>true</code> and <code>componentDatatype</code> is an integer format,
  41079. * indicate that the components should be mapped to the range [0, 1] (unsigned)
  41080. * or [-1, 1] (signed) when they are accessed as floating-point for rendering.
  41081. *
  41082. * @memberof DistanceDisplayConditionGeometryInstanceAttribute.prototype
  41083. *
  41084. * @type {Boolean}
  41085. * @readonly
  41086. *
  41087. * @default false
  41088. */
  41089. normalize : {
  41090. get : function() {
  41091. return false;
  41092. }
  41093. }
  41094. });
  41095. /**
  41096. * Creates a new {@link DistanceDisplayConditionGeometryInstanceAttribute} instance given the provided an enabled flag and {@link DistanceDisplayCondition}.
  41097. *
  41098. * @param {DistanceDisplayCondition} distanceDisplayCondition The distance display condition.
  41099. * @returns {DistanceDisplayConditionGeometryInstanceAttribute} The new {@link DistanceDisplayConditionGeometryInstanceAttribute} instance.
  41100. *
  41101. * @exception {DeveloperError} distanceDisplayCondition.far must be greater than distanceDisplayCondition.near
  41102. *
  41103. * @example
  41104. * var instance = new Cesium.GeometryInstance({
  41105. * geometry : geometry,
  41106. * attributes : {
  41107. * color : Cesium.DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition),
  41108. * }
  41109. * });
  41110. */
  41111. DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition = function(distanceDisplayCondition) {
  41112. if (!defined(distanceDisplayCondition)) {
  41113. throw new DeveloperError('distanceDisplayCondition is required.');
  41114. }
  41115. if (distanceDisplayCondition.far <= distanceDisplayCondition.near) {
  41116. throw new DeveloperError('distanceDisplayCondition.far distance must be greater than distanceDisplayCondition.near distance.');
  41117. }
  41118. return new DistanceDisplayConditionGeometryInstanceAttribute(distanceDisplayCondition.near, distanceDisplayCondition.far);
  41119. };
  41120. /**
  41121. * Converts a distance display condition to a typed array that can be used to assign a distance display condition attribute.
  41122. *
  41123. * @param {DistanceDisplayCondition} distanceDisplayCondition The distance display condition value.
  41124. * @param {Float32Array} [result] The array to store the result in, if undefined a new instance will be created.
  41125. * @returns {Float32Array} The modified result parameter or a new instance if result was undefined.
  41126. *
  41127. * @example
  41128. * var attributes = primitive.getGeometryInstanceAttributes('an id');
  41129. * attributes.distanceDisplayCondition = Cesium.DistanceDisplayConditionGeometryInstanceAttribute.toValue(distanceDisplayCondition, attributes.distanceDisplayCondition);
  41130. */
  41131. DistanceDisplayConditionGeometryInstanceAttribute.toValue = function(distanceDisplayCondition, result) {
  41132. if (!defined(distanceDisplayCondition)) {
  41133. throw new DeveloperError('distanceDisplayCondition is required.');
  41134. }
  41135. if (!defined(result)) {
  41136. return new Float32Array([distanceDisplayCondition.near, distanceDisplayCondition.far]);
  41137. }
  41138. result[0] = distanceDisplayCondition.near;
  41139. result[1] = distanceDisplayCondition.far;
  41140. return result;
  41141. };
  41142. return DistanceDisplayConditionGeometryInstanceAttribute;
  41143. });
  41144. /**
  41145. @license
  41146. tween.js - https://github.com/sole/tween.js
  41147. Copyright (c) 2010-2012 Tween.js authors.
  41148. Easing equations Copyright (c) 2001 Robert Penner http://robertpenner.com/easing/
  41149. Permission is hereby granted, free of charge, to any person obtaining a copy
  41150. of this software and associated documentation files (the "Software"), to deal
  41151. in the Software without restriction, including without limitation the rights
  41152. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  41153. copies of the Software, and to permit persons to whom the Software is
  41154. furnished to do so, subject to the following conditions:
  41155. The above copyright notice and this permission notice shall be included in
  41156. all copies or substantial portions of the Software.
  41157. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  41158. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  41159. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  41160. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  41161. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  41162. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  41163. THE SOFTWARE.
  41164. */
  41165. /**
  41166. * @author sole / http://soledadpenades.com
  41167. * @author mrdoob / http://mrdoob.com
  41168. * @author Robert Eisele / http://www.xarg.org
  41169. * @author Philippe / http://philippe.elsass.me
  41170. * @author Robert Penner / http://www.robertpenner.com/easing_terms_of_use.html
  41171. * @author Paul Lewis / http://www.aerotwist.com/
  41172. * @author lechecacharro
  41173. * @author Josh Faul / http://jocafa.com/
  41174. * @author egraether / http://egraether.com/
  41175. * @author endel / http://endel.me
  41176. * @author Ben Delarre / http://delarre.net
  41177. */
  41178. /*global define*/
  41179. define('ThirdParty/Tween',[],function() {
  41180. // Date.now shim for (ahem) Internet Explo(d|r)er
  41181. if ( Date.now === undefined ) {
  41182. Date.now = function () {
  41183. return new Date().valueOf();
  41184. };
  41185. }
  41186. var TWEEN = TWEEN || ( function () {
  41187. var _tweens = [];
  41188. return {
  41189. REVISION: '13',
  41190. getAll: function () {
  41191. return _tweens;
  41192. },
  41193. removeAll: function () {
  41194. _tweens = [];
  41195. },
  41196. add: function ( tween ) {
  41197. _tweens.push( tween );
  41198. },
  41199. remove: function ( tween ) {
  41200. var i = _tweens.indexOf( tween );
  41201. if ( i !== -1 ) {
  41202. _tweens.splice( i, 1 );
  41203. }
  41204. },
  41205. update: function ( time ) {
  41206. if ( _tweens.length === 0 ) return false;
  41207. var i = 0;
  41208. time = time !== undefined ? time : ( typeof window !== 'undefined' && window.performance !== undefined && window.performance.now !== undefined ? window.performance.now() : Date.now() );
  41209. while ( i < _tweens.length ) {
  41210. if ( _tweens[ i ].update( time ) ) {
  41211. i++;
  41212. } else {
  41213. _tweens.splice( i, 1 );
  41214. }
  41215. }
  41216. return true;
  41217. }
  41218. };
  41219. } )();
  41220. TWEEN.Tween = function ( object ) {
  41221. var _object = object;
  41222. var _valuesStart = {};
  41223. var _valuesEnd = {};
  41224. var _valuesStartRepeat = {};
  41225. var _duration = 1000;
  41226. var _repeat = 0;
  41227. var _yoyo = false;
  41228. var _isPlaying = false;
  41229. var _reversed = false;
  41230. var _delayTime = 0;
  41231. var _startTime = null;
  41232. var _easingFunction = TWEEN.Easing.Linear.None;
  41233. var _interpolationFunction = TWEEN.Interpolation.Linear;
  41234. var _chainedTweens = [];
  41235. var _onStartCallback = null;
  41236. var _onStartCallbackFired = false;
  41237. var _onUpdateCallback = null;
  41238. var _onCompleteCallback = null;
  41239. var _onStopCallback = null;
  41240. // Set all starting values present on the target object
  41241. for ( var field in object ) {
  41242. _valuesStart[ field ] = parseFloat(object[field], 10);
  41243. }
  41244. this.to = function ( properties, duration ) {
  41245. if ( duration !== undefined ) {
  41246. _duration = duration;
  41247. }
  41248. _valuesEnd = properties;
  41249. return this;
  41250. };
  41251. this.start = function ( time ) {
  41252. TWEEN.add( this );
  41253. _isPlaying = true;
  41254. _onStartCallbackFired = false;
  41255. _startTime = time !== undefined ? time : ( typeof window !== 'undefined' && window.performance !== undefined && window.performance.now !== undefined ? window.performance.now() : Date.now() );
  41256. _startTime += _delayTime;
  41257. for ( var property in _valuesEnd ) {
  41258. // check if an Array was provided as property value
  41259. if ( _valuesEnd[ property ] instanceof Array ) {
  41260. if ( _valuesEnd[ property ].length === 0 ) {
  41261. continue;
  41262. }
  41263. // create a local copy of the Array with the start value at the front
  41264. _valuesEnd[ property ] = [ _object[ property ] ].concat( _valuesEnd[ property ] );
  41265. }
  41266. _valuesStart[ property ] = _object[ property ];
  41267. if( ( _valuesStart[ property ] instanceof Array ) === false ) {
  41268. _valuesStart[ property ] *= 1.0; // Ensures we're using numbers, not strings
  41269. }
  41270. _valuesStartRepeat[ property ] = _valuesStart[ property ] || 0;
  41271. }
  41272. return this;
  41273. };
  41274. this.stop = function () {
  41275. if ( !_isPlaying ) {
  41276. return this;
  41277. }
  41278. TWEEN.remove( this );
  41279. _isPlaying = false;
  41280. if ( _onStopCallback !== null ) {
  41281. _onStopCallback.call( _object );
  41282. }
  41283. this.stopChainedTweens();
  41284. return this;
  41285. };
  41286. this.stopChainedTweens = function () {
  41287. for ( var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++ ) {
  41288. _chainedTweens[ i ].stop();
  41289. }
  41290. };
  41291. this.delay = function ( amount ) {
  41292. _delayTime = amount;
  41293. return this;
  41294. };
  41295. this.repeat = function ( times ) {
  41296. _repeat = times;
  41297. return this;
  41298. };
  41299. this.yoyo = function( yoyo ) {
  41300. _yoyo = yoyo;
  41301. return this;
  41302. };
  41303. this.easing = function ( easing ) {
  41304. _easingFunction = easing;
  41305. return this;
  41306. };
  41307. this.interpolation = function ( interpolation ) {
  41308. _interpolationFunction = interpolation;
  41309. return this;
  41310. };
  41311. this.chain = function () {
  41312. _chainedTweens = arguments;
  41313. return this;
  41314. };
  41315. this.onStart = function ( callback ) {
  41316. _onStartCallback = callback;
  41317. return this;
  41318. };
  41319. this.onUpdate = function ( callback ) {
  41320. _onUpdateCallback = callback;
  41321. return this;
  41322. };
  41323. this.onComplete = function ( callback ) {
  41324. _onCompleteCallback = callback;
  41325. return this;
  41326. };
  41327. this.onStop = function ( callback ) {
  41328. _onStopCallback = callback;
  41329. return this;
  41330. };
  41331. this.update = function ( time ) {
  41332. var property;
  41333. if ( time < _startTime ) {
  41334. return true;
  41335. }
  41336. if ( _onStartCallbackFired === false ) {
  41337. if ( _onStartCallback !== null ) {
  41338. _onStartCallback.call( _object );
  41339. }
  41340. _onStartCallbackFired = true;
  41341. }
  41342. var elapsed = ( time - _startTime ) / _duration;
  41343. elapsed = elapsed > 1 ? 1 : elapsed;
  41344. var value = _easingFunction( elapsed );
  41345. for ( property in _valuesEnd ) {
  41346. var start = _valuesStart[ property ] || 0;
  41347. var end = _valuesEnd[ property ];
  41348. if ( end instanceof Array ) {
  41349. _object[ property ] = _interpolationFunction( end, value );
  41350. } else {
  41351. // Parses relative end values with start as base (e.g.: +10, -3)
  41352. if ( typeof(end) === "string" ) {
  41353. end = start + parseFloat(end, 10);
  41354. }
  41355. // protect against non numeric properties.
  41356. if ( typeof(end) === "number" ) {
  41357. _object[ property ] = start + ( end - start ) * value;
  41358. }
  41359. }
  41360. }
  41361. if ( _onUpdateCallback !== null ) {
  41362. _onUpdateCallback.call( _object, value );
  41363. }
  41364. if ( elapsed == 1 ) {
  41365. if ( _repeat > 0 ) {
  41366. if( isFinite( _repeat ) ) {
  41367. _repeat--;
  41368. }
  41369. // reassign starting values, restart by making startTime = now
  41370. for( property in _valuesStartRepeat ) {
  41371. if ( typeof( _valuesEnd[ property ] ) === "string" ) {
  41372. _valuesStartRepeat[ property ] = _valuesStartRepeat[ property ] + parseFloat(_valuesEnd[ property ], 10);
  41373. }
  41374. if (_yoyo) {
  41375. var tmp = _valuesStartRepeat[ property ];
  41376. _valuesStartRepeat[ property ] = _valuesEnd[ property ];
  41377. _valuesEnd[ property ] = tmp;
  41378. }
  41379. _valuesStart[ property ] = _valuesStartRepeat[ property ];
  41380. }
  41381. if (_yoyo) {
  41382. _reversed = !_reversed;
  41383. }
  41384. _startTime = time + _delayTime;
  41385. return true;
  41386. } else {
  41387. if ( _onCompleteCallback !== null ) {
  41388. _onCompleteCallback.call( _object );
  41389. }
  41390. for ( var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++ ) {
  41391. _chainedTweens[ i ].start( time );
  41392. }
  41393. return false;
  41394. }
  41395. }
  41396. return true;
  41397. };
  41398. };
  41399. TWEEN.Easing = {
  41400. Linear: {
  41401. None: function ( k ) {
  41402. return k;
  41403. }
  41404. },
  41405. Quadratic: {
  41406. In: function ( k ) {
  41407. return k * k;
  41408. },
  41409. Out: function ( k ) {
  41410. return k * ( 2 - k );
  41411. },
  41412. InOut: function ( k ) {
  41413. if ( ( k *= 2 ) < 1 ) return 0.5 * k * k;
  41414. return - 0.5 * ( --k * ( k - 2 ) - 1 );
  41415. }
  41416. },
  41417. Cubic: {
  41418. In: function ( k ) {
  41419. return k * k * k;
  41420. },
  41421. Out: function ( k ) {
  41422. return --k * k * k + 1;
  41423. },
  41424. InOut: function ( k ) {
  41425. if ( ( k *= 2 ) < 1 ) return 0.5 * k * k * k;
  41426. return 0.5 * ( ( k -= 2 ) * k * k + 2 );
  41427. }
  41428. },
  41429. Quartic: {
  41430. In: function ( k ) {
  41431. return k * k * k * k;
  41432. },
  41433. Out: function ( k ) {
  41434. return 1 - ( --k * k * k * k );
  41435. },
  41436. InOut: function ( k ) {
  41437. if ( ( k *= 2 ) < 1) return 0.5 * k * k * k * k;
  41438. return - 0.5 * ( ( k -= 2 ) * k * k * k - 2 );
  41439. }
  41440. },
  41441. Quintic: {
  41442. In: function ( k ) {
  41443. return k * k * k * k * k;
  41444. },
  41445. Out: function ( k ) {
  41446. return --k * k * k * k * k + 1;
  41447. },
  41448. InOut: function ( k ) {
  41449. if ( ( k *= 2 ) < 1 ) return 0.5 * k * k * k * k * k;
  41450. return 0.5 * ( ( k -= 2 ) * k * k * k * k + 2 );
  41451. }
  41452. },
  41453. Sinusoidal: {
  41454. In: function ( k ) {
  41455. return 1 - Math.cos( k * Math.PI / 2 );
  41456. },
  41457. Out: function ( k ) {
  41458. return Math.sin( k * Math.PI / 2 );
  41459. },
  41460. InOut: function ( k ) {
  41461. return 0.5 * ( 1 - Math.cos( Math.PI * k ) );
  41462. }
  41463. },
  41464. Exponential: {
  41465. In: function ( k ) {
  41466. return k === 0 ? 0 : Math.pow( 1024, k - 1 );
  41467. },
  41468. Out: function ( k ) {
  41469. return k === 1 ? 1 : 1 - Math.pow( 2, - 10 * k );
  41470. },
  41471. InOut: function ( k ) {
  41472. if ( k === 0 ) return 0;
  41473. if ( k === 1 ) return 1;
  41474. if ( ( k *= 2 ) < 1 ) return 0.5 * Math.pow( 1024, k - 1 );
  41475. return 0.5 * ( - Math.pow( 2, - 10 * ( k - 1 ) ) + 2 );
  41476. }
  41477. },
  41478. Circular: {
  41479. In: function ( k ) {
  41480. return 1 - Math.sqrt( 1 - k * k );
  41481. },
  41482. Out: function ( k ) {
  41483. return Math.sqrt( 1 - ( --k * k ) );
  41484. },
  41485. InOut: function ( k ) {
  41486. if ( ( k *= 2 ) < 1) return - 0.5 * ( Math.sqrt( 1 - k * k) - 1);
  41487. return 0.5 * ( Math.sqrt( 1 - ( k -= 2) * k) + 1);
  41488. }
  41489. },
  41490. Elastic: {
  41491. In: function ( k ) {
  41492. var s, a = 0.1, p = 0.4;
  41493. if ( k === 0 ) return 0;
  41494. if ( k === 1 ) return 1;
  41495. if ( !a || a < 1 ) { a = 1; s = p / 4; }
  41496. else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
  41497. return - ( a * Math.pow( 2, 10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) );
  41498. },
  41499. Out: function ( k ) {
  41500. var s, a = 0.1, p = 0.4;
  41501. if ( k === 0 ) return 0;
  41502. if ( k === 1 ) return 1;
  41503. if ( !a || a < 1 ) { a = 1; s = p / 4; }
  41504. else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
  41505. return ( a * Math.pow( 2, - 10 * k) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) + 1 );
  41506. },
  41507. InOut: function ( k ) {
  41508. var s, a = 0.1, p = 0.4;
  41509. if ( k === 0 ) return 0;
  41510. if ( k === 1 ) return 1;
  41511. if ( !a || a < 1 ) { a = 1; s = p / 4; }
  41512. else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
  41513. if ( ( k *= 2 ) < 1 ) return - 0.5 * ( a * Math.pow( 2, 10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) );
  41514. return a * Math.pow( 2, -10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) * 0.5 + 1;
  41515. }
  41516. },
  41517. Back: {
  41518. In: function ( k ) {
  41519. var s = 1.70158;
  41520. return k * k * ( ( s + 1 ) * k - s );
  41521. },
  41522. Out: function ( k ) {
  41523. var s = 1.70158;
  41524. return --k * k * ( ( s + 1 ) * k + s ) + 1;
  41525. },
  41526. InOut: function ( k ) {
  41527. var s = 1.70158 * 1.525;
  41528. if ( ( k *= 2 ) < 1 ) return 0.5 * ( k * k * ( ( s + 1 ) * k - s ) );
  41529. return 0.5 * ( ( k -= 2 ) * k * ( ( s + 1 ) * k + s ) + 2 );
  41530. }
  41531. },
  41532. Bounce: {
  41533. In: function ( k ) {
  41534. return 1 - TWEEN.Easing.Bounce.Out( 1 - k );
  41535. },
  41536. Out: function ( k ) {
  41537. if ( k < ( 1 / 2.75 ) ) {
  41538. return 7.5625 * k * k;
  41539. } else if ( k < ( 2 / 2.75 ) ) {
  41540. return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
  41541. } else if ( k < ( 2.5 / 2.75 ) ) {
  41542. return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
  41543. } else {
  41544. return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
  41545. }
  41546. },
  41547. InOut: function ( k ) {
  41548. if ( k < 0.5 ) return TWEEN.Easing.Bounce.In( k * 2 ) * 0.5;
  41549. return TWEEN.Easing.Bounce.Out( k * 2 - 1 ) * 0.5 + 0.5;
  41550. }
  41551. }
  41552. };
  41553. TWEEN.Interpolation = {
  41554. Linear: function ( v, k ) {
  41555. var m = v.length - 1, f = m * k, i = Math.floor( f ), fn = TWEEN.Interpolation.Utils.Linear;
  41556. if ( k < 0 ) return fn( v[ 0 ], v[ 1 ], f );
  41557. if ( k > 1 ) return fn( v[ m ], v[ m - 1 ], m - f );
  41558. return fn( v[ i ], v[ i + 1 > m ? m : i + 1 ], f - i );
  41559. },
  41560. Bezier: function ( v, k ) {
  41561. var b = 0, n = v.length - 1, pw = Math.pow, bn = TWEEN.Interpolation.Utils.Bernstein, i;
  41562. for ( i = 0; i <= n; i++ ) {
  41563. b += pw( 1 - k, n - i ) * pw( k, i ) * v[ i ] * bn( n, i );
  41564. }
  41565. return b;
  41566. },
  41567. CatmullRom: function ( v, k ) {
  41568. var m = v.length - 1, f = m * k, i = Math.floor( f ), fn = TWEEN.Interpolation.Utils.CatmullRom;
  41569. if ( v[ 0 ] === v[ m ] ) {
  41570. if ( k < 0 ) i = Math.floor( f = m * ( 1 + k ) );
  41571. return fn( v[ ( i - 1 + m ) % m ], v[ i ], v[ ( i + 1 ) % m ], v[ ( i + 2 ) % m ], f - i );
  41572. } else {
  41573. if ( k < 0 ) return v[ 0 ] - ( fn( v[ 0 ], v[ 0 ], v[ 1 ], v[ 1 ], -f ) - v[ 0 ] );
  41574. if ( k > 1 ) return v[ m ] - ( fn( v[ m ], v[ m ], v[ m - 1 ], v[ m - 1 ], f - m ) - v[ m ] );
  41575. return fn( v[ i ? i - 1 : 0 ], v[ i ], v[ m < i + 1 ? m : i + 1 ], v[ m < i + 2 ? m : i + 2 ], f - i );
  41576. }
  41577. },
  41578. Utils: {
  41579. Linear: function ( p0, p1, t ) {
  41580. return ( p1 - p0 ) * t + p0;
  41581. },
  41582. Bernstein: function ( n , i ) {
  41583. var fc = TWEEN.Interpolation.Utils.Factorial;
  41584. return fc( n ) / fc( i ) / fc( n - i );
  41585. },
  41586. Factorial: ( function () {
  41587. var a = [ 1 ];
  41588. return function ( n ) {
  41589. var s = 1, i;
  41590. if ( a[ n ] ) return a[ n ];
  41591. for ( i = n; i > 1; i-- ) s *= i;
  41592. return a[ n ] = s;
  41593. };
  41594. } )(),
  41595. CatmullRom: function ( p0, p1, p2, p3, t ) {
  41596. var v0 = ( p2 - p0 ) * 0.5, v1 = ( p3 - p1 ) * 0.5, t2 = t * t, t3 = t * t2;
  41597. return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
  41598. }
  41599. }
  41600. };
  41601. return TWEEN;
  41602. });
  41603. /*global define*/
  41604. define('Core/EasingFunction',[
  41605. '../ThirdParty/Tween',
  41606. './freezeObject'
  41607. ], function(
  41608. Tween,
  41609. freezeObject) {
  41610. 'use strict';
  41611. /**
  41612. * Easing functions for use with {@link TweenCollection}. These function are from
  41613. * {@link https://github.com/sole/tween.js/|Tween.js} and Robert Penner. See the
  41614. * {@link http://sole.github.io/tween.js/examples/03_graphs.html|Tween.js graphs for each function}.
  41615. *
  41616. * @exports EasingFunction
  41617. */
  41618. var EasingFunction = {
  41619. /**
  41620. * Linear easing.
  41621. *
  41622. * @type {EasingFunction~Callback}
  41623. * @constant
  41624. */
  41625. LINEAR_NONE : Tween.Easing.Linear.None,
  41626. /**
  41627. * Quadratic in.
  41628. *
  41629. * @type {EasingFunction~Callback}
  41630. * @constant
  41631. */
  41632. QUADRACTIC_IN : Tween.Easing.Quadratic.In,
  41633. /**
  41634. * Quadratic out.
  41635. *
  41636. * @type {EasingFunction~Callback}
  41637. * @constant
  41638. */
  41639. QUADRACTIC_OUT : Tween.Easing.Quadratic.Out,
  41640. /**
  41641. * Quadratic in then out.
  41642. *
  41643. * @type {EasingFunction~Callback}
  41644. * @constant
  41645. */
  41646. QUADRACTIC_IN_OUT : Tween.Easing.Quadratic.InOut,
  41647. /**
  41648. * Cubic in.
  41649. *
  41650. * @type {EasingFunction~Callback}
  41651. * @constant
  41652. */
  41653. CUBIC_IN : Tween.Easing.Cubic.In,
  41654. /**
  41655. * Cubic out.
  41656. *
  41657. * @type {EasingFunction~Callback}
  41658. * @constant
  41659. */
  41660. CUBIC_OUT : Tween.Easing.Cubic.Out,
  41661. /**
  41662. * Cubic in then out.
  41663. *
  41664. * @type {EasingFunction~Callback}
  41665. * @constant
  41666. */
  41667. CUBIC_IN_OUT : Tween.Easing.Cubic.InOut,
  41668. /**
  41669. * Quartic in.
  41670. *
  41671. * @type {EasingFunction~Callback}
  41672. * @constant
  41673. */
  41674. QUARTIC_IN : Tween.Easing.Quartic.In,
  41675. /**
  41676. * Quartic out.
  41677. *
  41678. * @type {EasingFunction~Callback}
  41679. * @constant
  41680. */
  41681. QUARTIC_OUT : Tween.Easing.Quartic.Out,
  41682. /**
  41683. * Quartic in then out.
  41684. *
  41685. * @type {EasingFunction~Callback}
  41686. * @constant
  41687. */
  41688. QUARTIC_IN_OUT : Tween.Easing.Quartic.InOut,
  41689. /**
  41690. * Quintic in.
  41691. *
  41692. * @type {EasingFunction~Callback}
  41693. * @constant
  41694. */
  41695. QUINTIC_IN : Tween.Easing.Quintic.In,
  41696. /**
  41697. * Quintic out.
  41698. *
  41699. * @type {EasingFunction~Callback}
  41700. * @constant
  41701. */
  41702. QUINTIC_OUT : Tween.Easing.Quintic.Out,
  41703. /**
  41704. * Quintic in then out.
  41705. *
  41706. * @type {EasingFunction~Callback}
  41707. * @constant
  41708. */
  41709. QUINTIC_IN_OUT : Tween.Easing.Quintic.InOut,
  41710. /**
  41711. * Sinusoidal in.
  41712. *
  41713. * @type {EasingFunction~Callback}
  41714. * @constant
  41715. */
  41716. SINUSOIDAL_IN : Tween.Easing.Sinusoidal.In,
  41717. /**
  41718. * Sinusoidal out.
  41719. *
  41720. * @type {EasingFunction~Callback}
  41721. * @constant
  41722. */
  41723. SINUSOIDAL_OUT : Tween.Easing.Sinusoidal.Out,
  41724. /**
  41725. * Sinusoidal in then out.
  41726. *
  41727. * @type {EasingFunction~Callback}
  41728. * @constant
  41729. */
  41730. SINUSOIDAL_IN_OUT : Tween.Easing.Sinusoidal.InOut,
  41731. /**
  41732. * Exponential in.
  41733. *
  41734. * @type {EasingFunction~Callback}
  41735. * @constant
  41736. */
  41737. EXPONENTIAL_IN : Tween.Easing.Exponential.In,
  41738. /**
  41739. * Exponential out.
  41740. *
  41741. * @type {EasingFunction~Callback}
  41742. * @constant
  41743. */
  41744. EXPONENTIAL_OUT : Tween.Easing.Exponential.Out,
  41745. /**
  41746. * Exponential in then out.
  41747. *
  41748. * @type {EasingFunction~Callback}
  41749. * @constant
  41750. */
  41751. EXPONENTIAL_IN_OUT : Tween.Easing.Exponential.InOut,
  41752. /**
  41753. * Circular in.
  41754. *
  41755. * @type {EasingFunction~Callback}
  41756. * @constant
  41757. */
  41758. CIRCULAR_IN : Tween.Easing.Circular.In,
  41759. /**
  41760. * Circular out.
  41761. *
  41762. * @type {EasingFunction~Callback}
  41763. * @constant
  41764. */
  41765. CIRCULAR_OUT : Tween.Easing.Circular.Out,
  41766. /**
  41767. * Circular in then out.
  41768. *
  41769. * @type {EasingFunction~Callback}
  41770. * @constant
  41771. */
  41772. CIRCULAR_IN_OUT : Tween.Easing.Circular.InOut,
  41773. /**
  41774. * Elastic in.
  41775. *
  41776. * @type {EasingFunction~Callback}
  41777. * @constant
  41778. */
  41779. ELASTIC_IN : Tween.Easing.Elastic.In,
  41780. /**
  41781. * Elastic out.
  41782. *
  41783. * @type {EasingFunction~Callback}
  41784. * @constant
  41785. */
  41786. ELASTIC_OUT : Tween.Easing.Elastic.Out,
  41787. /**
  41788. * Elastic in then out.
  41789. *
  41790. * @type {EasingFunction~Callback}
  41791. * @constant
  41792. */
  41793. ELASTIC_IN_OUT : Tween.Easing.Elastic.InOut,
  41794. /**
  41795. * Back in.
  41796. *
  41797. * @type {EasingFunction~Callback}
  41798. * @constant
  41799. */
  41800. BACK_IN : Tween.Easing.Back.In,
  41801. /**
  41802. * Back out.
  41803. *
  41804. * @type {EasingFunction~Callback}
  41805. * @constant
  41806. */
  41807. BACK_OUT : Tween.Easing.Back.Out,
  41808. /**
  41809. * Back in then out.
  41810. *
  41811. * @type {EasingFunction~Callback}
  41812. * @constant
  41813. */
  41814. BACK_IN_OUT : Tween.Easing.Back.InOut,
  41815. /**
  41816. * Bounce in.
  41817. *
  41818. * @type {EasingFunction~Callback}
  41819. * @constant
  41820. */
  41821. BOUNCE_IN : Tween.Easing.Bounce.In,
  41822. /**
  41823. * Bounce out.
  41824. *
  41825. * @type {EasingFunction~Callback}
  41826. * @constant
  41827. */
  41828. BOUNCE_OUT : Tween.Easing.Bounce.Out,
  41829. /**
  41830. * Bounce in then out.
  41831. *
  41832. * @type {EasingFunction~Callback}
  41833. * @constant
  41834. */
  41835. BOUNCE_IN_OUT : Tween.Easing.Bounce.InOut
  41836. };
  41837. /**
  41838. * Function interface for implementing a custom easing function.
  41839. * @callback EasingFunction~Callback
  41840. * @param {Number} time The time in the range <code>[0, 1]</code>.
  41841. * @returns {Number} The value of the function at the given time.
  41842. *
  41843. * @example
  41844. * function quadraticIn(time) {
  41845. * return time * time;
  41846. * }
  41847. *
  41848. * @example
  41849. * function quadraticOut(time) {
  41850. * return time * (2.0 - time);
  41851. * }
  41852. */
  41853. return freezeObject(EasingFunction);
  41854. });
  41855. /*global define*/
  41856. define('Core/EllipsoidGeometry',[
  41857. './BoundingSphere',
  41858. './Cartesian2',
  41859. './Cartesian3',
  41860. './ComponentDatatype',
  41861. './defaultValue',
  41862. './defined',
  41863. './DeveloperError',
  41864. './Ellipsoid',
  41865. './Geometry',
  41866. './GeometryAttribute',
  41867. './GeometryAttributes',
  41868. './IndexDatatype',
  41869. './Math',
  41870. './PrimitiveType',
  41871. './VertexFormat'
  41872. ], function(
  41873. BoundingSphere,
  41874. Cartesian2,
  41875. Cartesian3,
  41876. ComponentDatatype,
  41877. defaultValue,
  41878. defined,
  41879. DeveloperError,
  41880. Ellipsoid,
  41881. Geometry,
  41882. GeometryAttribute,
  41883. GeometryAttributes,
  41884. IndexDatatype,
  41885. CesiumMath,
  41886. PrimitiveType,
  41887. VertexFormat) {
  41888. 'use strict';
  41889. var scratchPosition = new Cartesian3();
  41890. var scratchNormal = new Cartesian3();
  41891. var scratchTangent = new Cartesian3();
  41892. var scratchBinormal = new Cartesian3();
  41893. var scratchNormalST = new Cartesian3();
  41894. var defaultRadii = new Cartesian3(1.0, 1.0, 1.0);
  41895. var cos = Math.cos;
  41896. var sin = Math.sin;
  41897. /**
  41898. * A description of an ellipsoid centered at the origin.
  41899. *
  41900. * @alias EllipsoidGeometry
  41901. * @constructor
  41902. *
  41903. * @param {Object} [options] Object with the following properties:
  41904. * @param {Cartesian3} [options.radii=Cartesian3(1.0, 1.0, 1.0)] The radii of the ellipsoid in the x, y, and z directions.
  41905. * @param {Number} [options.stackPartitions=64] The number of times to partition the ellipsoid into stacks.
  41906. * @param {Number} [options.slicePartitions=64] The number of times to partition the ellipsoid into radial slices.
  41907. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  41908. *
  41909. * @exception {DeveloperError} options.slicePartitions cannot be less than three.
  41910. * @exception {DeveloperError} options.stackPartitions cannot be less than three.
  41911. *
  41912. * @see EllipsoidGeometry#createGeometry
  41913. *
  41914. * @example
  41915. * var ellipsoid = new Cesium.EllipsoidGeometry({
  41916. * vertexFormat : Cesium.VertexFormat.POSITION_ONLY,
  41917. * radii : new Cesium.Cartesian3(1000000.0, 500000.0, 500000.0)
  41918. * });
  41919. * var geometry = Cesium.EllipsoidGeometry.createGeometry(ellipsoid);
  41920. */
  41921. function EllipsoidGeometry(options) {
  41922. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  41923. var radii = defaultValue(options.radii, defaultRadii);
  41924. var stackPartitions = defaultValue(options.stackPartitions, 64);
  41925. var slicePartitions = defaultValue(options.slicePartitions, 64);
  41926. var vertexFormat = defaultValue(options.vertexFormat, VertexFormat.DEFAULT);
  41927. if (slicePartitions < 3) {
  41928. throw new DeveloperError ('options.slicePartitions cannot be less than three.');
  41929. }
  41930. if (stackPartitions < 3) {
  41931. throw new DeveloperError('options.stackPartitions cannot be less than three.');
  41932. }
  41933. this._radii = Cartesian3.clone(radii);
  41934. this._stackPartitions = stackPartitions;
  41935. this._slicePartitions = slicePartitions;
  41936. this._vertexFormat = VertexFormat.clone(vertexFormat);
  41937. this._workerName = 'createEllipsoidGeometry';
  41938. }
  41939. /**
  41940. * The number of elements used to pack the object into an array.
  41941. * @type {Number}
  41942. */
  41943. EllipsoidGeometry.packedLength = Cartesian3.packedLength + VertexFormat.packedLength + 2;
  41944. /**
  41945. * Stores the provided instance into the provided array.
  41946. *
  41947. * @param {EllipsoidGeometry} value The value to pack.
  41948. * @param {Number[]} array The array to pack into.
  41949. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  41950. *
  41951. * @returns {Number[]} The array that was packed into
  41952. */
  41953. EllipsoidGeometry.pack = function(value, array, startingIndex) {
  41954. if (!defined(value)) {
  41955. throw new DeveloperError('value is required');
  41956. }
  41957. if (!defined(array)) {
  41958. throw new DeveloperError('array is required');
  41959. }
  41960. startingIndex = defaultValue(startingIndex, 0);
  41961. Cartesian3.pack(value._radii, array, startingIndex);
  41962. startingIndex += Cartesian3.packedLength;
  41963. VertexFormat.pack(value._vertexFormat, array, startingIndex);
  41964. startingIndex += VertexFormat.packedLength;
  41965. array[startingIndex++] = value._stackPartitions;
  41966. array[startingIndex] = value._slicePartitions;
  41967. return array;
  41968. };
  41969. var scratchRadii = new Cartesian3();
  41970. var scratchVertexFormat = new VertexFormat();
  41971. var scratchOptions = {
  41972. radii : scratchRadii,
  41973. vertexFormat : scratchVertexFormat,
  41974. stackPartitions : undefined,
  41975. slicePartitions : undefined
  41976. };
  41977. /**
  41978. * Retrieves an instance from a packed array.
  41979. *
  41980. * @param {Number[]} array The packed array.
  41981. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  41982. * @param {EllipsoidGeometry} [result] The object into which to store the result.
  41983. * @returns {EllipsoidGeometry} The modified result parameter or a new EllipsoidGeometry instance if one was not provided.
  41984. */
  41985. EllipsoidGeometry.unpack = function(array, startingIndex, result) {
  41986. if (!defined(array)) {
  41987. throw new DeveloperError('array is required');
  41988. }
  41989. startingIndex = defaultValue(startingIndex, 0);
  41990. var radii = Cartesian3.unpack(array, startingIndex, scratchRadii);
  41991. startingIndex += Cartesian3.packedLength;
  41992. var vertexFormat = VertexFormat.unpack(array, startingIndex, scratchVertexFormat);
  41993. startingIndex += VertexFormat.packedLength;
  41994. var stackPartitions = array[startingIndex++];
  41995. var slicePartitions = array[startingIndex];
  41996. if (!defined(result)) {
  41997. scratchOptions.stackPartitions = stackPartitions;
  41998. scratchOptions.slicePartitions = slicePartitions;
  41999. return new EllipsoidGeometry(scratchOptions);
  42000. }
  42001. result._radii = Cartesian3.clone(radii, result._radii);
  42002. result._vertexFormat = VertexFormat.clone(vertexFormat, result._vertexFormat);
  42003. result._stackPartitions = stackPartitions;
  42004. result._slicePartitions = slicePartitions;
  42005. return result;
  42006. };
  42007. /**
  42008. * Computes the geometric representation of an ellipsoid, including its vertices, indices, and a bounding sphere.
  42009. *
  42010. * @param {EllipsoidGeometry} ellipsoidGeometry A description of the ellipsoid.
  42011. * @returns {Geometry|undefined} The computed vertices and indices.
  42012. */
  42013. EllipsoidGeometry.createGeometry = function(ellipsoidGeometry) {
  42014. var radii = ellipsoidGeometry._radii;
  42015. if ((radii.x <= 0) || (radii.y <= 0) || (radii.z <= 0)) {
  42016. return;
  42017. }
  42018. var ellipsoid = Ellipsoid.fromCartesian3(radii);
  42019. var vertexFormat = ellipsoidGeometry._vertexFormat;
  42020. // The extra slice and stack are for duplicating points at the x axis and poles.
  42021. // We need the texture coordinates to interpolate from (2 * pi - delta) to 2 * pi instead of
  42022. // (2 * pi - delta) to 0.
  42023. var slicePartitions = ellipsoidGeometry._slicePartitions + 1;
  42024. var stackPartitions = ellipsoidGeometry._stackPartitions + 1;
  42025. var vertexCount = stackPartitions * slicePartitions;
  42026. var positions = new Float64Array(vertexCount * 3);
  42027. var numIndices = 6 * (slicePartitions - 1) * (stackPartitions - 2);
  42028. var indices = IndexDatatype.createTypedArray(vertexCount, numIndices);
  42029. var normals = (vertexFormat.normal) ? new Float32Array(vertexCount * 3) : undefined;
  42030. var tangents = (vertexFormat.tangent) ? new Float32Array(vertexCount * 3) : undefined;
  42031. var binormals = (vertexFormat.binormal) ? new Float32Array(vertexCount * 3) : undefined;
  42032. var st = (vertexFormat.st) ? new Float32Array(vertexCount * 2) : undefined;
  42033. var cosTheta = new Array(slicePartitions);
  42034. var sinTheta = new Array(slicePartitions);
  42035. var i;
  42036. var j;
  42037. var index = 0;
  42038. for (i = 0; i < slicePartitions; i++) {
  42039. var theta = CesiumMath.TWO_PI * i / (slicePartitions - 1);
  42040. cosTheta[i] = cos(theta);
  42041. sinTheta[i] = sin(theta);
  42042. // duplicate first point for correct
  42043. // texture coordinates at the north pole.
  42044. positions[index++] = 0.0;
  42045. positions[index++] = 0.0;
  42046. positions[index++] = radii.z;
  42047. }
  42048. for (i = 1; i < stackPartitions - 1; i++) {
  42049. var phi = Math.PI * i / (stackPartitions - 1);
  42050. var sinPhi = sin(phi);
  42051. var xSinPhi = radii.x * sinPhi;
  42052. var ySinPhi = radii.y * sinPhi;
  42053. var zCosPhi = radii.z * cos(phi);
  42054. for (j = 0; j < slicePartitions; j++) {
  42055. positions[index++] = cosTheta[j] * xSinPhi;
  42056. positions[index++] = sinTheta[j] * ySinPhi;
  42057. positions[index++] = zCosPhi;
  42058. }
  42059. }
  42060. for (i = 0; i < slicePartitions; i++) {
  42061. // duplicate first point for correct
  42062. // texture coordinates at the south pole.
  42063. positions[index++] = 0.0;
  42064. positions[index++] = 0.0;
  42065. positions[index++] = -radii.z;
  42066. }
  42067. var attributes = new GeometryAttributes();
  42068. if (vertexFormat.position) {
  42069. attributes.position = new GeometryAttribute({
  42070. componentDatatype : ComponentDatatype.DOUBLE,
  42071. componentsPerAttribute : 3,
  42072. values : positions
  42073. });
  42074. }
  42075. var stIndex = 0;
  42076. var normalIndex = 0;
  42077. var tangentIndex = 0;
  42078. var binormalIndex = 0;
  42079. if (vertexFormat.st || vertexFormat.normal || vertexFormat.tangent || vertexFormat.binormal) {
  42080. for( i = 0; i < vertexCount; i++) {
  42081. var position = Cartesian3.fromArray(positions, i * 3, scratchPosition);
  42082. var normal = ellipsoid.geodeticSurfaceNormal(position, scratchNormal);
  42083. if (vertexFormat.st) {
  42084. var normalST = Cartesian2.negate(normal, scratchNormalST);
  42085. // if the point is at or close to the pole, find a point along the same longitude
  42086. // close to the xy-plane for the s coordinate.
  42087. if (Cartesian2.magnitude(normalST) < CesiumMath.EPSILON6) {
  42088. index = (i + slicePartitions * Math.floor(stackPartitions * 0.5)) * 3;
  42089. if (index > positions.length) {
  42090. index = (i - slicePartitions * Math.floor(stackPartitions * 0.5)) * 3;
  42091. }
  42092. Cartesian3.fromArray(positions, index, normalST);
  42093. ellipsoid.geodeticSurfaceNormal(normalST, normalST);
  42094. Cartesian2.negate(normalST, normalST);
  42095. }
  42096. st[stIndex++] = (Math.atan2(normalST.y, normalST.x) / CesiumMath.TWO_PI) + 0.5;
  42097. st[stIndex++] = (Math.asin(normal.z) / Math.PI) + 0.5;
  42098. }
  42099. if (vertexFormat.normal) {
  42100. normals[normalIndex++] = normal.x;
  42101. normals[normalIndex++] = normal.y;
  42102. normals[normalIndex++] = normal.z;
  42103. }
  42104. if (vertexFormat.tangent || vertexFormat.binormal) {
  42105. var tangent = scratchTangent;
  42106. if (i < slicePartitions || i > vertexCount - slicePartitions - 1) {
  42107. Cartesian3.cross(Cartesian3.UNIT_X, normal, tangent);
  42108. Cartesian3.normalize(tangent, tangent);
  42109. } else {
  42110. Cartesian3.cross(Cartesian3.UNIT_Z, normal, tangent);
  42111. Cartesian3.normalize(tangent, tangent);
  42112. }
  42113. if (vertexFormat.tangent) {
  42114. tangents[tangentIndex++] = tangent.x;
  42115. tangents[tangentIndex++] = tangent.y;
  42116. tangents[tangentIndex++] = tangent.z;
  42117. }
  42118. if (vertexFormat.binormal) {
  42119. var binormal = Cartesian3.cross(normal, tangent, scratchBinormal);
  42120. Cartesian3.normalize(binormal, binormal);
  42121. binormals[binormalIndex++] = binormal.x;
  42122. binormals[binormalIndex++] = binormal.y;
  42123. binormals[binormalIndex++] = binormal.z;
  42124. }
  42125. }
  42126. }
  42127. if (vertexFormat.st) {
  42128. attributes.st = new GeometryAttribute({
  42129. componentDatatype : ComponentDatatype.FLOAT,
  42130. componentsPerAttribute : 2,
  42131. values : st
  42132. });
  42133. }
  42134. if (vertexFormat.normal) {
  42135. attributes.normal = new GeometryAttribute({
  42136. componentDatatype : ComponentDatatype.FLOAT,
  42137. componentsPerAttribute : 3,
  42138. values : normals
  42139. });
  42140. }
  42141. if (vertexFormat.tangent) {
  42142. attributes.tangent = new GeometryAttribute({
  42143. componentDatatype : ComponentDatatype.FLOAT,
  42144. componentsPerAttribute : 3,
  42145. values : tangents
  42146. });
  42147. }
  42148. if (vertexFormat.binormal) {
  42149. attributes.binormal = new GeometryAttribute({
  42150. componentDatatype : ComponentDatatype.FLOAT,
  42151. componentsPerAttribute : 3,
  42152. values : binormals
  42153. });
  42154. }
  42155. }
  42156. index = 0;
  42157. for (j = 0; j < slicePartitions - 1; j++) {
  42158. indices[index++] = slicePartitions + j;
  42159. indices[index++] = slicePartitions + j + 1;
  42160. indices[index++] = j + 1;
  42161. }
  42162. var topOffset;
  42163. var bottomOffset;
  42164. for (i = 1; i < stackPartitions - 2; i++) {
  42165. topOffset = i * slicePartitions;
  42166. bottomOffset = (i + 1) * slicePartitions;
  42167. for (j = 0; j < slicePartitions - 1; j++) {
  42168. indices[index++] = bottomOffset + j;
  42169. indices[index++] = bottomOffset + j + 1;
  42170. indices[index++] = topOffset + j + 1;
  42171. indices[index++] = bottomOffset + j;
  42172. indices[index++] = topOffset + j + 1;
  42173. indices[index++] = topOffset + j;
  42174. }
  42175. }
  42176. i = stackPartitions - 2;
  42177. topOffset = i * slicePartitions;
  42178. bottomOffset = (i + 1) * slicePartitions;
  42179. for (j = 0; j < slicePartitions - 1; j++) {
  42180. indices[index++] = bottomOffset + j;
  42181. indices[index++] = topOffset + j + 1;
  42182. indices[index++] = topOffset + j;
  42183. }
  42184. return new Geometry({
  42185. attributes : attributes,
  42186. indices : indices,
  42187. primitiveType : PrimitiveType.TRIANGLES,
  42188. boundingSphere : BoundingSphere.fromEllipsoid(ellipsoid)
  42189. });
  42190. };
  42191. return EllipsoidGeometry;
  42192. });
  42193. /*global define*/
  42194. define('Core/EllipsoidOutlineGeometry',[
  42195. './BoundingSphere',
  42196. './Cartesian3',
  42197. './ComponentDatatype',
  42198. './defaultValue',
  42199. './defined',
  42200. './DeveloperError',
  42201. './Ellipsoid',
  42202. './Geometry',
  42203. './GeometryAttribute',
  42204. './GeometryAttributes',
  42205. './IndexDatatype',
  42206. './Math',
  42207. './PrimitiveType'
  42208. ], function(
  42209. BoundingSphere,
  42210. Cartesian3,
  42211. ComponentDatatype,
  42212. defaultValue,
  42213. defined,
  42214. DeveloperError,
  42215. Ellipsoid,
  42216. Geometry,
  42217. GeometryAttribute,
  42218. GeometryAttributes,
  42219. IndexDatatype,
  42220. CesiumMath,
  42221. PrimitiveType) {
  42222. 'use strict';
  42223. var defaultRadii = new Cartesian3(1.0, 1.0, 1.0);
  42224. var cos = Math.cos;
  42225. var sin = Math.sin;
  42226. /**
  42227. * A description of the outline of an ellipsoid centered at the origin.
  42228. *
  42229. * @alias EllipsoidOutlineGeometry
  42230. * @constructor
  42231. *
  42232. * @param {Object} [options] Object with the following properties:
  42233. * @param {Cartesian3} [options.radii=Cartesian3(1.0, 1.0, 1.0)] The radii of the ellipsoid in the x, y, and z directions.
  42234. * @param {Number} [options.stackPartitions=10] The count of stacks for the ellipsoid (1 greater than the number of parallel lines).
  42235. * @param {Number} [options.slicePartitions=8] The count of slices for the ellipsoid (Equal to the number of radial lines).
  42236. * @param {Number} [options.subdivisions=128] The number of points per line, determining the granularity of the curvature.
  42237. *
  42238. * @exception {DeveloperError} options.stackPartitions must be greater than or equal to one.
  42239. * @exception {DeveloperError} options.slicePartitions must be greater than or equal to zero.
  42240. * @exception {DeveloperError} options.subdivisions must be greater than or equal to zero.
  42241. *
  42242. * @example
  42243. * var ellipsoid = new Cesium.EllipsoidOutlineGeometry({
  42244. * radii : new Cesium.Cartesian3(1000000.0, 500000.0, 500000.0),
  42245. * stackPartitions: 6,
  42246. * slicePartitions: 5
  42247. * });
  42248. * var geometry = Cesium.EllipsoidOutlineGeometry.createGeometry(ellipsoid);
  42249. */
  42250. function EllipsoidOutlineGeometry(options) {
  42251. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  42252. var radii = defaultValue(options.radii, defaultRadii);
  42253. var stackPartitions = defaultValue(options.stackPartitions, 10);
  42254. var slicePartitions = defaultValue(options.slicePartitions, 8);
  42255. var subdivisions = defaultValue(options.subdivisions, 128);
  42256. if (stackPartitions < 1) {
  42257. throw new DeveloperError('options.stackPartitions cannot be less than 1');
  42258. }
  42259. if (slicePartitions < 0) {
  42260. throw new DeveloperError('options.slicePartitions cannot be less than 0');
  42261. }
  42262. if (subdivisions < 0) {
  42263. throw new DeveloperError('options.subdivisions must be greater than or equal to zero.');
  42264. }
  42265. this._radii = Cartesian3.clone(radii);
  42266. this._stackPartitions = stackPartitions;
  42267. this._slicePartitions = slicePartitions;
  42268. this._subdivisions = subdivisions;
  42269. this._workerName = 'createEllipsoidOutlineGeometry';
  42270. }
  42271. /**
  42272. * The number of elements used to pack the object into an array.
  42273. * @type {Number}
  42274. */
  42275. EllipsoidOutlineGeometry.packedLength = Cartesian3.packedLength + 3;
  42276. /**
  42277. * Stores the provided instance into the provided array.
  42278. *
  42279. * @param {EllipsoidOutlineGeometry} value The value to pack.
  42280. * @param {Number[]} array The array to pack into.
  42281. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  42282. *
  42283. * @returns {Number[]} The array that was packed into
  42284. */
  42285. EllipsoidOutlineGeometry.pack = function(value, array, startingIndex) {
  42286. if (!defined(value)) {
  42287. throw new DeveloperError('value is required');
  42288. }
  42289. if (!defined(array)) {
  42290. throw new DeveloperError('array is required');
  42291. }
  42292. startingIndex = defaultValue(startingIndex, 0);
  42293. Cartesian3.pack(value._radii, array, startingIndex);
  42294. startingIndex += Cartesian3.packedLength;
  42295. array[startingIndex++] = value._stackPartitions;
  42296. array[startingIndex++] = value._slicePartitions;
  42297. array[startingIndex] = value._subdivisions;
  42298. return array;
  42299. };
  42300. var scratchRadii = new Cartesian3();
  42301. var scratchOptions = {
  42302. radii : scratchRadii,
  42303. stackPartitions : undefined,
  42304. slicePartitions : undefined,
  42305. subdivisions : undefined
  42306. };
  42307. /**
  42308. * Retrieves an instance from a packed array.
  42309. *
  42310. * @param {Number[]} array The packed array.
  42311. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  42312. * @param {EllipsoidOutlineGeometry} [result] The object into which to store the result.
  42313. * @returns {EllipsoidOutlineGeometry} The modified result parameter or a new EllipsoidOutlineGeometry instance if one was not provided.
  42314. */
  42315. EllipsoidOutlineGeometry.unpack = function(array, startingIndex, result) {
  42316. if (!defined(array)) {
  42317. throw new DeveloperError('array is required');
  42318. }
  42319. startingIndex = defaultValue(startingIndex, 0);
  42320. var radii = Cartesian3.unpack(array, startingIndex, scratchRadii);
  42321. startingIndex += Cartesian3.packedLength;
  42322. var stackPartitions = array[startingIndex++];
  42323. var slicePartitions = array[startingIndex++];
  42324. var subdivisions = array[startingIndex++];
  42325. if (!defined(result)) {
  42326. scratchOptions.stackPartitions = stackPartitions;
  42327. scratchOptions.slicePartitions = slicePartitions;
  42328. scratchOptions.subdivisions = subdivisions;
  42329. return new EllipsoidOutlineGeometry(scratchOptions);
  42330. }
  42331. result._radii = Cartesian3.clone(radii, result._radii);
  42332. result._stackPartitions = stackPartitions;
  42333. result._slicePartitions = slicePartitions;
  42334. result._subdivisions = subdivisions;
  42335. return result;
  42336. };
  42337. /**
  42338. * Computes the geometric representation of an outline of an ellipsoid, including its vertices, indices, and a bounding sphere.
  42339. *
  42340. * @param {EllipsoidOutlineGeometry} ellipsoidGeometry A description of the ellipsoid outline.
  42341. * @returns {Geometry|undefined} The computed vertices and indices.
  42342. */
  42343. EllipsoidOutlineGeometry.createGeometry = function(ellipsoidGeometry) {
  42344. var radii = ellipsoidGeometry._radii;
  42345. if ((radii.x <= 0) || (radii.y <= 0) || (radii.z <= 0)) {
  42346. return;
  42347. }
  42348. var ellipsoid = Ellipsoid.fromCartesian3(radii);
  42349. var stackPartitions = ellipsoidGeometry._stackPartitions;
  42350. var slicePartitions = ellipsoidGeometry._slicePartitions;
  42351. var subdivisions = ellipsoidGeometry._subdivisions;
  42352. var indicesSize = subdivisions * (stackPartitions + slicePartitions - 1);
  42353. var positionSize = indicesSize - slicePartitions + 2;
  42354. var positions = new Float64Array(positionSize * 3);
  42355. var indices = IndexDatatype.createTypedArray(positionSize, indicesSize * 2);
  42356. var i;
  42357. var j;
  42358. var theta;
  42359. var phi;
  42360. var cosPhi;
  42361. var sinPhi;
  42362. var index = 0;
  42363. var cosTheta = new Array(subdivisions);
  42364. var sinTheta = new Array(subdivisions);
  42365. for (i = 0; i < subdivisions; i++) {
  42366. theta = CesiumMath.TWO_PI * i / subdivisions;
  42367. cosTheta[i] = cos(theta);
  42368. sinTheta[i] = sin(theta);
  42369. }
  42370. for (i = 1; i < stackPartitions; i++) {
  42371. phi = Math.PI * i / stackPartitions;
  42372. cosPhi = cos(phi);
  42373. sinPhi = sin(phi);
  42374. for (j = 0; j < subdivisions; j++) {
  42375. positions[index++] = radii.x * cosTheta[j] * sinPhi;
  42376. positions[index++] = radii.y * sinTheta[j] * sinPhi;
  42377. positions[index++] = radii.z * cosPhi;
  42378. }
  42379. }
  42380. cosTheta.length = slicePartitions;
  42381. sinTheta.length = slicePartitions;
  42382. for (i = 0; i < slicePartitions; i++) {
  42383. theta = CesiumMath.TWO_PI * i / slicePartitions;
  42384. cosTheta[i] = cos(theta);
  42385. sinTheta[i] = sin(theta);
  42386. }
  42387. positions[index++] = 0;
  42388. positions[index++] = 0;
  42389. positions[index++] = radii.z;
  42390. for (i = 1; i < subdivisions; i++) {
  42391. phi = Math.PI * i / subdivisions;
  42392. cosPhi = cos(phi);
  42393. sinPhi = sin(phi);
  42394. for (j = 0; j < slicePartitions; j++) {
  42395. positions[index++] = radii.x * cosTheta[j] * sinPhi;
  42396. positions[index++] = radii.y * sinTheta[j] * sinPhi;
  42397. positions[index++] = radii.z * cosPhi;
  42398. }
  42399. }
  42400. positions[index++] = 0;
  42401. positions[index++] = 0;
  42402. positions[index++] = -radii.z;
  42403. index = 0;
  42404. for (i = 0; i < stackPartitions - 1; ++i) {
  42405. var topRowOffset = (i * subdivisions);
  42406. for (j = 0; j < subdivisions - 1; ++j) {
  42407. indices[index++] = topRowOffset + j;
  42408. indices[index++] = topRowOffset + j + 1;
  42409. }
  42410. indices[index++] = topRowOffset + subdivisions - 1;
  42411. indices[index++] = topRowOffset;
  42412. }
  42413. var sliceOffset = subdivisions * (stackPartitions - 1);
  42414. for (j = 1; j < slicePartitions + 1; ++j) {
  42415. indices[index++] = sliceOffset;
  42416. indices[index++] = sliceOffset + j;
  42417. }
  42418. for (i = 0; i < subdivisions - 2; ++i) {
  42419. var topOffset = (i * slicePartitions) + 1 + sliceOffset;
  42420. var bottomOffset = ((i + 1) * slicePartitions) + 1 + sliceOffset;
  42421. for (j = 0; j < slicePartitions - 1; ++j) {
  42422. indices[index++] = bottomOffset + j;
  42423. indices[index++] = topOffset + j;
  42424. }
  42425. indices[index++] = bottomOffset + slicePartitions - 1;
  42426. indices[index++] = topOffset + slicePartitions - 1;
  42427. }
  42428. var lastPosition = positions.length / 3 - 1;
  42429. for (j = lastPosition - 1; j > lastPosition - slicePartitions - 1; --j) {
  42430. indices[index++] = lastPosition;
  42431. indices[index++] = j;
  42432. }
  42433. var attributes = new GeometryAttributes({
  42434. position: new GeometryAttribute({
  42435. componentDatatype : ComponentDatatype.DOUBLE,
  42436. componentsPerAttribute : 3,
  42437. values : positions
  42438. })
  42439. });
  42440. return new Geometry({
  42441. attributes : attributes,
  42442. indices : indices,
  42443. primitiveType : PrimitiveType.LINES,
  42444. boundingSphere : BoundingSphere.fromEllipsoid(ellipsoid)
  42445. });
  42446. };
  42447. return EllipsoidOutlineGeometry;
  42448. });
  42449. /*global define*/
  42450. define('Core/EllipsoidTerrainProvider',[
  42451. '../ThirdParty/when',
  42452. './defaultValue',
  42453. './defined',
  42454. './defineProperties',
  42455. './Ellipsoid',
  42456. './Event',
  42457. './GeographicTilingScheme',
  42458. './HeightmapTerrainData',
  42459. './TerrainProvider'
  42460. ], function(
  42461. when,
  42462. defaultValue,
  42463. defined,
  42464. defineProperties,
  42465. Ellipsoid,
  42466. Event,
  42467. GeographicTilingScheme,
  42468. HeightmapTerrainData,
  42469. TerrainProvider) {
  42470. 'use strict';
  42471. /**
  42472. * A very simple {@link TerrainProvider} that produces geometry by tessellating an ellipsoidal
  42473. * surface.
  42474. *
  42475. * @alias EllipsoidTerrainProvider
  42476. * @constructor
  42477. *
  42478. * @param {Object} [options] Object with the following properties:
  42479. * @param {TilingScheme} [options.tilingScheme] The tiling scheme specifying how the ellipsoidal
  42480. * surface is broken into tiles. If this parameter is not provided, a {@link GeographicTilingScheme}
  42481. * is used.
  42482. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If the tilingScheme is specified,
  42483. * this parameter is ignored and the tiling scheme's ellipsoid is used instead. If neither
  42484. * parameter is specified, the WGS84 ellipsoid is used.
  42485. *
  42486. * @see TerrainProvider
  42487. */
  42488. function EllipsoidTerrainProvider(options) {
  42489. options = defaultValue(options, {});
  42490. this._tilingScheme = options.tilingScheme;
  42491. if (!defined(this._tilingScheme)) {
  42492. this._tilingScheme = new GeographicTilingScheme({
  42493. ellipsoid : defaultValue(options.ellipsoid, Ellipsoid.WGS84)
  42494. });
  42495. }
  42496. // Note: the 64 below does NOT need to match the actual vertex dimensions, because
  42497. // the ellipsoid is significantly smoother than actual terrain.
  42498. this._levelZeroMaximumGeometricError = TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(this._tilingScheme.ellipsoid, 64, this._tilingScheme.getNumberOfXTilesAtLevel(0));
  42499. this._errorEvent = new Event();
  42500. this._readyPromise = when.resolve(true);
  42501. }
  42502. defineProperties(EllipsoidTerrainProvider.prototype, {
  42503. /**
  42504. * Gets an event that is raised when the terrain provider encounters an asynchronous error. By subscribing
  42505. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  42506. * are passed an instance of {@link TileProviderError}.
  42507. * @memberof EllipsoidTerrainProvider.prototype
  42508. * @type {Event}
  42509. */
  42510. errorEvent : {
  42511. get : function() {
  42512. return this._errorEvent;
  42513. }
  42514. },
  42515. /**
  42516. * Gets the credit to display when this terrain provider is active. Typically this is used to credit
  42517. * the source of the terrain. This function should not be called before {@link EllipsoidTerrainProvider#ready} returns true.
  42518. * @memberof EllipsoidTerrainProvider.prototype
  42519. * @type {Credit}
  42520. */
  42521. credit : {
  42522. get : function() {
  42523. return undefined;
  42524. }
  42525. },
  42526. /**
  42527. * Gets the tiling scheme used by this provider. This function should
  42528. * not be called before {@link EllipsoidTerrainProvider#ready} returns true.
  42529. * @memberof EllipsoidTerrainProvider.prototype
  42530. * @type {GeographicTilingScheme}
  42531. */
  42532. tilingScheme : {
  42533. get : function() {
  42534. return this._tilingScheme;
  42535. }
  42536. },
  42537. /**
  42538. * Gets a value indicating whether or not the provider is ready for use.
  42539. * @memberof EllipsoidTerrainProvider.prototype
  42540. * @type {Boolean}
  42541. */
  42542. ready : {
  42543. get : function() {
  42544. return true;
  42545. }
  42546. },
  42547. /**
  42548. * Gets a promise that resolves to true when the provider is ready for use.
  42549. * @memberof EllipsoidTerrainProvider.prototype
  42550. * @type {Promise.<Boolean>}
  42551. * @readonly
  42552. */
  42553. readyPromise : {
  42554. get : function() {
  42555. return this._readyPromise;
  42556. }
  42557. },
  42558. /**
  42559. * Gets a value indicating whether or not the provider includes a water mask. The water mask
  42560. * indicates which areas of the globe are water rather than land, so they can be rendered
  42561. * as a reflective surface with animated waves. This function should not be
  42562. * called before {@link EllipsoidTerrainProvider#ready} returns true.
  42563. * @memberof EllipsoidTerrainProvider.prototype
  42564. * @type {Boolean}
  42565. */
  42566. hasWaterMask : {
  42567. get : function() {
  42568. return false;
  42569. }
  42570. },
  42571. /**
  42572. * Gets a value indicating whether or not the requested tiles include vertex normals.
  42573. * This function should not be called before {@link EllipsoidTerrainProvider#ready} returns true.
  42574. * @memberof EllipsoidTerrainProvider.prototype
  42575. * @type {Boolean}
  42576. */
  42577. hasVertexNormals : {
  42578. get : function() {
  42579. return false;
  42580. }
  42581. }
  42582. });
  42583. /**
  42584. * Requests the geometry for a given tile. This function should not be called before
  42585. * {@link TerrainProvider#ready} returns true. The result includes terrain
  42586. * data and indicates that all child tiles are available.
  42587. *
  42588. * @param {Number} x The X coordinate of the tile for which to request geometry.
  42589. * @param {Number} y The Y coordinate of the tile for which to request geometry.
  42590. * @param {Number} level The level of the tile for which to request geometry.
  42591. * @param {Boolean} [throttleRequests=true] True if the number of simultaneous requests should be limited,
  42592. * or false if the request should be initiated regardless of the number of requests
  42593. * already in progress.
  42594. * @returns {Promise.<TerrainData>|undefined} A promise for the requested geometry. If this method
  42595. * returns undefined instead of a promise, it is an indication that too many requests are already
  42596. * pending and the request will be retried later.
  42597. */
  42598. EllipsoidTerrainProvider.prototype.requestTileGeometry = function(x, y, level, throttleRequests) {
  42599. var width = 16;
  42600. var height = 16;
  42601. return new HeightmapTerrainData({
  42602. buffer : new Uint8Array(width * height),
  42603. width : width,
  42604. height : height
  42605. });
  42606. };
  42607. /**
  42608. * Gets the maximum geometric error allowed in a tile at a given level.
  42609. *
  42610. * @param {Number} level The tile level for which to get the maximum geometric error.
  42611. * @returns {Number} The maximum geometric error.
  42612. */
  42613. EllipsoidTerrainProvider.prototype.getLevelMaximumGeometricError = function(level) {
  42614. return this._levelZeroMaximumGeometricError / (1 << level);
  42615. };
  42616. /**
  42617. * Determines whether data for a tile is available to be loaded.
  42618. *
  42619. * @param {Number} x The X coordinate of the tile for which to request geometry.
  42620. * @param {Number} y The Y coordinate of the tile for which to request geometry.
  42621. * @param {Number} level The level of the tile for which to request geometry.
  42622. * @returns {Boolean} Undefined if not supported, otherwise true or false.
  42623. */
  42624. EllipsoidTerrainProvider.prototype.getTileDataAvailable = function(x, y, level) {
  42625. return undefined;
  42626. };
  42627. return EllipsoidTerrainProvider;
  42628. });
  42629. /*global define*/
  42630. define('Core/EventHelper',[
  42631. './defined',
  42632. './DeveloperError'
  42633. ], function(
  42634. defined,
  42635. DeveloperError) {
  42636. 'use strict';
  42637. /**
  42638. * A convenience object that simplifies the common pattern of attaching event listeners
  42639. * to several events, then removing all those listeners at once later, for example, in
  42640. * a destroy method.
  42641. *
  42642. * @alias EventHelper
  42643. * @constructor
  42644. *
  42645. *
  42646. * @example
  42647. * var helper = new Cesium.EventHelper();
  42648. *
  42649. * helper.add(someObject.event, listener1, this);
  42650. * helper.add(otherObject.event, listener2, this);
  42651. *
  42652. * // later...
  42653. * helper.removeAll();
  42654. *
  42655. * @see Event
  42656. */
  42657. function EventHelper() {
  42658. this._removalFunctions = [];
  42659. }
  42660. /**
  42661. * Adds a listener to an event, and records the registration to be cleaned up later.
  42662. *
  42663. * @param {Event} event The event to attach to.
  42664. * @param {Function} listener The function to be executed when the event is raised.
  42665. * @param {Object} [scope] An optional object scope to serve as the <code>this</code>
  42666. * pointer in which the listener function will execute.
  42667. * @returns {EventHelper~RemoveCallback} A function that will remove this event listener when invoked.
  42668. *
  42669. * @see Event#addEventListener
  42670. */
  42671. EventHelper.prototype.add = function(event, listener, scope) {
  42672. if (!defined(event)) {
  42673. throw new DeveloperError('event is required');
  42674. }
  42675. var removalFunction = event.addEventListener(listener, scope);
  42676. this._removalFunctions.push(removalFunction);
  42677. var that = this;
  42678. return function() {
  42679. removalFunction();
  42680. var removalFunctions = that._removalFunctions;
  42681. removalFunctions.splice(removalFunctions.indexOf(removalFunction), 1);
  42682. };
  42683. };
  42684. /**
  42685. * Unregisters all previously added listeners.
  42686. *
  42687. * @see Event#removeEventListener
  42688. */
  42689. EventHelper.prototype.removeAll = function() {
  42690. var removalFunctions = this._removalFunctions;
  42691. for (var i = 0, len = removalFunctions.length; i < len; ++i) {
  42692. removalFunctions[i]();
  42693. }
  42694. removalFunctions.length = 0;
  42695. };
  42696. /**
  42697. * A function that removes a listener.
  42698. * @callback EventHelper~RemoveCallback
  42699. */
  42700. return EventHelper;
  42701. });
  42702. /*global define*/
  42703. define('Core/ExtrapolationType',[
  42704. './freezeObject'
  42705. ], function(
  42706. freezeObject) {
  42707. 'use strict';
  42708. /**
  42709. * Constants to determine how an interpolated value is extrapolated
  42710. * when querying outside the bounds of available data.
  42711. *
  42712. * @exports ExtrapolationType
  42713. *
  42714. * @see SampledProperty
  42715. */
  42716. var ExtrapolationType = {
  42717. /**
  42718. * No extrapolation occurs.
  42719. *
  42720. * @type {Number}
  42721. * @constant
  42722. */
  42723. NONE : 0,
  42724. /**
  42725. * The first or last value is used when outside the range of sample data.
  42726. *
  42727. * @type {Number}
  42728. * @constant
  42729. */
  42730. HOLD : 1,
  42731. /**
  42732. * The value is extrapolated.
  42733. *
  42734. * @type {Number}
  42735. * @constant
  42736. */
  42737. EXTRAPOLATE : 2
  42738. };
  42739. return freezeObject(ExtrapolationType);
  42740. });
  42741. /*global define*/
  42742. define('Core/GeometryInstanceAttribute',[
  42743. './defaultValue',
  42744. './defined',
  42745. './DeveloperError'
  42746. ], function(
  42747. defaultValue,
  42748. defined,
  42749. DeveloperError) {
  42750. 'use strict';
  42751. /**
  42752. * Values and type information for per-instance geometry attributes.
  42753. *
  42754. * @alias GeometryInstanceAttribute
  42755. * @constructor
  42756. *
  42757. * @param {Object} options Object with the following properties:
  42758. * @param {ComponentDatatype} [options.componentDatatype] The datatype of each component in the attribute, e.g., individual elements in values.
  42759. * @param {Number} [options.componentsPerAttribute] A number between 1 and 4 that defines the number of components in an attributes.
  42760. * @param {Boolean} [options.normalize=false] When <code>true</code> and <code>componentDatatype</code> is an integer format, indicate that the components should be mapped to the range [0, 1] (unsigned) or [-1, 1] (signed) when they are accessed as floating-point for rendering.
  42761. * @param {Number[]} [options.value] The value for the attribute.
  42762. *
  42763. * @exception {DeveloperError} options.componentsPerAttribute must be between 1 and 4.
  42764. *
  42765. *
  42766. * @example
  42767. * var instance = new Cesium.GeometryInstance({
  42768. * geometry : Cesium.BoxGeometry.fromDimensions({
  42769. * dimensions : new Cesium.Cartesian3(1000000.0, 1000000.0, 500000.0)
  42770. * }),
  42771. * modelMatrix : Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(
  42772. * Cesium.Cartesian3.fromDegrees(0.0, 0.0)), new Cesium.Cartesian3(0.0, 0.0, 1000000.0), new Cesium.Matrix4()),
  42773. * id : 'box',
  42774. * attributes : {
  42775. * color : new Cesium.GeometryInstanceAttribute({
  42776. * componentDatatype : Cesium.ComponentDatatype.UNSIGNED_BYTE,
  42777. * componentsPerAttribute : 4,
  42778. * normalize : true,
  42779. * value : [255, 255, 0, 255]
  42780. * })
  42781. * }
  42782. * });
  42783. *
  42784. * @see ColorGeometryInstanceAttribute
  42785. * @see ShowGeometryInstanceAttribute
  42786. * @see DistanceDisplayConditionGeometryInstanceAttribute
  42787. */
  42788. function GeometryInstanceAttribute(options) {
  42789. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  42790. if (!defined(options.componentDatatype)) {
  42791. throw new DeveloperError('options.componentDatatype is required.');
  42792. }
  42793. if (!defined(options.componentsPerAttribute)) {
  42794. throw new DeveloperError('options.componentsPerAttribute is required.');
  42795. }
  42796. if (options.componentsPerAttribute < 1 || options.componentsPerAttribute > 4) {
  42797. throw new DeveloperError('options.componentsPerAttribute must be between 1 and 4.');
  42798. }
  42799. if (!defined(options.value)) {
  42800. throw new DeveloperError('options.value is required.');
  42801. }
  42802. /**
  42803. * The datatype of each component in the attribute, e.g., individual elements in
  42804. * {@link GeometryInstanceAttribute#value}.
  42805. *
  42806. * @type ComponentDatatype
  42807. *
  42808. * @default undefined
  42809. */
  42810. this.componentDatatype = options.componentDatatype;
  42811. /**
  42812. * A number between 1 and 4 that defines the number of components in an attributes.
  42813. * For example, a position attribute with x, y, and z components would have 3 as
  42814. * shown in the code example.
  42815. *
  42816. * @type Number
  42817. *
  42818. * @default undefined
  42819. *
  42820. * @example
  42821. * show : new Cesium.GeometryInstanceAttribute({
  42822. * componentDatatype : Cesium.ComponentDatatype.UNSIGNED_BYTE,
  42823. * componentsPerAttribute : 1,
  42824. * normalize : true,
  42825. * value : [1.0]
  42826. * })
  42827. */
  42828. this.componentsPerAttribute = options.componentsPerAttribute;
  42829. /**
  42830. * When <code>true</code> and <code>componentDatatype</code> is an integer format,
  42831. * indicate that the components should be mapped to the range [0, 1] (unsigned)
  42832. * or [-1, 1] (signed) when they are accessed as floating-point for rendering.
  42833. * <p>
  42834. * This is commonly used when storing colors using {@link ComponentDatatype.UNSIGNED_BYTE}.
  42835. * </p>
  42836. *
  42837. * @type Boolean
  42838. *
  42839. * @default false
  42840. *
  42841. * @example
  42842. * attribute.componentDatatype = Cesium.ComponentDatatype.UNSIGNED_BYTE;
  42843. * attribute.componentsPerAttribute = 4;
  42844. * attribute.normalize = true;
  42845. * attribute.value = [
  42846. * Cesium.Color.floatToByte(color.red),
  42847. * Cesium.Color.floatToByte(color.green),
  42848. * Cesium.Color.floatToByte(color.blue),
  42849. * Cesium.Color.floatToByte(color.alpha)
  42850. * ];
  42851. */
  42852. this.normalize = defaultValue(options.normalize, false);
  42853. /**
  42854. * The values for the attributes stored in a typed array. In the code example,
  42855. * every three elements in <code>values</code> defines one attributes since
  42856. * <code>componentsPerAttribute</code> is 3.
  42857. *
  42858. * @type {Number[]}
  42859. *
  42860. * @default undefined
  42861. *
  42862. * @example
  42863. * show : new Cesium.GeometryInstanceAttribute({
  42864. * componentDatatype : Cesium.ComponentDatatype.UNSIGNED_BYTE,
  42865. * componentsPerAttribute : 1,
  42866. * normalize : true,
  42867. * value : [1.0]
  42868. * })
  42869. */
  42870. this.value = options.value;
  42871. }
  42872. return GeometryInstanceAttribute;
  42873. });
  42874. /*global define*/
  42875. define('Core/getBaseUri',[
  42876. '../ThirdParty/Uri',
  42877. './defined',
  42878. './DeveloperError'
  42879. ], function(
  42880. Uri,
  42881. defined,
  42882. DeveloperError) {
  42883. 'use strict';
  42884. /**
  42885. * Given a URI, returns the base path of the URI.
  42886. * @exports getBaseUri
  42887. *
  42888. * @param {String} uri The Uri.
  42889. * @param {Boolean} [includeQuery = false] Whether or not to include the query string and fragment form the uri
  42890. * @returns {String} The base path of the Uri.
  42891. *
  42892. * @example
  42893. * // basePath will be "/Gallery/";
  42894. * var basePath = Cesium.getBaseUri('/Gallery/simple.czml?value=true&example=false');
  42895. *
  42896. * // basePath will be "/Gallery/?value=true&example=false";
  42897. * var basePath = Cesium.getBaseUri('/Gallery/simple.czml?value=true&example=false', true);
  42898. */
  42899. function getBaseUri(uri, includeQuery) {
  42900. if (!defined(uri)) {
  42901. throw new DeveloperError('uri is required.');
  42902. }
  42903. var basePath = '';
  42904. var i = uri.lastIndexOf('/');
  42905. if (i !== -1) {
  42906. basePath = uri.substring(0, i + 1);
  42907. }
  42908. if (!includeQuery) {
  42909. return basePath;
  42910. }
  42911. uri = new Uri(uri);
  42912. if (defined(uri.query)) {
  42913. basePath += '?' + uri.query;
  42914. }
  42915. if (defined(uri.fragment)){
  42916. basePath += '#' + uri.fragment;
  42917. }
  42918. return basePath;
  42919. }
  42920. return getBaseUri;
  42921. });
  42922. /*global define*/
  42923. define('Core/getExtensionFromUri',[
  42924. '../ThirdParty/Uri',
  42925. './defined',
  42926. './DeveloperError'
  42927. ], function(
  42928. Uri,
  42929. defined,
  42930. DeveloperError) {
  42931. 'use strict';
  42932. /**
  42933. * Given a URI, returns the extension of the URI.
  42934. * @exports getExtensionFromUri
  42935. *
  42936. * @param {String} uri The Uri.
  42937. * @returns {String} The extension of the Uri.
  42938. *
  42939. * @example
  42940. * //extension will be "czml";
  42941. * var extension = Cesium.getExtensionFromUri('/Gallery/simple.czml?value=true&example=false');
  42942. */
  42943. function getExtensionFromUri(uri) {
  42944. if (!defined(uri)) {
  42945. throw new DeveloperError('uri is required.');
  42946. }
  42947. var uriObject = new Uri(uri);
  42948. uriObject.normalize();
  42949. var path = uriObject.path;
  42950. var index = path.lastIndexOf('/');
  42951. if (index !== -1) {
  42952. path = path.substr(index + 1);
  42953. }
  42954. index = path.lastIndexOf('.');
  42955. if (index === -1) {
  42956. path = '';
  42957. } else {
  42958. path = path.substr(index + 1);
  42959. }
  42960. return path;
  42961. }
  42962. return getExtensionFromUri;
  42963. });
  42964. /*global define*/
  42965. define('Core/getFilenameFromUri',[
  42966. '../ThirdParty/Uri',
  42967. './defined',
  42968. './DeveloperError'
  42969. ], function(
  42970. Uri,
  42971. defined,
  42972. DeveloperError) {
  42973. 'use strict';
  42974. /**
  42975. * Given a URI, returns the last segment of the URI, removing any path or query information.
  42976. * @exports getFilenameFromUri
  42977. *
  42978. * @param {String} uri The Uri.
  42979. * @returns {String} The last segment of the Uri.
  42980. *
  42981. * @example
  42982. * //fileName will be"simple.czml";
  42983. * var fileName = Cesium.getFilenameFromUri('/Gallery/simple.czml?value=true&example=false');
  42984. */
  42985. function getFilenameFromUri(uri) {
  42986. if (!defined(uri)) {
  42987. throw new DeveloperError('uri is required.');
  42988. }
  42989. var uriObject = new Uri(uri);
  42990. uriObject.normalize();
  42991. var path = uriObject.path;
  42992. var index = path.lastIndexOf('/');
  42993. if (index !== -1) {
  42994. path = path.substr(index + 1);
  42995. }
  42996. return path;
  42997. }
  42998. return getFilenameFromUri;
  42999. });
  43000. /*global define*/
  43001. define('Core/getStringFromTypedArray',[
  43002. './defaultValue',
  43003. './defined',
  43004. './DeveloperError'
  43005. ], function(
  43006. defaultValue,
  43007. defined,
  43008. DeveloperError) {
  43009. 'use strict';
  43010. /*global TextDecoder*/
  43011. /**
  43012. * @private
  43013. */
  43014. function getStringFromTypedArray(uint8Array, byteOffset, byteLength) {
  43015. if (!defined(uint8Array)) {
  43016. throw new DeveloperError('uint8Array is required.');
  43017. }
  43018. if (byteOffset < 0) {
  43019. throw new DeveloperError('byteOffset cannot be negative.');
  43020. }
  43021. if (byteLength < 0) {
  43022. throw new DeveloperError('byteLength cannot be negative.');
  43023. }
  43024. if ((byteOffset + byteLength) > uint8Array.byteLength) {
  43025. throw new DeveloperError('sub-region exceeds array bounds.');
  43026. }
  43027. byteOffset = defaultValue(byteOffset, 0);
  43028. byteLength = defaultValue(byteLength, uint8Array.byteLength - byteOffset);
  43029. uint8Array = uint8Array.subarray(byteOffset, byteOffset + byteLength);
  43030. return getStringFromTypedArray.decode(uint8Array);
  43031. }
  43032. // Exposed functions for testing
  43033. getStringFromTypedArray.decodeWithTextDecoder = function(view) {
  43034. var decoder = new TextDecoder('utf-8');
  43035. return decoder.decode(view);
  43036. };
  43037. getStringFromTypedArray.decodeWithFromCharCode = function(view) {
  43038. var result = '';
  43039. var length = view.length;
  43040. // Convert one character at a time to avoid stack overflow on iPad.
  43041. //
  43042. // fromCharCode will not handle all legal Unicode values (up to 21 bits). See
  43043. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCharCode
  43044. for (var i = 0; i < length; ++i) {
  43045. result += String.fromCharCode(view[i]);
  43046. }
  43047. return result;
  43048. };
  43049. if (typeof TextDecoder !== 'undefined') {
  43050. getStringFromTypedArray.decode = getStringFromTypedArray.decodeWithTextDecoder;
  43051. } else {
  43052. getStringFromTypedArray.decode = getStringFromTypedArray.decodeWithFromCharCode;
  43053. }
  43054. return getStringFromTypedArray;
  43055. });
  43056. /*global define*/
  43057. define('Core/getMagic',[
  43058. './defaultValue',
  43059. './getStringFromTypedArray'
  43060. ], function(
  43061. defaultValue,
  43062. getStringFromTypedArray) {
  43063. 'use strict';
  43064. /**
  43065. * @private
  43066. */
  43067. function getMagic(uint8Array, byteOffset) {
  43068. byteOffset = defaultValue(byteOffset, 0);
  43069. return getStringFromTypedArray(uint8Array, byteOffset, Math.min(4, uint8Array.length));
  43070. }
  43071. return getMagic;
  43072. });
  43073. /*global define*/
  43074. define('Core/HeadingPitchRange',[
  43075. './defaultValue',
  43076. './defined'
  43077. ], function(
  43078. defaultValue,
  43079. defined) {
  43080. 'use strict';
  43081. /**
  43082. * Defines a heading angle, pitch angle, and range in a local frame.
  43083. * Heading is the rotation from the local north direction where a positive angle is increasing eastward.
  43084. * Pitch is the rotation from the local xy-plane. Positive pitch angles are above the plane. Negative pitch
  43085. * angles are below the plane. Range is the distance from the center of the frame.
  43086. * @alias HeadingPitchRange
  43087. * @constructor
  43088. *
  43089. * @param {Number} [heading=0.0] The heading angle in radians.
  43090. * @param {Number} [pitch=0.0] The pitch angle in radians.
  43091. * @param {Number} [range=0.0] The distance from the center in meters.
  43092. */
  43093. function HeadingPitchRange(heading, pitch, range) {
  43094. /**
  43095. * Heading is the rotation from the local north direction where a positive angle is increasing eastward.
  43096. * @type {Number}
  43097. */
  43098. this.heading = defaultValue(heading, 0.0);
  43099. /**
  43100. * Pitch is the rotation from the local xy-plane. Positive pitch angles
  43101. * are above the plane. Negative pitch angles are below the plane.
  43102. * @type {Number}
  43103. */
  43104. this.pitch = defaultValue(pitch, 0.0);
  43105. /**
  43106. * Range is the distance from the center of the local frame.
  43107. * @type {Number}
  43108. */
  43109. this.range = defaultValue(range, 0.0);
  43110. }
  43111. /**
  43112. * Duplicates a HeadingPitchRange instance.
  43113. *
  43114. * @param {HeadingPitchRange} hpr The HeadingPitchRange to duplicate.
  43115. * @param {HeadingPitchRange} [result] The object onto which to store the result.
  43116. * @returns {HeadingPitchRange} The modified result parameter or a new HeadingPitchRange instance if one was not provided. (Returns undefined if hpr is undefined)
  43117. */
  43118. HeadingPitchRange.clone = function(hpr, result) {
  43119. if (!defined(hpr)) {
  43120. return undefined;
  43121. }
  43122. if (!defined(result)) {
  43123. result = new HeadingPitchRange();
  43124. }
  43125. result.heading = hpr.heading;
  43126. result.pitch = hpr.pitch;
  43127. result.range = hpr.range;
  43128. return result;
  43129. };
  43130. return HeadingPitchRange;
  43131. });
  43132. /*global define*/
  43133. define('Core/HermitePolynomialApproximation',[
  43134. './defaultValue',
  43135. './defined',
  43136. './DeveloperError',
  43137. './Math'
  43138. ], function(
  43139. defaultValue,
  43140. defined,
  43141. DeveloperError,
  43142. CesiumMath) {
  43143. 'use strict';
  43144. var factorial = CesiumMath.factorial;
  43145. function calculateCoefficientTerm(x, zIndices, xTable, derivOrder, termOrder, reservedIndices) {
  43146. var result = 0;
  43147. var reserved;
  43148. var i;
  43149. var j;
  43150. if (derivOrder > 0) {
  43151. for (i = 0; i < termOrder; i++) {
  43152. reserved = false;
  43153. for (j = 0; j < reservedIndices.length && !reserved; j++) {
  43154. if (i === reservedIndices[j]) {
  43155. reserved = true;
  43156. }
  43157. }
  43158. if (!reserved) {
  43159. reservedIndices.push(i);
  43160. result += calculateCoefficientTerm(x, zIndices, xTable, derivOrder - 1, termOrder, reservedIndices);
  43161. reservedIndices.splice(reservedIndices.length - 1, 1);
  43162. }
  43163. }
  43164. return result;
  43165. }
  43166. result = 1;
  43167. for (i = 0; i < termOrder; i++) {
  43168. reserved = false;
  43169. for (j = 0; j < reservedIndices.length && !reserved; j++) {
  43170. if (i === reservedIndices[j]) {
  43171. reserved = true;
  43172. }
  43173. }
  43174. if (!reserved) {
  43175. result *= x - xTable[zIndices[i]];
  43176. }
  43177. }
  43178. return result;
  43179. }
  43180. /**
  43181. * An {@link InterpolationAlgorithm} for performing Hermite interpolation.
  43182. *
  43183. * @exports HermitePolynomialApproximation
  43184. */
  43185. var HermitePolynomialApproximation = {
  43186. type : 'Hermite'
  43187. };
  43188. /**
  43189. * Given the desired degree, returns the number of data points required for interpolation.
  43190. *
  43191. * @param {Number} degree The desired degree of interpolation.
  43192. * @param {Number} [inputOrder=0] The order of the inputs (0 means just the data, 1 means the data and its derivative, etc).
  43193. * @returns {Number} The number of required data points needed for the desired degree of interpolation.
  43194. * @exception {DeveloperError} degree must be 0 or greater.
  43195. * @exception {DeveloperError} inputOrder must be 0 or greater.
  43196. */
  43197. HermitePolynomialApproximation.getRequiredDataPoints = function(degree, inputOrder) {
  43198. inputOrder = defaultValue(inputOrder, 0);
  43199. if (!defined(degree)) {
  43200. throw new DeveloperError('degree is required.');
  43201. }
  43202. if (degree < 0) {
  43203. throw new DeveloperError('degree must be 0 or greater.');
  43204. }
  43205. if (inputOrder < 0) {
  43206. throw new DeveloperError('inputOrder must be 0 or greater.');
  43207. }
  43208. return Math.max(Math.floor((degree + 1) / (inputOrder + 1)), 2);
  43209. };
  43210. /**
  43211. * Interpolates values using Hermite Polynomial Approximation.
  43212. *
  43213. * @param {Number} x The independent variable for which the dependent variables will be interpolated.
  43214. * @param {Number[]} xTable The array of independent variables to use to interpolate. The values
  43215. * in this array must be in increasing order and the same value must not occur twice in the array.
  43216. * @param {Number[]} yTable The array of dependent variables to use to interpolate. For a set of three
  43217. * dependent values (p,q,w) at time 1 and time 2 this should be as follows: {p1, q1, w1, p2, q2, w2}.
  43218. * @param {Number} yStride The number of dependent variable values in yTable corresponding to
  43219. * each independent variable value in xTable.
  43220. * @param {Number[]} [result] An existing array into which to store the result.
  43221. * @returns {Number[]} The array of interpolated values, or the result parameter if one was provided.
  43222. */
  43223. HermitePolynomialApproximation.interpolateOrderZero = function(x, xTable, yTable, yStride, result) {
  43224. if (!defined(result)) {
  43225. result = new Array(yStride);
  43226. }
  43227. var i;
  43228. var j;
  43229. var d;
  43230. var s;
  43231. var len;
  43232. var index;
  43233. var length = xTable.length;
  43234. var coefficients = new Array(yStride);
  43235. for (i = 0; i < yStride; i++) {
  43236. result[i] = 0;
  43237. var l = new Array(length);
  43238. coefficients[i] = l;
  43239. for (j = 0; j < length; j++) {
  43240. l[j] = [];
  43241. }
  43242. }
  43243. var zIndicesLength = length, zIndices = new Array(zIndicesLength);
  43244. for (i = 0; i < zIndicesLength; i++) {
  43245. zIndices[i] = i;
  43246. }
  43247. var highestNonZeroCoef = length - 1;
  43248. for (s = 0; s < yStride; s++) {
  43249. for (j = 0; j < zIndicesLength; j++) {
  43250. index = zIndices[j] * yStride + s;
  43251. coefficients[s][0].push(yTable[index]);
  43252. }
  43253. for (i = 1; i < zIndicesLength; i++) {
  43254. var nonZeroCoefficients = false;
  43255. for (j = 0; j < zIndicesLength - i; j++) {
  43256. var zj = xTable[zIndices[j]];
  43257. var zn = xTable[zIndices[j + i]];
  43258. var numerator;
  43259. if (zn - zj <= 0) {
  43260. index = zIndices[j] * yStride + yStride * i + s;
  43261. numerator = yTable[index];
  43262. coefficients[s][i].push(numerator / factorial(i));
  43263. } else {
  43264. numerator = (coefficients[s][i - 1][j + 1] - coefficients[s][i - 1][j]);
  43265. coefficients[s][i].push(numerator / (zn - zj));
  43266. }
  43267. nonZeroCoefficients = nonZeroCoefficients || (numerator !== 0);
  43268. }
  43269. if (!nonZeroCoefficients) {
  43270. highestNonZeroCoef = i - 1;
  43271. }
  43272. }
  43273. }
  43274. for (d = 0, len = 0; d <= len; d++) {
  43275. for (i = d; i <= highestNonZeroCoef; i++) {
  43276. var tempTerm = calculateCoefficientTerm(x, zIndices, xTable, d, i, []);
  43277. for (s = 0; s < yStride; s++) {
  43278. var coeff = coefficients[s][i][0];
  43279. result[s + d * yStride] += coeff * tempTerm;
  43280. }
  43281. }
  43282. }
  43283. return result;
  43284. };
  43285. var arrayScratch = [];
  43286. /**
  43287. * Interpolates values using Hermite Polynomial Approximation.
  43288. *
  43289. * @param {Number} x The independent variable for which the dependent variables will be interpolated.
  43290. * @param {Number[]} xTable The array of independent variables to use to interpolate. The values
  43291. * in this array must be in increasing order and the same value must not occur twice in the array.
  43292. * @param {Number[]} yTable The array of dependent variables to use to interpolate. For a set of three
  43293. * dependent values (p,q,w) at time 1 and time 2 this should be as follows: {p1, q1, w1, p2, q2, w2}.
  43294. * @param {Number} yStride The number of dependent variable values in yTable corresponding to
  43295. * each independent variable value in xTable.
  43296. * @param {Number} inputOrder The number of derivatives supplied for input.
  43297. * @param {Number} outputOrder The number of derivatives desired for output.
  43298. * @param {Number[]} [result] An existing array into which to store the result.
  43299. *
  43300. * @returns {Number[]} The array of interpolated values, or the result parameter if one was provided.
  43301. */
  43302. HermitePolynomialApproximation.interpolate = function(x, xTable, yTable, yStride, inputOrder, outputOrder, result) {
  43303. var resultLength = yStride * (outputOrder + 1);
  43304. if (!defined(result)) {
  43305. result = new Array(resultLength);
  43306. }
  43307. for (var r = 0; r < resultLength; r++) {
  43308. result[r] = 0;
  43309. }
  43310. var length = xTable.length;
  43311. // The zIndices array holds copies of the addresses of the xTable values
  43312. // in the range we're looking at. Even though this just holds information already
  43313. // available in xTable this is a much more convenient format.
  43314. var zIndices = new Array(length * (inputOrder + 1));
  43315. for (var i = 0; i < length; i++) {
  43316. for (var j = 0; j < (inputOrder + 1); j++) {
  43317. zIndices[i * (inputOrder + 1) + j] = i;
  43318. }
  43319. }
  43320. var zIndiceslength = zIndices.length;
  43321. var coefficients = arrayScratch;
  43322. var highestNonZeroCoef = fillCoefficientList(coefficients, zIndices, xTable, yTable, yStride, inputOrder);
  43323. var reservedIndices = [];
  43324. var tmp = zIndiceslength * (zIndiceslength + 1) / 2;
  43325. var loopStop = Math.min(highestNonZeroCoef, outputOrder);
  43326. for (var d = 0; d <= loopStop; d++) {
  43327. for (i = d; i <= highestNonZeroCoef; i++) {
  43328. reservedIndices.length = 0;
  43329. var tempTerm = calculateCoefficientTerm(x, zIndices, xTable, d, i, reservedIndices);
  43330. var dimTwo = Math.floor(i * (1 - i) / 2) + (zIndiceslength * i);
  43331. for (var s = 0; s < yStride; s++) {
  43332. var dimOne = Math.floor(s * tmp);
  43333. var coef = coefficients[dimOne + dimTwo];
  43334. result[s + d * yStride] += coef * tempTerm;
  43335. }
  43336. }
  43337. }
  43338. return result;
  43339. };
  43340. function fillCoefficientList(coefficients, zIndices, xTable, yTable, yStride, inputOrder) {
  43341. var j;
  43342. var index;
  43343. var highestNonZero = -1;
  43344. var zIndiceslength = zIndices.length;
  43345. var tmp = zIndiceslength * (zIndiceslength + 1) / 2;
  43346. for (var s = 0; s < yStride; s++) {
  43347. var dimOne = Math.floor(s * tmp);
  43348. for (j = 0; j < zIndiceslength; j++) {
  43349. index = zIndices[j] * yStride * (inputOrder + 1) + s;
  43350. coefficients[dimOne + j] = yTable[index];
  43351. }
  43352. for (var i = 1; i < zIndiceslength; i++) {
  43353. var coefIndex = 0;
  43354. var dimTwo = Math.floor(i * (1 - i) / 2) + (zIndiceslength * i);
  43355. var nonZeroCoefficients = false;
  43356. for (j = 0; j < zIndiceslength - i; j++) {
  43357. var zj = xTable[zIndices[j]];
  43358. var zn = xTable[zIndices[j + i]];
  43359. var numerator;
  43360. var coefficient;
  43361. if (zn - zj <= 0) {
  43362. index = zIndices[j] * yStride * (inputOrder + 1) + yStride * i + s;
  43363. numerator = yTable[index];
  43364. coefficient = (numerator / CesiumMath.factorial(i));
  43365. coefficients[dimOne + dimTwo + coefIndex] = coefficient;
  43366. coefIndex++;
  43367. } else {
  43368. var dimTwoMinusOne = Math.floor((i - 1) * (2 - i) / 2) + (zIndiceslength * (i - 1));
  43369. numerator = coefficients[dimOne + dimTwoMinusOne + j + 1] - coefficients[dimOne + dimTwoMinusOne + j];
  43370. coefficient = (numerator / (zn - zj));
  43371. coefficients[dimOne + dimTwo + coefIndex] = coefficient;
  43372. coefIndex++;
  43373. }
  43374. nonZeroCoefficients = nonZeroCoefficients || (numerator !== 0.0);
  43375. }
  43376. if (nonZeroCoefficients) {
  43377. highestNonZero = Math.max(highestNonZero, i);
  43378. }
  43379. }
  43380. }
  43381. return highestNonZero;
  43382. }
  43383. return HermitePolynomialApproximation;
  43384. });
  43385. /*global define*/
  43386. define('Core/IauOrientationParameters',[],function() {
  43387. 'use strict';
  43388. /**
  43389. * A structure containing the orientation data computed at a particular time. The data
  43390. * represents the direction of the pole of rotation and the rotation about that pole.
  43391. * <p>
  43392. * These parameters correspond to the parameters in the Report from the IAU/IAG Working Group
  43393. * except that they are expressed in radians.
  43394. * </p>
  43395. *
  43396. * @exports IauOrientationParameters
  43397. *
  43398. * @private
  43399. */
  43400. function IauOrientationParameters(rightAscension, declination, rotation, rotationRate) {
  43401. /**
  43402. * The right ascension of the north pole of the body with respect to
  43403. * the International Celestial Reference Frame, in radians.
  43404. * @type {Number}
  43405. *
  43406. * @private
  43407. */
  43408. this.rightAscension = rightAscension;
  43409. /**
  43410. * The declination of the north pole of the body with respect to
  43411. * the International Celestial Reference Frame, in radians.
  43412. * @type {Number}
  43413. *
  43414. * @private
  43415. */
  43416. this.declination = declination;
  43417. /**
  43418. * The rotation about the north pole used to align a set of axes with
  43419. * the meridian defined by the IAU report, in radians.
  43420. * @type {Number}
  43421. *
  43422. * @private
  43423. */
  43424. this.rotation = rotation;
  43425. /**
  43426. * The instantaneous rotation rate about the north pole, in radians per second.
  43427. * @type {Number}
  43428. *
  43429. * @private
  43430. */
  43431. this.rotationRate = rotationRate;
  43432. }
  43433. return IauOrientationParameters;
  43434. });
  43435. /*global define*/
  43436. define('Core/Iau2000Orientation',[
  43437. './defined',
  43438. './IauOrientationParameters',
  43439. './JulianDate',
  43440. './Math',
  43441. './TimeConstants'
  43442. ], function(
  43443. defined,
  43444. IauOrientationParameters,
  43445. JulianDate,
  43446. CesiumMath,
  43447. TimeConstants) {
  43448. 'use strict';
  43449. /**
  43450. * This is a collection of the orientation information available for central bodies.
  43451. * The data comes from the Report of the IAU/IAG Working Group on Cartographic
  43452. * Coordinates and Rotational Elements: 2000.
  43453. *
  43454. * @exports Iau2000Orientation
  43455. *
  43456. * @private
  43457. */
  43458. var Iau2000Orientation = {};
  43459. var TdtMinusTai = 32.184;
  43460. var J2000d = 2451545.0;
  43461. var c1 = -0.0529921;
  43462. var c2 = -0.1059842;
  43463. var c3 = 13.0120009;
  43464. var c4 = 13.3407154;
  43465. var c5 = 0.9856003;
  43466. var c6 = 26.4057084;
  43467. var c7 = 13.0649930;
  43468. var c8 = 0.3287146;
  43469. var c9 = 1.7484877;
  43470. var c10 = -0.1589763;
  43471. var c11 = 0.0036096;
  43472. var c12 = 0.1643573;
  43473. var c13 = 12.9590088;
  43474. var dateTT = new JulianDate();
  43475. /**
  43476. * Compute the orientation parameters for the Moon.
  43477. *
  43478. * @param {JulianDate} [date=JulianDate.now()] The date to evaluate the parameters.
  43479. * @param {IauOrientationParameters} [result] The object onto which to store the result.
  43480. * @returns {IauOrientationParameters} The modified result parameter or a new instance representing the orientation of the Earth's Moon.
  43481. */
  43482. Iau2000Orientation.ComputeMoon = function(date, result) {
  43483. if (!defined(date)) {
  43484. date = JulianDate.now();
  43485. }
  43486. dateTT = JulianDate.addSeconds(date, TdtMinusTai, dateTT);
  43487. var d = JulianDate.totalDays(dateTT) - J2000d;
  43488. var T = d / TimeConstants.DAYS_PER_JULIAN_CENTURY;
  43489. var E1 = (125.045 + c1 * d) * CesiumMath.RADIANS_PER_DEGREE;
  43490. var E2 = (250.089 + c2 * d) * CesiumMath.RADIANS_PER_DEGREE;
  43491. var E3 = (260.008 + c3 * d) * CesiumMath.RADIANS_PER_DEGREE;
  43492. var E4 = (176.625 + c4 * d) * CesiumMath.RADIANS_PER_DEGREE;
  43493. var E5 = (357.529 + c5 * d) * CesiumMath.RADIANS_PER_DEGREE;
  43494. var E6 = (311.589 + c6 * d) * CesiumMath.RADIANS_PER_DEGREE;
  43495. var E7 = (134.963 + c7 * d) * CesiumMath.RADIANS_PER_DEGREE;
  43496. var E8 = (276.617 + c8 * d) * CesiumMath.RADIANS_PER_DEGREE;
  43497. var E9 = (34.226 + c9 * d) * CesiumMath.RADIANS_PER_DEGREE;
  43498. var E10 = (15.134 + c10 * d) * CesiumMath.RADIANS_PER_DEGREE;
  43499. var E11 = (119.743 + c11 * d) * CesiumMath.RADIANS_PER_DEGREE;
  43500. var E12 = (239.961 + c12 * d) * CesiumMath.RADIANS_PER_DEGREE;
  43501. var E13 = (25.053 + c13 * d) * CesiumMath.RADIANS_PER_DEGREE;
  43502. var sinE1 = Math.sin(E1);
  43503. var sinE2 = Math.sin(E2);
  43504. var sinE3 = Math.sin(E3);
  43505. var sinE4 = Math.sin(E4);
  43506. var sinE5 = Math.sin(E5);
  43507. var sinE6 = Math.sin(E6);
  43508. var sinE7 = Math.sin(E7);
  43509. var sinE8 = Math.sin(E8);
  43510. var sinE9 = Math.sin(E9);
  43511. var sinE10 = Math.sin(E10);
  43512. var sinE11 = Math.sin(E11);
  43513. var sinE12 = Math.sin(E12);
  43514. var sinE13 = Math.sin(E13);
  43515. var cosE1 = Math.cos(E1);
  43516. var cosE2 = Math.cos(E2);
  43517. var cosE3 = Math.cos(E3);
  43518. var cosE4 = Math.cos(E4);
  43519. var cosE5 = Math.cos(E5);
  43520. var cosE6 = Math.cos(E6);
  43521. var cosE7 = Math.cos(E7);
  43522. var cosE8 = Math.cos(E8);
  43523. var cosE9 = Math.cos(E9);
  43524. var cosE10 = Math.cos(E10);
  43525. var cosE11 = Math.cos(E11);
  43526. var cosE12 = Math.cos(E12);
  43527. var cosE13 = Math.cos(E13);
  43528. var rightAscension = (269.9949 + 0.0031 * T - 3.8787 * sinE1 - 0.1204 * sinE2 +
  43529. 0.0700 * sinE3 - 0.0172 * sinE4 + 0.0072 * sinE6 -
  43530. 0.0052 * sinE10 + 0.0043 * sinE13) *
  43531. CesiumMath.RADIANS_PER_DEGREE;
  43532. var declination = (66.5392 + 0.013 * T + 1.5419 * cosE1 + 0.0239 * cosE2 -
  43533. 0.0278 * cosE3 + 0.0068 * cosE4 - 0.0029 * cosE6 +
  43534. 0.0009 * cosE7 + 0.0008 * cosE10 - 0.0009 * cosE13) *
  43535. CesiumMath.RADIANS_PER_DEGREE;
  43536. var rotation = (38.3213 + 13.17635815 * d - 1.4e-12 * d * d + 3.5610 * sinE1 +
  43537. 0.1208 * sinE2 - 0.0642 * sinE3 + 0.0158 * sinE4 +
  43538. 0.0252 * sinE5 - 0.0066 * sinE6 - 0.0047 * sinE7 -
  43539. 0.0046 * sinE8 + 0.0028 * sinE9 + 0.0052 * sinE10 +
  43540. 0.004 * sinE11 + 0.0019 * sinE12 - 0.0044 * sinE13) *
  43541. CesiumMath.RADIANS_PER_DEGREE;
  43542. var rotationRate = ((13.17635815 - 1.4e-12 * (2.0 * d)) +
  43543. 3.5610 * cosE1 * c1 +
  43544. 0.1208 * cosE2*c2 - 0.0642 * cosE3*c3 + 0.0158 * cosE4*c4 +
  43545. 0.0252 * cosE5*c5 - 0.0066 * cosE6*c6 - 0.0047 * cosE7*c7 -
  43546. 0.0046 * cosE8*c8 + 0.0028 * cosE9*c9 + 0.0052 * cosE10*c10 +
  43547. 0.004 * cosE11*c11 + 0.0019 * cosE12*c12 - 0.0044 * cosE13*c13) /
  43548. 86400.0 * CesiumMath.RADIANS_PER_DEGREE;
  43549. if (!defined(result)) {
  43550. result = new IauOrientationParameters();
  43551. }
  43552. result.rightAscension = rightAscension;
  43553. result.declination = declination;
  43554. result.rotation = rotation;
  43555. result.rotationRate = rotationRate;
  43556. return result;
  43557. };
  43558. return Iau2000Orientation;
  43559. });
  43560. /*global define*/
  43561. define('Core/IauOrientationAxes',[
  43562. './Cartesian3',
  43563. './defined',
  43564. './Iau2000Orientation',
  43565. './JulianDate',
  43566. './Math',
  43567. './Matrix3',
  43568. './Quaternion'
  43569. ], function(
  43570. Cartesian3,
  43571. defined,
  43572. Iau2000Orientation,
  43573. JulianDate,
  43574. CesiumMath,
  43575. Matrix3,
  43576. Quaternion) {
  43577. 'use strict';
  43578. /**
  43579. * The Axes representing the orientation of a Globe as represented by the data
  43580. * from the IAU/IAG Working Group reports on rotational elements.
  43581. * @alias IauOrientationAxes
  43582. * @constructor
  43583. *
  43584. * @param {IauOrientationAxes~ComputeFunction} [computeFunction] The function that computes the {@link IauOrientationParameters} given a {@link JulianDate}.
  43585. *
  43586. * @see Iau2000Orientation
  43587. *
  43588. * @private
  43589. */
  43590. function IauOrientationAxes(computeFunction) {
  43591. if (!defined(computeFunction) || typeof computeFunction !== 'function') {
  43592. computeFunction = Iau2000Orientation.ComputeMoon;
  43593. }
  43594. this._computeFunction = computeFunction;
  43595. }
  43596. var xAxisScratch = new Cartesian3();
  43597. var yAxisScratch = new Cartesian3();
  43598. var zAxisScratch = new Cartesian3();
  43599. function computeRotationMatrix(alpha, delta, result) {
  43600. var xAxis = xAxisScratch;
  43601. xAxis.x = Math.cos(alpha + CesiumMath.PI_OVER_TWO);
  43602. xAxis.y = Math.sin(alpha + CesiumMath.PI_OVER_TWO);
  43603. xAxis.z = 0.0;
  43604. var cosDec = Math.cos(delta);
  43605. var zAxis = zAxisScratch;
  43606. zAxis.x = cosDec * Math.cos(alpha);
  43607. zAxis.y = cosDec * Math.sin(alpha);
  43608. zAxis.z = Math.sin(delta);
  43609. var yAxis = Cartesian3.cross(zAxis, xAxis, yAxisScratch);
  43610. if (!defined(result)) {
  43611. result = new Matrix3();
  43612. }
  43613. result[0] = xAxis.x;
  43614. result[1] = yAxis.x;
  43615. result[2] = zAxis.x;
  43616. result[3] = xAxis.y;
  43617. result[4] = yAxis.y;
  43618. result[5] = zAxis.y;
  43619. result[6] = xAxis.z;
  43620. result[7] = yAxis.z;
  43621. result[8] = zAxis.z;
  43622. return result;
  43623. }
  43624. var rotMtxScratch = new Matrix3();
  43625. var quatScratch = new Quaternion();
  43626. /**
  43627. * Computes a rotation from ICRF to a Globe's Fixed axes.
  43628. *
  43629. * @param {JulianDate} date The date to evaluate the matrix.
  43630. * @param {Matrix3} result The object onto which to store the result.
  43631. * @returns {Matrix} The modified result parameter or a new instance of the rotation from ICRF to Fixed.
  43632. */
  43633. IauOrientationAxes.prototype.evaluate = function(date, result) {
  43634. if (!defined(date)) {
  43635. date = JulianDate.now();
  43636. }
  43637. var alphaDeltaW = this._computeFunction(date);
  43638. var precMtx = computeRotationMatrix(alphaDeltaW.rightAscension, alphaDeltaW.declination, result);
  43639. var rot = CesiumMath.zeroToTwoPi(alphaDeltaW.rotation);
  43640. var quat = Quaternion.fromAxisAngle(Cartesian3.UNIT_Z, rot, quatScratch);
  43641. var rotMtx = Matrix3.fromQuaternion(Quaternion.conjugate(quat, quat), rotMtxScratch);
  43642. var cbi2cbf = Matrix3.multiply(rotMtx, precMtx, precMtx);
  43643. return cbi2cbf;
  43644. };
  43645. /**
  43646. * A function that computes the {@link IauOrientationParameters} for a {@link JulianDate}.
  43647. * @callback IauOrientationAxes~ComputeFunction
  43648. * @param {JulianDate} date The date to evaluate the parameters.
  43649. * @returns {IauOrientationParameters} The orientation parameters.
  43650. */
  43651. return IauOrientationAxes;
  43652. });
  43653. /*global define*/
  43654. define('Core/InterpolationAlgorithm',[
  43655. './DeveloperError'
  43656. ], function(
  43657. DeveloperError) {
  43658. 'use strict';
  43659. /**
  43660. * The interface for interpolation algorithms.
  43661. *
  43662. * @exports InterpolationAlgorithm
  43663. *
  43664. * @see LagrangePolynomialApproximation
  43665. * @see LinearApproximation
  43666. * @see HermitePolynomialApproximation
  43667. */
  43668. var InterpolationAlgorithm = {};
  43669. /**
  43670. * Gets the name of this interpolation algorithm.
  43671. * @type {String}
  43672. */
  43673. InterpolationAlgorithm.type = undefined;
  43674. /**
  43675. * Given the desired degree, returns the number of data points required for interpolation.
  43676. * @function
  43677. *
  43678. * @param {Number} degree The desired degree of interpolation.
  43679. * @returns {Number} The number of required data points needed for the desired degree of interpolation.
  43680. */
  43681. InterpolationAlgorithm.getRequiredDataPoints = DeveloperError.throwInstantiationError;
  43682. /**
  43683. * Performs zero order interpolation.
  43684. * @function
  43685. *
  43686. * @param {Number} x The independent variable for which the dependent variables will be interpolated.
  43687. * @param {Number[]} xTable The array of independent variables to use to interpolate. The values
  43688. * in this array must be in increasing order and the same value must not occur twice in the array.
  43689. * @param {Number[]} yTable The array of dependent variables to use to interpolate. For a set of three
  43690. * dependent values (p,q,w) at time 1 and time 2 this should be as follows: {p1, q1, w1, p2, q2, w2}.
  43691. * @param {Number} yStride The number of dependent variable values in yTable corresponding to
  43692. * each independent variable value in xTable.
  43693. * @param {Number[]} [result] An existing array into which to store the result.
  43694. *
  43695. * @returns {Number[]} The array of interpolated values, or the result parameter if one was provided.
  43696. */
  43697. InterpolationAlgorithm.interpolateOrderZero = DeveloperError.throwInstantiationError;
  43698. /**
  43699. * Performs higher order interpolation. Not all interpolators need to support high-order interpolation,
  43700. * if this function remains undefined on implementing objects, interpolateOrderZero will be used instead.
  43701. * @function
  43702. * @param {Number} x The independent variable for which the dependent variables will be interpolated.
  43703. * @param {Number[]} xTable The array of independent variables to use to interpolate. The values
  43704. * in this array must be in increasing order and the same value must not occur twice in the array.
  43705. * @param {Number[]} yTable The array of dependent variables to use to interpolate. For a set of three
  43706. * dependent values (p,q,w) at time 1 and time 2 this should be as follows: {p1, q1, w1, p2, q2, w2}.
  43707. * @param {Number} yStride The number of dependent variable values in yTable corresponding to
  43708. * each independent variable value in xTable.
  43709. * @param {Number} inputOrder The number of derivatives supplied for input.
  43710. * @param {Number} outputOrder The number of derivatives desired for output.
  43711. * @param {Number[]} [result] An existing array into which to store the result.
  43712. * @returns {Number[]} The array of interpolated values, or the result parameter if one was provided.
  43713. */
  43714. InterpolationAlgorithm.interpolate = DeveloperError.throwInstantiationError;
  43715. return InterpolationAlgorithm;
  43716. });
  43717. /*global define*/
  43718. define('Core/TimeInterval',[
  43719. './defaultValue',
  43720. './defined',
  43721. './defineProperties',
  43722. './DeveloperError',
  43723. './freezeObject',
  43724. './JulianDate'
  43725. ], function(
  43726. defaultValue,
  43727. defined,
  43728. defineProperties,
  43729. DeveloperError,
  43730. freezeObject,
  43731. JulianDate) {
  43732. 'use strict';
  43733. /**
  43734. * An interval defined by a start and a stop time; optionally including those times as part of the interval.
  43735. * Arbitrary data can optionally be associated with each instance for used with {@link TimeIntervalCollection}.
  43736. *
  43737. * @alias TimeInterval
  43738. * @constructor
  43739. *
  43740. * @param {Object} [options] Object with the following properties:
  43741. * @param {JulianDate} [options.start=new JulianDate()] The start time of the interval.
  43742. * @param {JulianDate} [options.stop=new JulianDate()] The stop time of the interval.
  43743. * @param {Boolean} [options.isStartIncluded=true] <code>true</code> if <code>options.start</code> is included in the interval, <code>false</code> otherwise.
  43744. * @param {Boolean} [options.isStopIncluded=true] <code>true</code> if <code>options.stop</code> is included in the interval, <code>false</code> otherwise.
  43745. * @param {Object} [options.data] Arbitrary data associated with this interval.
  43746. *
  43747. * @example
  43748. * // Create an instance that spans August 1st, 1980 and is associated
  43749. * // with a Cartesian position.
  43750. * var timeInterval = new Cesium.TimeInterval({
  43751. * start : Cesium.JulianDate.fromIso8601('1980-08-01T00:00:00Z'),
  43752. * stop : Cesium.JulianDate.fromIso8601('1980-08-02T00:00:00Z'),
  43753. * isStartIncluded : true,
  43754. * isStopIncluded : false,
  43755. * data : Cesium.Cartesian3.fromDegrees(39.921037, -75.170082)
  43756. * });
  43757. *
  43758. * @example
  43759. * // Create two instances from ISO 8601 intervals with associated numeric data
  43760. * // then compute their intersection, summing the data they contain.
  43761. * var left = Cesium.TimeInterval.fromIso8601({
  43762. * iso8601 : '2000/2010',
  43763. * data : 2
  43764. * });
  43765. *
  43766. * var right = Cesium.TimeInterval.fromIso8601({
  43767. * iso8601 : '1995/2005',
  43768. * data : 3
  43769. * });
  43770. *
  43771. * //The result of the below intersection will be an interval equivalent to
  43772. * //var intersection = Cesium.TimeInterval.fromIso8601({
  43773. * // iso8601 : '2000/2005',
  43774. * // data : 5
  43775. * //});
  43776. * var intersection = new Cesium.TimeInterval();
  43777. * Cesium.TimeInterval.intersect(left, right, intersection, function(leftData, rightData) {
  43778. * return leftData + rightData;
  43779. * });
  43780. *
  43781. * @example
  43782. * // Check if an interval contains a specific time.
  43783. * var dateToCheck = Cesium.JulianDate.fromIso8601('1982-09-08T11:30:00Z');
  43784. * var containsDate = Cesium.TimeInterval.contains(timeInterval, dateToCheck);
  43785. */
  43786. function TimeInterval(options) {
  43787. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  43788. /**
  43789. * Gets or sets the start time of this interval.
  43790. * @type {JulianDate}
  43791. */
  43792. this.start = defined(options.start) ? JulianDate.clone(options.start) : new JulianDate();
  43793. /**
  43794. * Gets or sets the stop time of this interval.
  43795. * @type {JulianDate}
  43796. */
  43797. this.stop = defined(options.stop) ? JulianDate.clone(options.stop) : new JulianDate();
  43798. /**
  43799. * Gets or sets the data associated with this interval.
  43800. * @type {Object}
  43801. */
  43802. this.data = options.data;
  43803. /**
  43804. * Gets or sets whether or not the start time is included in this interval.
  43805. * @type {Boolean}
  43806. * @default true
  43807. */
  43808. this.isStartIncluded = defaultValue(options.isStartIncluded, true);
  43809. /**
  43810. * Gets or sets whether or not the stop time is included in this interval.
  43811. * @type {Boolean}
  43812. * @default true
  43813. */
  43814. this.isStopIncluded = defaultValue(options.isStopIncluded, true);
  43815. }
  43816. defineProperties(TimeInterval.prototype, {
  43817. /**
  43818. * Gets whether or not this interval is empty.
  43819. * @memberof TimeInterval.prototype
  43820. * @type {Boolean}
  43821. * @readonly
  43822. */
  43823. isEmpty : {
  43824. get : function() {
  43825. var stopComparedToStart = JulianDate.compare(this.stop, this.start);
  43826. return stopComparedToStart < 0 || (stopComparedToStart === 0 && (!this.isStartIncluded || !this.isStopIncluded));
  43827. }
  43828. }
  43829. });
  43830. var scratchInterval = {
  43831. start : undefined,
  43832. stop : undefined,
  43833. isStartIncluded : undefined,
  43834. isStopIncluded : undefined,
  43835. data : undefined
  43836. };
  43837. /**
  43838. * Creates a new instance from an {@link http://en.wikipedia.org/wiki/ISO_8601|ISO 8601} interval.
  43839. *
  43840. * @param {Object} options Object with the following properties:
  43841. * @param {String} options.iso8601 An ISO 8601 interval.
  43842. * @param {Boolean} [options.isStartIncluded=true] <code>true</code> if <code>options.start</code> is included in the interval, <code>false</code> otherwise.
  43843. * @param {Boolean} [options.isStopIncluded=true] <code>true</code> if <code>options.stop</code> is included in the interval, <code>false</code> otherwise.
  43844. * @param {Object} [options.data] Arbitrary data associated with this interval.
  43845. * @param {TimeInterval} [result] An existing instance to use for the result.
  43846. * @returns {TimeInterval} The modified result parameter or a new instance if none was provided.
  43847. */
  43848. TimeInterval.fromIso8601 = function(options, result) {
  43849. if (!defined(options)) {
  43850. throw new DeveloperError('options is required.');
  43851. }
  43852. if (!defined(options.iso8601)) {
  43853. throw new DeveloperError('options.iso8601 is required.');
  43854. }
  43855. var dates = options.iso8601.split('/');
  43856. var start = JulianDate.fromIso8601(dates[0]);
  43857. var stop = JulianDate.fromIso8601(dates[1]);
  43858. var isStartIncluded = defaultValue(options.isStartIncluded, true);
  43859. var isStopIncluded = defaultValue(options.isStopIncluded, true);
  43860. var data = options.data;
  43861. if (!defined(result)) {
  43862. scratchInterval.start = start;
  43863. scratchInterval.stop = stop;
  43864. scratchInterval.isStartIncluded = isStartIncluded;
  43865. scratchInterval.isStopIncluded = isStopIncluded;
  43866. scratchInterval.data = data;
  43867. return new TimeInterval(scratchInterval);
  43868. }
  43869. result.start = start;
  43870. result.stop = stop;
  43871. result.isStartIncluded = isStartIncluded;
  43872. result.isStopIncluded = isStopIncluded;
  43873. result.data = data;
  43874. return result;
  43875. };
  43876. /**
  43877. * Creates an ISO8601 representation of the provided interval.
  43878. *
  43879. * @param {TimeInterval} timeInterval The interval to be converted.
  43880. * @param {Number} [precision] The number of fractional digits used to represent the seconds component. By default, the most precise representation is used.
  43881. * @returns {String} The ISO8601 representation of the provided interval.
  43882. */
  43883. TimeInterval.toIso8601 = function(timeInterval, precision) {
  43884. if (!defined(timeInterval)) {
  43885. throw new DeveloperError('timeInterval is required.');
  43886. }
  43887. return JulianDate.toIso8601(timeInterval.start, precision) + '/' + JulianDate.toIso8601(timeInterval.stop, precision);
  43888. };
  43889. /**
  43890. * Duplicates the provided instance.
  43891. *
  43892. * @param {TimeInterval} [timeInterval] The instance to clone.
  43893. * @param {TimeInterval} [result] An existing instance to use for the result.
  43894. * @returns {TimeInterval} The modified result parameter or a new instance if none was provided.
  43895. */
  43896. TimeInterval.clone = function(timeInterval, result) {
  43897. if (!defined(timeInterval)) {
  43898. return undefined;
  43899. }
  43900. if (!defined(result)) {
  43901. return new TimeInterval(timeInterval);
  43902. }
  43903. result.start = timeInterval.start;
  43904. result.stop = timeInterval.stop;
  43905. result.isStartIncluded = timeInterval.isStartIncluded;
  43906. result.isStopIncluded = timeInterval.isStopIncluded;
  43907. result.data = timeInterval.data;
  43908. return result;
  43909. };
  43910. /**
  43911. * Compares two instances and returns <code>true</code> if they are equal, <code>false</code> otherwise.
  43912. *
  43913. * @param {TimeInterval} [left] The first instance.
  43914. * @param {TimeInterval} [right] The second instance.
  43915. * @param {TimeInterval~DataComparer} [dataComparer] A function which compares the data of the two intervals. If omitted, reference equality is used.
  43916. * @returns {Boolean} <code>true</code> if the dates are equal; otherwise, <code>false</code>.
  43917. */
  43918. TimeInterval.equals = function(left, right, dataComparer) {
  43919. return left === right ||
  43920. defined(left) && defined(right) &&
  43921. (left.isEmpty && right.isEmpty ||
  43922. left.isStartIncluded === right.isStartIncluded &&
  43923. left.isStopIncluded === right.isStopIncluded &&
  43924. JulianDate.equals(left.start, right.start) &&
  43925. JulianDate.equals(left.stop, right.stop) &&
  43926. (left.data === right.data || (defined(dataComparer) && dataComparer(left.data, right.data))));
  43927. };
  43928. /**
  43929. * Compares two instances and returns <code>true</code> if they are within <code>epsilon</code> seconds of
  43930. * each other. That is, in order for the dates to be considered equal (and for
  43931. * this function to return <code>true</code>), the absolute value of the difference between them, in
  43932. * seconds, must be less than <code>epsilon</code>.
  43933. *
  43934. * @param {TimeInterval} [left] The first instance.
  43935. * @param {TimeInterval} [right] The second instance.
  43936. * @param {Number} epsilon The maximum number of seconds that should separate the two instances.
  43937. * @param {TimeInterval~DataComparer} [dataComparer] A function which compares the data of the two intervals. If omitted, reference equality is used.
  43938. * @returns {Boolean} <code>true</code> if the two dates are within <code>epsilon</code> seconds of each other; otherwise <code>false</code>.
  43939. */
  43940. TimeInterval.equalsEpsilon = function(left, right, epsilon, dataComparer) {
  43941. if (typeof epsilon !== 'number') {
  43942. throw new DeveloperError('epsilon is required and must be a number.');
  43943. }
  43944. return left === right ||
  43945. defined(left) && defined(right) &&
  43946. (left.isEmpty && right.isEmpty ||
  43947. left.isStartIncluded === right.isStartIncluded &&
  43948. left.isStopIncluded === right.isStopIncluded &&
  43949. JulianDate.equalsEpsilon(left.start, right.start, epsilon) &&
  43950. JulianDate.equalsEpsilon(left.stop, right.stop, epsilon) &&
  43951. (left.data === right.data || (defined(dataComparer) && dataComparer(left.data, right.data))));
  43952. };
  43953. /**
  43954. * Computes the intersection of two intervals, optionally merging their data.
  43955. *
  43956. * @param {TimeInterval} left The first interval.
  43957. * @param {TimeInterval} [right] The second interval.
  43958. * @param {TimeInterval} result An existing instance to use for the result.
  43959. * @param {TimeInterval~MergeCallback} [mergeCallback] A function which merges the data of the two intervals. If omitted, the data from the left interval will be used.
  43960. * @returns {TimeInterval} The modified result parameter.
  43961. */
  43962. TimeInterval.intersect = function(left, right, result, mergeCallback) {
  43963. if (!defined(left)) {
  43964. throw new DeveloperError('left is required.');
  43965. }
  43966. if (!defined(result)) {
  43967. throw new DeveloperError('result is required.');
  43968. }
  43969. if (!defined(right)) {
  43970. return TimeInterval.clone(TimeInterval.EMPTY, result);
  43971. }
  43972. var leftStart = left.start;
  43973. var leftStop = left.stop;
  43974. var rightStart = right.start;
  43975. var rightStop = right.stop;
  43976. var intersectsStartRight = JulianDate.greaterThanOrEquals(rightStart, leftStart) && JulianDate.greaterThanOrEquals(leftStop, rightStart);
  43977. var intersectsStartLeft = !intersectsStartRight && JulianDate.lessThanOrEquals(rightStart, leftStart) && JulianDate.lessThanOrEquals(leftStart, rightStop);
  43978. if (!intersectsStartRight && !intersectsStartLeft) {
  43979. return TimeInterval.clone(TimeInterval.EMPTY, result);
  43980. }
  43981. var leftIsStartIncluded = left.isStartIncluded;
  43982. var leftIsStopIncluded = left.isStopIncluded;
  43983. var rightIsStartIncluded = right.isStartIncluded;
  43984. var rightIsStopIncluded = right.isStopIncluded;
  43985. var leftLessThanRight = JulianDate.lessThan(leftStop, rightStop);
  43986. result.start = intersectsStartRight ? rightStart : leftStart;
  43987. result.isStartIncluded = (leftIsStartIncluded && rightIsStartIncluded) || (!JulianDate.equals(rightStart, leftStart) && ((intersectsStartRight && rightIsStartIncluded) || (intersectsStartLeft && leftIsStartIncluded)));
  43988. result.stop = leftLessThanRight ? leftStop : rightStop;
  43989. result.isStopIncluded = leftLessThanRight ? leftIsStopIncluded : (leftIsStopIncluded && rightIsStopIncluded) || (!JulianDate.equals(rightStop, leftStop) && rightIsStopIncluded);
  43990. result.data = defined(mergeCallback) ? mergeCallback(left.data, right.data) : left.data;
  43991. return result;
  43992. };
  43993. /**
  43994. * Checks if the specified date is inside the provided interval.
  43995. *
  43996. * @param {TimeInterval} timeInterval The interval.
  43997. * @param {JulianDate} julianDate The date to check.
  43998. * @returns {Boolean} <code>true</code> if the interval contains the specified date, <code>false</code> otherwise.
  43999. */
  44000. TimeInterval.contains = function(timeInterval, julianDate) {
  44001. if (!defined(timeInterval)) {
  44002. throw new DeveloperError('timeInterval is required.');
  44003. }
  44004. if (!defined(julianDate)) {
  44005. throw new DeveloperError('julianDate is required.');
  44006. }
  44007. if (timeInterval.isEmpty) {
  44008. return false;
  44009. }
  44010. var startComparedToDate = JulianDate.compare(timeInterval.start, julianDate);
  44011. if (startComparedToDate === 0) {
  44012. return timeInterval.isStartIncluded;
  44013. }
  44014. var dateComparedToStop = JulianDate.compare(julianDate, timeInterval.stop);
  44015. if (dateComparedToStop === 0) {
  44016. return timeInterval.isStopIncluded;
  44017. }
  44018. return startComparedToDate < 0 && dateComparedToStop < 0;
  44019. };
  44020. /**
  44021. * Duplicates this instance.
  44022. *
  44023. * @param {TimeInterval} [result] An existing instance to use for the result.
  44024. * @returns {TimeInterval} The modified result parameter or a new instance if none was provided.
  44025. */
  44026. TimeInterval.prototype.clone = function(result) {
  44027. return TimeInterval.clone(this, result);
  44028. };
  44029. /**
  44030. * Compares this instance against the provided instance componentwise and returns
  44031. * <code>true</code> if they are equal, <code>false</code> otherwise.
  44032. *
  44033. * @param {TimeInterval} [right] The right hand side interval.
  44034. * @param {TimeInterval~DataComparer} [dataComparer] A function which compares the data of the two intervals. If omitted, reference equality is used.
  44035. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  44036. */
  44037. TimeInterval.prototype.equals = function(right, dataComparer) {
  44038. return TimeInterval.equals(this, right, dataComparer);
  44039. };
  44040. /**
  44041. * Compares this instance against the provided instance componentwise and returns
  44042. * <code>true</code> if they are within the provided epsilon,
  44043. * <code>false</code> otherwise.
  44044. *
  44045. * @param {TimeInterval} [right] The right hand side interval.
  44046. * @param {Number} epsilon The epsilon to use for equality testing.
  44047. * @param {TimeInterval~DataComparer} [dataComparer] A function which compares the data of the two intervals. If omitted, reference equality is used.
  44048. * @returns {Boolean} <code>true</code> if they are within the provided epsilon, <code>false</code> otherwise.
  44049. */
  44050. TimeInterval.prototype.equalsEpsilon = function(right, epsilon, dataComparer) {
  44051. return TimeInterval.equalsEpsilon(this, right, epsilon, dataComparer);
  44052. };
  44053. /**
  44054. * Creates a string representing this TimeInterval in ISO8601 format.
  44055. *
  44056. * @returns {String} A string representing this TimeInterval in ISO8601 format.
  44057. */
  44058. TimeInterval.prototype.toString = function() {
  44059. return TimeInterval.toIso8601(this);
  44060. };
  44061. /**
  44062. * An immutable empty interval.
  44063. *
  44064. * @type {TimeInterval}
  44065. * @constant
  44066. */
  44067. TimeInterval.EMPTY = freezeObject(new TimeInterval({
  44068. start : new JulianDate(),
  44069. stop : new JulianDate(),
  44070. isStartIncluded : false,
  44071. isStopIncluded : false
  44072. }));
  44073. /**
  44074. * Function interface for merging interval data.
  44075. * @callback TimeInterval~MergeCallback
  44076. *
  44077. * @param {Object} leftData The first data instance.
  44078. * @param {Object} rightData The second data instance.
  44079. * @returns {Object} The result of merging the two data instances.
  44080. */
  44081. /**
  44082. * Function interface for comparing interval data.
  44083. * @callback TimeInterval~DataComparer
  44084. * @param {Object} leftData The first data instance.
  44085. * @param {Object} rightData The second data instance.
  44086. * @returns {Boolean} <code>true</code> if the provided instances are equal, <code>false</code> otherwise.
  44087. */
  44088. return TimeInterval;
  44089. });
  44090. /*global define*/
  44091. define('Core/Iso8601',[
  44092. './freezeObject',
  44093. './JulianDate',
  44094. './TimeInterval'
  44095. ], function(
  44096. freezeObject,
  44097. JulianDate,
  44098. TimeInterval) {
  44099. 'use strict';
  44100. var MINIMUM_VALUE = freezeObject(JulianDate.fromIso8601('0000-01-01T00:00:00Z'));
  44101. var MAXIMUM_VALUE = freezeObject(JulianDate.fromIso8601('9999-12-31T24:00:00Z'));
  44102. var MAXIMUM_INTERVAL = freezeObject(new TimeInterval({
  44103. start : MINIMUM_VALUE,
  44104. stop : MAXIMUM_VALUE
  44105. }));
  44106. /**
  44107. * Constants related to ISO8601 support.
  44108. *
  44109. * @exports Iso8601
  44110. *
  44111. * @see {@link http://en.wikipedia.org/wiki/ISO_8601|ISO 8601 on Wikipedia}
  44112. * @see JulianDate
  44113. * @see TimeInterval
  44114. */
  44115. var Iso8601 = {
  44116. /**
  44117. * A {@link JulianDate} representing the earliest time representable by an ISO8601 date.
  44118. * This is equivalent to the date string '0000-01-01T00:00:00Z'
  44119. */
  44120. MINIMUM_VALUE : MINIMUM_VALUE,
  44121. /**
  44122. * A {@link JulianDate} representing the latest time representable by an ISO8601 date.
  44123. * This is equivalent to the date string '9999-12-31T24:00:00Z'
  44124. */
  44125. MAXIMUM_VALUE : MAXIMUM_VALUE,
  44126. /**
  44127. * A {@link TimeInterval} representing the largest interval representable by an ISO8601 interval.
  44128. * This is equivalent to the interval string '0000-01-01T00:00:00Z/9999-12-31T24:00:00Z'
  44129. */
  44130. MAXIMUM_INTERVAL : MAXIMUM_INTERVAL
  44131. };
  44132. return Iso8601;
  44133. });
  44134. /*global define*/
  44135. define('Core/KeyboardEventModifier',[
  44136. './freezeObject'
  44137. ], function(
  44138. freezeObject) {
  44139. 'use strict';
  44140. /**
  44141. * This enumerated type is for representing keyboard modifiers. These are keys
  44142. * that are held down in addition to other event types.
  44143. *
  44144. * @exports KeyboardEventModifier
  44145. */
  44146. var KeyboardEventModifier = {
  44147. /**
  44148. * Represents the shift key being held down.
  44149. *
  44150. * @type {Number}
  44151. * @constant
  44152. */
  44153. SHIFT : 0,
  44154. /**
  44155. * Represents the control key being held down.
  44156. *
  44157. * @type {Number}
  44158. * @constant
  44159. */
  44160. CTRL : 1,
  44161. /**
  44162. * Represents the alt key being held down.
  44163. *
  44164. * @type {Number}
  44165. * @constant
  44166. */
  44167. ALT : 2
  44168. };
  44169. return freezeObject(KeyboardEventModifier);
  44170. });
  44171. /*global define*/
  44172. define('Core/LagrangePolynomialApproximation',[
  44173. './defined'
  44174. ], function(
  44175. defined) {
  44176. 'use strict';
  44177. /**
  44178. * An {@link InterpolationAlgorithm} for performing Lagrange interpolation.
  44179. *
  44180. * @exports LagrangePolynomialApproximation
  44181. */
  44182. var LagrangePolynomialApproximation = {
  44183. type : 'Lagrange'
  44184. };
  44185. /**
  44186. * Given the desired degree, returns the number of data points required for interpolation.
  44187. *
  44188. * @param {Number} degree The desired degree of interpolation.
  44189. * @returns {Number} The number of required data points needed for the desired degree of interpolation.
  44190. */
  44191. LagrangePolynomialApproximation.getRequiredDataPoints = function(degree) {
  44192. return Math.max(degree + 1.0, 2);
  44193. };
  44194. /**
  44195. * Interpolates values using Lagrange Polynomial Approximation.
  44196. *
  44197. * @param {Number} x The independent variable for which the dependent variables will be interpolated.
  44198. * @param {Number[]} xTable The array of independent variables to use to interpolate. The values
  44199. * in this array must be in increasing order and the same value must not occur twice in the array.
  44200. * @param {Number[]} yTable The array of dependent variables to use to interpolate. For a set of three
  44201. * dependent values (p,q,w) at time 1 and time 2 this should be as follows: {p1, q1, w1, p2, q2, w2}.
  44202. * @param {Number} yStride The number of dependent variable values in yTable corresponding to
  44203. * each independent variable value in xTable.
  44204. * @param {Number[]} [result] An existing array into which to store the result.
  44205. * @returns {Number[]} The array of interpolated values, or the result parameter if one was provided.
  44206. */
  44207. LagrangePolynomialApproximation.interpolateOrderZero = function(x, xTable, yTable, yStride, result) {
  44208. if (!defined(result)) {
  44209. result = new Array(yStride);
  44210. }
  44211. var i;
  44212. var j;
  44213. var length = xTable.length;
  44214. for (i = 0; i < yStride; i++) {
  44215. result[i] = 0;
  44216. }
  44217. for (i = 0; i < length; i++) {
  44218. var coefficient = 1;
  44219. for (j = 0; j < length; j++) {
  44220. if (j !== i) {
  44221. var diffX = xTable[i] - xTable[j];
  44222. coefficient *= (x - xTable[j]) / diffX;
  44223. }
  44224. }
  44225. for (j = 0; j < yStride; j++) {
  44226. result[j] += coefficient * yTable[i * yStride + j];
  44227. }
  44228. }
  44229. return result;
  44230. };
  44231. return LagrangePolynomialApproximation;
  44232. });
  44233. /*global define*/
  44234. define('Core/LinearApproximation',[
  44235. './defined',
  44236. './DeveloperError'
  44237. ], function(
  44238. defined,
  44239. DeveloperError) {
  44240. 'use strict';
  44241. /**
  44242. * An {@link InterpolationAlgorithm} for performing linear interpolation.
  44243. *
  44244. * @exports LinearApproximation
  44245. */
  44246. var LinearApproximation = {
  44247. type : 'Linear'
  44248. };
  44249. /**
  44250. * Given the desired degree, returns the number of data points required for interpolation.
  44251. * Since linear interpolation can only generate a first degree polynomial, this function
  44252. * always returns 2.
  44253. * @param {Number} degree The desired degree of interpolation.
  44254. * @returns {Number} This function always returns 2.
  44255. *
  44256. */
  44257. LinearApproximation.getRequiredDataPoints = function(degree) {
  44258. return 2;
  44259. };
  44260. /**
  44261. * Interpolates values using linear approximation.
  44262. *
  44263. * @param {Number} x The independent variable for which the dependent variables will be interpolated.
  44264. * @param {Number[]} xTable The array of independent variables to use to interpolate. The values
  44265. * in this array must be in increasing order and the same value must not occur twice in the array.
  44266. * @param {Number[]} yTable The array of dependent variables to use to interpolate. For a set of three
  44267. * dependent values (p,q,w) at time 1 and time 2 this should be as follows: {p1, q1, w1, p2, q2, w2}.
  44268. * @param {Number} yStride The number of dependent variable values in yTable corresponding to
  44269. * each independent variable value in xTable.
  44270. * @param {Number[]} [result] An existing array into which to store the result.
  44271. * @returns {Number[]} The array of interpolated values, or the result parameter if one was provided.
  44272. */
  44273. LinearApproximation.interpolateOrderZero = function(x, xTable, yTable, yStride, result) {
  44274. if (xTable.length !== 2) {
  44275. throw new DeveloperError('The xTable provided to the linear interpolator must have exactly two elements.');
  44276. } else if (yStride <= 0) {
  44277. throw new DeveloperError('There must be at least 1 dependent variable for each independent variable.');
  44278. }
  44279. if (!defined(result)) {
  44280. result = new Array(yStride);
  44281. }
  44282. var i;
  44283. var y0;
  44284. var y1;
  44285. var x0 = xTable[0];
  44286. var x1 = xTable[1];
  44287. if (x0 === x1) {
  44288. throw new DeveloperError('Divide by zero error: xTable[0] and xTable[1] are equal');
  44289. }
  44290. for (i = 0; i < yStride; i++) {
  44291. y0 = yTable[i];
  44292. y1 = yTable[i + yStride];
  44293. result[i] = (((y1 - y0) * x) + (x1 * y0) - (x0 * y1)) / (x1 - x0);
  44294. }
  44295. return result;
  44296. };
  44297. return LinearApproximation;
  44298. });
  44299. /*global define*/
  44300. define('Core/loadBlob',[
  44301. './loadWithXhr'
  44302. ], function(
  44303. loadWithXhr) {
  44304. 'use strict';
  44305. /**
  44306. * Asynchronously loads the given URL as a blob. Returns a promise that will resolve to
  44307. * a Blob once loaded, or reject if the URL failed to load. The data is loaded
  44308. * using XMLHttpRequest, which means that in order to make requests to another origin,
  44309. * the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
  44310. *
  44311. * @exports loadBlob
  44312. *
  44313. * @param {String|Promise.<String>} url The URL of the data, or a promise for the URL.
  44314. * @param {Object} [headers] HTTP headers to send with the requests.
  44315. * @returns {Promise.<Blob>} a promise that will resolve to the requested data when loaded.
  44316. *
  44317. *
  44318. * @example
  44319. * // load a single URL asynchronously
  44320. * Cesium.loadBlob('some/url').then(function(blob) {
  44321. * // use the data
  44322. * }).otherwise(function(error) {
  44323. * // an error occurred
  44324. * });
  44325. *
  44326. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  44327. * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
  44328. */
  44329. function loadBlob(url, headers) {
  44330. return loadWithXhr({
  44331. url : url,
  44332. responseType : 'blob',
  44333. headers : headers
  44334. });
  44335. }
  44336. return loadBlob;
  44337. });
  44338. /*global define*/
  44339. define('Core/loadImageFromTypedArray',[
  44340. '../ThirdParty/when',
  44341. './defined',
  44342. './DeveloperError',
  44343. './loadImage'
  44344. ], function(
  44345. when,
  44346. defined,
  44347. DeveloperError,
  44348. loadImage) {
  44349. 'use strict';
  44350. /**
  44351. * @private
  44352. */
  44353. function loadImageFromTypedArray(uint8Array, format) {
  44354. if (!defined(uint8Array)) {
  44355. throw new DeveloperError('uint8Array is required.');
  44356. }
  44357. if (!defined(format)) {
  44358. throw new DeveloperError('format is required.');
  44359. }
  44360. var blob = new Blob([uint8Array], {
  44361. type : format
  44362. });
  44363. var blobUrl = window.URL.createObjectURL(blob);
  44364. return loadImage(blobUrl, false).then(function(image) {
  44365. window.URL.revokeObjectURL(blobUrl);
  44366. return image;
  44367. }, function(error) {
  44368. window.URL.revokeObjectURL(blobUrl);
  44369. return when.reject(error);
  44370. });
  44371. }
  44372. return loadImageFromTypedArray;
  44373. });
  44374. /*global define*/
  44375. define('Core/loadImageViaBlob',[
  44376. '../ThirdParty/when',
  44377. './loadBlob',
  44378. './loadImage'
  44379. ], function(
  44380. when,
  44381. loadBlob,
  44382. loadImage) {
  44383. 'use strict';
  44384. var dataUriRegex = /^data:/;
  44385. /**
  44386. * Asynchronously loads the given image URL by first downloading it as a blob using
  44387. * XMLHttpRequest and then loading the image from the buffer via a blob URL.
  44388. * This allows access to more information that is not accessible via normal
  44389. * Image-based downloading, such as the size of the response. This function
  44390. * returns a promise that will resolve to
  44391. * an {@link Image} once loaded, or reject if the image failed to load. The
  44392. * returned image will have a "blob" property with the Blob itself. If the browser
  44393. * does not support an XMLHttpRequests with a responseType of 'blob', or if the
  44394. * provided URI is a data URI, this function is equivalent to calling {@link loadImage},
  44395. * and the extra blob property will not be present.
  44396. *
  44397. * @exports loadImageViaBlob
  44398. *
  44399. * @param {String|Promise.<String>} url The source of the image, or a promise for the URL.
  44400. * @returns {Promise.<Image>} a promise that will resolve to the requested data when loaded.
  44401. *
  44402. *
  44403. * @example
  44404. * // load a single image asynchronously
  44405. * Cesium.loadImageViaBlob('some/image/url.png').then(function(image) {
  44406. * var blob = image.blob;
  44407. * // use the loaded image or XHR
  44408. * }).otherwise(function(error) {
  44409. * // an error occurred
  44410. * });
  44411. *
  44412. * // load several images in parallel
  44413. * when.all([loadImageViaBlob('image1.png'), loadImageViaBlob('image2.png')]).then(function(images) {
  44414. * // images is an array containing all the loaded images
  44415. * });
  44416. *
  44417. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  44418. * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
  44419. */
  44420. function loadImageViaBlob(url) {
  44421. if (dataUriRegex.test(url)) {
  44422. return loadImage(url);
  44423. }
  44424. return loadBlob(url).then(function(blob) {
  44425. var blobUrl = window.URL.createObjectURL(blob);
  44426. return loadImage(blobUrl, false).then(function(image) {
  44427. image.blob = blob;
  44428. window.URL.revokeObjectURL(blobUrl);
  44429. return image;
  44430. }, function(error) {
  44431. window.URL.revokeObjectURL(blobUrl);
  44432. return when.reject(error);
  44433. });
  44434. });
  44435. }
  44436. var xhrBlobSupported = (function() {
  44437. try {
  44438. var xhr = new XMLHttpRequest();
  44439. xhr.open('GET', '#', true);
  44440. xhr.responseType = 'blob';
  44441. return xhr.responseType === 'blob';
  44442. } catch (e) {
  44443. return false;
  44444. }
  44445. })();
  44446. return xhrBlobSupported ? loadImageViaBlob : loadImage;
  44447. });
  44448. /*global define*/
  44449. define('Core/objectToQuery',[
  44450. './defined',
  44451. './DeveloperError',
  44452. './isArray'
  44453. ], function(
  44454. defined,
  44455. DeveloperError,
  44456. isArray) {
  44457. 'use strict';
  44458. /**
  44459. * Converts an object representing a set of name/value pairs into a query string,
  44460. * with names and values encoded properly for use in a URL. Values that are arrays
  44461. * will produce multiple values with the same name.
  44462. * @exports objectToQuery
  44463. *
  44464. * @param {Object} obj The object containing data to encode.
  44465. * @returns {String} An encoded query string.
  44466. *
  44467. *
  44468. * @example
  44469. * var str = Cesium.objectToQuery({
  44470. * key1 : 'some value',
  44471. * key2 : 'a/b',
  44472. * key3 : ['x', 'y']
  44473. * });
  44474. *
  44475. * @see queryToObject
  44476. * // str will be:
  44477. * // 'key1=some%20value&key2=a%2Fb&key3=x&key3=y'
  44478. */
  44479. function objectToQuery(obj) {
  44480. if (!defined(obj)) {
  44481. throw new DeveloperError('obj is required.');
  44482. }
  44483. var result = '';
  44484. for ( var propName in obj) {
  44485. if (obj.hasOwnProperty(propName)) {
  44486. var value = obj[propName];
  44487. var part = encodeURIComponent(propName) + '=';
  44488. if (isArray(value)) {
  44489. for (var i = 0, len = value.length; i < len; ++i) {
  44490. result += part + encodeURIComponent(value[i]) + '&';
  44491. }
  44492. } else {
  44493. result += part + encodeURIComponent(value) + '&';
  44494. }
  44495. }
  44496. }
  44497. // trim last &
  44498. result = result.slice(0, -1);
  44499. // This function used to replace %20 with + which is more compact and readable.
  44500. // However, some servers didn't properly handle + as a space.
  44501. // https://github.com/AnalyticalGraphicsInc/cesium/issues/2192
  44502. return result;
  44503. }
  44504. return objectToQuery;
  44505. });
  44506. /*global define*/
  44507. define('Core/queryToObject',[
  44508. './defined',
  44509. './DeveloperError',
  44510. './isArray'
  44511. ], function(
  44512. defined,
  44513. DeveloperError,
  44514. isArray) {
  44515. 'use strict';
  44516. /**
  44517. * Parses a query string into an object, where the keys and values of the object are the
  44518. * name/value pairs from the query string, decoded. If a name appears multiple times,
  44519. * the value in the object will be an array of values.
  44520. * @exports queryToObject
  44521. *
  44522. * @param {String} queryString The query string.
  44523. * @returns {Object} An object containing the parameters parsed from the query string.
  44524. *
  44525. *
  44526. * @example
  44527. * var obj = Cesium.queryToObject('key1=some%20value&key2=a%2Fb&key3=x&key3=y');
  44528. * // obj will be:
  44529. * // {
  44530. * // key1 : 'some value',
  44531. * // key2 : 'a/b',
  44532. * // key3 : ['x', 'y']
  44533. * // }
  44534. *
  44535. * @see objectToQuery
  44536. */
  44537. function queryToObject(queryString) {
  44538. if (!defined(queryString)) {
  44539. throw new DeveloperError('queryString is required.');
  44540. }
  44541. var result = {};
  44542. if (queryString === '') {
  44543. return result;
  44544. }
  44545. var parts = queryString.replace(/\+/g, '%20').split('&');
  44546. for (var i = 0, len = parts.length; i < len; ++i) {
  44547. var subparts = parts[i].split('=');
  44548. var name = decodeURIComponent(subparts[0]);
  44549. var value = subparts[1];
  44550. if (defined(value)) {
  44551. value = decodeURIComponent(value);
  44552. } else {
  44553. value = '';
  44554. }
  44555. var resultValue = result[name];
  44556. if (typeof resultValue === 'string') {
  44557. // expand the single value to an array
  44558. result[name] = [resultValue, value];
  44559. } else if (isArray(resultValue)) {
  44560. resultValue.push(value);
  44561. } else {
  44562. result[name] = value;
  44563. }
  44564. }
  44565. return result;
  44566. }
  44567. return queryToObject;
  44568. });
  44569. /*global define*/
  44570. define('Core/loadJsonp',[
  44571. '../ThirdParty/Uri',
  44572. '../ThirdParty/when',
  44573. './combine',
  44574. './defaultValue',
  44575. './defined',
  44576. './DeveloperError',
  44577. './objectToQuery',
  44578. './queryToObject'
  44579. ], function(
  44580. Uri,
  44581. when,
  44582. combine,
  44583. defaultValue,
  44584. defined,
  44585. DeveloperError,
  44586. objectToQuery,
  44587. queryToObject) {
  44588. 'use strict';
  44589. /**
  44590. * Requests a resource using JSONP.
  44591. *
  44592. * @exports loadJsonp
  44593. *
  44594. * @param {String} url The URL to request.
  44595. * @param {Object} [options] Object with the following properties:
  44596. * @param {Object} [options.parameters] Any extra query parameters to append to the URL.
  44597. * @param {String} [options.callbackParameterName='callback'] The callback parameter name that the server expects.
  44598. * @param {Proxy} [options.proxy] A proxy to use for the request. This object is expected to have a getURL function which returns the proxied URL, if needed.
  44599. * @returns {Promise.<Object>} a promise that will resolve to the requested data when loaded.
  44600. *
  44601. *
  44602. * @example
  44603. * // load a data asynchronously
  44604. * Cesium.loadJsonp('some/webservice').then(function(data) {
  44605. * // use the loaded data
  44606. * }).otherwise(function(error) {
  44607. * // an error occurred
  44608. * });
  44609. *
  44610. * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
  44611. */
  44612. function loadJsonp(url, options) {
  44613. if (!defined(url)) {
  44614. throw new DeveloperError('url is required.');
  44615. }
  44616. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  44617. //generate a unique function name
  44618. var functionName;
  44619. do {
  44620. functionName = 'loadJsonp' + Math.random().toString().substring(2, 8);
  44621. } while (defined(window[functionName]));
  44622. var deferred = when.defer();
  44623. //assign a function with that name in the global scope
  44624. window[functionName] = function(data) {
  44625. deferred.resolve(data);
  44626. try {
  44627. delete window[functionName];
  44628. } catch (e) {
  44629. window[functionName] = undefined;
  44630. }
  44631. };
  44632. var uri = new Uri(url);
  44633. var queryOptions = queryToObject(defaultValue(uri.query, ''));
  44634. if (defined(options.parameters)) {
  44635. queryOptions = combine(options.parameters, queryOptions);
  44636. }
  44637. var callbackParameterName = defaultValue(options.callbackParameterName, 'callback');
  44638. queryOptions[callbackParameterName] = functionName;
  44639. uri.query = objectToQuery(queryOptions);
  44640. url = uri.toString();
  44641. var proxy = options.proxy;
  44642. if (defined(proxy)) {
  44643. url = proxy.getURL(url);
  44644. }
  44645. loadJsonp.loadAndExecuteScript(url, functionName, deferred);
  44646. return deferred.promise;
  44647. }
  44648. // This is broken out into a separate function so that it can be mocked for testing purposes.
  44649. loadJsonp.loadAndExecuteScript = function(url, functionName, deferred) {
  44650. var script = document.createElement('script');
  44651. script.async = true;
  44652. script.src = url;
  44653. var head = document.getElementsByTagName('head')[0];
  44654. script.onload = function() {
  44655. script.onload = undefined;
  44656. head.removeChild(script);
  44657. };
  44658. script.onerror = function(e) {
  44659. deferred.reject(e);
  44660. };
  44661. head.appendChild(script);
  44662. };
  44663. loadJsonp.defaultLoadAndExecuteScript = loadJsonp.loadAndExecuteScript;
  44664. return loadJsonp;
  44665. });
  44666. /*global define*/
  44667. define('Core/loadXML',[
  44668. './loadWithXhr'
  44669. ], function(
  44670. loadWithXhr) {
  44671. 'use strict';
  44672. /**
  44673. * Asynchronously loads the given URL as XML. Returns a promise that will resolve to
  44674. * an XML Document once loaded, or reject if the URL failed to load. The data is loaded
  44675. * using XMLHttpRequest, which means that in order to make requests to another origin,
  44676. * the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
  44677. *
  44678. * @exports loadXML
  44679. *
  44680. * @param {String|Promise.<String>} url The URL to request, or a promise for the URL.
  44681. * @param {Object} [headers] HTTP headers to send with the request.
  44682. * @returns {Promise.<XMLDocument>} a promise that will resolve to the requested data when loaded.
  44683. *
  44684. *
  44685. * @example
  44686. * // load XML from a URL, setting a custom header
  44687. * Cesium.loadXML('http://someUrl.com/someXML.xml', {
  44688. * 'X-Custom-Header' : 'some value'
  44689. * }).then(function(document) {
  44690. * // Do something with the document
  44691. * }).otherwise(function(error) {
  44692. * // an error occurred
  44693. * });
  44694. *
  44695. * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest|XMLHttpRequest}
  44696. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  44697. * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
  44698. */
  44699. function loadXML(url, headers) {
  44700. return loadWithXhr({
  44701. url : url,
  44702. responseType : 'document',
  44703. headers : headers,
  44704. overrideMimeType : 'text/xml'
  44705. });
  44706. }
  44707. return loadXML;
  44708. });
  44709. /*global define*/
  44710. define('Core/MapboxApi',[
  44711. './defined',
  44712. './Credit'
  44713. ], function(
  44714. defined,
  44715. Credit) {
  44716. 'use strict';
  44717. var MapboxApi = {
  44718. };
  44719. /**
  44720. * The default Mapbox API access token to use if one is not provided to the
  44721. * constructor of an object that uses the Mapbox API. If this property is undefined,
  44722. * Cesium's default access token is used, which is only suitable for use early in development.
  44723. * Please supply your own access token as soon as possible and prior to deployment.
  44724. * Visit {@link https://www.mapbox.com/help/create-api-access-token/} for details.
  44725. * When Cesium's default access token is used, a message is printed to the console the first
  44726. * time the Mapbox API is used.
  44727. *
  44728. * @type {String}
  44729. */
  44730. MapboxApi.defaultAccessToken = undefined;
  44731. var printedMapboxWarning = false;
  44732. var errorCredit;
  44733. var errorString = 'This application is using Cesium\'s default Mapbox access token. Please create a new access token for the application as soon as possible and prior to deployment by visiting https://www.mapbox.com/account/apps/, and provide your token to Cesium by setting the Cesium.MapboxApi.defaultAccessToken property before constructing the CesiumWidget or any other object that uses the Mapbox API.';
  44734. MapboxApi.getAccessToken = function(providedToken) {
  44735. if (defined(providedToken)) {
  44736. return providedToken;
  44737. }
  44738. if (!defined(MapboxApi.defaultAccessToken)) {
  44739. if (!printedMapboxWarning) {
  44740. console.log(errorString);
  44741. printedMapboxWarning = true;
  44742. }
  44743. return 'pk.eyJ1IjoiYW5hbHl0aWNhbGdyYXBoaWNzIiwiYSI6ImNpd204Zm4wejAwNzYyeW5uNjYyZmFwdWEifQ.7i-VIZZWX8pd1bTfxIVj9g';
  44744. }
  44745. return MapboxApi.defaultAccessToken;
  44746. };
  44747. MapboxApi.getErrorCredit = function(providedToken) {
  44748. if (defined(providedToken) || defined(MapboxApi.defaultAccessToken)) {
  44749. return undefined;
  44750. }
  44751. if (!defined(errorCredit)) {
  44752. errorCredit = new Credit(errorString);
  44753. }
  44754. return errorCredit;
  44755. };
  44756. return MapboxApi;
  44757. });
  44758. /*global define*/
  44759. define('Core/MapProjection',[
  44760. './defineProperties',
  44761. './DeveloperError'
  44762. ], function(
  44763. defineProperties,
  44764. DeveloperError) {
  44765. 'use strict';
  44766. /**
  44767. * Defines how geodetic ellipsoid coordinates ({@link Cartographic}) project to a
  44768. * flat map like Cesium's 2D and Columbus View modes.
  44769. *
  44770. * @alias MapProjection
  44771. * @constructor
  44772. *
  44773. * @see GeographicProjection
  44774. * @see WebMercatorProjection
  44775. */
  44776. function MapProjection() {
  44777. DeveloperError.throwInstantiationError();
  44778. }
  44779. defineProperties(MapProjection.prototype, {
  44780. /**
  44781. * Gets the {@link Ellipsoid}.
  44782. *
  44783. * @memberof MapProjection.prototype
  44784. *
  44785. * @type {Ellipsoid}
  44786. * @readonly
  44787. */
  44788. ellipsoid : {
  44789. get : DeveloperError.throwInstantiationError
  44790. }
  44791. });
  44792. /**
  44793. * Projects {@link Cartographic} coordinates, in radians, to projection-specific map coordinates, in meters.
  44794. *
  44795. * @memberof MapProjection
  44796. * @function
  44797. *
  44798. * @param {Cartographic} cartographic The coordinates to project.
  44799. * @param {Cartesian3} [result] An instance into which to copy the result. If this parameter is
  44800. * undefined, a new instance is created and returned.
  44801. * @returns {Cartesian3} The projected coordinates. If the result parameter is not undefined, the
  44802. * coordinates are copied there and that instance is returned. Otherwise, a new instance is
  44803. * created and returned.
  44804. */
  44805. MapProjection.prototype.project = DeveloperError.throwInstantiationError;
  44806. /**
  44807. * Unprojects projection-specific map {@link Cartesian3} coordinates, in meters, to {@link Cartographic}
  44808. * coordinates, in radians.
  44809. *
  44810. * @memberof MapProjection
  44811. * @function
  44812. *
  44813. * @param {Cartesian3} cartesian The Cartesian position to unproject with height (z) in meters.
  44814. * @param {Cartographic} [result] An instance into which to copy the result. If this parameter is
  44815. * undefined, a new instance is created and returned.
  44816. * @returns {Cartographic} The unprojected coordinates. If the result parameter is not undefined, the
  44817. * coordinates are copied there and that instance is returned. Otherwise, a new instance is
  44818. * created and returned.
  44819. */
  44820. MapProjection.prototype.unproject = DeveloperError.throwInstantiationError;
  44821. return MapProjection;
  44822. });
  44823. /*global define*/
  44824. define('Core/Matrix2',[
  44825. './Cartesian2',
  44826. './defaultValue',
  44827. './defined',
  44828. './defineProperties',
  44829. './DeveloperError',
  44830. './freezeObject'
  44831. ], function(
  44832. Cartesian2,
  44833. defaultValue,
  44834. defined,
  44835. defineProperties,
  44836. DeveloperError,
  44837. freezeObject) {
  44838. 'use strict';
  44839. /**
  44840. * A 2x2 matrix, indexable as a column-major order array.
  44841. * Constructor parameters are in row-major order for code readability.
  44842. * @alias Matrix2
  44843. * @constructor
  44844. *
  44845. * @param {Number} [column0Row0=0.0] The value for column 0, row 0.
  44846. * @param {Number} [column1Row0=0.0] The value for column 1, row 0.
  44847. * @param {Number} [column0Row1=0.0] The value for column 0, row 1.
  44848. * @param {Number} [column1Row1=0.0] The value for column 1, row 1.
  44849. *
  44850. * @see Matrix2.fromColumnMajorArray
  44851. * @see Matrix2.fromRowMajorArray
  44852. * @see Matrix2.fromScale
  44853. * @see Matrix2.fromUniformScale
  44854. * @see Matrix3
  44855. * @see Matrix4
  44856. */
  44857. function Matrix2(column0Row0, column1Row0, column0Row1, column1Row1) {
  44858. this[0] = defaultValue(column0Row0, 0.0);
  44859. this[1] = defaultValue(column0Row1, 0.0);
  44860. this[2] = defaultValue(column1Row0, 0.0);
  44861. this[3] = defaultValue(column1Row1, 0.0);
  44862. }
  44863. /**
  44864. * The number of elements used to pack the object into an array.
  44865. * @type {Number}
  44866. */
  44867. Matrix2.packedLength = 4;
  44868. /**
  44869. * Stores the provided instance into the provided array.
  44870. *
  44871. * @param {Matrix2} value The value to pack.
  44872. * @param {Number[]} array The array to pack into.
  44873. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  44874. *
  44875. * @returns {Number[]} The array that was packed into
  44876. */
  44877. Matrix2.pack = function(value, array, startingIndex) {
  44878. if (!defined(value)) {
  44879. throw new DeveloperError('value is required');
  44880. }
  44881. if (!defined(array)) {
  44882. throw new DeveloperError('array is required');
  44883. }
  44884. startingIndex = defaultValue(startingIndex, 0);
  44885. array[startingIndex++] = value[0];
  44886. array[startingIndex++] = value[1];
  44887. array[startingIndex++] = value[2];
  44888. array[startingIndex++] = value[3];
  44889. return array;
  44890. };
  44891. /**
  44892. * Retrieves an instance from a packed array.
  44893. *
  44894. * @param {Number[]} array The packed array.
  44895. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  44896. * @param {Matrix2} [result] The object into which to store the result.
  44897. * @returns {Matrix2} The modified result parameter or a new Matrix2 instance if one was not provided.
  44898. */
  44899. Matrix2.unpack = function(array, startingIndex, result) {
  44900. if (!defined(array)) {
  44901. throw new DeveloperError('array is required');
  44902. }
  44903. startingIndex = defaultValue(startingIndex, 0);
  44904. if (!defined(result)) {
  44905. result = new Matrix2();
  44906. }
  44907. result[0] = array[startingIndex++];
  44908. result[1] = array[startingIndex++];
  44909. result[2] = array[startingIndex++];
  44910. result[3] = array[startingIndex++];
  44911. return result;
  44912. };
  44913. /**
  44914. * Duplicates a Matrix2 instance.
  44915. *
  44916. * @param {Matrix2} matrix The matrix to duplicate.
  44917. * @param {Matrix2} [result] The object onto which to store the result.
  44918. * @returns {Matrix2} The modified result parameter or a new Matrix2 instance if one was not provided. (Returns undefined if matrix is undefined)
  44919. */
  44920. Matrix2.clone = function(values, result) {
  44921. if (!defined(values)) {
  44922. return undefined;
  44923. }
  44924. if (!defined(result)) {
  44925. return new Matrix2(values[0], values[2],
  44926. values[1], values[3]);
  44927. }
  44928. result[0] = values[0];
  44929. result[1] = values[1];
  44930. result[2] = values[2];
  44931. result[3] = values[3];
  44932. return result;
  44933. };
  44934. /**
  44935. * Creates a Matrix2 from 4 consecutive elements in an array.
  44936. *
  44937. * @param {Number[]} array The array whose 4 consecutive elements correspond to the positions of the matrix. Assumes column-major order.
  44938. * @param {Number} [startingIndex=0] The offset into the array of the first element, which corresponds to first column first row position in the matrix.
  44939. * @param {Matrix2} [result] The object onto which to store the result.
  44940. * @returns {Matrix2} The modified result parameter or a new Matrix2 instance if one was not provided.
  44941. *
  44942. * @example
  44943. * // Create the Matrix2:
  44944. * // [1.0, 2.0]
  44945. * // [1.0, 2.0]
  44946. *
  44947. * var v = [1.0, 1.0, 2.0, 2.0];
  44948. * var m = Cesium.Matrix2.fromArray(v);
  44949. *
  44950. * // Create same Matrix2 with using an offset into an array
  44951. * var v2 = [0.0, 0.0, 1.0, 1.0, 2.0, 2.0];
  44952. * var m2 = Cesium.Matrix2.fromArray(v2, 2);
  44953. */
  44954. Matrix2.fromArray = function(array, startingIndex, result) {
  44955. if (!defined(array)) {
  44956. throw new DeveloperError('array is required');
  44957. }
  44958. startingIndex = defaultValue(startingIndex, 0);
  44959. if (!defined(result)) {
  44960. result = new Matrix2();
  44961. }
  44962. result[0] = array[startingIndex];
  44963. result[1] = array[startingIndex + 1];
  44964. result[2] = array[startingIndex + 2];
  44965. result[3] = array[startingIndex + 3];
  44966. return result;
  44967. };
  44968. /**
  44969. * Creates a Matrix2 instance from a column-major order array.
  44970. *
  44971. * @param {Number[]} values The column-major order array.
  44972. * @param {Matrix2} [result] The object in which the result will be stored, if undefined a new instance will be created.
  44973. * @returns {Matrix2} The modified result parameter, or a new Matrix2 instance if one was not provided.
  44974. */
  44975. Matrix2.fromColumnMajorArray = function(values, result) {
  44976. if (!defined(values)) {
  44977. throw new DeveloperError('values parameter is required');
  44978. }
  44979. return Matrix2.clone(values, result);
  44980. };
  44981. /**
  44982. * Creates a Matrix2 instance from a row-major order array.
  44983. * The resulting matrix will be in column-major order.
  44984. *
  44985. * @param {Number[]} values The row-major order array.
  44986. * @param {Matrix2} [result] The object in which the result will be stored, if undefined a new instance will be created.
  44987. * @returns {Matrix2} The modified result parameter, or a new Matrix2 instance if one was not provided.
  44988. */
  44989. Matrix2.fromRowMajorArray = function(values, result) {
  44990. if (!defined(values)) {
  44991. throw new DeveloperError('values is required.');
  44992. }
  44993. if (!defined(result)) {
  44994. return new Matrix2(values[0], values[1],
  44995. values[2], values[3]);
  44996. }
  44997. result[0] = values[0];
  44998. result[1] = values[2];
  44999. result[2] = values[1];
  45000. result[3] = values[3];
  45001. return result;
  45002. };
  45003. /**
  45004. * Computes a Matrix2 instance representing a non-uniform scale.
  45005. *
  45006. * @param {Cartesian2} scale The x and y scale factors.
  45007. * @param {Matrix2} [result] The object in which the result will be stored, if undefined a new instance will be created.
  45008. * @returns {Matrix2} The modified result parameter, or a new Matrix2 instance if one was not provided.
  45009. *
  45010. * @example
  45011. * // Creates
  45012. * // [7.0, 0.0]
  45013. * // [0.0, 8.0]
  45014. * var m = Cesium.Matrix2.fromScale(new Cesium.Cartesian2(7.0, 8.0));
  45015. */
  45016. Matrix2.fromScale = function(scale, result) {
  45017. if (!defined(scale)) {
  45018. throw new DeveloperError('scale is required.');
  45019. }
  45020. if (!defined(result)) {
  45021. return new Matrix2(
  45022. scale.x, 0.0,
  45023. 0.0, scale.y);
  45024. }
  45025. result[0] = scale.x;
  45026. result[1] = 0.0;
  45027. result[2] = 0.0;
  45028. result[3] = scale.y;
  45029. return result;
  45030. };
  45031. /**
  45032. * Computes a Matrix2 instance representing a uniform scale.
  45033. *
  45034. * @param {Number} scale The uniform scale factor.
  45035. * @param {Matrix2} [result] The object in which the result will be stored, if undefined a new instance will be created.
  45036. * @returns {Matrix2} The modified result parameter, or a new Matrix2 instance if one was not provided.
  45037. *
  45038. * @example
  45039. * // Creates
  45040. * // [2.0, 0.0]
  45041. * // [0.0, 2.0]
  45042. * var m = Cesium.Matrix2.fromUniformScale(2.0);
  45043. */
  45044. Matrix2.fromUniformScale = function(scale, result) {
  45045. if (typeof scale !== 'number') {
  45046. throw new DeveloperError('scale is required.');
  45047. }
  45048. if (!defined(result)) {
  45049. return new Matrix2(
  45050. scale, 0.0,
  45051. 0.0, scale);
  45052. }
  45053. result[0] = scale;
  45054. result[1] = 0.0;
  45055. result[2] = 0.0;
  45056. result[3] = scale;
  45057. return result;
  45058. };
  45059. /**
  45060. * Creates a rotation matrix.
  45061. *
  45062. * @param {Number} angle The angle, in radians, of the rotation. Positive angles are counterclockwise.
  45063. * @param {Matrix2} [result] The object in which the result will be stored, if undefined a new instance will be created.
  45064. * @returns {Matrix2} The modified result parameter, or a new Matrix2 instance if one was not provided.
  45065. *
  45066. * @example
  45067. * // Rotate a point 45 degrees counterclockwise.
  45068. * var p = new Cesium.Cartesian2(5, 6);
  45069. * var m = Cesium.Matrix2.fromRotation(Cesium.Math.toRadians(45.0));
  45070. * var rotated = Cesium.Matrix2.multiplyByVector(m, p, new Cesium.Cartesian2());
  45071. */
  45072. Matrix2.fromRotation = function(angle, result) {
  45073. if (!defined(angle)) {
  45074. throw new DeveloperError('angle is required.');
  45075. }
  45076. var cosAngle = Math.cos(angle);
  45077. var sinAngle = Math.sin(angle);
  45078. if (!defined(result)) {
  45079. return new Matrix2(
  45080. cosAngle, -sinAngle,
  45081. sinAngle, cosAngle);
  45082. }
  45083. result[0] = cosAngle;
  45084. result[1] = sinAngle;
  45085. result[2] = -sinAngle;
  45086. result[3] = cosAngle;
  45087. return result;
  45088. };
  45089. /**
  45090. * Creates an Array from the provided Matrix2 instance.
  45091. * The array will be in column-major order.
  45092. *
  45093. * @param {Matrix2} matrix The matrix to use..
  45094. * @param {Number[]} [result] The Array onto which to store the result.
  45095. * @returns {Number[]} The modified Array parameter or a new Array instance if one was not provided.
  45096. */
  45097. Matrix2.toArray = function(matrix, result) {
  45098. if (!defined(matrix)) {
  45099. throw new DeveloperError('matrix is required');
  45100. }
  45101. if (!defined(result)) {
  45102. return [matrix[0], matrix[1], matrix[2], matrix[3]];
  45103. }
  45104. result[0] = matrix[0];
  45105. result[1] = matrix[1];
  45106. result[2] = matrix[2];
  45107. result[3] = matrix[3];
  45108. return result;
  45109. };
  45110. /**
  45111. * Computes the array index of the element at the provided row and column.
  45112. *
  45113. * @param {Number} row The zero-based index of the row.
  45114. * @param {Number} column The zero-based index of the column.
  45115. * @returns {Number} The index of the element at the provided row and column.
  45116. *
  45117. * @exception {DeveloperError} row must be 0 or 1.
  45118. * @exception {DeveloperError} column must be 0 or 1.
  45119. *
  45120. * @example
  45121. * var myMatrix = new Cesium.Matrix2();
  45122. * var column1Row0Index = Cesium.Matrix2.getElementIndex(1, 0);
  45123. * var column1Row0 = myMatrix[column1Row0Index]
  45124. * myMatrix[column1Row0Index] = 10.0;
  45125. */
  45126. Matrix2.getElementIndex = function(column, row) {
  45127. if (typeof row !== 'number' || row < 0 || row > 1) {
  45128. throw new DeveloperError('row must be 0 or 1.');
  45129. }
  45130. if (typeof column !== 'number' || column < 0 || column > 1) {
  45131. throw new DeveloperError('column must be 0 or 1.');
  45132. }
  45133. return column * 2 + row;
  45134. };
  45135. /**
  45136. * Retrieves a copy of the matrix column at the provided index as a Cartesian2 instance.
  45137. *
  45138. * @param {Matrix2} matrix The matrix to use.
  45139. * @param {Number} index The zero-based index of the column to retrieve.
  45140. * @param {Cartesian2} result The object onto which to store the result.
  45141. * @returns {Cartesian2} The modified result parameter.
  45142. *
  45143. * @exception {DeveloperError} index must be 0 or 1.
  45144. */
  45145. Matrix2.getColumn = function(matrix, index, result) {
  45146. if (!defined(matrix)) {
  45147. throw new DeveloperError('matrix is required.');
  45148. }
  45149. if (typeof index !== 'number' || index < 0 || index > 1) {
  45150. throw new DeveloperError('index must be 0 or 1.');
  45151. }
  45152. if (!defined(result)) {
  45153. throw new DeveloperError('result is required');
  45154. }
  45155. var startIndex = index * 2;
  45156. var x = matrix[startIndex];
  45157. var y = matrix[startIndex + 1];
  45158. result.x = x;
  45159. result.y = y;
  45160. return result;
  45161. };
  45162. /**
  45163. * Computes a new matrix that replaces the specified column in the provided matrix with the provided Cartesian2 instance.
  45164. *
  45165. * @param {Matrix2} matrix The matrix to use.
  45166. * @param {Number} index The zero-based index of the column to set.
  45167. * @param {Cartesian2} cartesian The Cartesian whose values will be assigned to the specified column.
  45168. * @param {Cartesian2} result The object onto which to store the result.
  45169. * @returns {Matrix2} The modified result parameter.
  45170. *
  45171. * @exception {DeveloperError} index must be 0 or 1.
  45172. */
  45173. Matrix2.setColumn = function(matrix, index, cartesian, result) {
  45174. if (!defined(matrix)) {
  45175. throw new DeveloperError('matrix is required');
  45176. }
  45177. if (!defined(cartesian)) {
  45178. throw new DeveloperError('cartesian is required');
  45179. }
  45180. if (typeof index !== 'number' || index < 0 || index > 1) {
  45181. throw new DeveloperError('index must be 0 or 1.');
  45182. }
  45183. if (!defined(result)) {
  45184. throw new DeveloperError('result is required');
  45185. }
  45186. result = Matrix2.clone(matrix, result);
  45187. var startIndex = index * 2;
  45188. result[startIndex] = cartesian.x;
  45189. result[startIndex + 1] = cartesian.y;
  45190. return result;
  45191. };
  45192. /**
  45193. * Retrieves a copy of the matrix row at the provided index as a Cartesian2 instance.
  45194. *
  45195. * @param {Matrix2} matrix The matrix to use.
  45196. * @param {Number} index The zero-based index of the row to retrieve.
  45197. * @param {Cartesian2} result The object onto which to store the result.
  45198. * @returns {Cartesian2} The modified result parameter.
  45199. *
  45200. * @exception {DeveloperError} index must be 0 or 1.
  45201. */
  45202. Matrix2.getRow = function(matrix, index, result) {
  45203. if (!defined(matrix)) {
  45204. throw new DeveloperError('matrix is required.');
  45205. }
  45206. if (typeof index !== 'number' || index < 0 || index > 1) {
  45207. throw new DeveloperError('index must be 0 or 1.');
  45208. }
  45209. if (!defined(result)) {
  45210. throw new DeveloperError('result is required');
  45211. }
  45212. var x = matrix[index];
  45213. var y = matrix[index + 2];
  45214. result.x = x;
  45215. result.y = y;
  45216. return result;
  45217. };
  45218. /**
  45219. * Computes a new matrix that replaces the specified row in the provided matrix with the provided Cartesian2 instance.
  45220. *
  45221. * @param {Matrix2} matrix The matrix to use.
  45222. * @param {Number} index The zero-based index of the row to set.
  45223. * @param {Cartesian2} cartesian The Cartesian whose values will be assigned to the specified row.
  45224. * @param {Matrix2} result The object onto which to store the result.
  45225. * @returns {Matrix2} The modified result parameter.
  45226. *
  45227. * @exception {DeveloperError} index must be 0 or 1.
  45228. */
  45229. Matrix2.setRow = function(matrix, index, cartesian, result) {
  45230. if (!defined(matrix)) {
  45231. throw new DeveloperError('matrix is required');
  45232. }
  45233. if (!defined(cartesian)) {
  45234. throw new DeveloperError('cartesian is required');
  45235. }
  45236. if (typeof index !== 'number' || index < 0 || index > 1) {
  45237. throw new DeveloperError('index must be 0 or 1.');
  45238. }
  45239. if (!defined(result)) {
  45240. throw new DeveloperError('result is required');
  45241. }
  45242. result = Matrix2.clone(matrix, result);
  45243. result[index] = cartesian.x;
  45244. result[index + 2] = cartesian.y;
  45245. return result;
  45246. };
  45247. var scratchColumn = new Cartesian2();
  45248. /**
  45249. * Extracts the non-uniform scale assuming the matrix is an affine transformation.
  45250. *
  45251. * @param {Matrix2} matrix The matrix.
  45252. * @param {Cartesian2} result The object onto which to store the result.
  45253. * @returns {Cartesian2} The modified result parameter.
  45254. */
  45255. Matrix2.getScale = function(matrix, result) {
  45256. if (!defined(matrix)) {
  45257. throw new DeveloperError('matrix is required.');
  45258. }
  45259. if (!defined(result)) {
  45260. throw new DeveloperError('result is required');
  45261. }
  45262. result.x = Cartesian2.magnitude(Cartesian2.fromElements(matrix[0], matrix[1], scratchColumn));
  45263. result.y = Cartesian2.magnitude(Cartesian2.fromElements(matrix[2], matrix[3], scratchColumn));
  45264. return result;
  45265. };
  45266. var scratchScale = new Cartesian2();
  45267. /**
  45268. * Computes the maximum scale assuming the matrix is an affine transformation.
  45269. * The maximum scale is the maximum length of the column vectors.
  45270. *
  45271. * @param {Matrix2} matrix The matrix.
  45272. * @returns {Number} The maximum scale.
  45273. */
  45274. Matrix2.getMaximumScale = function(matrix) {
  45275. Matrix2.getScale(matrix, scratchScale);
  45276. return Cartesian2.maximumComponent(scratchScale);
  45277. };
  45278. /**
  45279. * Computes the product of two matrices.
  45280. *
  45281. * @param {Matrix2} left The first matrix.
  45282. * @param {Matrix2} right The second matrix.
  45283. * @param {Matrix2} result The object onto which to store the result.
  45284. * @returns {Matrix2} The modified result parameter.
  45285. */
  45286. Matrix2.multiply = function(left, right, result) {
  45287. if (!defined(left)) {
  45288. throw new DeveloperError('left is required');
  45289. }
  45290. if (!defined(right)) {
  45291. throw new DeveloperError('right is required');
  45292. }
  45293. if (!defined(result)) {
  45294. throw new DeveloperError('result is required');
  45295. }
  45296. var column0Row0 = left[0] * right[0] + left[2] * right[1];
  45297. var column1Row0 = left[0] * right[2] + left[2] * right[3];
  45298. var column0Row1 = left[1] * right[0] + left[3] * right[1];
  45299. var column1Row1 = left[1] * right[2] + left[3] * right[3];
  45300. result[0] = column0Row0;
  45301. result[1] = column0Row1;
  45302. result[2] = column1Row0;
  45303. result[3] = column1Row1;
  45304. return result;
  45305. };
  45306. /**
  45307. * Computes the sum of two matrices.
  45308. *
  45309. * @param {Matrix2} left The first matrix.
  45310. * @param {Matrix2} right The second matrix.
  45311. * @param {Matrix2} result The object onto which to store the result.
  45312. * @returns {Matrix2} The modified result parameter.
  45313. */
  45314. Matrix2.add = function(left, right, result) {
  45315. if (!defined(left)) {
  45316. throw new DeveloperError('left is required');
  45317. }
  45318. if (!defined(right)) {
  45319. throw new DeveloperError('right is required');
  45320. }
  45321. if (!defined(result)) {
  45322. throw new DeveloperError('result is required');
  45323. }
  45324. result[0] = left[0] + right[0];
  45325. result[1] = left[1] + right[1];
  45326. result[2] = left[2] + right[2];
  45327. result[3] = left[3] + right[3];
  45328. return result;
  45329. };
  45330. /**
  45331. * Computes the difference of two matrices.
  45332. *
  45333. * @param {Matrix2} left The first matrix.
  45334. * @param {Matrix2} right The second matrix.
  45335. * @param {Matrix2} result The object onto which to store the result.
  45336. * @returns {Matrix2} The modified result parameter.
  45337. */
  45338. Matrix2.subtract = function(left, right, result) {
  45339. if (!defined(left)) {
  45340. throw new DeveloperError('left is required');
  45341. }
  45342. if (!defined(right)) {
  45343. throw new DeveloperError('right is required');
  45344. }
  45345. if (!defined(result)) {
  45346. throw new DeveloperError('result is required');
  45347. }
  45348. result[0] = left[0] - right[0];
  45349. result[1] = left[1] - right[1];
  45350. result[2] = left[2] - right[2];
  45351. result[3] = left[3] - right[3];
  45352. return result;
  45353. };
  45354. /**
  45355. * Computes the product of a matrix and a column vector.
  45356. *
  45357. * @param {Matrix2} matrix The matrix.
  45358. * @param {Cartesian2} cartesian The column.
  45359. * @param {Cartesian2} result The object onto which to store the result.
  45360. * @returns {Cartesian2} The modified result parameter.
  45361. */
  45362. Matrix2.multiplyByVector = function(matrix, cartesian, result) {
  45363. if (!defined(matrix)) {
  45364. throw new DeveloperError('matrix is required');
  45365. }
  45366. if (!defined(cartesian)) {
  45367. throw new DeveloperError('cartesian is required');
  45368. }
  45369. if (!defined(result)) {
  45370. throw new DeveloperError('result is required');
  45371. }
  45372. var x = matrix[0] * cartesian.x + matrix[2] * cartesian.y;
  45373. var y = matrix[1] * cartesian.x + matrix[3] * cartesian.y;
  45374. result.x = x;
  45375. result.y = y;
  45376. return result;
  45377. };
  45378. /**
  45379. * Computes the product of a matrix and a scalar.
  45380. *
  45381. * @param {Matrix2} matrix The matrix.
  45382. * @param {Number} scalar The number to multiply by.
  45383. * @param {Matrix2} result The object onto which to store the result.
  45384. * @returns {Matrix2} The modified result parameter.
  45385. */
  45386. Matrix2.multiplyByScalar = function(matrix, scalar, result) {
  45387. if (!defined(matrix)) {
  45388. throw new DeveloperError('matrix is required');
  45389. }
  45390. if (typeof scalar !== 'number') {
  45391. throw new DeveloperError('scalar is required and must be a number');
  45392. }
  45393. if (!defined(result)) {
  45394. throw new DeveloperError('result is required');
  45395. }
  45396. result[0] = matrix[0] * scalar;
  45397. result[1] = matrix[1] * scalar;
  45398. result[2] = matrix[2] * scalar;
  45399. result[3] = matrix[3] * scalar;
  45400. return result;
  45401. };
  45402. /**
  45403. * Computes the product of a matrix times a (non-uniform) scale, as if the scale were a scale matrix.
  45404. *
  45405. * @param {Matrix2} matrix The matrix on the left-hand side.
  45406. * @param {Cartesian2} scale The non-uniform scale on the right-hand side.
  45407. * @param {Matrix2} result The object onto which to store the result.
  45408. * @returns {Matrix2} The modified result parameter.
  45409. *
  45410. *
  45411. * @example
  45412. * // Instead of Cesium.Matrix2.multiply(m, Cesium.Matrix2.fromScale(scale), m);
  45413. * Cesium.Matrix2.multiplyByScale(m, scale, m);
  45414. *
  45415. * @see Matrix2.fromScale
  45416. * @see Matrix2.multiplyByUniformScale
  45417. */
  45418. Matrix2.multiplyByScale = function(matrix, scale, result) {
  45419. if (!defined(matrix)) {
  45420. throw new DeveloperError('matrix is required');
  45421. }
  45422. if (!defined(scale)) {
  45423. throw new DeveloperError('scale is required');
  45424. }
  45425. if (!defined(result)) {
  45426. throw new DeveloperError('result is required');
  45427. }
  45428. result[0] = matrix[0] * scale.x;
  45429. result[1] = matrix[1] * scale.x;
  45430. result[2] = matrix[2] * scale.y;
  45431. result[3] = matrix[3] * scale.y;
  45432. return result;
  45433. };
  45434. /**
  45435. * Creates a negated copy of the provided matrix.
  45436. *
  45437. * @param {Matrix2} matrix The matrix to negate.
  45438. * @param {Matrix2} result The object onto which to store the result.
  45439. * @returns {Matrix2} The modified result parameter.
  45440. */
  45441. Matrix2.negate = function(matrix, result) {
  45442. if (!defined(matrix)) {
  45443. throw new DeveloperError('matrix is required');
  45444. }
  45445. if (!defined(result)) {
  45446. throw new DeveloperError('result is required');
  45447. }
  45448. result[0] = -matrix[0];
  45449. result[1] = -matrix[1];
  45450. result[2] = -matrix[2];
  45451. result[3] = -matrix[3];
  45452. return result;
  45453. };
  45454. /**
  45455. * Computes the transpose of the provided matrix.
  45456. *
  45457. * @param {Matrix2} matrix The matrix to transpose.
  45458. * @param {Matrix2} result The object onto which to store the result.
  45459. * @returns {Matrix2} The modified result parameter.
  45460. */
  45461. Matrix2.transpose = function(matrix, result) {
  45462. if (!defined(matrix)) {
  45463. throw new DeveloperError('matrix is required');
  45464. }
  45465. if (!defined(result)) {
  45466. throw new DeveloperError('result is required');
  45467. }
  45468. var column0Row0 = matrix[0];
  45469. var column0Row1 = matrix[2];
  45470. var column1Row0 = matrix[1];
  45471. var column1Row1 = matrix[3];
  45472. result[0] = column0Row0;
  45473. result[1] = column0Row1;
  45474. result[2] = column1Row0;
  45475. result[3] = column1Row1;
  45476. return result;
  45477. };
  45478. /**
  45479. * Computes a matrix, which contains the absolute (unsigned) values of the provided matrix's elements.
  45480. *
  45481. * @param {Matrix2} matrix The matrix with signed elements.
  45482. * @param {Matrix2} result The object onto which to store the result.
  45483. * @returns {Matrix2} The modified result parameter.
  45484. */
  45485. Matrix2.abs = function(matrix, result) {
  45486. if (!defined(matrix)) {
  45487. throw new DeveloperError('matrix is required');
  45488. }
  45489. if (!defined(result)) {
  45490. throw new DeveloperError('result is required');
  45491. }
  45492. result[0] = Math.abs(matrix[0]);
  45493. result[1] = Math.abs(matrix[1]);
  45494. result[2] = Math.abs(matrix[2]);
  45495. result[3] = Math.abs(matrix[3]);
  45496. return result;
  45497. };
  45498. /**
  45499. * Compares the provided matrices componentwise and returns
  45500. * <code>true</code> if they are equal, <code>false</code> otherwise.
  45501. *
  45502. * @param {Matrix2} [left] The first matrix.
  45503. * @param {Matrix2} [right] The second matrix.
  45504. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  45505. */
  45506. Matrix2.equals = function(left, right) {
  45507. return (left === right) ||
  45508. (defined(left) &&
  45509. defined(right) &&
  45510. left[0] === right[0] &&
  45511. left[1] === right[1] &&
  45512. left[2] === right[2] &&
  45513. left[3] === right[3]);
  45514. };
  45515. /**
  45516. * @private
  45517. */
  45518. Matrix2.equalsArray = function(matrix, array, offset) {
  45519. return matrix[0] === array[offset] &&
  45520. matrix[1] === array[offset + 1] &&
  45521. matrix[2] === array[offset + 2] &&
  45522. matrix[3] === array[offset + 3];
  45523. };
  45524. /**
  45525. * Compares the provided matrices componentwise and returns
  45526. * <code>true</code> if they are within the provided epsilon,
  45527. * <code>false</code> otherwise.
  45528. *
  45529. * @param {Matrix2} [left] The first matrix.
  45530. * @param {Matrix2} [right] The second matrix.
  45531. * @param {Number} epsilon The epsilon to use for equality testing.
  45532. * @returns {Boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
  45533. */
  45534. Matrix2.equalsEpsilon = function(left, right, epsilon) {
  45535. if (typeof epsilon !== 'number') {
  45536. throw new DeveloperError('epsilon must be a number');
  45537. }
  45538. return (left === right) ||
  45539. (defined(left) &&
  45540. defined(right) &&
  45541. Math.abs(left[0] - right[0]) <= epsilon &&
  45542. Math.abs(left[1] - right[1]) <= epsilon &&
  45543. Math.abs(left[2] - right[2]) <= epsilon &&
  45544. Math.abs(left[3] - right[3]) <= epsilon);
  45545. };
  45546. /**
  45547. * An immutable Matrix2 instance initialized to the identity matrix.
  45548. *
  45549. * @type {Matrix2}
  45550. * @constant
  45551. */
  45552. Matrix2.IDENTITY = freezeObject(new Matrix2(1.0, 0.0,
  45553. 0.0, 1.0));
  45554. /**
  45555. * An immutable Matrix2 instance initialized to the zero matrix.
  45556. *
  45557. * @type {Matrix2}
  45558. * @constant
  45559. */
  45560. Matrix2.ZERO = freezeObject(new Matrix2(0.0, 0.0,
  45561. 0.0, 0.0));
  45562. /**
  45563. * The index into Matrix2 for column 0, row 0.
  45564. *
  45565. * @type {Number}
  45566. * @constant
  45567. *
  45568. * @example
  45569. * var matrix = new Cesium.Matrix2();
  45570. * matrix[Cesium.Matrix2.COLUMN0ROW0] = 5.0; // set column 0, row 0 to 5.0
  45571. */
  45572. Matrix2.COLUMN0ROW0 = 0;
  45573. /**
  45574. * The index into Matrix2 for column 0, row 1.
  45575. *
  45576. * @type {Number}
  45577. * @constant
  45578. *
  45579. * @example
  45580. * var matrix = new Cesium.Matrix2();
  45581. * matrix[Cesium.Matrix2.COLUMN0ROW1] = 5.0; // set column 0, row 1 to 5.0
  45582. */
  45583. Matrix2.COLUMN0ROW1 = 1;
  45584. /**
  45585. * The index into Matrix2 for column 1, row 0.
  45586. *
  45587. * @type {Number}
  45588. * @constant
  45589. *
  45590. * @example
  45591. * var matrix = new Cesium.Matrix2();
  45592. * matrix[Cesium.Matrix2.COLUMN1ROW0] = 5.0; // set column 1, row 0 to 5.0
  45593. */
  45594. Matrix2.COLUMN1ROW0 = 2;
  45595. /**
  45596. * The index into Matrix2 for column 1, row 1.
  45597. *
  45598. * @type {Number}
  45599. * @constant
  45600. *
  45601. * @example
  45602. * var matrix = new Cesium.Matrix2();
  45603. * matrix[Cesium.Matrix2.COLUMN1ROW1] = 5.0; // set column 1, row 1 to 5.0
  45604. */
  45605. Matrix2.COLUMN1ROW1 = 3;
  45606. defineProperties(Matrix2.prototype, {
  45607. /**
  45608. * Gets the number of items in the collection.
  45609. * @memberof Matrix2.prototype
  45610. *
  45611. * @type {Number}
  45612. */
  45613. length : {
  45614. get : function() {
  45615. return Matrix2.packedLength;
  45616. }
  45617. }
  45618. });
  45619. /**
  45620. * Duplicates the provided Matrix2 instance.
  45621. *
  45622. * @param {Matrix2} [result] The object onto which to store the result.
  45623. * @returns {Matrix2} The modified result parameter or a new Matrix2 instance if one was not provided.
  45624. */
  45625. Matrix2.prototype.clone = function(result) {
  45626. return Matrix2.clone(this, result);
  45627. };
  45628. /**
  45629. * Compares this matrix to the provided matrix componentwise and returns
  45630. * <code>true</code> if they are equal, <code>false</code> otherwise.
  45631. *
  45632. * @param {Matrix2} [right] The right hand side matrix.
  45633. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  45634. */
  45635. Matrix2.prototype.equals = function(right) {
  45636. return Matrix2.equals(this, right);
  45637. };
  45638. /**
  45639. * Compares this matrix to the provided matrix componentwise and returns
  45640. * <code>true</code> if they are within the provided epsilon,
  45641. * <code>false</code> otherwise.
  45642. *
  45643. * @param {Matrix2} [right] The right hand side matrix.
  45644. * @param {Number} epsilon The epsilon to use for equality testing.
  45645. * @returns {Boolean} <code>true</code> if they are within the provided epsilon, <code>false</code> otherwise.
  45646. */
  45647. Matrix2.prototype.equalsEpsilon = function(right, epsilon) {
  45648. return Matrix2.equalsEpsilon(this, right, epsilon);
  45649. };
  45650. /**
  45651. * Creates a string representing this Matrix with each row being
  45652. * on a separate line and in the format '(column0, column1)'.
  45653. *
  45654. * @returns {String} A string representing the provided Matrix with each row being on a separate line and in the format '(column0, column1)'.
  45655. */
  45656. Matrix2.prototype.toString = function() {
  45657. return '(' + this[0] + ', ' + this[2] + ')\n' +
  45658. '(' + this[1] + ', ' + this[3] + ')';
  45659. };
  45660. return Matrix2;
  45661. });
  45662. /*global define*/
  45663. define('Core/mergeSort',[
  45664. './defined',
  45665. './DeveloperError'
  45666. ], function(
  45667. defined,
  45668. DeveloperError) {
  45669. 'use strict';
  45670. var leftScratchArray = [];
  45671. var rightScratchArray = [];
  45672. function merge(array, compare, userDefinedObject, start, middle, end) {
  45673. var leftLength = middle - start + 1;
  45674. var rightLength = end - middle;
  45675. var left = leftScratchArray;
  45676. var right = rightScratchArray;
  45677. var i;
  45678. var j;
  45679. for (i = 0; i < leftLength; ++i) {
  45680. left[i] = array[start + i];
  45681. }
  45682. for (j = 0; j < rightLength; ++j) {
  45683. right[j] = array[middle + j + 1];
  45684. }
  45685. i = 0;
  45686. j = 0;
  45687. for (var k = start; k <= end; ++k) {
  45688. var leftElement = left[i];
  45689. var rightElement = right[j];
  45690. if (i < leftLength && (j >= rightLength || compare(leftElement, rightElement, userDefinedObject) <= 0)) {
  45691. array[k] = leftElement;
  45692. ++i;
  45693. } else if (j < rightLength) {
  45694. array[k] = rightElement;
  45695. ++j;
  45696. }
  45697. }
  45698. }
  45699. function sort(array, compare, userDefinedObject, start, end) {
  45700. if (start >= end) {
  45701. return;
  45702. }
  45703. var middle = Math.floor((start + end) * 0.5);
  45704. sort(array, compare, userDefinedObject, start, middle);
  45705. sort(array, compare, userDefinedObject, middle + 1, end);
  45706. merge(array, compare, userDefinedObject, start, middle, end);
  45707. }
  45708. /**
  45709. * A stable merge sort.
  45710. *
  45711. * @exports mergeSort
  45712. *
  45713. * @param {Array} array The array to sort.
  45714. * @param {mergeSort~Comparator} comparator The function to use to compare elements in the array.
  45715. * @param {Object} [userDefinedObject] An object to pass as the third parameter to <code>comparator</code>.
  45716. *
  45717. * @example
  45718. * // Assume array contains BoundingSpheres in world coordinates.
  45719. * // Sort them in ascending order of distance from the camera.
  45720. * var position = camera.positionWC;
  45721. * Cesium.mergeSort(array, function(a, b, position) {
  45722. * return Cesium.BoundingSphere.distanceSquaredTo(b, position) - Cesium.BoundingSphere.distanceSquaredTo(a, position);
  45723. * }, position);
  45724. */
  45725. function mergeSort(array, comparator, userDefinedObject) {
  45726. if (!defined(array)) {
  45727. throw new DeveloperError('array is required.');
  45728. }
  45729. if (!defined(comparator)) {
  45730. throw new DeveloperError('comparator is required.');
  45731. }
  45732. var length = array.length;
  45733. var scratchLength = Math.ceil(length * 0.5);
  45734. // preallocate space in scratch arrays
  45735. leftScratchArray.length = scratchLength;
  45736. rightScratchArray.length = scratchLength;
  45737. sort(array, comparator, userDefinedObject, 0, length - 1);
  45738. // trim scratch arrays
  45739. leftScratchArray.length = 0;
  45740. rightScratchArray.length = 0;
  45741. }
  45742. /**
  45743. * A function used to compare two items while performing a merge sort.
  45744. * @callback mergeSort~Comparator
  45745. *
  45746. * @param {Object} a An item in the array.
  45747. * @param {Object} b An item in the array.
  45748. * @param {Object} [userDefinedObject] An object that was passed to {@link mergeSort}.
  45749. * @returns {Number} Returns a negative value if <code>a</code> is less than <code>b</code>,
  45750. * a positive value if <code>a</code> is greater than <code>b</code>, or
  45751. * 0 if <code>a</code> is equal to <code>b</code>.
  45752. *
  45753. * @example
  45754. * function compareNumbers(a, b, userDefinedObject) {
  45755. * return a - b;
  45756. * }
  45757. */
  45758. return mergeSort;
  45759. });
  45760. /*global define*/
  45761. define('Core/NearFarScalar',[
  45762. './defaultValue',
  45763. './defined',
  45764. './DeveloperError'
  45765. ], function(
  45766. defaultValue,
  45767. defined,
  45768. DeveloperError) {
  45769. 'use strict';
  45770. /**
  45771. * Represents a scalar value's lower and upper bound at a near distance and far distance in eye space.
  45772. * @alias NearFarScalar
  45773. * @constructor
  45774. *
  45775. * @param {Number} [near=0.0] The lower bound of the camera range.
  45776. * @param {Number} [nearValue=0.0] The value at the lower bound of the camera range.
  45777. * @param {Number} [far=1.0] The upper bound of the camera range.
  45778. * @param {Number} [farValue=0.0] The value at the upper bound of the camera range.
  45779. *
  45780. * @see Packable
  45781. */
  45782. function NearFarScalar(near, nearValue, far, farValue) {
  45783. /**
  45784. * The lower bound of the camera range.
  45785. * @type {Number}
  45786. * @default 0.0
  45787. */
  45788. this.near = defaultValue(near, 0.0);
  45789. /**
  45790. * The value at the lower bound of the camera range.
  45791. * @type {Number}
  45792. * @default 0.0
  45793. */
  45794. this.nearValue = defaultValue(nearValue, 0.0);
  45795. /**
  45796. * The upper bound of the camera range.
  45797. * @type {Number}
  45798. * @default 1.0
  45799. */
  45800. this.far = defaultValue(far, 1.0);
  45801. /**
  45802. * The value at the upper bound of the camera range.
  45803. * @type {Number}
  45804. * @default 0.0
  45805. */
  45806. this.farValue = defaultValue(farValue, 0.0);
  45807. }
  45808. /**
  45809. * Duplicates a NearFarScalar instance.
  45810. *
  45811. * @param {NearFarScalar} nearFarScalar The NearFarScalar to duplicate.
  45812. * @param {NearFarScalar} [result] The object onto which to store the result.
  45813. * @returns {NearFarScalar} The modified result parameter or a new NearFarScalar instance if one was not provided. (Returns undefined if nearFarScalar is undefined)
  45814. */
  45815. NearFarScalar.clone = function(nearFarScalar, result) {
  45816. if (!defined(nearFarScalar)) {
  45817. return undefined;
  45818. }
  45819. if (!defined(result)) {
  45820. return new NearFarScalar(nearFarScalar.near, nearFarScalar.nearValue, nearFarScalar.far, nearFarScalar.farValue);
  45821. }
  45822. result.near = nearFarScalar.near;
  45823. result.nearValue = nearFarScalar.nearValue;
  45824. result.far = nearFarScalar.far;
  45825. result.farValue = nearFarScalar.farValue;
  45826. return result;
  45827. };
  45828. /**
  45829. * The number of elements used to pack the object into an array.
  45830. * @type {Number}
  45831. */
  45832. NearFarScalar.packedLength = 4;
  45833. /**
  45834. * Stores the provided instance into the provided array.
  45835. *
  45836. * @param {NearFarScalar} value The value to pack.
  45837. * @param {Number[]} array The array to pack into.
  45838. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  45839. *
  45840. * @returns {Number[]} The array that was packed into
  45841. */
  45842. NearFarScalar.pack = function(value, array, startingIndex) {
  45843. if (!defined(value)) {
  45844. throw new DeveloperError('value is required');
  45845. }
  45846. if (!defined(array)) {
  45847. throw new DeveloperError('array is required');
  45848. }
  45849. startingIndex = defaultValue(startingIndex, 0);
  45850. array[startingIndex++] = value.near;
  45851. array[startingIndex++] = value.nearValue;
  45852. array[startingIndex++] = value.far;
  45853. array[startingIndex] = value.farValue;
  45854. return array;
  45855. };
  45856. /**
  45857. * Retrieves an instance from a packed array.
  45858. *
  45859. * @param {Number[]} array The packed array.
  45860. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  45861. * @param {NearFarScalar} [result] The object into which to store the result.
  45862. * @returns {NearFarScalar} The modified result parameter or a new NearFarScalar instance if one was not provided.
  45863. */
  45864. NearFarScalar.unpack = function(array, startingIndex, result) {
  45865. if (!defined(array)) {
  45866. throw new DeveloperError('array is required');
  45867. }
  45868. startingIndex = defaultValue(startingIndex, 0);
  45869. if (!defined(result)) {
  45870. result = new NearFarScalar();
  45871. }
  45872. result.near = array[startingIndex++];
  45873. result.nearValue = array[startingIndex++];
  45874. result.far = array[startingIndex++];
  45875. result.farValue = array[startingIndex];
  45876. return result;
  45877. };
  45878. /**
  45879. * Compares the provided NearFarScalar and returns <code>true</code> if they are equal,
  45880. * <code>false</code> otherwise.
  45881. *
  45882. * @param {NearFarScalar} [left] The first NearFarScalar.
  45883. * @param {NearFarScalar} [right] The second NearFarScalar.
  45884. * @returns {Boolean} <code>true</code> if left and right are equal; otherwise <code>false</code>.
  45885. */
  45886. NearFarScalar.equals = function(left, right) {
  45887. return (left === right) ||
  45888. ((defined(left)) &&
  45889. (defined(right)) &&
  45890. (left.near === right.near) &&
  45891. (left.nearValue === right.nearValue) &&
  45892. (left.far === right.far) &&
  45893. (left.farValue === right.farValue));
  45894. };
  45895. /**
  45896. * Duplicates this instance.
  45897. *
  45898. * @param {NearFarScalar} [result] The object onto which to store the result.
  45899. * @returns {NearFarScalar} The modified result parameter or a new NearFarScalar instance if one was not provided.
  45900. */
  45901. NearFarScalar.prototype.clone = function(result) {
  45902. return NearFarScalar.clone(this, result);
  45903. };
  45904. /**
  45905. * Compares this instance to the provided NearFarScalar and returns <code>true</code> if they are equal,
  45906. * <code>false</code> otherwise.
  45907. *
  45908. * @param {NearFarScalar} [right] The right hand side NearFarScalar.
  45909. * @returns {Boolean} <code>true</code> if left and right are equal; otherwise <code>false</code>.
  45910. */
  45911. NearFarScalar.prototype.equals = function(right) {
  45912. return NearFarScalar.equals(this, right);
  45913. };
  45914. return NearFarScalar;
  45915. });
  45916. /*global define*/
  45917. define('Core/Visibility',[
  45918. './freezeObject'
  45919. ], function(
  45920. freezeObject) {
  45921. 'use strict';
  45922. /**
  45923. * This enumerated type is used in determining to what extent an object, the occludee,
  45924. * is visible during horizon culling. An occluder may fully block an occludee, in which case
  45925. * it has no visibility, may partially block an occludee from view, or may not block it at all,
  45926. * leading to full visibility.
  45927. *
  45928. * @exports Visibility
  45929. */
  45930. var Visibility = {
  45931. /**
  45932. * Represents that no part of an object is visible.
  45933. *
  45934. * @type {Number}
  45935. * @constant
  45936. */
  45937. NONE : -1,
  45938. /**
  45939. * Represents that part, but not all, of an object is visible
  45940. *
  45941. * @type {Number}
  45942. * @constant
  45943. */
  45944. PARTIAL : 0,
  45945. /**
  45946. * Represents that an object is visible in its entirety.
  45947. *
  45948. * @type {Number}
  45949. * @constant
  45950. */
  45951. FULL : 1
  45952. };
  45953. return freezeObject(Visibility);
  45954. });
  45955. /*global define*/
  45956. define('Core/Occluder',[
  45957. './BoundingSphere',
  45958. './Cartesian3',
  45959. './defaultValue',
  45960. './defined',
  45961. './defineProperties',
  45962. './DeveloperError',
  45963. './Ellipsoid',
  45964. './Math',
  45965. './Rectangle',
  45966. './Visibility'
  45967. ], function(
  45968. BoundingSphere,
  45969. Cartesian3,
  45970. defaultValue,
  45971. defined,
  45972. defineProperties,
  45973. DeveloperError,
  45974. Ellipsoid,
  45975. CesiumMath,
  45976. Rectangle,
  45977. Visibility) {
  45978. 'use strict';
  45979. /**
  45980. * Creates an Occluder derived from an object's position and radius, as well as the camera position.
  45981. * The occluder can be used to determine whether or not other objects are visible or hidden behind the
  45982. * visible horizon defined by the occluder and camera position.
  45983. *
  45984. * @alias Occluder
  45985. *
  45986. * @param {BoundingSphere} occluderBoundingSphere The bounding sphere surrounding the occluder.
  45987. * @param {Cartesian3} cameraPosition The coordinate of the viewer/camera.
  45988. *
  45989. * @constructor
  45990. *
  45991. * @example
  45992. * // Construct an occluder one unit away from the origin with a radius of one.
  45993. * var cameraPosition = Cesium.Cartesian3.ZERO;
  45994. * var occluderBoundingSphere = new Cesium.BoundingSphere(new Cesium.Cartesian3(0, 0, -1), 1);
  45995. * var occluder = new Cesium.Occluder(occluderBoundingSphere, cameraPosition);
  45996. */
  45997. function Occluder(occluderBoundingSphere, cameraPosition) {
  45998. if (!defined(occluderBoundingSphere)) {
  45999. throw new DeveloperError('occluderBoundingSphere is required.');
  46000. }
  46001. if (!defined(cameraPosition)) {
  46002. throw new DeveloperError('camera position is required.');
  46003. }
  46004. this._occluderPosition = Cartesian3.clone(occluderBoundingSphere.center);
  46005. this._occluderRadius = occluderBoundingSphere.radius;
  46006. this._horizonDistance = 0.0;
  46007. this._horizonPlaneNormal = undefined;
  46008. this._horizonPlanePosition = undefined;
  46009. this._cameraPosition = undefined;
  46010. // cameraPosition fills in the above values
  46011. this.cameraPosition = cameraPosition;
  46012. }
  46013. var scratchCartesian3 = new Cartesian3();
  46014. defineProperties(Occluder.prototype, {
  46015. /**
  46016. * The position of the occluder.
  46017. * @memberof Occluder.prototype
  46018. * @type {Cartesian3}
  46019. */
  46020. position: {
  46021. get: function() {
  46022. return this._occluderPosition;
  46023. }
  46024. },
  46025. /**
  46026. * The radius of the occluder.
  46027. * @memberof Occluder.prototype
  46028. * @type {Number}
  46029. */
  46030. radius: {
  46031. get: function() {
  46032. return this._occluderRadius;
  46033. }
  46034. },
  46035. /**
  46036. * The position of the camera.
  46037. * @memberof Occluder.prototype
  46038. * @type {Cartesian3}
  46039. */
  46040. cameraPosition: {
  46041. set: function(cameraPosition) {
  46042. if (!defined(cameraPosition)) {
  46043. throw new DeveloperError('cameraPosition is required.');
  46044. }
  46045. cameraPosition = Cartesian3.clone(cameraPosition, this._cameraPosition);
  46046. var cameraToOccluderVec = Cartesian3.subtract(this._occluderPosition, cameraPosition, scratchCartesian3);
  46047. var invCameraToOccluderDistance = Cartesian3.magnitudeSquared(cameraToOccluderVec);
  46048. var occluderRadiusSqrd = this._occluderRadius * this._occluderRadius;
  46049. var horizonDistance;
  46050. var horizonPlaneNormal;
  46051. var horizonPlanePosition;
  46052. if (invCameraToOccluderDistance > occluderRadiusSqrd) {
  46053. horizonDistance = Math.sqrt(invCameraToOccluderDistance - occluderRadiusSqrd);
  46054. invCameraToOccluderDistance = 1.0 / Math.sqrt(invCameraToOccluderDistance);
  46055. horizonPlaneNormal = Cartesian3.multiplyByScalar(cameraToOccluderVec, invCameraToOccluderDistance, scratchCartesian3);
  46056. var nearPlaneDistance = horizonDistance * horizonDistance * invCameraToOccluderDistance;
  46057. horizonPlanePosition = Cartesian3.add(cameraPosition, Cartesian3.multiplyByScalar(horizonPlaneNormal, nearPlaneDistance, scratchCartesian3), scratchCartesian3);
  46058. } else {
  46059. horizonDistance = Number.MAX_VALUE;
  46060. }
  46061. this._horizonDistance = horizonDistance;
  46062. this._horizonPlaneNormal = horizonPlaneNormal;
  46063. this._horizonPlanePosition = horizonPlanePosition;
  46064. this._cameraPosition = cameraPosition;
  46065. }
  46066. }
  46067. });
  46068. /**
  46069. * Creates an occluder from a bounding sphere and the camera position.
  46070. *
  46071. * @param {BoundingSphere} occluderBoundingSphere The bounding sphere surrounding the occluder.
  46072. * @param {Cartesian3} cameraPosition The coordinate of the viewer/camera.
  46073. * @param {Occluder} [result] The object onto which to store the result.
  46074. * @returns {Occluder} The occluder derived from an object's position and radius, as well as the camera position.
  46075. */
  46076. Occluder.fromBoundingSphere = function(occluderBoundingSphere, cameraPosition, result) {
  46077. if (!defined(occluderBoundingSphere)) {
  46078. throw new DeveloperError('occluderBoundingSphere is required.');
  46079. }
  46080. if (!defined(cameraPosition)) {
  46081. throw new DeveloperError('camera position is required.');
  46082. }
  46083. if (!defined(result)) {
  46084. return new Occluder(occluderBoundingSphere, cameraPosition);
  46085. }
  46086. Cartesian3.clone(occluderBoundingSphere.center, result._occluderPosition);
  46087. result._occluderRadius = occluderBoundingSphere.radius;
  46088. result.cameraPosition = cameraPosition;
  46089. return result;
  46090. };
  46091. var tempVecScratch = new Cartesian3();
  46092. /**
  46093. * Determines whether or not a point, the <code>occludee</code>, is hidden from view by the occluder.
  46094. *
  46095. * @param {Cartesian3} occludee The point surrounding the occludee object.
  46096. * @returns {Boolean} <code>true</code> if the occludee is visible; otherwise <code>false</code>.
  46097. *
  46098. *
  46099. * @example
  46100. * var cameraPosition = new Cesium.Cartesian3(0, 0, 0);
  46101. * var littleSphere = new Cesium.BoundingSphere(new Cesium.Cartesian3(0, 0, -1), 0.25);
  46102. * var occluder = new Cesium.Occluder(littleSphere, cameraPosition);
  46103. * var point = new Cesium.Cartesian3(0, 0, -3);
  46104. * occluder.isPointVisible(point); //returns true
  46105. *
  46106. * @see Occluder#computeVisibility
  46107. */
  46108. Occluder.prototype.isPointVisible = function(occludee) {
  46109. if (this._horizonDistance !== Number.MAX_VALUE) {
  46110. var tempVec = Cartesian3.subtract(occludee, this._occluderPosition, tempVecScratch);
  46111. var temp = this._occluderRadius;
  46112. temp = Cartesian3.magnitudeSquared(tempVec) - (temp * temp);
  46113. if (temp > 0.0) {
  46114. temp = Math.sqrt(temp) + this._horizonDistance;
  46115. tempVec = Cartesian3.subtract(occludee, this._cameraPosition, tempVec);
  46116. return temp * temp > Cartesian3.magnitudeSquared(tempVec);
  46117. }
  46118. }
  46119. return false;
  46120. };
  46121. var occludeePositionScratch = new Cartesian3();
  46122. /**
  46123. * Determines whether or not a sphere, the <code>occludee</code>, is hidden from view by the occluder.
  46124. *
  46125. * @param {BoundingSphere} occludee The bounding sphere surrounding the occludee object.
  46126. * @returns {Boolean} <code>true</code> if the occludee is visible; otherwise <code>false</code>.
  46127. *
  46128. *
  46129. * @example
  46130. * var cameraPosition = new Cesium.Cartesian3(0, 0, 0);
  46131. * var littleSphere = new Cesium.BoundingSphere(new Cesium.Cartesian3(0, 0, -1), 0.25);
  46132. * var occluder = new Cesium.Occluder(littleSphere, cameraPosition);
  46133. * var bigSphere = new Cesium.BoundingSphere(new Cesium.Cartesian3(0, 0, -3), 1);
  46134. * occluder.isBoundingSphereVisible(bigSphere); //returns true
  46135. *
  46136. * @see Occluder#computeVisibility
  46137. */
  46138. Occluder.prototype.isBoundingSphereVisible = function(occludee) {
  46139. var occludeePosition = Cartesian3.clone(occludee.center, occludeePositionScratch);
  46140. var occludeeRadius = occludee.radius;
  46141. if (this._horizonDistance !== Number.MAX_VALUE) {
  46142. var tempVec = Cartesian3.subtract(occludeePosition, this._occluderPosition, tempVecScratch);
  46143. var temp = this._occluderRadius - occludeeRadius;
  46144. temp = Cartesian3.magnitudeSquared(tempVec) - (temp * temp);
  46145. if (occludeeRadius < this._occluderRadius) {
  46146. if (temp > 0.0) {
  46147. temp = Math.sqrt(temp) + this._horizonDistance;
  46148. tempVec = Cartesian3.subtract(occludeePosition, this._cameraPosition, tempVec);
  46149. return ((temp * temp) + (occludeeRadius * occludeeRadius)) > Cartesian3.magnitudeSquared(tempVec);
  46150. }
  46151. return false;
  46152. }
  46153. // Prevent against the case where the occludee radius is larger than the occluder's; since this is
  46154. // an uncommon case, the following code should rarely execute.
  46155. if (temp > 0.0) {
  46156. tempVec = Cartesian3.subtract(occludeePosition, this._cameraPosition, tempVec);
  46157. var tempVecMagnitudeSquared = Cartesian3.magnitudeSquared(tempVec);
  46158. var occluderRadiusSquared = this._occluderRadius * this._occluderRadius;
  46159. var occludeeRadiusSquared = occludeeRadius * occludeeRadius;
  46160. if ((((this._horizonDistance * this._horizonDistance) + occluderRadiusSquared) * occludeeRadiusSquared) >
  46161. (tempVecMagnitudeSquared * occluderRadiusSquared)) {
  46162. // The occludee is close enough that the occluder cannot possible occlude the occludee
  46163. return true;
  46164. }
  46165. temp = Math.sqrt(temp) + this._horizonDistance;
  46166. return ((temp * temp) + occludeeRadiusSquared) > tempVecMagnitudeSquared;
  46167. }
  46168. // The occludee completely encompasses the occluder
  46169. return true;
  46170. }
  46171. return false;
  46172. };
  46173. var tempScratch = new Cartesian3();
  46174. /**
  46175. * Determine to what extent an occludee is visible (not visible, partially visible, or fully visible).
  46176. *
  46177. * @param {BoundingSphere} occludeeBS The bounding sphere of the occludee.
  46178. * @returns {Number} Visibility.NONE if the occludee is not visible,
  46179. * Visibility.PARTIAL if the occludee is partially visible, or
  46180. * Visibility.FULL if the occludee is fully visible.
  46181. *
  46182. *
  46183. * @example
  46184. * var sphere1 = new Cesium.BoundingSphere(new Cesium.Cartesian3(0, 0, -1.5), 0.5);
  46185. * var sphere2 = new Cesium.BoundingSphere(new Cesium.Cartesian3(0, 0, -2.5), 0.5);
  46186. * var cameraPosition = new Cesium.Cartesian3(0, 0, 0);
  46187. * var occluder = new Cesium.Occluder(sphere1, cameraPosition);
  46188. * occluder.computeVisibility(sphere2); //returns Visibility.NONE
  46189. *
  46190. * @see Occluder#isVisible
  46191. */
  46192. Occluder.prototype.computeVisibility = function(occludeeBS) {
  46193. if (!defined(occludeeBS)) {
  46194. throw new DeveloperError('occludeeBS is required.');
  46195. }
  46196. // If the occludee radius is larger than the occluders, this will return that
  46197. // the entire ocludee is visible, even though that may not be the case, though this should
  46198. // not occur too often.
  46199. var occludeePosition = Cartesian3.clone(occludeeBS.center);
  46200. var occludeeRadius = occludeeBS.radius;
  46201. if (occludeeRadius > this._occluderRadius) {
  46202. return Visibility.FULL;
  46203. }
  46204. if (this._horizonDistance !== Number.MAX_VALUE) {
  46205. // The camera is outside the occluder
  46206. var tempVec = Cartesian3.subtract(occludeePosition, this._occluderPosition, tempScratch);
  46207. var temp = this._occluderRadius - occludeeRadius;
  46208. var occluderToOccludeeDistSqrd = Cartesian3.magnitudeSquared(tempVec);
  46209. temp = occluderToOccludeeDistSqrd - (temp * temp);
  46210. if (temp > 0.0) {
  46211. // The occludee is not completely inside the occluder
  46212. // Check to see if the occluder completely hides the occludee
  46213. temp = Math.sqrt(temp) + this._horizonDistance;
  46214. tempVec = Cartesian3.subtract(occludeePosition, this._cameraPosition, tempVec);
  46215. var cameraToOccludeeDistSqrd = Cartesian3.magnitudeSquared(tempVec);
  46216. if (((temp * temp) + (occludeeRadius * occludeeRadius)) < cameraToOccludeeDistSqrd) {
  46217. return Visibility.NONE;
  46218. }
  46219. // Check to see whether the occluder is fully or partially visible
  46220. // when the occludee does not intersect the occluder
  46221. temp = this._occluderRadius + occludeeRadius;
  46222. temp = occluderToOccludeeDistSqrd - (temp * temp);
  46223. if (temp > 0.0) {
  46224. // The occludee does not intersect the occluder.
  46225. temp = Math.sqrt(temp) + this._horizonDistance;
  46226. return (cameraToOccludeeDistSqrd < ((temp * temp)) + (occludeeRadius * occludeeRadius)) ? Visibility.FULL : Visibility.PARTIAL;
  46227. }
  46228. //Check to see if the occluder is fully or partially visible when the occludee DOES
  46229. //intersect the occluder
  46230. tempVec = Cartesian3.subtract(occludeePosition, this._horizonPlanePosition, tempVec);
  46231. return (Cartesian3.dot(tempVec, this._horizonPlaneNormal) > -occludeeRadius) ? Visibility.PARTIAL : Visibility.FULL;
  46232. }
  46233. }
  46234. return Visibility.NONE;
  46235. };
  46236. var occludeePointScratch = new Cartesian3();
  46237. /**
  46238. * Computes a point that can be used as the occludee position to the visibility functions.
  46239. * Use a radius of zero for the occludee radius. Typically, a user computes a bounding sphere around
  46240. * an object that is used for visibility; however it is also possible to compute a point that if
  46241. * seen/not seen would also indicate if an object is visible/not visible. This function is better
  46242. * called for objects that do not move relative to the occluder and is large, such as a chunk of
  46243. * terrain. You are better off not calling this and using the object's bounding sphere for objects
  46244. * such as a satellite or ground vehicle.
  46245. *
  46246. * @param {BoundingSphere} occluderBoundingSphere The bounding sphere surrounding the occluder.
  46247. * @param {Cartesian3} occludeePosition The point where the occludee (bounding sphere of radius 0) is located.
  46248. * @param {Cartesian3[]} positions List of altitude points on the horizon near the surface of the occluder.
  46249. * @returns {Object} An object containing two attributes: <code>occludeePoint</code> and <code>valid</code>
  46250. * which is a boolean value.
  46251. *
  46252. * @exception {DeveloperError} <code>positions</code> must contain at least one element.
  46253. * @exception {DeveloperError} <code>occludeePosition</code> must have a value other than <code>occluderBoundingSphere.center</code>.
  46254. *
  46255. * @example
  46256. * var cameraPosition = new Cesium.Cartesian3(0, 0, 0);
  46257. * var occluderBoundingSphere = new Cesium.BoundingSphere(new Cesium.Cartesian3(0, 0, -8), 2);
  46258. * var occluder = new Cesium.Occluder(occluderBoundingSphere, cameraPosition);
  46259. * var positions = [new Cesium.Cartesian3(-0.25, 0, -5.3), new Cesium.Cartesian3(0.25, 0, -5.3)];
  46260. * var tileOccluderSphere = Cesium.BoundingSphere.fromPoints(positions);
  46261. * var occludeePosition = tileOccluderSphere.center;
  46262. * var occludeePt = Cesium.Occluder.computeOccludeePoint(occluderBoundingSphere, occludeePosition, positions);
  46263. */
  46264. Occluder.computeOccludeePoint = function(occluderBoundingSphere, occludeePosition, positions) {
  46265. if (!defined(occluderBoundingSphere)) {
  46266. throw new DeveloperError('occluderBoundingSphere is required.');
  46267. }
  46268. if (!defined(positions)) {
  46269. throw new DeveloperError('positions is required.');
  46270. }
  46271. if (positions.length === 0) {
  46272. throw new DeveloperError('positions must contain at least one element');
  46273. }
  46274. var occludeePos = Cartesian3.clone(occludeePosition);
  46275. var occluderPosition = Cartesian3.clone(occluderBoundingSphere.center);
  46276. var occluderRadius = occluderBoundingSphere.radius;
  46277. var numPositions = positions.length;
  46278. if (Cartesian3.equals(occluderPosition, occludeePosition)) {
  46279. throw new DeveloperError('occludeePosition must be different than occluderBoundingSphere.center');
  46280. }
  46281. // Compute a plane with a normal from the occluder to the occludee position.
  46282. var occluderPlaneNormal = Cartesian3.normalize(Cartesian3.subtract(occludeePos, occluderPosition, occludeePointScratch), occludeePointScratch);
  46283. var occluderPlaneD = -(Cartesian3.dot(occluderPlaneNormal, occluderPosition));
  46284. //For each position, determine the horizon intersection. Choose the position and intersection
  46285. //that results in the greatest angle with the occcluder plane.
  46286. var aRotationVector = Occluder._anyRotationVector(occluderPosition, occluderPlaneNormal, occluderPlaneD);
  46287. var dot = Occluder._horizonToPlaneNormalDotProduct(occluderBoundingSphere, occluderPlaneNormal, occluderPlaneD, aRotationVector, positions[0]);
  46288. if (!dot) {
  46289. //The position is inside the mimimum radius, which is invalid
  46290. return undefined;
  46291. }
  46292. var tempDot;
  46293. for ( var i = 1; i < numPositions; ++i) {
  46294. tempDot = Occluder._horizonToPlaneNormalDotProduct(occluderBoundingSphere, occluderPlaneNormal, occluderPlaneD, aRotationVector, positions[i]);
  46295. if (!tempDot) {
  46296. //The position is inside the minimum radius, which is invalid
  46297. return undefined;
  46298. }
  46299. if (tempDot < dot) {
  46300. dot = tempDot;
  46301. }
  46302. }
  46303. //Verify that the dot is not near 90 degress
  46304. if (dot < 0.00174532836589830883577820272085) {
  46305. return undefined;
  46306. }
  46307. var distance = occluderRadius / dot;
  46308. return Cartesian3.add(occluderPosition, Cartesian3.multiplyByScalar(occluderPlaneNormal, distance, occludeePointScratch), occludeePointScratch);
  46309. };
  46310. var computeOccludeePointFromRectangleScratch = [];
  46311. /**
  46312. * Computes a point that can be used as the occludee position to the visibility functions from an rectangle.
  46313. *
  46314. * @param {Rectangle} rectangle The rectangle used to create a bounding sphere.
  46315. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid used to determine positions of the rectangle.
  46316. * @returns {Object} An object containing two attributes: <code>occludeePoint</code> and <code>valid</code>
  46317. * which is a boolean value.
  46318. */
  46319. Occluder.computeOccludeePointFromRectangle = function(rectangle, ellipsoid) {
  46320. if (!defined(rectangle)) {
  46321. throw new DeveloperError('rectangle is required.');
  46322. }
  46323. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  46324. var positions = Rectangle.subsample(rectangle, ellipsoid, 0.0, computeOccludeePointFromRectangleScratch);
  46325. var bs = BoundingSphere.fromPoints(positions);
  46326. // TODO: get correct ellipsoid center
  46327. var ellipsoidCenter = Cartesian3.ZERO;
  46328. if (!Cartesian3.equals(ellipsoidCenter, bs.center)) {
  46329. return Occluder.computeOccludeePoint(new BoundingSphere(ellipsoidCenter, ellipsoid.minimumRadius), bs.center, positions);
  46330. }
  46331. return undefined;
  46332. };
  46333. var tempVec0Scratch = new Cartesian3();
  46334. Occluder._anyRotationVector = function(occluderPosition, occluderPlaneNormal, occluderPlaneD) {
  46335. var tempVec0 = Cartesian3.abs(occluderPlaneNormal, tempVec0Scratch);
  46336. var majorAxis = tempVec0.x > tempVec0.y ? 0 : 1;
  46337. if (((majorAxis === 0) && (tempVec0.z > tempVec0.x)) || ((majorAxis === 1) && (tempVec0.z > tempVec0.y))) {
  46338. majorAxis = 2;
  46339. }
  46340. var tempVec = new Cartesian3();
  46341. var tempVec1;
  46342. if (majorAxis === 0) {
  46343. tempVec0.x = occluderPosition.x;
  46344. tempVec0.y = occluderPosition.y + 1.0;
  46345. tempVec0.z = occluderPosition.z + 1.0;
  46346. tempVec1 = Cartesian3.UNIT_X;
  46347. } else if (majorAxis === 1) {
  46348. tempVec0.x = occluderPosition.x + 1.0;
  46349. tempVec0.y = occluderPosition.y;
  46350. tempVec0.z = occluderPosition.z + 1.0;
  46351. tempVec1 = Cartesian3.UNIT_Y;
  46352. } else {
  46353. tempVec0.x = occluderPosition.x + 1.0;
  46354. tempVec0.y = occluderPosition.y + 1.0;
  46355. tempVec0.z = occluderPosition.z;
  46356. tempVec1 = Cartesian3.UNIT_Z;
  46357. }
  46358. var u = (Cartesian3.dot(occluderPlaneNormal, tempVec0) + occluderPlaneD) / -(Cartesian3.dot(occluderPlaneNormal, tempVec1));
  46359. return Cartesian3.normalize(Cartesian3.subtract(Cartesian3.add(tempVec0, Cartesian3.multiplyByScalar(tempVec1, u, tempVec), tempVec0), occluderPosition, tempVec0), tempVec0);
  46360. };
  46361. var posDirectionScratch = new Cartesian3();
  46362. Occluder._rotationVector = function(occluderPosition, occluderPlaneNormal, occluderPlaneD, position, anyRotationVector) {
  46363. //Determine the angle between the occluder plane normal and the position direction
  46364. var positionDirection = Cartesian3.subtract(position, occluderPosition, posDirectionScratch);
  46365. positionDirection = Cartesian3.normalize(positionDirection, positionDirection);
  46366. if (Cartesian3.dot(occluderPlaneNormal, positionDirection) < 0.99999998476912904932780850903444) {
  46367. var crossProduct = Cartesian3.cross(occluderPlaneNormal, positionDirection, positionDirection);
  46368. var length = Cartesian3.magnitude(crossProduct);
  46369. if (length > CesiumMath.EPSILON13) {
  46370. return Cartesian3.normalize(crossProduct, new Cartesian3());
  46371. }
  46372. }
  46373. //The occluder plane normal and the position direction are colinear. Use any
  46374. //vector in the occluder plane as the rotation vector
  46375. return anyRotationVector;
  46376. };
  46377. var posScratch1 = new Cartesian3();
  46378. var occluerPosScratch = new Cartesian3();
  46379. var posScratch2 = new Cartesian3();
  46380. var horizonPlanePosScratch = new Cartesian3();
  46381. Occluder._horizonToPlaneNormalDotProduct = function(occluderBS, occluderPlaneNormal, occluderPlaneD, anyRotationVector, position) {
  46382. var pos = Cartesian3.clone(position, posScratch1);
  46383. var occluderPosition = Cartesian3.clone(occluderBS.center, occluerPosScratch);
  46384. var occluderRadius = occluderBS.radius;
  46385. //Verify that the position is outside the occluder
  46386. var positionToOccluder = Cartesian3.subtract(occluderPosition, pos, posScratch2);
  46387. var occluderToPositionDistanceSquared = Cartesian3.magnitudeSquared(positionToOccluder);
  46388. var occluderRadiusSquared = occluderRadius * occluderRadius;
  46389. if (occluderToPositionDistanceSquared < occluderRadiusSquared) {
  46390. return false;
  46391. }
  46392. //Horizon parameters
  46393. var horizonDistanceSquared = occluderToPositionDistanceSquared - occluderRadiusSquared;
  46394. var horizonDistance = Math.sqrt(horizonDistanceSquared);
  46395. var occluderToPositionDistance = Math.sqrt(occluderToPositionDistanceSquared);
  46396. var invOccluderToPositionDistance = 1.0 / occluderToPositionDistance;
  46397. var cosTheta = horizonDistance * invOccluderToPositionDistance;
  46398. var horizonPlaneDistance = cosTheta * horizonDistance;
  46399. positionToOccluder = Cartesian3.normalize(positionToOccluder, positionToOccluder);
  46400. var horizonPlanePosition = Cartesian3.add(pos, Cartesian3.multiplyByScalar(positionToOccluder, horizonPlaneDistance, horizonPlanePosScratch), horizonPlanePosScratch);
  46401. var horizonCrossDistance = Math.sqrt(horizonDistanceSquared - (horizonPlaneDistance * horizonPlaneDistance));
  46402. //Rotate the position to occluder vector 90 degrees
  46403. var tempVec = this._rotationVector(occluderPosition, occluderPlaneNormal, occluderPlaneD, pos, anyRotationVector);
  46404. var horizonCrossDirection = Cartesian3.fromElements(
  46405. (tempVec.x * tempVec.x * positionToOccluder.x) + ((tempVec.x * tempVec.y - tempVec.z) * positionToOccluder.y) + ((tempVec.x * tempVec.z + tempVec.y) * positionToOccluder.z),
  46406. ((tempVec.x * tempVec.y + tempVec.z) * positionToOccluder.x) + (tempVec.y * tempVec.y * positionToOccluder.y) + ((tempVec.y * tempVec.z - tempVec.x) * positionToOccluder.z),
  46407. ((tempVec.x * tempVec.z - tempVec.y) * positionToOccluder.x) + ((tempVec.y * tempVec.z + tempVec.x) * positionToOccluder.y) + (tempVec.z * tempVec.z * positionToOccluder.z),
  46408. posScratch1);
  46409. horizonCrossDirection = Cartesian3.normalize(horizonCrossDirection, horizonCrossDirection);
  46410. //Horizon positions
  46411. var offset = Cartesian3.multiplyByScalar(horizonCrossDirection, horizonCrossDistance, posScratch1);
  46412. tempVec = Cartesian3.normalize(Cartesian3.subtract(Cartesian3.add(horizonPlanePosition, offset, posScratch2), occluderPosition, posScratch2), posScratch2);
  46413. var dot0 = Cartesian3.dot(occluderPlaneNormal, tempVec);
  46414. tempVec = Cartesian3.normalize(Cartesian3.subtract(Cartesian3.subtract(horizonPlanePosition, offset, tempVec), occluderPosition, tempVec), tempVec);
  46415. var dot1 = Cartesian3.dot(occluderPlaneNormal, tempVec);
  46416. return (dot0 < dot1) ? dot0 : dot1;
  46417. };
  46418. return Occluder;
  46419. });
  46420. /*global define*/
  46421. define('Core/Packable',[
  46422. './DeveloperError'
  46423. ], function(
  46424. DeveloperError) {
  46425. 'use strict';
  46426. /**
  46427. * Static interface for types which can store their values as packed
  46428. * elements in an array. These methods and properties are expected to be
  46429. * defined on a constructor function.
  46430. *
  46431. * @exports Packable
  46432. *
  46433. * @see PackableForInterpolation
  46434. */
  46435. var Packable = {
  46436. /**
  46437. * The number of elements used to pack the object into an array.
  46438. * @type {Number}
  46439. */
  46440. packedLength : undefined,
  46441. /**
  46442. * Stores the provided instance into the provided array.
  46443. * @function
  46444. *
  46445. * @param {Object} value The value to pack.
  46446. * @param {Number[]} array The array to pack into.
  46447. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  46448. */
  46449. pack : DeveloperError.throwInstantiationError,
  46450. /**
  46451. * Retrieves an instance from a packed array.
  46452. * @function
  46453. *
  46454. * @param {Number[]} array The packed array.
  46455. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  46456. * @param {Object} [result] The object into which to store the result.
  46457. * @returns {Object} The modified result parameter or a new Object instance if one was not provided.
  46458. */
  46459. unpack : DeveloperError.throwInstantiationError
  46460. };
  46461. return Packable;
  46462. });
  46463. /*global define*/
  46464. define('Core/PackableForInterpolation',[
  46465. './DeveloperError'
  46466. ], function(
  46467. DeveloperError) {
  46468. 'use strict';
  46469. /**
  46470. * Static interface for {@link Packable} types which are interpolated in a
  46471. * different representation than their packed value. These methods and
  46472. * properties are expected to be defined on a constructor function.
  46473. *
  46474. * @exports PackableForInterpolation
  46475. *
  46476. * @see Packable
  46477. */
  46478. var PackableForInterpolation = {
  46479. /**
  46480. * The number of elements used to store the object into an array in its interpolatable form.
  46481. * @type {Number}
  46482. */
  46483. packedInterpolationLength : undefined,
  46484. /**
  46485. * Converts a packed array into a form suitable for interpolation.
  46486. * @function
  46487. *
  46488. * @param {Number[]} packedArray The packed array.
  46489. * @param {Number} [startingIndex=0] The index of the first element to be converted.
  46490. * @param {Number} [lastIndex=packedArray.length] The index of the last element to be converted.
  46491. * @param {Number[]} result The object into which to store the result.
  46492. */
  46493. convertPackedArrayForInterpolation : DeveloperError.throwInstantiationError,
  46494. /**
  46495. * Retrieves an instance from a packed array converted with {@link PackableForInterpolation.convertPackedArrayForInterpolation}.
  46496. * @function
  46497. *
  46498. * @param {Number[]} array The array previously packed for interpolation.
  46499. * @param {Number[]} sourceArray The original packed array.
  46500. * @param {Number} [startingIndex=0] The startingIndex used to convert the array.
  46501. * @param {Number} [lastIndex=packedArray.length] The lastIndex used to convert the array.
  46502. * @param {Object} [result] The object into which to store the result.
  46503. * @returns {Object} The modified result parameter or a new Object instance if one was not provided.
  46504. */
  46505. unpackInterpolationResult : DeveloperError.throwInstantiationError
  46506. };
  46507. return PackableForInterpolation;
  46508. });
  46509. /*
  46510. This library rewrites the Canvas2D "measureText" function
  46511. so that it returns a more complete metrics object.
  46512. ** -----------------------------------------------------------------------------
  46513. CHANGELOG:
  46514. 2012-01-21 - Whitespace handling added by Joe Turner
  46515. (https://github.com/oampo)
  46516. ** -----------------------------------------------------------------------------
  46517. */
  46518. /**
  46519. @license
  46520. fontmetrics.js - https://github.com/Pomax/fontmetrics.js
  46521. Copyright (C) 2011 by Mike "Pomax" Kamermans
  46522. Permission is hereby granted, free of charge, to any person obtaining a copy
  46523. of this software and associated documentation files (the "Software"), to deal
  46524. in the Software without restriction, including without limitation the rights
  46525. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  46526. copies of the Software, and to permit persons to whom the Software is
  46527. furnished to do so, subject to the following conditions:
  46528. The above copyright notice and this permission notice shall be included in
  46529. all copies or substantial portions of the Software.
  46530. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  46531. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  46532. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  46533. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  46534. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  46535. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  46536. THE SOFTWARE.
  46537. **/
  46538. /*global define*/
  46539. define('ThirdParty/measureText',[],function() {
  46540. /*jshint strict:false*/
  46541. /*
  46542. var NAME = "FontMetrics Library"
  46543. var VERSION = "1-2012.0121.1300";
  46544. // if there is no getComputedStyle, this library won't work.
  46545. if(!document.defaultView.getComputedStyle) {
  46546. throw("ERROR: 'document.defaultView.getComputedStyle' not found. This library only works in browsers that can report computed CSS values.");
  46547. }
  46548. // store the old text metrics function on the Canvas2D prototype
  46549. CanvasRenderingContext2D.prototype.measureTextWidth = CanvasRenderingContext2D.prototype.measureText;
  46550. */
  46551. /**
  46552. * shortcut function for getting computed CSS values
  46553. */
  46554. var getCSSValue = function(element, property) {
  46555. return document.defaultView.getComputedStyle(element,null).getPropertyValue(property);
  46556. };
  46557. /*
  46558. // debug function
  46559. var show = function(canvas, ctx, xstart, w, h, metrics)
  46560. {
  46561. document.body.appendChild(canvas);
  46562. ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)';
  46563. ctx.beginPath();
  46564. ctx.moveTo(xstart,0);
  46565. ctx.lineTo(xstart,h);
  46566. ctx.closePath();
  46567. ctx.stroke();
  46568. ctx.beginPath();
  46569. ctx.moveTo(xstart+metrics.bounds.maxx,0);
  46570. ctx.lineTo(xstart+metrics.bounds.maxx,h);
  46571. ctx.closePath();
  46572. ctx.stroke();
  46573. ctx.beginPath();
  46574. ctx.moveTo(0,h/2-metrics.ascent);
  46575. ctx.lineTo(w,h/2-metrics.ascent);
  46576. ctx.closePath();
  46577. ctx.stroke();
  46578. ctx.beginPath();
  46579. ctx.moveTo(0,h/2+metrics.descent);
  46580. ctx.lineTo(w,h/2+metrics.descent);
  46581. ctx.closePath();
  46582. ctx.stroke();
  46583. }
  46584. */
  46585. /**
  46586. * The new text metrics function
  46587. */
  46588. var measureText = function(context2D, textstring, stroke, fill) {
  46589. var metrics = context2D.measureText(textstring),
  46590. fontFamily = getCSSValue(context2D.canvas,"font-family"),
  46591. fontSize = getCSSValue(context2D.canvas,"font-size").replace("px",""),
  46592. fontStyle = getCSSValue(context2D.canvas,"font-style"),
  46593. fontWeight = getCSSValue(context2D.canvas,"font-weight"),
  46594. isSpace = !(/\S/.test(textstring));
  46595. metrics.fontsize = fontSize;
  46596. // for text lead values, we meaure a multiline text container.
  46597. var leadDiv = document.createElement("div");
  46598. leadDiv.style.position = "absolute";
  46599. leadDiv.style.opacity = 0;
  46600. leadDiv.style.font = fontStyle + " " + fontWeight + " " + fontSize + "px " + fontFamily;
  46601. leadDiv.innerHTML = textstring + "<br/>" + textstring;
  46602. document.body.appendChild(leadDiv);
  46603. // make some initial guess at the text leading (using the standard TeX ratio)
  46604. metrics.leading = 1.2 * fontSize;
  46605. // then we try to get the real value from the browser
  46606. var leadDivHeight = getCSSValue(leadDiv,"height");
  46607. leadDivHeight = leadDivHeight.replace("px","");
  46608. if (leadDivHeight >= fontSize * 2) { metrics.leading = (leadDivHeight/2) | 0; }
  46609. document.body.removeChild(leadDiv);
  46610. // if we're not dealing with white space, we can compute metrics
  46611. if (!isSpace) {
  46612. // Have characters, so measure the text
  46613. var canvas = document.createElement("canvas");
  46614. var padding = 100;
  46615. canvas.width = metrics.width + padding;
  46616. canvas.height = 3*fontSize;
  46617. canvas.style.opacity = 1;
  46618. canvas.style.fontFamily = fontFamily;
  46619. canvas.style.fontSize = fontSize;
  46620. canvas.style.fontStyle = fontStyle;
  46621. canvas.style.fontWeight = fontWeight;
  46622. var ctx = canvas.getContext("2d");
  46623. ctx.font = fontStyle + " " + fontWeight + " " + fontSize + "px " + fontFamily;
  46624. var w = canvas.width,
  46625. h = canvas.height,
  46626. baseline = h/2;
  46627. // Set all canvas pixeldata values to 255, with all the content
  46628. // data being 0. This lets us scan for data[i] != 255.
  46629. ctx.fillStyle = "white";
  46630. ctx.fillRect(-1, -1, w + 2, h + 2);
  46631. if (stroke) {
  46632. ctx.strokeStyle = "black";
  46633. ctx.lineWidth = context2D.lineWidth;
  46634. ctx.strokeText(textstring, (padding / 2), baseline);
  46635. }
  46636. if (fill) {
  46637. ctx.fillStyle = "black";
  46638. ctx.fillText(textstring, padding / 2, baseline);
  46639. }
  46640. var pixelData = ctx.getImageData(0, 0, w, h).data;
  46641. // canvas pixel data is w*4 by h*4, because R, G, B and A are separate,
  46642. // consecutive values in the array, rather than stored as 32 bit ints.
  46643. var i = 0,
  46644. w4 = w * 4,
  46645. len = pixelData.length;
  46646. // Finding the ascent uses a normal, forward scanline
  46647. while (++i < len && pixelData[i] === 255) {}
  46648. var ascent = (i/w4)|0;
  46649. // Finding the descent uses a reverse scanline
  46650. i = len - 1;
  46651. while (--i > 0 && pixelData[i] === 255) {}
  46652. var descent = (i/w4)|0;
  46653. // find the min-x coordinate
  46654. for(i = 0; i<len && pixelData[i] === 255; ) {
  46655. i += w4;
  46656. if(i>=len) { i = (i-len) + 4; }}
  46657. var minx = ((i%w4)/4) | 0;
  46658. // find the max-x coordinate
  46659. var step = 1;
  46660. for(i = len-3; i>=0 && pixelData[i] === 255; ) {
  46661. i -= w4;
  46662. if(i<0) { i = (len - 3) - (step++)*4; }}
  46663. var maxx = ((i%w4)/4) + 1 | 0;
  46664. // set font metrics
  46665. metrics.ascent = (baseline - ascent);
  46666. metrics.descent = (descent - baseline);
  46667. metrics.bounds = { minx: minx - (padding/2),
  46668. maxx: maxx - (padding/2),
  46669. miny: 0,
  46670. maxy: descent-ascent };
  46671. metrics.height = 1+(descent - ascent);
  46672. }
  46673. // if we ARE dealing with whitespace, most values will just be zero.
  46674. else {
  46675. // Only whitespace, so we can't measure the text
  46676. metrics.ascent = 0;
  46677. metrics.descent = 0;
  46678. metrics.bounds = { minx: 0,
  46679. maxx: metrics.width, // Best guess
  46680. miny: 0,
  46681. maxy: 0 };
  46682. metrics.height = 0;
  46683. }
  46684. return metrics;
  46685. };
  46686. return measureText;
  46687. });
  46688. /*global define*/
  46689. define('Core/writeTextToCanvas',[
  46690. '../ThirdParty/measureText',
  46691. './Color',
  46692. './defaultValue',
  46693. './defined',
  46694. './DeveloperError'
  46695. ], function(
  46696. measureText,
  46697. Color,
  46698. defaultValue,
  46699. defined,
  46700. DeveloperError) {
  46701. 'use strict';
  46702. var imageSmoothingEnabledName;
  46703. /**
  46704. * Writes the given text into a new canvas. The canvas will be sized to fit the text.
  46705. * If text is blank, returns undefined.
  46706. *
  46707. * @param {String} text The text to write.
  46708. * @param {Object} [options] Object with the following properties:
  46709. * @param {String} [options.font='10px sans-serif'] The CSS font to use.
  46710. * @param {String} [options.textBaseline='bottom'] The baseline of the text.
  46711. * @param {Boolean} [options.fill=true] Whether to fill the text.
  46712. * @param {Boolean} [options.stroke=false] Whether to stroke the text.
  46713. * @param {Color} [options.fillColor=Color.WHITE] The fill color.
  46714. * @param {Color} [options.strokeColor=Color.BLACK] The stroke color.
  46715. * @param {Number} [options.strokeWidth=1] The stroke width.
  46716. * @param {Color} [options.backgroundColor=Color.TRANSPARENT] The background color of the canvas.
  46717. * @param {Number} [options.padding=0] The pixel size of the padding to add around the text.
  46718. * @returns {Canvas} A new canvas with the given text drawn into it. The dimensions object
  46719. * from measureText will also be added to the returned canvas. If text is
  46720. * blank, returns undefined.
  46721. */
  46722. function writeTextToCanvas(text, options) {
  46723. if (!defined(text)) {
  46724. throw new DeveloperError('text is required.');
  46725. }
  46726. if (text === '') {
  46727. return undefined;
  46728. }
  46729. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  46730. var font = defaultValue(options.font, '10px sans-serif');
  46731. var stroke = defaultValue(options.stroke, false);
  46732. var fill = defaultValue(options.fill, true);
  46733. var strokeWidth = defaultValue(options.strokeWidth, 1);
  46734. var backgroundColor = defaultValue(options.backgroundColor, Color.TRANSPARENT);
  46735. var padding = defaultValue(options.padding, 0);
  46736. var doublePadding = padding * 2.0;
  46737. var canvas = document.createElement('canvas');
  46738. canvas.width = 1;
  46739. canvas.height = 1;
  46740. canvas.style.font = font;
  46741. var context2D = canvas.getContext('2d');
  46742. if (!defined(imageSmoothingEnabledName)) {
  46743. if (defined(context2D.imageSmoothingEnabled)) {
  46744. imageSmoothingEnabledName = 'imageSmoothingEnabled';
  46745. } else if (defined(context2D.mozImageSmoothingEnabled)) {
  46746. imageSmoothingEnabledName = 'mozImageSmoothingEnabled';
  46747. } else if (defined(context2D.webkitImageSmoothingEnabled)) {
  46748. imageSmoothingEnabledName = 'webkitImageSmoothingEnabled';
  46749. } else if (defined(context2D.msImageSmoothingEnabled)) {
  46750. imageSmoothingEnabledName = 'msImageSmoothingEnabled';
  46751. }
  46752. }
  46753. context2D.font = font;
  46754. context2D.lineJoin = 'round';
  46755. context2D.lineWidth = strokeWidth;
  46756. context2D[imageSmoothingEnabledName] = false;
  46757. // textBaseline needs to be set before the measureText call. It won't work otherwise.
  46758. // It's magic.
  46759. context2D.textBaseline = defaultValue(options.textBaseline, 'bottom');
  46760. // in order for measureText to calculate style, the canvas has to be
  46761. // (temporarily) added to the DOM.
  46762. canvas.style.visibility = 'hidden';
  46763. document.body.appendChild(canvas);
  46764. var dimensions = measureText(context2D, text, stroke, fill);
  46765. canvas.dimensions = dimensions;
  46766. document.body.removeChild(canvas);
  46767. canvas.style.visibility = '';
  46768. //Some characters, such as the letter j, have a non-zero starting position.
  46769. //This value is used for kerning later, but we need to take it into account
  46770. //now in order to draw the text completely on the canvas
  46771. var x = -dimensions.bounds.minx;
  46772. //Expand the width to include the starting position.
  46773. var width = Math.ceil(dimensions.width) + x + doublePadding;
  46774. //While the height of the letter is correct, we need to adjust
  46775. //where we start drawing it so that letters like j and y properly dip
  46776. //below the line.
  46777. var height = dimensions.height + doublePadding;
  46778. var baseline = height - dimensions.ascent + doublePadding;
  46779. var y = height - baseline + doublePadding;
  46780. canvas.width = width;
  46781. canvas.height = height;
  46782. // Properties must be explicitly set again after changing width and height
  46783. context2D.font = font;
  46784. context2D.lineJoin = 'round';
  46785. context2D.lineWidth = strokeWidth;
  46786. context2D[imageSmoothingEnabledName] = false;
  46787. // Draw background
  46788. if (backgroundColor !== Color.TRANSPARENT) {
  46789. context2D.fillStyle = backgroundColor.toCssColorString();
  46790. context2D.fillRect(0, 0, canvas.width, canvas.height);
  46791. }
  46792. if (stroke) {
  46793. var strokeColor = defaultValue(options.strokeColor, Color.BLACK);
  46794. context2D.strokeStyle = strokeColor.toCssColorString();
  46795. context2D.strokeText(text, x + padding, y);
  46796. }
  46797. if (fill) {
  46798. var fillColor = defaultValue(options.fillColor, Color.WHITE);
  46799. context2D.fillStyle = fillColor.toCssColorString();
  46800. context2D.fillText(text, x + padding, y);
  46801. }
  46802. return canvas;
  46803. }
  46804. return writeTextToCanvas;
  46805. });
  46806. /*global define*/
  46807. define('Core/PinBuilder',[
  46808. './buildModuleUrl',
  46809. './Color',
  46810. './defined',
  46811. './DeveloperError',
  46812. './loadImage',
  46813. './writeTextToCanvas'
  46814. ], function(
  46815. buildModuleUrl,
  46816. Color,
  46817. defined,
  46818. DeveloperError,
  46819. loadImage,
  46820. writeTextToCanvas) {
  46821. 'use strict';
  46822. /**
  46823. * A utility class for generating custom map pins as canvas elements.
  46824. * <br /><br />
  46825. * <div align='center'>
  46826. * <img src='images/PinBuilder.png' width='500'/><br />
  46827. * Example pins generated using both the maki icon set, which ships with Cesium, and single character text.
  46828. * </div>
  46829. *
  46830. * @alias PinBuilder
  46831. * @constructor
  46832. *
  46833. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Map%20Pins.html|Cesium Sandcastle PinBuilder Demo}
  46834. */
  46835. function PinBuilder() {
  46836. this._cache = {};
  46837. }
  46838. /**
  46839. * Creates an empty pin of the specified color and size.
  46840. *
  46841. * @param {Color} color The color of the pin.
  46842. * @param {Number} size The size of the pin, in pixels.
  46843. * @returns {Canvas} The canvas element that represents the generated pin.
  46844. */
  46845. PinBuilder.prototype.fromColor = function(color, size) {
  46846. if (!defined(color)) {
  46847. throw new DeveloperError('color is required');
  46848. }
  46849. if (!defined(size)) {
  46850. throw new DeveloperError('size is required');
  46851. }
  46852. return createPin(undefined, undefined, color, size, this._cache);
  46853. };
  46854. /**
  46855. * Creates a pin with the specified icon, color, and size.
  46856. *
  46857. * @param {String} url The url of the image to be stamped onto the pin.
  46858. * @param {Color} color The color of the pin.
  46859. * @param {Number} size The size of the pin, in pixels.
  46860. * @returns {Canvas|Promise.<Canvas>} The canvas element or a Promise to the canvas element that represents the generated pin.
  46861. */
  46862. PinBuilder.prototype.fromUrl = function(url, color, size) {
  46863. if (!defined(url)) {
  46864. throw new DeveloperError('url is required');
  46865. }
  46866. if (!defined(color)) {
  46867. throw new DeveloperError('color is required');
  46868. }
  46869. if (!defined(size)) {
  46870. throw new DeveloperError('size is required');
  46871. }
  46872. return createPin(url, undefined, color, size, this._cache);
  46873. };
  46874. /**
  46875. * Creates a pin with the specified {@link https://www.mapbox.com/maki/|maki} icon identifier, color, and size.
  46876. *
  46877. * @param {String} id The id of the maki icon to be stamped onto the pin.
  46878. * @param {Color} color The color of the pin.
  46879. * @param {Number} size The size of the pin, in pixels.
  46880. * @returns {Canvas|Promise.<Canvas>} The canvas element or a Promise to the canvas element that represents the generated pin.
  46881. */
  46882. PinBuilder.prototype.fromMakiIconId = function(id, color, size) {
  46883. if (!defined(id)) {
  46884. throw new DeveloperError('id is required');
  46885. }
  46886. if (!defined(color)) {
  46887. throw new DeveloperError('color is required');
  46888. }
  46889. if (!defined(size)) {
  46890. throw new DeveloperError('size is required');
  46891. }
  46892. return createPin(buildModuleUrl('Assets/Textures/maki/' + encodeURIComponent(id) + '.png'), undefined, color, size, this._cache);
  46893. };
  46894. /**
  46895. * Creates a pin with the specified text, color, and size. The text will be sized to be as large as possible
  46896. * while still being contained completely within the pin.
  46897. *
  46898. * @param {String} text The text to be stamped onto the pin.
  46899. * @param {Color} color The color of the pin.
  46900. * @param {Number} size The size of the pin, in pixels.
  46901. * @returns {Canvas} The canvas element that represents the generated pin.
  46902. */
  46903. PinBuilder.prototype.fromText = function(text, color, size) {
  46904. if (!defined(text)) {
  46905. throw new DeveloperError('text is required');
  46906. }
  46907. if (!defined(color)) {
  46908. throw new DeveloperError('color is required');
  46909. }
  46910. if (!defined(size)) {
  46911. throw new DeveloperError('size is required');
  46912. }
  46913. return createPin(undefined, text, color, size, this._cache);
  46914. };
  46915. var colorScratch = new Color();
  46916. //This function (except for the 3 commented lines) was auto-generated from an online tool,
  46917. //http://www.professorcloud.com/svg-to-canvas/, using Assets/Textures/pin.svg as input.
  46918. //The reason we simply can't load and draw the SVG directly to the canvas is because
  46919. //it taints the canvas in Internet Explorer (and possibly some other browsers); making
  46920. //it impossible to create a WebGL texture from the result.
  46921. function drawPin(context2D, color, size) {
  46922. context2D.save();
  46923. context2D.scale(size / 24, size / 24); //Added to auto-generated code to scale up to desired size.
  46924. context2D.fillStyle = color.toCssColorString(); //Modified from auto-generated code.
  46925. context2D.strokeStyle = color.brighten(0.6, colorScratch).toCssColorString(); //Modified from auto-generated code.
  46926. context2D.lineWidth = 0.846;
  46927. context2D.beginPath();
  46928. context2D.moveTo(6.72, 0.422);
  46929. context2D.lineTo(17.28, 0.422);
  46930. context2D.bezierCurveTo(18.553, 0.422, 19.577, 1.758, 19.577, 3.415);
  46931. context2D.lineTo(19.577, 10.973);
  46932. context2D.bezierCurveTo(19.577, 12.63, 18.553, 13.966, 17.282, 13.966);
  46933. context2D.lineTo(14.386, 14.008);
  46934. context2D.lineTo(11.826, 23.578);
  46935. context2D.lineTo(9.614, 14.008);
  46936. context2D.lineTo(6.719, 13.965);
  46937. context2D.bezierCurveTo(5.446, 13.983, 4.422, 12.629, 4.422, 10.972);
  46938. context2D.lineTo(4.422, 3.416);
  46939. context2D.bezierCurveTo(4.423, 1.76, 5.447, 0.423, 6.718, 0.423);
  46940. context2D.closePath();
  46941. context2D.fill();
  46942. context2D.stroke();
  46943. context2D.restore();
  46944. }
  46945. //This function takes an image or canvas and uses it as a template
  46946. //to "stamp" the pin with a white image outlined in black. The color
  46947. //values of the input image are ignored completely and only the alpha
  46948. //values are used.
  46949. function drawIcon(context2D, image, size) {
  46950. //Size is the largest image that looks good inside of pin box.
  46951. var imageSize = size / 2.5;
  46952. var sizeX = imageSize;
  46953. var sizeY = imageSize;
  46954. if (image.width > image.height) {
  46955. sizeY = imageSize * (image.height / image.width);
  46956. } else if (image.width < image.height) {
  46957. sizeX = imageSize * (image.width / image.height);
  46958. }
  46959. //x and y are the center of the pin box
  46960. var x = (size - sizeX) / 2;
  46961. var y = ((7 / 24) * size) - (sizeY / 2);
  46962. context2D.globalCompositeOperation = 'destination-out';
  46963. context2D.drawImage(image, x - 1, y, sizeX, sizeY);
  46964. context2D.drawImage(image, x, y - 1, sizeX, sizeY);
  46965. context2D.drawImage(image, x + 1, y, sizeX, sizeY);
  46966. context2D.drawImage(image, x, y + 1, sizeX, sizeY);
  46967. context2D.globalCompositeOperation = 'destination-over';
  46968. context2D.fillStyle = Color.BLACK.toCssColorString();
  46969. context2D.fillRect(x - 1, y - 1, sizeX + 1, sizeY + 1);
  46970. context2D.globalCompositeOperation = 'destination-out';
  46971. context2D.drawImage(image, x, y, sizeX, sizeY);
  46972. context2D.globalCompositeOperation = 'destination-over';
  46973. context2D.fillStyle = Color.WHITE.toCssColorString();
  46974. context2D.fillRect(x, y, sizeX, sizeY);
  46975. }
  46976. var stringifyScratch = new Array(4);
  46977. function createPin(url, label, color, size, cache) {
  46978. //Use the parameters as a unique ID for caching.
  46979. stringifyScratch[0] = url;
  46980. stringifyScratch[1] = label;
  46981. stringifyScratch[2] = color;
  46982. stringifyScratch[3] = size;
  46983. var id = JSON.stringify(stringifyScratch);
  46984. var item = cache[id];
  46985. if (defined(item)) {
  46986. return item;
  46987. }
  46988. var canvas = document.createElement('canvas');
  46989. canvas.width = size;
  46990. canvas.height = size;
  46991. var context2D = canvas.getContext("2d");
  46992. drawPin(context2D, color, size);
  46993. if (defined(url)) {
  46994. //If we have an image url, load it and then stamp the pin.
  46995. var promise = loadImage(url).then(function(image) {
  46996. drawIcon(context2D, image, size);
  46997. cache[id] = canvas;
  46998. return canvas;
  46999. });
  47000. cache[id] = promise;
  47001. return promise;
  47002. } else if (defined(label)) {
  47003. //If we have a label, write it to a canvas and then stamp the pin.
  47004. var image = writeTextToCanvas(label, {
  47005. font : 'bold ' + size + 'px sans-serif'
  47006. });
  47007. drawIcon(context2D, image, size);
  47008. }
  47009. cache[id] = canvas;
  47010. return canvas;
  47011. }
  47012. return PinBuilder;
  47013. });
  47014. /*global define*/
  47015. define('Core/PixelFormat',[
  47016. './freezeObject',
  47017. './WebGLConstants'
  47018. ], function(
  47019. freezeObject,
  47020. WebGLConstants) {
  47021. 'use strict';
  47022. /**
  47023. * The format of a pixel, i.e., the number of components it has and what they represent.
  47024. *
  47025. * @exports PixelFormat
  47026. */
  47027. var PixelFormat = {
  47028. /**
  47029. * A pixel format containing a depth value.
  47030. *
  47031. * @type {Number}
  47032. * @constant
  47033. */
  47034. DEPTH_COMPONENT : WebGLConstants.DEPTH_COMPONENT,
  47035. /**
  47036. * A pixel format containing a depth and stencil value, most often used with {@link PixelDatatype.UNSIGNED_INT_24_8}.
  47037. *
  47038. * @type {Number}
  47039. * @constant
  47040. */
  47041. DEPTH_STENCIL : WebGLConstants.DEPTH_STENCIL,
  47042. /**
  47043. * A pixel format containing an alpha channel.
  47044. *
  47045. * @type {Number}
  47046. * @constant
  47047. */
  47048. ALPHA : WebGLConstants.ALPHA,
  47049. /**
  47050. * A pixel format containing red, green, and blue channels.
  47051. *
  47052. * @type {Number}
  47053. * @constant
  47054. */
  47055. RGB : WebGLConstants.RGB,
  47056. /**
  47057. * A pixel format containing red, green, blue, and alpha channels.
  47058. *
  47059. * @type {Number}
  47060. * @constant
  47061. */
  47062. RGBA : WebGLConstants.RGBA,
  47063. /**
  47064. * A pixel format containing a luminance (intensity) channel.
  47065. *
  47066. * @type {Number}
  47067. * @constant
  47068. */
  47069. LUMINANCE : WebGLConstants.LUMINANCE,
  47070. /**
  47071. * A pixel format containing luminance (intensity) and alpha channels.
  47072. *
  47073. * @type {Number}
  47074. * @constant
  47075. */
  47076. LUMINANCE_ALPHA : WebGLConstants.LUMINANCE_ALPHA,
  47077. /**
  47078. * @private
  47079. */
  47080. validate : function(pixelFormat) {
  47081. return pixelFormat === PixelFormat.DEPTH_COMPONENT ||
  47082. pixelFormat === PixelFormat.DEPTH_STENCIL ||
  47083. pixelFormat === PixelFormat.ALPHA ||
  47084. pixelFormat === PixelFormat.RGB ||
  47085. pixelFormat === PixelFormat.RGBA ||
  47086. pixelFormat === PixelFormat.LUMINANCE ||
  47087. pixelFormat === PixelFormat.LUMINANCE_ALPHA;
  47088. },
  47089. /**
  47090. * @private
  47091. */
  47092. isColorFormat : function(pixelFormat) {
  47093. return pixelFormat === PixelFormat.ALPHA ||
  47094. pixelFormat === PixelFormat.RGB ||
  47095. pixelFormat === PixelFormat.RGBA ||
  47096. pixelFormat === PixelFormat.LUMINANCE ||
  47097. pixelFormat === PixelFormat.LUMINANCE_ALPHA;
  47098. },
  47099. /**
  47100. * @private
  47101. */
  47102. isDepthFormat : function(pixelFormat) {
  47103. return pixelFormat === PixelFormat.DEPTH_COMPONENT ||
  47104. pixelFormat === PixelFormat.DEPTH_STENCIL;
  47105. }
  47106. };
  47107. return freezeObject(PixelFormat);
  47108. });
  47109. /*global define*/
  47110. define('Core/PointGeometry',[
  47111. './BoundingSphere',
  47112. './ComponentDatatype',
  47113. './defaultValue',
  47114. './defined',
  47115. './DeveloperError',
  47116. './Geometry',
  47117. './GeometryAttribute',
  47118. './GeometryAttributes',
  47119. './PrimitiveType'
  47120. ], function(
  47121. BoundingSphere,
  47122. ComponentDatatype,
  47123. defaultValue,
  47124. defined,
  47125. DeveloperError,
  47126. Geometry,
  47127. GeometryAttribute,
  47128. GeometryAttributes,
  47129. PrimitiveType) {
  47130. 'use strict';
  47131. /**
  47132. * Describes a collection of points made up of positions and colors.
  47133. *
  47134. * @alias PointGeometry
  47135. * @constructor
  47136. *
  47137. * @param {Object} options Object with the following properties:
  47138. * @param {TypedArray} options.positionsTypedArray The position values of the points stored in a typed array. Positions are stored as packed (x, y, z) floats.
  47139. * @param {TypedArray} options.colorsTypedArray The color values of the points stored in a typed array. Colors are stored as packed (r, g, b) unsigned bytes.
  47140. * @param {BoundingSphere} [options.boundingSphere] Optional precomputed bounding sphere to save computation time.
  47141. *
  47142. * @example
  47143. * // Create a PointGeometry with two points
  47144. * var points = new Cesium.PointGeometry({
  47145. * positionsTypedArray : new Float32Array([0.0, 0.0, 0.0, 1.0, 1.0, 1.0]),
  47146. * colorsTypedArray : new Uint8Array([255, 0, 0, 127, 127, 127]),
  47147. * boundingSphere : boundingSphere
  47148. * });
  47149. * var geometry = Cesium.PointGeometry.createGeometry(points);
  47150. *
  47151. * @private
  47152. */
  47153. function PointGeometry(options) {
  47154. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  47155. if (!defined(options.positionsTypedArray)) {
  47156. throw new DeveloperError('options.positionsTypedArray is required.');
  47157. }
  47158. if (!defined(options.colorsTypedArray)) {
  47159. throw new DeveloperError('options.colorsTypedArray is required');
  47160. }
  47161. this._positionsTypedArray = options.positionsTypedArray;
  47162. this._colorsTypedArray = options.colorsTypedArray;
  47163. this._boundingSphere = BoundingSphere.clone(options.boundingSphere);
  47164. this._workerName = 'createPointGeometry';
  47165. }
  47166. /**
  47167. * Computes the geometric representation a point collection, including its vertices and a bounding sphere.
  47168. *
  47169. * @param {PointGeometry} pointGeometry A description of the points.
  47170. * @returns {Geometry} The computed vertices.
  47171. */
  47172. PointGeometry.createGeometry = function(pointGeometry) {
  47173. var positions = pointGeometry._positionsTypedArray;
  47174. var componentByteLength = positions.byteLength / positions.length;
  47175. var componentDatatype = componentByteLength === 4 ? ComponentDatatype.FLOAT : ComponentDatatype.DOUBLE;
  47176. var attributes = new GeometryAttributes();
  47177. attributes.position = new GeometryAttribute({
  47178. componentDatatype : componentDatatype,
  47179. componentsPerAttribute : 3,
  47180. values : positions
  47181. });
  47182. attributes.color = new GeometryAttribute({
  47183. componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
  47184. componentsPerAttribute : 3,
  47185. values : pointGeometry._colorsTypedArray,
  47186. normalize : true
  47187. });
  47188. // User provided bounding sphere to save computation time.
  47189. var boundingSphere = pointGeometry._boundingSphere;
  47190. if (!defined(boundingSphere)) {
  47191. boundingSphere = BoundingSphere.fromVertices(positions);
  47192. }
  47193. return new Geometry({
  47194. attributes : attributes,
  47195. primitiveType : PrimitiveType.POINTS,
  47196. boundingSphere : boundingSphere
  47197. });
  47198. };
  47199. return PointGeometry;
  47200. });
  47201. /*global define*/
  47202. define('Core/pointInsideTriangle',[
  47203. './barycentricCoordinates',
  47204. './Cartesian3'
  47205. ], function(
  47206. barycentricCoordinates,
  47207. Cartesian3) {
  47208. 'use strict';
  47209. var coords = new Cartesian3();
  47210. /**
  47211. * Determines if a point is inside a triangle.
  47212. *
  47213. * @exports pointInsideTriangle
  47214. *
  47215. * @param {Cartesian2|Cartesian3} point The point to test.
  47216. * @param {Cartesian2|Cartesian3} p0 The first point of the triangle.
  47217. * @param {Cartesian2|Cartesian3} p1 The second point of the triangle.
  47218. * @param {Cartesian2|Cartesian3} p2 The third point of the triangle.
  47219. * @returns {Boolean} <code>true</code> if the point is inside the triangle; otherwise, <code>false</code>.
  47220. *
  47221. * @example
  47222. * // Returns true
  47223. * var p = new Cesium.Cartesian2(0.25, 0.25);
  47224. * var b = Cesium.pointInsideTriangle(p,
  47225. * new Cesium.Cartesian2(0.0, 0.0),
  47226. * new Cesium.Cartesian2(1.0, 0.0),
  47227. * new Cesium.Cartesian2(0.0, 1.0));
  47228. */
  47229. function pointInsideTriangle(point, p0, p1, p2) {
  47230. barycentricCoordinates(point, p0, p1, p2, coords);
  47231. return (coords.x > 0.0) && (coords.y > 0.0) && (coords.z > 0);
  47232. }
  47233. return pointInsideTriangle;
  47234. });
  47235. /*global define*/
  47236. define('Core/Queue',[
  47237. './defineProperties'
  47238. ], function(
  47239. defineProperties) {
  47240. 'use strict';
  47241. /**
  47242. * A queue that can enqueue items at the end, and dequeue items from the front.
  47243. *
  47244. * @alias Queue
  47245. * @constructor
  47246. */
  47247. function Queue() {
  47248. this._array = [];
  47249. this._offset = 0;
  47250. this._length = 0;
  47251. }
  47252. defineProperties(Queue.prototype, {
  47253. /**
  47254. * The length of the queue.
  47255. *
  47256. * @memberof Queue.prototype
  47257. *
  47258. * @type {Number}
  47259. * @readonly
  47260. */
  47261. length : {
  47262. get : function() {
  47263. return this._length;
  47264. }
  47265. }
  47266. });
  47267. /**
  47268. * Enqueues the specified item.
  47269. *
  47270. * @param {Object} item The item to enqueue.
  47271. */
  47272. Queue.prototype.enqueue = function(item) {
  47273. this._array.push(item);
  47274. this._length++;
  47275. };
  47276. /**
  47277. * Dequeues an item. Returns undefined if the queue is empty.
  47278. *
  47279. * @returns {Object} The the dequeued item.
  47280. */
  47281. Queue.prototype.dequeue = function() {
  47282. if (this._length === 0) {
  47283. return undefined;
  47284. }
  47285. var array = this._array;
  47286. var offset = this._offset;
  47287. var item = array[offset];
  47288. array[offset] = undefined;
  47289. offset++;
  47290. if ((offset > 10) && (offset * 2 > array.length)) {
  47291. //compact array
  47292. this._array = array.slice(offset);
  47293. offset = 0;
  47294. }
  47295. this._offset = offset;
  47296. this._length--;
  47297. return item;
  47298. };
  47299. /**
  47300. * Returns the item at the front of the queue. Returns undefined if the queue is empty.
  47301. *
  47302. * @returns {Object} The item at the front of the queue.
  47303. */
  47304. Queue.prototype.peek = function() {
  47305. if (this._length === 0) {
  47306. return undefined;
  47307. }
  47308. return this._array[this._offset];
  47309. };
  47310. /**
  47311. * Check whether this queue contains the specified item.
  47312. *
  47313. * @param {Object} item The item to search for.
  47314. */
  47315. Queue.prototype.contains = function(item) {
  47316. return this._array.indexOf(item) !== -1;
  47317. };
  47318. /**
  47319. * Remove all items from the queue.
  47320. */
  47321. Queue.prototype.clear = function() {
  47322. this._array.length = this._offset = this._length = 0;
  47323. };
  47324. /**
  47325. * Sort the items in the queue in-place.
  47326. *
  47327. * @param {Queue~Comparator} compareFunction A function that defines the sort order.
  47328. */
  47329. Queue.prototype.sort = function(compareFunction) {
  47330. if (this._offset > 0) {
  47331. //compact array
  47332. this._array = this._array.slice(this._offset);
  47333. this._offset = 0;
  47334. }
  47335. this._array.sort(compareFunction);
  47336. };
  47337. /**
  47338. * A function used to compare two items while sorting a queue.
  47339. * @callback Queue~Comparator
  47340. *
  47341. * @param {Object} a An item in the array.
  47342. * @param {Object} b An item in the array.
  47343. * @returns {Number} Returns a negative value if <code>a</code> is less than <code>b</code>,
  47344. * a positive value if <code>a</code> is greater than <code>b</code>, or
  47345. * 0 if <code>a</code> is equal to <code>b</code>.
  47346. *
  47347. * @example
  47348. * function compareNumbers(a, b) {
  47349. * return a - b;
  47350. * }
  47351. */
  47352. return Queue;
  47353. });
  47354. /*global define*/
  47355. define('Core/PolygonGeometryLibrary',[
  47356. './arrayRemoveDuplicates',
  47357. './Cartesian3',
  47358. './ComponentDatatype',
  47359. './defaultValue',
  47360. './defined',
  47361. './Ellipsoid',
  47362. './Geometry',
  47363. './GeometryAttribute',
  47364. './GeometryAttributes',
  47365. './GeometryPipeline',
  47366. './IndexDatatype',
  47367. './Math',
  47368. './PolygonPipeline',
  47369. './PrimitiveType',
  47370. './Queue',
  47371. './WindingOrder'
  47372. ], function(
  47373. arrayRemoveDuplicates,
  47374. Cartesian3,
  47375. ComponentDatatype,
  47376. defaultValue,
  47377. defined,
  47378. Ellipsoid,
  47379. Geometry,
  47380. GeometryAttribute,
  47381. GeometryAttributes,
  47382. GeometryPipeline,
  47383. IndexDatatype,
  47384. CesiumMath,
  47385. PolygonPipeline,
  47386. PrimitiveType,
  47387. Queue,
  47388. WindingOrder) {
  47389. 'use strict';
  47390. /**
  47391. * @private
  47392. */
  47393. var PolygonGeometryLibrary = {};
  47394. PolygonGeometryLibrary.computeHierarchyPackedLength = function(polygonHierarchy) {
  47395. var numComponents = 0;
  47396. var stack = [polygonHierarchy];
  47397. while (stack.length > 0) {
  47398. var hierarchy = stack.pop();
  47399. if (!defined(hierarchy)) {
  47400. continue;
  47401. }
  47402. numComponents += 2;
  47403. var positions = hierarchy.positions;
  47404. var holes = hierarchy.holes;
  47405. if (defined(positions)) {
  47406. numComponents += positions.length * Cartesian3.packedLength;
  47407. }
  47408. if (defined(holes)) {
  47409. var length = holes.length;
  47410. for (var i = 0; i < length; ++i) {
  47411. stack.push(holes[i]);
  47412. }
  47413. }
  47414. }
  47415. return numComponents;
  47416. };
  47417. PolygonGeometryLibrary.packPolygonHierarchy = function(polygonHierarchy, array, startingIndex) {
  47418. var stack = [polygonHierarchy];
  47419. while (stack.length > 0) {
  47420. var hierarchy = stack.pop();
  47421. if (!defined(hierarchy)) {
  47422. continue;
  47423. }
  47424. var positions = hierarchy.positions;
  47425. var holes = hierarchy.holes;
  47426. array[startingIndex++] = defined(positions) ? positions.length : 0;
  47427. array[startingIndex++] = defined(holes) ? holes.length : 0;
  47428. if (defined(positions)) {
  47429. var positionsLength = positions.length;
  47430. for (var i = 0; i < positionsLength; ++i, startingIndex += 3) {
  47431. Cartesian3.pack(positions[i], array, startingIndex);
  47432. }
  47433. }
  47434. if (defined(holes)) {
  47435. var holesLength = holes.length;
  47436. for (var j = 0; j < holesLength; ++j) {
  47437. stack.push(holes[j]);
  47438. }
  47439. }
  47440. }
  47441. return startingIndex;
  47442. };
  47443. PolygonGeometryLibrary.unpackPolygonHierarchy = function(array, startingIndex) {
  47444. var positionsLength = array[startingIndex++];
  47445. var holesLength = array[startingIndex++];
  47446. var positions = new Array(positionsLength);
  47447. var holes = holesLength > 0 ? new Array(holesLength) : undefined;
  47448. for (var i = 0; i < positionsLength; ++i, startingIndex += Cartesian3.packedLength) {
  47449. positions[i] = Cartesian3.unpack(array, startingIndex);
  47450. }
  47451. for (var j = 0; j < holesLength; ++j) {
  47452. holes[j] = PolygonGeometryLibrary.unpackPolygonHierarchy(array, startingIndex);
  47453. startingIndex = holes[j].startingIndex;
  47454. delete holes[j].startingIndex;
  47455. }
  47456. return {
  47457. positions : positions,
  47458. holes : holes,
  47459. startingIndex : startingIndex
  47460. };
  47461. };
  47462. var distanceScratch = new Cartesian3();
  47463. function getPointAtDistance(p0, p1, distance, length) {
  47464. Cartesian3.subtract(p1, p0, distanceScratch);
  47465. Cartesian3.multiplyByScalar(distanceScratch, distance / length, distanceScratch);
  47466. Cartesian3.add(p0, distanceScratch, distanceScratch);
  47467. return [distanceScratch.x, distanceScratch.y, distanceScratch.z];
  47468. }
  47469. PolygonGeometryLibrary.subdivideLineCount = function(p0, p1, minDistance) {
  47470. var distance = Cartesian3.distance(p0, p1);
  47471. var n = distance / minDistance;
  47472. var countDivide = Math.max(0, Math.ceil(Math.log(n) / Math.log(2)));
  47473. return Math.pow(2, countDivide);
  47474. };
  47475. PolygonGeometryLibrary.subdivideLine = function(p0, p1, minDistance, result) {
  47476. var numVertices = PolygonGeometryLibrary.subdivideLineCount(p0, p1, minDistance);
  47477. var length = Cartesian3.distance(p0, p1);
  47478. var distanceBetweenVertices = length / numVertices;
  47479. if (!defined(result)) {
  47480. result = [];
  47481. }
  47482. var positions = result;
  47483. positions.length = numVertices * 3;
  47484. var index = 0;
  47485. for ( var i = 0; i < numVertices; i++) {
  47486. var p = getPointAtDistance(p0, p1, i * distanceBetweenVertices, length);
  47487. positions[index++] = p[0];
  47488. positions[index++] = p[1];
  47489. positions[index++] = p[2];
  47490. }
  47491. return positions;
  47492. };
  47493. var scaleToGeodeticHeightN1 = new Cartesian3();
  47494. var scaleToGeodeticHeightN2 = new Cartesian3();
  47495. var scaleToGeodeticHeightP1 = new Cartesian3();
  47496. var scaleToGeodeticHeightP2 = new Cartesian3();
  47497. PolygonGeometryLibrary.scaleToGeodeticHeightExtruded = function(geometry, maxHeight, minHeight, ellipsoid, perPositionHeight) {
  47498. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  47499. var n1 = scaleToGeodeticHeightN1;
  47500. var n2 = scaleToGeodeticHeightN2;
  47501. var p = scaleToGeodeticHeightP1;
  47502. var p2 = scaleToGeodeticHeightP2;
  47503. if (defined(geometry) && defined(geometry.attributes) && defined(geometry.attributes.position)) {
  47504. var positions = geometry.attributes.position.values;
  47505. var length = positions.length / 2;
  47506. for ( var i = 0; i < length; i += 3) {
  47507. Cartesian3.fromArray(positions, i, p);
  47508. ellipsoid.geodeticSurfaceNormal(p, n1);
  47509. p2 = ellipsoid.scaleToGeodeticSurface(p, p2);
  47510. n2 = Cartesian3.multiplyByScalar(n1, minHeight, n2);
  47511. n2 = Cartesian3.add(p2, n2, n2);
  47512. positions[i + length] = n2.x;
  47513. positions[i + 1 + length] = n2.y;
  47514. positions[i + 2 + length] = n2.z;
  47515. if (perPositionHeight) {
  47516. p2 = Cartesian3.clone(p, p2);
  47517. }
  47518. n2 = Cartesian3.multiplyByScalar(n1, maxHeight, n2);
  47519. n2 = Cartesian3.add(p2, n2, n2);
  47520. positions[i] = n2.x;
  47521. positions[i + 1] = n2.y;
  47522. positions[i + 2] = n2.z;
  47523. }
  47524. }
  47525. return geometry;
  47526. };
  47527. PolygonGeometryLibrary.polygonsFromHierarchy = function(polygonHierarchy, perPositionHeight, tangentPlane, ellipsoid) {
  47528. // create from a polygon hierarchy
  47529. // Algorithm adapted from http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
  47530. var hierarchy = [];
  47531. var polygons = [];
  47532. var queue = new Queue();
  47533. queue.enqueue(polygonHierarchy);
  47534. while (queue.length !== 0) {
  47535. var outerNode = queue.dequeue();
  47536. var outerRing = outerNode.positions;
  47537. var holes = outerNode.holes;
  47538. outerRing = arrayRemoveDuplicates(outerRing, Cartesian3.equalsEpsilon, true);
  47539. if (outerRing.length < 3) {
  47540. continue;
  47541. }
  47542. var positions2D = tangentPlane.projectPointsOntoPlane(outerRing);
  47543. var holeIndices = [];
  47544. var originalWindingOrder = PolygonPipeline.computeWindingOrder2D(positions2D);
  47545. if (originalWindingOrder === WindingOrder.CLOCKWISE) {
  47546. positions2D.reverse();
  47547. outerRing = outerRing.slice().reverse();
  47548. }
  47549. var positions = outerRing.slice();
  47550. var numChildren = defined(holes) ? holes.length : 0;
  47551. var polygonHoles = [];
  47552. var i;
  47553. var j;
  47554. for (i = 0; i < numChildren; i++) {
  47555. var hole = holes[i];
  47556. var holePositions = arrayRemoveDuplicates(hole.positions, Cartesian3.equalsEpsilon, true);
  47557. if (holePositions.length < 3) {
  47558. continue;
  47559. }
  47560. var holePositions2D = tangentPlane.projectPointsOntoPlane(holePositions);
  47561. originalWindingOrder = PolygonPipeline.computeWindingOrder2D(holePositions2D);
  47562. if (originalWindingOrder === WindingOrder.CLOCKWISE) {
  47563. holePositions2D.reverse();
  47564. holePositions = holePositions.slice().reverse();
  47565. }
  47566. polygonHoles.push(holePositions);
  47567. holeIndices.push(positions.length);
  47568. positions = positions.concat(holePositions);
  47569. positions2D = positions2D.concat(holePositions2D);
  47570. var numGrandchildren = 0;
  47571. if (defined(hole.holes)) {
  47572. numGrandchildren = hole.holes.length;
  47573. }
  47574. for (j = 0; j < numGrandchildren; j++) {
  47575. queue.enqueue(hole.holes[j]);
  47576. }
  47577. }
  47578. if (!perPositionHeight) {
  47579. for (i = 0; i < outerRing.length; i++) {
  47580. ellipsoid.scaleToGeodeticSurface(outerRing[i], outerRing[i]);
  47581. }
  47582. for (i = 0; i < polygonHoles.length; i++) {
  47583. var polygonHole = polygonHoles[i];
  47584. for (j = 0; j < polygonHole.length; ++j) {
  47585. ellipsoid.scaleToGeodeticSurface(polygonHole[j], polygonHole[j]);
  47586. }
  47587. }
  47588. }
  47589. hierarchy.push({
  47590. outerRing : outerRing,
  47591. holes : polygonHoles
  47592. });
  47593. polygons.push({
  47594. positions : positions,
  47595. positions2D : positions2D,
  47596. holes : holeIndices
  47597. });
  47598. }
  47599. return {
  47600. hierarchy : hierarchy,
  47601. polygons : polygons
  47602. };
  47603. };
  47604. PolygonGeometryLibrary.createGeometryFromPositions = function(ellipsoid, polygon, granularity, perPositionHeight, vertexFormat) {
  47605. var indices = PolygonPipeline.triangulate(polygon.positions2D, polygon.holes);
  47606. /* If polygon is completely unrenderable, just use the first three vertices */
  47607. if (indices.length < 3) {
  47608. indices = [0, 1, 2];
  47609. }
  47610. var positions = polygon.positions;
  47611. if (perPositionHeight) {
  47612. var length = positions.length;
  47613. var flattenedPositions = new Array(length * 3);
  47614. var index = 0;
  47615. for ( var i = 0; i < length; i++) {
  47616. var p = positions[i];
  47617. flattenedPositions[index++] = p.x;
  47618. flattenedPositions[index++] = p.y;
  47619. flattenedPositions[index++] = p.z;
  47620. }
  47621. var geometry = new Geometry({
  47622. attributes : {
  47623. position : new GeometryAttribute({
  47624. componentDatatype : ComponentDatatype.DOUBLE,
  47625. componentsPerAttribute : 3,
  47626. values : flattenedPositions
  47627. })
  47628. },
  47629. indices : indices,
  47630. primitiveType : PrimitiveType.TRIANGLES
  47631. });
  47632. if (vertexFormat.normal) {
  47633. return GeometryPipeline.computeNormal(geometry);
  47634. }
  47635. return geometry;
  47636. }
  47637. return PolygonPipeline.computeSubdivision(ellipsoid, positions, indices, granularity);
  47638. };
  47639. var computeWallIndicesSubdivided = [];
  47640. var p1Scratch = new Cartesian3();
  47641. var p2Scratch = new Cartesian3();
  47642. PolygonGeometryLibrary.computeWallGeometry = function(positions, ellipsoid, granularity, perPositionHeight) {
  47643. var edgePositions;
  47644. var topEdgeLength;
  47645. var i;
  47646. var p1;
  47647. var p2;
  47648. var length = positions.length;
  47649. var index = 0;
  47650. if (!perPositionHeight) {
  47651. var minDistance = CesiumMath.chordLength(granularity, ellipsoid.maximumRadius);
  47652. var numVertices = 0;
  47653. for (i = 0; i < length; i++) {
  47654. numVertices += PolygonGeometryLibrary.subdivideLineCount(positions[i], positions[(i + 1) % length], minDistance);
  47655. }
  47656. topEdgeLength = (numVertices + length) * 3;
  47657. edgePositions = new Array(topEdgeLength * 2);
  47658. for (i = 0; i < length; i++) {
  47659. p1 = positions[i];
  47660. p2 = positions[(i + 1) % length];
  47661. var tempPositions = PolygonGeometryLibrary.subdivideLine(p1, p2, minDistance, computeWallIndicesSubdivided);
  47662. var tempPositionsLength = tempPositions.length;
  47663. for (var j = 0; j < tempPositionsLength; ++j, ++index) {
  47664. edgePositions[index] = tempPositions[j];
  47665. edgePositions[index + topEdgeLength] = tempPositions[j];
  47666. }
  47667. edgePositions[index] = p2.x;
  47668. edgePositions[index + topEdgeLength] = p2.x;
  47669. ++index;
  47670. edgePositions[index] = p2.y;
  47671. edgePositions[index + topEdgeLength] = p2.y;
  47672. ++index;
  47673. edgePositions[index] = p2.z;
  47674. edgePositions[index + topEdgeLength] = p2.z;
  47675. ++index;
  47676. }
  47677. } else {
  47678. topEdgeLength = length * 3 * 2;
  47679. edgePositions = new Array(topEdgeLength * 2);
  47680. for (i = 0; i < length; i++) {
  47681. p1 = positions[i];
  47682. p2 = positions[(i + 1) % length];
  47683. edgePositions[index] = edgePositions[index + topEdgeLength] = p1.x;
  47684. ++index;
  47685. edgePositions[index] = edgePositions[index + topEdgeLength] = p1.y;
  47686. ++index;
  47687. edgePositions[index] = edgePositions[index + topEdgeLength] = p1.z;
  47688. ++index;
  47689. edgePositions[index] = edgePositions[index + topEdgeLength] = p2.x;
  47690. ++index;
  47691. edgePositions[index] = edgePositions[index + topEdgeLength] = p2.y;
  47692. ++index;
  47693. edgePositions[index] = edgePositions[index + topEdgeLength] = p2.z;
  47694. ++index;
  47695. }
  47696. }
  47697. length = edgePositions.length;
  47698. var indices = IndexDatatype.createTypedArray(length / 3, length - positions.length * 6);
  47699. var edgeIndex = 0;
  47700. length /= 6;
  47701. for (i = 0; i < length; i++) {
  47702. var UL = i;
  47703. var UR = UL + 1;
  47704. var LL = UL + length;
  47705. var LR = LL + 1;
  47706. p1 = Cartesian3.fromArray(edgePositions, UL * 3, p1Scratch);
  47707. p2 = Cartesian3.fromArray(edgePositions, UR * 3, p2Scratch);
  47708. if (Cartesian3.equalsEpsilon(p1, p2, CesiumMath.EPSILON14)) {
  47709. continue;
  47710. }
  47711. indices[edgeIndex++] = UL;
  47712. indices[edgeIndex++] = LL;
  47713. indices[edgeIndex++] = UR;
  47714. indices[edgeIndex++] = UR;
  47715. indices[edgeIndex++] = LL;
  47716. indices[edgeIndex++] = LR;
  47717. }
  47718. return new Geometry({
  47719. attributes : new GeometryAttributes({
  47720. position : new GeometryAttribute({
  47721. componentDatatype : ComponentDatatype.DOUBLE,
  47722. componentsPerAttribute : 3,
  47723. values : edgePositions
  47724. })
  47725. }),
  47726. indices : indices,
  47727. primitiveType : PrimitiveType.TRIANGLES
  47728. });
  47729. };
  47730. return PolygonGeometryLibrary;
  47731. });
  47732. /*global define*/
  47733. define('Core/PolygonGeometry',[
  47734. './BoundingRectangle',
  47735. './BoundingSphere',
  47736. './Cartesian2',
  47737. './Cartesian3',
  47738. './Cartographic',
  47739. './ComponentDatatype',
  47740. './defaultValue',
  47741. './defined',
  47742. './defineProperties',
  47743. './DeveloperError',
  47744. './Ellipsoid',
  47745. './EllipsoidTangentPlane',
  47746. './Geometry',
  47747. './GeometryAttribute',
  47748. './GeometryInstance',
  47749. './GeometryPipeline',
  47750. './IndexDatatype',
  47751. './Math',
  47752. './Matrix3',
  47753. './PolygonGeometryLibrary',
  47754. './PolygonPipeline',
  47755. './Quaternion',
  47756. './Rectangle',
  47757. './VertexFormat',
  47758. './WindingOrder'
  47759. ], function(
  47760. BoundingRectangle,
  47761. BoundingSphere,
  47762. Cartesian2,
  47763. Cartesian3,
  47764. Cartographic,
  47765. ComponentDatatype,
  47766. defaultValue,
  47767. defined,
  47768. defineProperties,
  47769. DeveloperError,
  47770. Ellipsoid,
  47771. EllipsoidTangentPlane,
  47772. Geometry,
  47773. GeometryAttribute,
  47774. GeometryInstance,
  47775. GeometryPipeline,
  47776. IndexDatatype,
  47777. CesiumMath,
  47778. Matrix3,
  47779. PolygonGeometryLibrary,
  47780. PolygonPipeline,
  47781. Quaternion,
  47782. Rectangle,
  47783. VertexFormat,
  47784. WindingOrder) {
  47785. 'use strict';
  47786. var computeBoundingRectangleCartesian2 = new Cartesian2();
  47787. var computeBoundingRectangleCartesian3 = new Cartesian3();
  47788. var computeBoundingRectangleQuaternion = new Quaternion();
  47789. var computeBoundingRectangleMatrix3 = new Matrix3();
  47790. function computeBoundingRectangle(tangentPlane, positions, angle, result) {
  47791. var rotation = Quaternion.fromAxisAngle(tangentPlane._plane.normal, angle, computeBoundingRectangleQuaternion);
  47792. var textureMatrix = Matrix3.fromQuaternion(rotation, computeBoundingRectangleMatrix3);
  47793. var minX = Number.POSITIVE_INFINITY;
  47794. var maxX = Number.NEGATIVE_INFINITY;
  47795. var minY = Number.POSITIVE_INFINITY;
  47796. var maxY = Number.NEGATIVE_INFINITY;
  47797. var length = positions.length;
  47798. for ( var i = 0; i < length; ++i) {
  47799. var p = Cartesian3.clone(positions[i], computeBoundingRectangleCartesian3);
  47800. Matrix3.multiplyByVector(textureMatrix, p, p);
  47801. var st = tangentPlane.projectPointOntoPlane(p, computeBoundingRectangleCartesian2);
  47802. if (defined(st)) {
  47803. minX = Math.min(minX, st.x);
  47804. maxX = Math.max(maxX, st.x);
  47805. minY = Math.min(minY, st.y);
  47806. maxY = Math.max(maxY, st.y);
  47807. }
  47808. }
  47809. result.x = minX;
  47810. result.y = minY;
  47811. result.width = maxX - minX;
  47812. result.height = maxY - minY;
  47813. return result;
  47814. }
  47815. var scratchCarto1 = new Cartographic();
  47816. var scratchCarto2 = new Cartographic();
  47817. function adjustPosHeightsForNormal(position, p1, p2, ellipsoid) {
  47818. var carto1 = ellipsoid.cartesianToCartographic(position, scratchCarto1);
  47819. var height = carto1.height;
  47820. var p1Carto = ellipsoid.cartesianToCartographic(p1, scratchCarto2);
  47821. p1Carto.height = height;
  47822. ellipsoid.cartographicToCartesian(p1Carto, p1);
  47823. var p2Carto = ellipsoid.cartesianToCartographic(p2, scratchCarto2);
  47824. p2Carto.height = height - 100;
  47825. ellipsoid.cartographicToCartesian(p2Carto, p2);
  47826. }
  47827. var scratchBoundingRectangle = new BoundingRectangle();
  47828. var scratchPosition = new Cartesian3();
  47829. var scratchNormal = new Cartesian3();
  47830. var scratchTangent = new Cartesian3();
  47831. var scratchBinormal = new Cartesian3();
  47832. var p1Scratch = new Cartesian3();
  47833. var p2Scratch = new Cartesian3();
  47834. var scratchPerPosNormal = new Cartesian3();
  47835. var scratchPerPosTangent = new Cartesian3();
  47836. var scratchPerPosBinormal = new Cartesian3();
  47837. var appendTextureCoordinatesOrigin = new Cartesian2();
  47838. var appendTextureCoordinatesCartesian2 = new Cartesian2();
  47839. var appendTextureCoordinatesCartesian3 = new Cartesian3();
  47840. var appendTextureCoordinatesQuaternion = new Quaternion();
  47841. var appendTextureCoordinatesMatrix3 = new Matrix3();
  47842. function computeAttributes(options) {
  47843. var vertexFormat = options.vertexFormat;
  47844. var geometry = options.geometry;
  47845. if (vertexFormat.st || vertexFormat.normal || vertexFormat.tangent || vertexFormat.binormal) {
  47846. // PERFORMANCE_IDEA: Compute before subdivision, then just interpolate during subdivision.
  47847. // PERFORMANCE_IDEA: Compute with createGeometryFromPositions() for fast path when there's no holes.
  47848. var boundingRectangle = options.boundingRectangle;
  47849. var tangentPlane = options.tangentPlane;
  47850. var ellipsoid = options.ellipsoid;
  47851. var stRotation = options.stRotation;
  47852. var wall = options.wall;
  47853. var top = options.top || wall;
  47854. var bottom = options.bottom || wall;
  47855. var perPositionHeight = options.perPositionHeight;
  47856. var origin = appendTextureCoordinatesOrigin;
  47857. origin.x = boundingRectangle.x;
  47858. origin.y = boundingRectangle.y;
  47859. var flatPositions = geometry.attributes.position.values;
  47860. var length = flatPositions.length;
  47861. var textureCoordinates = vertexFormat.st ? new Float32Array(2 * (length / 3)) : undefined;
  47862. var normals;
  47863. if (vertexFormat.normal) {
  47864. if (perPositionHeight && top && !wall) {
  47865. normals = geometry.attributes.normal.values;
  47866. } else {
  47867. normals = new Float32Array(length);
  47868. }
  47869. }
  47870. var tangents = vertexFormat.tangent ? new Float32Array(length) : undefined;
  47871. var binormals = vertexFormat.binormal ? new Float32Array(length) : undefined;
  47872. var textureCoordIndex = 0;
  47873. var attrIndex = 0;
  47874. var normal = scratchNormal;
  47875. var tangent = scratchTangent;
  47876. var binormal = scratchBinormal;
  47877. var recomputeNormal = true;
  47878. var rotation = Quaternion.fromAxisAngle(tangentPlane._plane.normal, stRotation, appendTextureCoordinatesQuaternion);
  47879. var textureMatrix = Matrix3.fromQuaternion(rotation, appendTextureCoordinatesMatrix3);
  47880. var bottomOffset = 0;
  47881. var bottomOffset2 = 0;
  47882. if (top && bottom) {
  47883. bottomOffset = length / 2;
  47884. bottomOffset2 = length / 3;
  47885. length /= 2;
  47886. }
  47887. for ( var i = 0; i < length; i += 3) {
  47888. var position = Cartesian3.fromArray(flatPositions, i, appendTextureCoordinatesCartesian3);
  47889. if (vertexFormat.st) {
  47890. var p = Matrix3.multiplyByVector(textureMatrix, position, scratchPosition);
  47891. p = ellipsoid.scaleToGeodeticSurface(p,p);
  47892. var st = tangentPlane.projectPointOntoPlane(p, appendTextureCoordinatesCartesian2);
  47893. Cartesian2.subtract(st, origin, st);
  47894. var stx = CesiumMath.clamp(st.x / boundingRectangle.width, 0, 1);
  47895. var sty = CesiumMath.clamp(st.y / boundingRectangle.height, 0, 1);
  47896. if (bottom) {
  47897. textureCoordinates[textureCoordIndex + bottomOffset2] = stx;
  47898. textureCoordinates[textureCoordIndex + 1 + bottomOffset2] = sty;
  47899. }
  47900. if (top) {
  47901. textureCoordinates[textureCoordIndex] = stx;
  47902. textureCoordinates[textureCoordIndex + 1] = sty;
  47903. }
  47904. textureCoordIndex += 2;
  47905. }
  47906. if (vertexFormat.normal || vertexFormat.tangent || vertexFormat.binormal) {
  47907. var attrIndex1 = attrIndex + 1;
  47908. var attrIndex2 = attrIndex + 2;
  47909. if (wall) {
  47910. if (i + 3 < length) {
  47911. var p1 = Cartesian3.fromArray(flatPositions, i + 3, p1Scratch);
  47912. if (recomputeNormal) {
  47913. var p2 = Cartesian3.fromArray(flatPositions, i + length, p2Scratch);
  47914. if (perPositionHeight) {
  47915. adjustPosHeightsForNormal(position, p1, p2, ellipsoid);
  47916. }
  47917. Cartesian3.subtract(p1, position, p1);
  47918. Cartesian3.subtract(p2, position, p2);
  47919. normal = Cartesian3.normalize(Cartesian3.cross(p2, p1, normal), normal);
  47920. recomputeNormal = false;
  47921. }
  47922. if (Cartesian3.equalsEpsilon(p1, position, CesiumMath.EPSILON10)) { // if we've reached a corner
  47923. recomputeNormal = true;
  47924. }
  47925. }
  47926. if (vertexFormat.tangent || vertexFormat.binormal) {
  47927. binormal = ellipsoid.geodeticSurfaceNormal(position, binormal);
  47928. if (vertexFormat.tangent) {
  47929. tangent = Cartesian3.normalize(Cartesian3.cross(binormal, normal, tangent), tangent);
  47930. }
  47931. }
  47932. } else {
  47933. normal = ellipsoid.geodeticSurfaceNormal(position, normal);
  47934. if (vertexFormat.tangent || vertexFormat.binormal) {
  47935. if (perPositionHeight) {
  47936. scratchPerPosNormal = Cartesian3.fromArray(normals, attrIndex, scratchPerPosNormal);
  47937. scratchPerPosTangent = Cartesian3.cross(Cartesian3.UNIT_Z, scratchPerPosNormal, scratchPerPosTangent);
  47938. scratchPerPosTangent = Cartesian3.normalize(Matrix3.multiplyByVector(textureMatrix, scratchPerPosTangent, scratchPerPosTangent), scratchPerPosTangent);
  47939. if (vertexFormat.binormal) {
  47940. scratchPerPosBinormal = Cartesian3.normalize(Cartesian3.cross(scratchPerPosNormal, scratchPerPosTangent, scratchPerPosBinormal), scratchPerPosBinormal);
  47941. }
  47942. }
  47943. tangent = Cartesian3.cross(Cartesian3.UNIT_Z, normal, tangent);
  47944. tangent = Cartesian3.normalize(Matrix3.multiplyByVector(textureMatrix, tangent, tangent), tangent);
  47945. if (vertexFormat.binormal) {
  47946. binormal = Cartesian3.normalize(Cartesian3.cross(normal, tangent, binormal), binormal);
  47947. }
  47948. }
  47949. }
  47950. if (vertexFormat.normal) {
  47951. if (options.wall) {
  47952. normals[attrIndex + bottomOffset] = normal.x;
  47953. normals[attrIndex1 + bottomOffset] = normal.y;
  47954. normals[attrIndex2 + bottomOffset] = normal.z;
  47955. } else if (bottom){
  47956. normals[attrIndex + bottomOffset] = -normal.x;
  47957. normals[attrIndex1 + bottomOffset] = -normal.y;
  47958. normals[attrIndex2 + bottomOffset] = -normal.z;
  47959. }
  47960. if ((top && !perPositionHeight) || wall) {
  47961. normals[attrIndex] = normal.x;
  47962. normals[attrIndex1] = normal.y;
  47963. normals[attrIndex2] = normal.z;
  47964. }
  47965. }
  47966. if (vertexFormat.tangent) {
  47967. if (options.wall) {
  47968. tangents[attrIndex + bottomOffset] = tangent.x;
  47969. tangents[attrIndex1 + bottomOffset] = tangent.y;
  47970. tangents[attrIndex2 + bottomOffset] = tangent.z;
  47971. } else if (bottom) {
  47972. tangents[attrIndex + bottomOffset] = -tangent.x;
  47973. tangents[attrIndex1 + bottomOffset] = -tangent.y;
  47974. tangents[attrIndex2 + bottomOffset] = -tangent.z;
  47975. }
  47976. if(top) {
  47977. if (perPositionHeight) {
  47978. tangents[attrIndex] = scratchPerPosTangent.x;
  47979. tangents[attrIndex1] = scratchPerPosTangent.y;
  47980. tangents[attrIndex2] = scratchPerPosTangent.z;
  47981. } else {
  47982. tangents[attrIndex] = tangent.x;
  47983. tangents[attrIndex1] = tangent.y;
  47984. tangents[attrIndex2] = tangent.z;
  47985. }
  47986. }
  47987. }
  47988. if (vertexFormat.binormal) {
  47989. if (bottom) {
  47990. binormals[attrIndex + bottomOffset] = binormal.x;
  47991. binormals[attrIndex1 + bottomOffset] = binormal.y;
  47992. binormals[attrIndex2 + bottomOffset] = binormal.z;
  47993. }
  47994. if (top) {
  47995. if (perPositionHeight) {
  47996. binormals[attrIndex] = scratchPerPosBinormal.x;
  47997. binormals[attrIndex1] = scratchPerPosBinormal.y;
  47998. binormals[attrIndex2] = scratchPerPosBinormal.z;
  47999. } else {
  48000. binormals[attrIndex] = binormal.x;
  48001. binormals[attrIndex1] = binormal.y;
  48002. binormals[attrIndex2] = binormal.z;
  48003. }
  48004. }
  48005. }
  48006. attrIndex += 3;
  48007. }
  48008. }
  48009. if (vertexFormat.st) {
  48010. geometry.attributes.st = new GeometryAttribute({
  48011. componentDatatype : ComponentDatatype.FLOAT,
  48012. componentsPerAttribute : 2,
  48013. values : textureCoordinates
  48014. });
  48015. }
  48016. if (vertexFormat.normal) {
  48017. geometry.attributes.normal = new GeometryAttribute({
  48018. componentDatatype : ComponentDatatype.FLOAT,
  48019. componentsPerAttribute : 3,
  48020. values : normals
  48021. });
  48022. }
  48023. if (vertexFormat.tangent) {
  48024. geometry.attributes.tangent = new GeometryAttribute({
  48025. componentDatatype : ComponentDatatype.FLOAT,
  48026. componentsPerAttribute : 3,
  48027. values : tangents
  48028. });
  48029. }
  48030. if (vertexFormat.binormal) {
  48031. geometry.attributes.binormal = new GeometryAttribute({
  48032. componentDatatype : ComponentDatatype.FLOAT,
  48033. componentsPerAttribute : 3,
  48034. values : binormals
  48035. });
  48036. }
  48037. }
  48038. return geometry;
  48039. }
  48040. var createGeometryFromPositionsExtrudedPositions = [];
  48041. function createGeometryFromPositionsExtruded(ellipsoid, polygon, granularity, hierarchy, perPositionHeight, closeTop, closeBottom, vertexFormat) {
  48042. var geos = {
  48043. walls : []
  48044. };
  48045. var i;
  48046. if (closeTop || closeBottom) {
  48047. var topGeo = PolygonGeometryLibrary.createGeometryFromPositions(ellipsoid, polygon, granularity, perPositionHeight, vertexFormat);
  48048. var edgePoints = topGeo.attributes.position.values;
  48049. var indices = topGeo.indices;
  48050. var numPositions;
  48051. var newIndices;
  48052. if (closeTop && closeBottom) {
  48053. var topBottomPositions = edgePoints.concat(edgePoints);
  48054. numPositions = topBottomPositions.length / 3;
  48055. newIndices = IndexDatatype.createTypedArray(numPositions, indices.length * 2);
  48056. newIndices.set(indices);
  48057. var ilength = indices.length;
  48058. var length = numPositions / 2;
  48059. for (i = 0; i < ilength; i += 3) {
  48060. var i0 = newIndices[i] + length;
  48061. var i1 = newIndices[i + 1] + length;
  48062. var i2 = newIndices[i + 2] + length;
  48063. newIndices[i + ilength] = i2;
  48064. newIndices[i + 1 + ilength] = i1;
  48065. newIndices[i + 2 + ilength] = i0;
  48066. }
  48067. topGeo.attributes.position.values = topBottomPositions;
  48068. if (perPositionHeight) {
  48069. var normals = topGeo.attributes.normal.values;
  48070. topGeo.attributes.normal.values = new Float32Array(topBottomPositions.length);
  48071. topGeo.attributes.normal.values.set(normals);
  48072. }
  48073. topGeo.indices = newIndices;
  48074. } else if (closeBottom) {
  48075. numPositions = edgePoints.length / 3;
  48076. newIndices = IndexDatatype.createTypedArray(numPositions, indices.length);
  48077. for (i = 0; i < indices.length; i += 3) {
  48078. newIndices[i] = indices[i + 2];
  48079. newIndices[i + 1] = indices[i + 1];
  48080. newIndices[i + 2] = indices[i];
  48081. }
  48082. topGeo.indices = newIndices;
  48083. }
  48084. geos.topAndBottom = new GeometryInstance({
  48085. geometry : topGeo
  48086. });
  48087. }
  48088. var outerRing = hierarchy.outerRing;
  48089. var tangentPlane = EllipsoidTangentPlane.fromPoints(outerRing, ellipsoid);
  48090. var positions2D = tangentPlane.projectPointsOntoPlane(outerRing, createGeometryFromPositionsExtrudedPositions);
  48091. var windingOrder = PolygonPipeline.computeWindingOrder2D(positions2D);
  48092. if (windingOrder === WindingOrder.CLOCKWISE) {
  48093. outerRing = outerRing.slice().reverse();
  48094. }
  48095. var wallGeo = PolygonGeometryLibrary.computeWallGeometry(outerRing, ellipsoid, granularity, perPositionHeight);
  48096. geos.walls.push(new GeometryInstance({
  48097. geometry : wallGeo
  48098. }));
  48099. var holes = hierarchy.holes;
  48100. for (i = 0; i < holes.length; i++) {
  48101. var hole = holes[i];
  48102. tangentPlane = EllipsoidTangentPlane.fromPoints(hole, ellipsoid);
  48103. positions2D = tangentPlane.projectPointsOntoPlane(hole, createGeometryFromPositionsExtrudedPositions);
  48104. windingOrder = PolygonPipeline.computeWindingOrder2D(positions2D);
  48105. if (windingOrder === WindingOrder.COUNTER_CLOCKWISE) {
  48106. hole = hole.slice().reverse();
  48107. }
  48108. wallGeo = PolygonGeometryLibrary.computeWallGeometry(hole, ellipsoid, granularity);
  48109. geos.walls.push(new GeometryInstance({
  48110. geometry : wallGeo
  48111. }));
  48112. }
  48113. return geos;
  48114. }
  48115. /**
  48116. * A description of a polygon on the ellipsoid. The polygon is defined by a polygon hierarchy. Polygon geometry can be rendered with both {@link Primitive} and {@link GroundPrimitive}.
  48117. *
  48118. * @alias PolygonGeometry
  48119. * @constructor
  48120. *
  48121. * @param {Object} options Object with the following properties:
  48122. * @param {PolygonHierarchy} options.polygonHierarchy A polygon hierarchy that can include holes.
  48123. * @param {Number} [options.height=0.0] The distance in meters between the polygon and the ellipsoid surface.
  48124. * @param {Number} [options.extrudedHeight] The distance in meters between the polygon's extruded face and the ellipsoid surface.
  48125. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  48126. * @param {Number} [options.stRotation=0.0] The rotation of the texture coordinates, in radians. A positive rotation is counter-clockwise.
  48127. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
  48128. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  48129. * @param {Boolean} [options.perPositionHeight=false] Use the height of options.positions for each position instead of using options.height to determine the height.
  48130. * @param {Boolean} [options.closeTop=true] When false, leaves off the top of an extruded polygon open.
  48131. * @param {Boolean} [options.closeBottom=true] When false, leaves off the bottom of an extruded polygon open.
  48132. *
  48133. * @see PolygonGeometry#createGeometry
  48134. * @see PolygonGeometry#fromPositions
  48135. *
  48136. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Polygon.html|Cesium Sandcastle Polygon Demo}
  48137. *
  48138. * @example
  48139. * // 1. create a polygon from points
  48140. * var polygon = new Cesium.PolygonGeometry({
  48141. * polygonHierarchy : new Cesium.PolygonHierarchy(
  48142. * Cesium.Cartesian3.fromDegreesArray([
  48143. * -72.0, 40.0,
  48144. * -70.0, 35.0,
  48145. * -75.0, 30.0,
  48146. * -70.0, 30.0,
  48147. * -68.0, 40.0
  48148. * ])
  48149. * )
  48150. * });
  48151. * var geometry = Cesium.PolygonGeometry.createGeometry(polygon);
  48152. *
  48153. * // 2. create a nested polygon with holes
  48154. * var polygonWithHole = new Cesium.PolygonGeometry({
  48155. * polygonHierarchy : new Cesium.PolygonHierarchy(
  48156. * Cesium.Cartesian3.fromDegreesArray([
  48157. * -109.0, 30.0,
  48158. * -95.0, 30.0,
  48159. * -95.0, 40.0,
  48160. * -109.0, 40.0
  48161. * ]),
  48162. * [new Cesium.PolygonHierarchy(
  48163. * Cesium.Cartesian3.fromDegreesArray([
  48164. * -107.0, 31.0,
  48165. * -107.0, 39.0,
  48166. * -97.0, 39.0,
  48167. * -97.0, 31.0
  48168. * ]),
  48169. * [new Cesium.PolygonHierarchy(
  48170. * Cesium.Cartesian3.fromDegreesArray([
  48171. * -105.0, 33.0,
  48172. * -99.0, 33.0,
  48173. * -99.0, 37.0,
  48174. * -105.0, 37.0
  48175. * ]),
  48176. * [new Cesium.PolygonHierarchy(
  48177. * Cesium.Cartesian3.fromDegreesArray([
  48178. * -103.0, 34.0,
  48179. * -101.0, 34.0,
  48180. * -101.0, 36.0,
  48181. * -103.0, 36.0
  48182. * ])
  48183. * )]
  48184. * )]
  48185. * )]
  48186. * )
  48187. * });
  48188. * var geometry = Cesium.PolygonGeometry.createGeometry(polygonWithHole);
  48189. *
  48190. * // 3. create extruded polygon
  48191. * var extrudedPolygon = new Cesium.PolygonGeometry({
  48192. * polygonHierarchy : new Cesium.PolygonHierarchy(
  48193. * Cesium.Cartesian3.fromDegreesArray([
  48194. * -72.0, 40.0,
  48195. * -70.0, 35.0,
  48196. * -75.0, 30.0,
  48197. * -70.0, 30.0,
  48198. * -68.0, 40.0
  48199. * ])
  48200. * ),
  48201. * extrudedHeight: 300000
  48202. * });
  48203. * var geometry = Cesium.PolygonGeometry.createGeometry(extrudedPolygon);
  48204. */
  48205. function PolygonGeometry(options) {
  48206. if (!defined(options) || !defined(options.polygonHierarchy)) {
  48207. throw new DeveloperError('options.polygonHierarchy is required.');
  48208. }
  48209. if (defined(options.perPositionHeight) && options.perPositionHeight && defined(options.height)) {
  48210. throw new DeveloperError('Cannot use both options.perPositionHeight and options.height');
  48211. }
  48212. var polygonHierarchy = options.polygonHierarchy;
  48213. var vertexFormat = defaultValue(options.vertexFormat, VertexFormat.DEFAULT);
  48214. var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  48215. var granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  48216. var stRotation = defaultValue(options.stRotation, 0.0);
  48217. var height = defaultValue(options.height, 0.0);
  48218. var perPositionHeight = defaultValue(options.perPositionHeight, false);
  48219. var extrudedHeight = options.extrudedHeight;
  48220. var extrude = defined(extrudedHeight);
  48221. if (!perPositionHeight && extrude) {
  48222. //Ignore extrudedHeight if it matches height
  48223. if (CesiumMath.equalsEpsilon(height, extrudedHeight, CesiumMath.EPSILON10)) {
  48224. extrudedHeight = undefined;
  48225. extrude = false;
  48226. } else {
  48227. var h = extrudedHeight;
  48228. extrudedHeight = Math.min(h, height);
  48229. height = Math.max(h, height);
  48230. }
  48231. }
  48232. this._vertexFormat = VertexFormat.clone(vertexFormat);
  48233. this._ellipsoid = Ellipsoid.clone(ellipsoid);
  48234. this._granularity = granularity;
  48235. this._stRotation = stRotation;
  48236. this._height = height;
  48237. this._extrudedHeight = defaultValue(extrudedHeight, 0.0);
  48238. this._extrude = extrude;
  48239. this._closeTop = defaultValue(options.closeTop, true);
  48240. this._closeBottom = defaultValue(options.closeBottom, true);
  48241. this._polygonHierarchy = polygonHierarchy;
  48242. this._perPositionHeight = perPositionHeight;
  48243. this._workerName = 'createPolygonGeometry';
  48244. var positions = polygonHierarchy.positions;
  48245. if (!defined(positions) || positions.length < 3) {
  48246. this._rectangle = new Rectangle();
  48247. } else {
  48248. this._rectangle = Rectangle.fromCartesianArray(positions, ellipsoid);
  48249. }
  48250. /**
  48251. * The number of elements used to pack the object into an array.
  48252. * @type {Number}
  48253. */
  48254. this.packedLength = PolygonGeometryLibrary.computeHierarchyPackedLength(polygonHierarchy) + Ellipsoid.packedLength + VertexFormat.packedLength + Rectangle.packedLength + 9;
  48255. }
  48256. /**
  48257. * A description of a polygon from an array of positions. Polygon geometry can be rendered with both {@link Primitive} and {@link GroundPrimitive}.
  48258. *
  48259. * @param {Object} options Object with the following properties:
  48260. * @param {Cartesian3[]} options.positions An array of positions that defined the corner points of the polygon.
  48261. * @param {Number} [options.height=0.0] The height of the polygon.
  48262. * @param {Number} [options.extrudedHeight] The height of the polygon extrusion.
  48263. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  48264. * @param {Number} [options.stRotation=0.0] The rotation of the texture coordiantes, in radians. A positive rotation is counter-clockwise.
  48265. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
  48266. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  48267. * @param {Boolean} [options.perPositionHeight=false] Use the height of options.positions for each position instead of using options.height to determine the height.
  48268. * @param {Boolean} [options.closeTop=true] When false, leaves off the top of an extruded polygon open.
  48269. * @param {Boolean} [options.closeBottom=true] When false, leaves off the bottom of an extruded polygon open.
  48270. * @returns {PolygonGeometry}
  48271. *
  48272. *
  48273. * @example
  48274. * // create a polygon from points
  48275. * var polygon = Cesium.PolygonGeometry.fromPositions({
  48276. * positions : Cesium.Cartesian3.fromDegreesArray([
  48277. * -72.0, 40.0,
  48278. * -70.0, 35.0,
  48279. * -75.0, 30.0,
  48280. * -70.0, 30.0,
  48281. * -68.0, 40.0
  48282. * ])
  48283. * });
  48284. * var geometry = Cesium.PolygonGeometry.createGeometry(polygon);
  48285. *
  48286. * @see PolygonGeometry#createGeometry
  48287. */
  48288. PolygonGeometry.fromPositions = function(options) {
  48289. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  48290. if (!defined(options.positions)) {
  48291. throw new DeveloperError('options.positions is required.');
  48292. }
  48293. var newOptions = {
  48294. polygonHierarchy : {
  48295. positions : options.positions
  48296. },
  48297. height : options.height,
  48298. extrudedHeight : options.extrudedHeight,
  48299. vertexFormat : options.vertexFormat,
  48300. stRotation : options.stRotation,
  48301. ellipsoid : options.ellipsoid,
  48302. granularity : options.granularity,
  48303. perPositionHeight : options.perPositionHeight,
  48304. closeTop : options.closeTop,
  48305. closeBottom: options.closeBottom
  48306. };
  48307. return new PolygonGeometry(newOptions);
  48308. };
  48309. /**
  48310. * Stores the provided instance into the provided array.
  48311. *
  48312. * @param {PolygonGeometry} value The value to pack.
  48313. * @param {Number[]} array The array to pack into.
  48314. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  48315. *
  48316. * @returns {Number[]} The array that was packed into
  48317. */
  48318. PolygonGeometry.pack = function(value, array, startingIndex) {
  48319. if (!defined(value)) {
  48320. throw new DeveloperError('value is required');
  48321. }
  48322. if (!defined(array)) {
  48323. throw new DeveloperError('array is required');
  48324. }
  48325. startingIndex = defaultValue(startingIndex, 0);
  48326. startingIndex = PolygonGeometryLibrary.packPolygonHierarchy(value._polygonHierarchy, array, startingIndex);
  48327. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  48328. startingIndex += Ellipsoid.packedLength;
  48329. VertexFormat.pack(value._vertexFormat, array, startingIndex);
  48330. startingIndex += VertexFormat.packedLength;
  48331. Rectangle.pack(value._rectangle, array, startingIndex);
  48332. startingIndex += Rectangle.packedLength;
  48333. array[startingIndex++] = value._height;
  48334. array[startingIndex++] = value._extrudedHeight;
  48335. array[startingIndex++] = value._granularity;
  48336. array[startingIndex++] = value._stRotation;
  48337. array[startingIndex++] = value._extrude ? 1.0 : 0.0;
  48338. array[startingIndex++] = value._perPositionHeight ? 1.0 : 0.0;
  48339. array[startingIndex++] = value._closeTop ? 1.0 : 0.0;
  48340. array[startingIndex++] = value._closeBottom ? 1.0 : 0.0;
  48341. array[startingIndex] = value.packedLength;
  48342. return array;
  48343. };
  48344. var scratchEllipsoid = Ellipsoid.clone(Ellipsoid.UNIT_SPHERE);
  48345. var scratchVertexFormat = new VertexFormat();
  48346. var scratchRectangle = new Rectangle();
  48347. //Only used to avoid inaability to default construct.
  48348. var dummyOptions = {
  48349. polygonHierarchy : {}
  48350. };
  48351. /**
  48352. * Retrieves an instance from a packed array.
  48353. *
  48354. * @param {Number[]} array The packed array.
  48355. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  48356. * @param {PolygonGeometry} [result] The object into which to store the result.
  48357. */
  48358. PolygonGeometry.unpack = function(array, startingIndex, result) {
  48359. if (!defined(array)) {
  48360. throw new DeveloperError('array is required');
  48361. }
  48362. startingIndex = defaultValue(startingIndex, 0);
  48363. var polygonHierarchy = PolygonGeometryLibrary.unpackPolygonHierarchy(array, startingIndex);
  48364. startingIndex = polygonHierarchy.startingIndex;
  48365. delete polygonHierarchy.startingIndex;
  48366. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  48367. startingIndex += Ellipsoid.packedLength;
  48368. var vertexFormat = VertexFormat.unpack(array, startingIndex, scratchVertexFormat);
  48369. startingIndex += VertexFormat.packedLength;
  48370. var rectangle = Rectangle.unpack(array, startingIndex, scratchRectangle);
  48371. startingIndex += Rectangle.packedLength;
  48372. var height = array[startingIndex++];
  48373. var extrudedHeight = array[startingIndex++];
  48374. var granularity = array[startingIndex++];
  48375. var stRotation = array[startingIndex++];
  48376. var extrude = array[startingIndex++] === 1.0;
  48377. var perPositionHeight = array[startingIndex++] === 1.0;
  48378. var closeTop = array[startingIndex++] === 1.0;
  48379. var closeBottom = array[startingIndex++] === 1.0;
  48380. var packedLength = array[startingIndex];
  48381. if (!defined(result)) {
  48382. result = new PolygonGeometry(dummyOptions);
  48383. }
  48384. result._polygonHierarchy = polygonHierarchy;
  48385. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  48386. result._vertexFormat = VertexFormat.clone(vertexFormat, result._vertexFormat);
  48387. result._height = height;
  48388. result._extrudedHeight = extrudedHeight;
  48389. result._granularity = granularity;
  48390. result._stRotation = stRotation;
  48391. result._extrude = extrude;
  48392. result._perPositionHeight = perPositionHeight;
  48393. result._closeTop = closeTop;
  48394. result._closeBottom = closeBottom;
  48395. result._rectangle = Rectangle.clone(rectangle);
  48396. result.packedLength = packedLength;
  48397. return result;
  48398. };
  48399. /**
  48400. * Computes the geometric representation of a polygon, including its vertices, indices, and a bounding sphere.
  48401. *
  48402. * @param {PolygonGeometry} polygonGeometry A description of the polygon.
  48403. * @returns {Geometry|undefined} The computed vertices and indices.
  48404. */
  48405. PolygonGeometry.createGeometry = function(polygonGeometry) {
  48406. var vertexFormat = polygonGeometry._vertexFormat;
  48407. var ellipsoid = polygonGeometry._ellipsoid;
  48408. var granularity = polygonGeometry._granularity;
  48409. var stRotation = polygonGeometry._stRotation;
  48410. var height = polygonGeometry._height;
  48411. var extrudedHeight = polygonGeometry._extrudedHeight;
  48412. var extrude = polygonGeometry._extrude;
  48413. var polygonHierarchy = polygonGeometry._polygonHierarchy;
  48414. var perPositionHeight = polygonGeometry._perPositionHeight;
  48415. var closeTop = polygonGeometry._closeTop;
  48416. var closeBottom = polygonGeometry._closeBottom;
  48417. var outerPositions = polygonHierarchy.positions;
  48418. if (outerPositions.length < 3) {
  48419. return;
  48420. }
  48421. var tangentPlane = EllipsoidTangentPlane.fromPoints(outerPositions, ellipsoid);
  48422. var results = PolygonGeometryLibrary.polygonsFromHierarchy(polygonHierarchy, perPositionHeight, tangentPlane, ellipsoid);
  48423. var hierarchy = results.hierarchy;
  48424. var polygons = results.polygons;
  48425. if (hierarchy.length === 0) {
  48426. return;
  48427. }
  48428. outerPositions = hierarchy[0].outerRing;
  48429. var boundingRectangle = computeBoundingRectangle(tangentPlane, outerPositions, stRotation, scratchBoundingRectangle);
  48430. var geometry;
  48431. var geometries = [];
  48432. var options = {
  48433. perPositionHeight: perPositionHeight,
  48434. vertexFormat: vertexFormat,
  48435. geometry: undefined,
  48436. tangentPlane: tangentPlane,
  48437. boundingRectangle: boundingRectangle,
  48438. ellipsoid: ellipsoid,
  48439. stRotation: stRotation,
  48440. bottom: false,
  48441. top: true,
  48442. wall: false
  48443. };
  48444. var i;
  48445. if (extrude) {
  48446. options.top = closeTop;
  48447. options.bottom = closeBottom;
  48448. for (i = 0; i < polygons.length; i++) {
  48449. geometry = createGeometryFromPositionsExtruded(ellipsoid, polygons[i], granularity, hierarchy[i], perPositionHeight, closeTop, closeBottom, vertexFormat);
  48450. var topAndBottom;
  48451. if (closeTop && closeBottom) {
  48452. topAndBottom = geometry.topAndBottom;
  48453. options.geometry = PolygonGeometryLibrary.scaleToGeodeticHeightExtruded(topAndBottom.geometry, height, extrudedHeight, ellipsoid, perPositionHeight);
  48454. } else if (closeTop) {
  48455. topAndBottom = geometry.topAndBottom;
  48456. topAndBottom.geometry.attributes.position.values = PolygonPipeline.scaleToGeodeticHeight(topAndBottom.geometry.attributes.position.values, height, ellipsoid, !perPositionHeight);
  48457. options.geometry = topAndBottom.geometry;
  48458. } else if (closeBottom) {
  48459. topAndBottom = geometry.topAndBottom;
  48460. topAndBottom.geometry.attributes.position.values = PolygonPipeline.scaleToGeodeticHeight(topAndBottom.geometry.attributes.position.values, extrudedHeight, ellipsoid, true);
  48461. options.geometry = topAndBottom.geometry;
  48462. }
  48463. if (closeTop || closeBottom) {
  48464. options.wall = false;
  48465. topAndBottom.geometry = computeAttributes(options);
  48466. geometries.push(topAndBottom);
  48467. }
  48468. var walls = geometry.walls;
  48469. options.wall = true;
  48470. for ( var k = 0; k < walls.length; k++) {
  48471. var wall = walls[k];
  48472. options.geometry = PolygonGeometryLibrary.scaleToGeodeticHeightExtruded(wall.geometry, height, extrudedHeight, ellipsoid, perPositionHeight);
  48473. wall.geometry = computeAttributes(options);
  48474. geometries.push(wall);
  48475. }
  48476. }
  48477. } else {
  48478. for (i = 0; i < polygons.length; i++) {
  48479. geometry = new GeometryInstance({
  48480. geometry : PolygonGeometryLibrary.createGeometryFromPositions(ellipsoid, polygons[i], granularity, perPositionHeight, vertexFormat)
  48481. });
  48482. geometry.geometry.attributes.position.values = PolygonPipeline.scaleToGeodeticHeight(geometry.geometry.attributes.position.values, height, ellipsoid, !perPositionHeight);
  48483. options.geometry = geometry.geometry;
  48484. geometry.geometry = computeAttributes(options);
  48485. geometries.push(geometry);
  48486. }
  48487. }
  48488. geometry = GeometryPipeline.combineInstances(geometries)[0];
  48489. geometry.attributes.position.values = new Float64Array(geometry.attributes.position.values);
  48490. geometry.indices = IndexDatatype.createTypedArray(geometry.attributes.position.values.length / 3, geometry.indices);
  48491. var attributes = geometry.attributes;
  48492. var boundingSphere = BoundingSphere.fromVertices(attributes.position.values);
  48493. if (!vertexFormat.position) {
  48494. delete attributes.position;
  48495. }
  48496. return new Geometry({
  48497. attributes : attributes,
  48498. indices : geometry.indices,
  48499. primitiveType : geometry.primitiveType,
  48500. boundingSphere : boundingSphere
  48501. });
  48502. };
  48503. /**
  48504. * @private
  48505. */
  48506. PolygonGeometry.createShadowVolume = function(polygonGeometry, minHeightFunc, maxHeightFunc) {
  48507. var granularity = polygonGeometry._granularity;
  48508. var ellipsoid = polygonGeometry._ellipsoid;
  48509. var minHeight = minHeightFunc(granularity, ellipsoid);
  48510. var maxHeight = maxHeightFunc(granularity, ellipsoid);
  48511. return new PolygonGeometry({
  48512. polygonHierarchy : polygonGeometry._polygonHierarchy,
  48513. ellipsoid : ellipsoid,
  48514. stRotation : polygonGeometry._stRotation,
  48515. granularity : granularity,
  48516. perPositionHeight : false,
  48517. extrudedHeight : minHeight,
  48518. height : maxHeight,
  48519. vertexFormat : VertexFormat.POSITION_ONLY
  48520. });
  48521. };
  48522. defineProperties(PolygonGeometry.prototype, {
  48523. /**
  48524. * @private
  48525. */
  48526. rectangle : {
  48527. get : function() {
  48528. return this._rectangle;
  48529. }
  48530. }
  48531. });
  48532. return PolygonGeometry;
  48533. });
  48534. /*global define*/
  48535. define('Core/PolygonHierarchy',[
  48536. './defined'
  48537. ], function(
  48538. defined) {
  48539. 'use strict';
  48540. /**
  48541. * An hierarchy of linear rings which define a polygon and its holes.
  48542. * The holes themselves may also have holes which nest inner polygons.
  48543. * @alias PolygonHierarchy
  48544. * @constructor
  48545. *
  48546. * @param {Cartesian3[]} [positions] A linear ring defining the outer boundary of the polygon or hole.
  48547. * @param {PolygonHierarchy[]} [holes] An array of polygon hierarchies defining holes in the polygon.
  48548. */
  48549. function PolygonHierarchy(positions, holes) {
  48550. /**
  48551. * A linear ring defining the outer boundary of the polygon or hole.
  48552. * @type {Cartesian3[]}
  48553. */
  48554. this.positions = defined(positions) ? positions : [];
  48555. /**
  48556. * An array of polygon hierarchies defining holes in the polygon.
  48557. * @type {PolygonHierarchy[]}
  48558. */
  48559. this.holes = defined(holes) ? holes : [];
  48560. }
  48561. return PolygonHierarchy;
  48562. });
  48563. /*global define*/
  48564. define('Core/PolygonOutlineGeometry',[
  48565. './arrayRemoveDuplicates',
  48566. './BoundingSphere',
  48567. './Cartesian3',
  48568. './ComponentDatatype',
  48569. './defaultValue',
  48570. './defined',
  48571. './DeveloperError',
  48572. './Ellipsoid',
  48573. './EllipsoidTangentPlane',
  48574. './Geometry',
  48575. './GeometryAttribute',
  48576. './GeometryAttributes',
  48577. './GeometryInstance',
  48578. './GeometryPipeline',
  48579. './IndexDatatype',
  48580. './Math',
  48581. './PolygonGeometryLibrary',
  48582. './PolygonPipeline',
  48583. './PrimitiveType',
  48584. './Queue',
  48585. './WindingOrder'
  48586. ], function(
  48587. arrayRemoveDuplicates,
  48588. BoundingSphere,
  48589. Cartesian3,
  48590. ComponentDatatype,
  48591. defaultValue,
  48592. defined,
  48593. DeveloperError,
  48594. Ellipsoid,
  48595. EllipsoidTangentPlane,
  48596. Geometry,
  48597. GeometryAttribute,
  48598. GeometryAttributes,
  48599. GeometryInstance,
  48600. GeometryPipeline,
  48601. IndexDatatype,
  48602. CesiumMath,
  48603. PolygonGeometryLibrary,
  48604. PolygonPipeline,
  48605. PrimitiveType,
  48606. Queue,
  48607. WindingOrder) {
  48608. 'use strict';
  48609. var createGeometryFromPositionsPositions = [];
  48610. var createGeometryFromPositionsSubdivided = [];
  48611. function createGeometryFromPositions(ellipsoid, positions, minDistance, perPositionHeight) {
  48612. var tangentPlane = EllipsoidTangentPlane.fromPoints(positions, ellipsoid);
  48613. var positions2D = tangentPlane.projectPointsOntoPlane(positions, createGeometryFromPositionsPositions);
  48614. var originalWindingOrder = PolygonPipeline.computeWindingOrder2D(positions2D);
  48615. if (originalWindingOrder === WindingOrder.CLOCKWISE) {
  48616. positions2D.reverse();
  48617. positions = positions.slice().reverse();
  48618. }
  48619. var subdividedPositions;
  48620. var i;
  48621. var length = positions.length;
  48622. var index = 0;
  48623. if (!perPositionHeight) {
  48624. var numVertices = 0;
  48625. for (i = 0; i < length; i++) {
  48626. numVertices += PolygonGeometryLibrary.subdivideLineCount(positions[i], positions[(i + 1) % length], minDistance);
  48627. }
  48628. subdividedPositions = new Float64Array(numVertices * 3);
  48629. for (i = 0; i < length; i++) {
  48630. var tempPositions = PolygonGeometryLibrary.subdivideLine(positions[i], positions[(i + 1) % length], minDistance, createGeometryFromPositionsSubdivided);
  48631. var tempPositionsLength = tempPositions.length;
  48632. for (var j = 0; j < tempPositionsLength; ++j) {
  48633. subdividedPositions[index++] = tempPositions[j];
  48634. }
  48635. }
  48636. } else {
  48637. subdividedPositions = new Float64Array(length * 2 * 3);
  48638. for (i = 0; i < length; i++) {
  48639. var p0 = positions[i];
  48640. var p1 = positions[(i + 1) % length];
  48641. subdividedPositions[index++] = p0.x;
  48642. subdividedPositions[index++] = p0.y;
  48643. subdividedPositions[index++] = p0.z;
  48644. subdividedPositions[index++] = p1.x;
  48645. subdividedPositions[index++] = p1.y;
  48646. subdividedPositions[index++] = p1.z;
  48647. }
  48648. }
  48649. length = subdividedPositions.length / 3;
  48650. var indicesSize = length * 2;
  48651. var indices = IndexDatatype.createTypedArray(length, indicesSize);
  48652. index = 0;
  48653. for (i = 0; i < length - 1; i++) {
  48654. indices[index++] = i;
  48655. indices[index++] = i + 1;
  48656. }
  48657. indices[index++] = length - 1;
  48658. indices[index++] = 0;
  48659. return new GeometryInstance({
  48660. geometry : new Geometry({
  48661. attributes : new GeometryAttributes({
  48662. position : new GeometryAttribute({
  48663. componentDatatype : ComponentDatatype.DOUBLE,
  48664. componentsPerAttribute : 3,
  48665. values : subdividedPositions
  48666. })
  48667. }),
  48668. indices : indices,
  48669. primitiveType : PrimitiveType.LINES
  48670. })
  48671. });
  48672. }
  48673. function createGeometryFromPositionsExtruded(ellipsoid, positions, minDistance, perPositionHeight) {
  48674. var tangentPlane = EllipsoidTangentPlane.fromPoints(positions, ellipsoid);
  48675. var positions2D = tangentPlane.projectPointsOntoPlane(positions, createGeometryFromPositionsPositions);
  48676. var originalWindingOrder = PolygonPipeline.computeWindingOrder2D(positions2D);
  48677. if (originalWindingOrder === WindingOrder.CLOCKWISE) {
  48678. positions2D.reverse();
  48679. positions = positions.slice().reverse();
  48680. }
  48681. var subdividedPositions;
  48682. var i;
  48683. var length = positions.length;
  48684. var corners = new Array(length);
  48685. var index = 0;
  48686. if (!perPositionHeight) {
  48687. var numVertices = 0;
  48688. for (i = 0; i < length; i++) {
  48689. numVertices += PolygonGeometryLibrary.subdivideLineCount(positions[i], positions[(i + 1) % length], minDistance);
  48690. }
  48691. subdividedPositions = new Float64Array(numVertices * 3 * 2);
  48692. for (i = 0; i < length; ++i) {
  48693. corners[i] = index / 3;
  48694. var tempPositions = PolygonGeometryLibrary.subdivideLine(positions[i], positions[(i + 1) % length], minDistance, createGeometryFromPositionsSubdivided);
  48695. var tempPositionsLength = tempPositions.length;
  48696. for (var j = 0; j < tempPositionsLength; ++j) {
  48697. subdividedPositions[index++] = tempPositions[j];
  48698. }
  48699. }
  48700. } else {
  48701. subdividedPositions = new Float64Array(length * 2 * 3 * 2);
  48702. for (i = 0; i < length; ++i) {
  48703. corners[i] = index / 3;
  48704. var p0 = positions[i];
  48705. var p1 = positions[(i + 1) % length];
  48706. subdividedPositions[index++] = p0.x;
  48707. subdividedPositions[index++] = p0.y;
  48708. subdividedPositions[index++] = p0.z;
  48709. subdividedPositions[index++] = p1.x;
  48710. subdividedPositions[index++] = p1.y;
  48711. subdividedPositions[index++] = p1.z;
  48712. }
  48713. }
  48714. length = subdividedPositions.length / (3 * 2);
  48715. var cornersLength = corners.length;
  48716. var indicesSize = ((length * 2) + cornersLength) * 2;
  48717. var indices = IndexDatatype.createTypedArray(length, indicesSize);
  48718. index = 0;
  48719. for (i = 0; i < length; ++i) {
  48720. indices[index++] = i;
  48721. indices[index++] = (i + 1) % length;
  48722. indices[index++] = i + length;
  48723. indices[index++] = ((i + 1) % length) + length;
  48724. }
  48725. for (i = 0; i < cornersLength; i++) {
  48726. var corner = corners[i];
  48727. indices[index++] = corner;
  48728. indices[index++] = corner + length;
  48729. }
  48730. return new GeometryInstance({
  48731. geometry : new Geometry({
  48732. attributes : new GeometryAttributes({
  48733. position : new GeometryAttribute({
  48734. componentDatatype : ComponentDatatype.DOUBLE,
  48735. componentsPerAttribute : 3,
  48736. values : subdividedPositions
  48737. })
  48738. }),
  48739. indices : indices,
  48740. primitiveType : PrimitiveType.LINES
  48741. })
  48742. });
  48743. }
  48744. /**
  48745. * A description of the outline of a polygon on the ellipsoid. The polygon is defined by a polygon hierarchy.
  48746. *
  48747. * @alias PolygonOutlineGeometry
  48748. * @constructor
  48749. *
  48750. * @param {Object} options Object with the following properties:
  48751. * @param {PolygonHierarchy} options.polygonHierarchy A polygon hierarchy that can include holes.
  48752. * @param {Number} [options.height=0.0] The distance in meters between the polygon and the ellipsoid surface.
  48753. * @param {Number} [options.extrudedHeight] The distance in meters between the polygon's extruded face and the ellipsoid surface.
  48754. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  48755. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
  48756. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  48757. * @param {Boolean} [options.perPositionHeight=false] Use the height of options.positions for each position instead of using options.height to determine the height.
  48758. *
  48759. * @see PolygonOutlineGeometry#createGeometry
  48760. * @see PolygonOutlineGeometry#fromPositions
  48761. *
  48762. * @example
  48763. * // 1. create a polygon outline from points
  48764. * var polygon = new Cesium.PolygonOutlineGeometry({
  48765. * polygonHierarchy : new Cesium.PolygonHierarchy(
  48766. * Cesium.Cartesian3.fromDegreesArray([
  48767. * -72.0, 40.0,
  48768. * -70.0, 35.0,
  48769. * -75.0, 30.0,
  48770. * -70.0, 30.0,
  48771. * -68.0, 40.0
  48772. * ])
  48773. * )
  48774. * });
  48775. * var geometry = Cesium.PolygonOutlineGeometry.createGeometry(polygon);
  48776. *
  48777. * // 2. create a nested polygon with holes outline
  48778. * var polygonWithHole = new Cesium.PolygonOutlineGeometry({
  48779. * polygonHierarchy : new Cesium.PolygonHierarchy(
  48780. * Cesium.Cartesian3.fromDegreesArray([
  48781. * -109.0, 30.0,
  48782. * -95.0, 30.0,
  48783. * -95.0, 40.0,
  48784. * -109.0, 40.0
  48785. * ]),
  48786. * [new Cesium.PolygonHierarchy(
  48787. * Cesium.Cartesian3.fromDegreesArray([
  48788. * -107.0, 31.0,
  48789. * -107.0, 39.0,
  48790. * -97.0, 39.0,
  48791. * -97.0, 31.0
  48792. * ]),
  48793. * [new Cesium.PolygonHierarchy(
  48794. * Cesium.Cartesian3.fromDegreesArray([
  48795. * -105.0, 33.0,
  48796. * -99.0, 33.0,
  48797. * -99.0, 37.0,
  48798. * -105.0, 37.0
  48799. * ]),
  48800. * [new Cesium.PolygonHierarchy(
  48801. * Cesium.Cartesian3.fromDegreesArray([
  48802. * -103.0, 34.0,
  48803. * -101.0, 34.0,
  48804. * -101.0, 36.0,
  48805. * -103.0, 36.0
  48806. * ])
  48807. * )]
  48808. * )]
  48809. * )]
  48810. * )
  48811. * });
  48812. * var geometry = Cesium.PolygonOutlineGeometry.createGeometry(polygonWithHole);
  48813. *
  48814. * // 3. create extruded polygon outline
  48815. * var extrudedPolygon = new Cesium.PolygonOutlineGeometry({
  48816. * polygonHierarchy : new Cesium.PolygonHierarchy(
  48817. * Cesium.Cartesian3.fromDegreesArray([
  48818. * -72.0, 40.0,
  48819. * -70.0, 35.0,
  48820. * -75.0, 30.0,
  48821. * -70.0, 30.0,
  48822. * -68.0, 40.0
  48823. * ])
  48824. * ),
  48825. * extrudedHeight: 300000
  48826. * });
  48827. * var geometry = Cesium.PolygonOutlineGeometry.createGeometry(extrudedPolygon);
  48828. */
  48829. function PolygonOutlineGeometry(options) {
  48830. if (!defined(options) || !defined(options.polygonHierarchy)) {
  48831. throw new DeveloperError('options.polygonHierarchy is required.');
  48832. }
  48833. if (defined(options.perPositionHeight) && options.perPositionHeight && defined(options.height)) {
  48834. throw new DeveloperError('Cannot use both options.perPositionHeight and options.height');
  48835. }
  48836. var polygonHierarchy = options.polygonHierarchy;
  48837. var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  48838. var granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  48839. var height = defaultValue(options.height, 0.0);
  48840. var perPositionHeight = defaultValue(options.perPositionHeight, false);
  48841. var extrudedHeight = options.extrudedHeight;
  48842. var extrude = defined(extrudedHeight);
  48843. if (extrude && !perPositionHeight) {
  48844. var h = extrudedHeight;
  48845. extrudedHeight = Math.min(h, height);
  48846. height = Math.max(h, height);
  48847. }
  48848. this._ellipsoid = Ellipsoid.clone(ellipsoid);
  48849. this._granularity = granularity;
  48850. this._height = height;
  48851. this._extrudedHeight = defaultValue(extrudedHeight, 0.0);
  48852. this._extrude = extrude;
  48853. this._polygonHierarchy = polygonHierarchy;
  48854. this._perPositionHeight = perPositionHeight;
  48855. this._workerName = 'createPolygonOutlineGeometry';
  48856. /**
  48857. * The number of elements used to pack the object into an array.
  48858. * @type {Number}
  48859. */
  48860. this.packedLength = PolygonGeometryLibrary.computeHierarchyPackedLength(polygonHierarchy) + Ellipsoid.packedLength + 6;
  48861. }
  48862. /**
  48863. * Stores the provided instance into the provided array.
  48864. *
  48865. * @param {PolygonOutlineGeometry} value The value to pack.
  48866. * @param {Number[]} array The array to pack into.
  48867. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  48868. *
  48869. * @returns {Number[]} The array that was packed into
  48870. */
  48871. PolygonOutlineGeometry.pack = function(value, array, startingIndex) {
  48872. if (!defined(value)) {
  48873. throw new DeveloperError('value is required');
  48874. }
  48875. if (!defined(array)) {
  48876. throw new DeveloperError('array is required');
  48877. }
  48878. startingIndex = defaultValue(startingIndex, 0);
  48879. startingIndex = PolygonGeometryLibrary.packPolygonHierarchy(value._polygonHierarchy, array, startingIndex);
  48880. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  48881. startingIndex += Ellipsoid.packedLength;
  48882. array[startingIndex++] = value._height;
  48883. array[startingIndex++] = value._extrudedHeight;
  48884. array[startingIndex++] = value._granularity;
  48885. array[startingIndex++] = value._extrude ? 1.0 : 0.0;
  48886. array[startingIndex++] = value._perPositionHeight ? 1.0 : 0.0;
  48887. array[startingIndex++] = value.packedLength;
  48888. return array;
  48889. };
  48890. var scratchEllipsoid = Ellipsoid.clone(Ellipsoid.UNIT_SPHERE);
  48891. var dummyOptions = {
  48892. polygonHierarchy : {}
  48893. };
  48894. /**
  48895. * Retrieves an instance from a packed array.
  48896. *
  48897. * @param {Number[]} array The packed array.
  48898. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  48899. * @param {PolygonOutlineGeometry} [result] The object into which to store the result.
  48900. * @returns {PolygonOutlineGeometry} The modified result parameter or a new PolygonOutlineGeometry instance if one was not provided.
  48901. */
  48902. PolygonOutlineGeometry.unpack = function(array, startingIndex, result) {
  48903. if (!defined(array)) {
  48904. throw new DeveloperError('array is required');
  48905. }
  48906. startingIndex = defaultValue(startingIndex, 0);
  48907. var polygonHierarchy = PolygonGeometryLibrary.unpackPolygonHierarchy(array, startingIndex);
  48908. startingIndex = polygonHierarchy.startingIndex;
  48909. delete polygonHierarchy.startingIndex;
  48910. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  48911. startingIndex += Ellipsoid.packedLength;
  48912. var height = array[startingIndex++];
  48913. var extrudedHeight = array[startingIndex++];
  48914. var granularity = array[startingIndex++];
  48915. var extrude = array[startingIndex++] === 1.0;
  48916. var perPositionHeight = array[startingIndex++] === 1.0;
  48917. var packedLength = array[startingIndex++];
  48918. if (!defined(result)) {
  48919. result = new PolygonOutlineGeometry(dummyOptions);
  48920. }
  48921. result._polygonHierarchy = polygonHierarchy;
  48922. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  48923. result._height = height;
  48924. result._extrudedHeight = extrudedHeight;
  48925. result._granularity = granularity;
  48926. result._extrude = extrude;
  48927. result._perPositionHeight = perPositionHeight;
  48928. result.packedLength = packedLength;
  48929. return result;
  48930. };
  48931. /**
  48932. * A description of a polygon outline from an array of positions.
  48933. *
  48934. * @param {Object} options Object with the following properties:
  48935. * @param {Cartesian3[]} options.positions An array of positions that defined the corner points of the polygon.
  48936. * @param {Number} [options.height=0.0] The height of the polygon.
  48937. * @param {Number} [options.extrudedHeight] The height of the polygon extrusion.
  48938. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
  48939. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  48940. * @param {Boolean} [options.perPositionHeight=false] Use the height of options.positions for each position instead of using options.height to determine the height.
  48941. * @returns {PolygonOutlineGeometry}
  48942. *
  48943. *
  48944. * @example
  48945. * // create a polygon from points
  48946. * var polygon = Cesium.PolygonOutlineGeometry.fromPositions({
  48947. * positions : Cesium.Cartesian3.fromDegreesArray([
  48948. * -72.0, 40.0,
  48949. * -70.0, 35.0,
  48950. * -75.0, 30.0,
  48951. * -70.0, 30.0,
  48952. * -68.0, 40.0
  48953. * ])
  48954. * });
  48955. * var geometry = Cesium.PolygonOutlineGeometry.createGeometry(polygon);
  48956. *
  48957. * @see PolygonOutlineGeometry#createGeometry
  48958. */
  48959. PolygonOutlineGeometry.fromPositions = function(options) {
  48960. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  48961. if (!defined(options.positions)) {
  48962. throw new DeveloperError('options.positions is required.');
  48963. }
  48964. var newOptions = {
  48965. polygonHierarchy : {
  48966. positions : options.positions
  48967. },
  48968. height : options.height,
  48969. extrudedHeight : options.extrudedHeight,
  48970. ellipsoid : options.ellipsoid,
  48971. granularity : options.granularity,
  48972. perPositionHeight : options.perPositionHeight
  48973. };
  48974. return new PolygonOutlineGeometry(newOptions);
  48975. };
  48976. /**
  48977. * Computes the geometric representation of a polygon outline, including its vertices, indices, and a bounding sphere.
  48978. *
  48979. * @param {PolygonOutlineGeometry} polygonGeometry A description of the polygon outline.
  48980. * @returns {Geometry|undefined} The computed vertices and indices.
  48981. */
  48982. PolygonOutlineGeometry.createGeometry = function(polygonGeometry) {
  48983. var ellipsoid = polygonGeometry._ellipsoid;
  48984. var granularity = polygonGeometry._granularity;
  48985. var height = polygonGeometry._height;
  48986. var extrudedHeight = polygonGeometry._extrudedHeight;
  48987. var extrude = polygonGeometry._extrude;
  48988. var polygonHierarchy = polygonGeometry._polygonHierarchy;
  48989. var perPositionHeight = polygonGeometry._perPositionHeight;
  48990. // create from a polygon hierarchy
  48991. // Algorithm adapted from http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
  48992. var polygons = [];
  48993. var queue = new Queue();
  48994. queue.enqueue(polygonHierarchy);
  48995. var i;
  48996. while (queue.length !== 0) {
  48997. var outerNode = queue.dequeue();
  48998. var outerRing = outerNode.positions;
  48999. outerRing = arrayRemoveDuplicates(outerRing, Cartesian3.equalsEpsilon, true);
  49000. if (outerRing.length < 3) {
  49001. continue;
  49002. }
  49003. var numChildren = outerNode.holes ? outerNode.holes.length : 0;
  49004. // The outer polygon contains inner polygons
  49005. for (i = 0; i < numChildren; i++) {
  49006. var hole = outerNode.holes[i];
  49007. hole.positions = arrayRemoveDuplicates(hole.positions, Cartesian3.equalsEpsilon, true);
  49008. if (hole.positions.length < 3) {
  49009. continue;
  49010. }
  49011. polygons.push(hole.positions);
  49012. var numGrandchildren = 0;
  49013. if (defined(hole.holes)) {
  49014. numGrandchildren = hole.holes.length;
  49015. }
  49016. for ( var j = 0; j < numGrandchildren; j++) {
  49017. queue.enqueue(hole.holes[j]);
  49018. }
  49019. }
  49020. polygons.push(outerRing);
  49021. }
  49022. if (polygons.length === 0) {
  49023. return undefined;
  49024. }
  49025. var geometry;
  49026. var geometries = [];
  49027. var minDistance = CesiumMath.chordLength(granularity, ellipsoid.maximumRadius);
  49028. if (extrude) {
  49029. for (i = 0; i < polygons.length; i++) {
  49030. geometry = createGeometryFromPositionsExtruded(ellipsoid, polygons[i], minDistance, perPositionHeight);
  49031. geometry.geometry = PolygonGeometryLibrary.scaleToGeodeticHeightExtruded(geometry.geometry, height, extrudedHeight, ellipsoid, perPositionHeight);
  49032. geometries.push(geometry);
  49033. }
  49034. } else {
  49035. for (i = 0; i < polygons.length; i++) {
  49036. geometry = createGeometryFromPositions(ellipsoid, polygons[i], minDistance, perPositionHeight);
  49037. geometry.geometry.attributes.position.values = PolygonPipeline.scaleToGeodeticHeight(geometry.geometry.attributes.position.values, height, ellipsoid, !perPositionHeight);
  49038. geometries.push(geometry);
  49039. }
  49040. }
  49041. geometry = GeometryPipeline.combineInstances(geometries)[0];
  49042. var boundingSphere = BoundingSphere.fromVertices(geometry.attributes.position.values);
  49043. return new Geometry({
  49044. attributes : geometry.attributes,
  49045. indices : geometry.indices,
  49046. primitiveType : geometry.primitiveType,
  49047. boundingSphere : boundingSphere
  49048. });
  49049. };
  49050. return PolygonOutlineGeometry;
  49051. });
  49052. /*global define*/
  49053. define('Core/PolylineGeometry',[
  49054. './arrayRemoveDuplicates',
  49055. './BoundingSphere',
  49056. './Cartesian3',
  49057. './Color',
  49058. './ComponentDatatype',
  49059. './defaultValue',
  49060. './defined',
  49061. './DeveloperError',
  49062. './Ellipsoid',
  49063. './Geometry',
  49064. './GeometryAttribute',
  49065. './GeometryAttributes',
  49066. './GeometryType',
  49067. './IndexDatatype',
  49068. './Math',
  49069. './PolylinePipeline',
  49070. './PrimitiveType',
  49071. './VertexFormat'
  49072. ], function(
  49073. arrayRemoveDuplicates,
  49074. BoundingSphere,
  49075. Cartesian3,
  49076. Color,
  49077. ComponentDatatype,
  49078. defaultValue,
  49079. defined,
  49080. DeveloperError,
  49081. Ellipsoid,
  49082. Geometry,
  49083. GeometryAttribute,
  49084. GeometryAttributes,
  49085. GeometryType,
  49086. IndexDatatype,
  49087. CesiumMath,
  49088. PolylinePipeline,
  49089. PrimitiveType,
  49090. VertexFormat) {
  49091. 'use strict';
  49092. var scratchInterpolateColorsArray = [];
  49093. function interpolateColors(p0, p1, color0, color1, numPoints) {
  49094. var colors = scratchInterpolateColorsArray;
  49095. colors.length = numPoints;
  49096. var i;
  49097. var r0 = color0.red;
  49098. var g0 = color0.green;
  49099. var b0 = color0.blue;
  49100. var a0 = color0.alpha;
  49101. var r1 = color1.red;
  49102. var g1 = color1.green;
  49103. var b1 = color1.blue;
  49104. var a1 = color1.alpha;
  49105. if (Color.equals(color0, color1)) {
  49106. for (i = 0; i < numPoints; i++) {
  49107. colors[i] = Color.clone(color0);
  49108. }
  49109. return colors;
  49110. }
  49111. var redPerVertex = (r1 - r0) / numPoints;
  49112. var greenPerVertex = (g1 - g0) / numPoints;
  49113. var bluePerVertex = (b1 - b0) / numPoints;
  49114. var alphaPerVertex = (a1 - a0) / numPoints;
  49115. for (i = 0; i < numPoints; i++) {
  49116. colors[i] = new Color(r0 + i * redPerVertex, g0 + i * greenPerVertex, b0 + i * bluePerVertex, a0 + i * alphaPerVertex);
  49117. }
  49118. return colors;
  49119. }
  49120. /**
  49121. * A description of a polyline modeled as a line strip; the first two positions define a line segment,
  49122. * and each additional position defines a line segment from the previous position. The polyline is capable of
  49123. * displaying with a material.
  49124. *
  49125. * @alias PolylineGeometry
  49126. * @constructor
  49127. *
  49128. * @param {Object} options Object with the following properties:
  49129. * @param {Cartesian3[]} options.positions An array of {@link Cartesian3} defining the positions in the polyline as a line strip.
  49130. * @param {Number} [options.width=1.0] The width in pixels.
  49131. * @param {Color[]} [options.colors] An Array of {@link Color} defining the per vertex or per segment colors.
  49132. * @param {Boolean} [options.colorsPerVertex=false] A boolean that determines whether the colors will be flat across each segment of the line or interpolated across the vertices.
  49133. * @param {Boolean} [options.followSurface=true] A boolean that determines whether positions will be adjusted to the surface of the ellipsoid via a great arc.
  49134. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude if options.followSurface=true. Determines the number of positions in the buffer.
  49135. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  49136. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
  49137. *
  49138. * @exception {DeveloperError} At least two positions are required.
  49139. * @exception {DeveloperError} width must be greater than or equal to one.
  49140. * @exception {DeveloperError} colors has an invalid length.
  49141. *
  49142. * @see PolylineGeometry#createGeometry
  49143. *
  49144. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Polyline.html|Cesium Sandcastle Polyline Demo}
  49145. *
  49146. * @example
  49147. * // A polyline with two connected line segments
  49148. * var polyline = new Cesium.PolylineGeometry({
  49149. * positions : Cesium.Cartesian3.fromDegreesArray([
  49150. * 0.0, 0.0,
  49151. * 5.0, 0.0,
  49152. * 5.0, 5.0
  49153. * ]),
  49154. * width : 10.0
  49155. * });
  49156. * var geometry = Cesium.PolylineGeometry.createGeometry(polyline);
  49157. */
  49158. function PolylineGeometry(options) {
  49159. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  49160. var positions = options.positions;
  49161. var colors = options.colors;
  49162. var width = defaultValue(options.width, 1.0);
  49163. var colorsPerVertex = defaultValue(options.colorsPerVertex, false);
  49164. if ((!defined(positions)) || (positions.length < 2)) {
  49165. throw new DeveloperError('At least two positions are required.');
  49166. }
  49167. if (typeof width !== 'number') {
  49168. throw new DeveloperError('width must be a number');
  49169. }
  49170. if (defined(colors) && ((colorsPerVertex && colors.length < positions.length) || (!colorsPerVertex && colors.length < positions.length - 1))) {
  49171. throw new DeveloperError('colors has an invalid length.');
  49172. }
  49173. this._positions = positions;
  49174. this._colors = colors;
  49175. this._width = width;
  49176. this._colorsPerVertex = colorsPerVertex;
  49177. this._vertexFormat = VertexFormat.clone(defaultValue(options.vertexFormat, VertexFormat.DEFAULT));
  49178. this._followSurface = defaultValue(options.followSurface, true);
  49179. this._granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  49180. this._ellipsoid = Ellipsoid.clone(defaultValue(options.ellipsoid, Ellipsoid.WGS84));
  49181. this._workerName = 'createPolylineGeometry';
  49182. var numComponents = 1 + positions.length * Cartesian3.packedLength;
  49183. numComponents += defined(colors) ? 1 + colors.length * Color.packedLength : 1;
  49184. /**
  49185. * The number of elements used to pack the object into an array.
  49186. * @type {Number}
  49187. */
  49188. this.packedLength = numComponents + Ellipsoid.packedLength + VertexFormat.packedLength + 4;
  49189. }
  49190. /**
  49191. * Stores the provided instance into the provided array.
  49192. *
  49193. * @param {PolylineGeometry} value The value to pack.
  49194. * @param {Number[]} array The array to pack into.
  49195. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  49196. *
  49197. * @returns {Number[]} The array that was packed into
  49198. */
  49199. PolylineGeometry.pack = function(value, array, startingIndex) {
  49200. if (!defined(value)) {
  49201. throw new DeveloperError('value is required');
  49202. }
  49203. if (!defined(array)) {
  49204. throw new DeveloperError('array is required');
  49205. }
  49206. startingIndex = defaultValue(startingIndex, 0);
  49207. var i;
  49208. var positions = value._positions;
  49209. var length = positions.length;
  49210. array[startingIndex++] = length;
  49211. for (i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  49212. Cartesian3.pack(positions[i], array, startingIndex);
  49213. }
  49214. var colors = value._colors;
  49215. length = defined(colors) ? colors.length : 0.0;
  49216. array[startingIndex++] = length;
  49217. for (i = 0; i < length; ++i, startingIndex += Color.packedLength) {
  49218. Color.pack(colors[i], array, startingIndex);
  49219. }
  49220. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  49221. startingIndex += Ellipsoid.packedLength;
  49222. VertexFormat.pack(value._vertexFormat, array, startingIndex);
  49223. startingIndex += VertexFormat.packedLength;
  49224. array[startingIndex++] = value._width;
  49225. array[startingIndex++] = value._colorsPerVertex ? 1.0 : 0.0;
  49226. array[startingIndex++] = value._followSurface ? 1.0 : 0.0;
  49227. array[startingIndex] = value._granularity;
  49228. return array;
  49229. };
  49230. var scratchEllipsoid = Ellipsoid.clone(Ellipsoid.UNIT_SPHERE);
  49231. var scratchVertexFormat = new VertexFormat();
  49232. var scratchOptions = {
  49233. positions : undefined,
  49234. colors : undefined,
  49235. ellipsoid : scratchEllipsoid,
  49236. vertexFormat : scratchVertexFormat,
  49237. width : undefined,
  49238. colorsPerVertex : undefined,
  49239. followSurface : undefined,
  49240. granularity : undefined
  49241. };
  49242. /**
  49243. * Retrieves an instance from a packed array.
  49244. *
  49245. * @param {Number[]} array The packed array.
  49246. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  49247. * @param {PolylineGeometry} [result] The object into which to store the result.
  49248. * @returns {PolylineGeometry} The modified result parameter or a new PolylineGeometry instance if one was not provided.
  49249. */
  49250. PolylineGeometry.unpack = function(array, startingIndex, result) {
  49251. if (!defined(array)) {
  49252. throw new DeveloperError('array is required');
  49253. }
  49254. startingIndex = defaultValue(startingIndex, 0);
  49255. var i;
  49256. var length = array[startingIndex++];
  49257. var positions = new Array(length);
  49258. for (i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  49259. positions[i] = Cartesian3.unpack(array, startingIndex);
  49260. }
  49261. length = array[startingIndex++];
  49262. var colors = length > 0 ? new Array(length) : undefined;
  49263. for (i = 0; i < length; ++i, startingIndex += Color.packedLength) {
  49264. colors[i] = Color.unpack(array, startingIndex);
  49265. }
  49266. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  49267. startingIndex += Ellipsoid.packedLength;
  49268. var vertexFormat = VertexFormat.unpack(array, startingIndex, scratchVertexFormat);
  49269. startingIndex += VertexFormat.packedLength;
  49270. var width = array[startingIndex++];
  49271. var colorsPerVertex = array[startingIndex++] === 1.0;
  49272. var followSurface = array[startingIndex++] === 1.0;
  49273. var granularity = array[startingIndex];
  49274. if (!defined(result)) {
  49275. scratchOptions.positions = positions;
  49276. scratchOptions.colors = colors;
  49277. scratchOptions.width = width;
  49278. scratchOptions.colorsPerVertex = colorsPerVertex;
  49279. scratchOptions.followSurface = followSurface;
  49280. scratchOptions.granularity = granularity;
  49281. return new PolylineGeometry(scratchOptions);
  49282. }
  49283. result._positions = positions;
  49284. result._colors = colors;
  49285. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  49286. result._vertexFormat = VertexFormat.clone(vertexFormat, result._vertexFormat);
  49287. result._width = width;
  49288. result._colorsPerVertex = colorsPerVertex;
  49289. result._followSurface = followSurface;
  49290. result._granularity = granularity;
  49291. return result;
  49292. };
  49293. var scratchCartesian3 = new Cartesian3();
  49294. var scratchPosition = new Cartesian3();
  49295. var scratchPrevPosition = new Cartesian3();
  49296. var scratchNextPosition = new Cartesian3();
  49297. /**
  49298. * Computes the geometric representation of a polyline, including its vertices, indices, and a bounding sphere.
  49299. *
  49300. * @param {PolylineGeometry} polylineGeometry A description of the polyline.
  49301. * @returns {Geometry|undefined} The computed vertices and indices.
  49302. */
  49303. PolylineGeometry.createGeometry = function(polylineGeometry) {
  49304. var width = polylineGeometry._width;
  49305. var vertexFormat = polylineGeometry._vertexFormat;
  49306. var colors = polylineGeometry._colors;
  49307. var colorsPerVertex = polylineGeometry._colorsPerVertex;
  49308. var followSurface = polylineGeometry._followSurface;
  49309. var granularity = polylineGeometry._granularity;
  49310. var ellipsoid = polylineGeometry._ellipsoid;
  49311. var i;
  49312. var j;
  49313. var k;
  49314. var positions = arrayRemoveDuplicates(polylineGeometry._positions, Cartesian3.equalsEpsilon);
  49315. var positionsLength = positions.length;
  49316. // A width of a pixel or less is not a valid geometry, but in order to support external data
  49317. // that may have errors we treat this as an empty geometry.
  49318. if (positionsLength < 2 || width <= 0.0) {
  49319. return undefined;
  49320. }
  49321. if (followSurface) {
  49322. var heights = PolylinePipeline.extractHeights(positions, ellipsoid);
  49323. var minDistance = CesiumMath.chordLength(granularity, ellipsoid.maximumRadius);
  49324. if (defined(colors)) {
  49325. var colorLength = 1;
  49326. for (i = 0; i < positionsLength - 1; ++i) {
  49327. colorLength += PolylinePipeline.numberOfPoints(positions[i], positions[i+1], minDistance);
  49328. }
  49329. var newColors = new Array(colorLength);
  49330. var newColorIndex = 0;
  49331. for (i = 0; i < positionsLength - 1; ++i) {
  49332. var p0 = positions[i];
  49333. var p1 = positions[i+1];
  49334. var c0 = colors[i];
  49335. var numColors = PolylinePipeline.numberOfPoints(p0, p1, minDistance);
  49336. if (colorsPerVertex && i < colorLength) {
  49337. var c1 = colors[i+1];
  49338. var interpolatedColors = interpolateColors(p0, p1, c0, c1, numColors);
  49339. var interpolatedColorsLength = interpolatedColors.length;
  49340. for (j = 0; j < interpolatedColorsLength; ++j) {
  49341. newColors[newColorIndex++] = interpolatedColors[j];
  49342. }
  49343. } else {
  49344. for (j = 0; j < numColors; ++j) {
  49345. newColors[newColorIndex++] = Color.clone(c0);
  49346. }
  49347. }
  49348. }
  49349. newColors[newColorIndex] = Color.clone(colors[colors.length-1]);
  49350. colors = newColors;
  49351. scratchInterpolateColorsArray.length = 0;
  49352. }
  49353. positions = PolylinePipeline.generateCartesianArc({
  49354. positions: positions,
  49355. minDistance: minDistance,
  49356. ellipsoid: ellipsoid,
  49357. height: heights
  49358. });
  49359. }
  49360. positionsLength = positions.length;
  49361. var size = positionsLength * 4.0 - 4.0;
  49362. var finalPositions = new Float64Array(size * 3);
  49363. var prevPositions = new Float64Array(size * 3);
  49364. var nextPositions = new Float64Array(size * 3);
  49365. var expandAndWidth = new Float32Array(size * 2);
  49366. var st = vertexFormat.st ? new Float32Array(size * 2) : undefined;
  49367. var finalColors = defined(colors) ? new Uint8Array(size * 4) : undefined;
  49368. var positionIndex = 0;
  49369. var expandAndWidthIndex = 0;
  49370. var stIndex = 0;
  49371. var colorIndex = 0;
  49372. var position;
  49373. for (j = 0; j < positionsLength; ++j) {
  49374. if (j === 0) {
  49375. position = scratchCartesian3;
  49376. Cartesian3.subtract(positions[0], positions[1], position);
  49377. Cartesian3.add(positions[0], position, position);
  49378. } else {
  49379. position = positions[j - 1];
  49380. }
  49381. Cartesian3.clone(position, scratchPrevPosition);
  49382. Cartesian3.clone(positions[j], scratchPosition);
  49383. if (j === positionsLength - 1) {
  49384. position = scratchCartesian3;
  49385. Cartesian3.subtract(positions[positionsLength - 1], positions[positionsLength - 2], position);
  49386. Cartesian3.add(positions[positionsLength - 1], position, position);
  49387. } else {
  49388. position = positions[j + 1];
  49389. }
  49390. Cartesian3.clone(position, scratchNextPosition);
  49391. var color0, color1;
  49392. if (defined(finalColors)) {
  49393. if (j !== 0 && !colorsPerVertex) {
  49394. color0 = colors[j - 1];
  49395. } else {
  49396. color0 = colors[j];
  49397. }
  49398. if (j !== positionsLength - 1) {
  49399. color1 = colors[j];
  49400. }
  49401. }
  49402. var startK = j === 0 ? 2 : 0;
  49403. var endK = j === positionsLength - 1 ? 2 : 4;
  49404. for (k = startK; k < endK; ++k) {
  49405. Cartesian3.pack(scratchPosition, finalPositions, positionIndex);
  49406. Cartesian3.pack(scratchPrevPosition, prevPositions, positionIndex);
  49407. Cartesian3.pack(scratchNextPosition, nextPositions, positionIndex);
  49408. positionIndex += 3;
  49409. var direction = (k - 2 < 0) ? -1.0 : 1.0;
  49410. expandAndWidth[expandAndWidthIndex++] = 2 * (k % 2) - 1; // expand direction
  49411. expandAndWidth[expandAndWidthIndex++] = direction * width;
  49412. if (vertexFormat.st) {
  49413. st[stIndex++] = j / (positionsLength - 1);
  49414. st[stIndex++] = Math.max(expandAndWidth[expandAndWidthIndex - 2], 0.0);
  49415. }
  49416. if (defined(finalColors)) {
  49417. var color = (k < 2) ? color0 : color1;
  49418. finalColors[colorIndex++] = Color.floatToByte(color.red);
  49419. finalColors[colorIndex++] = Color.floatToByte(color.green);
  49420. finalColors[colorIndex++] = Color.floatToByte(color.blue);
  49421. finalColors[colorIndex++] = Color.floatToByte(color.alpha);
  49422. }
  49423. }
  49424. }
  49425. var attributes = new GeometryAttributes();
  49426. attributes.position = new GeometryAttribute({
  49427. componentDatatype : ComponentDatatype.DOUBLE,
  49428. componentsPerAttribute : 3,
  49429. values : finalPositions
  49430. });
  49431. attributes.prevPosition = new GeometryAttribute({
  49432. componentDatatype : ComponentDatatype.DOUBLE,
  49433. componentsPerAttribute : 3,
  49434. values : prevPositions
  49435. });
  49436. attributes.nextPosition = new GeometryAttribute({
  49437. componentDatatype : ComponentDatatype.DOUBLE,
  49438. componentsPerAttribute : 3,
  49439. values : nextPositions
  49440. });
  49441. attributes.expandAndWidth = new GeometryAttribute({
  49442. componentDatatype : ComponentDatatype.FLOAT,
  49443. componentsPerAttribute : 2,
  49444. values : expandAndWidth
  49445. });
  49446. if (vertexFormat.st) {
  49447. attributes.st = new GeometryAttribute({
  49448. componentDatatype : ComponentDatatype.FLOAT,
  49449. componentsPerAttribute : 2,
  49450. values : st
  49451. });
  49452. }
  49453. if (defined(finalColors)) {
  49454. attributes.color = new GeometryAttribute({
  49455. componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
  49456. componentsPerAttribute : 4,
  49457. values : finalColors,
  49458. normalize : true
  49459. });
  49460. }
  49461. var indices = IndexDatatype.createTypedArray(size, positionsLength * 6 - 6);
  49462. var index = 0;
  49463. var indicesIndex = 0;
  49464. var length = positionsLength - 1.0;
  49465. for (j = 0; j < length; ++j) {
  49466. indices[indicesIndex++] = index;
  49467. indices[indicesIndex++] = index + 2;
  49468. indices[indicesIndex++] = index + 1;
  49469. indices[indicesIndex++] = index + 1;
  49470. indices[indicesIndex++] = index + 2;
  49471. indices[indicesIndex++] = index + 3;
  49472. index += 4;
  49473. }
  49474. return new Geometry({
  49475. attributes : attributes,
  49476. indices : indices,
  49477. primitiveType : PrimitiveType.TRIANGLES,
  49478. boundingSphere : BoundingSphere.fromPoints(positions),
  49479. geometryType : GeometryType.POLYLINES
  49480. });
  49481. };
  49482. return PolylineGeometry;
  49483. });
  49484. /*global define*/
  49485. define('Core/PolylineVolumeGeometry',[
  49486. './arrayRemoveDuplicates',
  49487. './BoundingRectangle',
  49488. './BoundingSphere',
  49489. './Cartesian2',
  49490. './Cartesian3',
  49491. './ComponentDatatype',
  49492. './CornerType',
  49493. './defaultValue',
  49494. './defined',
  49495. './DeveloperError',
  49496. './Ellipsoid',
  49497. './Geometry',
  49498. './GeometryAttribute',
  49499. './GeometryAttributes',
  49500. './GeometryPipeline',
  49501. './IndexDatatype',
  49502. './Math',
  49503. './oneTimeWarning',
  49504. './PolygonPipeline',
  49505. './PolylineVolumeGeometryLibrary',
  49506. './PrimitiveType',
  49507. './VertexFormat',
  49508. './WindingOrder'
  49509. ], function(
  49510. arrayRemoveDuplicates,
  49511. BoundingRectangle,
  49512. BoundingSphere,
  49513. Cartesian2,
  49514. Cartesian3,
  49515. ComponentDatatype,
  49516. CornerType,
  49517. defaultValue,
  49518. defined,
  49519. DeveloperError,
  49520. Ellipsoid,
  49521. Geometry,
  49522. GeometryAttribute,
  49523. GeometryAttributes,
  49524. GeometryPipeline,
  49525. IndexDatatype,
  49526. CesiumMath,
  49527. oneTimeWarning,
  49528. PolygonPipeline,
  49529. PolylineVolumeGeometryLibrary,
  49530. PrimitiveType,
  49531. VertexFormat,
  49532. WindingOrder) {
  49533. 'use strict';
  49534. function computeAttributes(combinedPositions, shape, boundingRectangle, vertexFormat) {
  49535. var attributes = new GeometryAttributes();
  49536. if (vertexFormat.position) {
  49537. attributes.position = new GeometryAttribute({
  49538. componentDatatype : ComponentDatatype.DOUBLE,
  49539. componentsPerAttribute : 3,
  49540. values : combinedPositions
  49541. });
  49542. }
  49543. var shapeLength = shape.length;
  49544. var vertexCount = combinedPositions.length / 3;
  49545. var length = (vertexCount - shapeLength * 2) / (shapeLength * 2);
  49546. var firstEndIndices = PolygonPipeline.triangulate(shape);
  49547. var indicesCount = (length - 1) * (shapeLength) * 6 + firstEndIndices.length * 2;
  49548. var indices = IndexDatatype.createTypedArray(vertexCount, indicesCount);
  49549. var i, j;
  49550. var ll, ul, ur, lr;
  49551. var offset = shapeLength * 2;
  49552. var index = 0;
  49553. for (i = 0; i < length - 1; i++) {
  49554. for (j = 0; j < shapeLength - 1; j++) {
  49555. ll = j * 2 + i * shapeLength * 2;
  49556. lr = ll + offset;
  49557. ul = ll + 1;
  49558. ur = ul + offset;
  49559. indices[index++] = ul;
  49560. indices[index++] = ll;
  49561. indices[index++] = ur;
  49562. indices[index++] = ur;
  49563. indices[index++] = ll;
  49564. indices[index++] = lr;
  49565. }
  49566. ll = shapeLength * 2 - 2 + i * shapeLength * 2;
  49567. ul = ll + 1;
  49568. ur = ul + offset;
  49569. lr = ll + offset;
  49570. indices[index++] = ul;
  49571. indices[index++] = ll;
  49572. indices[index++] = ur;
  49573. indices[index++] = ur;
  49574. indices[index++] = ll;
  49575. indices[index++] = lr;
  49576. }
  49577. if (vertexFormat.st || vertexFormat.tangent || vertexFormat.binormal) { // st required for tangent/binormal calculation
  49578. var st = new Float32Array(vertexCount * 2);
  49579. var lengthSt = 1 / (length - 1);
  49580. var heightSt = 1 / (boundingRectangle.height);
  49581. var heightOffset = boundingRectangle.height / 2;
  49582. var s, t;
  49583. var stindex = 0;
  49584. for (i = 0; i < length; i++) {
  49585. s = i * lengthSt;
  49586. t = heightSt * (shape[0].y + heightOffset);
  49587. st[stindex++] = s;
  49588. st[stindex++] = t;
  49589. for (j = 1; j < shapeLength; j++) {
  49590. t = heightSt * (shape[j].y + heightOffset);
  49591. st[stindex++] = s;
  49592. st[stindex++] = t;
  49593. st[stindex++] = s;
  49594. st[stindex++] = t;
  49595. }
  49596. t = heightSt * (shape[0].y + heightOffset);
  49597. st[stindex++] = s;
  49598. st[stindex++] = t;
  49599. }
  49600. for (j = 0; j < shapeLength; j++) {
  49601. s = 0;
  49602. t = heightSt * (shape[j].y + heightOffset);
  49603. st[stindex++] = s;
  49604. st[stindex++] = t;
  49605. }
  49606. for (j = 0; j < shapeLength; j++) {
  49607. s = (length - 1) * lengthSt;
  49608. t = heightSt * (shape[j].y + heightOffset);
  49609. st[stindex++] = s;
  49610. st[stindex++] = t;
  49611. }
  49612. attributes.st = new GeometryAttribute({
  49613. componentDatatype : ComponentDatatype.FLOAT,
  49614. componentsPerAttribute : 2,
  49615. values : new Float32Array(st)
  49616. });
  49617. }
  49618. var endOffset = vertexCount - shapeLength * 2;
  49619. for (i = 0; i < firstEndIndices.length; i += 3) {
  49620. var v0 = firstEndIndices[i] + endOffset;
  49621. var v1 = firstEndIndices[i + 1] + endOffset;
  49622. var v2 = firstEndIndices[i + 2] + endOffset;
  49623. indices[index++] = v0;
  49624. indices[index++] = v1;
  49625. indices[index++] = v2;
  49626. indices[index++] = v2 + shapeLength;
  49627. indices[index++] = v1 + shapeLength;
  49628. indices[index++] = v0 + shapeLength;
  49629. }
  49630. var geometry = new Geometry({
  49631. attributes : attributes,
  49632. indices : indices,
  49633. boundingSphere : BoundingSphere.fromVertices(combinedPositions),
  49634. primitiveType : PrimitiveType.TRIANGLES
  49635. });
  49636. if (vertexFormat.normal) {
  49637. geometry = GeometryPipeline.computeNormal(geometry);
  49638. }
  49639. if (vertexFormat.tangent || vertexFormat.binormal) {
  49640. try {
  49641. geometry = GeometryPipeline.computeBinormalAndTangent(geometry);
  49642. } catch (e) {
  49643. oneTimeWarning('polyline-volume-tangent-binormal', 'Unable to compute tangents and binormals for polyline volume geometry');
  49644. //TODO https://github.com/AnalyticalGraphicsInc/cesium/issues/3609
  49645. }
  49646. if (!vertexFormat.tangent) {
  49647. geometry.attributes.tangent = undefined;
  49648. }
  49649. if (!vertexFormat.binormal) {
  49650. geometry.attributes.binormal = undefined;
  49651. }
  49652. if (!vertexFormat.st) {
  49653. geometry.attributes.st = undefined;
  49654. }
  49655. }
  49656. return geometry;
  49657. }
  49658. /**
  49659. * A description of a polyline with a volume (a 2D shape extruded along a polyline).
  49660. *
  49661. * @alias PolylineVolumeGeometry
  49662. * @constructor
  49663. *
  49664. * @param {Object} options Object with the following properties:
  49665. * @param {Cartesian3[]} options.polylinePositions An array of {@link Cartesain3} positions that define the center of the polyline volume.
  49666. * @param {Cartesian2[]} options.shapePositions An array of {@link Cartesian2} positions that define the shape to be extruded along the polyline
  49667. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
  49668. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  49669. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  49670. * @param {CornerType} [options.cornerType=CornerType.ROUNDED] Determines the style of the corners.
  49671. *
  49672. * @see PolylineVolumeGeometry#createGeometry
  49673. *
  49674. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Polyline%20Volume.html|Cesium Sandcastle Polyline Volume Demo}
  49675. *
  49676. * @example
  49677. * function computeCircle(radius) {
  49678. * var positions = [];
  49679. * for (var i = 0; i < 360; i++) {
  49680. * var radians = Cesium.Math.toRadians(i);
  49681. * positions.push(new Cesium.Cartesian2(radius * Math.cos(radians), radius * Math.sin(radians)));
  49682. * }
  49683. * return positions;
  49684. * }
  49685. *
  49686. * var volume = new Cesium.PolylineVolumeGeometry({
  49687. * vertexFormat : Cesium.VertexFormat.POSITION_ONLY,
  49688. * polylinePositions : Cesium.Cartesian3.fromDegreesArray([
  49689. * -72.0, 40.0,
  49690. * -70.0, 35.0
  49691. * ]),
  49692. * shapePositions : computeCircle(100000.0)
  49693. * });
  49694. */
  49695. function PolylineVolumeGeometry(options) {
  49696. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  49697. var positions = options.polylinePositions;
  49698. var shape = options.shapePositions;
  49699. if (!defined(positions)) {
  49700. throw new DeveloperError('options.polylinePositions is required.');
  49701. }
  49702. if (!defined(shape)) {
  49703. throw new DeveloperError('options.shapePositions is required.');
  49704. }
  49705. this._positions = positions;
  49706. this._shape = shape;
  49707. this._ellipsoid = Ellipsoid.clone(defaultValue(options.ellipsoid, Ellipsoid.WGS84));
  49708. this._cornerType = defaultValue(options.cornerType, CornerType.ROUNDED);
  49709. this._vertexFormat = VertexFormat.clone(defaultValue(options.vertexFormat, VertexFormat.DEFAULT));
  49710. this._granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  49711. this._workerName = 'createPolylineVolumeGeometry';
  49712. var numComponents = 1 + positions.length * Cartesian3.packedLength;
  49713. numComponents += 1 + shape.length * Cartesian2.packedLength;
  49714. /**
  49715. * The number of elements used to pack the object into an array.
  49716. * @type {Number}
  49717. */
  49718. this.packedLength = numComponents + Ellipsoid.packedLength + VertexFormat.packedLength + 2;
  49719. }
  49720. /**
  49721. * Stores the provided instance into the provided array.
  49722. *
  49723. * @param {PolylineVolumeGeometry} value The value to pack.
  49724. * @param {Number[]} array The array to pack into.
  49725. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  49726. *
  49727. * @returns {Number[]} The array that was packed into
  49728. */
  49729. PolylineVolumeGeometry.pack = function(value, array, startingIndex) {
  49730. if (!defined(value)) {
  49731. throw new DeveloperError('value is required');
  49732. }
  49733. if (!defined(array)) {
  49734. throw new DeveloperError('array is required');
  49735. }
  49736. startingIndex = defaultValue(startingIndex, 0);
  49737. var i;
  49738. var positions = value._positions;
  49739. var length = positions.length;
  49740. array[startingIndex++] = length;
  49741. for (i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  49742. Cartesian3.pack(positions[i], array, startingIndex);
  49743. }
  49744. var shape = value._shape;
  49745. length = shape.length;
  49746. array[startingIndex++] = length;
  49747. for (i = 0; i < length; ++i, startingIndex += Cartesian2.packedLength) {
  49748. Cartesian2.pack(shape[i], array, startingIndex);
  49749. }
  49750. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  49751. startingIndex += Ellipsoid.packedLength;
  49752. VertexFormat.pack(value._vertexFormat, array, startingIndex);
  49753. startingIndex += VertexFormat.packedLength;
  49754. array[startingIndex++] = value._cornerType;
  49755. array[startingIndex] = value._granularity;
  49756. return array;
  49757. };
  49758. var scratchEllipsoid = Ellipsoid.clone(Ellipsoid.UNIT_SPHERE);
  49759. var scratchVertexFormat = new VertexFormat();
  49760. var scratchOptions = {
  49761. polylinePositions : undefined,
  49762. shapePositions : undefined,
  49763. ellipsoid : scratchEllipsoid,
  49764. vertexFormat : scratchVertexFormat,
  49765. cornerType : undefined,
  49766. granularity : undefined
  49767. };
  49768. /**
  49769. * Retrieves an instance from a packed array.
  49770. *
  49771. * @param {Number[]} array The packed array.
  49772. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  49773. * @param {PolylineVolumeGeometry} [result] The object into which to store the result.
  49774. * @returns {PolylineVolumeGeometry} The modified result parameter or a new PolylineVolumeGeometry instance if one was not provided.
  49775. */
  49776. PolylineVolumeGeometry.unpack = function(array, startingIndex, result) {
  49777. if (!defined(array)) {
  49778. throw new DeveloperError('array is required');
  49779. }
  49780. startingIndex = defaultValue(startingIndex, 0);
  49781. var i;
  49782. var length = array[startingIndex++];
  49783. var positions = new Array(length);
  49784. for (i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  49785. positions[i] = Cartesian3.unpack(array, startingIndex);
  49786. }
  49787. length = array[startingIndex++];
  49788. var shape = new Array(length);
  49789. for (i = 0; i < length; ++i, startingIndex += Cartesian2.packedLength) {
  49790. shape[i] = Cartesian2.unpack(array, startingIndex);
  49791. }
  49792. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  49793. startingIndex += Ellipsoid.packedLength;
  49794. var vertexFormat = VertexFormat.unpack(array, startingIndex, scratchVertexFormat);
  49795. startingIndex += VertexFormat.packedLength;
  49796. var cornerType = array[startingIndex++];
  49797. var granularity = array[startingIndex];
  49798. if (!defined(result)) {
  49799. scratchOptions.polylinePositions = positions;
  49800. scratchOptions.shapePositions = shape;
  49801. scratchOptions.cornerType = cornerType;
  49802. scratchOptions.granularity = granularity;
  49803. return new PolylineVolumeGeometry(scratchOptions);
  49804. }
  49805. result._positions = positions;
  49806. result._shape = shape;
  49807. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  49808. result._vertexFormat = VertexFormat.clone(vertexFormat, result._vertexFormat);
  49809. result._cornerType = cornerType;
  49810. result._granularity = granularity;
  49811. return result;
  49812. };
  49813. var brScratch = new BoundingRectangle();
  49814. /**
  49815. * Computes the geometric representation of a polyline with a volume, including its vertices, indices, and a bounding sphere.
  49816. *
  49817. * @param {PolylineVolumeGeometry} polylineVolumeGeometry A description of the polyline volume.
  49818. * @returns {Geometry|undefined} The computed vertices and indices.
  49819. */
  49820. PolylineVolumeGeometry.createGeometry = function(polylineVolumeGeometry) {
  49821. var positions = polylineVolumeGeometry._positions;
  49822. var cleanPositions = arrayRemoveDuplicates(positions, Cartesian3.equalsEpsilon);
  49823. var shape2D = polylineVolumeGeometry._shape;
  49824. shape2D = PolylineVolumeGeometryLibrary.removeDuplicatesFromShape(shape2D);
  49825. if (cleanPositions.length < 2 || shape2D.length < 3) {
  49826. return undefined;
  49827. }
  49828. if (PolygonPipeline.computeWindingOrder2D(shape2D) === WindingOrder.CLOCKWISE) {
  49829. shape2D.reverse();
  49830. }
  49831. var boundingRectangle = BoundingRectangle.fromPoints(shape2D, brScratch);
  49832. var computedPositions = PolylineVolumeGeometryLibrary.computePositions(cleanPositions, shape2D, boundingRectangle, polylineVolumeGeometry, true);
  49833. return computeAttributes(computedPositions, shape2D, boundingRectangle, polylineVolumeGeometry._vertexFormat);
  49834. };
  49835. return PolylineVolumeGeometry;
  49836. });
  49837. /*global define*/
  49838. define('Core/PolylineVolumeOutlineGeometry',[
  49839. './arrayRemoveDuplicates',
  49840. './BoundingRectangle',
  49841. './BoundingSphere',
  49842. './Cartesian2',
  49843. './Cartesian3',
  49844. './ComponentDatatype',
  49845. './CornerType',
  49846. './defaultValue',
  49847. './defined',
  49848. './DeveloperError',
  49849. './Ellipsoid',
  49850. './Geometry',
  49851. './GeometryAttribute',
  49852. './GeometryAttributes',
  49853. './IndexDatatype',
  49854. './Math',
  49855. './PolygonPipeline',
  49856. './PolylineVolumeGeometryLibrary',
  49857. './PrimitiveType',
  49858. './WindingOrder'
  49859. ], function(
  49860. arrayRemoveDuplicates,
  49861. BoundingRectangle,
  49862. BoundingSphere,
  49863. Cartesian2,
  49864. Cartesian3,
  49865. ComponentDatatype,
  49866. CornerType,
  49867. defaultValue,
  49868. defined,
  49869. DeveloperError,
  49870. Ellipsoid,
  49871. Geometry,
  49872. GeometryAttribute,
  49873. GeometryAttributes,
  49874. IndexDatatype,
  49875. CesiumMath,
  49876. PolygonPipeline,
  49877. PolylineVolumeGeometryLibrary,
  49878. PrimitiveType,
  49879. WindingOrder) {
  49880. 'use strict';
  49881. function computeAttributes(positions, shape) {
  49882. var attributes = new GeometryAttributes();
  49883. attributes.position = new GeometryAttribute({
  49884. componentDatatype : ComponentDatatype.DOUBLE,
  49885. componentsPerAttribute : 3,
  49886. values : positions
  49887. });
  49888. var shapeLength = shape.length;
  49889. var vertexCount = attributes.position.values.length / 3;
  49890. var positionLength = positions.length / 3;
  49891. var shapeCount = positionLength / shapeLength;
  49892. var indices = IndexDatatype.createTypedArray(vertexCount, 2 * shapeLength * (shapeCount + 1));
  49893. var i, j;
  49894. var index = 0;
  49895. i = 0;
  49896. var offset = i * shapeLength;
  49897. for (j = 0; j < shapeLength - 1; j++) {
  49898. indices[index++] = j + offset;
  49899. indices[index++] = j + offset + 1;
  49900. }
  49901. indices[index++] = shapeLength - 1 + offset;
  49902. indices[index++] = offset;
  49903. i = shapeCount - 1;
  49904. offset = i * shapeLength;
  49905. for (j = 0; j < shapeLength - 1; j++) {
  49906. indices[index++] = j + offset;
  49907. indices[index++] = j + offset + 1;
  49908. }
  49909. indices[index++] = shapeLength - 1 + offset;
  49910. indices[index++] = offset;
  49911. for (i = 0; i < shapeCount - 1; i++) {
  49912. var firstOffset = shapeLength * i;
  49913. var secondOffset = firstOffset + shapeLength;
  49914. for (j = 0; j < shapeLength; j++) {
  49915. indices[index++] = j + firstOffset;
  49916. indices[index++] = j + secondOffset;
  49917. }
  49918. }
  49919. var geometry = new Geometry({
  49920. attributes : attributes,
  49921. indices : IndexDatatype.createTypedArray(vertexCount, indices),
  49922. boundingSphere : BoundingSphere.fromVertices(positions),
  49923. primitiveType : PrimitiveType.LINES
  49924. });
  49925. return geometry;
  49926. }
  49927. /**
  49928. * A description of a polyline with a volume (a 2D shape extruded along a polyline).
  49929. *
  49930. * @alias PolylineVolumeOutlineGeometry
  49931. * @constructor
  49932. *
  49933. * @param {Object} options Object with the following properties:
  49934. * @param {Cartesian3[]} options.polylinePositions An array of positions that define the center of the polyline volume.
  49935. * @param {Cartesian2[]} options.shapePositions An array of positions that define the shape to be extruded along the polyline
  49936. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
  49937. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  49938. * @param {CornerType} [options.cornerType=CornerType.ROUNDED] Determines the style of the corners.
  49939. *
  49940. * @see PolylineVolumeOutlineGeometry#createGeometry
  49941. *
  49942. * @example
  49943. * function computeCircle(radius) {
  49944. * var positions = [];
  49945. * for (var i = 0; i < 360; i++) {
  49946. * var radians = Cesium.Math.toRadians(i);
  49947. * positions.push(new Cesium.Cartesian2(radius * Math.cos(radians), radius * Math.sin(radians)));
  49948. * }
  49949. * return positions;
  49950. * }
  49951. *
  49952. * var volumeOutline = new Cesium.PolylineVolumeOutlineGeometry({
  49953. * polylinePositions : Cesium.Cartesian3.fromDegreesArray([
  49954. * -72.0, 40.0,
  49955. * -70.0, 35.0
  49956. * ]),
  49957. * shapePositions : computeCircle(100000.0)
  49958. * });
  49959. */
  49960. function PolylineVolumeOutlineGeometry(options) {
  49961. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  49962. var positions = options.polylinePositions;
  49963. var shape = options.shapePositions;
  49964. if (!defined(positions)) {
  49965. throw new DeveloperError('options.polylinePositions is required.');
  49966. }
  49967. if (!defined(shape)) {
  49968. throw new DeveloperError('options.shapePositions is required.');
  49969. }
  49970. this._positions = positions;
  49971. this._shape = shape;
  49972. this._ellipsoid = Ellipsoid.clone(defaultValue(options.ellipsoid, Ellipsoid.WGS84));
  49973. this._cornerType = defaultValue(options.cornerType, CornerType.ROUNDED);
  49974. this._granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  49975. this._workerName = 'createPolylineVolumeOutlineGeometry';
  49976. var numComponents = 1 + positions.length * Cartesian3.packedLength;
  49977. numComponents += 1 + shape.length * Cartesian2.packedLength;
  49978. /**
  49979. * The number of elements used to pack the object into an array.
  49980. * @type {Number}
  49981. */
  49982. this.packedLength = numComponents + Ellipsoid.packedLength + 2;
  49983. }
  49984. /**
  49985. * Stores the provided instance into the provided array.
  49986. *
  49987. * @param {PolylineVolumeOutlineGeometry} value The value to pack.
  49988. * @param {Number[]} array The array to pack into.
  49989. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  49990. *
  49991. * @returns {Number[]} The array that was packed into
  49992. */
  49993. PolylineVolumeOutlineGeometry.pack = function(value, array, startingIndex) {
  49994. if (!defined(value)) {
  49995. throw new DeveloperError('value is required');
  49996. }
  49997. if (!defined(array)) {
  49998. throw new DeveloperError('array is required');
  49999. }
  50000. startingIndex = defaultValue(startingIndex, 0);
  50001. var i;
  50002. var positions = value._positions;
  50003. var length = positions.length;
  50004. array[startingIndex++] = length;
  50005. for (i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  50006. Cartesian3.pack(positions[i], array, startingIndex);
  50007. }
  50008. var shape = value._shape;
  50009. length = shape.length;
  50010. array[startingIndex++] = length;
  50011. for (i = 0; i < length; ++i, startingIndex += Cartesian2.packedLength) {
  50012. Cartesian2.pack(shape[i], array, startingIndex);
  50013. }
  50014. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  50015. startingIndex += Ellipsoid.packedLength;
  50016. array[startingIndex++] = value._cornerType;
  50017. array[startingIndex] = value._granularity;
  50018. return array;
  50019. };
  50020. var scratchEllipsoid = Ellipsoid.clone(Ellipsoid.UNIT_SPHERE);
  50021. var scratchOptions = {
  50022. polylinePositions : undefined,
  50023. shapePositions : undefined,
  50024. ellipsoid : scratchEllipsoid,
  50025. height : undefined,
  50026. cornerType : undefined,
  50027. granularity : undefined
  50028. };
  50029. /**
  50030. * Retrieves an instance from a packed array.
  50031. *
  50032. * @param {Number[]} array The packed array.
  50033. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  50034. * @param {PolylineVolumeOutlineGeometry} [result] The object into which to store the result.
  50035. * @returns {PolylineVolumeOutlineGeometry} The modified result parameter or a new PolylineVolumeOutlineGeometry instance if one was not provided.
  50036. */
  50037. PolylineVolumeOutlineGeometry.unpack = function(array, startingIndex, result) {
  50038. if (!defined(array)) {
  50039. throw new DeveloperError('array is required');
  50040. }
  50041. startingIndex = defaultValue(startingIndex, 0);
  50042. var i;
  50043. var length = array[startingIndex++];
  50044. var positions = new Array(length);
  50045. for (i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  50046. positions[i] = Cartesian3.unpack(array, startingIndex);
  50047. }
  50048. length = array[startingIndex++];
  50049. var shape = new Array(length);
  50050. for (i = 0; i < length; ++i, startingIndex += Cartesian2.packedLength) {
  50051. shape[i] = Cartesian2.unpack(array, startingIndex);
  50052. }
  50053. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  50054. startingIndex += Ellipsoid.packedLength;
  50055. var cornerType = array[startingIndex++];
  50056. var granularity = array[startingIndex];
  50057. if (!defined(result)) {
  50058. scratchOptions.polylinePositions = positions;
  50059. scratchOptions.shapePositions = shape;
  50060. scratchOptions.cornerType = cornerType;
  50061. scratchOptions.granularity = granularity;
  50062. return new PolylineVolumeOutlineGeometry(scratchOptions);
  50063. }
  50064. result._positions = positions;
  50065. result._shape = shape;
  50066. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  50067. result._cornerType = cornerType;
  50068. result._granularity = granularity;
  50069. return result;
  50070. };
  50071. var brScratch = new BoundingRectangle();
  50072. /**
  50073. * Computes the geometric representation of the outline of a polyline with a volume, including its vertices, indices, and a bounding sphere.
  50074. *
  50075. * @param {PolylineVolumeOutlineGeometry} polylineVolumeOutlineGeometry A description of the polyline volume outline.
  50076. * @returns {Geometry|undefined} The computed vertices and indices.
  50077. */
  50078. PolylineVolumeOutlineGeometry.createGeometry = function(polylineVolumeOutlineGeometry) {
  50079. var positions = polylineVolumeOutlineGeometry._positions;
  50080. var cleanPositions = arrayRemoveDuplicates(positions, Cartesian3.equalsEpsilon);
  50081. var shape2D = polylineVolumeOutlineGeometry._shape;
  50082. shape2D = PolylineVolumeGeometryLibrary.removeDuplicatesFromShape(shape2D);
  50083. if (cleanPositions.length < 2 || shape2D.length < 3) {
  50084. return undefined;
  50085. }
  50086. if (PolygonPipeline.computeWindingOrder2D(shape2D) === WindingOrder.CLOCKWISE) {
  50087. shape2D.reverse();
  50088. }
  50089. var boundingRectangle = BoundingRectangle.fromPoints(shape2D, brScratch);
  50090. var computedPositions = PolylineVolumeGeometryLibrary.computePositions(cleanPositions, shape2D, boundingRectangle, polylineVolumeOutlineGeometry, false);
  50091. return computeAttributes(computedPositions, shape2D);
  50092. };
  50093. return PolylineVolumeOutlineGeometry;
  50094. });
  50095. /*global define*/
  50096. define('Core/QuaternionSpline',[
  50097. './defaultValue',
  50098. './defined',
  50099. './defineProperties',
  50100. './DeveloperError',
  50101. './Quaternion',
  50102. './Spline'
  50103. ], function(
  50104. defaultValue,
  50105. defined,
  50106. defineProperties,
  50107. DeveloperError,
  50108. Quaternion,
  50109. Spline) {
  50110. 'use strict';
  50111. function computeInnerQuadrangles(points, firstInnerQuadrangle, lastInnerQuadrangle) {
  50112. var length = points.length;
  50113. var quads = new Array(length);
  50114. quads[0] = defined(firstInnerQuadrangle) ? firstInnerQuadrangle : points[0];
  50115. quads[length - 1] = defined(lastInnerQuadrangle) ? lastInnerQuadrangle : points[length - 1];
  50116. for (var i = 1; i < length - 1; ++i) {
  50117. quads[i] = Quaternion.computeInnerQuadrangle(points[i - 1], points[i], points[i + 1], new Quaternion());
  50118. }
  50119. return quads;
  50120. }
  50121. function createEvaluateFunction(spline) {
  50122. var points = spline.points;
  50123. var quads = spline.innerQuadrangles;
  50124. var times = spline.times;
  50125. // use slerp interpolation for 2 points
  50126. if (points.length < 3) {
  50127. var t0 = times[0];
  50128. var invSpan = 1.0 / (times[1] - t0);
  50129. var q0 = points[0];
  50130. var q1 = points[1];
  50131. return function(time, result) {
  50132. if (!defined(result)){
  50133. result = new Quaternion();
  50134. }
  50135. var u = (time - t0) * invSpan;
  50136. return Quaternion.fastSlerp(q0, q1, u, result);
  50137. };
  50138. }
  50139. // use quad interpolation for more than 3 points
  50140. return function(time, result) {
  50141. if (!defined(result)){
  50142. result = new Quaternion();
  50143. }
  50144. var i = spline._lastTimeIndex = spline.findTimeInterval(time, spline._lastTimeIndex);
  50145. var u = (time - times[i]) / (times[i + 1] - times[i]);
  50146. var q0 = points[i];
  50147. var q1 = points[i + 1];
  50148. var s0 = quads[i];
  50149. var s1 = quads[i + 1];
  50150. return Quaternion.fastSquad(q0, q1, s0, s1, u, result);
  50151. };
  50152. }
  50153. /**
  50154. * A spline that uses spherical quadrangle (squad) interpolation to create a quaternion curve.
  50155. * The generated curve is in the class C<sup>1</sup>.
  50156. *
  50157. * @alias QuaternionSpline
  50158. * @constructor
  50159. *
  50160. * @param {Object} options Object with the following properties:
  50161. * @param {Number[]} options.times An array of strictly increasing, unit-less, floating-point times at each point.
  50162. * The values are in no way connected to the clock time. They are the parameterization for the curve.
  50163. * @param {Quaternion[]} options.points The array of {@link Quaternion} control points.
  50164. * @param {Quaternion} [options.firstInnerQuadrangle] The inner quadrangle of the curve at the first control point.
  50165. * If the inner quadrangle is not given, it will be estimated.
  50166. * @param {Quaternion} [options.lastInnerQuadrangle] The inner quadrangle of the curve at the last control point.
  50167. * If the inner quadrangle is not given, it will be estimated.
  50168. *
  50169. * @exception {DeveloperError} points.length must be greater than or equal to 2.
  50170. * @exception {DeveloperError} times.length must be equal to points.length.
  50171. *
  50172. * @see HermiteSpline
  50173. * @see CatmullRomSpline
  50174. * @see LinearSpline
  50175. */
  50176. function QuaternionSpline(options) {
  50177. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  50178. var points = options.points;
  50179. var times = options.times;
  50180. var firstInnerQuadrangle = options.firstInnerQuadrangle;
  50181. var lastInnerQuadrangle = options.lastInnerQuadrangle;
  50182. if (!defined(points) || !defined(times)) {
  50183. throw new DeveloperError('points and times are required.');
  50184. }
  50185. if (points.length < 2) {
  50186. throw new DeveloperError('points.length must be greater than or equal to 2.');
  50187. }
  50188. if (times.length !== points.length) {
  50189. throw new DeveloperError('times.length must be equal to points.length.');
  50190. }
  50191. var innerQuadrangles = computeInnerQuadrangles(points, firstInnerQuadrangle, lastInnerQuadrangle);
  50192. this._times = times;
  50193. this._points = points;
  50194. this._innerQuadrangles = innerQuadrangles;
  50195. this._evaluateFunction = createEvaluateFunction(this);
  50196. this._lastTimeIndex = 0;
  50197. }
  50198. defineProperties(QuaternionSpline.prototype, {
  50199. /**
  50200. * An array of times for the control points.
  50201. *
  50202. * @memberof QuaternionSpline.prototype
  50203. *
  50204. * @type {Number[]}
  50205. * @readonly
  50206. */
  50207. times : {
  50208. get : function() {
  50209. return this._times;
  50210. }
  50211. },
  50212. /**
  50213. * An array of {@link Quaternion} control points.
  50214. *
  50215. * @memberof QuaternionSpline.prototype
  50216. *
  50217. * @type {Quaternion[]}
  50218. * @readonly
  50219. */
  50220. points : {
  50221. get : function() {
  50222. return this._points;
  50223. }
  50224. },
  50225. /**
  50226. * An array of {@link Quaternion} inner quadrangles for the control points.
  50227. *
  50228. * @memberof QuaternionSpline.prototype
  50229. *
  50230. * @type {Quaternion[]}
  50231. * @readonly
  50232. */
  50233. innerQuadrangles : {
  50234. get : function() {
  50235. return this._innerQuadrangles;
  50236. }
  50237. }
  50238. });
  50239. /**
  50240. * Finds an index <code>i</code> in <code>times</code> such that the parameter
  50241. * <code>time</code> is in the interval <code>[times[i], times[i + 1]]</code>.
  50242. * @function
  50243. *
  50244. * @param {Number} time The time.
  50245. * @returns {Number} The index for the element at the start of the interval.
  50246. *
  50247. * @exception {DeveloperError} time must be in the range <code>[t<sub>0</sub>, t<sub>n</sub>]</code>, where <code>t<sub>0</sub></code>
  50248. * is the first element in the array <code>times</code> and <code>t<sub>n</sub></code> is the last element
  50249. * in the array <code>times</code>.
  50250. */
  50251. QuaternionSpline.prototype.findTimeInterval = Spline.prototype.findTimeInterval;
  50252. /**
  50253. * Evaluates the curve at a given time.
  50254. *
  50255. * @param {Number} time The time at which to evaluate the curve.
  50256. * @param {Quaternion} [result] The object onto which to store the result.
  50257. * @returns {Quaternion} The modified result parameter or a new instance of the point on the curve at the given time.
  50258. *
  50259. * @exception {DeveloperError} time must be in the range <code>[t<sub>0</sub>, t<sub>n</sub>]</code>, where <code>t<sub>0</sub></code>
  50260. * is the first element in the array <code>times</code> and <code>t<sub>n</sub></code> is the last element
  50261. * in the array <code>times</code>.
  50262. */
  50263. QuaternionSpline.prototype.evaluate = function(time, result) {
  50264. return this._evaluateFunction(time, result);
  50265. };
  50266. return QuaternionSpline;
  50267. });
  50268. /*global define*/
  50269. define('Core/RectangleGeometryLibrary',[
  50270. './Cartesian3',
  50271. './Cartographic',
  50272. './defined',
  50273. './DeveloperError',
  50274. './GeographicProjection',
  50275. './Math',
  50276. './Matrix2',
  50277. './Rectangle'
  50278. ], function(
  50279. Cartesian3,
  50280. Cartographic,
  50281. defined,
  50282. DeveloperError,
  50283. GeographicProjection,
  50284. CesiumMath,
  50285. Matrix2,
  50286. Rectangle) {
  50287. 'use strict';
  50288. var cos = Math.cos;
  50289. var sin = Math.sin;
  50290. var sqrt = Math.sqrt;
  50291. /**
  50292. * @private
  50293. */
  50294. var RectangleGeometryLibrary = {};
  50295. /**
  50296. * @private
  50297. */
  50298. RectangleGeometryLibrary.computePosition = function(options, row, col, position, st) {
  50299. var radiiSquared = options.ellipsoid.radiiSquared;
  50300. var nwCorner = options.nwCorner;
  50301. var rectangle = options.rectangle;
  50302. var stLatitude = nwCorner.latitude - options.granYCos * row + col * options.granXSin;
  50303. var cosLatitude = cos(stLatitude);
  50304. var nZ = sin(stLatitude);
  50305. var kZ = radiiSquared.z * nZ;
  50306. var stLongitude = nwCorner.longitude + row * options.granYSin + col * options.granXCos;
  50307. var nX = cosLatitude * cos(stLongitude);
  50308. var nY = cosLatitude * sin(stLongitude);
  50309. var kX = radiiSquared.x * nX;
  50310. var kY = radiiSquared.y * nY;
  50311. var gamma = sqrt((kX * nX) + (kY * nY) + (kZ * nZ));
  50312. position.x = kX / gamma;
  50313. position.y = kY / gamma;
  50314. position.z = kZ / gamma;
  50315. if (defined(options.vertexFormat) && options.vertexFormat.st) {
  50316. var stNwCorner = options.stNwCorner;
  50317. if (defined(stNwCorner)) {
  50318. stLatitude = stNwCorner.latitude - options.stGranYCos * row + col * options.stGranXSin;
  50319. stLongitude = stNwCorner.longitude + row * options.stGranYSin + col * options.stGranXCos;
  50320. st.x = (stLongitude - options.stWest) * options.lonScalar;
  50321. st.y = (stLatitude - options.stSouth) * options.latScalar;
  50322. } else {
  50323. st.x = (stLongitude - rectangle.west) * options.lonScalar;
  50324. st.y = (stLatitude - rectangle.south) * options.latScalar;
  50325. }
  50326. }
  50327. };
  50328. var rotationMatrixScratch = new Matrix2();
  50329. var nwCartesian = new Cartesian3();
  50330. var centerScratch = new Cartographic();
  50331. var centerCartesian = new Cartesian3();
  50332. var proj = new GeographicProjection();
  50333. function getRotationOptions(nwCorner, rotation, granularityX, granularityY, center, width, height) {
  50334. var cosRotation = Math.cos(rotation);
  50335. var granYCos = granularityY * cosRotation;
  50336. var granXCos = granularityX * cosRotation;
  50337. var sinRotation = Math.sin(rotation);
  50338. var granYSin = granularityY * sinRotation;
  50339. var granXSin = granularityX * sinRotation;
  50340. nwCartesian = proj.project(nwCorner, nwCartesian);
  50341. nwCartesian = Cartesian3.subtract(nwCartesian, centerCartesian, nwCartesian);
  50342. var rotationMatrix = Matrix2.fromRotation(rotation, rotationMatrixScratch);
  50343. nwCartesian = Matrix2.multiplyByVector(rotationMatrix, nwCartesian, nwCartesian);
  50344. nwCartesian = Cartesian3.add(nwCartesian, centerCartesian, nwCartesian);
  50345. nwCorner = proj.unproject(nwCartesian, nwCorner);
  50346. width -= 1;
  50347. height -= 1;
  50348. var latitude = nwCorner.latitude;
  50349. var latitude0 = latitude + width * granXSin;
  50350. var latitude1 = latitude - granYCos * height;
  50351. var latitude2 = latitude - granYCos * height + width * granXSin;
  50352. var north = Math.max(latitude, latitude0, latitude1, latitude2);
  50353. var south = Math.min(latitude, latitude0, latitude1, latitude2);
  50354. var longitude = nwCorner.longitude;
  50355. var longitude0 = longitude + width * granXCos;
  50356. var longitude1 = longitude + height * granYSin;
  50357. var longitude2 = longitude + height * granYSin + width * granXCos;
  50358. var east = Math.max(longitude, longitude0, longitude1, longitude2);
  50359. var west = Math.min(longitude, longitude0, longitude1, longitude2);
  50360. return {
  50361. north: north,
  50362. south: south,
  50363. east: east,
  50364. west: west,
  50365. granYCos : granYCos,
  50366. granYSin : granYSin,
  50367. granXCos : granXCos,
  50368. granXSin : granXSin,
  50369. nwCorner : nwCorner
  50370. };
  50371. }
  50372. /**
  50373. * @private
  50374. */
  50375. RectangleGeometryLibrary.computeOptions = function(geometry, rectangle, nwCorner, stNwCorner) {
  50376. var granularity = geometry._granularity;
  50377. var ellipsoid = geometry._ellipsoid;
  50378. var surfaceHeight = geometry._surfaceHeight;
  50379. var rotation = geometry._rotation;
  50380. var stRotation = geometry._stRotation;
  50381. var extrudedHeight = geometry._extrudedHeight;
  50382. var east = rectangle.east;
  50383. var west = rectangle.west;
  50384. var north = rectangle.north;
  50385. var south = rectangle.south;
  50386. var width;
  50387. var height;
  50388. var granularityX;
  50389. var granularityY;
  50390. var dx;
  50391. var dy = north - south;
  50392. if (west > east) {
  50393. dx = (CesiumMath.TWO_PI - west + east);
  50394. width = Math.ceil(dx / granularity) + 1;
  50395. height = Math.ceil(dy / granularity) + 1;
  50396. granularityX = dx / (width - 1);
  50397. granularityY = dy / (height - 1);
  50398. } else {
  50399. dx = east - west;
  50400. width = Math.ceil(dx / granularity) + 1;
  50401. height = Math.ceil(dy / granularity) + 1;
  50402. granularityX = dx / (width - 1);
  50403. granularityY = dy / (height - 1);
  50404. }
  50405. nwCorner = Rectangle.northwest(rectangle, nwCorner);
  50406. var center = Rectangle.center(rectangle, centerScratch);
  50407. if (rotation !== 0 || stRotation !== 0) {
  50408. if (center.longitude < nwCorner.longitude) {
  50409. center.longitude += CesiumMath.TWO_PI;
  50410. }
  50411. centerCartesian = proj.project(center, centerCartesian);
  50412. }
  50413. var granYCos = granularityY;
  50414. var granXCos = granularityX;
  50415. var granYSin = 0.0;
  50416. var granXSin = 0.0;
  50417. var options = {
  50418. granYCos : granYCos,
  50419. granYSin : granYSin,
  50420. granXCos : granXCos,
  50421. granXSin : granXSin,
  50422. ellipsoid : ellipsoid,
  50423. surfaceHeight : surfaceHeight,
  50424. extrudedHeight : extrudedHeight,
  50425. nwCorner : nwCorner,
  50426. rectangle : rectangle,
  50427. width: width,
  50428. height: height
  50429. };
  50430. if (rotation !== 0) {
  50431. var rotationOptions = getRotationOptions(nwCorner, rotation, granularityX, granularityY, center, width, height);
  50432. north = rotationOptions.north;
  50433. south = rotationOptions.south;
  50434. east = rotationOptions.east;
  50435. west = rotationOptions.west;
  50436. if (north < -CesiumMath.PI_OVER_TWO || north > CesiumMath.PI_OVER_TWO ||
  50437. south < -CesiumMath.PI_OVER_TWO || south > CesiumMath.PI_OVER_TWO) {
  50438. throw new DeveloperError('Rotated rectangle is invalid. It crosses over either the north or south pole.');
  50439. }
  50440. options.granYCos = rotationOptions.granYCos;
  50441. options.granYSin = rotationOptions.granYSin;
  50442. options.granXCos = rotationOptions.granXCos;
  50443. options.granXSin = rotationOptions.granXSin;
  50444. rectangle.north = north;
  50445. rectangle.south = south;
  50446. rectangle.east = east;
  50447. rectangle.west = west;
  50448. }
  50449. if (stRotation !== 0) {
  50450. rotation = rotation - stRotation;
  50451. stNwCorner = Rectangle.northwest(rectangle, stNwCorner);
  50452. var stRotationOptions = getRotationOptions(stNwCorner, rotation, granularityX, granularityY, center, width, height);
  50453. options.stGranYCos = stRotationOptions.granYCos;
  50454. options.stGranXCos = stRotationOptions.granXCos;
  50455. options.stGranYSin = stRotationOptions.granYSin;
  50456. options.stGranXSin = stRotationOptions.granXSin;
  50457. options.stNwCorner = stNwCorner;
  50458. options.stWest = stRotationOptions.west;
  50459. options.stSouth = stRotationOptions.south;
  50460. }
  50461. return options;
  50462. };
  50463. return RectangleGeometryLibrary;
  50464. });
  50465. /*global define*/
  50466. define('Core/RectangleGeometry',[
  50467. './BoundingSphere',
  50468. './Cartesian2',
  50469. './Cartesian3',
  50470. './Cartographic',
  50471. './ComponentDatatype',
  50472. './defaultValue',
  50473. './defined',
  50474. './defineProperties',
  50475. './DeveloperError',
  50476. './Ellipsoid',
  50477. './Geometry',
  50478. './GeometryAttribute',
  50479. './GeometryAttributes',
  50480. './GeometryInstance',
  50481. './GeometryPipeline',
  50482. './IndexDatatype',
  50483. './Math',
  50484. './Matrix2',
  50485. './Matrix3',
  50486. './PolygonPipeline',
  50487. './PrimitiveType',
  50488. './Quaternion',
  50489. './Rectangle',
  50490. './RectangleGeometryLibrary',
  50491. './VertexFormat'
  50492. ], function(
  50493. BoundingSphere,
  50494. Cartesian2,
  50495. Cartesian3,
  50496. Cartographic,
  50497. ComponentDatatype,
  50498. defaultValue,
  50499. defined,
  50500. defineProperties,
  50501. DeveloperError,
  50502. Ellipsoid,
  50503. Geometry,
  50504. GeometryAttribute,
  50505. GeometryAttributes,
  50506. GeometryInstance,
  50507. GeometryPipeline,
  50508. IndexDatatype,
  50509. CesiumMath,
  50510. Matrix2,
  50511. Matrix3,
  50512. PolygonPipeline,
  50513. PrimitiveType,
  50514. Quaternion,
  50515. Rectangle,
  50516. RectangleGeometryLibrary,
  50517. VertexFormat) {
  50518. 'use strict';
  50519. var positionScratch = new Cartesian3();
  50520. var normalScratch = new Cartesian3();
  50521. var tangentScratch = new Cartesian3();
  50522. var binormalScratch = new Cartesian3();
  50523. var rectangleScratch = new Rectangle();
  50524. var stScratch = new Cartesian2();
  50525. var bottomBoundingSphere = new BoundingSphere();
  50526. var topBoundingSphere = new BoundingSphere();
  50527. function createAttributes(vertexFormat, attributes) {
  50528. var geo = new Geometry({
  50529. attributes : new GeometryAttributes(),
  50530. primitiveType : PrimitiveType.TRIANGLES
  50531. });
  50532. geo.attributes.position = new GeometryAttribute({
  50533. componentDatatype : ComponentDatatype.DOUBLE,
  50534. componentsPerAttribute : 3,
  50535. values : attributes.positions
  50536. });
  50537. if (vertexFormat.normal) {
  50538. geo.attributes.normal = new GeometryAttribute({
  50539. componentDatatype : ComponentDatatype.FLOAT,
  50540. componentsPerAttribute : 3,
  50541. values : attributes.normals
  50542. });
  50543. }
  50544. if (vertexFormat.tangent) {
  50545. geo.attributes.tangent = new GeometryAttribute({
  50546. componentDatatype : ComponentDatatype.FLOAT,
  50547. componentsPerAttribute : 3,
  50548. values : attributes.tangents
  50549. });
  50550. }
  50551. if (vertexFormat.binormal) {
  50552. geo.attributes.binormal = new GeometryAttribute({
  50553. componentDatatype : ComponentDatatype.FLOAT,
  50554. componentsPerAttribute : 3,
  50555. values : attributes.binormals
  50556. });
  50557. }
  50558. return geo;
  50559. }
  50560. function calculateAttributes(positions, vertexFormat, ellipsoid, tangentRotationMatrix) {
  50561. var length = positions.length;
  50562. var normals = (vertexFormat.normal) ? new Float32Array(length) : undefined;
  50563. var tangents = (vertexFormat.tangent) ? new Float32Array(length) : undefined;
  50564. var binormals = (vertexFormat.binormal) ? new Float32Array(length) : undefined;
  50565. var attrIndex = 0;
  50566. var binormal = binormalScratch;
  50567. var tangent = tangentScratch;
  50568. var normal = normalScratch;
  50569. for (var i = 0; i < length; i += 3) {
  50570. var p = Cartesian3.fromArray(positions, i, positionScratch);
  50571. var attrIndex1 = attrIndex + 1;
  50572. var attrIndex2 = attrIndex + 2;
  50573. if (vertexFormat.normal || vertexFormat.tangent || vertexFormat.binormal) {
  50574. normal = ellipsoid.geodeticSurfaceNormal(p, normal);
  50575. if (vertexFormat.tangent || vertexFormat.binormal) {
  50576. Cartesian3.cross(Cartesian3.UNIT_Z, normal, tangent);
  50577. Matrix3.multiplyByVector(tangentRotationMatrix, tangent, tangent);
  50578. Cartesian3.normalize(tangent, tangent);
  50579. if (vertexFormat.binormal) {
  50580. Cartesian3.normalize(Cartesian3.cross(normal, tangent, binormal), binormal);
  50581. }
  50582. }
  50583. if (vertexFormat.normal) {
  50584. normals[attrIndex] = normal.x;
  50585. normals[attrIndex1] = normal.y;
  50586. normals[attrIndex2] = normal.z;
  50587. }
  50588. if (vertexFormat.tangent) {
  50589. tangents[attrIndex] = tangent.x;
  50590. tangents[attrIndex1] = tangent.y;
  50591. tangents[attrIndex2] = tangent.z;
  50592. }
  50593. if (vertexFormat.binormal) {
  50594. binormals[attrIndex] = binormal.x;
  50595. binormals[attrIndex1] = binormal.y;
  50596. binormals[attrIndex2] = binormal.z;
  50597. }
  50598. }
  50599. attrIndex += 3;
  50600. }
  50601. return createAttributes(vertexFormat, {
  50602. positions : positions,
  50603. normals : normals,
  50604. tangents : tangents,
  50605. binormals : binormals
  50606. });
  50607. }
  50608. var v1Scratch = new Cartesian3();
  50609. var v2Scratch = new Cartesian3();
  50610. function calculateAttributesWall(positions, vertexFormat, ellipsoid) {
  50611. var length = positions.length;
  50612. var normals = (vertexFormat.normal) ? new Float32Array(length) : undefined;
  50613. var tangents = (vertexFormat.tangent) ? new Float32Array(length) : undefined;
  50614. var binormals = (vertexFormat.binormal) ? new Float32Array(length) : undefined;
  50615. var normalIndex = 0;
  50616. var tangentIndex = 0;
  50617. var binormalIndex = 0;
  50618. var recomputeNormal = true;
  50619. var binormal = binormalScratch;
  50620. var tangent = tangentScratch;
  50621. var normal = normalScratch;
  50622. for (var i = 0; i < length; i += 6) {
  50623. var p = Cartesian3.fromArray(positions, i, positionScratch);
  50624. if (vertexFormat.normal || vertexFormat.tangent || vertexFormat.binormal) {
  50625. var p1 = Cartesian3.fromArray(positions, (i + 6) % length, v1Scratch);
  50626. if (recomputeNormal) {
  50627. var p2 = Cartesian3.fromArray(positions, (i + 3) % length, v2Scratch);
  50628. Cartesian3.subtract(p1, p, p1);
  50629. Cartesian3.subtract(p2, p, p2);
  50630. normal = Cartesian3.normalize(Cartesian3.cross(p2, p1, normal), normal);
  50631. recomputeNormal = false;
  50632. }
  50633. if (Cartesian3.equalsEpsilon(p1, p, CesiumMath.EPSILON10)) { // if we've reached a corner
  50634. recomputeNormal = true;
  50635. }
  50636. if (vertexFormat.tangent || vertexFormat.binormal) {
  50637. binormal = ellipsoid.geodeticSurfaceNormal(p, binormal);
  50638. if (vertexFormat.tangent) {
  50639. tangent = Cartesian3.normalize(Cartesian3.cross(binormal, normal, tangent), tangent);
  50640. }
  50641. }
  50642. if (vertexFormat.normal) {
  50643. normals[normalIndex++] = normal.x;
  50644. normals[normalIndex++] = normal.y;
  50645. normals[normalIndex++] = normal.z;
  50646. normals[normalIndex++] = normal.x;
  50647. normals[normalIndex++] = normal.y;
  50648. normals[normalIndex++] = normal.z;
  50649. }
  50650. if (vertexFormat.tangent) {
  50651. tangents[tangentIndex++] = tangent.x;
  50652. tangents[tangentIndex++] = tangent.y;
  50653. tangents[tangentIndex++] = tangent.z;
  50654. tangents[tangentIndex++] = tangent.x;
  50655. tangents[tangentIndex++] = tangent.y;
  50656. tangents[tangentIndex++] = tangent.z;
  50657. }
  50658. if (vertexFormat.binormal) {
  50659. binormals[binormalIndex++] = binormal.x;
  50660. binormals[binormalIndex++] = binormal.y;
  50661. binormals[binormalIndex++] = binormal.z;
  50662. binormals[binormalIndex++] = binormal.x;
  50663. binormals[binormalIndex++] = binormal.y;
  50664. binormals[binormalIndex++] = binormal.z;
  50665. }
  50666. }
  50667. }
  50668. return createAttributes(vertexFormat, {
  50669. positions : positions,
  50670. normals : normals,
  50671. tangents : tangents,
  50672. binormals : binormals
  50673. });
  50674. }
  50675. function constructRectangle(options) {
  50676. var vertexFormat = options.vertexFormat;
  50677. var ellipsoid = options.ellipsoid;
  50678. var size = options.size;
  50679. var height = options.height;
  50680. var width = options.width;
  50681. var positions = (vertexFormat.position) ? new Float64Array(size * 3) : undefined;
  50682. var textureCoordinates = (vertexFormat.st) ? new Float32Array(size * 2) : undefined;
  50683. var posIndex = 0;
  50684. var stIndex = 0;
  50685. var position = positionScratch;
  50686. var st = stScratch;
  50687. var minX = Number.MAX_VALUE;
  50688. var minY = Number.MAX_VALUE;
  50689. var maxX = -Number.MAX_VALUE;
  50690. var maxY = -Number.MAX_VALUE;
  50691. for (var row = 0; row < height; ++row) {
  50692. for (var col = 0; col < width; ++col) {
  50693. RectangleGeometryLibrary.computePosition(options, row, col, position, st);
  50694. positions[posIndex++] = position.x;
  50695. positions[posIndex++] = position.y;
  50696. positions[posIndex++] = position.z;
  50697. if (vertexFormat.st) {
  50698. textureCoordinates[stIndex++] = st.x;
  50699. textureCoordinates[stIndex++] = st.y;
  50700. minX = Math.min(minX, st.x);
  50701. minY = Math.min(minY, st.y);
  50702. maxX = Math.max(maxX, st.x);
  50703. maxY = Math.max(maxY, st.y);
  50704. }
  50705. }
  50706. }
  50707. if (vertexFormat.st && (minX < 0.0 || minY < 0.0 || maxX > 1.0 || maxY > 1.0)) {
  50708. for (var k = 0; k < textureCoordinates.length; k += 2) {
  50709. textureCoordinates[k] = (textureCoordinates[k] - minX) / (maxX - minX);
  50710. textureCoordinates[k + 1] = (textureCoordinates[k + 1] - minY) / (maxY - minY);
  50711. }
  50712. }
  50713. var geo = calculateAttributes(positions, vertexFormat, ellipsoid, options.tangentRotationMatrix);
  50714. var indicesSize = 6 * (width - 1) * (height - 1);
  50715. var indices = IndexDatatype.createTypedArray(size, indicesSize);
  50716. var index = 0;
  50717. var indicesIndex = 0;
  50718. for (var i = 0; i < height - 1; ++i) {
  50719. for (var j = 0; j < width - 1; ++j) {
  50720. var upperLeft = index;
  50721. var lowerLeft = upperLeft + width;
  50722. var lowerRight = lowerLeft + 1;
  50723. var upperRight = upperLeft + 1;
  50724. indices[indicesIndex++] = upperLeft;
  50725. indices[indicesIndex++] = lowerLeft;
  50726. indices[indicesIndex++] = upperRight;
  50727. indices[indicesIndex++] = upperRight;
  50728. indices[indicesIndex++] = lowerLeft;
  50729. indices[indicesIndex++] = lowerRight;
  50730. ++index;
  50731. }
  50732. ++index;
  50733. }
  50734. geo.indices = indices;
  50735. if (vertexFormat.st) {
  50736. geo.attributes.st = new GeometryAttribute({
  50737. componentDatatype : ComponentDatatype.FLOAT,
  50738. componentsPerAttribute : 2,
  50739. values : textureCoordinates
  50740. });
  50741. }
  50742. return geo;
  50743. }
  50744. function addWallPositions(wallPositions, posIndex, i, topPositions, bottomPositions) {
  50745. wallPositions[posIndex++] = topPositions[i];
  50746. wallPositions[posIndex++] = topPositions[i + 1];
  50747. wallPositions[posIndex++] = topPositions[i + 2];
  50748. wallPositions[posIndex++] = bottomPositions[i];
  50749. wallPositions[posIndex++] = bottomPositions[i + 1];
  50750. wallPositions[posIndex++] = bottomPositions[i + 2];
  50751. return wallPositions;
  50752. }
  50753. function addWallTextureCoordinates(wallTextures, stIndex, i, st) {
  50754. wallTextures[stIndex++] = st[i];
  50755. wallTextures[stIndex++] = st[i + 1];
  50756. wallTextures[stIndex++] = st[i];
  50757. wallTextures[stIndex++] = st[i + 1];
  50758. return wallTextures;
  50759. }
  50760. function constructExtrudedRectangle(options) {
  50761. var vertexFormat = options.vertexFormat;
  50762. var surfaceHeight = options.surfaceHeight;
  50763. var extrudedHeight = options.extrudedHeight;
  50764. var minHeight = Math.min(extrudedHeight, surfaceHeight);
  50765. var maxHeight = Math.max(extrudedHeight, surfaceHeight);
  50766. var height = options.height;
  50767. var width = options.width;
  50768. var ellipsoid = options.ellipsoid;
  50769. var i;
  50770. var topBottomGeo = constructRectangle(options);
  50771. if (CesiumMath.equalsEpsilon(minHeight, maxHeight, CesiumMath.EPSILON10)) {
  50772. return topBottomGeo;
  50773. }
  50774. var topPositions = PolygonPipeline.scaleToGeodeticHeight(topBottomGeo.attributes.position.values, maxHeight, ellipsoid, false);
  50775. topPositions = new Float64Array(topPositions);
  50776. var length = topPositions.length;
  50777. var newLength = length*2;
  50778. var positions = new Float64Array(newLength);
  50779. positions.set(topPositions);
  50780. var bottomPositions = PolygonPipeline.scaleToGeodeticHeight(topBottomGeo.attributes.position.values, minHeight, ellipsoid);
  50781. positions.set(bottomPositions, length);
  50782. topBottomGeo.attributes.position.values = positions;
  50783. var normals = (vertexFormat.normal) ? new Float32Array(newLength) : undefined;
  50784. var tangents = (vertexFormat.tangent) ? new Float32Array(newLength) : undefined;
  50785. var binormals = (vertexFormat.binormal) ? new Float32Array(newLength) : undefined;
  50786. var textures = (vertexFormat.st) ? new Float32Array(newLength/3*2) : undefined;
  50787. var topSt;
  50788. if (vertexFormat.normal) {
  50789. var topNormals = topBottomGeo.attributes.normal.values;
  50790. normals.set(topNormals);
  50791. for (i = 0; i < length; i ++) {
  50792. topNormals[i] = -topNormals[i];
  50793. }
  50794. normals.set(topNormals, length);
  50795. topBottomGeo.attributes.normal.values = normals;
  50796. }
  50797. if (vertexFormat.tangent) {
  50798. var topTangents = topBottomGeo.attributes.tangent.values;
  50799. tangents.set(topTangents);
  50800. for (i = 0; i < length; i ++) {
  50801. topTangents[i] = -topTangents[i];
  50802. }
  50803. tangents.set(topTangents, length);
  50804. topBottomGeo.attributes.tangent.values = tangents;
  50805. }
  50806. if (vertexFormat.binormal) {
  50807. var topBinormals = topBottomGeo.attributes.binormal.values;
  50808. binormals.set(topBinormals);
  50809. binormals.set(topBinormals, length);
  50810. topBottomGeo.attributes.binormal.values = binormals;
  50811. }
  50812. if (vertexFormat.st) {
  50813. topSt = topBottomGeo.attributes.st.values;
  50814. textures.set(topSt);
  50815. textures.set(topSt, length/3*2);
  50816. topBottomGeo.attributes.st.values = textures;
  50817. }
  50818. var indices = topBottomGeo.indices;
  50819. var indicesLength = indices.length;
  50820. var posLength = length / 3;
  50821. var newIndices = IndexDatatype.createTypedArray(newLength/3, indicesLength*2);
  50822. newIndices.set(indices);
  50823. for (i = 0; i < indicesLength; i += 3) {
  50824. newIndices[i + indicesLength] = indices[i + 2] + posLength;
  50825. newIndices[i + 1 + indicesLength] = indices[i + 1] + posLength;
  50826. newIndices[i + 2 + indicesLength] = indices[i] + posLength;
  50827. }
  50828. topBottomGeo.indices = newIndices;
  50829. var perimeterPositions = 2 * width + 2 * height - 4;
  50830. var wallCount = (perimeterPositions + 4) * 2;
  50831. var wallPositions = new Float64Array(wallCount * 3);
  50832. var wallTextures = (vertexFormat.st) ? new Float32Array(wallCount * 2) : undefined;
  50833. var posIndex = 0;
  50834. var stIndex = 0;
  50835. var area = width * height;
  50836. for (i = 0; i < area; i+=width) {
  50837. wallPositions = addWallPositions(wallPositions, posIndex, i*3, topPositions, bottomPositions);
  50838. posIndex += 6;
  50839. if (vertexFormat.st) {
  50840. wallTextures = addWallTextureCoordinates(wallTextures, stIndex, i*2, topSt);
  50841. stIndex += 4;
  50842. }
  50843. }
  50844. for (i = area-width; i < area; i++) {
  50845. wallPositions = addWallPositions(wallPositions, posIndex, i*3, topPositions, bottomPositions);
  50846. posIndex += 6;
  50847. if (vertexFormat.st) {
  50848. wallTextures = addWallTextureCoordinates(wallTextures, stIndex, i*2, topSt);
  50849. stIndex += 4;
  50850. }
  50851. }
  50852. for (i = area-1; i > 0; i-=width) {
  50853. wallPositions = addWallPositions(wallPositions, posIndex, i*3, topPositions, bottomPositions);
  50854. posIndex += 6;
  50855. if (vertexFormat.st) {
  50856. wallTextures = addWallTextureCoordinates(wallTextures, stIndex, i*2, topSt);
  50857. stIndex += 4;
  50858. }
  50859. }
  50860. for (i = width-1; i >= 0; i--) {
  50861. wallPositions = addWallPositions(wallPositions, posIndex, i*3, topPositions, bottomPositions);
  50862. posIndex += 6;
  50863. if (vertexFormat.st) {
  50864. wallTextures = addWallTextureCoordinates(wallTextures, stIndex, i*2, topSt);
  50865. stIndex += 4;
  50866. }
  50867. }
  50868. var geo = calculateAttributesWall(wallPositions, vertexFormat, ellipsoid);
  50869. if (vertexFormat.st) {
  50870. geo.attributes.st = new GeometryAttribute({
  50871. componentDatatype : ComponentDatatype.FLOAT,
  50872. componentsPerAttribute : 2,
  50873. values : wallTextures
  50874. });
  50875. }
  50876. var wallIndices = IndexDatatype.createTypedArray(wallCount, perimeterPositions * 6);
  50877. var upperLeft;
  50878. var lowerLeft;
  50879. var lowerRight;
  50880. var upperRight;
  50881. length = wallPositions.length / 3;
  50882. var index = 0;
  50883. for (i = 0; i < length - 1; i+=2) {
  50884. upperLeft = i;
  50885. upperRight = (upperLeft + 2) % length;
  50886. var p1 = Cartesian3.fromArray(wallPositions, upperLeft * 3, v1Scratch);
  50887. var p2 = Cartesian3.fromArray(wallPositions, upperRight * 3, v2Scratch);
  50888. if (Cartesian3.equalsEpsilon(p1, p2, CesiumMath.EPSILON10)) {
  50889. continue;
  50890. }
  50891. lowerLeft = (upperLeft + 1) % length;
  50892. lowerRight = (lowerLeft + 2) % length;
  50893. wallIndices[index++] = upperLeft;
  50894. wallIndices[index++] = lowerLeft;
  50895. wallIndices[index++] = upperRight;
  50896. wallIndices[index++] = upperRight;
  50897. wallIndices[index++] = lowerLeft;
  50898. wallIndices[index++] = lowerRight;
  50899. }
  50900. geo.indices = wallIndices;
  50901. geo = GeometryPipeline.combineInstances([
  50902. new GeometryInstance({
  50903. geometry : topBottomGeo
  50904. }),
  50905. new GeometryInstance({
  50906. geometry : geo
  50907. })
  50908. ]);
  50909. return geo[0];
  50910. }
  50911. var scratchRotationMatrix = new Matrix3();
  50912. var scratchCartesian3 = new Cartesian3();
  50913. var scratchQuaternion = new Quaternion();
  50914. var scratchRectanglePoints = [new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3()];
  50915. var scratchCartographicPoints = [new Cartographic(), new Cartographic(), new Cartographic(), new Cartographic()];
  50916. function computeRectangle(rectangle, ellipsoid, rotation) {
  50917. if (rotation === 0.0) {
  50918. return Rectangle.clone(rectangle);
  50919. }
  50920. Rectangle.northeast(rectangle, scratchCartographicPoints[0]);
  50921. Rectangle.northwest(rectangle, scratchCartographicPoints[1]);
  50922. Rectangle.southeast(rectangle, scratchCartographicPoints[2]);
  50923. Rectangle.southwest(rectangle, scratchCartographicPoints[3]);
  50924. ellipsoid.cartographicArrayToCartesianArray(scratchCartographicPoints, scratchRectanglePoints);
  50925. var surfaceNormal = ellipsoid.geodeticSurfaceNormalCartographic(Rectangle.center(rectangle, scratchCartesian3));
  50926. Quaternion.fromAxisAngle(surfaceNormal, rotation, scratchQuaternion);
  50927. Matrix3.fromQuaternion(scratchQuaternion, scratchRotationMatrix);
  50928. for (var i = 0; i < 4; ++i) {
  50929. // Apply the rotation
  50930. Matrix3.multiplyByVector(scratchRotationMatrix, scratchRectanglePoints[i], scratchRectanglePoints[i]);
  50931. }
  50932. ellipsoid.cartesianArrayToCartographicArray(scratchRectanglePoints, scratchCartographicPoints);
  50933. return Rectangle.fromCartographicArray(scratchCartographicPoints);
  50934. }
  50935. /**
  50936. * A description of a cartographic rectangle on an ellipsoid centered at the origin. Rectangle geometry can be rendered with both {@link Primitive} and {@link GroundPrimitive}.
  50937. *
  50938. * @alias RectangleGeometry
  50939. * @constructor
  50940. *
  50941. * @param {Object} options Object with the following properties:
  50942. * @param {Rectangle} options.rectangle A cartographic rectangle with north, south, east and west properties in radians.
  50943. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  50944. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the rectangle lies.
  50945. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  50946. * @param {Number} [options.height=0.0] The distance in meters between the rectangle and the ellipsoid surface.
  50947. * @param {Number} [options.rotation=0.0] The rotation of the rectangle, in radians. A positive rotation is counter-clockwise.
  50948. * @param {Number} [options.stRotation=0.0] The rotation of the texture coordinates, in radians. A positive rotation is counter-clockwise.
  50949. * @param {Number} [options.extrudedHeight] The distance in meters between the rectangle's extruded face and the ellipsoid surface.
  50950. * @param {Boolean} [options.closeTop=true] Specifies whether the rectangle has a top cover when extruded.
  50951. * @param {Boolean} [options.closeBottom=true] Specifies whether the rectangle has a bottom cover when extruded.
  50952. *
  50953. * @exception {DeveloperError} <code>options.rectangle.north</code> must be in the interval [<code>-Pi/2</code>, <code>Pi/2</code>].
  50954. * @exception {DeveloperError} <code>options.rectangle.south</code> must be in the interval [<code>-Pi/2</code>, <code>Pi/2</code>].
  50955. * @exception {DeveloperError} <code>options.rectangle.east</code> must be in the interval [<code>-Pi</code>, <code>Pi</code>].
  50956. * @exception {DeveloperError} <code>options.rectangle.west</code> must be in the interval [<code>-Pi</code>, <code>Pi</code>].
  50957. * @exception {DeveloperError} <code>options.rectangle.north</code> must be greater than <code>options.rectangle.south</code>.
  50958. *
  50959. * @see RectangleGeometry#createGeometry
  50960. *
  50961. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Rectangle.html|Cesium Sandcastle Rectangle Demo}
  50962. *
  50963. * @example
  50964. * // 1. create an rectangle
  50965. * var rectangle = new Cesium.RectangleGeometry({
  50966. * ellipsoid : Cesium.Ellipsoid.WGS84,
  50967. * rectangle : Cesium.Rectangle.fromDegrees(-80.0, 39.0, -74.0, 42.0),
  50968. * height : 10000.0
  50969. * });
  50970. * var geometry = Cesium.RectangleGeometry.createGeometry(rectangle);
  50971. *
  50972. * // 2. create an extruded rectangle without a top
  50973. * var rectangle = new Cesium.RectangleGeometry({
  50974. * ellipsoid : Cesium.Ellipsoid.WGS84,
  50975. * rectangle : Cesium.Rectangle.fromDegrees(-80.0, 39.0, -74.0, 42.0),
  50976. * height : 10000.0,
  50977. * extrudedHeight: 300000,
  50978. * closeTop: false
  50979. * });
  50980. * var geometry = Cesium.RectangleGeometry.createGeometry(rectangle);
  50981. */
  50982. function RectangleGeometry(options) {
  50983. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  50984. var rectangle = options.rectangle;
  50985. var granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  50986. var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  50987. var surfaceHeight = defaultValue(options.height, 0.0);
  50988. var rotation = defaultValue(options.rotation, 0.0);
  50989. var stRotation = defaultValue(options.stRotation, 0.0);
  50990. var vertexFormat = defaultValue(options.vertexFormat, VertexFormat.DEFAULT);
  50991. var extrudedHeight = options.extrudedHeight;
  50992. var extrude = defined(extrudedHeight);
  50993. var closeTop = defaultValue(options.closeTop, true);
  50994. var closeBottom = defaultValue(options.closeBottom, true);
  50995. if (!defined(rectangle)) {
  50996. throw new DeveloperError('rectangle is required.');
  50997. }
  50998. Rectangle.validate(rectangle);
  50999. if (rectangle.north < rectangle.south) {
  51000. throw new DeveloperError('options.rectangle.north must be greater than options.rectangle.south');
  51001. }
  51002. this._rectangle = rectangle;
  51003. this._granularity = granularity;
  51004. this._ellipsoid = Ellipsoid.clone(ellipsoid);
  51005. this._surfaceHeight = surfaceHeight;
  51006. this._rotation = rotation;
  51007. this._stRotation = stRotation;
  51008. this._vertexFormat = VertexFormat.clone(vertexFormat);
  51009. this._extrudedHeight = defaultValue(extrudedHeight, 0.0);
  51010. this._extrude = extrude;
  51011. this._closeTop = closeTop;
  51012. this._closeBottom = closeBottom;
  51013. this._workerName = 'createRectangleGeometry';
  51014. this._rotatedRectangle = computeRectangle(this._rectangle, this._ellipsoid, rotation);
  51015. }
  51016. /**
  51017. * The number of elements used to pack the object into an array.
  51018. * @type {Number}
  51019. */
  51020. RectangleGeometry.packedLength = Rectangle.packedLength + Ellipsoid.packedLength + VertexFormat.packedLength + Rectangle.packedLength + 8;
  51021. /**
  51022. * Stores the provided instance into the provided array.
  51023. *
  51024. * @param {RectangleGeometry} value The value to pack.
  51025. * @param {Number[]} array The array to pack into.
  51026. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  51027. *
  51028. * @returns {Number[]} The array that was packed into
  51029. */
  51030. RectangleGeometry.pack = function(value, array, startingIndex) {
  51031. if (!defined(value)) {
  51032. throw new DeveloperError('value is required');
  51033. }
  51034. if (!defined(array)) {
  51035. throw new DeveloperError('array is required');
  51036. }
  51037. startingIndex = defaultValue(startingIndex, 0);
  51038. Rectangle.pack(value._rectangle, array, startingIndex);
  51039. startingIndex += Rectangle.packedLength;
  51040. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  51041. startingIndex += Ellipsoid.packedLength;
  51042. VertexFormat.pack(value._vertexFormat, array, startingIndex);
  51043. startingIndex += VertexFormat.packedLength;
  51044. Rectangle.pack(value._rotatedRectangle, array, startingIndex);
  51045. startingIndex += Rectangle.packedLength;
  51046. array[startingIndex++] = value._granularity;
  51047. array[startingIndex++] = value._surfaceHeight;
  51048. array[startingIndex++] = value._rotation;
  51049. array[startingIndex++] = value._stRotation;
  51050. array[startingIndex++] = value._extrudedHeight;
  51051. array[startingIndex++] = value._extrude ? 1.0 : 0.0;
  51052. array[startingIndex++] = value._closeTop ? 1.0 : 0.0;
  51053. array[startingIndex] = value._closeBottom ? 1.0 : 0.0;
  51054. return array;
  51055. };
  51056. var scratchRectangle = new Rectangle();
  51057. var scratchRotatedRectangle = new Rectangle();
  51058. var scratchEllipsoid = Ellipsoid.clone(Ellipsoid.UNIT_SPHERE);
  51059. var scratchVertexFormat = new VertexFormat();
  51060. var scratchOptions = {
  51061. rectangle : scratchRectangle,
  51062. ellipsoid : scratchEllipsoid,
  51063. vertexFormat : scratchVertexFormat,
  51064. granularity : undefined,
  51065. height : undefined,
  51066. rotation : undefined,
  51067. stRotation : undefined,
  51068. extrudedHeight : undefined,
  51069. closeTop : undefined,
  51070. closeBottom : undefined
  51071. };
  51072. /**
  51073. * Retrieves an instance from a packed array.
  51074. *
  51075. * @param {Number[]} array The packed array.
  51076. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  51077. * @param {RectangleGeometry} [result] The object into which to store the result.
  51078. * @returns {RectangleGeometry} The modified result parameter or a new RectangleGeometry instance if one was not provided.
  51079. */
  51080. RectangleGeometry.unpack = function(array, startingIndex, result) {
  51081. if (!defined(array)) {
  51082. throw new DeveloperError('array is required');
  51083. }
  51084. startingIndex = defaultValue(startingIndex, 0);
  51085. var rectangle = Rectangle.unpack(array, startingIndex, scratchRectangle);
  51086. startingIndex += Rectangle.packedLength;
  51087. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  51088. startingIndex += Ellipsoid.packedLength;
  51089. var vertexFormat = VertexFormat.unpack(array, startingIndex, scratchVertexFormat);
  51090. startingIndex += VertexFormat.packedLength;
  51091. var rotatedRectangle = Rectangle.unpack(array, startingIndex, scratchRotatedRectangle);
  51092. startingIndex += Rectangle.packedLength;
  51093. var granularity = array[startingIndex++];
  51094. var surfaceHeight = array[startingIndex++];
  51095. var rotation = array[startingIndex++];
  51096. var stRotation = array[startingIndex++];
  51097. var extrudedHeight = array[startingIndex++];
  51098. var extrude = array[startingIndex++] === 1.0;
  51099. var closeTop = array[startingIndex++] === 1.0;
  51100. var closeBottom = array[startingIndex] === 1.0;
  51101. if (!defined(result)) {
  51102. scratchOptions.granularity = granularity;
  51103. scratchOptions.height = surfaceHeight;
  51104. scratchOptions.rotation = rotation;
  51105. scratchOptions.stRotation = stRotation;
  51106. scratchOptions.extrudedHeight = extrude ? extrudedHeight : undefined;
  51107. scratchOptions.closeTop = closeTop;
  51108. scratchOptions.closeBottom = closeBottom;
  51109. return new RectangleGeometry(scratchOptions);
  51110. }
  51111. result._rectangle = Rectangle.clone(rectangle, result._rectangle);
  51112. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  51113. result._vertexFormat = VertexFormat.clone(vertexFormat, result._vertexFormat);
  51114. result._granularity = granularity;
  51115. result._surfaceHeight = surfaceHeight;
  51116. result._rotation = rotation;
  51117. result._stRotation = stRotation;
  51118. result._extrudedHeight = extrude ? extrudedHeight : undefined;
  51119. result._extrude = extrude;
  51120. result._closeTop = closeTop;
  51121. result._closeBottom = closeBottom;
  51122. result._rotatedRectangle = rotatedRectangle;
  51123. return result;
  51124. };
  51125. var tangentRotationMatrixScratch = new Matrix3();
  51126. var nwScratch = new Cartographic();
  51127. var stNwScratch = new Cartographic();
  51128. var quaternionScratch = new Quaternion();
  51129. var centerScratch = new Cartographic();
  51130. /**
  51131. * Computes the geometric representation of an rectangle, including its vertices, indices, and a bounding sphere.
  51132. *
  51133. * @param {RectangleGeometry} rectangleGeometry A description of the rectangle.
  51134. * @returns {Geometry|undefined} The computed vertices and indices.
  51135. *
  51136. * @exception {DeveloperError} Rotated rectangle is invalid.
  51137. */
  51138. RectangleGeometry.createGeometry = function(rectangleGeometry) {
  51139. if ((CesiumMath.equalsEpsilon(rectangleGeometry._rectangle.north, rectangleGeometry._rectangle.south, CesiumMath.EPSILON10) ||
  51140. (CesiumMath.equalsEpsilon(rectangleGeometry._rectangle.east, rectangleGeometry._rectangle.west, CesiumMath.EPSILON10)))) {
  51141. return undefined;
  51142. }
  51143. var rectangle = Rectangle.clone(rectangleGeometry._rectangle, rectangleScratch);
  51144. var ellipsoid = rectangleGeometry._ellipsoid;
  51145. var surfaceHeight = rectangleGeometry._surfaceHeight;
  51146. var extrude = rectangleGeometry._extrude;
  51147. var extrudedHeight = rectangleGeometry._extrudedHeight;
  51148. var rotation = rectangleGeometry._rotation;
  51149. var stRotation = rectangleGeometry._stRotation;
  51150. var vertexFormat = rectangleGeometry._vertexFormat;
  51151. var options = RectangleGeometryLibrary.computeOptions(rectangleGeometry, rectangle, nwScratch, stNwScratch);
  51152. var tangentRotationMatrix = tangentRotationMatrixScratch;
  51153. if (stRotation !== 0 || rotation !== 0) {
  51154. var center = Rectangle.center(rectangle, centerScratch);
  51155. var axis = ellipsoid.geodeticSurfaceNormalCartographic(center, v1Scratch);
  51156. Quaternion.fromAxisAngle(axis, -stRotation, quaternionScratch);
  51157. Matrix3.fromQuaternion(quaternionScratch, tangentRotationMatrix);
  51158. } else {
  51159. Matrix3.clone(Matrix3.IDENTITY, tangentRotationMatrix);
  51160. }
  51161. options.lonScalar = 1.0 / rectangleGeometry._rectangle.width;
  51162. options.latScalar = 1.0 / rectangleGeometry._rectangle.height;
  51163. options.vertexFormat = vertexFormat;
  51164. options.rotation = rotation;
  51165. options.stRotation = stRotation;
  51166. options.tangentRotationMatrix = tangentRotationMatrix;
  51167. options.size = options.width * options.height;
  51168. var geometry;
  51169. var boundingSphere;
  51170. rectangle = rectangleGeometry._rectangle;
  51171. if (extrude) {
  51172. geometry = constructExtrudedRectangle(options);
  51173. var topBS = BoundingSphere.fromRectangle3D(rectangle, ellipsoid, surfaceHeight, topBoundingSphere);
  51174. var bottomBS = BoundingSphere.fromRectangle3D(rectangle, ellipsoid, extrudedHeight, bottomBoundingSphere);
  51175. boundingSphere = BoundingSphere.union(topBS, bottomBS);
  51176. } else {
  51177. geometry = constructRectangle(options);
  51178. geometry.attributes.position.values = PolygonPipeline.scaleToGeodeticHeight(geometry.attributes.position.values, surfaceHeight, ellipsoid, false);
  51179. boundingSphere = BoundingSphere.fromRectangle3D(rectangle, ellipsoid, surfaceHeight);
  51180. }
  51181. if (!vertexFormat.position) {
  51182. delete geometry.attributes.position;
  51183. }
  51184. return new Geometry({
  51185. attributes : new GeometryAttributes(geometry.attributes),
  51186. indices : geometry.indices,
  51187. primitiveType : geometry.primitiveType,
  51188. boundingSphere : boundingSphere
  51189. });
  51190. };
  51191. /**
  51192. * @private
  51193. */
  51194. RectangleGeometry.createShadowVolume = function(rectangleGeometry, minHeightFunc, maxHeightFunc) {
  51195. var granularity = rectangleGeometry._granularity;
  51196. var ellipsoid = rectangleGeometry._ellipsoid;
  51197. var minHeight = minHeightFunc(granularity, ellipsoid);
  51198. var maxHeight = maxHeightFunc(granularity, ellipsoid);
  51199. // TODO: stRotation
  51200. return new RectangleGeometry({
  51201. rectangle : rectangleGeometry._rectangle,
  51202. rotation : rectangleGeometry._rotation,
  51203. ellipsoid : ellipsoid,
  51204. stRotation : rectangleGeometry._stRotation,
  51205. granularity : granularity,
  51206. extrudedHeight : maxHeight,
  51207. height : minHeight,
  51208. closeTop : true,
  51209. closeBottom : true,
  51210. vertexFormat : VertexFormat.POSITION_ONLY
  51211. });
  51212. };
  51213. defineProperties(RectangleGeometry.prototype, {
  51214. /**
  51215. * @private
  51216. */
  51217. rectangle : {
  51218. get : function() {
  51219. return this._rotatedRectangle;
  51220. }
  51221. }
  51222. });
  51223. return RectangleGeometry;
  51224. });
  51225. /*global define*/
  51226. define('Core/RectangleOutlineGeometry',[
  51227. './BoundingSphere',
  51228. './Cartesian3',
  51229. './Cartographic',
  51230. './ComponentDatatype',
  51231. './defaultValue',
  51232. './defined',
  51233. './DeveloperError',
  51234. './Ellipsoid',
  51235. './Geometry',
  51236. './GeometryAttribute',
  51237. './GeometryAttributes',
  51238. './IndexDatatype',
  51239. './Math',
  51240. './PolygonPipeline',
  51241. './PrimitiveType',
  51242. './Rectangle',
  51243. './RectangleGeometryLibrary'
  51244. ], function(
  51245. BoundingSphere,
  51246. Cartesian3,
  51247. Cartographic,
  51248. ComponentDatatype,
  51249. defaultValue,
  51250. defined,
  51251. DeveloperError,
  51252. Ellipsoid,
  51253. Geometry,
  51254. GeometryAttribute,
  51255. GeometryAttributes,
  51256. IndexDatatype,
  51257. CesiumMath,
  51258. PolygonPipeline,
  51259. PrimitiveType,
  51260. Rectangle,
  51261. RectangleGeometryLibrary) {
  51262. 'use strict';
  51263. var bottomBoundingSphere = new BoundingSphere();
  51264. var topBoundingSphere = new BoundingSphere();
  51265. var positionScratch = new Cartesian3();
  51266. var rectangleScratch = new Rectangle();
  51267. function constructRectangle(options) {
  51268. var size = options.size;
  51269. var height = options.height;
  51270. var width = options.width;
  51271. var positions = new Float64Array(size * 3);
  51272. var posIndex = 0;
  51273. var row = 0;
  51274. var col;
  51275. var position = positionScratch;
  51276. for (col = 0; col < width; col++) {
  51277. RectangleGeometryLibrary.computePosition(options, row, col, position);
  51278. positions[posIndex++] = position.x;
  51279. positions[posIndex++] = position.y;
  51280. positions[posIndex++] = position.z;
  51281. }
  51282. col = width - 1;
  51283. for (row = 1; row < height; row++) {
  51284. RectangleGeometryLibrary.computePosition(options, row, col, position);
  51285. positions[posIndex++] = position.x;
  51286. positions[posIndex++] = position.y;
  51287. positions[posIndex++] = position.z;
  51288. }
  51289. row = height - 1;
  51290. for (col = width-2; col >=0; col--){
  51291. RectangleGeometryLibrary.computePosition(options, row, col, position);
  51292. positions[posIndex++] = position.x;
  51293. positions[posIndex++] = position.y;
  51294. positions[posIndex++] = position.z;
  51295. }
  51296. col = 0;
  51297. for (row = height - 2; row > 0; row--) {
  51298. RectangleGeometryLibrary.computePosition(options, row, col, position);
  51299. positions[posIndex++] = position.x;
  51300. positions[posIndex++] = position.y;
  51301. positions[posIndex++] = position.z;
  51302. }
  51303. var indicesSize = positions.length/3 * 2;
  51304. var indices = IndexDatatype.createTypedArray(positions.length / 3, indicesSize);
  51305. var index = 0;
  51306. for(var i = 0; i < (positions.length/3)-1; i++) {
  51307. indices[index++] = i;
  51308. indices[index++] = i+1;
  51309. }
  51310. indices[index++] = (positions.length/3)-1;
  51311. indices[index++] = 0;
  51312. var geo = new Geometry({
  51313. attributes : new GeometryAttributes(),
  51314. primitiveType : PrimitiveType.LINES
  51315. });
  51316. geo.attributes.position = new GeometryAttribute({
  51317. componentDatatype : ComponentDatatype.DOUBLE,
  51318. componentsPerAttribute : 3,
  51319. values : positions
  51320. });
  51321. geo.indices = indices;
  51322. return geo;
  51323. }
  51324. function constructExtrudedRectangle(options) {
  51325. var surfaceHeight = options.surfaceHeight;
  51326. var extrudedHeight = options.extrudedHeight;
  51327. var ellipsoid = options.ellipsoid;
  51328. var minHeight = Math.min(extrudedHeight, surfaceHeight);
  51329. var maxHeight = Math.max(extrudedHeight, surfaceHeight);
  51330. var geo = constructRectangle(options);
  51331. if (CesiumMath.equalsEpsilon(minHeight, maxHeight, CesiumMath.EPSILON10)) {
  51332. return geo;
  51333. }
  51334. var height = options.height;
  51335. var width = options.width;
  51336. var topPositions = PolygonPipeline.scaleToGeodeticHeight(geo.attributes.position.values, maxHeight, ellipsoid, false);
  51337. var length = topPositions.length;
  51338. var positions = new Float64Array(length*2);
  51339. positions.set(topPositions);
  51340. var bottomPositions = PolygonPipeline.scaleToGeodeticHeight(geo.attributes.position.values, minHeight, ellipsoid);
  51341. positions.set(bottomPositions, length);
  51342. geo.attributes.position.values = positions;
  51343. var indicesSize = positions.length/3 * 2 + 8;
  51344. var indices = IndexDatatype.createTypedArray(positions.length / 3, indicesSize);
  51345. length = positions.length/6;
  51346. var index = 0;
  51347. for (var i = 0; i < length - 1; i++) {
  51348. indices[index++] = i;
  51349. indices[index++] =i+1;
  51350. indices[index++] = i + length;
  51351. indices[index++] = i + length + 1;
  51352. }
  51353. indices[index++] = length - 1;
  51354. indices[index++] = 0;
  51355. indices[index++] = length + length - 1;
  51356. indices[index++] = length;
  51357. indices[index++] = 0;
  51358. indices[index++] = length;
  51359. indices[index++] = width-1;
  51360. indices[index++] = length + width-1;
  51361. indices[index++] = width + height - 2;
  51362. indices[index++] = width + height - 2 + length;
  51363. indices[index++] = 2*width + height - 3;
  51364. indices[index++] = 2*width + height - 3 + length;
  51365. geo.indices = indices;
  51366. return geo;
  51367. }
  51368. /**
  51369. * A description of the outline of a a cartographic rectangle on an ellipsoid centered at the origin.
  51370. *
  51371. * @alias RectangleOutlineGeometry
  51372. * @constructor
  51373. *
  51374. * @param {Object} options Object with the following properties:
  51375. * @param {Rectangle} options.rectangle A cartographic rectangle with north, south, east and west properties in radians.
  51376. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the rectangle lies.
  51377. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  51378. * @param {Number} [options.height=0.0] The distance in meters between the rectangle and the ellipsoid surface.
  51379. * @param {Number} [options.rotation=0.0] The rotation of the rectangle, in radians. A positive rotation is counter-clockwise.
  51380. * @param {Number} [options.extrudedHeight] The distance in meters between the rectangle's extruded face and the ellipsoid surface.
  51381. *
  51382. * @exception {DeveloperError} <code>options.rectangle.north</code> must be in the interval [<code>-Pi/2</code>, <code>Pi/2</code>].
  51383. * @exception {DeveloperError} <code>options.rectangle.south</code> must be in the interval [<code>-Pi/2</code>, <code>Pi/2</code>].
  51384. * @exception {DeveloperError} <code>options.rectangle.east</code> must be in the interval [<code>-Pi</code>, <code>Pi</code>].
  51385. * @exception {DeveloperError} <code>options.rectangle.west</code> must be in the interval [<code>-Pi</code>, <code>Pi</code>].
  51386. * @exception {DeveloperError} <code>options.rectangle.north</code> must be greater than <code>rectangle.south</code>.
  51387. *
  51388. * @see RectangleOutlineGeometry#createGeometry
  51389. *
  51390. * @example
  51391. * var rectangle = new Cesium.RectangleOutlineGeometry({
  51392. * ellipsoid : Cesium.Ellipsoid.WGS84,
  51393. * rectangle : Cesium.Rectangle.fromDegrees(-80.0, 39.0, -74.0, 42.0),
  51394. * height : 10000.0
  51395. * });
  51396. * var geometry = Cesium.RectangleOutlineGeometry.createGeometry(rectangle);
  51397. */
  51398. function RectangleOutlineGeometry(options) {
  51399. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  51400. var rectangle = options.rectangle;
  51401. var granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  51402. var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  51403. var surfaceHeight = defaultValue(options.height, 0.0);
  51404. var rotation = defaultValue(options.rotation, 0.0);
  51405. var extrudedHeight = options.extrudedHeight;
  51406. if (!defined(rectangle)) {
  51407. throw new DeveloperError('rectangle is required.');
  51408. }
  51409. Rectangle.validate(rectangle);
  51410. if (rectangle.north < rectangle.south) {
  51411. throw new DeveloperError('options.rectangle.north must be greater than options.rectangle.south');
  51412. }
  51413. this._rectangle = rectangle;
  51414. this._granularity = granularity;
  51415. this._ellipsoid = ellipsoid;
  51416. this._surfaceHeight = surfaceHeight;
  51417. this._rotation = rotation;
  51418. this._extrudedHeight = extrudedHeight;
  51419. this._workerName = 'createRectangleOutlineGeometry';
  51420. }
  51421. /**
  51422. * The number of elements used to pack the object into an array.
  51423. * @type {Number}
  51424. */
  51425. RectangleOutlineGeometry.packedLength = Rectangle.packedLength + Ellipsoid.packedLength + 5;
  51426. /**
  51427. * Stores the provided instance into the provided array.
  51428. *
  51429. * @param {RectangleOutlineGeometry} value The value to pack.
  51430. * @param {Number[]} array The array to pack into.
  51431. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  51432. *
  51433. * @returns {Number[]} The array that was packed into
  51434. */
  51435. RectangleOutlineGeometry.pack = function(value, array, startingIndex) {
  51436. if (!defined(value)) {
  51437. throw new DeveloperError('value is required');
  51438. }
  51439. if (!defined(array)) {
  51440. throw new DeveloperError('array is required');
  51441. }
  51442. startingIndex = defaultValue(startingIndex, 0);
  51443. Rectangle.pack(value._rectangle, array, startingIndex);
  51444. startingIndex += Rectangle.packedLength;
  51445. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  51446. startingIndex += Ellipsoid.packedLength;
  51447. array[startingIndex++] = value._granularity;
  51448. array[startingIndex++] = value._surfaceHeight;
  51449. array[startingIndex++] = value._rotation;
  51450. array[startingIndex++] = defined(value._extrudedHeight) ? 1.0 : 0.0;
  51451. array[startingIndex] = defaultValue(value._extrudedHeight, 0.0);
  51452. return array;
  51453. };
  51454. var scratchRectangle = new Rectangle();
  51455. var scratchEllipsoid = Ellipsoid.clone(Ellipsoid.UNIT_SPHERE);
  51456. var scratchOptions = {
  51457. rectangle : scratchRectangle,
  51458. ellipsoid : scratchEllipsoid,
  51459. granularity : undefined,
  51460. height : undefined,
  51461. rotation : undefined,
  51462. extrudedHeight : undefined
  51463. };
  51464. /**
  51465. * Retrieves an instance from a packed array.
  51466. *
  51467. * @param {Number[]} array The packed array.
  51468. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  51469. * @param {RectangleOutlineGeometry} [result] The object into which to store the result.
  51470. * @returns {RectangleOutlineGeometry} The modified result parameter or a new Quaternion instance if one was not provided.
  51471. */
  51472. RectangleOutlineGeometry.unpack = function(array, startingIndex, result) {
  51473. if (!defined(array)) {
  51474. throw new DeveloperError('array is required');
  51475. }
  51476. startingIndex = defaultValue(startingIndex, 0);
  51477. var rectangle = Rectangle.unpack(array, startingIndex, scratchRectangle);
  51478. startingIndex += Rectangle.packedLength;
  51479. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  51480. startingIndex += Ellipsoid.packedLength;
  51481. var granularity = array[startingIndex++];
  51482. var height = array[startingIndex++];
  51483. var rotation = array[startingIndex++];
  51484. var hasExtrudedHeight = array[startingIndex++];
  51485. var extrudedHeight = array[startingIndex];
  51486. if (!defined(result)) {
  51487. scratchOptions.granularity = granularity;
  51488. scratchOptions.height = height;
  51489. scratchOptions.rotation = rotation;
  51490. scratchOptions.extrudedHeight = hasExtrudedHeight ? extrudedHeight : undefined;
  51491. return new RectangleOutlineGeometry(scratchOptions);
  51492. }
  51493. result._rectangle = Rectangle.clone(rectangle, result._rectangle);
  51494. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  51495. result._surfaceHeight = height;
  51496. result._rotation = rotation;
  51497. result._extrudedHeight = hasExtrudedHeight ? extrudedHeight : undefined;
  51498. return result;
  51499. };
  51500. var nwScratch = new Cartographic();
  51501. /**
  51502. * Computes the geometric representation of an outline of an rectangle, including its vertices, indices, and a bounding sphere.
  51503. *
  51504. * @param {RectangleOutlineGeometry} rectangleGeometry A description of the rectangle outline.
  51505. * @returns {Geometry|undefined} The computed vertices and indices.
  51506. *
  51507. * @exception {DeveloperError} Rotated rectangle is invalid.
  51508. */
  51509. RectangleOutlineGeometry.createGeometry = function(rectangleGeometry) {
  51510. var rectangle = Rectangle.clone(rectangleGeometry._rectangle, rectangleScratch);
  51511. var ellipsoid = rectangleGeometry._ellipsoid;
  51512. var surfaceHeight = rectangleGeometry._surfaceHeight;
  51513. var extrudedHeight = rectangleGeometry._extrudedHeight;
  51514. var options = RectangleGeometryLibrary.computeOptions(rectangleGeometry, rectangle, nwScratch);
  51515. options.size = 2*options.width + 2*options.height - 4;
  51516. var geometry;
  51517. var boundingSphere;
  51518. rectangle = rectangleGeometry._rectangle;
  51519. if ((CesiumMath.equalsEpsilon(rectangle.north, rectangle.south, CesiumMath.EPSILON10) ||
  51520. (CesiumMath.equalsEpsilon(rectangle.east, rectangle.west, CesiumMath.EPSILON10)))) {
  51521. return undefined;
  51522. }
  51523. if (defined(extrudedHeight)) {
  51524. geometry = constructExtrudedRectangle(options);
  51525. var topBS = BoundingSphere.fromRectangle3D(rectangle, ellipsoid, surfaceHeight, topBoundingSphere);
  51526. var bottomBS = BoundingSphere.fromRectangle3D(rectangle, ellipsoid, extrudedHeight, bottomBoundingSphere);
  51527. boundingSphere = BoundingSphere.union(topBS, bottomBS);
  51528. } else {
  51529. geometry = constructRectangle(options);
  51530. geometry.attributes.position.values = PolygonPipeline.scaleToGeodeticHeight(geometry.attributes.position.values, surfaceHeight, ellipsoid, false);
  51531. boundingSphere = BoundingSphere.fromRectangle3D(rectangle, ellipsoid, surfaceHeight);
  51532. }
  51533. return new Geometry({
  51534. attributes : geometry.attributes,
  51535. indices : geometry.indices,
  51536. primitiveType : PrimitiveType.LINES,
  51537. boundingSphere : boundingSphere
  51538. });
  51539. };
  51540. return RectangleOutlineGeometry;
  51541. });
  51542. /*global define*/
  51543. define('Core/ReferenceFrame',[
  51544. './freezeObject'
  51545. ], function(
  51546. freezeObject) {
  51547. 'use strict';
  51548. /**
  51549. * Constants for identifying well-known reference frames.
  51550. *
  51551. * @exports ReferenceFrame
  51552. */
  51553. var ReferenceFrame = {
  51554. /**
  51555. * The fixed frame.
  51556. *
  51557. * @type {Number}
  51558. * @constant
  51559. */
  51560. FIXED : 0,
  51561. /**
  51562. * The inertial frame.
  51563. *
  51564. * @type {Number}
  51565. * @constant
  51566. */
  51567. INERTIAL : 1
  51568. };
  51569. return freezeObject(ReferenceFrame);
  51570. });
  51571. /*global define*/
  51572. define('Core/requestAnimationFrame',[
  51573. './defined',
  51574. './getTimestamp'
  51575. ], function(
  51576. defined,
  51577. getTimestamp) {
  51578. 'use strict';
  51579. if (typeof window === 'undefined') {
  51580. return;
  51581. }
  51582. var implementation = window.requestAnimationFrame;
  51583. (function() {
  51584. // look for vendor prefixed function
  51585. if (!defined(implementation)) {
  51586. var vendors = ['webkit', 'moz', 'ms', 'o'];
  51587. var i = 0;
  51588. var len = vendors.length;
  51589. while (i < len && !defined(implementation)) {
  51590. implementation = window[vendors[i] + 'RequestAnimationFrame'];
  51591. ++i;
  51592. }
  51593. }
  51594. // build an implementation based on setTimeout
  51595. if (!defined(implementation)) {
  51596. var msPerFrame = 1000.0 / 60.0;
  51597. var lastFrameTime = 0;
  51598. implementation = function(callback) {
  51599. var currentTime = getTimestamp();
  51600. // schedule the callback to target 60fps, 16.7ms per frame,
  51601. // accounting for the time taken by the callback
  51602. var delay = Math.max(msPerFrame - (currentTime - lastFrameTime), 0);
  51603. lastFrameTime = currentTime + delay;
  51604. return setTimeout(function() {
  51605. callback(lastFrameTime);
  51606. }, delay);
  51607. };
  51608. }
  51609. })();
  51610. /**
  51611. * A browser-independent function to request a new animation frame. This is used to create
  51612. * an application's draw loop as shown in the example below.
  51613. *
  51614. * @exports requestAnimationFrame
  51615. *
  51616. * @param {requestAnimationFrame~Callback} callback The function to call when the next frame should be drawn.
  51617. * @returns {Number} An ID that can be passed to {@link cancelAnimationFrame} to cancel the request.
  51618. *
  51619. *
  51620. * @example
  51621. * // Create a draw loop using requestAnimationFrame. The
  51622. * // tick callback function is called for every animation frame.
  51623. * function tick() {
  51624. * scene.render();
  51625. * Cesium.requestAnimationFrame(tick);
  51626. * }
  51627. * tick();
  51628. *
  51629. * @see {@link http://www.w3.org/TR/animation-timing/#the-WindowAnimationTiming-interface|The WindowAnimationTiming interface}
  51630. */
  51631. function requestAnimationFrame(callback) {
  51632. // we need this extra wrapper function because the native requestAnimationFrame
  51633. // functions must be invoked on the global scope (window), which is not the case
  51634. // if invoked as Cesium.requestAnimationFrame(callback)
  51635. return implementation(callback);
  51636. }
  51637. /**
  51638. * A function that will be called when the next frame should be drawn.
  51639. * @callback requestAnimationFrame~Callback
  51640. *
  51641. * @param {Number} timestamp A timestamp for the frame, in milliseconds.
  51642. */
  51643. return requestAnimationFrame;
  51644. });
  51645. /*global define*/
  51646. define('Core/sampleTerrain',[
  51647. '../ThirdParty/when',
  51648. './defined',
  51649. './DeveloperError'
  51650. ], function(
  51651. when,
  51652. defined,
  51653. DeveloperError) {
  51654. 'use strict';
  51655. /**
  51656. * Initiates a terrain height query for an array of {@link Cartographic} positions by
  51657. * requesting tiles from a terrain provider, sampling, and interpolating. The interpolation
  51658. * matches the triangles used to render the terrain at the specified level. The query
  51659. * happens asynchronously, so this function returns a promise that is resolved when
  51660. * the query completes. Each point height is modified in place. If a height can not be
  51661. * determined because no terrain data is available for the specified level at that location,
  51662. * or another error occurs, the height is set to undefined. As is typical of the
  51663. * {@link Cartographic} type, the supplied height is a height above the reference ellipsoid
  51664. * (such as {@link Ellipsoid.WGS84}) rather than an altitude above mean sea level. In other
  51665. * words, it will not necessarily be 0.0 if sampled in the ocean.
  51666. *
  51667. * @exports sampleTerrain
  51668. *
  51669. * @param {TerrainProvider} terrainProvider The terrain provider from which to query heights.
  51670. * @param {Number} level The terrain level-of-detail from which to query terrain heights.
  51671. * @param {Cartographic[]} positions The positions to update with terrain heights.
  51672. * @returns {Promise.<Cartographic[]>} A promise that resolves to the provided list of positions when terrain the query has completed.
  51673. *
  51674. * @example
  51675. * // Query the terrain height of two Cartographic positions
  51676. * var terrainProvider = new Cesium.CesiumTerrainProvider({
  51677. * url : 'https://assets.agi.com/stk-terrain/world'
  51678. * });
  51679. * var positions = [
  51680. * Cesium.Cartographic.fromDegrees(86.925145, 27.988257),
  51681. * Cesium.Cartographic.fromDegrees(87.0, 28.0)
  51682. * ];
  51683. * var promise = Cesium.sampleTerrain(terrainProvider, 11, positions);
  51684. * Cesium.when(promise, function(updatedPositions) {
  51685. * // positions[0].height and positions[1].height have been updated.
  51686. * // updatedPositions is just a reference to positions.
  51687. * });
  51688. */
  51689. function sampleTerrain(terrainProvider, level, positions) {
  51690. if (!defined(terrainProvider)) {
  51691. throw new DeveloperError('terrainProvider is required.');
  51692. }
  51693. if (!defined(level)) {
  51694. throw new DeveloperError('level is required.');
  51695. }
  51696. if (!defined(positions)) {
  51697. throw new DeveloperError('positions is required.');
  51698. }
  51699. var deferred = when.defer();
  51700. function doSamplingWhenReady() {
  51701. if (terrainProvider.ready) {
  51702. when(doSampling(terrainProvider, level, positions), function(updatedPositions) {
  51703. deferred.resolve(updatedPositions);
  51704. });
  51705. } else {
  51706. setTimeout(doSamplingWhenReady, 10);
  51707. }
  51708. }
  51709. doSamplingWhenReady();
  51710. return deferred.promise;
  51711. }
  51712. function doSampling(terrainProvider, level, positions) {
  51713. var tilingScheme = terrainProvider.tilingScheme;
  51714. var i;
  51715. // Sort points into a set of tiles
  51716. var tileRequests = []; // Result will be an Array as it's easier to work with
  51717. var tileRequestSet = {}; // A unique set
  51718. for (i = 0; i < positions.length; ++i) {
  51719. var xy = tilingScheme.positionToTileXY(positions[i], level);
  51720. var key = xy.toString();
  51721. if (!tileRequestSet.hasOwnProperty(key)) {
  51722. // When tile is requested for the first time
  51723. var value = {
  51724. x : xy.x,
  51725. y : xy.y,
  51726. level : level,
  51727. tilingScheme : tilingScheme,
  51728. terrainProvider : terrainProvider,
  51729. positions : []
  51730. };
  51731. tileRequestSet[key] = value;
  51732. tileRequests.push(value);
  51733. }
  51734. // Now append to array of points for the tile
  51735. tileRequestSet[key].positions.push(positions[i]);
  51736. }
  51737. // Send request for each required tile
  51738. var tilePromises = [];
  51739. for (i = 0; i < tileRequests.length; ++i) {
  51740. var tileRequest = tileRequests[i];
  51741. var requestPromise = tileRequest.terrainProvider.requestTileGeometry(tileRequest.x, tileRequest.y, tileRequest.level, false);
  51742. var tilePromise = when(requestPromise, createInterpolateFunction(tileRequest), createMarkFailedFunction(tileRequest));
  51743. tilePromises.push(tilePromise);
  51744. }
  51745. return when.all(tilePromises, function() {
  51746. return positions;
  51747. });
  51748. }
  51749. function createInterpolateFunction(tileRequest) {
  51750. var tilePositions = tileRequest.positions;
  51751. var rectangle = tileRequest.tilingScheme.tileXYToRectangle(tileRequest.x, tileRequest.y, tileRequest.level);
  51752. return function(terrainData) {
  51753. for (var i = 0; i < tilePositions.length; ++i) {
  51754. var position = tilePositions[i];
  51755. position.height = terrainData.interpolateHeight(rectangle, position.longitude, position.latitude);
  51756. }
  51757. };
  51758. }
  51759. function createMarkFailedFunction(tileRequest) {
  51760. var tilePositions = tileRequest.positions;
  51761. return function() {
  51762. for (var i = 0; i < tilePositions.length; ++i) {
  51763. var position = tilePositions[i];
  51764. position.height = undefined;
  51765. }
  51766. };
  51767. }
  51768. return sampleTerrain;
  51769. });
  51770. /*global define*/
  51771. define('Core/ScreenSpaceEventType',[
  51772. './freezeObject'
  51773. ], function(
  51774. freezeObject) {
  51775. 'use strict';
  51776. /**
  51777. * This enumerated type is for classifying mouse events: down, up, click, double click, move and move while a button is held down.
  51778. *
  51779. * @exports ScreenSpaceEventType
  51780. */
  51781. var ScreenSpaceEventType = {
  51782. /**
  51783. * Represents a mouse left button down event.
  51784. *
  51785. * @type {Number}
  51786. * @constant
  51787. */
  51788. LEFT_DOWN : 0,
  51789. /**
  51790. * Represents a mouse left button up event.
  51791. *
  51792. * @type {Number}
  51793. * @constant
  51794. */
  51795. LEFT_UP : 1,
  51796. /**
  51797. * Represents a mouse left click event.
  51798. *
  51799. * @type {Number}
  51800. * @constant
  51801. */
  51802. LEFT_CLICK : 2,
  51803. /**
  51804. * Represents a mouse left double click event.
  51805. *
  51806. * @type {Number}
  51807. * @constant
  51808. */
  51809. LEFT_DOUBLE_CLICK : 3,
  51810. /**
  51811. * Represents a mouse left button down event.
  51812. *
  51813. * @type {Number}
  51814. * @constant
  51815. */
  51816. RIGHT_DOWN : 5,
  51817. /**
  51818. * Represents a mouse right button up event.
  51819. *
  51820. * @type {Number}
  51821. * @constant
  51822. */
  51823. RIGHT_UP : 6,
  51824. /**
  51825. * Represents a mouse right click event.
  51826. *
  51827. * @type {Number}
  51828. * @constant
  51829. */
  51830. RIGHT_CLICK : 7,
  51831. /**
  51832. * Represents a mouse right double click event.
  51833. *
  51834. * @type {Number}
  51835. * @constant
  51836. */
  51837. RIGHT_DOUBLE_CLICK : 8,
  51838. /**
  51839. * Represents a mouse middle button down event.
  51840. *
  51841. * @type {Number}
  51842. * @constant
  51843. */
  51844. MIDDLE_DOWN : 10,
  51845. /**
  51846. * Represents a mouse middle button up event.
  51847. *
  51848. * @type {Number}
  51849. * @constant
  51850. */
  51851. MIDDLE_UP : 11,
  51852. /**
  51853. * Represents a mouse middle click event.
  51854. *
  51855. * @type {Number}
  51856. * @constant
  51857. */
  51858. MIDDLE_CLICK : 12,
  51859. /**
  51860. * Represents a mouse middle double click event.
  51861. *
  51862. * @type {Number}
  51863. * @constant
  51864. */
  51865. MIDDLE_DOUBLE_CLICK : 13,
  51866. /**
  51867. * Represents a mouse move event.
  51868. *
  51869. * @type {Number}
  51870. * @constant
  51871. */
  51872. MOUSE_MOVE : 15,
  51873. /**
  51874. * Represents a mouse wheel event.
  51875. *
  51876. * @type {Number}
  51877. * @constant
  51878. */
  51879. WHEEL : 16,
  51880. /**
  51881. * Represents the start of a two-finger event on a touch surface.
  51882. *
  51883. * @type {Number}
  51884. * @constant
  51885. */
  51886. PINCH_START : 17,
  51887. /**
  51888. * Represents the end of a two-finger event on a touch surface.
  51889. *
  51890. * @type {Number}
  51891. * @constant
  51892. */
  51893. PINCH_END : 18,
  51894. /**
  51895. * Represents a change of a two-finger event on a touch surface.
  51896. *
  51897. * @type {Number}
  51898. * @constant
  51899. */
  51900. PINCH_MOVE : 19
  51901. };
  51902. return freezeObject(ScreenSpaceEventType);
  51903. });
  51904. /*global define*/
  51905. define('Core/ScreenSpaceEventHandler',[
  51906. './AssociativeArray',
  51907. './Cartesian2',
  51908. './defaultValue',
  51909. './defined',
  51910. './destroyObject',
  51911. './DeveloperError',
  51912. './FeatureDetection',
  51913. './getTimestamp',
  51914. './KeyboardEventModifier',
  51915. './ScreenSpaceEventType'
  51916. ], function(
  51917. AssociativeArray,
  51918. Cartesian2,
  51919. defaultValue,
  51920. defined,
  51921. destroyObject,
  51922. DeveloperError,
  51923. FeatureDetection,
  51924. getTimestamp,
  51925. KeyboardEventModifier,
  51926. ScreenSpaceEventType) {
  51927. 'use strict';
  51928. function getPosition(screenSpaceEventHandler, event, result) {
  51929. var element = screenSpaceEventHandler._element;
  51930. if (element === document) {
  51931. result.x = event.clientX;
  51932. result.y = event.clientY;
  51933. return result;
  51934. }
  51935. var rect = element.getBoundingClientRect();
  51936. result.x = event.clientX - rect.left;
  51937. result.y = event.clientY - rect.top;
  51938. return result;
  51939. }
  51940. function getInputEventKey(type, modifier) {
  51941. var key = type;
  51942. if (defined(modifier)) {
  51943. key += '+' + modifier;
  51944. }
  51945. return key;
  51946. }
  51947. function getModifier(event) {
  51948. if (event.shiftKey) {
  51949. return KeyboardEventModifier.SHIFT;
  51950. } else if (event.ctrlKey) {
  51951. return KeyboardEventModifier.CTRL;
  51952. } else if (event.altKey) {
  51953. return KeyboardEventModifier.ALT;
  51954. }
  51955. return undefined;
  51956. }
  51957. var MouseButton = {
  51958. LEFT : 0,
  51959. MIDDLE : 1,
  51960. RIGHT : 2
  51961. };
  51962. function registerListener(screenSpaceEventHandler, domType, element, callback) {
  51963. function listener(e) {
  51964. callback(screenSpaceEventHandler, e);
  51965. }
  51966. element.addEventListener(domType, listener, false);
  51967. screenSpaceEventHandler._removalFunctions.push(function() {
  51968. element.removeEventListener(domType, listener, false);
  51969. });
  51970. }
  51971. function registerListeners(screenSpaceEventHandler) {
  51972. var element = screenSpaceEventHandler._element;
  51973. // some listeners may be registered on the document, so we still get events even after
  51974. // leaving the bounds of element.
  51975. // this is affected by the existence of an undocumented disableRootEvents property on element.
  51976. var alternateElement = !defined(element.disableRootEvents) ? document : element;
  51977. if (FeatureDetection.supportsPointerEvents()) {
  51978. registerListener(screenSpaceEventHandler, 'pointerdown', element, handlePointerDown);
  51979. registerListener(screenSpaceEventHandler, 'pointerup', element, handlePointerUp);
  51980. registerListener(screenSpaceEventHandler, 'pointermove', element, handlePointerMove);
  51981. registerListener(screenSpaceEventHandler, 'pointercancel', element, handlePointerUp);
  51982. } else {
  51983. registerListener(screenSpaceEventHandler, 'mousedown', element, handleMouseDown);
  51984. registerListener(screenSpaceEventHandler, 'mouseup', alternateElement, handleMouseUp);
  51985. registerListener(screenSpaceEventHandler, 'mousemove', alternateElement, handleMouseMove);
  51986. registerListener(screenSpaceEventHandler, 'touchstart', element, handleTouchStart);
  51987. registerListener(screenSpaceEventHandler, 'touchend', alternateElement, handleTouchEnd);
  51988. registerListener(screenSpaceEventHandler, 'touchmove', alternateElement, handleTouchMove);
  51989. registerListener(screenSpaceEventHandler, 'touchcancel', alternateElement, handleTouchEnd);
  51990. }
  51991. registerListener(screenSpaceEventHandler, 'dblclick', element, handleDblClick);
  51992. // detect available wheel event
  51993. var wheelEvent;
  51994. if ('onwheel' in element) {
  51995. // spec event type
  51996. wheelEvent = 'wheel';
  51997. } else if (document.onmousewheel !== undefined) {
  51998. // legacy event type
  51999. wheelEvent = 'mousewheel';
  52000. } else {
  52001. // older Firefox
  52002. wheelEvent = 'DOMMouseScroll';
  52003. }
  52004. registerListener(screenSpaceEventHandler, wheelEvent, element, handleWheel);
  52005. }
  52006. function unregisterListeners(screenSpaceEventHandler) {
  52007. var removalFunctions = screenSpaceEventHandler._removalFunctions;
  52008. for (var i = 0; i < removalFunctions.length; ++i) {
  52009. removalFunctions[i]();
  52010. }
  52011. }
  52012. var mouseDownEvent = {
  52013. position : new Cartesian2()
  52014. };
  52015. function gotTouchEvent(screenSpaceEventHandler) {
  52016. screenSpaceEventHandler._lastSeenTouchEvent = getTimestamp();
  52017. }
  52018. function canProcessMouseEvent(screenSpaceEventHandler) {
  52019. return (getTimestamp() - screenSpaceEventHandler._lastSeenTouchEvent) > ScreenSpaceEventHandler.mouseEmulationIgnoreMilliseconds;
  52020. }
  52021. function handleMouseDown(screenSpaceEventHandler, event) {
  52022. if (!canProcessMouseEvent(screenSpaceEventHandler)) {
  52023. return;
  52024. }
  52025. var button = event.button;
  52026. screenSpaceEventHandler._buttonDown = button;
  52027. var screenSpaceEventType;
  52028. if (button === MouseButton.LEFT) {
  52029. screenSpaceEventType = ScreenSpaceEventType.LEFT_DOWN;
  52030. } else if (button === MouseButton.MIDDLE) {
  52031. screenSpaceEventType = ScreenSpaceEventType.MIDDLE_DOWN;
  52032. } else if (button === MouseButton.RIGHT) {
  52033. screenSpaceEventType = ScreenSpaceEventType.RIGHT_DOWN;
  52034. } else {
  52035. return;
  52036. }
  52037. var position = getPosition(screenSpaceEventHandler, event, screenSpaceEventHandler._primaryPosition);
  52038. Cartesian2.clone(position, screenSpaceEventHandler._primaryStartPosition);
  52039. Cartesian2.clone(position, screenSpaceEventHandler._primaryPreviousPosition);
  52040. var modifier = getModifier(event);
  52041. var action = screenSpaceEventHandler.getInputAction(screenSpaceEventType, modifier);
  52042. if (defined(action)) {
  52043. Cartesian2.clone(position, mouseDownEvent.position);
  52044. action(mouseDownEvent);
  52045. event.preventDefault();
  52046. }
  52047. }
  52048. var mouseUpEvent = {
  52049. position : new Cartesian2()
  52050. };
  52051. var mouseClickEvent = {
  52052. position : new Cartesian2()
  52053. };
  52054. function handleMouseUp(screenSpaceEventHandler, event) {
  52055. if (!canProcessMouseEvent(screenSpaceEventHandler)) {
  52056. return;
  52057. }
  52058. var button = event.button;
  52059. screenSpaceEventHandler._buttonDown = undefined;
  52060. var screenSpaceEventType;
  52061. var clickScreenSpaceEventType;
  52062. if (button === MouseButton.LEFT) {
  52063. screenSpaceEventType = ScreenSpaceEventType.LEFT_UP;
  52064. clickScreenSpaceEventType = ScreenSpaceEventType.LEFT_CLICK;
  52065. } else if (button === MouseButton.MIDDLE) {
  52066. screenSpaceEventType = ScreenSpaceEventType.MIDDLE_UP;
  52067. clickScreenSpaceEventType = ScreenSpaceEventType.MIDDLE_CLICK;
  52068. } else if (button === MouseButton.RIGHT) {
  52069. screenSpaceEventType = ScreenSpaceEventType.RIGHT_UP;
  52070. clickScreenSpaceEventType = ScreenSpaceEventType.RIGHT_CLICK;
  52071. } else {
  52072. return;
  52073. }
  52074. var modifier = getModifier(event);
  52075. var action = screenSpaceEventHandler.getInputAction(screenSpaceEventType, modifier);
  52076. var clickAction = screenSpaceEventHandler.getInputAction(clickScreenSpaceEventType, modifier);
  52077. if (defined(action) || defined(clickAction)) {
  52078. var position = getPosition(screenSpaceEventHandler, event, screenSpaceEventHandler._primaryPosition);
  52079. if (defined(action)) {
  52080. Cartesian2.clone(position, mouseUpEvent.position);
  52081. action(mouseUpEvent);
  52082. }
  52083. if (defined(clickAction)) {
  52084. var startPosition = screenSpaceEventHandler._primaryStartPosition;
  52085. var xDiff = startPosition.x - position.x;
  52086. var yDiff = startPosition.y - position.y;
  52087. var totalPixels = Math.sqrt(xDiff * xDiff + yDiff * yDiff);
  52088. if (totalPixels < screenSpaceEventHandler._clickPixelTolerance) {
  52089. Cartesian2.clone(position, mouseClickEvent.position);
  52090. clickAction(mouseClickEvent);
  52091. }
  52092. }
  52093. }
  52094. }
  52095. var mouseMoveEvent = {
  52096. startPosition : new Cartesian2(),
  52097. endPosition : new Cartesian2()
  52098. };
  52099. function handleMouseMove(screenSpaceEventHandler, event) {
  52100. if (!canProcessMouseEvent(screenSpaceEventHandler)) {
  52101. return;
  52102. }
  52103. var modifier = getModifier(event);
  52104. var position = getPosition(screenSpaceEventHandler, event, screenSpaceEventHandler._primaryPosition);
  52105. var previousPosition = screenSpaceEventHandler._primaryPreviousPosition;
  52106. var action = screenSpaceEventHandler.getInputAction(ScreenSpaceEventType.MOUSE_MOVE, modifier);
  52107. if (defined(action)) {
  52108. Cartesian2.clone(previousPosition, mouseMoveEvent.startPosition);
  52109. Cartesian2.clone(position, mouseMoveEvent.endPosition);
  52110. action(mouseMoveEvent);
  52111. }
  52112. Cartesian2.clone(position, previousPosition);
  52113. if (defined(screenSpaceEventHandler._buttonDown)) {
  52114. event.preventDefault();
  52115. }
  52116. }
  52117. var mouseDblClickEvent = {
  52118. position : new Cartesian2()
  52119. };
  52120. function handleDblClick(screenSpaceEventHandler, event) {
  52121. var button = event.button;
  52122. var screenSpaceEventType;
  52123. if (button === MouseButton.LEFT) {
  52124. screenSpaceEventType = ScreenSpaceEventType.LEFT_DOUBLE_CLICK;
  52125. } else if (button === MouseButton.MIDDLE) {
  52126. screenSpaceEventType = ScreenSpaceEventType.MIDDLE_DOUBLE_CLICK;
  52127. } else if (button === MouseButton.RIGHT) {
  52128. screenSpaceEventType = ScreenSpaceEventType.RIGHT_DOUBLE_CLICK;
  52129. } else {
  52130. return;
  52131. }
  52132. var modifier = getModifier(event);
  52133. var action = screenSpaceEventHandler.getInputAction(screenSpaceEventType, modifier);
  52134. if (defined(action)) {
  52135. getPosition(screenSpaceEventHandler, event, mouseDblClickEvent.position);
  52136. action(mouseDblClickEvent);
  52137. }
  52138. }
  52139. function handleWheel(screenSpaceEventHandler, event) {
  52140. // currently this event exposes the delta value in terms of
  52141. // the obsolete mousewheel event type. so, for now, we adapt the other
  52142. // values to that scheme.
  52143. var delta;
  52144. // standard wheel event uses deltaY. sign is opposite wheelDelta.
  52145. // deltaMode indicates what unit it is in.
  52146. if (defined(event.deltaY)) {
  52147. var deltaMode = event.deltaMode;
  52148. if (deltaMode === event.DOM_DELTA_PIXEL) {
  52149. delta = -event.deltaY;
  52150. } else if (deltaMode === event.DOM_DELTA_LINE) {
  52151. delta = -event.deltaY * 40;
  52152. } else {
  52153. // DOM_DELTA_PAGE
  52154. delta = -event.deltaY * 120;
  52155. }
  52156. } else if (event.detail > 0) {
  52157. // old Firefox versions use event.detail to count the number of clicks. The sign
  52158. // of the integer is the direction the wheel is scrolled.
  52159. delta = event.detail * -120;
  52160. } else {
  52161. delta = event.wheelDelta;
  52162. }
  52163. if (!defined(delta)) {
  52164. return;
  52165. }
  52166. var modifier = getModifier(event);
  52167. var action = screenSpaceEventHandler.getInputAction(ScreenSpaceEventType.WHEEL, modifier);
  52168. if (defined(action)) {
  52169. action(delta);
  52170. event.preventDefault();
  52171. }
  52172. }
  52173. function handleTouchStart(screenSpaceEventHandler, event) {
  52174. gotTouchEvent(screenSpaceEventHandler);
  52175. var changedTouches = event.changedTouches;
  52176. var i;
  52177. var length = changedTouches.length;
  52178. var touch;
  52179. var identifier;
  52180. var positions = screenSpaceEventHandler._positions;
  52181. for (i = 0; i < length; ++i) {
  52182. touch = changedTouches[i];
  52183. identifier = touch.identifier;
  52184. positions.set(identifier, getPosition(screenSpaceEventHandler, touch, new Cartesian2()));
  52185. }
  52186. fireTouchEvents(screenSpaceEventHandler, event);
  52187. var previousPositions = screenSpaceEventHandler._previousPositions;
  52188. for (i = 0; i < length; ++i) {
  52189. touch = changedTouches[i];
  52190. identifier = touch.identifier;
  52191. previousPositions.set(identifier, Cartesian2.clone(positions.get(identifier)));
  52192. }
  52193. }
  52194. function handleTouchEnd(screenSpaceEventHandler, event) {
  52195. gotTouchEvent(screenSpaceEventHandler);
  52196. var changedTouches = event.changedTouches;
  52197. var i;
  52198. var length = changedTouches.length;
  52199. var touch;
  52200. var identifier;
  52201. var positions = screenSpaceEventHandler._positions;
  52202. for (i = 0; i < length; ++i) {
  52203. touch = changedTouches[i];
  52204. identifier = touch.identifier;
  52205. positions.remove(identifier);
  52206. }
  52207. fireTouchEvents(screenSpaceEventHandler, event);
  52208. var previousPositions = screenSpaceEventHandler._previousPositions;
  52209. for (i = 0; i < length; ++i) {
  52210. touch = changedTouches[i];
  52211. identifier = touch.identifier;
  52212. previousPositions.remove(identifier);
  52213. }
  52214. }
  52215. var touchStartEvent = {
  52216. position : new Cartesian2()
  52217. };
  52218. var touch2StartEvent = {
  52219. position1 : new Cartesian2(),
  52220. position2 : new Cartesian2()
  52221. };
  52222. var touchEndEvent = {
  52223. position : new Cartesian2()
  52224. };
  52225. var touchClickEvent = {
  52226. position : new Cartesian2()
  52227. };
  52228. function fireTouchEvents(screenSpaceEventHandler, event) {
  52229. var modifier = getModifier(event);
  52230. var positions = screenSpaceEventHandler._positions;
  52231. var previousPositions = screenSpaceEventHandler._previousPositions;
  52232. var numberOfTouches = positions.length;
  52233. var action;
  52234. var clickAction;
  52235. if (numberOfTouches !== 1 && screenSpaceEventHandler._buttonDown === MouseButton.LEFT) {
  52236. // transitioning from single touch, trigger UP and might trigger CLICK
  52237. screenSpaceEventHandler._buttonDown = undefined;
  52238. action = screenSpaceEventHandler.getInputAction(ScreenSpaceEventType.LEFT_UP, modifier);
  52239. if (defined(action)) {
  52240. Cartesian2.clone(screenSpaceEventHandler._primaryPosition, touchEndEvent.position);
  52241. action(touchEndEvent);
  52242. }
  52243. if (numberOfTouches === 0) {
  52244. // releasing single touch, check for CLICK
  52245. clickAction = screenSpaceEventHandler.getInputAction(ScreenSpaceEventType.LEFT_CLICK, modifier);
  52246. if (defined(clickAction)) {
  52247. var startPosition = screenSpaceEventHandler._primaryStartPosition;
  52248. var endPosition = previousPositions.values[0];
  52249. var xDiff = startPosition.x - endPosition.x;
  52250. var yDiff = startPosition.y - endPosition.y;
  52251. var totalPixels = Math.sqrt(xDiff * xDiff + yDiff * yDiff);
  52252. if (totalPixels < screenSpaceEventHandler._clickPixelTolerance) {
  52253. Cartesian2.clone(screenSpaceEventHandler._primaryPosition, touchClickEvent.position);
  52254. clickAction(touchClickEvent);
  52255. }
  52256. }
  52257. }
  52258. // Otherwise don't trigger CLICK, because we are adding more touches.
  52259. }
  52260. if (numberOfTouches !== 2 && screenSpaceEventHandler._isPinching) {
  52261. // transitioning from pinch, trigger PINCH_END
  52262. screenSpaceEventHandler._isPinching = false;
  52263. action = screenSpaceEventHandler.getInputAction(ScreenSpaceEventType.PINCH_END, modifier);
  52264. if (defined(action)) {
  52265. action();
  52266. }
  52267. }
  52268. if (numberOfTouches === 1) {
  52269. // transitioning to single touch, trigger DOWN
  52270. var position = positions.values[0];
  52271. Cartesian2.clone(position, screenSpaceEventHandler._primaryPosition);
  52272. Cartesian2.clone(position, screenSpaceEventHandler._primaryStartPosition);
  52273. Cartesian2.clone(position, screenSpaceEventHandler._primaryPreviousPosition);
  52274. screenSpaceEventHandler._buttonDown = MouseButton.LEFT;
  52275. action = screenSpaceEventHandler.getInputAction(ScreenSpaceEventType.LEFT_DOWN, modifier);
  52276. if (defined(action)) {
  52277. Cartesian2.clone(position, touchStartEvent.position);
  52278. action(touchStartEvent);
  52279. }
  52280. event.preventDefault();
  52281. }
  52282. if (numberOfTouches === 2) {
  52283. // transitioning to pinch, trigger PINCH_START
  52284. screenSpaceEventHandler._isPinching = true;
  52285. action = screenSpaceEventHandler.getInputAction(ScreenSpaceEventType.PINCH_START, modifier);
  52286. if (defined(action)) {
  52287. Cartesian2.clone(positions.values[0], touch2StartEvent.position1);
  52288. Cartesian2.clone(positions.values[1], touch2StartEvent.position2);
  52289. action(touch2StartEvent);
  52290. // Touch-enabled devices, in particular iOS can have many default behaviours for
  52291. // "pinch" events, which can still be executed unless we prevent them here.
  52292. event.preventDefault();
  52293. }
  52294. }
  52295. }
  52296. function handleTouchMove(screenSpaceEventHandler, event) {
  52297. gotTouchEvent(screenSpaceEventHandler);
  52298. var changedTouches = event.changedTouches;
  52299. var i;
  52300. var length = changedTouches.length;
  52301. var touch;
  52302. var identifier;
  52303. var positions = screenSpaceEventHandler._positions;
  52304. for (i = 0; i < length; ++i) {
  52305. touch = changedTouches[i];
  52306. identifier = touch.identifier;
  52307. var position = positions.get(identifier);
  52308. if (defined(position)) {
  52309. getPosition(screenSpaceEventHandler, touch, position);
  52310. }
  52311. }
  52312. fireTouchMoveEvents(screenSpaceEventHandler, event);
  52313. var previousPositions = screenSpaceEventHandler._previousPositions;
  52314. for (i = 0; i < length; ++i) {
  52315. touch = changedTouches[i];
  52316. identifier = touch.identifier;
  52317. Cartesian2.clone(positions.get(identifier), previousPositions.get(identifier));
  52318. }
  52319. }
  52320. var touchMoveEvent = {
  52321. startPosition : new Cartesian2(),
  52322. endPosition : new Cartesian2()
  52323. };
  52324. var touchPinchMovementEvent = {
  52325. distance : {
  52326. startPosition : new Cartesian2(),
  52327. endPosition : new Cartesian2()
  52328. },
  52329. angleAndHeight : {
  52330. startPosition : new Cartesian2(),
  52331. endPosition : new Cartesian2()
  52332. }
  52333. };
  52334. function fireTouchMoveEvents(screenSpaceEventHandler, event) {
  52335. var modifier = getModifier(event);
  52336. var positions = screenSpaceEventHandler._positions;
  52337. var previousPositions = screenSpaceEventHandler._previousPositions;
  52338. var numberOfTouches = positions.length;
  52339. var action;
  52340. if (numberOfTouches === 1 && screenSpaceEventHandler._buttonDown === MouseButton.LEFT) {
  52341. // moving single touch
  52342. var position = positions.values[0];
  52343. Cartesian2.clone(position, screenSpaceEventHandler._primaryPosition);
  52344. var previousPosition = screenSpaceEventHandler._primaryPreviousPosition;
  52345. action = screenSpaceEventHandler.getInputAction(ScreenSpaceEventType.MOUSE_MOVE, modifier);
  52346. if (defined(action)) {
  52347. Cartesian2.clone(previousPosition, touchMoveEvent.startPosition);
  52348. Cartesian2.clone(position, touchMoveEvent.endPosition);
  52349. action(touchMoveEvent);
  52350. }
  52351. Cartesian2.clone(position, previousPosition);
  52352. event.preventDefault();
  52353. } else if (numberOfTouches === 2 && screenSpaceEventHandler._isPinching) {
  52354. // moving pinch
  52355. action = screenSpaceEventHandler.getInputAction(ScreenSpaceEventType.PINCH_MOVE, modifier);
  52356. if (defined(action)) {
  52357. var position1 = positions.values[0];
  52358. var position2 = positions.values[1];
  52359. var previousPosition1 = previousPositions.values[0];
  52360. var previousPosition2 = previousPositions.values[1];
  52361. var dX = position2.x - position1.x;
  52362. var dY = position2.y - position1.y;
  52363. var dist = Math.sqrt(dX * dX + dY * dY) * 0.25;
  52364. var prevDX = previousPosition2.x - previousPosition1.x;
  52365. var prevDY = previousPosition2.y - previousPosition1.y;
  52366. var prevDist = Math.sqrt(prevDX * prevDX + prevDY * prevDY) * 0.25;
  52367. var cY = (position2.y + position1.y) * 0.125;
  52368. var prevCY = (previousPosition2.y + previousPosition1.y) * 0.125;
  52369. var angle = Math.atan2(dY, dX);
  52370. var prevAngle = Math.atan2(prevDY, prevDX);
  52371. Cartesian2.fromElements(0.0, prevDist, touchPinchMovementEvent.distance.startPosition);
  52372. Cartesian2.fromElements(0.0, dist, touchPinchMovementEvent.distance.endPosition);
  52373. Cartesian2.fromElements(prevAngle, prevCY, touchPinchMovementEvent.angleAndHeight.startPosition);
  52374. Cartesian2.fromElements(angle, cY, touchPinchMovementEvent.angleAndHeight.endPosition);
  52375. action(touchPinchMovementEvent);
  52376. }
  52377. }
  52378. }
  52379. function handlePointerDown(screenSpaceEventHandler, event) {
  52380. event.target.setPointerCapture(event.pointerId);
  52381. if (event.pointerType === 'touch') {
  52382. var positions = screenSpaceEventHandler._positions;
  52383. var identifier = event.pointerId;
  52384. positions.set(identifier, getPosition(screenSpaceEventHandler, event, new Cartesian2()));
  52385. fireTouchEvents(screenSpaceEventHandler, event);
  52386. var previousPositions = screenSpaceEventHandler._previousPositions;
  52387. previousPositions.set(identifier, Cartesian2.clone(positions.get(identifier)));
  52388. } else {
  52389. handleMouseDown(screenSpaceEventHandler, event);
  52390. }
  52391. }
  52392. function handlePointerUp(screenSpaceEventHandler, event) {
  52393. if (event.pointerType === 'touch') {
  52394. var positions = screenSpaceEventHandler._positions;
  52395. var identifier = event.pointerId;
  52396. positions.remove(identifier);
  52397. fireTouchEvents(screenSpaceEventHandler, event);
  52398. var previousPositions = screenSpaceEventHandler._previousPositions;
  52399. previousPositions.remove(identifier);
  52400. } else {
  52401. handleMouseUp(screenSpaceEventHandler, event);
  52402. }
  52403. }
  52404. function handlePointerMove(screenSpaceEventHandler, event) {
  52405. if (event.pointerType === 'touch') {
  52406. var positions = screenSpaceEventHandler._positions;
  52407. var identifier = event.pointerId;
  52408. var position = positions.get(identifier);
  52409. if(!defined(position)){
  52410. return;
  52411. }
  52412. getPosition(screenSpaceEventHandler, event, position);
  52413. fireTouchMoveEvents(screenSpaceEventHandler, event);
  52414. var previousPositions = screenSpaceEventHandler._previousPositions;
  52415. Cartesian2.clone(positions.get(identifier), previousPositions.get(identifier));
  52416. } else {
  52417. handleMouseMove(screenSpaceEventHandler, event);
  52418. }
  52419. }
  52420. /**
  52421. * Handles user input events. Custom functions can be added to be executed on
  52422. * when the user enters input.
  52423. *
  52424. * @alias ScreenSpaceEventHandler
  52425. *
  52426. * @param {Canvas} [element=document] The element to add events to.
  52427. *
  52428. * @constructor
  52429. */
  52430. function ScreenSpaceEventHandler(element) {
  52431. this._inputEvents = {};
  52432. this._buttonDown = undefined;
  52433. this._isPinching = false;
  52434. this._lastSeenTouchEvent = -ScreenSpaceEventHandler.mouseEmulationIgnoreMilliseconds;
  52435. this._primaryStartPosition = new Cartesian2();
  52436. this._primaryPosition = new Cartesian2();
  52437. this._primaryPreviousPosition = new Cartesian2();
  52438. this._positions = new AssociativeArray();
  52439. this._previousPositions = new AssociativeArray();
  52440. this._removalFunctions = [];
  52441. // TODO: Revisit when doing mobile development. May need to be configurable
  52442. // or determined based on the platform?
  52443. this._clickPixelTolerance = 5;
  52444. this._element = defaultValue(element, document);
  52445. registerListeners(this);
  52446. }
  52447. /**
  52448. * Set a function to be executed on an input event.
  52449. *
  52450. * @param {Function} action Function to be executed when the input event occurs.
  52451. * @param {Number} type The ScreenSpaceEventType of input event.
  52452. * @param {Number} [modifier] A KeyboardEventModifier key that is held when a <code>type</code>
  52453. * event occurs.
  52454. *
  52455. * @see ScreenSpaceEventHandler#getInputAction
  52456. * @see ScreenSpaceEventHandler#removeInputAction
  52457. */
  52458. ScreenSpaceEventHandler.prototype.setInputAction = function(action, type, modifier) {
  52459. if (!defined(action)) {
  52460. throw new DeveloperError('action is required.');
  52461. }
  52462. if (!defined(type)) {
  52463. throw new DeveloperError('type is required.');
  52464. }
  52465. var key = getInputEventKey(type, modifier);
  52466. this._inputEvents[key] = action;
  52467. };
  52468. /**
  52469. * Returns the function to be executed on an input event.
  52470. *
  52471. * @param {Number} type The ScreenSpaceEventType of input event.
  52472. * @param {Number} [modifier] A KeyboardEventModifier key that is held when a <code>type</code>
  52473. * event occurs.
  52474. *
  52475. * @see ScreenSpaceEventHandler#setInputAction
  52476. * @see ScreenSpaceEventHandler#removeInputAction
  52477. */
  52478. ScreenSpaceEventHandler.prototype.getInputAction = function(type, modifier) {
  52479. if (!defined(type)) {
  52480. throw new DeveloperError('type is required.');
  52481. }
  52482. var key = getInputEventKey(type, modifier);
  52483. return this._inputEvents[key];
  52484. };
  52485. /**
  52486. * Removes the function to be executed on an input event.
  52487. *
  52488. * @param {Number} type The ScreenSpaceEventType of input event.
  52489. * @param {Number} [modifier] A KeyboardEventModifier key that is held when a <code>type</code>
  52490. * event occurs.
  52491. *
  52492. * @see ScreenSpaceEventHandler#getInputAction
  52493. * @see ScreenSpaceEventHandler#setInputAction
  52494. */
  52495. ScreenSpaceEventHandler.prototype.removeInputAction = function(type, modifier) {
  52496. if (!defined(type)) {
  52497. throw new DeveloperError('type is required.');
  52498. }
  52499. var key = getInputEventKey(type, modifier);
  52500. delete this._inputEvents[key];
  52501. };
  52502. /**
  52503. * Returns true if this object was destroyed; otherwise, false.
  52504. * <br /><br />
  52505. * If this object was destroyed, it should not be used; calling any function other than
  52506. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  52507. *
  52508. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  52509. *
  52510. * @see ScreenSpaceEventHandler#destroy
  52511. */
  52512. ScreenSpaceEventHandler.prototype.isDestroyed = function() {
  52513. return false;
  52514. };
  52515. /**
  52516. * Removes listeners held by this object.
  52517. * <br /><br />
  52518. * Once an object is destroyed, it should not be used; calling any function other than
  52519. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  52520. * assign the return value (<code>undefined</code>) to the object as done in the example.
  52521. *
  52522. * @returns {undefined}
  52523. *
  52524. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  52525. *
  52526. *
  52527. * @example
  52528. * handler = handler && handler.destroy();
  52529. *
  52530. * @see ScreenSpaceEventHandler#isDestroyed
  52531. */
  52532. ScreenSpaceEventHandler.prototype.destroy = function() {
  52533. unregisterListeners(this);
  52534. return destroyObject(this);
  52535. };
  52536. /**
  52537. * The amount of time, in milliseconds, that mouse events will be disabled after
  52538. * receiving any touch events, such that any emulated mouse events will be ignored.
  52539. * @default 800
  52540. */
  52541. ScreenSpaceEventHandler.mouseEmulationIgnoreMilliseconds = 800;
  52542. return ScreenSpaceEventHandler;
  52543. });
  52544. /*global define*/
  52545. define('Core/ShowGeometryInstanceAttribute',[
  52546. './ComponentDatatype',
  52547. './defaultValue',
  52548. './defined',
  52549. './defineProperties',
  52550. './DeveloperError'
  52551. ], function(
  52552. ComponentDatatype,
  52553. defaultValue,
  52554. defined,
  52555. defineProperties,
  52556. DeveloperError) {
  52557. 'use strict';
  52558. /**
  52559. * Value and type information for per-instance geometry attribute that determines if the geometry instance will be shown.
  52560. *
  52561. * @alias ShowGeometryInstanceAttribute
  52562. * @constructor
  52563. *
  52564. * @param {Boolean} [show=true] Determines if the geometry instance will be shown.
  52565. *
  52566. *
  52567. * @example
  52568. * var instance = new Cesium.GeometryInstance({
  52569. * geometry : new Cesium.BoxGeometry({
  52570. * vertexFormat : Cesium.VertexFormat.POSITION_AND_NORMAL,
  52571. * minimum : new Cesium.Cartesian3(-250000.0, -250000.0, -250000.0),
  52572. * maximum : new Cesium.Cartesian3(250000.0, 250000.0, 250000.0)
  52573. * }),
  52574. * modelMatrix : Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(
  52575. * Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883)), new Cesium.Cartesian3(0.0, 0.0, 1000000.0), new Cesium.Matrix4()),
  52576. * id : 'box',
  52577. * attributes : {
  52578. * show : new Cesium.ShowGeometryInstanceAttribute(false)
  52579. * }
  52580. * });
  52581. *
  52582. * @see GeometryInstance
  52583. * @see GeometryInstanceAttribute
  52584. */
  52585. function ShowGeometryInstanceAttribute(show) {
  52586. show = defaultValue(show, true);
  52587. /**
  52588. * The values for the attributes stored in a typed array.
  52589. *
  52590. * @type Uint8Array
  52591. *
  52592. * @default [1.0]
  52593. */
  52594. this.value = ShowGeometryInstanceAttribute.toValue(show);
  52595. }
  52596. defineProperties(ShowGeometryInstanceAttribute.prototype, {
  52597. /**
  52598. * The datatype of each component in the attribute, e.g., individual elements in
  52599. * {@link ColorGeometryInstanceAttribute#value}.
  52600. *
  52601. * @memberof ShowGeometryInstanceAttribute.prototype
  52602. *
  52603. * @type {ComponentDatatype}
  52604. * @readonly
  52605. *
  52606. * @default {@link ComponentDatatype.UNSIGNED_BYTE}
  52607. */
  52608. componentDatatype : {
  52609. get : function() {
  52610. return ComponentDatatype.UNSIGNED_BYTE;
  52611. }
  52612. },
  52613. /**
  52614. * The number of components in the attributes, i.e., {@link ColorGeometryInstanceAttribute#value}.
  52615. *
  52616. * @memberof ShowGeometryInstanceAttribute.prototype
  52617. *
  52618. * @type {Number}
  52619. * @readonly
  52620. *
  52621. * @default 1
  52622. */
  52623. componentsPerAttribute : {
  52624. get : function() {
  52625. return 1;
  52626. }
  52627. },
  52628. /**
  52629. * When <code>true</code> and <code>componentDatatype</code> is an integer format,
  52630. * indicate that the components should be mapped to the range [0, 1] (unsigned)
  52631. * or [-1, 1] (signed) when they are accessed as floating-point for rendering.
  52632. *
  52633. * @memberof ShowGeometryInstanceAttribute.prototype
  52634. *
  52635. * @type {Boolean}
  52636. * @readonly
  52637. *
  52638. * @default true
  52639. */
  52640. normalize : {
  52641. get : function() {
  52642. return false;
  52643. }
  52644. }
  52645. });
  52646. /**
  52647. * Converts a boolean show to a typed array that can be used to assign a show attribute.
  52648. *
  52649. * @param {Boolean} show The show value.
  52650. * @param {Uint8Array} [result] The array to store the result in, if undefined a new instance will be created.
  52651. * @returns {Uint8Array} The modified result parameter or a new instance if result was undefined.
  52652. *
  52653. * @example
  52654. * var attributes = primitive.getGeometryInstanceAttributes('an id');
  52655. * attributes.show = Cesium.ShowGeometryInstanceAttribute.toValue(true, attributes.show);
  52656. */
  52657. ShowGeometryInstanceAttribute.toValue = function(show, result) {
  52658. if (!defined(show)) {
  52659. throw new DeveloperError('show is required.');
  52660. }
  52661. if (!defined(result)) {
  52662. return new Uint8Array([show]);
  52663. }
  52664. result[0] = show;
  52665. return result;
  52666. };
  52667. return ShowGeometryInstanceAttribute;
  52668. });
  52669. /*global define*/
  52670. define('Core/Simon1994PlanetaryPositions',[
  52671. './Cartesian3',
  52672. './defined',
  52673. './DeveloperError',
  52674. './JulianDate',
  52675. './Math',
  52676. './Matrix3',
  52677. './TimeConstants',
  52678. './TimeStandard'
  52679. ], function(
  52680. Cartesian3,
  52681. defined,
  52682. DeveloperError,
  52683. JulianDate,
  52684. CesiumMath,
  52685. Matrix3,
  52686. TimeConstants,
  52687. TimeStandard) {
  52688. 'use strict';
  52689. /**
  52690. * Contains functions for finding the Cartesian coordinates of the sun and the moon in the
  52691. * Earth-centered inertial frame.
  52692. *
  52693. * @exports Simon1994PlanetaryPositions
  52694. */
  52695. var Simon1994PlanetaryPositions = {};
  52696. function computeTdbMinusTtSpice(daysSinceJ2000InTerrestrialTime) {
  52697. /* STK Comments ------------------------------------------------------
  52698. * This function uses constants designed to be consistent with
  52699. * the SPICE Toolkit from JPL version N0051 (unitim.c)
  52700. * M0 = 6.239996
  52701. * M0Dot = 1.99096871e-7 rad/s = 0.01720197 rad/d
  52702. * EARTH_ECC = 1.671e-2
  52703. * TDB_AMPL = 1.657e-3 secs
  52704. *--------------------------------------------------------------------*/
  52705. //* Values taken as specified in STK Comments except: 0.01720197 rad/day = 1.99096871e-7 rad/sec
  52706. //* Here we use the more precise value taken from the SPICE value 1.99096871e-7 rad/sec converted to rad/day
  52707. //* All other constants are consistent with the SPICE implementation of the TDB conversion
  52708. //* except where we treat the independent time parameter to be in TT instead of TDB.
  52709. //* This is an approximation made to facilitate performance due to the higher prevalance of
  52710. //* the TT2TDB conversion over TDB2TT in order to avoid having to iterate when converting to TDB for the JPL ephemeris.
  52711. //* Days are used instead of seconds to provide a slight improvement in numerical precision.
  52712. //* For more information see:
  52713. //* http://www.cv.nrao.edu/~rfisher/Ephemerides/times.html#TDB
  52714. //* ftp://ssd.jpl.nasa.gov/pub/eph/planets/ioms/ExplSupplChap8.pdf
  52715. var g = 6.239996 + (0.0172019696544) * daysSinceJ2000InTerrestrialTime;
  52716. return 1.657e-3 * Math.sin(g + 1.671e-2 * Math.sin(g));
  52717. }
  52718. var TdtMinusTai = 32.184;
  52719. var J2000d = 2451545;
  52720. function taiToTdb(date, result) {
  52721. //Converts TAI to TT
  52722. result = JulianDate.addSeconds(date, TdtMinusTai, result);
  52723. //Converts TT to TDB
  52724. var days = JulianDate.totalDays(result) - J2000d;
  52725. result = JulianDate.addSeconds(result, computeTdbMinusTtSpice(days), result);
  52726. return result;
  52727. }
  52728. var epoch = new JulianDate(2451545, 0, TimeStandard.TAI); //Actually TDB (not TAI)
  52729. var MetersPerKilometer = 1000.0;
  52730. var RadiansPerDegree = CesiumMath.RADIANS_PER_DEGREE;
  52731. var RadiansPerArcSecond = CesiumMath.RADIANS_PER_ARCSECOND;
  52732. var MetersPerAstronomicalUnit = 1.49597870e+11; // IAU 1976 value
  52733. var perifocalToEquatorial = new Matrix3();
  52734. function elementsToCartesian(semimajorAxis, eccentricity, inclination, longitudeOfPerigee, longitudeOfNode, meanLongitude, result) {
  52735. if (inclination < 0.0) {
  52736. inclination = -inclination;
  52737. longitudeOfNode += CesiumMath.PI;
  52738. }
  52739. if (inclination < 0 || inclination > CesiumMath.PI) {
  52740. throw new DeveloperError('The inclination is out of range. Inclination must be greater than or equal to zero and less than or equal to Pi radians.');
  52741. }
  52742. var radiusOfPeriapsis = semimajorAxis * (1.0 - eccentricity);
  52743. var argumentOfPeriapsis = longitudeOfPerigee - longitudeOfNode;
  52744. var rightAscensionOfAscendingNode = longitudeOfNode;
  52745. var trueAnomaly = meanAnomalyToTrueAnomaly(meanLongitude - longitudeOfPerigee, eccentricity);
  52746. var type = chooseOrbit(eccentricity, 0.0);
  52747. if (type === 'Hyperbolic' && Math.abs(CesiumMath.negativePiToPi(trueAnomaly)) >= Math.acos(- 1.0 / eccentricity)) {
  52748. throw new DeveloperError('The true anomaly of the hyperbolic orbit lies outside of the bounds of the hyperbola.');
  52749. }
  52750. perifocalToCartesianMatrix(argumentOfPeriapsis, inclination, rightAscensionOfAscendingNode, perifocalToEquatorial);
  52751. var semilatus = radiusOfPeriapsis * (1.0 + eccentricity);
  52752. var costheta = Math.cos(trueAnomaly);
  52753. var sintheta = Math.sin(trueAnomaly);
  52754. var denom = (1.0 + eccentricity * costheta);
  52755. if (denom <= CesiumMath.Epsilon10) {
  52756. throw new DeveloperError('elements cannot be converted to cartesian');
  52757. }
  52758. var radius = semilatus / denom;
  52759. if (!defined(result)) {
  52760. result = new Cartesian3(radius * costheta, radius * sintheta, 0.0);
  52761. } else {
  52762. result.x = radius * costheta;
  52763. result.y = radius * sintheta;
  52764. result.z = 0.0;
  52765. }
  52766. return Matrix3.multiplyByVector(perifocalToEquatorial, result, result);
  52767. }
  52768. function chooseOrbit(eccentricity, tolerance) {
  52769. if (eccentricity < 0) {
  52770. throw new DeveloperError('eccentricity cannot be negative.');
  52771. }
  52772. if (eccentricity <= tolerance) {
  52773. return 'Circular';
  52774. } else if (eccentricity < 1.0 - tolerance) {
  52775. return 'Elliptical';
  52776. } else if (eccentricity <= 1.0 + tolerance) {
  52777. return 'Parabolic';
  52778. } else {
  52779. return 'Hyperbolic';
  52780. }
  52781. }
  52782. // Calculates the true anomaly given the mean anomaly and the eccentricity.
  52783. function meanAnomalyToTrueAnomaly(meanAnomaly, eccentricity) {
  52784. if (eccentricity < 0.0 || eccentricity >= 1.0) {
  52785. throw new DeveloperError('eccentricity out of range.');
  52786. }
  52787. var eccentricAnomaly = meanAnomalyToEccentricAnomaly(meanAnomaly, eccentricity);
  52788. return eccentricAnomalyToTrueAnomaly(eccentricAnomaly, eccentricity);
  52789. }
  52790. var maxIterationCount = 50;
  52791. var keplerEqConvergence = CesiumMath.EPSILON8;
  52792. // Calculates the eccentric anomaly given the mean anomaly and the eccentricity.
  52793. function meanAnomalyToEccentricAnomaly(meanAnomaly, eccentricity) {
  52794. if (eccentricity < 0.0 || eccentricity >= 1.0) {
  52795. throw new DeveloperError('eccentricity out of range.');
  52796. }
  52797. var revs = Math.floor(meanAnomaly / CesiumMath.TWO_PI);
  52798. // Find angle in current revolution
  52799. meanAnomaly -= revs * CesiumMath.TWO_PI;
  52800. // calculate starting value for iteration sequence
  52801. var iterationValue = meanAnomaly + (eccentricity * Math.sin(meanAnomaly)) /
  52802. (1.0 - Math.sin(meanAnomaly + eccentricity) + Math.sin(meanAnomaly));
  52803. // Perform Newton-Raphson iteration on Kepler's equation
  52804. var eccentricAnomaly = Number.MAX_VALUE;
  52805. var count;
  52806. for (count = 0;
  52807. count < maxIterationCount && Math.abs(eccentricAnomaly - iterationValue) > keplerEqConvergence;
  52808. ++count)
  52809. {
  52810. eccentricAnomaly = iterationValue;
  52811. var NRfunction = eccentricAnomaly - eccentricity * Math.sin(eccentricAnomaly) - meanAnomaly;
  52812. var dNRfunction = 1 - eccentricity * Math.cos(eccentricAnomaly);
  52813. iterationValue = eccentricAnomaly - NRfunction / dNRfunction;
  52814. }
  52815. if (count >= maxIterationCount) {
  52816. throw new DeveloperError('Kepler equation did not converge');
  52817. // STK Components uses a numerical method to find the eccentric anomaly in the case that Kepler's
  52818. // equation does not converge. We don't expect that to ever be necessary for the reasonable orbits used here.
  52819. }
  52820. eccentricAnomaly = iterationValue + revs * CesiumMath.TWO_PI;
  52821. return eccentricAnomaly;
  52822. }
  52823. // Calculates the true anomaly given the eccentric anomaly and the eccentricity.
  52824. function eccentricAnomalyToTrueAnomaly(eccentricAnomaly, eccentricity) {
  52825. if (eccentricity < 0.0 || eccentricity >= 1.0) {
  52826. throw new DeveloperError('eccentricity out of range.');
  52827. }
  52828. // Calculate the number of previous revolutions
  52829. var revs = Math.floor(eccentricAnomaly / CesiumMath.TWO_PI);
  52830. // Find angle in current revolution
  52831. eccentricAnomaly -= revs * CesiumMath.TWO_PI;
  52832. // Calculate true anomaly from eccentric anomaly
  52833. var trueAnomalyX = Math.cos(eccentricAnomaly) - eccentricity;
  52834. var trueAnomalyY = Math.sin(eccentricAnomaly) * Math.sqrt(1 - eccentricity * eccentricity);
  52835. var trueAnomaly = Math.atan2(trueAnomalyY, trueAnomalyX);
  52836. // Ensure the correct quadrant
  52837. trueAnomaly = CesiumMath.zeroToTwoPi(trueAnomaly);
  52838. if (eccentricAnomaly < 0)
  52839. {
  52840. trueAnomaly -= CesiumMath.TWO_PI;
  52841. }
  52842. // Add on previous revolutions
  52843. trueAnomaly += revs * CesiumMath.TWO_PI;
  52844. return trueAnomaly;
  52845. }
  52846. // Calculates the transformation matrix to convert from the perifocal (PQW) coordinate
  52847. // system to inertial cartesian coordinates.
  52848. function perifocalToCartesianMatrix(argumentOfPeriapsis, inclination, rightAscension, result) {
  52849. if (inclination < 0 || inclination > CesiumMath.PI) {
  52850. throw new DeveloperError('inclination out of range');
  52851. }
  52852. var cosap = Math.cos(argumentOfPeriapsis);
  52853. var sinap = Math.sin(argumentOfPeriapsis);
  52854. var cosi = Math.cos(inclination);
  52855. var sini = Math.sin(inclination);
  52856. var cosraan = Math.cos(rightAscension);
  52857. var sinraan = Math.sin(rightAscension);
  52858. if (!defined(result)) {
  52859. result = new Matrix3(
  52860. cosraan * cosap - sinraan * sinap * cosi,
  52861. -cosraan * sinap - sinraan * cosap * cosi,
  52862. sinraan * sini,
  52863. sinraan * cosap + cosraan * sinap * cosi,
  52864. -sinraan * sinap + cosraan * cosap * cosi,
  52865. -cosraan * sini,
  52866. sinap * sini,
  52867. cosap * sini,
  52868. cosi);
  52869. } else {
  52870. result[0] = cosraan * cosap - sinraan * sinap * cosi;
  52871. result[1] = sinraan * cosap + cosraan * sinap * cosi;
  52872. result[2] = sinap * sini;
  52873. result[3] = -cosraan * sinap - sinraan * cosap * cosi;
  52874. result[4] = -sinraan * sinap + cosraan * cosap * cosi;
  52875. result[5] = cosap * sini;
  52876. result[6] = sinraan * sini;
  52877. result[7] = -cosraan * sini;
  52878. result[8] = cosi;
  52879. }
  52880. return result;
  52881. }
  52882. // From section 5.8
  52883. var semiMajorAxis0 = 1.0000010178 * MetersPerAstronomicalUnit;
  52884. var meanLongitude0 = 100.46645683 * RadiansPerDegree;
  52885. var meanLongitude1 = 1295977422.83429 * RadiansPerArcSecond;
  52886. // From table 6
  52887. var p1u = 16002;
  52888. var p2u = 21863;
  52889. var p3u = 32004;
  52890. var p4u = 10931;
  52891. var p5u = 14529;
  52892. var p6u = 16368;
  52893. var p7u = 15318;
  52894. var p8u = 32794;
  52895. var Ca1 = 64 * 1e-7 * MetersPerAstronomicalUnit;
  52896. var Ca2 = -152 * 1e-7 * MetersPerAstronomicalUnit;
  52897. var Ca3 = 62 * 1e-7 * MetersPerAstronomicalUnit;
  52898. var Ca4 = -8 * 1e-7 * MetersPerAstronomicalUnit;
  52899. var Ca5 = 32 * 1e-7 * MetersPerAstronomicalUnit;
  52900. var Ca6 = -41 * 1e-7 * MetersPerAstronomicalUnit;
  52901. var Ca7 = 19 * 1e-7 * MetersPerAstronomicalUnit;
  52902. var Ca8 = -11 * 1e-7 * MetersPerAstronomicalUnit;
  52903. var Sa1 = -150 * 1e-7 * MetersPerAstronomicalUnit;
  52904. var Sa2 = -46 * 1e-7 * MetersPerAstronomicalUnit;
  52905. var Sa3 = 68 * 1e-7 * MetersPerAstronomicalUnit;
  52906. var Sa4 = 54 * 1e-7 * MetersPerAstronomicalUnit;
  52907. var Sa5 = 14 * 1e-7 * MetersPerAstronomicalUnit;
  52908. var Sa6 = 24 * 1e-7 * MetersPerAstronomicalUnit;
  52909. var Sa7 = -28 * 1e-7 * MetersPerAstronomicalUnit;
  52910. var Sa8 = 22 * 1e-7 * MetersPerAstronomicalUnit;
  52911. var q1u = 10;
  52912. var q2u = 16002;
  52913. var q3u = 21863;
  52914. var q4u = 10931;
  52915. var q5u = 1473;
  52916. var q6u = 32004;
  52917. var q7u = 4387;
  52918. var q8u = 73;
  52919. var Cl1 = -325 * 1e-7;
  52920. var Cl2 = -322 * 1e-7;
  52921. var Cl3 = -79 * 1e-7;
  52922. var Cl4 = 232 * 1e-7;
  52923. var Cl5 = -52 * 1e-7;
  52924. var Cl6 = 97 * 1e-7;
  52925. var Cl7 = 55 * 1e-7;
  52926. var Cl8 = -41 * 1e-7;
  52927. var Sl1 = -105 * 1e-7;
  52928. var Sl2 = -137 * 1e-7;
  52929. var Sl3 = 258 * 1e-7;
  52930. var Sl4 = 35 * 1e-7;
  52931. var Sl5 = -116 * 1e-7;
  52932. var Sl6 = -88 * 1e-7;
  52933. var Sl7 = -112 * 1e-7;
  52934. var Sl8 = -80 * 1e-7;
  52935. var scratchDate = new JulianDate(0, 0.0, TimeStandard.TAI);
  52936. /**
  52937. * Gets a point describing the motion of the Earth-Moon barycenter according to the equations
  52938. * described in section 6.
  52939. */
  52940. function computeSimonEarthMoonBarycenter(date, result) {
  52941. // t is thousands of years from J2000 TDB
  52942. taiToTdb(date, scratchDate);
  52943. var x = (scratchDate.dayNumber - epoch.dayNumber) + ((scratchDate.secondsOfDay - epoch.secondsOfDay)/TimeConstants.SECONDS_PER_DAY);
  52944. var t = x / (TimeConstants.DAYS_PER_JULIAN_CENTURY * 10.0);
  52945. var u = 0.35953620 * t;
  52946. var semimajorAxis = semiMajorAxis0 +
  52947. Ca1 * Math.cos(p1u * u) + Sa1 * Math.sin(p1u * u) +
  52948. Ca2 * Math.cos(p2u * u) + Sa2 * Math.sin(p2u * u) +
  52949. Ca3 * Math.cos(p3u * u) + Sa3 * Math.sin(p3u * u) +
  52950. Ca4 * Math.cos(p4u * u) + Sa4 * Math.sin(p4u * u) +
  52951. Ca5 * Math.cos(p5u * u) + Sa5 * Math.sin(p5u * u) +
  52952. Ca6 * Math.cos(p6u * u) + Sa6 * Math.sin(p6u * u) +
  52953. Ca7 * Math.cos(p7u * u) + Sa7 * Math.sin(p7u * u) +
  52954. Ca8 * Math.cos(p8u * u) + Sa8 * Math.sin(p8u * u);
  52955. var meanLongitude = meanLongitude0 + meanLongitude1 * t +
  52956. Cl1 * Math.cos(q1u * u) + Sl1 * Math.sin(q1u * u) +
  52957. Cl2 * Math.cos(q2u * u) + Sl2 * Math.sin(q2u * u) +
  52958. Cl3 * Math.cos(q3u * u) + Sl3 * Math.sin(q3u * u) +
  52959. Cl4 * Math.cos(q4u * u) + Sl4 * Math.sin(q4u * u) +
  52960. Cl5 * Math.cos(q5u * u) + Sl5 * Math.sin(q5u * u) +
  52961. Cl6 * Math.cos(q6u * u) + Sl6 * Math.sin(q6u * u) +
  52962. Cl7 * Math.cos(q7u * u) + Sl7 * Math.sin(q7u * u) +
  52963. Cl8 * Math.cos(q8u * u) + Sl8 * Math.sin(q8u * u);
  52964. // All constants in this part are from section 5.8
  52965. var eccentricity = 0.0167086342 - 0.0004203654 * t;
  52966. var longitudeOfPerigee = 102.93734808 * RadiansPerDegree + 11612.35290 * RadiansPerArcSecond * t;
  52967. var inclination = 469.97289 * RadiansPerArcSecond * t;
  52968. var longitudeOfNode = 174.87317577 * RadiansPerDegree - 8679.27034 * RadiansPerArcSecond * t;
  52969. return elementsToCartesian(semimajorAxis, eccentricity, inclination, longitudeOfPerigee,
  52970. longitudeOfNode, meanLongitude, result);
  52971. }
  52972. /**
  52973. * Gets a point describing the position of the moon according to the equations described in section 4.
  52974. */
  52975. function computeSimonMoon(date, result) {
  52976. taiToTdb(date, scratchDate);
  52977. var x = (scratchDate.dayNumber - epoch.dayNumber) + ((scratchDate.secondsOfDay - epoch.secondsOfDay)/TimeConstants.SECONDS_PER_DAY);
  52978. var t = x / (TimeConstants.DAYS_PER_JULIAN_CENTURY);
  52979. var t2 = t * t;
  52980. var t3 = t2 * t;
  52981. var t4 = t3 * t;
  52982. // Terms from section 3.4 (b.1)
  52983. var semimajorAxis = 383397.7725 + 0.0040 * t;
  52984. var eccentricity = 0.055545526 - 0.000000016 * t;
  52985. var inclinationConstant = 5.15668983 * RadiansPerDegree;
  52986. var inclinationSecPart = -0.00008 * t + 0.02966 * t2 -
  52987. 0.000042 * t3 - 0.00000013 * t4;
  52988. var longitudeOfPerigeeConstant = 83.35324312 * RadiansPerDegree;
  52989. var longitudeOfPerigeeSecPart = 14643420.2669 * t - 38.2702 * t2 -
  52990. 0.045047 * t3 + 0.00021301 * t4;
  52991. var longitudeOfNodeConstant = 125.04455501 * RadiansPerDegree;
  52992. var longitudeOfNodeSecPart = -6967919.3631 * t + 6.3602 * t2 +
  52993. 0.007625 * t3 - 0.00003586 * t4;
  52994. var meanLongitudeConstant = 218.31664563 * RadiansPerDegree;
  52995. var meanLongitudeSecPart = 1732559343.48470 * t - 6.3910 * t2 +
  52996. 0.006588 * t3 - 0.00003169 * t4;
  52997. // Delaunay arguments from section 3.5 b
  52998. var D = 297.85019547 * RadiansPerDegree + RadiansPerArcSecond *
  52999. (1602961601.2090 * t - 6.3706 * t2 + 0.006593 * t3 - 0.00003169 * t4);
  53000. var F = 93.27209062 * RadiansPerDegree + RadiansPerArcSecond *
  53001. (1739527262.8478 * t - 12.7512 * t2 - 0.001037 * t3 + 0.00000417 * t4);
  53002. var l = 134.96340251 * RadiansPerDegree + RadiansPerArcSecond *
  53003. (1717915923.2178 * t + 31.8792 * t2 + 0.051635 * t3 - 0.00024470 * t4);
  53004. var lprime = 357.52910918 * RadiansPerDegree + RadiansPerArcSecond *
  53005. (129596581.0481 * t - 0.5532 * t2 + 0.000136 * t3 - 0.00001149 * t4);
  53006. var psi = 310.17137918 * RadiansPerDegree - RadiansPerArcSecond *
  53007. (6967051.4360 * t + 6.2068 * t2 + 0.007618 * t3 - 0.00003219 * t4);
  53008. // Add terms from Table 4
  53009. var twoD = 2.0 * D;
  53010. var fourD = 4.0 * D;
  53011. var sixD = 6.0 * D;
  53012. var twol = 2.0 * l;
  53013. var threel = 3.0 * l;
  53014. var fourl = 4.0 * l;
  53015. var twoF = 2.0 * F;
  53016. semimajorAxis += 3400.4 * Math.cos(twoD) - 635.6 * Math.cos(twoD - l) -
  53017. 235.6 * Math.cos(l) + 218.1 * Math.cos(twoD - lprime) +
  53018. 181.0 * Math.cos(twoD + l);
  53019. eccentricity += 0.014216 * Math.cos(twoD - l) + 0.008551 * Math.cos(twoD - twol) -
  53020. 0.001383 * Math.cos(l) + 0.001356 * Math.cos(twoD + l) -
  53021. 0.001147 * Math.cos(fourD - threel) - 0.000914 * Math.cos(fourD - twol) +
  53022. 0.000869 * Math.cos(twoD - lprime - l) - 0.000627 * Math.cos(twoD) -
  53023. 0.000394 * Math.cos(fourD - fourl) + 0.000282 * Math.cos(twoD - lprime - twol) -
  53024. 0.000279 * Math.cos(D - l) - 0.000236 * Math.cos(twol) +
  53025. 0.000231 * Math.cos(fourD) + 0.000229 * Math.cos(sixD - fourl) -
  53026. 0.000201 * Math.cos(twol - twoF);
  53027. inclinationSecPart += 486.26 * Math.cos(twoD - twoF) - 40.13 * Math.cos(twoD) +
  53028. 37.51 * Math.cos(twoF) + 25.73 * Math.cos(twol - twoF) +
  53029. 19.97 * Math.cos(twoD - lprime - twoF);
  53030. longitudeOfPerigeeSecPart += -55609 * Math.sin(twoD - l) - 34711 * Math.sin(twoD - twol) -
  53031. 9792 * Math.sin(l) + 9385 * Math.sin(fourD - threel) +
  53032. 7505 * Math.sin(fourD - twol) + 5318 * Math.sin(twoD + l) +
  53033. 3484 * Math.sin(fourD - fourl) - 3417 * Math.sin(twoD - lprime - l) -
  53034. 2530 * Math.sin(sixD - fourl) - 2376 * Math.sin(twoD) -
  53035. 2075 * Math.sin(twoD - threel) - 1883 * Math.sin(twol) -
  53036. 1736 * Math.sin(sixD - 5.0 * l) + 1626 * Math.sin(lprime) -
  53037. 1370 * Math.sin(sixD - threel);
  53038. longitudeOfNodeSecPart += -5392 * Math.sin(twoD - twoF) - 540 * Math.sin(lprime) -
  53039. 441 * Math.sin(twoD) + 423 * Math.sin(twoF) -
  53040. 288 * Math.sin(twol - twoF);
  53041. meanLongitudeSecPart += -3332.9 * Math.sin(twoD) + 1197.4 * Math.sin(twoD - l) -
  53042. 662.5 * Math.sin(lprime) + 396.3 * Math.sin(l) -
  53043. 218.0 * Math.sin(twoD - lprime);
  53044. // Add terms from Table 5
  53045. var twoPsi = 2.0 * psi;
  53046. var threePsi = 3.0 * psi;
  53047. inclinationSecPart += 46.997 * Math.cos(psi) * t - 0.614 * Math.cos(twoD - twoF + psi) * t +
  53048. 0.614 * Math.cos(twoD - twoF - psi) * t - 0.0297 * Math.cos(twoPsi) * t2 -
  53049. 0.0335 * Math.cos(psi) * t2 + 0.0012 * Math.cos(twoD - twoF + twoPsi) * t2 -
  53050. 0.00016 * Math.cos(psi) * t3 + 0.00004 * Math.cos(threePsi) * t3 +
  53051. 0.00004 * Math.cos(twoPsi) * t3;
  53052. var perigeeAndMean = 2.116 * Math.sin(psi) * t - 0.111 * Math.sin(twoD - twoF - psi) * t -
  53053. 0.0015 * Math.sin(psi) * t2;
  53054. longitudeOfPerigeeSecPart += perigeeAndMean;
  53055. meanLongitudeSecPart += perigeeAndMean;
  53056. longitudeOfNodeSecPart += -520.77 * Math.sin(psi) * t + 13.66 * Math.sin(twoD - twoF + psi) * t +
  53057. 1.12 * Math.sin(twoD - psi) * t - 1.06 * Math.sin(twoF - psi) * t +
  53058. 0.660 * Math.sin(twoPsi) * t2 + 0.371 * Math.sin(psi) * t2 -
  53059. 0.035 * Math.sin(twoD - twoF + twoPsi) * t2 - 0.015 * Math.sin(twoD - twoF + psi) * t2 +
  53060. 0.0014 * Math.sin(psi) * t3 - 0.0011 * Math.sin(threePsi) * t3 -
  53061. 0.0009 * Math.sin(twoPsi) * t3;
  53062. // Add constants and convert units
  53063. semimajorAxis *= MetersPerKilometer;
  53064. var inclination = inclinationConstant + inclinationSecPart * RadiansPerArcSecond;
  53065. var longitudeOfPerigee = longitudeOfPerigeeConstant + longitudeOfPerigeeSecPart * RadiansPerArcSecond;
  53066. var meanLongitude = meanLongitudeConstant + meanLongitudeSecPart * RadiansPerArcSecond;
  53067. var longitudeOfNode = longitudeOfNodeConstant + longitudeOfNodeSecPart * RadiansPerArcSecond;
  53068. return elementsToCartesian(semimajorAxis, eccentricity, inclination, longitudeOfPerigee,
  53069. longitudeOfNode, meanLongitude, result);
  53070. }
  53071. /**
  53072. * Gets a point describing the motion of the Earth. This point uses the Moon point and
  53073. * the 1992 mu value (ratio between Moon and Earth masses) in Table 2 of the paper in order
  53074. * to determine the position of the Earth relative to the Earth-Moon barycenter.
  53075. */
  53076. var moonEarthMassRatio = 0.012300034; // From 1992 mu value in Table 2
  53077. var factor = moonEarthMassRatio / (moonEarthMassRatio + 1.0) * -1;
  53078. function computeSimonEarth(date, result) {
  53079. result = computeSimonMoon(date, result);
  53080. return Cartesian3.multiplyByScalar(result, factor, result);
  53081. }
  53082. // Values for the <code>axesTransformation</code> needed for the rotation were found using the STK Components
  53083. // GreographicTransformer on the position of the sun center of mass point and the earth J2000 frame.
  53084. var axesTransformation = new Matrix3(1.0000000000000002, 5.619723173785822e-16, 4.690511510146299e-19,
  53085. -5.154129427414611e-16, 0.9174820620691819, -0.39777715593191376,
  53086. -2.23970096136568e-16, 0.39777715593191376, 0.9174820620691819);
  53087. var translation = new Cartesian3();
  53088. /**
  53089. * Computes the position of the Sun in the Earth-centered inertial frame
  53090. *
  53091. * @param {JulianDate} [julianDate] The time at which to compute the Sun's position, if not provided the current system time is used.
  53092. * @param {Cartesian3} [result] The object onto which to store the result.
  53093. * @returns {Cartesian3} Calculated sun position
  53094. */
  53095. Simon1994PlanetaryPositions.computeSunPositionInEarthInertialFrame= function(date, result){
  53096. if (!defined(date)) {
  53097. date = JulianDate.now();
  53098. }
  53099. if (!defined(result)) {
  53100. result = new Cartesian3();
  53101. }
  53102. //first forward transformation
  53103. translation = computeSimonEarthMoonBarycenter(date, translation);
  53104. result = Cartesian3.negate(translation, result);
  53105. //second forward transformation
  53106. computeSimonEarth(date, translation);
  53107. Cartesian3.subtract(result, translation, result);
  53108. Matrix3.multiplyByVector(axesTransformation, result, result);
  53109. return result;
  53110. };
  53111. /**
  53112. * Computes the position of the Moon in the Earth-centered inertial frame
  53113. *
  53114. * @param {JulianDate} [julianDate] The time at which to compute the Sun's position, if not provided the current system time is used.
  53115. * @param {Cartesian3} [result] The object onto which to store the result.
  53116. * @returns {Cartesian3} Calculated moon position
  53117. */
  53118. Simon1994PlanetaryPositions.computeMoonPositionInEarthInertialFrame = function(date, result){
  53119. if (!defined(date)) {
  53120. date = JulianDate.now();
  53121. }
  53122. result = computeSimonMoon(date, result);
  53123. Matrix3.multiplyByVector(axesTransformation, result, result);
  53124. return result;
  53125. };
  53126. return Simon1994PlanetaryPositions;
  53127. });
  53128. /*global define*/
  53129. define('Core/SimplePolylineGeometry',[
  53130. './BoundingSphere',
  53131. './Cartesian3',
  53132. './Color',
  53133. './ComponentDatatype',
  53134. './defaultValue',
  53135. './defined',
  53136. './DeveloperError',
  53137. './Ellipsoid',
  53138. './Geometry',
  53139. './GeometryAttribute',
  53140. './GeometryAttributes',
  53141. './IndexDatatype',
  53142. './Math',
  53143. './PolylinePipeline',
  53144. './PrimitiveType'
  53145. ], function(
  53146. BoundingSphere,
  53147. Cartesian3,
  53148. Color,
  53149. ComponentDatatype,
  53150. defaultValue,
  53151. defined,
  53152. DeveloperError,
  53153. Ellipsoid,
  53154. Geometry,
  53155. GeometryAttribute,
  53156. GeometryAttributes,
  53157. IndexDatatype,
  53158. CesiumMath,
  53159. PolylinePipeline,
  53160. PrimitiveType) {
  53161. 'use strict';
  53162. function interpolateColors(p0, p1, color0, color1, minDistance, array, offset) {
  53163. var numPoints = PolylinePipeline.numberOfPoints(p0, p1, minDistance);
  53164. var i;
  53165. var r0 = color0.red;
  53166. var g0 = color0.green;
  53167. var b0 = color0.blue;
  53168. var a0 = color0.alpha;
  53169. var r1 = color1.red;
  53170. var g1 = color1.green;
  53171. var b1 = color1.blue;
  53172. var a1 = color1.alpha;
  53173. if (Color.equals(color0, color1)) {
  53174. for (i = 0; i < numPoints; i++) {
  53175. array[offset++] = Color.floatToByte(r0);
  53176. array[offset++] = Color.floatToByte(g0);
  53177. array[offset++] = Color.floatToByte(b0);
  53178. array[offset++] = Color.floatToByte(a0);
  53179. }
  53180. return offset;
  53181. }
  53182. var redPerVertex = (r1 - r0) / numPoints;
  53183. var greenPerVertex = (g1 - g0) / numPoints;
  53184. var bluePerVertex = (b1 - b0) / numPoints;
  53185. var alphaPerVertex = (a1 - a0) / numPoints;
  53186. var index = offset;
  53187. for (i = 0; i < numPoints; i++) {
  53188. array[index++] = Color.floatToByte(r0 + i * redPerVertex);
  53189. array[index++] = Color.floatToByte(g0 + i * greenPerVertex);
  53190. array[index++] = Color.floatToByte(b0 + i * bluePerVertex);
  53191. array[index++] = Color.floatToByte(a0 + i * alphaPerVertex);
  53192. }
  53193. return index;
  53194. }
  53195. /**
  53196. * A description of a polyline modeled as a line strip; the first two positions define a line segment,
  53197. * and each additional position defines a line segment from the previous position.
  53198. *
  53199. * @alias SimplePolylineGeometry
  53200. * @constructor
  53201. *
  53202. * @param {Object} options Object with the following properties:
  53203. * @param {Cartesian3[]} options.positions An array of {@link Cartesian3} defining the positions in the polyline as a line strip.
  53204. * @param {Color[]} [options.colors] An Array of {@link Color} defining the per vertex or per segment colors.
  53205. * @param {Boolean} [options.colorsPerVertex=false] A boolean that determines whether the colors will be flat across each segment of the line or interpolated across the vertices.
  53206. * @param {Boolean} [options.followSurface=true] A boolean that determines whether positions will be adjusted to the surface of the ellipsoid via a great arc.
  53207. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude if options.followSurface=true. Determines the number of positions in the buffer.
  53208. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
  53209. *
  53210. * @exception {DeveloperError} At least two positions are required.
  53211. * @exception {DeveloperError} colors has an invalid length.
  53212. *
  53213. * @see SimplePolylineGeometry#createGeometry
  53214. *
  53215. * @example
  53216. * // A polyline with two connected line segments
  53217. * var polyline = new Cesium.SimplePolylineGeometry({
  53218. * positions : Cesium.Cartesian3.fromDegreesArray([
  53219. * 0.0, 0.0,
  53220. * 5.0, 0.0,
  53221. * 5.0, 5.0
  53222. * ])
  53223. * });
  53224. * var geometry = Cesium.SimplePolylineGeometry.createGeometry(polyline);
  53225. */
  53226. function SimplePolylineGeometry(options) {
  53227. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  53228. var positions = options.positions;
  53229. var colors = options.colors;
  53230. var colorsPerVertex = defaultValue(options.colorsPerVertex, false);
  53231. if ((!defined(positions)) || (positions.length < 2)) {
  53232. throw new DeveloperError('At least two positions are required.');
  53233. }
  53234. if (defined(colors) && ((colorsPerVertex && colors.length < positions.length) || (!colorsPerVertex && colors.length < positions.length - 1))) {
  53235. throw new DeveloperError('colors has an invalid length.');
  53236. }
  53237. this._positions = positions;
  53238. this._colors = colors;
  53239. this._colorsPerVertex = colorsPerVertex;
  53240. this._followSurface = defaultValue(options.followSurface, true);
  53241. this._granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  53242. this._ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  53243. this._workerName = 'createSimplePolylineGeometry';
  53244. var numComponents = 1 + positions.length * Cartesian3.packedLength;
  53245. numComponents += defined(colors) ? 1 + colors.length * Color.packedLength : 1;
  53246. /**
  53247. * The number of elements used to pack the object into an array.
  53248. * @type {Number}
  53249. */
  53250. this.packedLength = numComponents + Ellipsoid.packedLength + 3;
  53251. }
  53252. /**
  53253. * Stores the provided instance into the provided array.
  53254. *
  53255. * @param {SimplePolylineGeometry} value The value to pack.
  53256. * @param {Number[]} array The array to pack into.
  53257. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  53258. *
  53259. * @returns {Number[]} The array that was packed into
  53260. */
  53261. SimplePolylineGeometry.pack = function(value, array, startingIndex) {
  53262. if (!defined(value)) {
  53263. throw new DeveloperError('value is required');
  53264. }
  53265. if (!defined(array)) {
  53266. throw new DeveloperError('array is required');
  53267. }
  53268. startingIndex = defaultValue(startingIndex, 0);
  53269. var i;
  53270. var positions = value._positions;
  53271. var length = positions.length;
  53272. array[startingIndex++] = length;
  53273. for (i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  53274. Cartesian3.pack(positions[i], array, startingIndex);
  53275. }
  53276. var colors = value._colors;
  53277. length = defined(colors) ? colors.length : 0.0;
  53278. array[startingIndex++] = length;
  53279. for (i = 0; i < length; ++i, startingIndex += Color.packedLength) {
  53280. Color.pack(colors[i], array, startingIndex);
  53281. }
  53282. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  53283. startingIndex += Ellipsoid.packedLength;
  53284. array[startingIndex++] = value._colorsPerVertex ? 1.0 : 0.0;
  53285. array[startingIndex++] = value._followSurface ? 1.0 : 0.0;
  53286. array[startingIndex] = value._granularity;
  53287. return array;
  53288. };
  53289. /**
  53290. * Retrieves an instance from a packed array.
  53291. *
  53292. * @param {Number[]} array The packed array.
  53293. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  53294. * @param {SimplePolylineGeometry} [result] The object into which to store the result.
  53295. * @returns {SimplePolylineGeometry} The modified result parameter or a new SimplePolylineGeometry instance if one was not provided.
  53296. */
  53297. SimplePolylineGeometry.unpack = function(array, startingIndex, result) {
  53298. if (!defined(array)) {
  53299. throw new DeveloperError('array is required');
  53300. }
  53301. startingIndex = defaultValue(startingIndex, 0);
  53302. var i;
  53303. var length = array[startingIndex++];
  53304. var positions = new Array(length);
  53305. for (i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  53306. positions[i] = Cartesian3.unpack(array, startingIndex);
  53307. }
  53308. length = array[startingIndex++];
  53309. var colors = length > 0 ? new Array(length) : undefined;
  53310. for (i = 0; i < length; ++i, startingIndex += Color.packedLength) {
  53311. colors[i] = Color.unpack(array, startingIndex);
  53312. }
  53313. var ellipsoid = Ellipsoid.unpack(array, startingIndex);
  53314. startingIndex += Ellipsoid.packedLength;
  53315. var colorsPerVertex = array[startingIndex++] === 1.0;
  53316. var followSurface = array[startingIndex++] === 1.0;
  53317. var granularity = array[startingIndex];
  53318. if (!defined(result)) {
  53319. return new SimplePolylineGeometry({
  53320. positions : positions,
  53321. colors : colors,
  53322. ellipsoid : ellipsoid,
  53323. colorsPerVertex : colorsPerVertex,
  53324. followSurface : followSurface,
  53325. granularity : granularity
  53326. });
  53327. }
  53328. result._positions = positions;
  53329. result._colors = colors;
  53330. result._ellipsoid = ellipsoid;
  53331. result._colorsPerVertex = colorsPerVertex;
  53332. result._followSurface = followSurface;
  53333. result._granularity = granularity;
  53334. return result;
  53335. };
  53336. var scratchArray1 = new Array(2);
  53337. var scratchArray2 = new Array(2);
  53338. var generateArcOptionsScratch = {
  53339. positions : scratchArray1,
  53340. height: scratchArray2,
  53341. ellipsoid: undefined,
  53342. minDistance : undefined
  53343. };
  53344. /**
  53345. * Computes the geometric representation of a simple polyline, including its vertices, indices, and a bounding sphere.
  53346. *
  53347. * @param {SimplePolylineGeometry} simplePolylineGeometry A description of the polyline.
  53348. * @returns {Geometry} The computed vertices and indices.
  53349. */
  53350. SimplePolylineGeometry.createGeometry = function(simplePolylineGeometry) {
  53351. var positions = simplePolylineGeometry._positions;
  53352. var colors = simplePolylineGeometry._colors;
  53353. var colorsPerVertex = simplePolylineGeometry._colorsPerVertex;
  53354. var followSurface = simplePolylineGeometry._followSurface;
  53355. var granularity = simplePolylineGeometry._granularity;
  53356. var ellipsoid = simplePolylineGeometry._ellipsoid;
  53357. var minDistance = CesiumMath.chordLength(granularity, ellipsoid.maximumRadius);
  53358. var perSegmentColors = defined(colors) && !colorsPerVertex;
  53359. var i;
  53360. var length = positions.length;
  53361. var positionValues;
  53362. var numberOfPositions;
  53363. var colorValues;
  53364. var color;
  53365. var offset = 0;
  53366. if (followSurface) {
  53367. var heights = PolylinePipeline.extractHeights(positions, ellipsoid);
  53368. var generateArcOptions = generateArcOptionsScratch;
  53369. generateArcOptions.minDistance = minDistance;
  53370. generateArcOptions.ellipsoid = ellipsoid;
  53371. if (perSegmentColors) {
  53372. var positionCount = 0;
  53373. for (i = 0; i < length - 1; i++) {
  53374. positionCount += PolylinePipeline.numberOfPoints(positions[i], positions[i+1], minDistance) + 1;
  53375. }
  53376. positionValues = new Float64Array(positionCount * 3);
  53377. colorValues = new Uint8Array(positionCount * 4);
  53378. generateArcOptions.positions = scratchArray1;
  53379. generateArcOptions.height= scratchArray2;
  53380. var ci = 0;
  53381. for (i = 0; i < length - 1; ++i) {
  53382. scratchArray1[0] = positions[i];
  53383. scratchArray1[1] = positions[i + 1];
  53384. scratchArray2[0] = heights[i];
  53385. scratchArray2[1] = heights[i + 1];
  53386. var pos = PolylinePipeline.generateArc(generateArcOptions);
  53387. if (defined(colors)) {
  53388. var segLen = pos.length / 3;
  53389. color = colors[i];
  53390. for(var k = 0; k < segLen; ++k) {
  53391. colorValues[ci++] = Color.floatToByte(color.red);
  53392. colorValues[ci++] = Color.floatToByte(color.green);
  53393. colorValues[ci++] = Color.floatToByte(color.blue);
  53394. colorValues[ci++] = Color.floatToByte(color.alpha);
  53395. }
  53396. }
  53397. positionValues.set(pos, offset);
  53398. offset += pos.length;
  53399. }
  53400. } else {
  53401. generateArcOptions.positions = positions;
  53402. generateArcOptions.height= heights;
  53403. positionValues = new Float64Array(PolylinePipeline.generateArc(generateArcOptions));
  53404. if (defined(colors)) {
  53405. colorValues = new Uint8Array(positionValues.length / 3 * 4);
  53406. for (i = 0; i < length - 1; ++i) {
  53407. var p0 = positions[i];
  53408. var p1 = positions[i + 1];
  53409. var c0 = colors[i];
  53410. var c1 = colors[i + 1];
  53411. offset = interpolateColors(p0, p1, c0, c1, minDistance, colorValues, offset);
  53412. }
  53413. var lastColor = colors[length - 1];
  53414. colorValues[offset++] = Color.floatToByte(lastColor.red);
  53415. colorValues[offset++] = Color.floatToByte(lastColor.green);
  53416. colorValues[offset++] = Color.floatToByte(lastColor.blue);
  53417. colorValues[offset++] = Color.floatToByte(lastColor.alpha);
  53418. }
  53419. }
  53420. } else {
  53421. numberOfPositions = perSegmentColors ? length * 2 - 2 : length;
  53422. positionValues = new Float64Array(numberOfPositions * 3);
  53423. colorValues = defined(colors) ? new Uint8Array(numberOfPositions * 4) : undefined;
  53424. var positionIndex = 0;
  53425. var colorIndex = 0;
  53426. for (i = 0; i < length; ++i) {
  53427. var p = positions[i];
  53428. if (perSegmentColors && i > 0) {
  53429. Cartesian3.pack(p, positionValues, positionIndex);
  53430. positionIndex += 3;
  53431. color = colors[i - 1];
  53432. colorValues[colorIndex++] = Color.floatToByte(color.red);
  53433. colorValues[colorIndex++] = Color.floatToByte(color.green);
  53434. colorValues[colorIndex++] = Color.floatToByte(color.blue);
  53435. colorValues[colorIndex++] = Color.floatToByte(color.alpha);
  53436. }
  53437. if (perSegmentColors && i === length - 1) {
  53438. break;
  53439. }
  53440. Cartesian3.pack(p, positionValues, positionIndex);
  53441. positionIndex += 3;
  53442. if (defined(colors)) {
  53443. color = colors[i];
  53444. colorValues[colorIndex++] = Color.floatToByte(color.red);
  53445. colorValues[colorIndex++] = Color.floatToByte(color.green);
  53446. colorValues[colorIndex++] = Color.floatToByte(color.blue);
  53447. colorValues[colorIndex++] = Color.floatToByte(color.alpha);
  53448. }
  53449. }
  53450. }
  53451. var attributes = new GeometryAttributes();
  53452. attributes.position = new GeometryAttribute({
  53453. componentDatatype : ComponentDatatype.DOUBLE,
  53454. componentsPerAttribute : 3,
  53455. values : positionValues
  53456. });
  53457. if (defined(colors)) {
  53458. attributes.color = new GeometryAttribute({
  53459. componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
  53460. componentsPerAttribute : 4,
  53461. values : colorValues,
  53462. normalize : true
  53463. });
  53464. }
  53465. numberOfPositions = positionValues.length / 3;
  53466. var numberOfIndices = (numberOfPositions - 1) * 2;
  53467. var indices = IndexDatatype.createTypedArray(numberOfPositions, numberOfIndices);
  53468. var index = 0;
  53469. for (i = 0; i < numberOfPositions - 1; ++i) {
  53470. indices[index++] = i;
  53471. indices[index++] = i + 1;
  53472. }
  53473. return new Geometry({
  53474. attributes : attributes,
  53475. indices : indices,
  53476. primitiveType : PrimitiveType.LINES,
  53477. boundingSphere : BoundingSphere.fromPoints(positions)
  53478. });
  53479. };
  53480. return SimplePolylineGeometry;
  53481. });
  53482. /*global define*/
  53483. define('Core/SphereGeometry',[
  53484. './Cartesian3',
  53485. './defaultValue',
  53486. './defined',
  53487. './DeveloperError',
  53488. './EllipsoidGeometry',
  53489. './VertexFormat'
  53490. ], function(
  53491. Cartesian3,
  53492. defaultValue,
  53493. defined,
  53494. DeveloperError,
  53495. EllipsoidGeometry,
  53496. VertexFormat) {
  53497. 'use strict';
  53498. /**
  53499. * A description of a sphere centered at the origin.
  53500. *
  53501. * @alias SphereGeometry
  53502. * @constructor
  53503. *
  53504. * @param {Object} [options] Object with the following properties:
  53505. * @param {Number} [options.radius=1.0] The radius of the sphere.
  53506. * @param {Number} [options.stackPartitions=64] The number of times to partition the ellipsoid into stacks.
  53507. * @param {Number} [options.slicePartitions=64] The number of times to partition the ellipsoid into radial slices.
  53508. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  53509. *
  53510. * @exception {DeveloperError} options.slicePartitions cannot be less than three.
  53511. * @exception {DeveloperError} options.stackPartitions cannot be less than three.
  53512. *
  53513. * @see SphereGeometry#createGeometry
  53514. *
  53515. * @example
  53516. * var sphere = new Cesium.SphereGeometry({
  53517. * radius : 100.0,
  53518. * vertexFormat : Cesium.VertexFormat.POSITION_ONLY
  53519. * });
  53520. * var geometry = Cesium.SphereGeometry.createGeometry(sphere);
  53521. */
  53522. function SphereGeometry(options) {
  53523. var radius = defaultValue(options.radius, 1.0);
  53524. var radii = new Cartesian3(radius, radius, radius);
  53525. var ellipsoidOptions = {
  53526. radii: radii,
  53527. stackPartitions: options.stackPartitions,
  53528. slicePartitions: options.slicePartitions,
  53529. vertexFormat: options.vertexFormat
  53530. };
  53531. this._ellipsoidGeometry = new EllipsoidGeometry(ellipsoidOptions);
  53532. this._workerName = 'createSphereGeometry';
  53533. }
  53534. /**
  53535. * The number of elements used to pack the object into an array.
  53536. * @type {Number}
  53537. */
  53538. SphereGeometry.packedLength = EllipsoidGeometry.packedLength;
  53539. /**
  53540. * Stores the provided instance into the provided array.
  53541. *
  53542. * @param {SphereGeometry} value The value to pack.
  53543. * @param {Number[]} array The array to pack into.
  53544. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  53545. *
  53546. * @returns {Number[]} The array that was packed into
  53547. */
  53548. SphereGeometry.pack = function(value, array, startingIndex) {
  53549. if (!defined(value)) {
  53550. throw new DeveloperError('value is required');
  53551. }
  53552. return EllipsoidGeometry.pack(value._ellipsoidGeometry, array, startingIndex);
  53553. };
  53554. var scratchEllipsoidGeometry = new EllipsoidGeometry();
  53555. var scratchOptions = {
  53556. radius : undefined,
  53557. radii : new Cartesian3(),
  53558. vertexFormat : new VertexFormat(),
  53559. stackPartitions : undefined,
  53560. slicePartitions : undefined
  53561. };
  53562. /**
  53563. * Retrieves an instance from a packed array.
  53564. *
  53565. * @param {Number[]} array The packed array.
  53566. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  53567. * @param {SphereGeometry} [result] The object into which to store the result.
  53568. * @returns {SphereGeometry} The modified result parameter or a new SphereGeometry instance if one was not provided.
  53569. */
  53570. SphereGeometry.unpack = function(array, startingIndex, result) {
  53571. var ellipsoidGeometry = EllipsoidGeometry.unpack(array, startingIndex, scratchEllipsoidGeometry);
  53572. scratchOptions.vertexFormat = VertexFormat.clone(ellipsoidGeometry._vertexFormat, scratchOptions.vertexFormat);
  53573. scratchOptions.stackPartitions = ellipsoidGeometry._stackPartitions;
  53574. scratchOptions.slicePartitions = ellipsoidGeometry._slicePartitions;
  53575. if (!defined(result)) {
  53576. scratchOptions.radius = ellipsoidGeometry._radii.x;
  53577. return new SphereGeometry(scratchOptions);
  53578. }
  53579. Cartesian3.clone(ellipsoidGeometry._radii, scratchOptions.radii);
  53580. result._ellipsoidGeometry = new EllipsoidGeometry(scratchOptions);
  53581. return result;
  53582. };
  53583. /**
  53584. * Computes the geometric representation of a sphere, including its vertices, indices, and a bounding sphere.
  53585. *
  53586. * @param {SphereGeometry} sphereGeometry A description of the sphere.
  53587. * @returns {Geometry} The computed vertices and indices.
  53588. */
  53589. SphereGeometry.createGeometry = function(sphereGeometry) {
  53590. return EllipsoidGeometry.createGeometry(sphereGeometry._ellipsoidGeometry);
  53591. };
  53592. return SphereGeometry;
  53593. });
  53594. /*global define*/
  53595. define('Core/SphereOutlineGeometry',[
  53596. './Cartesian3',
  53597. './defaultValue',
  53598. './defined',
  53599. './DeveloperError',
  53600. './EllipsoidOutlineGeometry'
  53601. ], function(
  53602. Cartesian3,
  53603. defaultValue,
  53604. defined,
  53605. DeveloperError,
  53606. EllipsoidOutlineGeometry) {
  53607. 'use strict';
  53608. /**
  53609. * A description of the outline of a sphere.
  53610. *
  53611. * @alias SphereOutlineGeometry
  53612. * @constructor
  53613. *
  53614. * @param {Object} [options] Object with the following properties:
  53615. * @param {Number} [options.radius=1.0] The radius of the sphere.
  53616. * @param {Number} [options.stackPartitions=10] The count of stacks for the sphere (1 greater than the number of parallel lines).
  53617. * @param {Number} [options.slicePartitions=8] The count of slices for the sphere (Equal to the number of radial lines).
  53618. * @param {Number} [options.subdivisions=200] The number of points per line, determining the granularity of the curvature .
  53619. *
  53620. * @exception {DeveloperError} options.stackPartitions must be greater than or equal to one.
  53621. * @exception {DeveloperError} options.slicePartitions must be greater than or equal to zero.
  53622. * @exception {DeveloperError} options.subdivisions must be greater than or equal to zero.
  53623. *
  53624. * @example
  53625. * var sphere = new Cesium.SphereOutlineGeometry({
  53626. * radius : 100.0,
  53627. * stackPartitions : 6,
  53628. * slicePartitions: 5
  53629. * });
  53630. * var geometry = Cesium.SphereOutlineGeometry.createGeometry(sphere);
  53631. */
  53632. function SphereOutlineGeometry(options) {
  53633. var radius = defaultValue(options.radius, 1.0);
  53634. var radii = new Cartesian3(radius, radius, radius);
  53635. var ellipsoidOptions = {
  53636. radii: radii,
  53637. stackPartitions: options.stackPartitions,
  53638. slicePartitions: options.slicePartitions,
  53639. subdivisions: options.subdivisions
  53640. };
  53641. this._ellipsoidGeometry = new EllipsoidOutlineGeometry(ellipsoidOptions);
  53642. this._workerName = 'createSphereOutlineGeometry';
  53643. }
  53644. /**
  53645. * The number of elements used to pack the object into an array.
  53646. * @type {Number}
  53647. */
  53648. SphereOutlineGeometry.packedLength = EllipsoidOutlineGeometry.packedLength;
  53649. /**
  53650. * Stores the provided instance into the provided array.
  53651. *
  53652. * @param {SphereOutlineGeometry} value The value to pack.
  53653. * @param {Number[]} array The array to pack into.
  53654. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  53655. *
  53656. * @returns {Number[]} The array that was packed into
  53657. */
  53658. SphereOutlineGeometry.pack = function(value, array, startingIndex) {
  53659. if (!defined(value)) {
  53660. throw new DeveloperError('value is required');
  53661. }
  53662. return EllipsoidOutlineGeometry.pack(value._ellipsoidGeometry, array, startingIndex);
  53663. };
  53664. var scratchEllipsoidGeometry = new EllipsoidOutlineGeometry();
  53665. var scratchOptions = {
  53666. radius : undefined,
  53667. radii : new Cartesian3(),
  53668. stackPartitions : undefined,
  53669. slicePartitions : undefined,
  53670. subdivisions : undefined
  53671. };
  53672. /**
  53673. * Retrieves an instance from a packed array.
  53674. *
  53675. * @param {Number[]} array The packed array.
  53676. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  53677. * @param {SphereOutlineGeometry} [result] The object into which to store the result.
  53678. * @returns {SphereOutlineGeometry} The modified result parameter or a new SphereOutlineGeometry instance if one was not provided.
  53679. */
  53680. SphereOutlineGeometry.unpack = function(array, startingIndex, result) {
  53681. var ellipsoidGeometry = EllipsoidOutlineGeometry.unpack(array, startingIndex, scratchEllipsoidGeometry);
  53682. scratchOptions.stackPartitions = ellipsoidGeometry._stackPartitions;
  53683. scratchOptions.slicePartitions = ellipsoidGeometry._slicePartitions;
  53684. scratchOptions.subdivisions = ellipsoidGeometry._subdivisions;
  53685. if (!defined(result)) {
  53686. scratchOptions.radius = ellipsoidGeometry._radii.x;
  53687. return new SphereOutlineGeometry(scratchOptions);
  53688. }
  53689. Cartesian3.clone(ellipsoidGeometry._radii, scratchOptions.radii);
  53690. result._ellipsoidGeometry = new EllipsoidOutlineGeometry(scratchOptions);
  53691. return result;
  53692. };
  53693. /**
  53694. * Computes the geometric representation of an outline of a sphere, including its vertices, indices, and a bounding sphere.
  53695. *
  53696. * @param {SphereOutlineGeometry} sphereGeometry A description of the sphere outline.
  53697. * @returns {Geometry} The computed vertices and indices.
  53698. */
  53699. SphereOutlineGeometry.createGeometry = function(sphereGeometry) {
  53700. return EllipsoidOutlineGeometry.createGeometry(sphereGeometry._ellipsoidGeometry);
  53701. };
  53702. return SphereOutlineGeometry;
  53703. });
  53704. /*global define*/
  53705. define('Core/Spherical',[
  53706. './defaultValue',
  53707. './defined',
  53708. './DeveloperError'
  53709. ], function(
  53710. defaultValue,
  53711. defined,
  53712. DeveloperError) {
  53713. 'use strict';
  53714. /**
  53715. * A set of curvilinear 3-dimensional coordinates.
  53716. *
  53717. * @alias Spherical
  53718. * @constructor
  53719. *
  53720. * @param {Number} [clock=0.0] The angular coordinate lying in the xy-plane measured from the positive x-axis and toward the positive y-axis.
  53721. * @param {Number} [cone=0.0] The angular coordinate measured from the positive z-axis and toward the negative z-axis.
  53722. * @param {Number} [magnitude=1.0] The linear coordinate measured from the origin.
  53723. */
  53724. function Spherical(clock, cone, magnitude) {
  53725. this.clock = defaultValue(clock, 0.0);
  53726. this.cone = defaultValue(cone, 0.0);
  53727. this.magnitude = defaultValue(magnitude, 1.0);
  53728. }
  53729. /**
  53730. * Converts the provided Cartesian3 into Spherical coordinates.
  53731. *
  53732. * @param {Cartesian3} cartesian3 The Cartesian3 to be converted to Spherical.
  53733. * @param {Spherical} [spherical] The object in which the result will be stored, if undefined a new instance will be created.
  53734. * @returns {Spherical} The modified result parameter, or a new instance if one was not provided.
  53735. */
  53736. Spherical.fromCartesian3 = function(cartesian3, result) {
  53737. if (!defined(cartesian3)) {
  53738. throw new DeveloperError('cartesian3 is required');
  53739. }
  53740. var x = cartesian3.x;
  53741. var y = cartesian3.y;
  53742. var z = cartesian3.z;
  53743. var radialSquared = x * x + y * y;
  53744. if (!defined(result)) {
  53745. result = new Spherical();
  53746. }
  53747. result.clock = Math.atan2(y, x);
  53748. result.cone = Math.atan2(Math.sqrt(radialSquared), z);
  53749. result.magnitude = Math.sqrt(radialSquared + z * z);
  53750. return result;
  53751. };
  53752. /**
  53753. * Creates a duplicate of a Spherical.
  53754. *
  53755. * @param {Spherical} spherical The spherical to clone.
  53756. * @param {Spherical} [result] The object to store the result into, if undefined a new instance will be created.
  53757. * @returns {Spherical} The modified result parameter or a new instance if result was undefined. (Returns undefined if spherical is undefined)
  53758. */
  53759. Spherical.clone = function(spherical, result) {
  53760. if (!defined(spherical)) {
  53761. return undefined;
  53762. }
  53763. if (!defined(result)) {
  53764. return new Spherical(spherical.clock, spherical.cone, spherical.magnitude);
  53765. }
  53766. result.clock = spherical.clock;
  53767. result.cone = spherical.cone;
  53768. result.magnitude = spherical.magnitude;
  53769. return result;
  53770. };
  53771. /**
  53772. * Computes the normalized version of the provided spherical.
  53773. *
  53774. * @param {Spherical} spherical The spherical to be normalized.
  53775. * @param {Spherical} [result] The object to store the result into, if undefined a new instance will be created.
  53776. * @returns {Spherical} The modified result parameter or a new instance if result was undefined.
  53777. */
  53778. Spherical.normalize = function(spherical, result) {
  53779. if (!defined(spherical)) {
  53780. throw new DeveloperError('spherical is required');
  53781. }
  53782. if (!defined(result)) {
  53783. return new Spherical(spherical.clock, spherical.cone, 1.0);
  53784. }
  53785. result.clock = spherical.clock;
  53786. result.cone = spherical.cone;
  53787. result.magnitude = 1.0;
  53788. return result;
  53789. };
  53790. /**
  53791. * Returns true if the first spherical is equal to the second spherical, false otherwise.
  53792. *
  53793. * @param {Spherical} left The first Spherical to be compared.
  53794. * @param {Spherical} right The second Spherical to be compared.
  53795. * @returns {Boolean} true if the first spherical is equal to the second spherical, false otherwise.
  53796. */
  53797. Spherical.equals = function(left, right) {
  53798. return (left === right) ||
  53799. ((defined(left)) &&
  53800. (defined(right)) &&
  53801. (left.clock === right.clock) &&
  53802. (left.cone === right.cone) &&
  53803. (left.magnitude === right.magnitude));
  53804. };
  53805. /**
  53806. * Returns true if the first spherical is within the provided epsilon of the second spherical, false otherwise.
  53807. *
  53808. * @param {Spherical} left The first Spherical to be compared.
  53809. * @param {Spherical} right The second Spherical to be compared.
  53810. * @param {Number} [epsilon=0.0] The epsilon to compare against.
  53811. * @returns {Boolean} true if the first spherical is within the provided epsilon of the second spherical, false otherwise.
  53812. */
  53813. Spherical.equalsEpsilon = function(left, right, epsilon) {
  53814. epsilon = defaultValue(epsilon, 0.0);
  53815. return (left === right) ||
  53816. ((defined(left)) &&
  53817. (defined(right)) &&
  53818. (Math.abs(left.clock - right.clock) <= epsilon) &&
  53819. (Math.abs(left.cone - right.cone) <= epsilon) &&
  53820. (Math.abs(left.magnitude - right.magnitude) <= epsilon));
  53821. };
  53822. /**
  53823. * Returns true if this spherical is equal to the provided spherical, false otherwise.
  53824. *
  53825. * @param {Spherical} other The Spherical to be compared.
  53826. * @returns {Boolean} true if this spherical is equal to the provided spherical, false otherwise.
  53827. */
  53828. Spherical.prototype.equals = function(other) {
  53829. return Spherical.equals(this, other);
  53830. };
  53831. /**
  53832. * Creates a duplicate of this Spherical.
  53833. *
  53834. * @param {Spherical} [result] The object to store the result into, if undefined a new instance will be created.
  53835. * @returns {Spherical} The modified result parameter or a new instance if result was undefined.
  53836. */
  53837. Spherical.prototype.clone = function(result) {
  53838. return Spherical.clone(this, result);
  53839. };
  53840. /**
  53841. * Returns true if this spherical is within the provided epsilon of the provided spherical, false otherwise.
  53842. *
  53843. * @param {Spherical} other The Spherical to be compared.
  53844. * @param {Number} epsilon The epsilon to compare against.
  53845. * @returns {Boolean} true if this spherical is within the provided epsilon of the provided spherical, false otherwise.
  53846. */
  53847. Spherical.prototype.equalsEpsilon = function(other, epsilon) {
  53848. return Spherical.equalsEpsilon(this, other, epsilon);
  53849. };
  53850. /**
  53851. * Returns a string representing this instance in the format (clock, cone, magnitude).
  53852. *
  53853. * @returns {String} A string representing this instance.
  53854. */
  53855. Spherical.prototype.toString = function() {
  53856. return '(' + this.clock + ', ' + this.cone + ', ' + this.magnitude + ')';
  53857. };
  53858. return Spherical;
  53859. });
  53860. /*global define*/
  53861. define('Core/subdivideArray',[
  53862. './defined',
  53863. './DeveloperError'
  53864. ], function(
  53865. defined,
  53866. DeveloperError) {
  53867. 'use strict';
  53868. /**
  53869. * Subdivides an array into a number of smaller, equal sized arrays.
  53870. *
  53871. * @exports subdivideArray
  53872. *
  53873. * @param {Array} array The array to divide.
  53874. * @param {Number} numberOfArrays The number of arrays to divide the provided array into.
  53875. *
  53876. * @exception {DeveloperError} numberOfArrays must be greater than 0.
  53877. */
  53878. function subdivideArray(array, numberOfArrays) {
  53879. if (!defined(array)) {
  53880. throw new DeveloperError('array is required.');
  53881. }
  53882. if (!defined(numberOfArrays) || numberOfArrays < 1) {
  53883. throw new DeveloperError('numberOfArrays must be greater than 0.');
  53884. }
  53885. var result = [];
  53886. var len = array.length;
  53887. var i = 0;
  53888. while (i < len) {
  53889. var size = Math.ceil((len - i) / numberOfArrays--);
  53890. result.push(array.slice(i, i + size));
  53891. i += size;
  53892. }
  53893. return result;
  53894. }
  53895. return subdivideArray;
  53896. });
  53897. /*global define*/
  53898. define('Core/TerrainData',[
  53899. './defineProperties',
  53900. './DeveloperError'
  53901. ], function(
  53902. defineProperties,
  53903. DeveloperError) {
  53904. 'use strict';
  53905. /**
  53906. * Terrain data for a single tile. This type describes an
  53907. * interface and is not intended to be instantiated directly.
  53908. *
  53909. * @alias TerrainData
  53910. * @constructor
  53911. *
  53912. * @see HeightmapTerrainData
  53913. * @see QuantizedMeshTerrainData
  53914. */
  53915. function TerrainData() {
  53916. DeveloperError.throwInstantiationError();
  53917. }
  53918. defineProperties(TerrainData.prototype, {
  53919. /**
  53920. * The water mask included in this terrain data, if any. A water mask is a rectangular
  53921. * Uint8Array or image where a value of 255 indicates water and a value of 0 indicates land.
  53922. * Values in between 0 and 255 are allowed as well to smoothly blend between land and water.
  53923. * @memberof TerrainData.prototype
  53924. * @type {Uint8Array|Image|Canvas}
  53925. */
  53926. waterMask : {
  53927. get : DeveloperError.throwInstantiationError
  53928. }
  53929. });
  53930. /**
  53931. * Computes the terrain height at a specified longitude and latitude.
  53932. * @function
  53933. *
  53934. * @param {Rectangle} rectangle The rectangle covered by this terrain data.
  53935. * @param {Number} longitude The longitude in radians.
  53936. * @param {Number} latitude The latitude in radians.
  53937. * @returns {Number} The terrain height at the specified position. If the position
  53938. * is outside the rectangle, this method will extrapolate the height, which is likely to be wildly
  53939. * incorrect for positions far outside the rectangle.
  53940. */
  53941. TerrainData.prototype.interpolateHeight = DeveloperError.throwInstantiationError;
  53942. /**
  53943. * Determines if a given child tile is available, based on the
  53944. * {@link TerrainData#childTileMask}. The given child tile coordinates are assumed
  53945. * to be one of the four children of this tile. If non-child tile coordinates are
  53946. * given, the availability of the southeast child tile is returned.
  53947. * @function
  53948. *
  53949. * @param {Number} thisX The tile X coordinate of this (the parent) tile.
  53950. * @param {Number} thisY The tile Y coordinate of this (the parent) tile.
  53951. * @param {Number} childX The tile X coordinate of the child tile to check for availability.
  53952. * @param {Number} childY The tile Y coordinate of the child tile to check for availability.
  53953. * @returns {Boolean} True if the child tile is available; otherwise, false.
  53954. */
  53955. TerrainData.prototype.isChildAvailable = DeveloperError.throwInstantiationError;
  53956. /**
  53957. * Creates a {@link TerrainMesh} from this terrain data.
  53958. * @function
  53959. *
  53960. * @private
  53961. *
  53962. * @param {TilingScheme} tilingScheme The tiling scheme to which this tile belongs.
  53963. * @param {Number} x The X coordinate of the tile for which to create the terrain data.
  53964. * @param {Number} y The Y coordinate of the tile for which to create the terrain data.
  53965. * @param {Number} level The level of the tile for which to create the terrain data.
  53966. * @returns {Promise.<TerrainMesh>|undefined} A promise for the terrain mesh, or undefined if too many
  53967. * asynchronous mesh creations are already in progress and the operation should
  53968. * be retried later.
  53969. */
  53970. TerrainData.prototype.createMesh = DeveloperError.throwInstantiationError;
  53971. /**
  53972. * Upsamples this terrain data for use by a descendant tile.
  53973. * @function
  53974. *
  53975. * @param {TilingScheme} tilingScheme The tiling scheme of this terrain data.
  53976. * @param {Number} thisX The X coordinate of this tile in the tiling scheme.
  53977. * @param {Number} thisY The Y coordinate of this tile in the tiling scheme.
  53978. * @param {Number} thisLevel The level of this tile in the tiling scheme.
  53979. * @param {Number} descendantX The X coordinate within the tiling scheme of the descendant tile for which we are upsampling.
  53980. * @param {Number} descendantY The Y coordinate within the tiling scheme of the descendant tile for which we are upsampling.
  53981. * @param {Number} descendantLevel The level within the tiling scheme of the descendant tile for which we are upsampling.
  53982. * @returns {Promise.<TerrainData>|undefined} A promise for upsampled terrain data for the descendant tile,
  53983. * or undefined if too many asynchronous upsample operations are in progress and the request has been
  53984. * deferred.
  53985. */
  53986. TerrainData.prototype.upsample = DeveloperError.throwInstantiationError;
  53987. /**
  53988. * Gets a value indicating whether or not this terrain data was created by upsampling lower resolution
  53989. * terrain data. If this value is false, the data was obtained from some other source, such
  53990. * as by downloading it from a remote server. This method should return true for instances
  53991. * returned from a call to {@link TerrainData#upsample}.
  53992. * @function
  53993. *
  53994. * @returns {Boolean} True if this instance was created by upsampling; otherwise, false.
  53995. */
  53996. TerrainData.prototype.wasCreatedByUpsampling = DeveloperError.throwInstantiationError;
  53997. return TerrainData;
  53998. });
  53999. /*global define*/
  54000. define('Core/TilingScheme',[
  54001. './defineProperties',
  54002. './DeveloperError'
  54003. ], function(
  54004. defineProperties,
  54005. DeveloperError) {
  54006. 'use strict';
  54007. /**
  54008. * A tiling scheme for geometry or imagery on the surface of an ellipsoid. At level-of-detail zero,
  54009. * the coarsest, least-detailed level, the number of tiles is configurable.
  54010. * At level of detail one, each of the level zero tiles has four children, two in each direction.
  54011. * At level of detail two, each of the level one tiles has four children, two in each direction.
  54012. * This continues for as many levels as are present in the geometry or imagery source.
  54013. *
  54014. * @alias TilingScheme
  54015. * @constructor
  54016. *
  54017. * @see WebMercatorTilingScheme
  54018. * @see GeographicTilingScheme
  54019. */
  54020. function TilingScheme(options) {
  54021. throw new DeveloperError('This type should not be instantiated directly. Instead, use WebMercatorTilingScheme or GeographicTilingScheme.');
  54022. }
  54023. defineProperties(TilingScheme.prototype, {
  54024. /**
  54025. * Gets the ellipsoid that is tiled by the tiling scheme.
  54026. * @memberof TilingScheme.prototype
  54027. * @type {Ellipsoid}
  54028. */
  54029. ellipsoid: {
  54030. get : DeveloperError.throwInstantiationError
  54031. },
  54032. /**
  54033. * Gets the rectangle, in radians, covered by this tiling scheme.
  54034. * @memberof TilingScheme.prototype
  54035. * @type {Rectangle}
  54036. */
  54037. rectangle : {
  54038. get : DeveloperError.throwInstantiationError
  54039. },
  54040. /**
  54041. * Gets the map projection used by the tiling scheme.
  54042. * @memberof TilingScheme.prototype
  54043. * @type {MapProjection}
  54044. */
  54045. projection : {
  54046. get : DeveloperError.throwInstantiationError
  54047. }
  54048. });
  54049. /**
  54050. * Gets the total number of tiles in the X direction at a specified level-of-detail.
  54051. * @function
  54052. *
  54053. * @param {Number} level The level-of-detail.
  54054. * @returns {Number} The number of tiles in the X direction at the given level.
  54055. */
  54056. TilingScheme.prototype.getNumberOfXTilesAtLevel = DeveloperError.throwInstantiationError;
  54057. /**
  54058. * Gets the total number of tiles in the Y direction at a specified level-of-detail.
  54059. * @function
  54060. *
  54061. * @param {Number} level The level-of-detail.
  54062. * @returns {Number} The number of tiles in the Y direction at the given level.
  54063. */
  54064. TilingScheme.prototype.getNumberOfYTilesAtLevel = DeveloperError.throwInstantiationError;
  54065. /**
  54066. * Transforms an rectangle specified in geodetic radians to the native coordinate system
  54067. * of this tiling scheme.
  54068. * @function
  54069. *
  54070. * @param {Rectangle} rectangle The rectangle to transform.
  54071. * @param {Rectangle} [result] The instance to which to copy the result, or undefined if a new instance
  54072. * should be created.
  54073. * @returns {Rectangle} The specified 'result', or a new object containing the native rectangle if 'result'
  54074. * is undefined.
  54075. */
  54076. TilingScheme.prototype.rectangleToNativeRectangle = DeveloperError.throwInstantiationError;
  54077. /**
  54078. * Converts tile x, y coordinates and level to an rectangle expressed in the native coordinates
  54079. * of the tiling scheme.
  54080. * @function
  54081. *
  54082. * @param {Number} x The integer x coordinate of the tile.
  54083. * @param {Number} y The integer y coordinate of the tile.
  54084. * @param {Number} level The tile level-of-detail. Zero is the least detailed.
  54085. * @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
  54086. * should be created.
  54087. * @returns {Rectangle} The specified 'result', or a new object containing the rectangle
  54088. * if 'result' is undefined.
  54089. */
  54090. TilingScheme.prototype.tileXYToNativeRectangle = DeveloperError.throwInstantiationError;
  54091. /**
  54092. * Converts tile x, y coordinates and level to a cartographic rectangle in radians.
  54093. * @function
  54094. *
  54095. * @param {Number} x The integer x coordinate of the tile.
  54096. * @param {Number} y The integer y coordinate of the tile.
  54097. * @param {Number} level The tile level-of-detail. Zero is the least detailed.
  54098. * @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
  54099. * should be created.
  54100. * @returns {Rectangle} The specified 'result', or a new object containing the rectangle
  54101. * if 'result' is undefined.
  54102. */
  54103. TilingScheme.prototype.tileXYToRectangle = DeveloperError.throwInstantiationError;
  54104. /**
  54105. * Calculates the tile x, y coordinates of the tile containing
  54106. * a given cartographic position.
  54107. * @function
  54108. *
  54109. * @param {Cartographic} position The position.
  54110. * @param {Number} level The tile level-of-detail. Zero is the least detailed.
  54111. * @param {Cartesian2} [result] The instance to which to copy the result, or undefined if a new instance
  54112. * should be created.
  54113. * @returns {Cartesian2} The specified 'result', or a new object containing the tile x, y coordinates
  54114. * if 'result' is undefined.
  54115. */
  54116. TilingScheme.prototype.positionToTileXY = DeveloperError.throwInstantiationError;
  54117. return TilingScheme;
  54118. });
  54119. /*global define*/
  54120. define('Core/TimeIntervalCollection',[
  54121. './binarySearch',
  54122. './defaultValue',
  54123. './defined',
  54124. './defineProperties',
  54125. './DeveloperError',
  54126. './Event',
  54127. './JulianDate',
  54128. './TimeInterval'
  54129. ], function(
  54130. binarySearch,
  54131. defaultValue,
  54132. defined,
  54133. defineProperties,
  54134. DeveloperError,
  54135. Event,
  54136. JulianDate,
  54137. TimeInterval) {
  54138. 'use strict';
  54139. function compareIntervalStartTimes(left, right) {
  54140. return JulianDate.compare(left.start, right.start);
  54141. }
  54142. /**
  54143. * A non-overlapping collection of {@link TimeInterval} instances sorted by start time.
  54144. * @alias TimeIntervalCollection
  54145. * @constructor
  54146. *
  54147. * @param {TimeInterval[]} [intervals] An array of intervals to add to the collection.
  54148. */
  54149. function TimeIntervalCollection(intervals) {
  54150. this._intervals = [];
  54151. this._changedEvent = new Event();
  54152. if (defined(intervals)) {
  54153. var length = intervals.length;
  54154. for (var i = 0; i < length; i++) {
  54155. this.addInterval(intervals[i]);
  54156. }
  54157. }
  54158. }
  54159. defineProperties(TimeIntervalCollection.prototype, {
  54160. /**
  54161. * Gets an event that is raised whenever the collection of intervals change.
  54162. * @memberof TimeIntervalCollection.prototype
  54163. * @type {Event}
  54164. * @readonly
  54165. */
  54166. changedEvent : {
  54167. get : function() {
  54168. return this._changedEvent;
  54169. }
  54170. },
  54171. /**
  54172. * Gets the start time of the collection.
  54173. * @memberof TimeIntervalCollection.prototype
  54174. * @type {JulianDate}
  54175. * @readonly
  54176. */
  54177. start : {
  54178. get : function() {
  54179. var intervals = this._intervals;
  54180. return intervals.length === 0 ? undefined : intervals[0].start;
  54181. }
  54182. },
  54183. /**
  54184. * Gets whether or not the start time is included in the collection.
  54185. * @memberof TimeIntervalCollection.prototype
  54186. * @type {Boolean}
  54187. * @readonly
  54188. */
  54189. isStartIncluded : {
  54190. get : function() {
  54191. var intervals = this._intervals;
  54192. return intervals.length === 0 ? false : intervals[0].isStartIncluded;
  54193. }
  54194. },
  54195. /**
  54196. * Gets the stop time of the collection.
  54197. * @memberof TimeIntervalCollection.prototype
  54198. * @type {JulianDate}
  54199. * @readonly
  54200. */
  54201. stop : {
  54202. get : function() {
  54203. var intervals = this._intervals;
  54204. var length = intervals.length;
  54205. return length === 0 ? undefined : intervals[length - 1].stop;
  54206. }
  54207. },
  54208. /**
  54209. * Gets whether or not the stop time is included in the collection.
  54210. * @memberof TimeIntervalCollection.prototype
  54211. * @type {Boolean}
  54212. * @readonly
  54213. */
  54214. isStopIncluded : {
  54215. get : function() {
  54216. var intervals = this._intervals;
  54217. var length = intervals.length;
  54218. return length === 0 ? false : intervals[length - 1].isStopIncluded;
  54219. }
  54220. },
  54221. /**
  54222. * Gets the number of intervals in the collection.
  54223. * @memberof TimeIntervalCollection.prototype
  54224. * @type {Number}
  54225. * @readonly
  54226. */
  54227. length : {
  54228. get : function() {
  54229. return this._intervals.length;
  54230. }
  54231. },
  54232. /**
  54233. * Gets whether or not the collection is empty.
  54234. * @memberof TimeIntervalCollection.prototype
  54235. * @type {Boolean}
  54236. * @readonly
  54237. */
  54238. isEmpty : {
  54239. get : function() {
  54240. return this._intervals.length === 0;
  54241. }
  54242. }
  54243. });
  54244. /**
  54245. * Compares this instance against the provided instance componentwise and returns
  54246. * <code>true</code> if they are equal, <code>false</code> otherwise.
  54247. *
  54248. * @param {TimeIntervalCollection} [right] The right hand side collection.
  54249. * @param {TimeInterval~DataComparer} [dataComparer] A function which compares the data of the two intervals. If omitted, reference equality is used.
  54250. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  54251. */
  54252. TimeIntervalCollection.prototype.equals = function(right, dataComparer) {
  54253. if (this === right) {
  54254. return true;
  54255. }
  54256. if (!(right instanceof TimeIntervalCollection)) {
  54257. return false;
  54258. }
  54259. var intervals = this._intervals;
  54260. var rightIntervals = right._intervals;
  54261. var length = intervals.length;
  54262. if (length !== rightIntervals.length) {
  54263. return false;
  54264. }
  54265. for (var i = 0; i < length; i++) {
  54266. if (!TimeInterval.equals(intervals[i], rightIntervals[i], dataComparer)) {
  54267. return false;
  54268. }
  54269. }
  54270. return true;
  54271. };
  54272. /**
  54273. * Gets the interval at the specified index.
  54274. *
  54275. * @param {Number} index The index of the interval to retrieve.
  54276. * @returns {TimeInterval} The interval at the specified index, or <code>undefined</code> if no interval exists as that index.
  54277. */
  54278. TimeIntervalCollection.prototype.get = function(index) {
  54279. if (!defined(index)) {
  54280. throw new DeveloperError('index is required.');
  54281. }
  54282. return this._intervals[index];
  54283. };
  54284. /**
  54285. * Removes all intervals from the collection.
  54286. */
  54287. TimeIntervalCollection.prototype.removeAll = function() {
  54288. if (this._intervals.length > 0) {
  54289. this._intervals.length = 0;
  54290. this._changedEvent.raiseEvent(this);
  54291. }
  54292. };
  54293. /**
  54294. * Finds and returns the interval that contains the specified date.
  54295. *
  54296. * @param {JulianDate} date The date to search for.
  54297. * @returns {TimeInterval|undefined} The interval containing the specified date, <code>undefined</code> if no such interval exists.
  54298. */
  54299. TimeIntervalCollection.prototype.findIntervalContainingDate = function(date) {
  54300. var index = this.indexOf(date);
  54301. return index >= 0 ? this._intervals[index] : undefined;
  54302. };
  54303. /**
  54304. * Finds and returns the data for the interval that contains the specified date.
  54305. *
  54306. * @param {JulianDate} date The date to search for.
  54307. * @returns {Object} The data for the interval containing the specified date, or <code>undefined</code> if no such interval exists.
  54308. */
  54309. TimeIntervalCollection.prototype.findDataForIntervalContainingDate = function(date) {
  54310. var index = this.indexOf(date);
  54311. return index >= 0 ? this._intervals[index].data : undefined;
  54312. };
  54313. /**
  54314. * Checks if the specified date is inside this collection.
  54315. *
  54316. * @param {JulianDate} julianDate The date to check.
  54317. * @returns {Boolean} <code>true</code> if the collection contains the specified date, <code>false</code> otherwise.
  54318. */
  54319. TimeIntervalCollection.prototype.contains = function(date) {
  54320. return this.indexOf(date) >= 0;
  54321. };
  54322. var indexOfScratch = new TimeInterval();
  54323. /**
  54324. * Finds and returns the index of the interval in the collection that contains the specified date.
  54325. *
  54326. * @param {JulianDate} date The date to search for.
  54327. * @returns {Number} The index of the interval that contains the specified date, if no such interval exists,
  54328. * it returns a negative number which is the bitwise complement of the index of the next interval that
  54329. * starts after the date, or if no interval starts after the specified date, the bitwise complement of
  54330. * the length of the collection.
  54331. */
  54332. TimeIntervalCollection.prototype.indexOf = function(date) {
  54333. if (!defined(date)) {
  54334. throw new DeveloperError('date is required');
  54335. }
  54336. var intervals = this._intervals;
  54337. indexOfScratch.start = date;
  54338. indexOfScratch.stop = date;
  54339. var index = binarySearch(intervals, indexOfScratch, compareIntervalStartTimes);
  54340. if (index >= 0) {
  54341. if (intervals[index].isStartIncluded) {
  54342. return index;
  54343. }
  54344. if (index > 0 && intervals[index - 1].stop.equals(date) && intervals[index - 1].isStopIncluded) {
  54345. return index - 1;
  54346. }
  54347. return ~index;
  54348. }
  54349. index = ~index;
  54350. if (index > 0 && (index - 1) < intervals.length && TimeInterval.contains(intervals[index - 1], date)) {
  54351. return index - 1;
  54352. }
  54353. return ~index;
  54354. };
  54355. /**
  54356. * Returns the first interval in the collection that matches the specified parameters.
  54357. * All parameters are optional and <code>undefined</code> parameters are treated as a don't care condition.
  54358. *
  54359. * @param {Object} [options] Object with the following properties:
  54360. * @param {JulianDate} [options.start] The start time of the interval.
  54361. * @param {JulianDate} [options.stop] The stop time of the interval.
  54362. * @param {Boolean} [options.isStartIncluded] <code>true</code> if <code>options.start</code> is included in the interval, <code>false</code> otherwise.
  54363. * @param {Boolean} [options.isStopIncluded] <code>true</code> if <code>options.stop</code> is included in the interval, <code>false</code> otherwise.
  54364. * @returns {TimeInterval} The first interval in the collection that matches the specified parameters.
  54365. */
  54366. TimeIntervalCollection.prototype.findInterval = function(options) {
  54367. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  54368. var start = options.start;
  54369. var stop = options.stop;
  54370. var isStartIncluded = options.isStartIncluded;
  54371. var isStopIncluded = options.isStopIncluded;
  54372. var intervals = this._intervals;
  54373. for (var i = 0, len = intervals.length; i < len; i++) {
  54374. var interval = intervals[i];
  54375. if ((!defined(start) || interval.start.equals(start)) &&
  54376. (!defined(stop) || interval.stop.equals(stop)) &&
  54377. (!defined(isStartIncluded) || interval.isStartIncluded === isStartIncluded) &&
  54378. (!defined(isStopIncluded) || interval.isStopIncluded === isStopIncluded)) {
  54379. return intervals[i];
  54380. }
  54381. }
  54382. return undefined;
  54383. };
  54384. /**
  54385. * Adds an interval to the collection, merging intervals that contain the same data and
  54386. * splitting intervals of different data as needed in order to maintain a non-overlapping collection.
  54387. * The data in the new interval takes precedence over any existing intervals in the collection.
  54388. *
  54389. * @param {TimeInterval} interval The interval to add.
  54390. * @param {TimeInterval~DataComparer} [dataComparer] A function which compares the data of the two intervals. If omitted, reference equality is used.
  54391. */
  54392. TimeIntervalCollection.prototype.addInterval = function(interval, dataComparer) {
  54393. if (!defined(interval)) {
  54394. throw new DeveloperError("interval is required");
  54395. }
  54396. if (interval.isEmpty) {
  54397. return;
  54398. }
  54399. var comparison;
  54400. var index;
  54401. var intervals = this._intervals;
  54402. // Handle the common case quickly: we're adding a new interval which is after all existing intervals.
  54403. if (intervals.length === 0 || JulianDate.greaterThan(interval.start, intervals[intervals.length - 1].stop)) {
  54404. intervals.push(interval);
  54405. this._changedEvent.raiseEvent(this);
  54406. return;
  54407. }
  54408. // Keep the list sorted by the start date
  54409. index = binarySearch(intervals, interval, compareIntervalStartTimes);
  54410. if (index < 0) {
  54411. index = ~index;
  54412. } else {
  54413. // interval's start date exactly equals the start date of at least one interval in the collection.
  54414. // It could actually equal the start date of two intervals if one of them does not actually
  54415. // include the date. In that case, the binary search could have found either. We need to
  54416. // look at the surrounding intervals and their IsStartIncluded properties in order to make sure
  54417. // we're working with the correct interval.
  54418. if (index > 0 && interval.isStartIncluded && intervals[index - 1].isStartIncluded && intervals[index - 1].start.equals(interval.start)) {
  54419. --index;
  54420. } else if (index < intervals.length && !interval.isStartIncluded && intervals[index].isStartIncluded && intervals[index].start.equals(interval.start)) {
  54421. ++index;
  54422. }
  54423. }
  54424. if (index > 0) {
  54425. // Not the first thing in the list, so see if the interval before this one
  54426. // overlaps this one.
  54427. comparison = JulianDate.compare(intervals[index - 1].stop, interval.start);
  54428. if (comparison > 0 || (comparison === 0 && (intervals[index - 1].isStopIncluded || interval.isStartIncluded))) {
  54429. // There is an overlap
  54430. if (defined(dataComparer) ? dataComparer(intervals[index - 1].data, interval.data) : (intervals[index - 1].data === interval.data)) {
  54431. // Overlapping intervals have the same data, so combine them
  54432. if (JulianDate.greaterThan(interval.stop, intervals[index - 1].stop)) {
  54433. interval = new TimeInterval({
  54434. start : intervals[index - 1].start,
  54435. stop : interval.stop,
  54436. isStartIncluded : intervals[index - 1].isStartIncluded,
  54437. isStopIncluded : interval.isStopIncluded,
  54438. data : interval.data
  54439. });
  54440. } else {
  54441. interval = new TimeInterval({
  54442. start : intervals[index - 1].start,
  54443. stop : intervals[index - 1].stop,
  54444. isStartIncluded : intervals[index - 1].isStartIncluded,
  54445. isStopIncluded : intervals[index - 1].isStopIncluded || (interval.stop.equals(intervals[index - 1].stop) && interval.isStopIncluded),
  54446. data : interval.data
  54447. });
  54448. }
  54449. intervals.splice(index - 1, 1);
  54450. --index;
  54451. } else {
  54452. // Overlapping intervals have different data. The new interval
  54453. // being added 'wins' so truncate the previous interval.
  54454. // If the existing interval extends past the end of the new one,
  54455. // split the existing interval into two intervals.
  54456. comparison = JulianDate.compare(intervals[index - 1].stop, interval.stop);
  54457. if (comparison > 0 || (comparison === 0 && intervals[index - 1].isStopIncluded && !interval.isStopIncluded)) {
  54458. intervals.splice(index - 1, 1, new TimeInterval({
  54459. start : intervals[index - 1].start,
  54460. stop : interval.start,
  54461. isStartIncluded : intervals[index - 1].isStartIncluded,
  54462. isStopIncluded : !interval.isStartIncluded,
  54463. data : intervals[index - 1].data
  54464. }), new TimeInterval({
  54465. start : interval.stop,
  54466. stop : intervals[index - 1].stop,
  54467. isStartIncluded : !interval.isStopIncluded,
  54468. isStopIncluded : intervals[index - 1].isStopIncluded,
  54469. data : intervals[index - 1].data
  54470. }));
  54471. } else {
  54472. intervals[index - 1] = new TimeInterval({
  54473. start : intervals[index - 1].start,
  54474. stop : interval.start,
  54475. isStartIncluded : intervals[index - 1].isStartIncluded,
  54476. isStopIncluded : !interval.isStartIncluded,
  54477. data : intervals[index - 1].data
  54478. });
  54479. }
  54480. }
  54481. }
  54482. }
  54483. while (index < intervals.length) {
  54484. // Not the last thing in the list, so see if the intervals after this one overlap this one.
  54485. comparison = JulianDate.compare(interval.stop, intervals[index].start);
  54486. if (comparison > 0 || (comparison === 0 && (interval.isStopIncluded || intervals[index].isStartIncluded))) {
  54487. // There is an overlap
  54488. if (defined(dataComparer) ? dataComparer(intervals[index].data, interval.data) : intervals[index].data === interval.data) {
  54489. // Overlapping intervals have the same data, so combine them
  54490. interval = new TimeInterval({
  54491. start : interval.start,
  54492. stop : JulianDate.greaterThan(intervals[index].stop, interval.stop) ? intervals[index].stop : interval.stop,
  54493. isStartIncluded : interval.isStartIncluded,
  54494. isStopIncluded : JulianDate.greaterThan(intervals[index].stop, interval.stop) ? intervals[index].isStopIncluded : interval.isStopIncluded,
  54495. data : interval.data
  54496. });
  54497. intervals.splice(index, 1);
  54498. } else {
  54499. // Overlapping intervals have different data. The new interval
  54500. // being added 'wins' so truncate the next interval.
  54501. intervals[index] = new TimeInterval({
  54502. start : interval.stop,
  54503. stop : intervals[index].stop,
  54504. isStartIncluded : !interval.isStopIncluded,
  54505. isStopIncluded : intervals[index].isStopIncluded,
  54506. data : intervals[index].data
  54507. });
  54508. if (intervals[index].isEmpty) {
  54509. intervals.splice(index, 1);
  54510. } else {
  54511. // Found a partial span, so it is not possible for the next
  54512. // interval to be spanned at all. Stop looking.
  54513. break;
  54514. }
  54515. }
  54516. } else {
  54517. // Found the last one we're spanning, so stop looking.
  54518. break;
  54519. }
  54520. }
  54521. // Add the new interval
  54522. intervals.splice(index, 0, interval);
  54523. this._changedEvent.raiseEvent(this);
  54524. };
  54525. /**
  54526. * Removes the specified interval from this interval collection, creating a hole over the specified interval.
  54527. * The data property of the input interval is ignored.
  54528. *
  54529. * @param {TimeInterval} interval The interval to remove.
  54530. * @returns <code>true</code> if the interval was removed, <code>false</code> if no part of the interval was in the collection.
  54531. */
  54532. TimeIntervalCollection.prototype.removeInterval = function(interval) {
  54533. if (!defined(interval)) {
  54534. throw new DeveloperError("interval is required");
  54535. }
  54536. if (interval.isEmpty) {
  54537. return false;
  54538. }
  54539. var result = false;
  54540. var intervals = this._intervals;
  54541. var index = binarySearch(intervals, interval, compareIntervalStartTimes);
  54542. if (index < 0) {
  54543. index = ~index;
  54544. }
  54545. var intervalStart = interval.start;
  54546. var intervalStop = interval.stop;
  54547. var intervalIsStartIncluded = interval.isStartIncluded;
  54548. var intervalIsStopIncluded = interval.isStopIncluded;
  54549. // Check for truncation of the end of the previous interval.
  54550. if (index > 0) {
  54551. var indexMinus1 = intervals[index - 1];
  54552. var indexMinus1Stop = indexMinus1.stop;
  54553. if (JulianDate.greaterThan(indexMinus1Stop, intervalStart) ||
  54554. (TimeInterval.equals(indexMinus1Stop, intervalStart) &&
  54555. indexMinus1.isStopIncluded && intervalIsStartIncluded)) {
  54556. result = true;
  54557. if (JulianDate.greaterThan(indexMinus1Stop, intervalStop) ||
  54558. (indexMinus1.isStopIncluded && !intervalIsStopIncluded && TimeInterval.equals(indexMinus1Stop, intervalStop))) {
  54559. // Break the existing interval into two pieces
  54560. intervals.splice(index, 0, new TimeInterval({
  54561. start : intervalStop,
  54562. stop : indexMinus1Stop,
  54563. isStartIncluded : !intervalIsStopIncluded,
  54564. isStopIncluded : indexMinus1.isStopIncluded,
  54565. data : indexMinus1.data
  54566. }));
  54567. }
  54568. intervals[index - 1] = new TimeInterval({
  54569. start : indexMinus1.start,
  54570. stop : intervalStart,
  54571. isStartIncluded : indexMinus1.isStartIncluded,
  54572. isStopIncluded : !intervalIsStartIncluded,
  54573. data : indexMinus1.data
  54574. });
  54575. }
  54576. }
  54577. // Check if the Start of the current interval should remain because interval.start is the same but
  54578. // it is not included.
  54579. var indexInterval = intervals[index];
  54580. if (index < intervals.length &&
  54581. !intervalIsStartIncluded &&
  54582. indexInterval.isStartIncluded &&
  54583. intervalStart.equals(indexInterval.start)) {
  54584. result = true;
  54585. intervals.splice(index, 0, new TimeInterval({
  54586. start : indexInterval.start,
  54587. stop : indexInterval.start,
  54588. isStartIncluded : true,
  54589. isStopIncluded : true,
  54590. data : indexInterval.data
  54591. }));
  54592. ++index;
  54593. indexInterval = intervals[index];
  54594. }
  54595. // Remove any intervals that are completely overlapped by the input interval.
  54596. while (index < intervals.length && JulianDate.greaterThan(intervalStop, indexInterval.stop)) {
  54597. result = true;
  54598. intervals.splice(index, 1);
  54599. indexInterval = intervals[index];
  54600. }
  54601. // Check for the case where the input interval ends on the same date
  54602. // as an existing interval.
  54603. if (index < intervals.length && intervalStop.equals(indexInterval.stop)) {
  54604. result = true;
  54605. if (!intervalIsStopIncluded && indexInterval.isStopIncluded) {
  54606. // Last point of interval should remain because the stop date is included in
  54607. // the existing interval but is not included in the input interval.
  54608. if ((index + 1) < intervals.length && intervals[index + 1].start.equals(intervalStop) && indexInterval.data === intervals[index + 1].data) {
  54609. // Combine single point with the next interval
  54610. intervals.splice(index, 1);
  54611. indexInterval = new TimeInterval({
  54612. start : indexInterval.start,
  54613. stop : indexInterval.stop,
  54614. isStartIncluded : true,
  54615. isStopIncluded : indexInterval.isStopIncluded,
  54616. data : indexInterval.data
  54617. });
  54618. } else {
  54619. indexInterval = new TimeInterval({
  54620. start : intervalStop,
  54621. stop : intervalStop,
  54622. isStartIncluded : true,
  54623. isStopIncluded : true,
  54624. data : indexInterval.data
  54625. });
  54626. }
  54627. intervals[index] = indexInterval;
  54628. } else {
  54629. // Interval is completely overlapped
  54630. intervals.splice(index, 1);
  54631. }
  54632. }
  54633. // Truncate any partially-overlapped intervals.
  54634. if (index < intervals.length &&
  54635. (JulianDate.greaterThan(intervalStop, indexInterval.start) ||
  54636. (intervalStop.equals(indexInterval.start) &&
  54637. intervalIsStopIncluded &&
  54638. indexInterval.isStartIncluded))) {
  54639. result = true;
  54640. intervals[index] = new TimeInterval({
  54641. start : intervalStop,
  54642. stop : indexInterval.stop,
  54643. isStartIncluded : !intervalIsStopIncluded,
  54644. isStopIncluded : indexInterval.isStopIncluded,
  54645. data : indexInterval.data
  54646. });
  54647. }
  54648. if (result) {
  54649. this._changedEvent.raiseEvent(this);
  54650. }
  54651. return result;
  54652. };
  54653. /**
  54654. * Creates a new instance that is the intersection of this collection and the provided collection.
  54655. *
  54656. * @param {TimeIntervalCollection} other The collection to intersect with.
  54657. * @param {TimeInterval~DataComparer} [dataComparer] A function which compares the data of the two intervals. If omitted, reference equality is used.
  54658. * @param {TimeInterval~MergeCallback} [mergeCallback] A function which merges the data of the two intervals. If omitted, the data from the left interval will be used.
  54659. * @returns {TimeIntervalCollection} A new TimeIntervalCollection which is the intersection of this collection and the provided collection.
  54660. */
  54661. TimeIntervalCollection.prototype.intersect = function(other, dataComparer, mergeCallback) {
  54662. if (!defined(other)) {
  54663. throw new DeveloperError('other is required.');
  54664. }
  54665. var left = 0;
  54666. var right = 0;
  54667. var result = new TimeIntervalCollection();
  54668. var intervals = this._intervals;
  54669. var otherIntervals = other._intervals;
  54670. while (left < intervals.length && right < otherIntervals.length) {
  54671. var leftInterval = intervals[left];
  54672. var rightInterval = otherIntervals[right];
  54673. if (JulianDate.lessThan(leftInterval.stop, rightInterval.start)) {
  54674. ++left;
  54675. } else if (JulianDate.lessThan(rightInterval.stop, leftInterval.start)) {
  54676. ++right;
  54677. } else {
  54678. // The following will return an intersection whose data is 'merged' if the callback is defined
  54679. if (defined(mergeCallback) ||
  54680. ((defined(dataComparer) && dataComparer(leftInterval.data, rightInterval.data)) ||
  54681. (!defined(dataComparer) && rightInterval.data === leftInterval.data))) {
  54682. var intersection = TimeInterval.intersect(leftInterval, rightInterval, new TimeInterval(), mergeCallback);
  54683. if (!intersection.isEmpty) {
  54684. // Since we start with an empty collection for 'result', and there are no overlapping intervals in 'this' (as a rule),
  54685. // the 'intersection' will never overlap with a previous interval in 'result'. So, no need to do any additional 'merging'.
  54686. result.addInterval(intersection, dataComparer);
  54687. }
  54688. }
  54689. if (JulianDate.lessThan(leftInterval.stop, rightInterval.stop) ||
  54690. (leftInterval.stop.equals(rightInterval.stop) &&
  54691. !leftInterval.isStopIncluded &&
  54692. rightInterval.isStopIncluded)) {
  54693. ++left;
  54694. } else {
  54695. ++right;
  54696. }
  54697. }
  54698. }
  54699. return result;
  54700. };
  54701. return TimeIntervalCollection;
  54702. });
  54703. /*global define*/
  54704. define('Core/TranslationRotationScale',[
  54705. './Cartesian3',
  54706. './defaultValue',
  54707. './defined',
  54708. './Quaternion'
  54709. ], function(
  54710. Cartesian3,
  54711. defaultValue,
  54712. defined,
  54713. Quaternion) {
  54714. 'use strict';
  54715. var defaultScale = new Cartesian3(1.0, 1.0, 1.0);
  54716. var defaultTranslation = Cartesian3.ZERO;
  54717. var defaultRotation = Quaternion.IDENTITY;
  54718. /**
  54719. * An affine transformation defined by a translation, rotation, and scale.
  54720. * @alias TranslationRotationScale
  54721. * @constructor
  54722. *
  54723. * @param {Cartesian3} [translation=Cartesian3.ZERO] A {@link Cartesian3} specifying the (x, y, z) translation to apply to the node.
  54724. * @param {Quaternion} [rotation=Quaternion.IDENTITY] A {@link Quaternion} specifying the (x, y, z, w) rotation to apply to the node.
  54725. * @param {Cartesian3} [scale=new Cartesian3(1.0, 1.0, 1.0)] A {@link Cartesian3} specifying the (x, y, z) scaling to apply to the node.
  54726. */
  54727. var TranslationRotationScale = function(translation, rotation, scale) {
  54728. /**
  54729. * Gets or sets the (x, y, z) translation to apply to the node.
  54730. * @type {Cartesian3}
  54731. * @default Cartesian3.ZERO
  54732. */
  54733. this.translation = Cartesian3.clone(defaultValue(translation, defaultTranslation));
  54734. /**
  54735. * Gets or sets the (x, y, z, w) rotation to apply to the node.
  54736. * @type {Quaternion}
  54737. * @default Quaternion.IDENTITY
  54738. */
  54739. this.rotation = Quaternion.clone(defaultValue(rotation, defaultRotation));
  54740. /**
  54741. * Gets or sets the (x, y, z) scaling to apply to the node.
  54742. * @type {Cartesian3}
  54743. * @default new Cartesian3(1.0, 1.0, 1.0)
  54744. */
  54745. this.scale = Cartesian3.clone(defaultValue(scale, defaultScale));
  54746. };
  54747. /**
  54748. * Compares this instance against the provided instance and returns
  54749. * <code>true</code> if they are equal, <code>false</code> otherwise.
  54750. *
  54751. * @param {TranslationRotationScale} [right] The right hand side TranslationRotationScale.
  54752. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  54753. */
  54754. TranslationRotationScale.prototype.equals = function(right) {
  54755. return (this === right) ||
  54756. (defined(right) &&
  54757. Cartesian3.equals(this.translation, right.translation) &&
  54758. Quaternion.equals(this.rotation, right.rotation) &&
  54759. Cartesian3.equals(this.scale, right.scale));
  54760. };
  54761. return TranslationRotationScale;
  54762. });
  54763. /*global define*/
  54764. define('Core/VideoSynchronizer',[
  54765. './defaultValue',
  54766. './defined',
  54767. './defineProperties',
  54768. './destroyObject',
  54769. './Iso8601',
  54770. './JulianDate'
  54771. ], function(
  54772. defaultValue,
  54773. defined,
  54774. defineProperties,
  54775. destroyObject,
  54776. Iso8601,
  54777. JulianDate) {
  54778. 'use strict';
  54779. /**
  54780. * Synchronizes a video element with a simulation clock.
  54781. *
  54782. * @alias VideoSynchronizer
  54783. * @constructor
  54784. *
  54785. * @param {Object} [options] Object with the following properties:
  54786. * @param {Clock} [options.clock] The clock instance used to drive the video.
  54787. * @param {HTMLVideoElement} [options.element] The video element to be synchronized.
  54788. * @param {JulianDate} [options.epoch=Iso8601.MINIMUM_VALUE] The simulation time that marks the start of the video.
  54789. * @param {Number} [options.tolerance=1.0] The maximum amount of time, in seconds, that the clock and video can diverge.
  54790. *
  54791. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Video.html|Video Material Demo}
  54792. */
  54793. function VideoSynchronizer(options) {
  54794. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  54795. this._clock = undefined;
  54796. this._element = undefined;
  54797. this._clockSubscription = undefined;
  54798. this._seekFunction = undefined;
  54799. this.clock = options.clock;
  54800. this.element = options.element;
  54801. /**
  54802. * Gets or sets the simulation time that marks the start of the video.
  54803. * @type {JulianDate}
  54804. * @default Iso8601.MINIMUM_VALUE
  54805. */
  54806. this.epoch = defaultValue(options.epoch, Iso8601.MINIMUM_VALUE);
  54807. /**
  54808. * Gets or sets the amount of time in seconds the video's currentTime
  54809. * and the clock's currentTime can diverge before a video seek is performed.
  54810. * Lower values make the synchronization more accurate but video
  54811. * performance might suffer. Higher values provide better performance
  54812. * but at the cost of accuracy.
  54813. * @type {Number}
  54814. * @default 1.0
  54815. */
  54816. this.tolerance = defaultValue(options.tolerance, 1.0);
  54817. this._seeking = false;
  54818. this._seekFunction = undefined;
  54819. this._firstTickAfterSeek = false;
  54820. }
  54821. defineProperties(VideoSynchronizer.prototype, {
  54822. /**
  54823. * Gets or sets the clock used to drive the video element.
  54824. *
  54825. * @memberof VideoSynchronizer.prototype
  54826. * @type {Clock}
  54827. */
  54828. clock : {
  54829. get : function() {
  54830. return this._clock;
  54831. },
  54832. set : function(value) {
  54833. var oldValue = this._clock;
  54834. if (oldValue === value) {
  54835. return;
  54836. }
  54837. if (defined(oldValue)) {
  54838. this._clockSubscription();
  54839. this._clockSubscription = undefined;
  54840. }
  54841. if (defined(value)) {
  54842. this._clockSubscription = value.onTick.addEventListener(VideoSynchronizer.prototype._onTick, this);
  54843. }
  54844. this._clock = value;
  54845. }
  54846. },
  54847. /**
  54848. * Gets or sets the video element to synchronize.
  54849. *
  54850. * @memberof VideoSynchronizer.prototype
  54851. * @type {HTMLVideoElement}
  54852. */
  54853. element : {
  54854. get : function() {
  54855. return this._element;
  54856. },
  54857. set : function(value) {
  54858. var oldValue = this._element;
  54859. if (oldValue === value) {
  54860. return;
  54861. }
  54862. if (defined(oldValue)) {
  54863. oldValue.removeEventListener("seeked", this._seekFunction, false);
  54864. }
  54865. if (defined(value)) {
  54866. this._seeking = false;
  54867. this._seekFunction = createSeekFunction(this);
  54868. value.addEventListener("seeked", this._seekFunction, false);
  54869. }
  54870. this._element = value;
  54871. this._seeking = false;
  54872. this._firstTickAfterSeek = false;
  54873. }
  54874. }
  54875. });
  54876. /**
  54877. * Destroys and resources used by the object. Once an object is destroyed, it should not be used.
  54878. *
  54879. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  54880. */
  54881. VideoSynchronizer.prototype.destroy = function() {
  54882. this.element = undefined;
  54883. this.clock = undefined;
  54884. return destroyObject(this);
  54885. };
  54886. /**
  54887. * Returns true if this object was destroyed; otherwise, false.
  54888. *
  54889. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  54890. */
  54891. VideoSynchronizer.prototype.isDestroyed = function() {
  54892. return false;
  54893. };
  54894. VideoSynchronizer.prototype._onTick = function(clock) {
  54895. var element = this._element;
  54896. if (!defined(element) || element.readyState < 2) {
  54897. return;
  54898. }
  54899. var paused = element.paused;
  54900. var shouldAnimate = clock.shouldAnimate;
  54901. if (shouldAnimate === paused) {
  54902. if (shouldAnimate) {
  54903. element.play();
  54904. } else {
  54905. element.pause();
  54906. }
  54907. }
  54908. //We need to avoid constant seeking or the video will
  54909. //never contain a complete frame for us to render.
  54910. //So don't do anything if we're seeing or on the first
  54911. //tick after a seek (the latter of which allows the frame
  54912. //to actually be rendered.
  54913. if (this._seeking || this._firstTickAfterSeek) {
  54914. this._firstTickAfterSeek = false;
  54915. return;
  54916. }
  54917. element.playbackRate = clock.multiplier;
  54918. var clockTime = clock.currentTime;
  54919. var epoch = defaultValue(this.epoch, Iso8601.MINIMUM_VALUE);
  54920. var videoTime = JulianDate.secondsDifference(clockTime, epoch);
  54921. var duration = element.duration;
  54922. var desiredTime;
  54923. var currentTime = element.currentTime;
  54924. if (element.loop) {
  54925. videoTime = videoTime % duration;
  54926. if (videoTime < 0.0) {
  54927. videoTime = duration - videoTime;
  54928. }
  54929. desiredTime = videoTime;
  54930. } else if (videoTime > duration) {
  54931. desiredTime = duration;
  54932. } else if (videoTime < 0.0) {
  54933. desiredTime = 0.0;
  54934. } else {
  54935. desiredTime = videoTime;
  54936. }
  54937. //If the playing video's time and the scene's clock time
  54938. //ever drift too far apart, we want to set the video to match
  54939. var tolerance = shouldAnimate ? defaultValue(this.tolerance, 1.0) : 0.001;
  54940. if (Math.abs(desiredTime - currentTime) > tolerance) {
  54941. this._seeking = true;
  54942. element.currentTime = desiredTime;
  54943. }
  54944. };
  54945. function createSeekFunction(that) {
  54946. return function() {
  54947. that._seeking = false;
  54948. that._firstTickAfterSeek = true;
  54949. };
  54950. }
  54951. return VideoSynchronizer;
  54952. });
  54953. /*global define*/
  54954. define('Core/VRTheWorldTerrainProvider',[
  54955. '../ThirdParty/when',
  54956. './Credit',
  54957. './defaultValue',
  54958. './defined',
  54959. './defineProperties',
  54960. './DeveloperError',
  54961. './Ellipsoid',
  54962. './Event',
  54963. './GeographicTilingScheme',
  54964. './getImagePixels',
  54965. './HeightmapTerrainData',
  54966. './loadImage',
  54967. './loadXML',
  54968. './Math',
  54969. './Rectangle',
  54970. './TerrainProvider',
  54971. './throttleRequestByServer',
  54972. './TileProviderError'
  54973. ], function(
  54974. when,
  54975. Credit,
  54976. defaultValue,
  54977. defined,
  54978. defineProperties,
  54979. DeveloperError,
  54980. Ellipsoid,
  54981. Event,
  54982. GeographicTilingScheme,
  54983. getImagePixels,
  54984. HeightmapTerrainData,
  54985. loadImage,
  54986. loadXML,
  54987. CesiumMath,
  54988. Rectangle,
  54989. TerrainProvider,
  54990. throttleRequestByServer,
  54991. TileProviderError) {
  54992. 'use strict';
  54993. function DataRectangle(rectangle, maxLevel) {
  54994. this.rectangle = rectangle;
  54995. this.maxLevel = maxLevel;
  54996. }
  54997. /**
  54998. * A {@link TerrainProvider} that produces terrain geometry by tessellating height maps
  54999. * retrieved from a {@link http://vr-theworld.com/|VT MÄK VR-TheWorld server}.
  55000. *
  55001. * @alias VRTheWorldTerrainProvider
  55002. * @constructor
  55003. *
  55004. * @param {Object} options Object with the following properties:
  55005. * @param {String} options.url The URL of the VR-TheWorld TileMap.
  55006. * @param {Object} [options.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL, if needed.
  55007. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid. If this parameter is not
  55008. * specified, the WGS84 ellipsoid is used.
  55009. * @param {Credit|String} [options.credit] A credit for the data source, which is displayed on the canvas.
  55010. *
  55011. *
  55012. * @example
  55013. * var terrainProvider = new Cesium.VRTheWorldTerrainProvider({
  55014. * url : 'https://www.vr-theworld.com/vr-theworld/tiles1.0.0/73/'
  55015. * });
  55016. * viewer.terrainProvider = terrainProvider;
  55017. *
  55018. * @see TerrainProvider
  55019. */
  55020. function VRTheWorldTerrainProvider(options) {
  55021. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  55022. if (!defined(options.url)) {
  55023. throw new DeveloperError('options.url is required.');
  55024. }
  55025. this._url = options.url;
  55026. if (this._url.length > 0 && this._url[this._url.length - 1] !== '/') {
  55027. this._url += '/';
  55028. }
  55029. this._errorEvent = new Event();
  55030. this._ready = false;
  55031. this._readyPromise = when.defer();
  55032. this._proxy = options.proxy;
  55033. this._terrainDataStructure = {
  55034. heightScale : 1.0 / 1000.0,
  55035. heightOffset : -1000.0,
  55036. elementsPerHeight : 3,
  55037. stride : 4,
  55038. elementMultiplier : 256.0,
  55039. isBigEndian : true,
  55040. lowestEncodedHeight : 0,
  55041. highestEncodedHeight : 256 * 256 * 256 - 1
  55042. };
  55043. var credit = options.credit;
  55044. if (typeof credit === 'string') {
  55045. credit = new Credit(credit);
  55046. }
  55047. this._credit = credit;
  55048. this._tilingScheme = undefined;
  55049. this._rectangles = [];
  55050. var that = this;
  55051. var metadataError;
  55052. var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  55053. function metadataSuccess(xml) {
  55054. var srs = xml.getElementsByTagName('SRS')[0].textContent;
  55055. if (srs === 'EPSG:4326') {
  55056. that._tilingScheme = new GeographicTilingScheme({ ellipsoid : ellipsoid });
  55057. } else {
  55058. metadataFailure('SRS ' + srs + ' is not supported.');
  55059. return;
  55060. }
  55061. var tileFormat = xml.getElementsByTagName('TileFormat')[0];
  55062. that._heightmapWidth = parseInt(tileFormat.getAttribute('width'), 10);
  55063. that._heightmapHeight = parseInt(tileFormat.getAttribute('height'), 10);
  55064. that._levelZeroMaximumGeometricError = TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(ellipsoid, Math.min(that._heightmapWidth, that._heightmapHeight), that._tilingScheme.getNumberOfXTilesAtLevel(0));
  55065. var dataRectangles = xml.getElementsByTagName('DataExtent');
  55066. for (var i = 0; i < dataRectangles.length; ++i) {
  55067. var dataRectangle = dataRectangles[i];
  55068. var west = CesiumMath.toRadians(parseFloat(dataRectangle.getAttribute('minx')));
  55069. var south = CesiumMath.toRadians(parseFloat(dataRectangle.getAttribute('miny')));
  55070. var east = CesiumMath.toRadians(parseFloat(dataRectangle.getAttribute('maxx')));
  55071. var north = CesiumMath.toRadians(parseFloat(dataRectangle.getAttribute('maxy')));
  55072. var maxLevel = parseInt(dataRectangle.getAttribute('maxlevel'), 10);
  55073. that._rectangles.push(new DataRectangle(new Rectangle(west, south, east, north), maxLevel));
  55074. }
  55075. that._ready = true;
  55076. that._readyPromise.resolve(true);
  55077. }
  55078. function metadataFailure(e) {
  55079. var message = defaultValue(e, 'An error occurred while accessing ' + that._url + '.');
  55080. metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
  55081. }
  55082. function requestMetadata() {
  55083. when(loadXML(that._url), metadataSuccess, metadataFailure);
  55084. }
  55085. requestMetadata();
  55086. }
  55087. defineProperties(VRTheWorldTerrainProvider.prototype, {
  55088. /**
  55089. * Gets an event that is raised when the terrain provider encounters an asynchronous error. By subscribing
  55090. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  55091. * are passed an instance of {@link TileProviderError}.
  55092. * @memberof VRTheWorldTerrainProvider.prototype
  55093. * @type {Event}
  55094. */
  55095. errorEvent : {
  55096. get : function() {
  55097. return this._errorEvent;
  55098. }
  55099. },
  55100. /**
  55101. * Gets the credit to display when this terrain provider is active. Typically this is used to credit
  55102. * the source of the terrain. This function should not be called before {@link VRTheWorldTerrainProvider#ready} returns true.
  55103. * @memberof VRTheWorldTerrainProvider.prototype
  55104. * @type {Credit}
  55105. */
  55106. credit : {
  55107. get : function() {
  55108. return this._credit;
  55109. }
  55110. },
  55111. /**
  55112. * Gets the tiling scheme used by this provider. This function should
  55113. * not be called before {@link VRTheWorldTerrainProvider#ready} returns true.
  55114. * @memberof VRTheWorldTerrainProvider.prototype
  55115. * @type {GeographicTilingScheme}
  55116. */
  55117. tilingScheme : {
  55118. get : function() {
  55119. if (!this.ready) {
  55120. throw new DeveloperError('requestTileGeometry must not be called before ready returns true.');
  55121. }
  55122. return this._tilingScheme;
  55123. }
  55124. },
  55125. /**
  55126. * Gets a value indicating whether or not the provider is ready for use.
  55127. * @memberof VRTheWorldTerrainProvider.prototype
  55128. * @type {Boolean}
  55129. */
  55130. ready : {
  55131. get : function() {
  55132. return this._ready;
  55133. }
  55134. },
  55135. /**
  55136. * Gets a promise that resolves to true when the provider is ready for use.
  55137. * @memberof VRTheWorldTerrainProvider.prototype
  55138. * @type {Promise.<Boolean>}
  55139. * @readonly
  55140. */
  55141. readyPromise : {
  55142. get : function() {
  55143. return this._readyPromise.promise;
  55144. }
  55145. },
  55146. /**
  55147. * Gets a value indicating whether or not the provider includes a water mask. The water mask
  55148. * indicates which areas of the globe are water rather than land, so they can be rendered
  55149. * as a reflective surface with animated waves. This function should not be
  55150. * called before {@link VRTheWorldTerrainProvider#ready} returns true.
  55151. * @memberof VRTheWorldTerrainProvider.prototype
  55152. * @type {Boolean}
  55153. */
  55154. hasWaterMask : {
  55155. get : function() {
  55156. return false;
  55157. }
  55158. },
  55159. /**
  55160. * Gets a value indicating whether or not the requested tiles include vertex normals.
  55161. * This function should not be called before {@link VRTheWorldTerrainProvider#ready} returns true.
  55162. * @memberof VRTheWorldTerrainProvider.prototype
  55163. * @type {Boolean}
  55164. */
  55165. hasVertexNormals : {
  55166. get : function() {
  55167. return false;
  55168. }
  55169. }
  55170. });
  55171. /**
  55172. * Requests the geometry for a given tile. This function should not be called before
  55173. * {@link VRTheWorldTerrainProvider#ready} returns true. The result includes terrain
  55174. * data and indicates that all child tiles are available.
  55175. *
  55176. * @param {Number} x The X coordinate of the tile for which to request geometry.
  55177. * @param {Number} y The Y coordinate of the tile for which to request geometry.
  55178. * @param {Number} level The level of the tile for which to request geometry.
  55179. * @param {Boolean} [throttleRequests=true] True if the number of simultaneous requests should be limited,
  55180. * or false if the request should be initiated regardless of the number of requests
  55181. * already in progress.
  55182. * @returns {Promise.<TerrainData>|undefined} A promise for the requested geometry. If this method
  55183. * returns undefined instead of a promise, it is an indication that too many requests are already
  55184. * pending and the request will be retried later.
  55185. */
  55186. VRTheWorldTerrainProvider.prototype.requestTileGeometry = function(x, y, level, throttleRequests) {
  55187. if (!this.ready) {
  55188. throw new DeveloperError('requestTileGeometry must not be called before ready returns true.');
  55189. }
  55190. var yTiles = this._tilingScheme.getNumberOfYTilesAtLevel(level);
  55191. var url = this._url + level + '/' + x + '/' + (yTiles - y - 1) + '.tif?cesium=true';
  55192. var proxy = this._proxy;
  55193. if (defined(proxy)) {
  55194. url = proxy.getURL(url);
  55195. }
  55196. var promise;
  55197. throttleRequests = defaultValue(throttleRequests, true);
  55198. if (throttleRequests) {
  55199. promise = throttleRequestByServer(url, loadImage);
  55200. if (!defined(promise)) {
  55201. return undefined;
  55202. }
  55203. } else {
  55204. promise = loadImage(url);
  55205. }
  55206. var that = this;
  55207. return when(promise, function(image) {
  55208. return new HeightmapTerrainData({
  55209. buffer : getImagePixels(image),
  55210. width : that._heightmapWidth,
  55211. height : that._heightmapHeight,
  55212. childTileMask : getChildMask(that, x, y, level),
  55213. structure : that._terrainDataStructure
  55214. });
  55215. });
  55216. };
  55217. /**
  55218. * Gets the maximum geometric error allowed in a tile at a given level.
  55219. *
  55220. * @param {Number} level The tile level for which to get the maximum geometric error.
  55221. * @returns {Number} The maximum geometric error.
  55222. */
  55223. VRTheWorldTerrainProvider.prototype.getLevelMaximumGeometricError = function(level) {
  55224. if (!this.ready) {
  55225. throw new DeveloperError('requestTileGeometry must not be called before ready returns true.');
  55226. }
  55227. return this._levelZeroMaximumGeometricError / (1 << level);
  55228. };
  55229. var rectangleScratch = new Rectangle();
  55230. function getChildMask(provider, x, y, level) {
  55231. var tilingScheme = provider._tilingScheme;
  55232. var rectangles = provider._rectangles;
  55233. var parentRectangle = tilingScheme.tileXYToRectangle(x, y, level);
  55234. var childMask = 0;
  55235. for (var i = 0; i < rectangles.length && childMask !== 15; ++i) {
  55236. var rectangle = rectangles[i];
  55237. if (rectangle.maxLevel <= level) {
  55238. continue;
  55239. }
  55240. var testRectangle = rectangle.rectangle;
  55241. var intersection = Rectangle.intersection(testRectangle, parentRectangle, rectangleScratch);
  55242. if (defined(intersection)) {
  55243. // Parent tile is inside this rectangle, so at least one child is, too.
  55244. if (isTileInRectangle(tilingScheme, testRectangle, x * 2, y * 2, level + 1)) {
  55245. childMask |= 4; // northwest
  55246. }
  55247. if (isTileInRectangle(tilingScheme, testRectangle, x * 2 + 1, y * 2, level + 1)) {
  55248. childMask |= 8; // northeast
  55249. }
  55250. if (isTileInRectangle(tilingScheme, testRectangle, x * 2, y * 2 + 1, level + 1)) {
  55251. childMask |= 1; // southwest
  55252. }
  55253. if (isTileInRectangle(tilingScheme, testRectangle, x * 2 + 1, y * 2 + 1, level + 1)) {
  55254. childMask |= 2; // southeast
  55255. }
  55256. }
  55257. }
  55258. return childMask;
  55259. }
  55260. function isTileInRectangle(tilingScheme, rectangle, x, y, level) {
  55261. var tileRectangle = tilingScheme.tileXYToRectangle(x, y, level);
  55262. return defined(Rectangle.intersection(tileRectangle, rectangle, rectangleScratch));
  55263. }
  55264. /**
  55265. * Determines whether data for a tile is available to be loaded.
  55266. *
  55267. * @param {Number} x The X coordinate of the tile for which to request geometry.
  55268. * @param {Number} y The Y coordinate of the tile for which to request geometry.
  55269. * @param {Number} level The level of the tile for which to request geometry.
  55270. * @returns {Boolean} Undefined if not supported, otherwise true or false.
  55271. */
  55272. VRTheWorldTerrainProvider.prototype.getTileDataAvailable = function(x, y, level) {
  55273. return undefined;
  55274. };
  55275. return VRTheWorldTerrainProvider;
  55276. });
  55277. /*global define*/
  55278. define('Core/WallGeometryLibrary',[
  55279. './Cartographic',
  55280. './defined',
  55281. './EllipsoidTangentPlane',
  55282. './Math',
  55283. './PolygonPipeline',
  55284. './PolylinePipeline',
  55285. './WindingOrder'
  55286. ], function(
  55287. Cartographic,
  55288. defined,
  55289. EllipsoidTangentPlane,
  55290. CesiumMath,
  55291. PolygonPipeline,
  55292. PolylinePipeline,
  55293. WindingOrder) {
  55294. 'use strict';
  55295. /**
  55296. * private
  55297. */
  55298. var WallGeometryLibrary = {};
  55299. function latLonEquals(c0, c1) {
  55300. return ((CesiumMath.equalsEpsilon(c0.latitude, c1.latitude, CesiumMath.EPSILON14)) && (CesiumMath.equalsEpsilon(c0.longitude, c1.longitude, CesiumMath.EPSILON14)));
  55301. }
  55302. var scratchCartographic1 = new Cartographic();
  55303. var scratchCartographic2 = new Cartographic();
  55304. function removeDuplicates(ellipsoid, positions, topHeights, bottomHeights) {
  55305. var length = positions.length;
  55306. if (length < 2) {
  55307. return;
  55308. }
  55309. var hasBottomHeights = defined(bottomHeights);
  55310. var hasTopHeights = defined(topHeights);
  55311. var hasAllZeroHeights = true;
  55312. var cleanedPositions = new Array(length);
  55313. var cleanedTopHeights = new Array(length);
  55314. var cleanedBottomHeights = new Array(length);
  55315. var v0 = positions[0];
  55316. cleanedPositions[0] = v0;
  55317. var c0 = ellipsoid.cartesianToCartographic(v0, scratchCartographic1);
  55318. if (hasTopHeights) {
  55319. c0.height = topHeights[0];
  55320. }
  55321. hasAllZeroHeights = hasAllZeroHeights && c0.height <= 0;
  55322. cleanedTopHeights[0] = c0.height;
  55323. if (hasBottomHeights) {
  55324. cleanedBottomHeights[0] = bottomHeights[0];
  55325. } else {
  55326. cleanedBottomHeights[0] = 0.0;
  55327. }
  55328. var index = 1;
  55329. for (var i = 1; i < length; ++i) {
  55330. var v1 = positions[i];
  55331. var c1 = ellipsoid.cartesianToCartographic(v1, scratchCartographic2);
  55332. if (hasTopHeights) {
  55333. c1.height = topHeights[i];
  55334. }
  55335. hasAllZeroHeights = hasAllZeroHeights && c1.height <= 0;
  55336. if (!latLonEquals(c0, c1)) {
  55337. cleanedPositions[index] = v1; // Shallow copy!
  55338. cleanedTopHeights[index] = c1.height;
  55339. if (hasBottomHeights) {
  55340. cleanedBottomHeights[index] = bottomHeights[i];
  55341. } else {
  55342. cleanedBottomHeights[index] = 0.0;
  55343. }
  55344. Cartographic.clone(c1, c0);
  55345. ++index;
  55346. } else if (c0.height < c1.height) {
  55347. cleanedTopHeights[index - 1] = c1.height;
  55348. }
  55349. }
  55350. if (hasAllZeroHeights || index < 2) {
  55351. return;
  55352. }
  55353. cleanedPositions.length = index;
  55354. cleanedTopHeights.length = index;
  55355. cleanedBottomHeights.length = index;
  55356. return {
  55357. positions: cleanedPositions,
  55358. topHeights: cleanedTopHeights,
  55359. bottomHeights: cleanedBottomHeights
  55360. };
  55361. }
  55362. var positionsArrayScratch = new Array(2);
  55363. var heightsArrayScratch = new Array(2);
  55364. var generateArcOptionsScratch = {
  55365. positions : undefined,
  55366. height : undefined,
  55367. granularity : undefined,
  55368. ellipsoid : undefined
  55369. };
  55370. /**
  55371. * @private
  55372. */
  55373. WallGeometryLibrary.computePositions = function(ellipsoid, wallPositions, maximumHeights, minimumHeights, granularity, duplicateCorners) {
  55374. var o = removeDuplicates(ellipsoid, wallPositions, maximumHeights, minimumHeights);
  55375. if (!defined(o)) {
  55376. return;
  55377. }
  55378. wallPositions = o.positions;
  55379. maximumHeights = o.topHeights;
  55380. minimumHeights = o.bottomHeights;
  55381. if (wallPositions.length >= 3) {
  55382. // Order positions counter-clockwise
  55383. var tangentPlane = EllipsoidTangentPlane.fromPoints(wallPositions, ellipsoid);
  55384. var positions2D = tangentPlane.projectPointsOntoPlane(wallPositions);
  55385. if (PolygonPipeline.computeWindingOrder2D(positions2D) === WindingOrder.CLOCKWISE) {
  55386. wallPositions.reverse();
  55387. maximumHeights.reverse();
  55388. minimumHeights.reverse();
  55389. }
  55390. }
  55391. var length = wallPositions.length;
  55392. var numCorners = length - 2;
  55393. var topPositions;
  55394. var bottomPositions;
  55395. var minDistance = CesiumMath.chordLength(granularity, ellipsoid.maximumRadius);
  55396. var generateArcOptions = generateArcOptionsScratch;
  55397. generateArcOptions.minDistance = minDistance;
  55398. generateArcOptions.ellipsoid = ellipsoid;
  55399. if (duplicateCorners) {
  55400. var count = 0;
  55401. var i;
  55402. for (i = 0; i < length - 1; i++) {
  55403. count += PolylinePipeline.numberOfPoints(wallPositions[i], wallPositions[i+1], minDistance) + 1;
  55404. }
  55405. topPositions = new Float64Array(count * 3);
  55406. bottomPositions = new Float64Array(count * 3);
  55407. var generateArcPositions = positionsArrayScratch;
  55408. var generateArcHeights = heightsArrayScratch;
  55409. generateArcOptions.positions = generateArcPositions;
  55410. generateArcOptions.height = generateArcHeights;
  55411. var offset = 0;
  55412. for (i = 0; i < length - 1; i++) {
  55413. generateArcPositions[0] = wallPositions[i];
  55414. generateArcPositions[1] = wallPositions[i + 1];
  55415. generateArcHeights[0] = maximumHeights[i];
  55416. generateArcHeights[1] = maximumHeights[i + 1];
  55417. var pos = PolylinePipeline.generateArc(generateArcOptions);
  55418. topPositions.set(pos, offset);
  55419. generateArcHeights[0] = minimumHeights[i];
  55420. generateArcHeights[1] = minimumHeights[i + 1];
  55421. bottomPositions.set(PolylinePipeline.generateArc(generateArcOptions), offset);
  55422. offset += pos.length;
  55423. }
  55424. } else {
  55425. generateArcOptions.positions = wallPositions;
  55426. generateArcOptions.height = maximumHeights;
  55427. topPositions = new Float64Array(PolylinePipeline.generateArc(generateArcOptions));
  55428. generateArcOptions.height = minimumHeights;
  55429. bottomPositions = new Float64Array(PolylinePipeline.generateArc(generateArcOptions));
  55430. }
  55431. return {
  55432. bottomPositions: bottomPositions,
  55433. topPositions: topPositions,
  55434. numCorners: numCorners
  55435. };
  55436. };
  55437. return WallGeometryLibrary;
  55438. });
  55439. /*global define*/
  55440. define('Core/WallGeometry',[
  55441. './BoundingSphere',
  55442. './Cartesian3',
  55443. './ComponentDatatype',
  55444. './defaultValue',
  55445. './defined',
  55446. './DeveloperError',
  55447. './Ellipsoid',
  55448. './Geometry',
  55449. './GeometryAttribute',
  55450. './GeometryAttributes',
  55451. './IndexDatatype',
  55452. './Math',
  55453. './PrimitiveType',
  55454. './VertexFormat',
  55455. './WallGeometryLibrary'
  55456. ], function(
  55457. BoundingSphere,
  55458. Cartesian3,
  55459. ComponentDatatype,
  55460. defaultValue,
  55461. defined,
  55462. DeveloperError,
  55463. Ellipsoid,
  55464. Geometry,
  55465. GeometryAttribute,
  55466. GeometryAttributes,
  55467. IndexDatatype,
  55468. CesiumMath,
  55469. PrimitiveType,
  55470. VertexFormat,
  55471. WallGeometryLibrary) {
  55472. 'use strict';
  55473. var scratchCartesian3Position1 = new Cartesian3();
  55474. var scratchCartesian3Position2 = new Cartesian3();
  55475. var scratchCartesian3Position3 = new Cartesian3();
  55476. var scratchCartesian3Position4 = new Cartesian3();
  55477. var scratchCartesian3Position5 = new Cartesian3();
  55478. var scratchBinormal = new Cartesian3();
  55479. var scratchTangent = new Cartesian3();
  55480. var scratchNormal = new Cartesian3();
  55481. /**
  55482. * A description of a wall, which is similar to a KML line string. A wall is defined by a series of points,
  55483. * which extrude down to the ground. Optionally, they can extrude downwards to a specified height.
  55484. *
  55485. * @alias WallGeometry
  55486. * @constructor
  55487. *
  55488. * @param {Object} options Object with the following properties:
  55489. * @param {Cartesian3[]} options.positions An array of Cartesian objects, which are the points of the wall.
  55490. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  55491. * @param {Number[]} [options.maximumHeights] An array parallel to <code>positions</code> that give the maximum height of the
  55492. * wall at <code>positions</code>. If undefined, the height of each position in used.
  55493. * @param {Number[]} [options.minimumHeights] An array parallel to <code>positions</code> that give the minimum height of the
  55494. * wall at <code>positions</code>. If undefined, the height at each position is 0.0.
  55495. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid for coordinate manipulation
  55496. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  55497. *
  55498. * @exception {DeveloperError} positions length must be greater than or equal to 2.
  55499. * @exception {DeveloperError} positions and maximumHeights must have the same length.
  55500. * @exception {DeveloperError} positions and minimumHeights must have the same length.
  55501. *
  55502. * @see WallGeometry#createGeometry
  55503. * @see WallGeometry#fromConstantHeight
  55504. *
  55505. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Wall.html|Cesium Sandcastle Wall Demo}
  55506. *
  55507. * @example
  55508. * // create a wall that spans from ground level to 10000 meters
  55509. * var wall = new Cesium.WallGeometry({
  55510. * positions : Cesium.Cartesian3.fromDegreesArrayHeights([
  55511. * 19.0, 47.0, 10000.0,
  55512. * 19.0, 48.0, 10000.0,
  55513. * 20.0, 48.0, 10000.0,
  55514. * 20.0, 47.0, 10000.0,
  55515. * 19.0, 47.0, 10000.0
  55516. * ])
  55517. * });
  55518. * var geometry = Cesium.WallGeometry.createGeometry(wall);
  55519. */
  55520. function WallGeometry(options) {
  55521. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  55522. var wallPositions = options.positions;
  55523. var maximumHeights = options.maximumHeights;
  55524. var minimumHeights = options.minimumHeights;
  55525. if (!defined(wallPositions)) {
  55526. throw new DeveloperError('options.positions is required.');
  55527. }
  55528. if (defined(maximumHeights) && maximumHeights.length !== wallPositions.length) {
  55529. throw new DeveloperError('options.positions and options.maximumHeights must have the same length.');
  55530. }
  55531. if (defined(minimumHeights) && minimumHeights.length !== wallPositions.length) {
  55532. throw new DeveloperError('options.positions and options.minimumHeights must have the same length.');
  55533. }
  55534. var vertexFormat = defaultValue(options.vertexFormat, VertexFormat.DEFAULT);
  55535. var granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  55536. var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  55537. this._positions = wallPositions;
  55538. this._minimumHeights = minimumHeights;
  55539. this._maximumHeights = maximumHeights;
  55540. this._vertexFormat = VertexFormat.clone(vertexFormat);
  55541. this._granularity = granularity;
  55542. this._ellipsoid = Ellipsoid.clone(ellipsoid);
  55543. this._workerName = 'createWallGeometry';
  55544. var numComponents = 1 + wallPositions.length * Cartesian3.packedLength + 2;
  55545. if (defined(minimumHeights)) {
  55546. numComponents += minimumHeights.length;
  55547. }
  55548. if (defined(maximumHeights)) {
  55549. numComponents += maximumHeights.length;
  55550. }
  55551. /**
  55552. * The number of elements used to pack the object into an array.
  55553. * @type {Number}
  55554. */
  55555. this.packedLength = numComponents + Ellipsoid.packedLength + VertexFormat.packedLength + 1;
  55556. }
  55557. /**
  55558. * Stores the provided instance into the provided array.
  55559. *
  55560. * @param {WallGeometry} value The value to pack.
  55561. * @param {Number[]} array The array to pack into.
  55562. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  55563. *
  55564. * @returns {Number[]} The array that was packed into
  55565. */
  55566. WallGeometry.pack = function(value, array, startingIndex) {
  55567. if (!defined(value)) {
  55568. throw new DeveloperError('value is required');
  55569. }
  55570. if (!defined(array)) {
  55571. throw new DeveloperError('array is required');
  55572. }
  55573. startingIndex = defaultValue(startingIndex, 0);
  55574. var i;
  55575. var positions = value._positions;
  55576. var length = positions.length;
  55577. array[startingIndex++] = length;
  55578. for (i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  55579. Cartesian3.pack(positions[i], array, startingIndex);
  55580. }
  55581. var minimumHeights = value._minimumHeights;
  55582. length = defined(minimumHeights) ? minimumHeights.length : 0;
  55583. array[startingIndex++] = length;
  55584. if (defined(minimumHeights)) {
  55585. for (i = 0; i < length; ++i) {
  55586. array[startingIndex++] = minimumHeights[i];
  55587. }
  55588. }
  55589. var maximumHeights = value._maximumHeights;
  55590. length = defined(maximumHeights) ? maximumHeights.length : 0;
  55591. array[startingIndex++] = length;
  55592. if (defined(maximumHeights)) {
  55593. for (i = 0; i < length; ++i) {
  55594. array[startingIndex++] = maximumHeights[i];
  55595. }
  55596. }
  55597. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  55598. startingIndex += Ellipsoid.packedLength;
  55599. VertexFormat.pack(value._vertexFormat, array, startingIndex);
  55600. startingIndex += VertexFormat.packedLength;
  55601. array[startingIndex] = value._granularity;
  55602. return array;
  55603. };
  55604. var scratchEllipsoid = Ellipsoid.clone(Ellipsoid.UNIT_SPHERE);
  55605. var scratchVertexFormat = new VertexFormat();
  55606. var scratchOptions = {
  55607. positions : undefined,
  55608. minimumHeights : undefined,
  55609. maximumHeights : undefined,
  55610. ellipsoid : scratchEllipsoid,
  55611. vertexFormat : scratchVertexFormat,
  55612. granularity : undefined
  55613. };
  55614. /**
  55615. * Retrieves an instance from a packed array.
  55616. *
  55617. * @param {Number[]} array The packed array.
  55618. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  55619. * @param {WallGeometry} [result] The object into which to store the result.
  55620. * @returns {WallGeometry} The modified result parameter or a new WallGeometry instance if one was not provided.
  55621. */
  55622. WallGeometry.unpack = function(array, startingIndex, result) {
  55623. if (!defined(array)) {
  55624. throw new DeveloperError('array is required');
  55625. }
  55626. startingIndex = defaultValue(startingIndex, 0);
  55627. var i;
  55628. var length = array[startingIndex++];
  55629. var positions = new Array(length);
  55630. for (i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  55631. positions[i] = Cartesian3.unpack(array, startingIndex);
  55632. }
  55633. length = array[startingIndex++];
  55634. var minimumHeights;
  55635. if (length > 0) {
  55636. minimumHeights = new Array(length);
  55637. for (i = 0; i < length; ++i) {
  55638. minimumHeights[i] = array[startingIndex++];
  55639. }
  55640. }
  55641. length = array[startingIndex++];
  55642. var maximumHeights;
  55643. if (length > 0) {
  55644. maximumHeights = new Array(length);
  55645. for (i = 0; i < length; ++i) {
  55646. maximumHeights[i] = array[startingIndex++];
  55647. }
  55648. }
  55649. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  55650. startingIndex += Ellipsoid.packedLength;
  55651. var vertexFormat = VertexFormat.unpack(array, startingIndex, scratchVertexFormat);
  55652. startingIndex += VertexFormat.packedLength;
  55653. var granularity = array[startingIndex];
  55654. if (!defined(result)) {
  55655. scratchOptions.positions = positions;
  55656. scratchOptions.minimumHeights = minimumHeights;
  55657. scratchOptions.maximumHeights = maximumHeights;
  55658. scratchOptions.granularity = granularity;
  55659. return new WallGeometry(scratchOptions);
  55660. }
  55661. result._positions = positions;
  55662. result._minimumHeights = minimumHeights;
  55663. result._maximumHeights = maximumHeights;
  55664. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  55665. result._vertexFormat = VertexFormat.clone(vertexFormat, result._vertexFormat);
  55666. result._granularity = granularity;
  55667. return result;
  55668. };
  55669. /**
  55670. * A description of a wall, which is similar to a KML line string. A wall is defined by a series of points,
  55671. * which extrude down to the ground. Optionally, they can extrude downwards to a specified height.
  55672. *
  55673. * @param {Object} options Object with the following properties:
  55674. * @param {Cartesian3[]} options.positions An array of Cartesian objects, which are the points of the wall.
  55675. * @param {Number} [options.maximumHeight] A constant that defines the maximum height of the
  55676. * wall at <code>positions</code>. If undefined, the height of each position in used.
  55677. * @param {Number} [options.minimumHeight] A constant that defines the minimum height of the
  55678. * wall at <code>positions</code>. If undefined, the height at each position is 0.0.
  55679. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid for coordinate manipulation
  55680. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  55681. * @returns {WallGeometry}
  55682. *
  55683. *
  55684. * @example
  55685. * // create a wall that spans from 10000 meters to 20000 meters
  55686. * var wall = Cesium.WallGeometry.fromConstantHeights({
  55687. * positions : Cesium.Cartesian3.fromDegreesArray([
  55688. * 19.0, 47.0,
  55689. * 19.0, 48.0,
  55690. * 20.0, 48.0,
  55691. * 20.0, 47.0,
  55692. * 19.0, 47.0,
  55693. * ]),
  55694. * minimumHeight : 20000.0,
  55695. * maximumHeight : 10000.0
  55696. * });
  55697. * var geometry = Cesium.WallGeometry.createGeometry(wall);
  55698. *
  55699. * @see WallGeometry#createGeometry
  55700. */
  55701. WallGeometry.fromConstantHeights = function(options) {
  55702. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  55703. var positions = options.positions;
  55704. if (!defined(positions)) {
  55705. throw new DeveloperError('options.positions is required.');
  55706. }
  55707. var minHeights;
  55708. var maxHeights;
  55709. var min = options.minimumHeight;
  55710. var max = options.maximumHeight;
  55711. var doMin = defined(min);
  55712. var doMax = defined(max);
  55713. if (doMin || doMax) {
  55714. var length = positions.length;
  55715. minHeights = (doMin) ? new Array(length) : undefined;
  55716. maxHeights = (doMax) ? new Array(length) : undefined;
  55717. for (var i = 0; i < length; ++i) {
  55718. if (doMin) {
  55719. minHeights[i] = min;
  55720. }
  55721. if (doMax) {
  55722. maxHeights[i] = max;
  55723. }
  55724. }
  55725. }
  55726. var newOptions = {
  55727. positions : positions,
  55728. maximumHeights : maxHeights,
  55729. minimumHeights : minHeights,
  55730. ellipsoid : options.ellipsoid,
  55731. vertexFormat : options.vertexFormat
  55732. };
  55733. return new WallGeometry(newOptions);
  55734. };
  55735. /**
  55736. * Computes the geometric representation of a wall, including its vertices, indices, and a bounding sphere.
  55737. *
  55738. * @param {WallGeometry} wallGeometry A description of the wall.
  55739. * @returns {Geometry|undefined} The computed vertices and indices.
  55740. */
  55741. WallGeometry.createGeometry = function(wallGeometry) {
  55742. var wallPositions = wallGeometry._positions;
  55743. var minimumHeights = wallGeometry._minimumHeights;
  55744. var maximumHeights = wallGeometry._maximumHeights;
  55745. var vertexFormat = wallGeometry._vertexFormat;
  55746. var granularity = wallGeometry._granularity;
  55747. var ellipsoid = wallGeometry._ellipsoid;
  55748. var pos = WallGeometryLibrary.computePositions(ellipsoid, wallPositions, maximumHeights, minimumHeights, granularity, true);
  55749. if (!defined(pos)) {
  55750. return;
  55751. }
  55752. var bottomPositions = pos.bottomPositions;
  55753. var topPositions = pos.topPositions;
  55754. var numCorners = pos.numCorners;
  55755. var length = topPositions.length;
  55756. var size = length * 2;
  55757. var positions = vertexFormat.position ? new Float64Array(size) : undefined;
  55758. var normals = vertexFormat.normal ? new Float32Array(size) : undefined;
  55759. var tangents = vertexFormat.tangent ? new Float32Array(size) : undefined;
  55760. var binormals = vertexFormat.binormal ? new Float32Array(size) : undefined;
  55761. var textureCoordinates = vertexFormat.st ? new Float32Array(size / 3 * 2) : undefined;
  55762. var positionIndex = 0;
  55763. var normalIndex = 0;
  55764. var binormalIndex = 0;
  55765. var tangentIndex = 0;
  55766. var stIndex = 0;
  55767. // add lower and upper points one after the other, lower
  55768. // points being even and upper points being odd
  55769. var normal = scratchNormal;
  55770. var tangent = scratchTangent;
  55771. var binormal = scratchBinormal;
  55772. var recomputeNormal = true;
  55773. length /= 3;
  55774. var i;
  55775. var s = 0;
  55776. var ds = 1/(length - wallPositions.length + 1);
  55777. for (i = 0; i < length; ++i) {
  55778. var i3 = i * 3;
  55779. var topPosition = Cartesian3.fromArray(topPositions, i3, scratchCartesian3Position1);
  55780. var bottomPosition = Cartesian3.fromArray(bottomPositions, i3, scratchCartesian3Position2);
  55781. if (vertexFormat.position) {
  55782. // insert the lower point
  55783. positions[positionIndex++] = bottomPosition.x;
  55784. positions[positionIndex++] = bottomPosition.y;
  55785. positions[positionIndex++] = bottomPosition.z;
  55786. // insert the upper point
  55787. positions[positionIndex++] = topPosition.x;
  55788. positions[positionIndex++] = topPosition.y;
  55789. positions[positionIndex++] = topPosition.z;
  55790. }
  55791. if (vertexFormat.st) {
  55792. textureCoordinates[stIndex++] = s;
  55793. textureCoordinates[stIndex++] = 0.0;
  55794. textureCoordinates[stIndex++] = s;
  55795. textureCoordinates[stIndex++] = 1.0;
  55796. }
  55797. if (vertexFormat.normal || vertexFormat.tangent || vertexFormat.binormal) {
  55798. var nextPosition;
  55799. var nextTop = Cartesian3.clone(Cartesian3.ZERO, scratchCartesian3Position5);
  55800. var groundPosition = ellipsoid.scaleToGeodeticSurface(Cartesian3.fromArray(topPositions, i3, scratchCartesian3Position2), scratchCartesian3Position2);
  55801. if (i + 1 < length) {
  55802. nextPosition = ellipsoid.scaleToGeodeticSurface(Cartesian3.fromArray(topPositions, i3 + 3, scratchCartesian3Position3), scratchCartesian3Position3);
  55803. nextTop = Cartesian3.fromArray(topPositions, i3 + 3, scratchCartesian3Position5);
  55804. }
  55805. if (recomputeNormal) {
  55806. var scalednextPosition = Cartesian3.subtract(nextTop, topPosition, scratchCartesian3Position4);
  55807. var scaledGroundPosition = Cartesian3.subtract(groundPosition, topPosition, scratchCartesian3Position1);
  55808. normal = Cartesian3.normalize(Cartesian3.cross(scaledGroundPosition, scalednextPosition, normal), normal);
  55809. recomputeNormal = false;
  55810. }
  55811. if (Cartesian3.equalsEpsilon(nextPosition, groundPosition, CesiumMath.EPSILON10)) {
  55812. recomputeNormal = true;
  55813. } else {
  55814. s += ds;
  55815. if (vertexFormat.tangent) {
  55816. tangent = Cartesian3.normalize(Cartesian3.subtract(nextPosition, groundPosition, tangent), tangent);
  55817. }
  55818. if (vertexFormat.binormal) {
  55819. binormal = Cartesian3.normalize(Cartesian3.cross(normal, tangent, binormal), binormal);
  55820. }
  55821. }
  55822. if (vertexFormat.normal) {
  55823. normals[normalIndex++] = normal.x;
  55824. normals[normalIndex++] = normal.y;
  55825. normals[normalIndex++] = normal.z;
  55826. normals[normalIndex++] = normal.x;
  55827. normals[normalIndex++] = normal.y;
  55828. normals[normalIndex++] = normal.z;
  55829. }
  55830. if (vertexFormat.tangent) {
  55831. tangents[tangentIndex++] = tangent.x;
  55832. tangents[tangentIndex++] = tangent.y;
  55833. tangents[tangentIndex++] = tangent.z;
  55834. tangents[tangentIndex++] = tangent.x;
  55835. tangents[tangentIndex++] = tangent.y;
  55836. tangents[tangentIndex++] = tangent.z;
  55837. }
  55838. if (vertexFormat.binormal) {
  55839. binormals[binormalIndex++] = binormal.x;
  55840. binormals[binormalIndex++] = binormal.y;
  55841. binormals[binormalIndex++] = binormal.z;
  55842. binormals[binormalIndex++] = binormal.x;
  55843. binormals[binormalIndex++] = binormal.y;
  55844. binormals[binormalIndex++] = binormal.z;
  55845. }
  55846. }
  55847. }
  55848. var attributes = new GeometryAttributes();
  55849. if (vertexFormat.position) {
  55850. attributes.position = new GeometryAttribute({
  55851. componentDatatype : ComponentDatatype.DOUBLE,
  55852. componentsPerAttribute : 3,
  55853. values : positions
  55854. });
  55855. }
  55856. if (vertexFormat.normal) {
  55857. attributes.normal = new GeometryAttribute({
  55858. componentDatatype : ComponentDatatype.FLOAT,
  55859. componentsPerAttribute : 3,
  55860. values : normals
  55861. });
  55862. }
  55863. if (vertexFormat.tangent) {
  55864. attributes.tangent = new GeometryAttribute({
  55865. componentDatatype : ComponentDatatype.FLOAT,
  55866. componentsPerAttribute : 3,
  55867. values : tangents
  55868. });
  55869. }
  55870. if (vertexFormat.binormal) {
  55871. attributes.binormal = new GeometryAttribute({
  55872. componentDatatype : ComponentDatatype.FLOAT,
  55873. componentsPerAttribute : 3,
  55874. values : binormals
  55875. });
  55876. }
  55877. if (vertexFormat.st) {
  55878. attributes.st = new GeometryAttribute({
  55879. componentDatatype : ComponentDatatype.FLOAT,
  55880. componentsPerAttribute : 2,
  55881. values : textureCoordinates
  55882. });
  55883. }
  55884. // prepare the side walls, two triangles for each wall
  55885. //
  55886. // A (i+1) B (i+3) E
  55887. // +--------+-------+
  55888. // | / | /| triangles: A C B
  55889. // | / | / | B C D
  55890. // | / | / |
  55891. // | / | / |
  55892. // | / | / |
  55893. // | / | / |
  55894. // +--------+-------+
  55895. // C (i) D (i+2) F
  55896. //
  55897. var numVertices = size / 3;
  55898. size -= 6 * (numCorners + 1);
  55899. var indices = IndexDatatype.createTypedArray(numVertices, size);
  55900. var edgeIndex = 0;
  55901. for (i = 0; i < numVertices - 2; i += 2) {
  55902. var LL = i;
  55903. var LR = i + 2;
  55904. var pl = Cartesian3.fromArray(positions, LL * 3, scratchCartesian3Position1);
  55905. var pr = Cartesian3.fromArray(positions, LR * 3, scratchCartesian3Position2);
  55906. if (Cartesian3.equalsEpsilon(pl, pr, CesiumMath.EPSILON10)) {
  55907. continue;
  55908. }
  55909. var UL = i + 1;
  55910. var UR = i + 3;
  55911. indices[edgeIndex++] = UL;
  55912. indices[edgeIndex++] = LL;
  55913. indices[edgeIndex++] = UR;
  55914. indices[edgeIndex++] = UR;
  55915. indices[edgeIndex++] = LL;
  55916. indices[edgeIndex++] = LR;
  55917. }
  55918. return new Geometry({
  55919. attributes : attributes,
  55920. indices : indices,
  55921. primitiveType : PrimitiveType.TRIANGLES,
  55922. boundingSphere : new BoundingSphere.fromVertices(positions)
  55923. });
  55924. };
  55925. return WallGeometry;
  55926. });
  55927. /*global define*/
  55928. define('Core/WallOutlineGeometry',[
  55929. './BoundingSphere',
  55930. './Cartesian3',
  55931. './ComponentDatatype',
  55932. './defaultValue',
  55933. './defined',
  55934. './DeveloperError',
  55935. './Ellipsoid',
  55936. './Geometry',
  55937. './GeometryAttribute',
  55938. './GeometryAttributes',
  55939. './IndexDatatype',
  55940. './Math',
  55941. './PrimitiveType',
  55942. './WallGeometryLibrary'
  55943. ], function(
  55944. BoundingSphere,
  55945. Cartesian3,
  55946. ComponentDatatype,
  55947. defaultValue,
  55948. defined,
  55949. DeveloperError,
  55950. Ellipsoid,
  55951. Geometry,
  55952. GeometryAttribute,
  55953. GeometryAttributes,
  55954. IndexDatatype,
  55955. CesiumMath,
  55956. PrimitiveType,
  55957. WallGeometryLibrary) {
  55958. 'use strict';
  55959. var scratchCartesian3Position1 = new Cartesian3();
  55960. var scratchCartesian3Position2 = new Cartesian3();
  55961. /**
  55962. * A description of a wall outline. A wall is defined by a series of points,
  55963. * which extrude down to the ground. Optionally, they can extrude downwards to a specified height.
  55964. *
  55965. * @alias WallOutlineGeometry
  55966. * @constructor
  55967. *
  55968. * @param {Object} options Object with the following properties:
  55969. * @param {Cartesian3[]} options.positions An array of Cartesian objects, which are the points of the wall.
  55970. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  55971. * @param {Number[]} [options.maximumHeights] An array parallel to <code>positions</code> that give the maximum height of the
  55972. * wall at <code>positions</code>. If undefined, the height of each position in used.
  55973. * @param {Number[]} [options.minimumHeights] An array parallel to <code>positions</code> that give the minimum height of the
  55974. * wall at <code>positions</code>. If undefined, the height at each position is 0.0.
  55975. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid for coordinate manipulation
  55976. *
  55977. * @exception {DeveloperError} positions length must be greater than or equal to 2.
  55978. * @exception {DeveloperError} positions and maximumHeights must have the same length.
  55979. * @exception {DeveloperError} positions and minimumHeights must have the same length.
  55980. *
  55981. * @see WallGeometry#createGeometry
  55982. * @see WallGeometry#fromConstantHeight
  55983. *
  55984. * @example
  55985. * // create a wall outline that spans from ground level to 10000 meters
  55986. * var wall = new Cesium.WallOutlineGeometry({
  55987. * positions : Cesium.Cartesian3.fromDegreesArrayHeights([
  55988. * 19.0, 47.0, 10000.0,
  55989. * 19.0, 48.0, 10000.0,
  55990. * 20.0, 48.0, 10000.0,
  55991. * 20.0, 47.0, 10000.0,
  55992. * 19.0, 47.0, 10000.0
  55993. * ])
  55994. * });
  55995. * var geometry = Cesium.WallOutlineGeometry.createGeometry(wall);
  55996. */
  55997. function WallOutlineGeometry(options) {
  55998. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  55999. var wallPositions = options.positions;
  56000. var maximumHeights = options.maximumHeights;
  56001. var minimumHeights = options.minimumHeights;
  56002. if (!defined(wallPositions)) {
  56003. throw new DeveloperError('options.positions is required.');
  56004. }
  56005. if (defined(maximumHeights) && maximumHeights.length !== wallPositions.length) {
  56006. throw new DeveloperError('options.positions and options.maximumHeights must have the same length.');
  56007. }
  56008. if (defined(minimumHeights) && minimumHeights.length !== wallPositions.length) {
  56009. throw new DeveloperError('options.positions and options.minimumHeights must have the same length.');
  56010. }
  56011. var granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  56012. var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  56013. this._positions = wallPositions;
  56014. this._minimumHeights = minimumHeights;
  56015. this._maximumHeights = maximumHeights;
  56016. this._granularity = granularity;
  56017. this._ellipsoid = Ellipsoid.clone(ellipsoid);
  56018. this._workerName = 'createWallOutlineGeometry';
  56019. var numComponents = 1 + wallPositions.length * Cartesian3.packedLength + 2;
  56020. if (defined(minimumHeights)) {
  56021. numComponents += minimumHeights.length;
  56022. }
  56023. if (defined(maximumHeights)) {
  56024. numComponents += maximumHeights.length;
  56025. }
  56026. /**
  56027. * The number of elements used to pack the object into an array.
  56028. * @type {Number}
  56029. */
  56030. this.packedLength = numComponents + Ellipsoid.packedLength + 1;
  56031. }
  56032. /**
  56033. * Stores the provided instance into the provided array.
  56034. *
  56035. * @param {WallOutlineGeometry} value The value to pack.
  56036. * @param {Number[]} array The array to pack into.
  56037. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  56038. *
  56039. * @returns {Number[]} The array that was packed into
  56040. */
  56041. WallOutlineGeometry.pack = function(value, array, startingIndex) {
  56042. if (!defined(value)) {
  56043. throw new DeveloperError('value is required');
  56044. }
  56045. if (!defined(array)) {
  56046. throw new DeveloperError('array is required');
  56047. }
  56048. startingIndex = defaultValue(startingIndex, 0);
  56049. var i;
  56050. var positions = value._positions;
  56051. var length = positions.length;
  56052. array[startingIndex++] = length;
  56053. for (i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  56054. Cartesian3.pack(positions[i], array, startingIndex);
  56055. }
  56056. var minimumHeights = value._minimumHeights;
  56057. length = defined(minimumHeights) ? minimumHeights.length : 0;
  56058. array[startingIndex++] = length;
  56059. if (defined(minimumHeights)) {
  56060. for (i = 0; i < length; ++i) {
  56061. array[startingIndex++] = minimumHeights[i];
  56062. }
  56063. }
  56064. var maximumHeights = value._maximumHeights;
  56065. length = defined(maximumHeights) ? maximumHeights.length : 0;
  56066. array[startingIndex++] = length;
  56067. if (defined(maximumHeights)) {
  56068. for (i = 0; i < length; ++i) {
  56069. array[startingIndex++] = maximumHeights[i];
  56070. }
  56071. }
  56072. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  56073. startingIndex += Ellipsoid.packedLength;
  56074. array[startingIndex] = value._granularity;
  56075. return array;
  56076. };
  56077. var scratchEllipsoid = Ellipsoid.clone(Ellipsoid.UNIT_SPHERE);
  56078. var scratchOptions = {
  56079. positions : undefined,
  56080. minimumHeights : undefined,
  56081. maximumHeights : undefined,
  56082. ellipsoid : scratchEllipsoid,
  56083. granularity : undefined
  56084. };
  56085. /**
  56086. * Retrieves an instance from a packed array.
  56087. *
  56088. * @param {Number[]} array The packed array.
  56089. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  56090. * @param {WallOutlineGeometry} [result] The object into which to store the result.
  56091. * @returns {WallOutlineGeometry} The modified result parameter or a new WallOutlineGeometry instance if one was not provided.
  56092. */
  56093. WallOutlineGeometry.unpack = function(array, startingIndex, result) {
  56094. if (!defined(array)) {
  56095. throw new DeveloperError('array is required');
  56096. }
  56097. startingIndex = defaultValue(startingIndex, 0);
  56098. var i;
  56099. var length = array[startingIndex++];
  56100. var positions = new Array(length);
  56101. for (i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) {
  56102. positions[i] = Cartesian3.unpack(array, startingIndex);
  56103. }
  56104. length = array[startingIndex++];
  56105. var minimumHeights;
  56106. if (length > 0) {
  56107. minimumHeights = new Array(length);
  56108. for (i = 0; i < length; ++i) {
  56109. minimumHeights[i] = array[startingIndex++];
  56110. }
  56111. }
  56112. length = array[startingIndex++];
  56113. var maximumHeights;
  56114. if (length > 0) {
  56115. maximumHeights = new Array(length);
  56116. for (i = 0; i < length; ++i) {
  56117. maximumHeights[i] = array[startingIndex++];
  56118. }
  56119. }
  56120. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  56121. startingIndex += Ellipsoid.packedLength;
  56122. var granularity = array[startingIndex];
  56123. if (!defined(result)) {
  56124. scratchOptions.positions = positions;
  56125. scratchOptions.minimumHeights = minimumHeights;
  56126. scratchOptions.maximumHeights = maximumHeights;
  56127. scratchOptions.granularity = granularity;
  56128. return new WallOutlineGeometry(scratchOptions);
  56129. }
  56130. result._positions = positions;
  56131. result._minimumHeights = minimumHeights;
  56132. result._maximumHeights = maximumHeights;
  56133. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  56134. result._granularity = granularity;
  56135. return result;
  56136. };
  56137. /**
  56138. * A description of a walloutline. A wall is defined by a series of points,
  56139. * which extrude down to the ground. Optionally, they can extrude downwards to a specified height.
  56140. *
  56141. * @param {Object} options Object with the following properties:
  56142. * @param {Cartesian3[]} options.positions An array of Cartesian objects, which are the points of the wall.
  56143. * @param {Number} [options.maximumHeight] A constant that defines the maximum height of the
  56144. * wall at <code>positions</code>. If undefined, the height of each position in used.
  56145. * @param {Number} [options.minimumHeight] A constant that defines the minimum height of the
  56146. * wall at <code>positions</code>. If undefined, the height at each position is 0.0.
  56147. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid for coordinate manipulation
  56148. * @returns {WallOutlineGeometry}
  56149. *
  56150. *
  56151. * @example
  56152. * // create a wall that spans from 10000 meters to 20000 meters
  56153. * var wall = Cesium.WallOutlineGeometry.fromConstantHeights({
  56154. * positions : Cesium.Cartesian3.fromDegreesArray([
  56155. * 19.0, 47.0,
  56156. * 19.0, 48.0,
  56157. * 20.0, 48.0,
  56158. * 20.0, 47.0,
  56159. * 19.0, 47.0,
  56160. * ]),
  56161. * minimumHeight : 20000.0,
  56162. * maximumHeight : 10000.0
  56163. * });
  56164. * var geometry = Cesium.WallOutlineGeometry.createGeometry(wall);
  56165. *
  56166. * @see WallOutlineGeometry#createGeometry
  56167. */
  56168. WallOutlineGeometry.fromConstantHeights = function(options) {
  56169. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  56170. var positions = options.positions;
  56171. if (!defined(positions)) {
  56172. throw new DeveloperError('options.positions is required.');
  56173. }
  56174. var minHeights;
  56175. var maxHeights;
  56176. var min = options.minimumHeight;
  56177. var max = options.maximumHeight;
  56178. var doMin = defined(min);
  56179. var doMax = defined(max);
  56180. if (doMin || doMax) {
  56181. var length = positions.length;
  56182. minHeights = (doMin) ? new Array(length) : undefined;
  56183. maxHeights = (doMax) ? new Array(length) : undefined;
  56184. for (var i = 0; i < length; ++i) {
  56185. if (doMin) {
  56186. minHeights[i] = min;
  56187. }
  56188. if (doMax) {
  56189. maxHeights[i] = max;
  56190. }
  56191. }
  56192. }
  56193. var newOptions = {
  56194. positions : positions,
  56195. maximumHeights : maxHeights,
  56196. minimumHeights : minHeights,
  56197. ellipsoid : options.ellipsoid
  56198. };
  56199. return new WallOutlineGeometry(newOptions);
  56200. };
  56201. /**
  56202. * Computes the geometric representation of a wall outline, including its vertices, indices, and a bounding sphere.
  56203. *
  56204. * @param {WallOutlineGeometry} wallGeometry A description of the wall outline.
  56205. * @returns {Geometry|undefined} The computed vertices and indices.
  56206. */
  56207. WallOutlineGeometry.createGeometry = function(wallGeometry) {
  56208. var wallPositions = wallGeometry._positions;
  56209. var minimumHeights = wallGeometry._minimumHeights;
  56210. var maximumHeights = wallGeometry._maximumHeights;
  56211. var granularity = wallGeometry._granularity;
  56212. var ellipsoid = wallGeometry._ellipsoid;
  56213. var pos = WallGeometryLibrary.computePositions(ellipsoid, wallPositions, maximumHeights, minimumHeights, granularity, false);
  56214. if (!defined(pos)) {
  56215. return;
  56216. }
  56217. var bottomPositions = pos.bottomPositions;
  56218. var topPositions = pos.topPositions;
  56219. var length = topPositions.length;
  56220. var size = length * 2;
  56221. var positions = new Float64Array(size);
  56222. var positionIndex = 0;
  56223. // add lower and upper points one after the other, lower
  56224. // points being even and upper points being odd
  56225. length /= 3;
  56226. var i;
  56227. for (i = 0; i < length; ++i) {
  56228. var i3 = i * 3;
  56229. var topPosition = Cartesian3.fromArray(topPositions, i3, scratchCartesian3Position1);
  56230. var bottomPosition = Cartesian3.fromArray(bottomPositions, i3, scratchCartesian3Position2);
  56231. // insert the lower point
  56232. positions[positionIndex++] = bottomPosition.x;
  56233. positions[positionIndex++] = bottomPosition.y;
  56234. positions[positionIndex++] = bottomPosition.z;
  56235. // insert the upper point
  56236. positions[positionIndex++] = topPosition.x;
  56237. positions[positionIndex++] = topPosition.y;
  56238. positions[positionIndex++] = topPosition.z;
  56239. }
  56240. var attributes = new GeometryAttributes({
  56241. position : new GeometryAttribute({
  56242. componentDatatype : ComponentDatatype.DOUBLE,
  56243. componentsPerAttribute : 3,
  56244. values : positions
  56245. })
  56246. });
  56247. var numVertices = size / 3;
  56248. size = 2 * numVertices - 4 + numVertices;
  56249. var indices = IndexDatatype.createTypedArray(numVertices, size);
  56250. var edgeIndex = 0;
  56251. for (i = 0; i < numVertices - 2; i += 2) {
  56252. var LL = i;
  56253. var LR = i + 2;
  56254. var pl = Cartesian3.fromArray(positions, LL * 3, scratchCartesian3Position1);
  56255. var pr = Cartesian3.fromArray(positions, LR * 3, scratchCartesian3Position2);
  56256. if (Cartesian3.equalsEpsilon(pl, pr, CesiumMath.EPSILON10)) {
  56257. continue;
  56258. }
  56259. var UL = i + 1;
  56260. var UR = i + 3;
  56261. indices[edgeIndex++] = UL;
  56262. indices[edgeIndex++] = LL;
  56263. indices[edgeIndex++] = UL;
  56264. indices[edgeIndex++] = UR;
  56265. indices[edgeIndex++] = LL;
  56266. indices[edgeIndex++] = LR;
  56267. }
  56268. indices[edgeIndex++] = numVertices - 2;
  56269. indices[edgeIndex++] = numVertices - 1;
  56270. return new Geometry({
  56271. attributes : attributes,
  56272. indices : indices,
  56273. primitiveType : PrimitiveType.LINES,
  56274. boundingSphere : new BoundingSphere.fromVertices(positions)
  56275. });
  56276. };
  56277. return WallOutlineGeometry;
  56278. });
  56279. /*global define*/
  56280. define('Core/WebMercatorTilingScheme',[
  56281. './Cartesian2',
  56282. './defaultValue',
  56283. './defined',
  56284. './defineProperties',
  56285. './Ellipsoid',
  56286. './Rectangle',
  56287. './WebMercatorProjection'
  56288. ], function(
  56289. Cartesian2,
  56290. defaultValue,
  56291. defined,
  56292. defineProperties,
  56293. Ellipsoid,
  56294. Rectangle,
  56295. WebMercatorProjection) {
  56296. 'use strict';
  56297. /**
  56298. * A tiling scheme for geometry referenced to a {@link WebMercatorProjection}, EPSG:3857. This is
  56299. * the tiling scheme used by Google Maps, Microsoft Bing Maps, and most of ESRI ArcGIS Online.
  56300. *
  56301. * @alias WebMercatorTilingScheme
  56302. * @constructor
  56303. *
  56304. * @param {Object} [options] Object with the following properties:
  56305. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid whose surface is being tiled. Defaults to
  56306. * the WGS84 ellipsoid.
  56307. * @param {Number} [options.numberOfLevelZeroTilesX=1] The number of tiles in the X direction at level zero of
  56308. * the tile tree.
  56309. * @param {Number} [options.numberOfLevelZeroTilesY=1] The number of tiles in the Y direction at level zero of
  56310. * the tile tree.
  56311. * @param {Cartesian2} [options.rectangleSouthwestInMeters] The southwest corner of the rectangle covered by the
  56312. * tiling scheme, in meters. If this parameter or rectangleNortheastInMeters is not specified, the entire
  56313. * globe is covered in the longitude direction and an equal distance is covered in the latitude
  56314. * direction, resulting in a square projection.
  56315. * @param {Cartesian2} [options.rectangleNortheastInMeters] The northeast corner of the rectangle covered by the
  56316. * tiling scheme, in meters. If this parameter or rectangleSouthwestInMeters is not specified, the entire
  56317. * globe is covered in the longitude direction and an equal distance is covered in the latitude
  56318. * direction, resulting in a square projection.
  56319. */
  56320. function WebMercatorTilingScheme(options) {
  56321. options = defaultValue(options, {});
  56322. this._ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  56323. this._numberOfLevelZeroTilesX = defaultValue(options.numberOfLevelZeroTilesX, 1);
  56324. this._numberOfLevelZeroTilesY = defaultValue(options.numberOfLevelZeroTilesY, 1);
  56325. this._projection = new WebMercatorProjection(this._ellipsoid);
  56326. if (defined(options.rectangleSouthwestInMeters) &&
  56327. defined(options.rectangleNortheastInMeters)) {
  56328. this._rectangleSouthwestInMeters = options.rectangleSouthwestInMeters;
  56329. this._rectangleNortheastInMeters = options.rectangleNortheastInMeters;
  56330. } else {
  56331. var semimajorAxisTimesPi = this._ellipsoid.maximumRadius * Math.PI;
  56332. this._rectangleSouthwestInMeters = new Cartesian2(-semimajorAxisTimesPi, -semimajorAxisTimesPi);
  56333. this._rectangleNortheastInMeters = new Cartesian2(semimajorAxisTimesPi, semimajorAxisTimesPi);
  56334. }
  56335. var southwest = this._projection.unproject(this._rectangleSouthwestInMeters);
  56336. var northeast = this._projection.unproject(this._rectangleNortheastInMeters);
  56337. this._rectangle = new Rectangle(southwest.longitude, southwest.latitude,
  56338. northeast.longitude, northeast.latitude);
  56339. }
  56340. defineProperties(WebMercatorTilingScheme.prototype, {
  56341. /**
  56342. * Gets the ellipsoid that is tiled by this tiling scheme.
  56343. * @memberof WebMercatorTilingScheme.prototype
  56344. * @type {Ellipsoid}
  56345. */
  56346. ellipsoid : {
  56347. get : function() {
  56348. return this._ellipsoid;
  56349. }
  56350. },
  56351. /**
  56352. * Gets the rectangle, in radians, covered by this tiling scheme.
  56353. * @memberof WebMercatorTilingScheme.prototype
  56354. * @type {Rectangle}
  56355. */
  56356. rectangle : {
  56357. get : function() {
  56358. return this._rectangle;
  56359. }
  56360. },
  56361. /**
  56362. * Gets the map projection used by this tiling scheme.
  56363. * @memberof WebMercatorTilingScheme.prototype
  56364. * @type {MapProjection}
  56365. */
  56366. projection : {
  56367. get : function() {
  56368. return this._projection;
  56369. }
  56370. }
  56371. });
  56372. /**
  56373. * Gets the total number of tiles in the X direction at a specified level-of-detail.
  56374. *
  56375. * @param {Number} level The level-of-detail.
  56376. * @returns {Number} The number of tiles in the X direction at the given level.
  56377. */
  56378. WebMercatorTilingScheme.prototype.getNumberOfXTilesAtLevel = function(level) {
  56379. return this._numberOfLevelZeroTilesX << level;
  56380. };
  56381. /**
  56382. * Gets the total number of tiles in the Y direction at a specified level-of-detail.
  56383. *
  56384. * @param {Number} level The level-of-detail.
  56385. * @returns {Number} The number of tiles in the Y direction at the given level.
  56386. */
  56387. WebMercatorTilingScheme.prototype.getNumberOfYTilesAtLevel = function(level) {
  56388. return this._numberOfLevelZeroTilesY << level;
  56389. };
  56390. /**
  56391. * Transforms an rectangle specified in geodetic radians to the native coordinate system
  56392. * of this tiling scheme.
  56393. *
  56394. * @param {Rectangle} rectangle The rectangle to transform.
  56395. * @param {Rectangle} [result] The instance to which to copy the result, or undefined if a new instance
  56396. * should be created.
  56397. * @returns {Rectangle} The specified 'result', or a new object containing the native rectangle if 'result'
  56398. * is undefined.
  56399. */
  56400. WebMercatorTilingScheme.prototype.rectangleToNativeRectangle = function(rectangle, result) {
  56401. var projection = this._projection;
  56402. var southwest = projection.project(Rectangle.southwest(rectangle));
  56403. var northeast = projection.project(Rectangle.northeast(rectangle));
  56404. if (!defined(result)) {
  56405. return new Rectangle(southwest.x, southwest.y, northeast.x, northeast.y);
  56406. }
  56407. result.west = southwest.x;
  56408. result.south = southwest.y;
  56409. result.east = northeast.x;
  56410. result.north = northeast.y;
  56411. return result;
  56412. };
  56413. /**
  56414. * Converts tile x, y coordinates and level to an rectangle expressed in the native coordinates
  56415. * of the tiling scheme.
  56416. *
  56417. * @param {Number} x The integer x coordinate of the tile.
  56418. * @param {Number} y The integer y coordinate of the tile.
  56419. * @param {Number} level The tile level-of-detail. Zero is the least detailed.
  56420. * @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
  56421. * should be created.
  56422. * @returns {Rectangle} The specified 'result', or a new object containing the rectangle
  56423. * if 'result' is undefined.
  56424. */
  56425. WebMercatorTilingScheme.prototype.tileXYToNativeRectangle = function(x, y, level, result) {
  56426. var xTiles = this.getNumberOfXTilesAtLevel(level);
  56427. var yTiles = this.getNumberOfYTilesAtLevel(level);
  56428. var xTileWidth = (this._rectangleNortheastInMeters.x - this._rectangleSouthwestInMeters.x) / xTiles;
  56429. var west = this._rectangleSouthwestInMeters.x + x * xTileWidth;
  56430. var east = this._rectangleSouthwestInMeters.x + (x + 1) * xTileWidth;
  56431. var yTileHeight = (this._rectangleNortheastInMeters.y - this._rectangleSouthwestInMeters.y) / yTiles;
  56432. var north = this._rectangleNortheastInMeters.y - y * yTileHeight;
  56433. var south = this._rectangleNortheastInMeters.y - (y + 1) * yTileHeight;
  56434. if (!defined(result)) {
  56435. return new Rectangle(west, south, east, north);
  56436. }
  56437. result.west = west;
  56438. result.south = south;
  56439. result.east = east;
  56440. result.north = north;
  56441. return result;
  56442. };
  56443. /**
  56444. * Converts tile x, y coordinates and level to a cartographic rectangle in radians.
  56445. *
  56446. * @param {Number} x The integer x coordinate of the tile.
  56447. * @param {Number} y The integer y coordinate of the tile.
  56448. * @param {Number} level The tile level-of-detail. Zero is the least detailed.
  56449. * @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
  56450. * should be created.
  56451. * @returns {Rectangle} The specified 'result', or a new object containing the rectangle
  56452. * if 'result' is undefined.
  56453. */
  56454. WebMercatorTilingScheme.prototype.tileXYToRectangle = function(x, y, level, result) {
  56455. var nativeRectangle = this.tileXYToNativeRectangle(x, y, level, result);
  56456. var projection = this._projection;
  56457. var southwest = projection.unproject(new Cartesian2(nativeRectangle.west, nativeRectangle.south));
  56458. var northeast = projection.unproject(new Cartesian2(nativeRectangle.east, nativeRectangle.north));
  56459. nativeRectangle.west = southwest.longitude;
  56460. nativeRectangle.south = southwest.latitude;
  56461. nativeRectangle.east = northeast.longitude;
  56462. nativeRectangle.north = northeast.latitude;
  56463. return nativeRectangle;
  56464. };
  56465. /**
  56466. * Calculates the tile x, y coordinates of the tile containing
  56467. * a given cartographic position.
  56468. *
  56469. * @param {Cartographic} position The position.
  56470. * @param {Number} level The tile level-of-detail. Zero is the least detailed.
  56471. * @param {Cartesian2} [result] The instance to which to copy the result, or undefined if a new instance
  56472. * should be created.
  56473. * @returns {Cartesian2} The specified 'result', or a new object containing the tile x, y coordinates
  56474. * if 'result' is undefined.
  56475. */
  56476. WebMercatorTilingScheme.prototype.positionToTileXY = function(position, level, result) {
  56477. var rectangle = this._rectangle;
  56478. if (!Rectangle.contains(rectangle, position)) {
  56479. // outside the bounds of the tiling scheme
  56480. return undefined;
  56481. }
  56482. var xTiles = this.getNumberOfXTilesAtLevel(level);
  56483. var yTiles = this.getNumberOfYTilesAtLevel(level);
  56484. var overallWidth = this._rectangleNortheastInMeters.x - this._rectangleSouthwestInMeters.x;
  56485. var xTileWidth = overallWidth / xTiles;
  56486. var overallHeight = this._rectangleNortheastInMeters.y - this._rectangleSouthwestInMeters.y;
  56487. var yTileHeight = overallHeight / yTiles;
  56488. var projection = this._projection;
  56489. var webMercatorPosition = projection.project(position);
  56490. var distanceFromWest = webMercatorPosition.x - this._rectangleSouthwestInMeters.x;
  56491. var distanceFromNorth = this._rectangleNortheastInMeters.y - webMercatorPosition.y;
  56492. var xTileCoordinate = distanceFromWest / xTileWidth | 0;
  56493. if (xTileCoordinate >= xTiles) {
  56494. xTileCoordinate = xTiles - 1;
  56495. }
  56496. var yTileCoordinate = distanceFromNorth / yTileHeight | 0;
  56497. if (yTileCoordinate >= yTiles) {
  56498. yTileCoordinate = yTiles - 1;
  56499. }
  56500. if (!defined(result)) {
  56501. return new Cartesian2(xTileCoordinate, yTileCoordinate);
  56502. }
  56503. result.x = xTileCoordinate;
  56504. result.y = yTileCoordinate;
  56505. return result;
  56506. };
  56507. return WebMercatorTilingScheme;
  56508. });
  56509. /*global define*/
  56510. define('Core/wrapFunction',[
  56511. './DeveloperError'
  56512. ], function(
  56513. DeveloperError) {
  56514. 'use strict';
  56515. /**
  56516. * Wraps a function on the provided objects with another function called in the
  56517. * object's context so that the new function is always called immediately
  56518. * before the old one.
  56519. *
  56520. * @private
  56521. */
  56522. function wrapFunction(obj, oldFunction, newFunction) {
  56523. if (typeof oldFunction !== 'function') {
  56524. throw new DeveloperError("oldFunction is required to be a function.");
  56525. }
  56526. if (typeof newFunction !== 'function') {
  56527. throw new DeveloperError("oldFunction is required to be a function.");
  56528. }
  56529. return function() {
  56530. newFunction.apply(obj, arguments);
  56531. oldFunction.apply(obj, arguments);
  56532. };
  56533. }
  56534. return wrapFunction;
  56535. });
  56536. /*global define*/
  56537. define('DataSources/ConstantProperty',[
  56538. '../Core/defined',
  56539. '../Core/defineProperties',
  56540. '../Core/Event'
  56541. ], function(
  56542. defined,
  56543. defineProperties,
  56544. Event) {
  56545. 'use strict';
  56546. /**
  56547. * A {@link Property} whose value does not change with respect to simulation time.
  56548. *
  56549. * @alias ConstantProperty
  56550. * @constructor
  56551. *
  56552. * @param {Object} [value] The property value.
  56553. *
  56554. * @see ConstantPositionProperty
  56555. *
  56556. * @exception {DeveloperError} value.clone is a required function.
  56557. * @exception {DeveloperError} value.equals is a required function.
  56558. */
  56559. function ConstantProperty(value) {
  56560. this._value = undefined;
  56561. this._hasClone = false;
  56562. this._hasEquals = false;
  56563. this._definitionChanged = new Event();
  56564. this.setValue(value);
  56565. }
  56566. defineProperties(ConstantProperty.prototype, {
  56567. /**
  56568. * Gets a value indicating if this property is constant.
  56569. * This property always returns <code>true</code>.
  56570. * @memberof ConstantProperty.prototype
  56571. *
  56572. * @type {Boolean}
  56573. * @readonly
  56574. */
  56575. isConstant : {
  56576. value : true
  56577. },
  56578. /**
  56579. * Gets the event that is raised whenever the definition of this property changes.
  56580. * The definition is changed whenever setValue is called with data different
  56581. * than the current value.
  56582. * @memberof ConstantProperty.prototype
  56583. *
  56584. * @type {Event}
  56585. * @readonly
  56586. */
  56587. definitionChanged : {
  56588. get : function() {
  56589. return this._definitionChanged;
  56590. }
  56591. }
  56592. });
  56593. /**
  56594. * Gets the value of the property.
  56595. *
  56596. * @param {JulianDate} [time] The time for which to retrieve the value. This parameter is unused since the value does not change with respect to time.
  56597. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  56598. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  56599. */
  56600. ConstantProperty.prototype.getValue = function(time, result) {
  56601. return this._hasClone ? this._value.clone(result) : this._value;
  56602. };
  56603. /**
  56604. * Sets the value of the property.
  56605. *
  56606. * @param {Object} value The property value.
  56607. *
  56608. * @exception {DeveloperError} value.clone is a required function.
  56609. * @exception {DeveloperError} value.equals is a required function.
  56610. */
  56611. ConstantProperty.prototype.setValue = function(value) {
  56612. var oldValue = this._value;
  56613. if (oldValue !== value) {
  56614. var isDefined = defined(value);
  56615. var hasClone = isDefined && typeof value.clone === 'function';
  56616. var hasEquals = isDefined && typeof value.equals === 'function';
  56617. this._hasClone = hasClone;
  56618. this._hasEquals = hasEquals;
  56619. var changed = !hasEquals || !value.equals(oldValue);
  56620. if (changed) {
  56621. this._value = !hasClone ? value : value.clone();
  56622. this._definitionChanged.raiseEvent(this);
  56623. }
  56624. }
  56625. };
  56626. /**
  56627. * Compares this property to the provided property and returns
  56628. * <code>true</code> if they are equal, <code>false</code> otherwise.
  56629. *
  56630. * @param {Property} [other] The other property.
  56631. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  56632. */
  56633. ConstantProperty.prototype.equals = function(other) {
  56634. return this === other || //
  56635. (other instanceof ConstantProperty && //
  56636. ((!this._hasEquals && (this._value === other._value)) || //
  56637. (this._hasEquals && this._value.equals(other._value))));
  56638. };
  56639. return ConstantProperty;
  56640. });
  56641. /*global define*/
  56642. define('DataSources/createPropertyDescriptor',[
  56643. '../Core/defaultValue',
  56644. '../Core/defined',
  56645. './ConstantProperty'
  56646. ], function(
  56647. defaultValue,
  56648. defined,
  56649. ConstantProperty) {
  56650. 'use strict';
  56651. function createProperty(name, privateName, subscriptionName, configurable, createPropertyCallback) {
  56652. return {
  56653. configurable : configurable,
  56654. get : function() {
  56655. return this[privateName];
  56656. },
  56657. set : function(value) {
  56658. var oldValue = this[privateName];
  56659. var subscription = this[subscriptionName];
  56660. if (defined(subscription)) {
  56661. subscription();
  56662. this[subscriptionName] = undefined;
  56663. }
  56664. var hasValue = defined(value);
  56665. if (hasValue && !defined(value.getValue) && defined(createPropertyCallback)) {
  56666. value = createPropertyCallback(value);
  56667. }
  56668. if (oldValue !== value) {
  56669. this[privateName] = value;
  56670. this._definitionChanged.raiseEvent(this, name, value, oldValue);
  56671. }
  56672. if (defined(value) && defined(value.definitionChanged)) {
  56673. this[subscriptionName] = value.definitionChanged.addEventListener(function() {
  56674. this._definitionChanged.raiseEvent(this, name, value, value);
  56675. }, this);
  56676. }
  56677. }
  56678. };
  56679. }
  56680. function createConstantProperty(value) {
  56681. return new ConstantProperty(value);
  56682. }
  56683. /**
  56684. * Used to consistently define all DataSources graphics objects.
  56685. * This is broken into two functions because the Chrome profiler does a better
  56686. * job of optimizing lookups if it notices that the string is constant throughout the function.
  56687. * @private
  56688. */
  56689. function createPropertyDescriptor(name, configurable, createPropertyCallback) {
  56690. //Safari 8.0.3 has a JavaScript bug that causes it to confuse two variables and treat them as the same.
  56691. //The two extra toString calls work around the issue.
  56692. return createProperty(name, '_' + name.toString(), '_' + name.toString() + 'Subscription', defaultValue(configurable, false), defaultValue(createPropertyCallback, createConstantProperty));
  56693. }
  56694. return createPropertyDescriptor;
  56695. });
  56696. /*global define*/
  56697. define('DataSources/BillboardGraphics',[
  56698. '../Core/defaultValue',
  56699. '../Core/defined',
  56700. '../Core/defineProperties',
  56701. '../Core/DeveloperError',
  56702. '../Core/Event',
  56703. './createPropertyDescriptor'
  56704. ], function(
  56705. defaultValue,
  56706. defined,
  56707. defineProperties,
  56708. DeveloperError,
  56709. Event,
  56710. createPropertyDescriptor) {
  56711. 'use strict';
  56712. /**
  56713. * Describes a two dimensional icon located at the position of the containing {@link Entity}.
  56714. * <p>
  56715. * <div align='center'>
  56716. * <img src='images/Billboard.png' width='400' height='300' /><br />
  56717. * Example billboards
  56718. * </div>
  56719. * </p>
  56720. *
  56721. * @alias BillboardGraphics
  56722. * @constructor
  56723. *
  56724. * @param {Object} [options] Object with the following properties:
  56725. * @param {Property} [options.image] A Property specifying the Image, URI, or Canvas to use for the billboard.
  56726. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the billboard.
  56727. * @param {Property} [options.scale=1.0] A numeric Property specifying the scale to apply to the image size.
  56728. * @param {Property} [options.horizontalOrigin=HorizontalOrigin.CENTER] A Property specifying the {@link HorizontalOrigin}.
  56729. * @param {Property} [options.verticalOrigin=VerticalOrigin.CENTER] A Property specifying the {@link VerticalOrigin}.
  56730. * @param {Property} [options.eyeOffset=Cartesian3.ZERO] A {@link Cartesian3} Property specifying the eye offset.
  56731. * @param {Property} [options.pixelOffset=Cartesian2.ZERO] A {@link Cartesian2} Property specifying the pixel offset.
  56732. * @param {Property} [options.rotation=0] A numeric Property specifying the rotation about the alignedAxis.
  56733. * @param {Property} [options.alignedAxis=Cartesian3.ZERO] A {@link Cartesian3} Property specifying the unit vector axis of rotation.
  56734. * @param {Property} [options.width] A numeric Property specifying the width of the billboard in pixels, overriding the native size.
  56735. * @param {Property} [options.height] A numeric Property specifying the height of the billboard in pixels, overriding the native size.
  56736. * @param {Property} [options.color=Color.WHITE] A Property specifying the tint {@link Color} of the image.
  56737. * @param {Property} [options.scaleByDistance] A {@link NearFarScalar} Property used to scale the point based on distance from the camera.
  56738. * @param {Property} [options.translucencyByDistance] A {@link NearFarScalar} Property used to set translucency based on distance from the camera.
  56739. * @param {Property} [options.pixelOffsetScaleByDistance] A {@link NearFarScalar} Property used to set pixelOffset based on distance from the camera.
  56740. * @param {Property} [options.imageSubRegion] A Property specifying a {@link BoundingRectangle} that defines a sub-region of the image to use for the billboard, rather than the entire image, measured in pixels from the bottom-left.
  56741. * @param {Property} [options.sizeInMeters] A boolean Property specifying whether this billboard's size should be measured in meters.
  56742. * @param {Property} [options.heightReference=HeightReference.NONE] A Property specifying what the height is relative to.
  56743. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this billboard will be displayed.
  56744. *
  56745. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Billboards.html|Cesium Sandcastle Billboard Demo}
  56746. */
  56747. function BillboardGraphics(options) {
  56748. this._image = undefined;
  56749. this._imageSubscription = undefined;
  56750. this._imageSubRegion = undefined;
  56751. this._imageSubRegionSubscription = undefined;
  56752. this._width = undefined;
  56753. this._widthSubscription = undefined;
  56754. this._height = undefined;
  56755. this._heightSubscription = undefined;
  56756. this._scale = undefined;
  56757. this._scaleSubscription = undefined;
  56758. this._rotation = undefined;
  56759. this._rotationSubscription = undefined;
  56760. this._alignedAxis = undefined;
  56761. this._alignedAxisSubscription = undefined;
  56762. this._horizontalOrigin = undefined;
  56763. this._horizontalOriginSubscription = undefined;
  56764. this._verticalOrigin = undefined;
  56765. this._verticalOriginSubscription = undefined;
  56766. this._color = undefined;
  56767. this._colorSubscription = undefined;
  56768. this._eyeOffset = undefined;
  56769. this._eyeOffsetSubscription = undefined;
  56770. this._heightReference = undefined;
  56771. this._heightReferenceSubscription = undefined;
  56772. this._pixelOffset = undefined;
  56773. this._pixelOffsetSubscription = undefined;
  56774. this._show = undefined;
  56775. this._showSubscription = undefined;
  56776. this._scaleByDistance = undefined;
  56777. this._scaleByDistanceSubscription = undefined;
  56778. this._translucencyByDistance = undefined;
  56779. this._translucencyByDistanceSubscription = undefined;
  56780. this._pixelOffsetScaleByDistance = undefined;
  56781. this._pixelOffsetScaleByDistanceSubscription = undefined;
  56782. this._sizeInMeters = undefined;
  56783. this._sizeInMetersSubscription = undefined;
  56784. this._distanceDisplayCondition = undefined;
  56785. this._distanceDisplayConditionSubscription = undefined;
  56786. this._definitionChanged = new Event();
  56787. this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
  56788. }
  56789. defineProperties(BillboardGraphics.prototype, {
  56790. /**
  56791. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  56792. * @memberof BillboardGraphics.prototype
  56793. *
  56794. * @type {Event}
  56795. * @readonly
  56796. */
  56797. definitionChanged : {
  56798. get : function() {
  56799. return this._definitionChanged;
  56800. }
  56801. },
  56802. /**
  56803. * Gets or sets the Property specifying the Image, URI, or Canvas to use for the billboard.
  56804. * @memberof BillboardGraphics.prototype
  56805. * @type {Property}
  56806. */
  56807. image : createPropertyDescriptor('image'),
  56808. /**
  56809. * Gets or sets the Property specifying a {@link BoundingRectangle} that defines a
  56810. * sub-region of the <code>image</code> to use for the billboard, rather than the entire image,
  56811. * measured in pixels from the bottom-left.
  56812. * @memberof BillboardGraphics.prototype
  56813. * @type {Property}
  56814. */
  56815. imageSubRegion : createPropertyDescriptor('imageSubRegion'),
  56816. /**
  56817. * Gets or sets the numeric Property specifying the uniform scale to apply to the image.
  56818. * A scale greater than <code>1.0</code> enlarges the billboard while a scale less than <code>1.0</code> shrinks it.
  56819. * <p>
  56820. * <div align='center'>
  56821. * <img src='images/Billboard.setScale.png' width='400' height='300' /><br/>
  56822. * From left to right in the above image, the scales are <code>0.5</code>, <code>1.0</code>, and <code>2.0</code>.
  56823. * </div>
  56824. * </p>
  56825. * @memberof BillboardGraphics.prototype
  56826. * @type {Property}
  56827. * @default 1.0
  56828. */
  56829. scale : createPropertyDescriptor('scale'),
  56830. /**
  56831. * Gets or sets the numeric Property specifying the rotation of the image
  56832. * counter clockwise from the <code>alignedAxis</code>.
  56833. * @memberof BillboardGraphics.prototype
  56834. * @type {Property}
  56835. * @default 0
  56836. */
  56837. rotation : createPropertyDescriptor('rotation'),
  56838. /**
  56839. * Gets or sets the {@link Cartesian3} Property specifying the unit vector axis of rotation
  56840. * in the fixed frame. When set to Cartesian3.ZERO the rotation is from the top of the screen.
  56841. * @memberof BillboardGraphics.prototype
  56842. * @type {Property}
  56843. * @default Cartesian3.ZERO
  56844. */
  56845. alignedAxis : createPropertyDescriptor('alignedAxis'),
  56846. /**
  56847. * Gets or sets the Property specifying the {@link HorizontalOrigin}.
  56848. * @memberof BillboardGraphics.prototype
  56849. * @type {Property}
  56850. * @default HorizontalOrigin.CENTER
  56851. */
  56852. horizontalOrigin : createPropertyDescriptor('horizontalOrigin'),
  56853. /**
  56854. * Gets or sets the Property specifying the {@link VerticalOrigin}.
  56855. * @memberof BillboardGraphics.prototype
  56856. * @type {Property}
  56857. * @default VerticalOrigin.CENTER
  56858. */
  56859. verticalOrigin : createPropertyDescriptor('verticalOrigin'),
  56860. /**
  56861. * Gets or sets the Property specifying the {@link Color} that is multiplied with the <code>image</code>.
  56862. * This has two common use cases. First, the same white texture may be used by many different billboards,
  56863. * each with a different color, to create colored billboards. Second, the color's alpha component can be
  56864. * used to make the billboard translucent as shown below. An alpha of <code>0.0</code> makes the billboard
  56865. * transparent, and <code>1.0</code> makes the billboard opaque.
  56866. * <p>
  56867. * <div align='center'>
  56868. * <table border='0' cellpadding='5'><tr>
  56869. * <td align='center'><code>default</code><br/><img src='images/Billboard.setColor.Alpha255.png' width='250' height='188' /></td>
  56870. * <td align='center'><code>alpha : 0.5</code><br/><img src='images/Billboard.setColor.Alpha127.png' width='250' height='188' /></td>
  56871. * </tr></table>
  56872. * </div>
  56873. * </p>
  56874. * @memberof BillboardGraphics.prototype
  56875. * @type {Property}
  56876. * @default Color.WHITE
  56877. */
  56878. color : createPropertyDescriptor('color'),
  56879. /**
  56880. * Gets or sets the {@link Cartesian3} Property specifying the billboard's offset in eye coordinates.
  56881. * Eye coordinates is a left-handed coordinate system, where <code>x</code> points towards the viewer's
  56882. * right, <code>y</code> points up, and <code>z</code> points into the screen.
  56883. * <p>
  56884. * An eye offset is commonly used to arrange multiple billboards or objects at the same position, e.g., to
  56885. * arrange a billboard above its corresponding 3D model.
  56886. * </p>
  56887. * Below, the billboard is positioned at the center of the Earth but an eye offset makes it always
  56888. * appear on top of the Earth regardless of the viewer's or Earth's orientation.
  56889. * <p>
  56890. * <div align='center'>
  56891. * <table border='0' cellpadding='5'><tr>
  56892. * <td align='center'><img src='images/Billboard.setEyeOffset.one.png' width='250' height='188' /></td>
  56893. * <td align='center'><img src='images/Billboard.setEyeOffset.two.png' width='250' height='188' /></td>
  56894. * </tr></table>
  56895. * <code>b.eyeOffset = new Cartesian3(0.0, 8000000.0, 0.0);</code>
  56896. * </div>
  56897. * </p>
  56898. * @memberof BillboardGraphics.prototype
  56899. * @type {Property}
  56900. * @default Cartesian3.ZERO
  56901. */
  56902. eyeOffset : createPropertyDescriptor('eyeOffset'),
  56903. /**
  56904. * Gets or sets the Property specifying the {@link HeightReference}.
  56905. * @memberof BillboardGraphics.prototype
  56906. * @type {Property}
  56907. * @default HeightReference.NONE
  56908. */
  56909. heightReference : createPropertyDescriptor('heightReference'),
  56910. /**
  56911. * Gets or sets the {@link Cartesian2} Property specifying the billboard's pixel offset in screen space
  56912. * from the origin of this billboard. This is commonly used to align multiple billboards and labels at
  56913. * the same position, e.g., an image and text. The screen space origin is the top, left corner of the
  56914. * canvas; <code>x</code> increases from left to right, and <code>y</code> increases from top to bottom.
  56915. * <p>
  56916. * <div align='center'>
  56917. * <table border='0' cellpadding='5'><tr>
  56918. * <td align='center'><code>default</code><br/><img src='images/Billboard.setPixelOffset.default.png' width='250' height='188' /></td>
  56919. * <td align='center'><code>b.pixeloffset = new Cartesian2(50, 25);</code><br/><img src='images/Billboard.setPixelOffset.x50y-25.png' width='250' height='188' /></td>
  56920. * </tr></table>
  56921. * The billboard's origin is indicated by the yellow point.
  56922. * </div>
  56923. * </p>
  56924. * @memberof BillboardGraphics.prototype
  56925. * @type {Property}
  56926. * @default Cartesian2.ZERO
  56927. */
  56928. pixelOffset : createPropertyDescriptor('pixelOffset'),
  56929. /**
  56930. * Gets or sets the boolean Property specifying the visibility of the billboard.
  56931. * @memberof BillboardGraphics.prototype
  56932. * @type {Property}
  56933. * @default true
  56934. */
  56935. show : createPropertyDescriptor('show'),
  56936. /**
  56937. * Gets or sets the numeric Property specifying the billboard's width in pixels.
  56938. * When undefined, the native width is used.
  56939. * @memberof BillboardGraphics.prototype
  56940. * @type {Property}
  56941. */
  56942. width : createPropertyDescriptor('width'),
  56943. /**
  56944. * Gets or sets the numeric Property specifying the height of the billboard in pixels.
  56945. * When undefined, the native height is used.
  56946. * @memberof BillboardGraphics.prototype
  56947. * @type {Property}
  56948. */
  56949. height : createPropertyDescriptor('height'),
  56950. /**
  56951. * Gets or sets {@link NearFarScalar} Property specifying the scale of the billboard based on the distance from the camera.
  56952. * A billboard's scale will interpolate between the {@link NearFarScalar#nearValue} and
  56953. * {@link NearFarScalar#farValue} while the camera distance falls within the upper and lower bounds
  56954. * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
  56955. * Outside of these ranges the billboard's scale remains clamped to the nearest bound.
  56956. * @memberof BillboardGraphics.prototype
  56957. * @type {Property}
  56958. */
  56959. scaleByDistance : createPropertyDescriptor('scaleByDistance'),
  56960. /**
  56961. * Gets or sets {@link NearFarScalar} Property specifying the translucency of the billboard based on the distance from the camera.
  56962. * A billboard's translucency will interpolate between the {@link NearFarScalar#nearValue} and
  56963. * {@link NearFarScalar#farValue} while the camera distance falls within the upper and lower bounds
  56964. * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
  56965. * Outside of these ranges the billboard's translucency remains clamped to the nearest bound.
  56966. * @memberof BillboardGraphics.prototype
  56967. * @type {Property}
  56968. */
  56969. translucencyByDistance : createPropertyDescriptor('translucencyByDistance'),
  56970. /**
  56971. * Gets or sets {@link NearFarScalar} Property specifying the pixel offset of the billboard based on the distance from the camera.
  56972. * A billboard's pixel offset will interpolate between the {@link NearFarScalar#nearValue} and
  56973. * {@link NearFarScalar#farValue} while the camera distance falls within the upper and lower bounds
  56974. * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
  56975. * Outside of these ranges the billboard's pixel offset remains clamped to the nearest bound.
  56976. * @memberof BillboardGraphics.prototype
  56977. * @type {Property}
  56978. */
  56979. pixelOffsetScaleByDistance : createPropertyDescriptor('pixelOffsetScaleByDistance'),
  56980. /**
  56981. * Gets or sets the boolean Property specifying if this billboard's size will be measured in meters.
  56982. * @memberof BillboardGraphics.prototype
  56983. * @type {Property}
  56984. * @default false
  56985. */
  56986. sizeInMeters : createPropertyDescriptor('sizeInMeters'),
  56987. /**
  56988. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this billboard will be displayed.
  56989. * @memberof BillboardGraphics.prototype
  56990. * @type {Property}
  56991. */
  56992. distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition')
  56993. });
  56994. /**
  56995. * Duplicates this instance.
  56996. *
  56997. * @param {BillboardGraphics} [result] The object onto which to store the result.
  56998. * @returns {BillboardGraphics} The modified result parameter or a new instance if one was not provided.
  56999. */
  57000. BillboardGraphics.prototype.clone = function(result) {
  57001. if (!defined(result)) {
  57002. return new BillboardGraphics(this);
  57003. }
  57004. result.color = this._color;
  57005. result.eyeOffset = this._eyeOffset;
  57006. result.heightReference = this._heightReference;
  57007. result.horizontalOrigin = this._horizontalOrigin;
  57008. result.image = this._image;
  57009. result.imageSubRegion = this._imageSubRegion;
  57010. result.pixelOffset = this._pixelOffset;
  57011. result.scale = this._scale;
  57012. result.rotation = this._rotation;
  57013. result.alignedAxis = this._alignedAxis;
  57014. result.show = this._show;
  57015. result.verticalOrigin = this._verticalOrigin;
  57016. result.width = this._width;
  57017. result.height = this._height;
  57018. result.scaleByDistance = this._scaleByDistance;
  57019. result.translucencyByDistance = this._translucencyByDistance;
  57020. result.pixelOffsetScaleByDistance = this._pixelOffsetScaleByDistance;
  57021. result.sizeInMeters = this._sizeInMeters;
  57022. result.distanceDisplayCondition = this._distanceDisplayCondition;
  57023. return result;
  57024. };
  57025. /**
  57026. * Assigns each unassigned property on this object to the value
  57027. * of the same property on the provided source object.
  57028. *
  57029. * @param {BillboardGraphics} source The object to be merged into this object.
  57030. */
  57031. BillboardGraphics.prototype.merge = function(source) {
  57032. if (!defined(source)) {
  57033. throw new DeveloperError('source is required.');
  57034. }
  57035. this.color = defaultValue(this._color, source.color);
  57036. this.eyeOffset = defaultValue(this._eyeOffset, source.eyeOffset);
  57037. this.heightReference = defaultValue(this._heightReference, source.heightReference);
  57038. this.horizontalOrigin = defaultValue(this._horizontalOrigin, source.horizontalOrigin);
  57039. this.image = defaultValue(this._image, source.image);
  57040. this.imageSubRegion = defaultValue(this._imageSubRegion, source.imageSubRegion);
  57041. this.pixelOffset = defaultValue(this._pixelOffset, source.pixelOffset);
  57042. this.scale = defaultValue(this._scale, source.scale);
  57043. this.rotation = defaultValue(this._rotation, source.rotation);
  57044. this.alignedAxis = defaultValue(this._alignedAxis, source.alignedAxis);
  57045. this.show = defaultValue(this._show, source.show);
  57046. this.verticalOrigin = defaultValue(this._verticalOrigin, source.verticalOrigin);
  57047. this.width = defaultValue(this._width, source.width);
  57048. this.height = defaultValue(this._height, source.height);
  57049. this.scaleByDistance = defaultValue(this._scaleByDistance, source.scaleByDistance);
  57050. this.translucencyByDistance = defaultValue(this._translucencyByDistance, source.translucencyByDistance);
  57051. this.pixelOffsetScaleByDistance = defaultValue(this._pixelOffsetScaleByDistance, source.pixelOffsetScaleByDistance);
  57052. this.sizeInMeters = defaultValue(this._sizeInMeters, source.sizeInMeters);
  57053. this.distanceDisplayCondition = defaultValue(this._distanceDisplayCondition, source.distanceDisplayCondition);
  57054. };
  57055. return BillboardGraphics;
  57056. });
  57057. /*global define*/
  57058. define('Scene/HeightReference',[
  57059. '../Core/freezeObject'
  57060. ], function(
  57061. freezeObject) {
  57062. 'use strict';
  57063. /**
  57064. * Represents the position relative to the terrain.
  57065. *
  57066. * @exports HeightReference
  57067. */
  57068. var HeightReference = {
  57069. /**
  57070. * The position is absolute.
  57071. * @type {Number}
  57072. * @constant
  57073. */
  57074. NONE : 0,
  57075. /**
  57076. * The position is clamped to the terrain.
  57077. * @type {Number}
  57078. * @constant
  57079. */
  57080. CLAMP_TO_GROUND : 1,
  57081. /**
  57082. * The position height is the height above the terrain.
  57083. * @type {Number}
  57084. * @constant
  57085. */
  57086. RELATIVE_TO_GROUND : 2
  57087. };
  57088. return freezeObject(HeightReference);
  57089. });
  57090. /*global define*/
  57091. define('Scene/HorizontalOrigin',[
  57092. '../Core/freezeObject'
  57093. ], function(
  57094. freezeObject) {
  57095. 'use strict';
  57096. /**
  57097. * The horizontal location of an origin relative to an object, e.g., a {@link Billboard}
  57098. * or {@link Label}. For example, setting the horizontal origin to <code>LEFT</code>
  57099. * or <code>RIGHT</code> will display a billboard to the left or right (in screen space)
  57100. * of the anchor position.
  57101. * <br /><br />
  57102. * <div align='center'>
  57103. * <img src='images/Billboard.setHorizontalOrigin.png' width='648' height='196' /><br />
  57104. * </div>
  57105. *
  57106. * @exports HorizontalOrigin
  57107. *
  57108. * @see Billboard#horizontalOrigin
  57109. * @see Label#horizontalOrigin
  57110. */
  57111. var HorizontalOrigin = {
  57112. /**
  57113. * The origin is at the horizontal center of the object.
  57114. *
  57115. * @type {Number}
  57116. * @constant
  57117. */
  57118. CENTER : 0,
  57119. /**
  57120. * The origin is on the left side of the object.
  57121. *
  57122. * @type {Number}
  57123. * @constant
  57124. */
  57125. LEFT : 1,
  57126. /**
  57127. * The origin is on the right side of the object.
  57128. *
  57129. * @type {Number}
  57130. * @constant
  57131. */
  57132. RIGHT : -1
  57133. };
  57134. return freezeObject(HorizontalOrigin);
  57135. });
  57136. /*global define*/
  57137. define('Scene/VerticalOrigin',[
  57138. '../Core/freezeObject'
  57139. ], function(
  57140. freezeObject) {
  57141. 'use strict';
  57142. /**
  57143. * The vertical location of an origin relative to an object, e.g., a {@link Billboard}
  57144. * or {@link Label}. For example, setting the vertical origin to <code>TOP</code>
  57145. * or <code>BOTTOM</code> will display a billboard above or below (in screen space)
  57146. * the anchor position.
  57147. * <br /><br />
  57148. * <div align='center'>
  57149. * <img src='images/Billboard.setVerticalOrigin.png' width='695' height='175' /><br />
  57150. * </div>
  57151. *
  57152. * @exports VerticalOrigin
  57153. *
  57154. * @see Billboard#verticalOrigin
  57155. * @see Label#verticalOrigin
  57156. */
  57157. var VerticalOrigin = {
  57158. /**
  57159. * The origin is at the vertical center between <code>BASELINE</code> and <code>TOP</code>.
  57160. *
  57161. * @type {Number}
  57162. * @constant
  57163. */
  57164. CENTER : 0,
  57165. /**
  57166. * The origin is at the bottom of the object.
  57167. *
  57168. * @type {Number}
  57169. * @constant
  57170. */
  57171. BOTTOM : 1,
  57172. /**
  57173. * If the object contains text, the origin is at the baseline of the text, else the origin is at the bottom of the object.
  57174. *
  57175. * @type {Number}
  57176. * @constant
  57177. */
  57178. BASELINE : 2,
  57179. /**
  57180. * The origin is at the top of the object.
  57181. *
  57182. * @type {Number}
  57183. * @constant
  57184. */
  57185. TOP : -1
  57186. };
  57187. return freezeObject(VerticalOrigin);
  57188. });
  57189. /*global define*/
  57190. define('DataSources/BoundingSphereState',[
  57191. '../Core/freezeObject'
  57192. ], function(
  57193. freezeObject) {
  57194. 'use strict';
  57195. /**
  57196. * The state of a BoundingSphere computation being performed by a {@link Visualizer}.
  57197. * @exports BoundingSphereState
  57198. * @private
  57199. */
  57200. var BoundingSphereState = {
  57201. /**
  57202. * The BoundingSphere has been computed.
  57203. * @type BoundingSphereState
  57204. * @constant
  57205. */
  57206. DONE : 0,
  57207. /**
  57208. * The BoundingSphere is still being computed.
  57209. * @type BoundingSphereState
  57210. * @constant
  57211. */
  57212. PENDING : 1,
  57213. /**
  57214. * The BoundingSphere does not exist.
  57215. * @type BoundingSphereState
  57216. * @constant
  57217. */
  57218. FAILED : 2
  57219. };
  57220. return freezeObject(BoundingSphereState);
  57221. });
  57222. /*global define*/
  57223. define('DataSources/Property',[
  57224. '../Core/defaultValue',
  57225. '../Core/defined',
  57226. '../Core/defineProperties',
  57227. '../Core/DeveloperError'
  57228. ], function(
  57229. defaultValue,
  57230. defined,
  57231. defineProperties,
  57232. DeveloperError) {
  57233. 'use strict';
  57234. /**
  57235. * The interface for all properties, which represent a value that can optionally vary over time.
  57236. * This type defines an interface and cannot be instantiated directly.
  57237. *
  57238. * @alias Property
  57239. * @constructor
  57240. *
  57241. * @see CompositeProperty
  57242. * @see ConstantProperty
  57243. * @see SampledProperty
  57244. * @see TimeIntervalCollectionProperty
  57245. * @see MaterialProperty
  57246. * @see PositionProperty
  57247. * @see ReferenceProperty
  57248. */
  57249. function Property() {
  57250. DeveloperError.throwInstantiationError();
  57251. }
  57252. defineProperties(Property.prototype, {
  57253. /**
  57254. * Gets a value indicating if this property is constant. A property is considered
  57255. * constant if getValue always returns the same result for the current definition.
  57256. * @memberof Property.prototype
  57257. *
  57258. * @type {Boolean}
  57259. * @readonly
  57260. */
  57261. isConstant : {
  57262. get : DeveloperError.throwInstantiationError
  57263. },
  57264. /**
  57265. * Gets the event that is raised whenever the definition of this property changes.
  57266. * The definition is considered to have changed if a call to getValue would return
  57267. * a different result for the same time.
  57268. * @memberof Property.prototype
  57269. *
  57270. * @type {Event}
  57271. * @readonly
  57272. */
  57273. definitionChanged : {
  57274. get : DeveloperError.throwInstantiationError
  57275. }
  57276. });
  57277. /**
  57278. * Gets the value of the property at the provided time.
  57279. * @function
  57280. *
  57281. * @param {JulianDate} time The time for which to retrieve the value.
  57282. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  57283. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  57284. */
  57285. Property.prototype.getValue = DeveloperError.throwInstantiationError;
  57286. /**
  57287. * Compares this property to the provided property and returns
  57288. * <code>true</code> if they are equal, <code>false</code> otherwise.
  57289. * @function
  57290. *
  57291. * @param {Property} [other] The other property.
  57292. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  57293. */
  57294. Property.prototype.equals = DeveloperError.throwInstantiationError;
  57295. /**
  57296. * @private
  57297. */
  57298. Property.equals = function(left, right) {
  57299. return left === right || (defined(left) && left.equals(right));
  57300. };
  57301. /**
  57302. * @private
  57303. */
  57304. Property.arrayEquals = function(left, right) {
  57305. if (left === right) {
  57306. return true;
  57307. }
  57308. if ((!defined(left) || !defined(right)) || (left.length !== right.length)) {
  57309. return false;
  57310. }
  57311. var length = left.length;
  57312. for (var i = 0; i < length; i++) {
  57313. if (!Property.equals(left[i], right[i])) {
  57314. return false;
  57315. }
  57316. }
  57317. return true;
  57318. };
  57319. /**
  57320. * @private
  57321. */
  57322. Property.isConstant = function(property) {
  57323. return !defined(property) || property.isConstant;
  57324. };
  57325. /**
  57326. * @private
  57327. */
  57328. Property.getValueOrUndefined = function(property, time, result) {
  57329. return defined(property) ? property.getValue(time, result) : undefined;
  57330. };
  57331. /**
  57332. * @private
  57333. */
  57334. Property.getValueOrDefault = function(property, time, valueDefault, result) {
  57335. return defined(property) ? defaultValue(property.getValue(time, result), valueDefault) : valueDefault;
  57336. };
  57337. /**
  57338. * @private
  57339. */
  57340. Property.getValueOrClonedDefault = function(property, time, valueDefault, result) {
  57341. var value;
  57342. if (defined(property)) {
  57343. value = property.getValue(time, result);
  57344. }
  57345. if (!defined(value)) {
  57346. value = valueDefault.clone(value);
  57347. }
  57348. return value;
  57349. };
  57350. return Property;
  57351. });
  57352. /*global define*/
  57353. define('DataSources/BillboardVisualizer',[
  57354. '../Core/AssociativeArray',
  57355. '../Core/BoundingRectangle',
  57356. '../Core/Cartesian2',
  57357. '../Core/Cartesian3',
  57358. '../Core/Color',
  57359. '../Core/defined',
  57360. '../Core/destroyObject',
  57361. '../Core/DeveloperError',
  57362. '../Core/DistanceDisplayCondition',
  57363. '../Core/NearFarScalar',
  57364. '../Scene/HeightReference',
  57365. '../Scene/HorizontalOrigin',
  57366. '../Scene/VerticalOrigin',
  57367. './BoundingSphereState',
  57368. './Property'
  57369. ], function(
  57370. AssociativeArray,
  57371. BoundingRectangle,
  57372. Cartesian2,
  57373. Cartesian3,
  57374. Color,
  57375. defined,
  57376. destroyObject,
  57377. DeveloperError,
  57378. DistanceDisplayCondition,
  57379. NearFarScalar,
  57380. HeightReference,
  57381. HorizontalOrigin,
  57382. VerticalOrigin,
  57383. BoundingSphereState,
  57384. Property) {
  57385. 'use strict';
  57386. var defaultColor = Color.WHITE;
  57387. var defaultEyeOffset = Cartesian3.ZERO;
  57388. var defaultHeightReference = HeightReference.NONE;
  57389. var defaultPixelOffset = Cartesian2.ZERO;
  57390. var defaultScale = 1.0;
  57391. var defaultRotation = 0.0;
  57392. var defaultAlignedAxis = Cartesian3.ZERO;
  57393. var defaultHorizontalOrigin = HorizontalOrigin.CENTER;
  57394. var defaultVerticalOrigin = VerticalOrigin.CENTER;
  57395. var defaultSizeInMeters = false;
  57396. var position = new Cartesian3();
  57397. var color = new Color();
  57398. var eyeOffset = new Cartesian3();
  57399. var pixelOffset = new Cartesian2();
  57400. var scaleByDistance = new NearFarScalar();
  57401. var translucencyByDistance = new NearFarScalar();
  57402. var pixelOffsetScaleByDistance = new NearFarScalar();
  57403. var boundingRectangle = new BoundingRectangle();
  57404. var distanceDisplayCondition = new DistanceDisplayCondition();
  57405. function EntityData(entity) {
  57406. this.entity = entity;
  57407. this.billboard = undefined;
  57408. this.textureValue = undefined;
  57409. }
  57410. /**
  57411. * A {@link Visualizer} which maps {@link Entity#billboard} to a {@link Billboard}.
  57412. * @alias BillboardVisualizer
  57413. * @constructor
  57414. *
  57415. * @param {EntityCluster} entityCluster The entity cluster to manage the collection of billboards and optionally cluster with other entities.
  57416. * @param {EntityCollection} entityCollection The entityCollection to visualize.
  57417. */
  57418. function BillboardVisualizer(entityCluster, entityCollection) {
  57419. if (!defined(entityCluster)) {
  57420. throw new DeveloperError('entityCluster is required.');
  57421. }
  57422. if (!defined(entityCollection)) {
  57423. throw new DeveloperError('entityCollection is required.');
  57424. }
  57425. entityCollection.collectionChanged.addEventListener(BillboardVisualizer.prototype._onCollectionChanged, this);
  57426. this._cluster = entityCluster;
  57427. this._entityCollection = entityCollection;
  57428. this._items = new AssociativeArray();
  57429. this._onCollectionChanged(entityCollection, entityCollection.values, [], []);
  57430. }
  57431. /**
  57432. * Updates the primitives created by this visualizer to match their
  57433. * Entity counterpart at the given time.
  57434. *
  57435. * @param {JulianDate} time The time to update to.
  57436. * @returns {Boolean} This function always returns true.
  57437. */
  57438. BillboardVisualizer.prototype.update = function(time) {
  57439. if (!defined(time)) {
  57440. throw new DeveloperError('time is required.');
  57441. }
  57442. var items = this._items.values;
  57443. var cluster = this._cluster;
  57444. for (var i = 0, len = items.length; i < len; i++) {
  57445. var item = items[i];
  57446. var entity = item.entity;
  57447. var billboardGraphics = entity._billboard;
  57448. var textureValue;
  57449. var billboard = item.billboard;
  57450. var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(billboardGraphics._show, time, true);
  57451. if (show) {
  57452. position = Property.getValueOrUndefined(entity._position, time, position);
  57453. textureValue = Property.getValueOrUndefined(billboardGraphics._image, time);
  57454. show = defined(position) && defined(textureValue);
  57455. }
  57456. if (!show) {
  57457. //don't bother creating or updating anything else
  57458. returnPrimitive(item, entity, cluster);
  57459. continue;
  57460. }
  57461. if (!Property.isConstant(entity._position)) {
  57462. cluster._clusterDirty = true;
  57463. }
  57464. if (!defined(billboard)) {
  57465. billboard = cluster.getBillboard(entity);
  57466. billboard.id = entity;
  57467. billboard.image = undefined;
  57468. item.billboard = billboard;
  57469. }
  57470. billboard.show = show;
  57471. if (!defined(billboard.image) || item.textureValue !== textureValue) {
  57472. billboard.image = textureValue;
  57473. item.textureValue = textureValue;
  57474. }
  57475. billboard.position = position;
  57476. billboard.color = Property.getValueOrDefault(billboardGraphics._color, time, defaultColor, color);
  57477. billboard.eyeOffset = Property.getValueOrDefault(billboardGraphics._eyeOffset, time, defaultEyeOffset, eyeOffset);
  57478. billboard.heightReference = Property.getValueOrDefault(billboardGraphics._heightReference, time, defaultHeightReference);
  57479. billboard.pixelOffset = Property.getValueOrDefault(billboardGraphics._pixelOffset, time, defaultPixelOffset, pixelOffset);
  57480. billboard.scale = Property.getValueOrDefault(billboardGraphics._scale, time, defaultScale);
  57481. billboard.rotation = Property.getValueOrDefault(billboardGraphics._rotation, time, defaultRotation);
  57482. billboard.alignedAxis = Property.getValueOrDefault(billboardGraphics._alignedAxis, time, defaultAlignedAxis);
  57483. billboard.horizontalOrigin = Property.getValueOrDefault(billboardGraphics._horizontalOrigin, time, defaultHorizontalOrigin);
  57484. billboard.verticalOrigin = Property.getValueOrDefault(billboardGraphics._verticalOrigin, time, defaultVerticalOrigin);
  57485. billboard.width = Property.getValueOrUndefined(billboardGraphics._width, time);
  57486. billboard.height = Property.getValueOrUndefined(billboardGraphics._height, time);
  57487. billboard.scaleByDistance = Property.getValueOrUndefined(billboardGraphics._scaleByDistance, time, scaleByDistance);
  57488. billboard.translucencyByDistance = Property.getValueOrUndefined(billboardGraphics._translucencyByDistance, time, translucencyByDistance);
  57489. billboard.pixelOffsetScaleByDistance = Property.getValueOrUndefined(billboardGraphics._pixelOffsetScaleByDistance, time, pixelOffsetScaleByDistance);
  57490. billboard.sizeInMeters = Property.getValueOrDefault(billboardGraphics._sizeInMeters, defaultSizeInMeters);
  57491. billboard.distanceDisplayCondition = Property.getValueOrUndefined(billboardGraphics._distanceDisplayCondition, time, distanceDisplayCondition);
  57492. var subRegion = Property.getValueOrUndefined(billboardGraphics._imageSubRegion, time, boundingRectangle);
  57493. if (defined(subRegion)) {
  57494. billboard.setImageSubRegion(billboard._imageId, subRegion);
  57495. }
  57496. }
  57497. return true;
  57498. };
  57499. /**
  57500. * Computes a bounding sphere which encloses the visualization produced for the specified entity.
  57501. * The bounding sphere is in the fixed frame of the scene's globe.
  57502. *
  57503. * @param {Entity} entity The entity whose bounding sphere to compute.
  57504. * @param {BoundingSphere} result The bounding sphere onto which to store the result.
  57505. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere,
  57506. * BoundingSphereState.PENDING if the result is still being computed, or
  57507. * BoundingSphereState.FAILED if the entity has no visualization in the current scene.
  57508. * @private
  57509. */
  57510. BillboardVisualizer.prototype.getBoundingSphere = function(entity, result) {
  57511. if (!defined(entity)) {
  57512. throw new DeveloperError('entity is required.');
  57513. }
  57514. if (!defined(result)) {
  57515. throw new DeveloperError('result is required.');
  57516. }
  57517. var item = this._items.get(entity.id);
  57518. if (!defined(item) || !defined(item.billboard)) {
  57519. return BoundingSphereState.FAILED;
  57520. }
  57521. var billboard = item.billboard;
  57522. if (billboard.heightReference === HeightReference.NONE) {
  57523. result.center = Cartesian3.clone(billboard.position, result.center);
  57524. } else {
  57525. if (!defined(billboard._clampedPosition)) {
  57526. return BoundingSphereState.PENDING;
  57527. }
  57528. result.center = Cartesian3.clone(billboard._clampedPosition, result.center);
  57529. }
  57530. result.radius = 0;
  57531. return BoundingSphereState.DONE;
  57532. };
  57533. /**
  57534. * Returns true if this object was destroyed; otherwise, false.
  57535. *
  57536. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  57537. */
  57538. BillboardVisualizer.prototype.isDestroyed = function() {
  57539. return false;
  57540. };
  57541. /**
  57542. * Removes and destroys all primitives created by this instance.
  57543. */
  57544. BillboardVisualizer.prototype.destroy = function() {
  57545. this._entityCollection.collectionChanged.removeEventListener(BillboardVisualizer.prototype._onCollectionChanged, this);
  57546. var entities = this._entityCollection.values;
  57547. for (var i = 0; i < entities.length; i++) {
  57548. this._cluster.removeBillboard(entities[i]);
  57549. }
  57550. return destroyObject(this);
  57551. };
  57552. BillboardVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed, changed) {
  57553. var i;
  57554. var entity;
  57555. var items = this._items;
  57556. var cluster = this._cluster;
  57557. for (i = added.length - 1; i > -1; i--) {
  57558. entity = added[i];
  57559. if (defined(entity._billboard) && defined(entity._position)) {
  57560. items.set(entity.id, new EntityData(entity));
  57561. }
  57562. }
  57563. for (i = changed.length - 1; i > -1; i--) {
  57564. entity = changed[i];
  57565. if (defined(entity._billboard) && defined(entity._position)) {
  57566. if (!items.contains(entity.id)) {
  57567. items.set(entity.id, new EntityData(entity));
  57568. }
  57569. } else {
  57570. returnPrimitive(items.get(entity.id), entity, cluster);
  57571. items.remove(entity.id);
  57572. }
  57573. }
  57574. for (i = removed.length - 1; i > -1; i--) {
  57575. entity = removed[i];
  57576. returnPrimitive(items.get(entity.id), entity, cluster);
  57577. items.remove(entity.id);
  57578. }
  57579. };
  57580. function returnPrimitive(item, entity, cluster) {
  57581. if (defined(item)) {
  57582. item.billboard = undefined;
  57583. cluster.removeBillboard(entity);
  57584. }
  57585. }
  57586. return BillboardVisualizer;
  57587. });
  57588. //This file is automatically rebuilt by the Cesium build process.
  57589. /*global define*/
  57590. define('Shaders/Appearances/AllMaterialAppearanceFS',[],function() {
  57591. 'use strict';
  57592. return "varying vec3 v_positionEC;\n\
  57593. varying vec3 v_normalEC;\n\
  57594. varying vec3 v_tangentEC;\n\
  57595. varying vec3 v_binormalEC;\n\
  57596. varying vec2 v_st;\n\
  57597. void main()\n\
  57598. {\n\
  57599. vec3 positionToEyeEC = -v_positionEC;\n\
  57600. mat3 tangentToEyeMatrix = czm_tangentToEyeSpaceMatrix(v_normalEC, v_tangentEC, v_binormalEC);\n\
  57601. vec3 normalEC = normalize(v_normalEC);\n\
  57602. #ifdef FACE_FORWARD\n\
  57603. normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n\
  57604. #endif\n\
  57605. czm_materialInput materialInput;\n\
  57606. materialInput.normalEC = normalEC;\n\
  57607. materialInput.tangentToEyeMatrix = tangentToEyeMatrix;\n\
  57608. materialInput.positionToEyeEC = positionToEyeEC;\n\
  57609. materialInput.st = v_st;\n\
  57610. czm_material material = czm_getMaterial(materialInput);\n\
  57611. #ifdef FLAT\n\
  57612. gl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n\
  57613. #else\n\
  57614. gl_FragColor = czm_phong(normalize(positionToEyeEC), material);\n\
  57615. #endif\n\
  57616. }\n\
  57617. ";
  57618. });
  57619. //This file is automatically rebuilt by the Cesium build process.
  57620. /*global define*/
  57621. define('Shaders/Appearances/AllMaterialAppearanceVS',[],function() {
  57622. 'use strict';
  57623. return "attribute vec3 position3DHigh;\n\
  57624. attribute vec3 position3DLow;\n\
  57625. attribute vec3 normal;\n\
  57626. attribute vec3 tangent;\n\
  57627. attribute vec3 binormal;\n\
  57628. attribute vec2 st;\n\
  57629. attribute float batchId;\n\
  57630. varying vec3 v_positionEC;\n\
  57631. varying vec3 v_normalEC;\n\
  57632. varying vec3 v_tangentEC;\n\
  57633. varying vec3 v_binormalEC;\n\
  57634. varying vec2 v_st;\n\
  57635. void main()\n\
  57636. {\n\
  57637. vec4 p = czm_computePosition();\n\
  57638. v_positionEC = (czm_modelViewRelativeToEye * p).xyz;\n\
  57639. v_normalEC = czm_normal * normal;\n\
  57640. v_tangentEC = czm_normal * tangent;\n\
  57641. v_binormalEC = czm_normal * binormal;\n\
  57642. v_st = st;\n\
  57643. gl_Position = czm_modelViewProjectionRelativeToEye * p;\n\
  57644. }\n\
  57645. ";
  57646. });
  57647. //This file is automatically rebuilt by the Cesium build process.
  57648. /*global define*/
  57649. define('Shaders/Appearances/BasicMaterialAppearanceFS',[],function() {
  57650. 'use strict';
  57651. return "varying vec3 v_positionEC;\n\
  57652. varying vec3 v_normalEC;\n\
  57653. void main()\n\
  57654. {\n\
  57655. vec3 positionToEyeEC = -v_positionEC;\n\
  57656. vec3 normalEC = normalize(v_normalEC);\n\
  57657. #ifdef FACE_FORWARD\n\
  57658. normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n\
  57659. #endif\n\
  57660. czm_materialInput materialInput;\n\
  57661. materialInput.normalEC = normalEC;\n\
  57662. materialInput.positionToEyeEC = positionToEyeEC;\n\
  57663. czm_material material = czm_getMaterial(materialInput);\n\
  57664. #ifdef FLAT\n\
  57665. gl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n\
  57666. #else\n\
  57667. gl_FragColor = czm_phong(normalize(positionToEyeEC), material);\n\
  57668. #endif\n\
  57669. }\n\
  57670. ";
  57671. });
  57672. //This file is automatically rebuilt by the Cesium build process.
  57673. /*global define*/
  57674. define('Shaders/Appearances/BasicMaterialAppearanceVS',[],function() {
  57675. 'use strict';
  57676. return "attribute vec3 position3DHigh;\n\
  57677. attribute vec3 position3DLow;\n\
  57678. attribute vec3 normal;\n\
  57679. attribute float batchId;\n\
  57680. varying vec3 v_positionEC;\n\
  57681. varying vec3 v_normalEC;\n\
  57682. void main()\n\
  57683. {\n\
  57684. vec4 p = czm_computePosition();\n\
  57685. v_positionEC = (czm_modelViewRelativeToEye * p).xyz;\n\
  57686. v_normalEC = czm_normal * normal;\n\
  57687. gl_Position = czm_modelViewProjectionRelativeToEye * p;\n\
  57688. }\n\
  57689. ";
  57690. });
  57691. //This file is automatically rebuilt by the Cesium build process.
  57692. /*global define*/
  57693. define('Shaders/Appearances/TexturedMaterialAppearanceFS',[],function() {
  57694. 'use strict';
  57695. return "varying vec3 v_positionEC;\n\
  57696. varying vec3 v_normalEC;\n\
  57697. varying vec2 v_st;\n\
  57698. void main()\n\
  57699. {\n\
  57700. vec3 positionToEyeEC = -v_positionEC;\n\
  57701. vec3 normalEC = normalize(v_normalEC);;\n\
  57702. #ifdef FACE_FORWARD\n\
  57703. normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n\
  57704. #endif\n\
  57705. czm_materialInput materialInput;\n\
  57706. materialInput.normalEC = normalEC;\n\
  57707. materialInput.positionToEyeEC = positionToEyeEC;\n\
  57708. materialInput.st = v_st;\n\
  57709. czm_material material = czm_getMaterial(materialInput);\n\
  57710. #ifdef FLAT\n\
  57711. gl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n\
  57712. #else\n\
  57713. gl_FragColor = czm_phong(normalize(positionToEyeEC), material);\n\
  57714. #endif\n\
  57715. }\n\
  57716. ";
  57717. });
  57718. //This file is automatically rebuilt by the Cesium build process.
  57719. /*global define*/
  57720. define('Shaders/Appearances/TexturedMaterialAppearanceVS',[],function() {
  57721. 'use strict';
  57722. return "attribute vec3 position3DHigh;\n\
  57723. attribute vec3 position3DLow;\n\
  57724. attribute vec3 normal;\n\
  57725. attribute vec2 st;\n\
  57726. attribute float batchId;\n\
  57727. varying vec3 v_positionEC;\n\
  57728. varying vec3 v_normalEC;\n\
  57729. varying vec2 v_st;\n\
  57730. void main()\n\
  57731. {\n\
  57732. vec4 p = czm_computePosition();\n\
  57733. v_positionEC = (czm_modelViewRelativeToEye * p).xyz;\n\
  57734. v_normalEC = czm_normal * normal;\n\
  57735. v_st = st;\n\
  57736. gl_Position = czm_modelViewProjectionRelativeToEye * p;\n\
  57737. }\n\
  57738. ";
  57739. });
  57740. /*global define*/
  57741. define('Scene/BlendEquation',[
  57742. '../Core/freezeObject',
  57743. '../Core/WebGLConstants'
  57744. ], function(
  57745. freezeObject,
  57746. WebGLConstants) {
  57747. 'use strict';
  57748. /**
  57749. * Determines how two pixels' values are combined.
  57750. *
  57751. * @exports BlendEquation
  57752. */
  57753. var BlendEquation = {
  57754. /**
  57755. * Pixel values are added componentwise. This is used in additive blending for translucency.
  57756. *
  57757. * @type {Number}
  57758. * @constant
  57759. */
  57760. ADD : WebGLConstants.FUNC_ADD,
  57761. /**
  57762. * Pixel values are subtracted componentwise (source - destination). This is used in alpha blending for translucency.
  57763. *
  57764. * @type {Number}
  57765. * @constant
  57766. */
  57767. SUBTRACT : WebGLConstants.FUNC_SUBTRACT,
  57768. /**
  57769. * Pixel values are subtracted componentwise (destination - source).
  57770. *
  57771. * @type {Number}
  57772. * @constant
  57773. */
  57774. REVERSE_SUBTRACT : WebGLConstants.FUNC_REVERSE_SUBTRACT
  57775. // No min and max like in ColladaFX GLES2 profile
  57776. };
  57777. return freezeObject(BlendEquation);
  57778. });
  57779. /*global define*/
  57780. define('Scene/BlendFunction',[
  57781. '../Core/freezeObject',
  57782. '../Core/WebGLConstants'
  57783. ], function(
  57784. freezeObject,
  57785. WebGLConstants) {
  57786. 'use strict';
  57787. /**
  57788. * Determines how blending factors are computed.
  57789. *
  57790. * @exports BlendFunction
  57791. */
  57792. var BlendFunction = {
  57793. /**
  57794. * The blend factor is zero.
  57795. *
  57796. * @type {Number}
  57797. * @constant
  57798. */
  57799. ZERO : WebGLConstants.ZERO,
  57800. /**
  57801. * The blend factor is one.
  57802. *
  57803. * @type {Number}
  57804. * @constant
  57805. */
  57806. ONE : WebGLConstants.ONE,
  57807. /**
  57808. * The blend factor is the source color.
  57809. *
  57810. * @type {Number}
  57811. * @constant
  57812. */
  57813. SOURCE_COLOR : WebGLConstants.SRC_COLOR,
  57814. /**
  57815. * The blend factor is one minus the source color.
  57816. *
  57817. * @type {Number}
  57818. * @constant
  57819. */
  57820. ONE_MINUS_SOURCE_COLOR : WebGLConstants.ONE_MINUS_SRC_COLOR,
  57821. /**
  57822. * The blend factor is the destination color.
  57823. *
  57824. * @type {Number}
  57825. * @constant
  57826. */
  57827. DESTINATION_COLOR : WebGLConstants.DST_COLOR,
  57828. /**
  57829. * The blend factor is one minus the destination color.
  57830. *
  57831. * @type {Number}
  57832. * @constant
  57833. */
  57834. ONE_MINUS_DESTINATION_COLOR : WebGLConstants.ONE_MINUS_DST_COLOR,
  57835. /**
  57836. * The blend factor is the source alpha.
  57837. *
  57838. * @type {Number}
  57839. * @constant
  57840. */
  57841. SOURCE_ALPHA : WebGLConstants.SRC_ALPHA,
  57842. /**
  57843. * The blend factor is one minus the source alpha.
  57844. *
  57845. * @type {Number}
  57846. * @constant
  57847. */
  57848. ONE_MINUS_SOURCE_ALPHA : WebGLConstants.ONE_MINUS_SRC_ALPHA,
  57849. /**
  57850. * The blend factor is the destination alpha.
  57851. *
  57852. * @type {Number}
  57853. * @constant
  57854. */
  57855. DESTINATION_ALPHA : WebGLConstants.DST_ALPHA,
  57856. /**
  57857. * The blend factor is one minus the destination alpha.
  57858. *
  57859. * @type {Number}
  57860. * @constant
  57861. */
  57862. ONE_MINUS_DESTINATION_ALPHA : WebGLConstants.ONE_MINUS_DST_ALPHA,
  57863. /**
  57864. * The blend factor is the constant color.
  57865. *
  57866. * @type {Number}
  57867. * @constant
  57868. */
  57869. CONSTANT_COLOR : WebGLConstants.CONSTANT_COLOR,
  57870. /**
  57871. * The blend factor is one minus the constant color.
  57872. *
  57873. * @type {Number}
  57874. * @constant
  57875. */
  57876. ONE_MINUS_CONSTANT_COLOR : WebGLConstants.ONE_MINUS_CONSTANT_ALPHA,
  57877. /**
  57878. * The blend factor is the constant alpha.
  57879. *
  57880. * @type {Number}
  57881. * @constant
  57882. */
  57883. CONSTANT_ALPHA : WebGLConstants.CONSTANT_ALPHA,
  57884. /**
  57885. * The blend factor is one minus the constant alpha.
  57886. *
  57887. * @type {Number}
  57888. * @constant
  57889. */
  57890. ONE_MINUS_CONSTANT_ALPHA : WebGLConstants.ONE_MINUS_CONSTANT_ALPHA,
  57891. /**
  57892. * The blend factor is the saturated source alpha.
  57893. *
  57894. * @type {Number}
  57895. * @constant
  57896. */
  57897. SOURCE_ALPHA_SATURATE : WebGLConstants.SRC_ALPHA_SATURATE
  57898. };
  57899. return freezeObject(BlendFunction);
  57900. });
  57901. /*global define*/
  57902. define('Scene/BlendingState',[
  57903. '../Core/freezeObject',
  57904. './BlendEquation',
  57905. './BlendFunction'
  57906. ], function(
  57907. freezeObject,
  57908. BlendEquation,
  57909. BlendFunction) {
  57910. 'use strict';
  57911. /**
  57912. * The blending state combines {@link BlendEquation} and {@link BlendFunction} and the
  57913. * <code>enabled</code> flag to define the full blending state for combining source and
  57914. * destination fragments when rendering.
  57915. * <p>
  57916. * This is a helper when using custom render states with {@link Appearance#renderState}.
  57917. * </p>
  57918. *
  57919. * @exports BlendingState
  57920. */
  57921. var BlendingState = {
  57922. /**
  57923. * Blending is disabled.
  57924. *
  57925. * @type {Object}
  57926. * @constant
  57927. */
  57928. DISABLED : freezeObject({
  57929. enabled : false
  57930. }),
  57931. /**
  57932. * Blending is enabled using alpha blending, <code>source(source.alpha) + destination(1 - source.alpha)</code>.
  57933. *
  57934. * @type {Object}
  57935. * @constant
  57936. */
  57937. ALPHA_BLEND : freezeObject({
  57938. enabled : true,
  57939. equationRgb : BlendEquation.ADD,
  57940. equationAlpha : BlendEquation.ADD,
  57941. functionSourceRgb : BlendFunction.SOURCE_ALPHA,
  57942. functionSourceAlpha : BlendFunction.SOURCE_ALPHA,
  57943. functionDestinationRgb : BlendFunction.ONE_MINUS_SOURCE_ALPHA,
  57944. functionDestinationAlpha : BlendFunction.ONE_MINUS_SOURCE_ALPHA
  57945. }),
  57946. /**
  57947. * Blending is enabled using alpha blending with premultiplied alpha, <code>source + destination(1 - source.alpha)</code>.
  57948. *
  57949. * @type {Object}
  57950. * @constant
  57951. */
  57952. PRE_MULTIPLIED_ALPHA_BLEND : freezeObject({
  57953. enabled : true,
  57954. equationRgb : BlendEquation.ADD,
  57955. equationAlpha : BlendEquation.ADD,
  57956. functionSourceRgb : BlendFunction.ONE,
  57957. functionSourceAlpha : BlendFunction.ONE,
  57958. functionDestinationRgb : BlendFunction.ONE_MINUS_SOURCE_ALPHA,
  57959. functionDestinationAlpha : BlendFunction.ONE_MINUS_SOURCE_ALPHA
  57960. }),
  57961. /**
  57962. * Blending is enabled using additive blending, <code>source(source.alpha) + destination</code>.
  57963. *
  57964. * @type {Object}
  57965. * @constant
  57966. */
  57967. ADDITIVE_BLEND : freezeObject({
  57968. enabled : true,
  57969. equationRgb : BlendEquation.ADD,
  57970. equationAlpha : BlendEquation.ADD,
  57971. functionSourceRgb : BlendFunction.SOURCE_ALPHA,
  57972. functionSourceAlpha : BlendFunction.SOURCE_ALPHA,
  57973. functionDestinationRgb : BlendFunction.ONE,
  57974. functionDestinationAlpha : BlendFunction.ONE
  57975. })
  57976. };
  57977. return freezeObject(BlendingState);
  57978. });
  57979. /*global define*/
  57980. define('Scene/CullFace',[
  57981. '../Core/freezeObject',
  57982. '../Core/WebGLConstants'
  57983. ], function(
  57984. freezeObject,
  57985. WebGLConstants) {
  57986. 'use strict';
  57987. /**
  57988. * Determines which triangles, if any, are culled.
  57989. *
  57990. * @exports CullFace
  57991. */
  57992. var CullFace = {
  57993. /**
  57994. * Front-facing triangles are culled.
  57995. *
  57996. * @type {Number}
  57997. * @constant
  57998. */
  57999. FRONT : WebGLConstants.FRONT,
  58000. /**
  58001. * Back-facing triangles are culled.
  58002. *
  58003. * @type {Number}
  58004. * @constant
  58005. */
  58006. BACK : WebGLConstants.BACK,
  58007. /**
  58008. * Both front-facing and back-facing triangles are culled.
  58009. *
  58010. * @type {Number}
  58011. * @constant
  58012. */
  58013. FRONT_AND_BACK : WebGLConstants.FRONT_AND_BACK
  58014. };
  58015. return freezeObject(CullFace);
  58016. });
  58017. /*global define*/
  58018. define('Scene/Appearance',[
  58019. '../Core/clone',
  58020. '../Core/combine',
  58021. '../Core/defaultValue',
  58022. '../Core/defined',
  58023. '../Core/defineProperties',
  58024. './BlendingState',
  58025. './CullFace'
  58026. ], function(
  58027. clone,
  58028. combine,
  58029. defaultValue,
  58030. defined,
  58031. defineProperties,
  58032. BlendingState,
  58033. CullFace) {
  58034. 'use strict';
  58035. /**
  58036. * An appearance defines the full GLSL vertex and fragment shaders and the
  58037. * render state used to draw a {@link Primitive}. All appearances implement
  58038. * this base <code>Appearance</code> interface.
  58039. *
  58040. * @alias Appearance
  58041. * @constructor
  58042. *
  58043. * @param {Object} [options] Object with the following properties:
  58044. * @param {Boolean} [options.translucent=true] When <code>true</code>, the geometry is expected to appear translucent so {@link Appearance#renderState} has alpha blending enabled.
  58045. * @param {Boolean} [options.closed=false] When <code>true</code>, the geometry is expected to be closed so {@link Appearance#renderState} has backface culling enabled.
  58046. * @param {Material} [options.material=Material.ColorType] The material used to determine the fragment color.
  58047. * @param {String} [options.vertexShaderSource] Optional GLSL vertex shader source to override the default vertex shader.
  58048. * @param {String} [options.fragmentShaderSource] Optional GLSL fragment shader source to override the default fragment shader.
  58049. * @param {RenderState} [options.renderState] Optional render state to override the default render state.
  58050. *
  58051. * @see MaterialAppearance
  58052. * @see EllipsoidSurfaceAppearance
  58053. * @see PerInstanceColorAppearance
  58054. * @see DebugAppearance
  58055. * @see PolylineColorAppearance
  58056. * @see PolylineMaterialAppearance
  58057. *
  58058. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Geometry%20and%20Appearances.html|Geometry and Appearances Demo}
  58059. */
  58060. function Appearance(options) {
  58061. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  58062. /**
  58063. * The material used to determine the fragment color. Unlike other {@link Appearance}
  58064. * properties, this is not read-only, so an appearance's material can change on the fly.
  58065. *
  58066. * @type Material
  58067. *
  58068. * @see {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}
  58069. */
  58070. this.material = options.material;
  58071. /**
  58072. * When <code>true</code>, the geometry is expected to appear translucent.
  58073. *
  58074. * @type {Boolean}
  58075. *
  58076. * @default true
  58077. */
  58078. this.translucent = defaultValue(options.translucent, true);
  58079. this._vertexShaderSource = options.vertexShaderSource;
  58080. this._fragmentShaderSource = options.fragmentShaderSource;
  58081. this._renderState = options.renderState;
  58082. this._closed = defaultValue(options.closed, false);
  58083. }
  58084. defineProperties(Appearance.prototype, {
  58085. /**
  58086. * The GLSL source code for the vertex shader.
  58087. *
  58088. * @memberof Appearance.prototype
  58089. *
  58090. * @type {String}
  58091. * @readonly
  58092. */
  58093. vertexShaderSource : {
  58094. get : function() {
  58095. return this._vertexShaderSource;
  58096. }
  58097. },
  58098. /**
  58099. * The GLSL source code for the fragment shader. The full fragment shader
  58100. * source is built procedurally taking into account the {@link Appearance#material}.
  58101. * Use {@link Appearance#getFragmentShaderSource} to get the full source.
  58102. *
  58103. * @memberof Appearance.prototype
  58104. *
  58105. * @type {String}
  58106. * @readonly
  58107. */
  58108. fragmentShaderSource : {
  58109. get : function() {
  58110. return this._fragmentShaderSource;
  58111. }
  58112. },
  58113. /**
  58114. * The WebGL fixed-function state to use when rendering the geometry.
  58115. *
  58116. * @memberof Appearance.prototype
  58117. *
  58118. * @type {Object}
  58119. * @readonly
  58120. */
  58121. renderState : {
  58122. get : function() {
  58123. return this._renderState;
  58124. }
  58125. },
  58126. /**
  58127. * When <code>true</code>, the geometry is expected to be closed.
  58128. *
  58129. * @memberof Appearance.prototype
  58130. *
  58131. * @type {Boolean}
  58132. * @readonly
  58133. *
  58134. * @default false
  58135. */
  58136. closed : {
  58137. get : function() {
  58138. return this._closed;
  58139. }
  58140. }
  58141. });
  58142. /**
  58143. * Procedurally creates the full GLSL fragment shader source for this appearance
  58144. * taking into account {@link Appearance#fragmentShaderSource} and {@link Appearance#material}.
  58145. *
  58146. * @returns {String} The full GLSL fragment shader source.
  58147. */
  58148. Appearance.prototype.getFragmentShaderSource = function() {
  58149. var parts = [];
  58150. if (this.flat) {
  58151. parts.push('#define FLAT');
  58152. }
  58153. if (this.faceForward) {
  58154. parts.push('#define FACE_FORWARD');
  58155. }
  58156. if (defined(this.material)) {
  58157. parts.push(this.material.shaderSource);
  58158. }
  58159. parts.push(this.fragmentShaderSource);
  58160. return parts.join('\n');
  58161. };
  58162. /**
  58163. * Determines if the geometry is translucent based on {@link Appearance#translucent} and {@link Material#isTranslucent}.
  58164. *
  58165. * @returns {Boolean} <code>true</code> if the appearance is translucent.
  58166. */
  58167. Appearance.prototype.isTranslucent = function() {
  58168. return (defined(this.material) && this.material.isTranslucent()) || (!defined(this.material) && this.translucent);
  58169. };
  58170. /**
  58171. * Creates a render state. This is not the final render state instance; instead,
  58172. * it can contain a subset of render state properties identical to the render state
  58173. * created in the context.
  58174. *
  58175. * @returns {Object} The render state.
  58176. */
  58177. Appearance.prototype.getRenderState = function() {
  58178. var translucent = this.isTranslucent();
  58179. var rs = clone(this.renderState, false);
  58180. if (translucent) {
  58181. rs.depthMask = false;
  58182. rs.blending = BlendingState.ALPHA_BLEND;
  58183. } else {
  58184. rs.depthMask = true;
  58185. }
  58186. return rs;
  58187. };
  58188. /**
  58189. * @private
  58190. */
  58191. Appearance.getDefaultRenderState = function(translucent, closed, existing) {
  58192. var rs = {
  58193. depthTest : {
  58194. enabled : true
  58195. }
  58196. };
  58197. if (translucent) {
  58198. rs.depthMask = false;
  58199. rs.blending = BlendingState.ALPHA_BLEND;
  58200. }
  58201. if (closed) {
  58202. rs.cull = {
  58203. enabled : true,
  58204. face : CullFace.BACK
  58205. };
  58206. }
  58207. if (defined(existing)) {
  58208. rs = combine(existing, rs, true);
  58209. }
  58210. return rs;
  58211. };
  58212. return Appearance;
  58213. });
  58214. /*global define*/
  58215. define('Renderer/ContextLimits',[
  58216. '../Core/defineProperties'
  58217. ], function(
  58218. defineProperties) {
  58219. 'use strict';
  58220. /**
  58221. * @private
  58222. */
  58223. var ContextLimits = {
  58224. _maximumCombinedTextureImageUnits : 0,
  58225. _maximumCubeMapSize : 0,
  58226. _maximumFragmentUniformVectors : 0,
  58227. _maximumTextureImageUnits : 0,
  58228. _maximumRenderbufferSize : 0,
  58229. _maximumTextureSize : 0,
  58230. _maximumVaryingVectors : 0,
  58231. _maximumVertexAttributes : 0,
  58232. _maximumVertexTextureImageUnits : 0,
  58233. _maximumVertexUniformVectors : 0,
  58234. _minimumAliasedLineWidth : 0,
  58235. _maximumAliasedLineWidth : 0,
  58236. _minimumAliasedPointSize : 0,
  58237. _maximumAliasedPointSize : 0,
  58238. _maximumViewportWidth : 0,
  58239. _maximumViewportHeight : 0,
  58240. _maximumTextureFilterAnisotropy : 0,
  58241. _maximumDrawBuffers : 0,
  58242. _maximumColorAttachments : 0,
  58243. _highpFloatSupported: false,
  58244. _highpIntSupported: false
  58245. };
  58246. defineProperties(ContextLimits, {
  58247. /**
  58248. * The maximum number of texture units that can be used from the vertex and fragment
  58249. * shader with this WebGL implementation. The minimum is eight. If both shaders access the
  58250. * same texture unit, this counts as two texture units.
  58251. * @memberof ContextLimits
  58252. * @type {Number}
  58253. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>MAX_COMBINED_TEXTURE_IMAGE_UNITS</code>.
  58254. */
  58255. maximumCombinedTextureImageUnits : {
  58256. get: function () {
  58257. return ContextLimits._maximumCombinedTextureImageUnits;
  58258. }
  58259. },
  58260. /**
  58261. * The approximate maximum cube mape width and height supported by this WebGL implementation.
  58262. * The minimum is 16, but most desktop and laptop implementations will support much larger sizes like 8,192.
  58263. * @memberof ContextLimits
  58264. * @type {Number}
  58265. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>MAX_CUBE_MAP_TEXTURE_SIZE</code>.
  58266. */
  58267. maximumCubeMapSize : {
  58268. get: function () {
  58269. return ContextLimits._maximumCubeMapSize;
  58270. }
  58271. },
  58272. /**
  58273. * The maximum number of <code>vec4</code>, <code>ivec4</code>, and <code>bvec4</code>
  58274. * uniforms that can be used by a fragment shader with this WebGL implementation. The minimum is 16.
  58275. * @memberof ContextLimits
  58276. * @type {Number}
  58277. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>MAX_FRAGMENT_UNIFORM_VECTORS</code>.
  58278. */
  58279. maximumFragmentUniformVectors : {
  58280. get: function () {
  58281. return ContextLimits._maximumFragmentUniformVectors;
  58282. }
  58283. },
  58284. /**
  58285. * The maximum number of texture units that can be used from the fragment shader with this WebGL implementation. The minimum is eight.
  58286. * @memberof ContextLimits
  58287. * @type {Number}
  58288. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>MAX_TEXTURE_IMAGE_UNITS</code>.
  58289. */
  58290. maximumTextureImageUnits : {
  58291. get: function () {
  58292. return ContextLimits._maximumTextureImageUnits;
  58293. }
  58294. },
  58295. /**
  58296. * The maximum renderbuffer width and height supported by this WebGL implementation.
  58297. * The minimum is 16, but most desktop and laptop implementations will support much larger sizes like 8,192.
  58298. * @memberof ContextLimits
  58299. * @type {Number}
  58300. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>MAX_RENDERBUFFER_SIZE</code>.
  58301. */
  58302. maximumRenderbufferSize : {
  58303. get: function () {
  58304. return ContextLimits._maximumRenderbufferSize;
  58305. }
  58306. },
  58307. /**
  58308. * The approximate maximum texture width and height supported by this WebGL implementation.
  58309. * The minimum is 64, but most desktop and laptop implementations will support much larger sizes like 8,192.
  58310. * @memberof ContextLimits
  58311. * @type {Number}
  58312. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>MAX_TEXTURE_SIZE</code>.
  58313. */
  58314. maximumTextureSize : {
  58315. get: function () {
  58316. return ContextLimits._maximumTextureSize;
  58317. }
  58318. },
  58319. /**
  58320. * The maximum number of <code>vec4</code> varying variables supported by this WebGL implementation.
  58321. * The minimum is eight. Matrices and arrays count as multiple <code>vec4</code>s.
  58322. * @memberof ContextLimits
  58323. * @type {Number}
  58324. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>MAX_VARYING_VECTORS</code>.
  58325. */
  58326. maximumVaryingVectors : {
  58327. get: function () {
  58328. return ContextLimits._maximumVaryingVectors;
  58329. }
  58330. },
  58331. /**
  58332. * The maximum number of <code>vec4</code> vertex attributes supported by this WebGL implementation. The minimum is eight.
  58333. * @memberof ContextLimits
  58334. * @type {Number}
  58335. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>MAX_VERTEX_ATTRIBS</code>.
  58336. */
  58337. maximumVertexAttributes : {
  58338. get: function () {
  58339. return ContextLimits._maximumVertexAttributes;
  58340. }
  58341. },
  58342. /**
  58343. * The maximum number of texture units that can be used from the vertex shader with this WebGL implementation.
  58344. * The minimum is zero, which means the GL does not support vertex texture fetch.
  58345. * @memberof ContextLimits
  58346. * @type {Number}
  58347. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>MAX_VERTEX_TEXTURE_IMAGE_UNITS</code>.
  58348. */
  58349. maximumVertexTextureImageUnits : {
  58350. get: function () {
  58351. return ContextLimits._maximumVertexTextureImageUnits;
  58352. }
  58353. },
  58354. /**
  58355. * The maximum number of <code>vec4</code>, <code>ivec4</code>, and <code>bvec4</code>
  58356. * uniforms that can be used by a vertex shader with this WebGL implementation. The minimum is 16.
  58357. * @memberof ContextLimits
  58358. * @type {Number}
  58359. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>MAX_VERTEX_UNIFORM_VECTORS</code>.
  58360. */
  58361. maximumVertexUniformVectors : {
  58362. get: function () {
  58363. return ContextLimits._maximumVertexUniformVectors;
  58364. }
  58365. },
  58366. /**
  58367. * The minimum aliased line width, in pixels, supported by this WebGL implementation. It will be at most one.
  58368. * @memberof ContextLimits
  58369. * @type {Number}
  58370. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>ALIASED_LINE_WIDTH_RANGE</code>.
  58371. */
  58372. minimumAliasedLineWidth : {
  58373. get: function () {
  58374. return ContextLimits._minimumAliasedLineWidth;
  58375. }
  58376. },
  58377. /**
  58378. * The maximum aliased line width, in pixels, supported by this WebGL implementation. It will be at least one.
  58379. * @memberof ContextLimits
  58380. * @type {Number}
  58381. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>ALIASED_LINE_WIDTH_RANGE</code>.
  58382. */
  58383. maximumAliasedLineWidth : {
  58384. get: function () {
  58385. return ContextLimits._maximumAliasedLineWidth;
  58386. }
  58387. },
  58388. /**
  58389. * The minimum aliased point size, in pixels, supported by this WebGL implementation. It will be at most one.
  58390. * @memberof ContextLimits
  58391. * @type {Number}
  58392. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>ALIASED_POINT_SIZE_RANGE</code>.
  58393. */
  58394. minimumAliasedPointSize : {
  58395. get: function () {
  58396. return ContextLimits._minimumAliasedPointSize;
  58397. }
  58398. },
  58399. /**
  58400. * The maximum aliased point size, in pixels, supported by this WebGL implementation. It will be at least one.
  58401. * @memberof ContextLimits
  58402. * @type {Number}
  58403. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>ALIASED_POINT_SIZE_RANGE</code>.
  58404. */
  58405. maximumAliasedPointSize : {
  58406. get: function () {
  58407. return ContextLimits._maximumAliasedPointSize;
  58408. }
  58409. },
  58410. /**
  58411. * The maximum supported width of the viewport. It will be at least as large as the visible width of the associated canvas.
  58412. * @memberof ContextLimits
  58413. * @type {Number}
  58414. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>MAX_VIEWPORT_DIMS</code>.
  58415. */
  58416. maximumViewportWidth : {
  58417. get: function () {
  58418. return ContextLimits._maximumViewportWidth;
  58419. }
  58420. },
  58421. /**
  58422. * The maximum supported height of the viewport. It will be at least as large as the visible height of the associated canvas.
  58423. * @memberof ContextLimits
  58424. * @type {Number}
  58425. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>MAX_VIEWPORT_DIMS</code>.
  58426. */
  58427. maximumViewportHeight : {
  58428. get: function () {
  58429. return ContextLimits._maximumViewportHeight;
  58430. }
  58431. },
  58432. /**
  58433. * The maximum degree of anisotropy for texture filtering
  58434. * @memberof ContextLimits
  58435. * @type {Number}
  58436. */
  58437. maximumTextureFilterAnisotropy : {
  58438. get: function () {
  58439. return ContextLimits._maximumTextureFilterAnisotropy;
  58440. }
  58441. },
  58442. /**
  58443. * The maximum number of simultaneous outputs that may be written in a fragment shader.
  58444. * @memberof ContextLimits
  58445. * @type {Number}
  58446. */
  58447. maximumDrawBuffers : {
  58448. get: function () {
  58449. return ContextLimits._maximumDrawBuffers;
  58450. }
  58451. },
  58452. /**
  58453. * The maximum number of color attachments supported.
  58454. * @memberof ContextLimits
  58455. * @type {Number}
  58456. */
  58457. maximumColorAttachments : {
  58458. get: function () {
  58459. return ContextLimits._maximumColorAttachments;
  58460. }
  58461. },
  58462. /**
  58463. * High precision float supported (<code>highp</code>) in fragment shaders.
  58464. * @memberof ContextLimits
  58465. * @type {Boolean}
  58466. */
  58467. highpFloatSupported : {
  58468. get: function () {
  58469. return ContextLimits._highpFloatSupported;
  58470. }
  58471. },
  58472. /**
  58473. * High precision int supported (<code>highp</code>) in fragment shaders.
  58474. * @memberof ContextLimits
  58475. * @type {Boolean}
  58476. */
  58477. highpIntSupported : {
  58478. get: function () {
  58479. return ContextLimits._highpIntSupported;
  58480. }
  58481. }
  58482. });
  58483. return ContextLimits;
  58484. });
  58485. /*global define*/
  58486. define('Renderer/PixelDatatype',[
  58487. '../Core/freezeObject',
  58488. '../Core/WebGLConstants'
  58489. ], function(
  58490. freezeObject,
  58491. WebGLConstants) {
  58492. 'use strict';
  58493. /**
  58494. * @private
  58495. */
  58496. var PixelDatatype = {
  58497. UNSIGNED_BYTE : WebGLConstants.UNSIGNED_BYTE,
  58498. UNSIGNED_SHORT : WebGLConstants.UNSIGNED_SHORT,
  58499. UNSIGNED_INT : WebGLConstants.UNSIGNED_INT,
  58500. FLOAT : WebGLConstants.FLOAT,
  58501. UNSIGNED_INT_24_8 : WebGLConstants.UNSIGNED_INT_24_8,
  58502. UNSIGNED_SHORT_4_4_4_4 : WebGLConstants.UNSIGNED_SHORT_4_4_4_4,
  58503. UNSIGNED_SHORT_5_5_5_1 : WebGLConstants.UNSIGNED_SHORT_5_5_5_1,
  58504. UNSIGNED_SHORT_5_6_5 : WebGLConstants.UNSIGNED_SHORT_5_6_5,
  58505. validate : function(pixelDatatype) {
  58506. return ((pixelDatatype === PixelDatatype.UNSIGNED_BYTE) ||
  58507. (pixelDatatype === PixelDatatype.UNSIGNED_SHORT) ||
  58508. (pixelDatatype === PixelDatatype.UNSIGNED_INT) ||
  58509. (pixelDatatype === PixelDatatype.FLOAT) ||
  58510. (pixelDatatype === PixelDatatype.UNSIGNED_INT_24_8) ||
  58511. (pixelDatatype === PixelDatatype.UNSIGNED_SHORT_4_4_4_4) ||
  58512. (pixelDatatype === PixelDatatype.UNSIGNED_SHORT_5_5_5_1) ||
  58513. (pixelDatatype === PixelDatatype.UNSIGNED_SHORT_5_6_5));
  58514. }
  58515. };
  58516. return freezeObject(PixelDatatype);
  58517. });
  58518. /*global define*/
  58519. define('Renderer/CubeMapFace',[
  58520. '../Core/defaultValue',
  58521. '../Core/defineProperties',
  58522. '../Core/DeveloperError',
  58523. './PixelDatatype'
  58524. ], function(
  58525. defaultValue,
  58526. defineProperties,
  58527. DeveloperError,
  58528. PixelDatatype) {
  58529. 'use strict';
  58530. /**
  58531. * @private
  58532. */
  58533. function CubeMapFace(gl, texture, textureTarget, targetFace, pixelFormat, pixelDatatype, size, preMultiplyAlpha, flipY) {
  58534. this._gl = gl;
  58535. this._texture = texture;
  58536. this._textureTarget = textureTarget;
  58537. this._targetFace = targetFace;
  58538. this._pixelFormat = pixelFormat;
  58539. this._pixelDatatype = pixelDatatype;
  58540. this._size = size;
  58541. this._preMultiplyAlpha = preMultiplyAlpha;
  58542. this._flipY = flipY;
  58543. }
  58544. defineProperties(CubeMapFace.prototype, {
  58545. pixelFormat : {
  58546. get : function() {
  58547. return this._pixelFormat;
  58548. }
  58549. },
  58550. pixelDatatype : {
  58551. get : function() {
  58552. return this._pixelDatatype;
  58553. }
  58554. },
  58555. _target : {
  58556. get : function() {
  58557. return this._targetFace;
  58558. }
  58559. }
  58560. });
  58561. /**
  58562. * Copies texels from the source to the cubemap's face.
  58563. *
  58564. * @param {Object} source The source ImageData, HTMLImageElement, HTMLCanvasElement, HTMLVideoElement, or an object with a width, height, and typed array as shown in the example.
  58565. * @param {Number} [xOffset=0] An offset in the x direction in the cubemap where copying begins.
  58566. * @param {Number} [yOffset=0] An offset in the y direction in the cubemap where copying begins.
  58567. *
  58568. * @exception {DeveloperError} xOffset must be greater than or equal to zero.
  58569. * @exception {DeveloperError} yOffset must be greater than or equal to zero.
  58570. * @exception {DeveloperError} xOffset + source.width must be less than or equal to width.
  58571. * @exception {DeveloperError} yOffset + source.height must be less than or equal to height.
  58572. * @exception {DeveloperError} This CubeMap was destroyed, i.e., destroy() was called.
  58573. *
  58574. * @example
  58575. * // Create a cubemap with 1x1 faces, and make the +x face red.
  58576. * var cubeMap = new CubeMap({
  58577. * context : context
  58578. * width : 1,
  58579. * height : 1
  58580. * });
  58581. * cubeMap.positiveX.copyFrom({
  58582. * width : 1,
  58583. * height : 1,
  58584. * arrayBufferView : new Uint8Array([255, 0, 0, 255])
  58585. * });
  58586. */
  58587. CubeMapFace.prototype.copyFrom = function(source, xOffset, yOffset) {
  58588. xOffset = defaultValue(xOffset, 0);
  58589. yOffset = defaultValue(yOffset, 0);
  58590. if (!source) {
  58591. throw new DeveloperError('source is required.');
  58592. }
  58593. if (xOffset < 0) {
  58594. throw new DeveloperError('xOffset must be greater than or equal to zero.');
  58595. }
  58596. if (yOffset < 0) {
  58597. throw new DeveloperError('yOffset must be greater than or equal to zero.');
  58598. }
  58599. if (xOffset + source.width > this._size) {
  58600. throw new DeveloperError('xOffset + source.width must be less than or equal to width.');
  58601. }
  58602. if (yOffset + source.height > this._size) {
  58603. throw new DeveloperError('yOffset + source.height must be less than or equal to height.');
  58604. }
  58605. var gl = this._gl;
  58606. var target = this._textureTarget;
  58607. // TODO: gl.pixelStorei(gl._UNPACK_ALIGNMENT, 4);
  58608. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this._preMultiplyAlpha);
  58609. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, this._flipY);
  58610. gl.activeTexture(gl.TEXTURE0);
  58611. gl.bindTexture(target, this._texture);
  58612. if (source.arrayBufferView) {
  58613. gl.texSubImage2D(this._targetFace, 0, xOffset, yOffset, source.width, source.height, this._pixelFormat, this._pixelDatatype, source.arrayBufferView);
  58614. } else {
  58615. gl.texSubImage2D(this._targetFace, 0, xOffset, yOffset, this._pixelFormat, this._pixelDatatype, source);
  58616. }
  58617. gl.bindTexture(target, null);
  58618. };
  58619. /**
  58620. * Copies texels from the framebuffer to the cubemap's face.
  58621. *
  58622. * @param {Number} [xOffset=0] An offset in the x direction in the cubemap where copying begins.
  58623. * @param {Number} [yOffset=0] An offset in the y direction in the cubemap where copying begins.
  58624. * @param {Number} [framebufferXOffset=0] An offset in the x direction in the framebuffer where copying begins from.
  58625. * @param {Number} [framebufferYOffset=0] An offset in the y direction in the framebuffer where copying begins from.
  58626. * @param {Number} [width=CubeMap's width] The width of the subimage to copy.
  58627. * @param {Number} [height=CubeMap's height] The height of the subimage to copy.
  58628. *
  58629. * @exception {DeveloperError} Cannot call copyFromFramebuffer when the texture pixel data type is FLOAT.
  58630. * @exception {DeveloperError} This CubeMap was destroyed, i.e., destroy() was called.
  58631. * @exception {DeveloperError} xOffset must be greater than or equal to zero.
  58632. * @exception {DeveloperError} yOffset must be greater than or equal to zero.
  58633. * @exception {DeveloperError} framebufferXOffset must be greater than or equal to zero.
  58634. * @exception {DeveloperError} framebufferYOffset must be greater than or equal to zero.
  58635. * @exception {DeveloperError} xOffset + source.width must be less than or equal to width.
  58636. * @exception {DeveloperError} yOffset + source.height must be less than or equal to height.
  58637. * @exception {DeveloperError} This CubeMap was destroyed, i.e., destroy() was called.
  58638. *
  58639. * @example
  58640. * // Copy the framebuffer contents to the +x cube map face.
  58641. * cubeMap.positiveX.copyFromFramebuffer();
  58642. */
  58643. CubeMapFace.prototype.copyFromFramebuffer = function(xOffset, yOffset, framebufferXOffset, framebufferYOffset, width, height) {
  58644. xOffset = defaultValue(xOffset, 0);
  58645. yOffset = defaultValue(yOffset, 0);
  58646. framebufferXOffset = defaultValue(framebufferXOffset, 0);
  58647. framebufferYOffset = defaultValue(framebufferYOffset, 0);
  58648. width = defaultValue(width, this._size);
  58649. height = defaultValue(height, this._size);
  58650. if (xOffset < 0) {
  58651. throw new DeveloperError('xOffset must be greater than or equal to zero.');
  58652. }
  58653. if (yOffset < 0) {
  58654. throw new DeveloperError('yOffset must be greater than or equal to zero.');
  58655. }
  58656. if (framebufferXOffset < 0) {
  58657. throw new DeveloperError('framebufferXOffset must be greater than or equal to zero.');
  58658. }
  58659. if (framebufferYOffset < 0) {
  58660. throw new DeveloperError('framebufferYOffset must be greater than or equal to zero.');
  58661. }
  58662. if (xOffset + width > this._size) {
  58663. throw new DeveloperError('xOffset + source.width must be less than or equal to width.');
  58664. }
  58665. if (yOffset + height > this._size) {
  58666. throw new DeveloperError('yOffset + source.height must be less than or equal to height.');
  58667. }
  58668. if (this._pixelDatatype === PixelDatatype.FLOAT) {
  58669. throw new DeveloperError('Cannot call copyFromFramebuffer when the texture pixel data type is FLOAT.');
  58670. }
  58671. var gl = this._gl;
  58672. var target = this._textureTarget;
  58673. gl.activeTexture(gl.TEXTURE0);
  58674. gl.bindTexture(target, this._texture);
  58675. gl.copyTexSubImage2D(this._targetFace, 0, xOffset, yOffset, framebufferXOffset, framebufferYOffset, width, height);
  58676. gl.bindTexture(target, null);
  58677. };
  58678. return CubeMapFace;
  58679. });
  58680. /*global define*/
  58681. define('Renderer/MipmapHint',[
  58682. '../Core/freezeObject',
  58683. '../Core/WebGLConstants'
  58684. ], function(
  58685. freezeObject,
  58686. WebGLConstants) {
  58687. 'use strict';
  58688. /**
  58689. * @private
  58690. */
  58691. var MipmapHint = {
  58692. DONT_CARE : WebGLConstants.DONT_CARE,
  58693. FASTEST : WebGLConstants.FASTEST,
  58694. NICEST : WebGLConstants.NICEST,
  58695. validate : function(mipmapHint) {
  58696. return ((mipmapHint === MipmapHint.DONT_CARE) ||
  58697. (mipmapHint === MipmapHint.FASTEST) ||
  58698. (mipmapHint === MipmapHint.NICEST));
  58699. }
  58700. };
  58701. return freezeObject(MipmapHint);
  58702. });
  58703. /*global define*/
  58704. define('Renderer/TextureMagnificationFilter',[
  58705. '../Core/freezeObject',
  58706. '../Core/WebGLConstants'
  58707. ], function(
  58708. freezeObject,
  58709. WebGLConstants) {
  58710. 'use strict';
  58711. /**
  58712. * @private
  58713. */
  58714. var TextureMagnificationFilter = {
  58715. NEAREST : WebGLConstants.NEAREST,
  58716. LINEAR : WebGLConstants.LINEAR,
  58717. validate : function(textureMagnificationFilter) {
  58718. return ((textureMagnificationFilter === TextureMagnificationFilter.NEAREST) ||
  58719. (textureMagnificationFilter === TextureMagnificationFilter.LINEAR));
  58720. }
  58721. };
  58722. return freezeObject(TextureMagnificationFilter);
  58723. });
  58724. /*global define*/
  58725. define('Renderer/TextureMinificationFilter',[
  58726. '../Core/freezeObject',
  58727. '../Core/WebGLConstants'
  58728. ], function(
  58729. freezeObject,
  58730. WebGLConstants) {
  58731. 'use strict';
  58732. /**
  58733. * @private
  58734. */
  58735. var TextureMinificationFilter = {
  58736. NEAREST : WebGLConstants.NEAREST,
  58737. LINEAR : WebGLConstants.LINEAR,
  58738. NEAREST_MIPMAP_NEAREST : WebGLConstants.NEAREST_MIPMAP_NEAREST,
  58739. LINEAR_MIPMAP_NEAREST : WebGLConstants.LINEAR_MIPMAP_NEAREST,
  58740. NEAREST_MIPMAP_LINEAR : WebGLConstants.NEAREST_MIPMAP_LINEAR,
  58741. LINEAR_MIPMAP_LINEAR : WebGLConstants.LINEAR_MIPMAP_LINEAR,
  58742. validate : function(textureMinificationFilter) {
  58743. return ((textureMinificationFilter === TextureMinificationFilter.NEAREST) ||
  58744. (textureMinificationFilter === TextureMinificationFilter.LINEAR) ||
  58745. (textureMinificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST) ||
  58746. (textureMinificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_NEAREST) ||
  58747. (textureMinificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR) ||
  58748. (textureMinificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_LINEAR));
  58749. }
  58750. };
  58751. return freezeObject(TextureMinificationFilter);
  58752. });
  58753. /*global define*/
  58754. define('Renderer/TextureWrap',[
  58755. '../Core/freezeObject',
  58756. '../Core/WebGLConstants'
  58757. ], function(
  58758. freezeObject,
  58759. WebGLConstants) {
  58760. 'use strict';
  58761. /**
  58762. * @private
  58763. */
  58764. var TextureWrap = {
  58765. CLAMP_TO_EDGE : WebGLConstants.CLAMP_TO_EDGE,
  58766. REPEAT : WebGLConstants.REPEAT,
  58767. MIRRORED_REPEAT : WebGLConstants.MIRRORED_REPEAT,
  58768. validate : function(textureWrap) {
  58769. return ((textureWrap === TextureWrap.CLAMP_TO_EDGE) ||
  58770. (textureWrap === TextureWrap.REPEAT) ||
  58771. (textureWrap === TextureWrap.MIRRORED_REPEAT));
  58772. }
  58773. };
  58774. return freezeObject(TextureWrap);
  58775. });
  58776. /*global define*/
  58777. define('Renderer/Sampler',[
  58778. '../Core/defaultValue',
  58779. '../Core/defined',
  58780. '../Core/defineProperties',
  58781. '../Core/DeveloperError',
  58782. './TextureMagnificationFilter',
  58783. './TextureMinificationFilter',
  58784. './TextureWrap'
  58785. ], function(
  58786. defaultValue,
  58787. defined,
  58788. defineProperties,
  58789. DeveloperError,
  58790. TextureMagnificationFilter,
  58791. TextureMinificationFilter,
  58792. TextureWrap) {
  58793. 'use strict';
  58794. /**
  58795. * @private
  58796. */
  58797. function Sampler(options) {
  58798. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  58799. var wrapS = defaultValue(options.wrapS, TextureWrap.CLAMP_TO_EDGE);
  58800. var wrapT = defaultValue(options.wrapT, TextureWrap.CLAMP_TO_EDGE);
  58801. var minificationFilter = defaultValue(options.minificationFilter, TextureMinificationFilter.LINEAR);
  58802. var magnificationFilter = defaultValue(options.magnificationFilter, TextureMagnificationFilter.LINEAR);
  58803. var maximumAnisotropy = (defined(options.maximumAnisotropy)) ? options.maximumAnisotropy : 1.0;
  58804. if (!TextureWrap.validate(wrapS)) {
  58805. throw new DeveloperError('Invalid sampler.wrapS.');
  58806. }
  58807. if (!TextureWrap.validate(wrapT)) {
  58808. throw new DeveloperError('Invalid sampler.wrapT.');
  58809. }
  58810. if (!TextureMinificationFilter.validate(minificationFilter)) {
  58811. throw new DeveloperError('Invalid sampler.minificationFilter.');
  58812. }
  58813. if (!TextureMagnificationFilter.validate(magnificationFilter)) {
  58814. throw new DeveloperError('Invalid sampler.magnificationFilter.');
  58815. }
  58816. if (maximumAnisotropy < 1.0) {
  58817. throw new DeveloperError('sampler.maximumAnisotropy must be greater than or equal to one.');
  58818. }
  58819. this._wrapS = wrapS;
  58820. this._wrapT = wrapT;
  58821. this._minificationFilter = minificationFilter;
  58822. this._magnificationFilter = magnificationFilter;
  58823. this._maximumAnisotropy = maximumAnisotropy;
  58824. }
  58825. defineProperties(Sampler.prototype, {
  58826. wrapS : {
  58827. get : function() {
  58828. return this._wrapS;
  58829. }
  58830. },
  58831. wrapT : {
  58832. get : function() {
  58833. return this._wrapT;
  58834. }
  58835. },
  58836. minificationFilter : {
  58837. get : function() {
  58838. return this._minificationFilter;
  58839. }
  58840. },
  58841. magnificationFilter : {
  58842. get : function() {
  58843. return this._magnificationFilter;
  58844. }
  58845. },
  58846. maximumAnisotropy : {
  58847. get : function() {
  58848. return this._maximumAnisotropy;
  58849. }
  58850. }
  58851. });
  58852. return Sampler;
  58853. });
  58854. /*global define*/
  58855. define('Renderer/CubeMap',[
  58856. '../Core/defaultValue',
  58857. '../Core/defined',
  58858. '../Core/defineProperties',
  58859. '../Core/destroyObject',
  58860. '../Core/DeveloperError',
  58861. '../Core/Math',
  58862. '../Core/PixelFormat',
  58863. './ContextLimits',
  58864. './CubeMapFace',
  58865. './MipmapHint',
  58866. './PixelDatatype',
  58867. './Sampler',
  58868. './TextureMagnificationFilter',
  58869. './TextureMinificationFilter'
  58870. ], function(
  58871. defaultValue,
  58872. defined,
  58873. defineProperties,
  58874. destroyObject,
  58875. DeveloperError,
  58876. CesiumMath,
  58877. PixelFormat,
  58878. ContextLimits,
  58879. CubeMapFace,
  58880. MipmapHint,
  58881. PixelDatatype,
  58882. Sampler,
  58883. TextureMagnificationFilter,
  58884. TextureMinificationFilter) {
  58885. 'use strict';
  58886. function CubeMap(options) {
  58887. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  58888. if (!defined(options.context)) {
  58889. throw new DeveloperError('options.context is required.');
  58890. }
  58891. var context = options.context;
  58892. var source = options.source;
  58893. var width;
  58894. var height;
  58895. if (defined(source)) {
  58896. var faces = [source.positiveX, source.negativeX, source.positiveY, source.negativeY, source.positiveZ, source.negativeZ];
  58897. if (!faces[0] || !faces[1] || !faces[2] || !faces[3] || !faces[4] || !faces[5]) {
  58898. throw new DeveloperError('options.source requires positiveX, negativeX, positiveY, negativeY, positiveZ, and negativeZ faces.');
  58899. }
  58900. width = faces[0].width;
  58901. height = faces[0].height;
  58902. for ( var i = 1; i < 6; ++i) {
  58903. if ((Number(faces[i].width) !== width) || (Number(faces[i].height) !== height)) {
  58904. throw new DeveloperError('Each face in options.source must have the same width and height.');
  58905. }
  58906. }
  58907. } else {
  58908. width = options.width;
  58909. height = options.height;
  58910. }
  58911. var size = width;
  58912. var pixelFormat = defaultValue(options.pixelFormat, PixelFormat.RGBA);
  58913. var pixelDatatype = defaultValue(options.pixelDatatype, PixelDatatype.UNSIGNED_BYTE);
  58914. if (!defined(width) || !defined(height)) {
  58915. throw new DeveloperError('options requires a source field to create an initialized cube map or width and height fields to create a blank cube map.');
  58916. }
  58917. if (width !== height) {
  58918. throw new DeveloperError('Width must equal height.');
  58919. }
  58920. if (size <= 0) {
  58921. throw new DeveloperError('Width and height must be greater than zero.');
  58922. }
  58923. if (size > ContextLimits.maximumCubeMapSize) {
  58924. throw new DeveloperError('Width and height must be less than or equal to the maximum cube map size (' + ContextLimits.maximumCubeMapSize + '). Check maximumCubeMapSize.');
  58925. }
  58926. if (!PixelFormat.validate(pixelFormat)) {
  58927. throw new DeveloperError('Invalid options.pixelFormat.');
  58928. }
  58929. if (PixelFormat.isDepthFormat(pixelFormat)) {
  58930. throw new DeveloperError('options.pixelFormat cannot be DEPTH_COMPONENT or DEPTH_STENCIL.');
  58931. }
  58932. if (!PixelDatatype.validate(pixelDatatype)) {
  58933. throw new DeveloperError('Invalid options.pixelDatatype.');
  58934. }
  58935. if ((pixelDatatype === PixelDatatype.FLOAT) && !context.floatingPointTexture) {
  58936. throw new DeveloperError('When options.pixelDatatype is FLOAT, this WebGL implementation must support the OES_texture_float extension.');
  58937. }
  58938. // Use premultiplied alpha for opaque textures should perform better on Chrome:
  58939. // http://media.tojicode.com/webglCamp4/#20
  58940. var preMultiplyAlpha = options.preMultiplyAlpha || ((pixelFormat === PixelFormat.RGB) || (pixelFormat === PixelFormat.LUMINANCE));
  58941. var flipY = defaultValue(options.flipY, true);
  58942. var gl = context._gl;
  58943. var textureTarget = gl.TEXTURE_CUBE_MAP;
  58944. var texture = gl.createTexture();
  58945. gl.activeTexture(gl.TEXTURE0);
  58946. gl.bindTexture(textureTarget, texture);
  58947. function createFace(target, sourceFace) {
  58948. if (sourceFace.arrayBufferView) {
  58949. gl.texImage2D(target, 0, pixelFormat, size, size, 0, pixelFormat, pixelDatatype, sourceFace.arrayBufferView);
  58950. } else {
  58951. gl.texImage2D(target, 0, pixelFormat, pixelFormat, pixelDatatype, sourceFace);
  58952. }
  58953. }
  58954. if (defined(source)) {
  58955. // TODO: _gl.pixelStorei(_gl._UNPACK_ALIGNMENT, 4);
  58956. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, preMultiplyAlpha);
  58957. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
  58958. createFace(gl.TEXTURE_CUBE_MAP_POSITIVE_X, source.positiveX);
  58959. createFace(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, source.negativeX);
  58960. createFace(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, source.positiveY);
  58961. createFace(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, source.negativeY);
  58962. createFace(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, source.positiveZ);
  58963. createFace(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, source.negativeZ);
  58964. } else {
  58965. gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, pixelFormat, size, size, 0, pixelFormat, pixelDatatype, null);
  58966. gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, pixelFormat, size, size, 0, pixelFormat, pixelDatatype, null);
  58967. gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, pixelFormat, size, size, 0, pixelFormat, pixelDatatype, null);
  58968. gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, pixelFormat, size, size, 0, pixelFormat, pixelDatatype, null);
  58969. gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, pixelFormat, size, size, 0, pixelFormat, pixelDatatype, null);
  58970. gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, pixelFormat, size, size, 0, pixelFormat, pixelDatatype, null);
  58971. }
  58972. gl.bindTexture(textureTarget, null);
  58973. this._gl = gl;
  58974. this._textureFilterAnisotropic = context._textureFilterAnisotropic;
  58975. this._textureTarget = textureTarget;
  58976. this._texture = texture;
  58977. this._pixelFormat = pixelFormat;
  58978. this._pixelDatatype = pixelDatatype;
  58979. this._size = size;
  58980. this._preMultiplyAlpha = preMultiplyAlpha;
  58981. this._flipY = flipY;
  58982. this._sampler = undefined;
  58983. this._positiveX = new CubeMapFace(gl, texture, textureTarget, gl.TEXTURE_CUBE_MAP_POSITIVE_X, pixelFormat, pixelDatatype, size, preMultiplyAlpha, flipY);
  58984. this._negativeX = new CubeMapFace(gl, texture, textureTarget, gl.TEXTURE_CUBE_MAP_NEGATIVE_X, pixelFormat, pixelDatatype, size, preMultiplyAlpha, flipY);
  58985. this._positiveY = new CubeMapFace(gl, texture, textureTarget, gl.TEXTURE_CUBE_MAP_POSITIVE_Y, pixelFormat, pixelDatatype, size, preMultiplyAlpha, flipY);
  58986. this._negativeY = new CubeMapFace(gl, texture, textureTarget, gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, pixelFormat, pixelDatatype, size, preMultiplyAlpha, flipY);
  58987. this._positiveZ = new CubeMapFace(gl, texture, textureTarget, gl.TEXTURE_CUBE_MAP_POSITIVE_Z, pixelFormat, pixelDatatype, size, preMultiplyAlpha, flipY);
  58988. this._negativeZ = new CubeMapFace(gl, texture, textureTarget, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, pixelFormat, pixelDatatype, size, preMultiplyAlpha, flipY);
  58989. this.sampler = defined(options.sampler) ? options.sampler : new Sampler();
  58990. }
  58991. defineProperties(CubeMap.prototype, {
  58992. positiveX : {
  58993. get : function() {
  58994. return this._positiveX;
  58995. }
  58996. },
  58997. negativeX : {
  58998. get : function() {
  58999. return this._negativeX;
  59000. }
  59001. },
  59002. positiveY : {
  59003. get : function() {
  59004. return this._positiveY;
  59005. }
  59006. },
  59007. negativeY : {
  59008. get : function() {
  59009. return this._negativeY;
  59010. }
  59011. },
  59012. positiveZ : {
  59013. get : function() {
  59014. return this._positiveZ;
  59015. }
  59016. },
  59017. negativeZ : {
  59018. get : function() {
  59019. return this._negativeZ;
  59020. }
  59021. },
  59022. sampler : {
  59023. get : function() {
  59024. return this._sampler;
  59025. },
  59026. set : function(sampler) {
  59027. var minificationFilter = sampler.minificationFilter;
  59028. var magnificationFilter = sampler.magnificationFilter;
  59029. var mipmap =
  59030. (minificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST) ||
  59031. (minificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR) ||
  59032. (minificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_NEAREST) ||
  59033. (minificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_LINEAR);
  59034. // float textures only support nearest filtering, so override the sampler's settings
  59035. if (this._pixelDatatype === PixelDatatype.FLOAT) {
  59036. minificationFilter = mipmap ? TextureMinificationFilter.NEAREST_MIPMAP_NEAREST : TextureMinificationFilter.NEAREST;
  59037. magnificationFilter = TextureMagnificationFilter.NEAREST;
  59038. }
  59039. var gl = this._gl;
  59040. var target = this._textureTarget;
  59041. gl.activeTexture(gl.TEXTURE0);
  59042. gl.bindTexture(target, this._texture);
  59043. gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, minificationFilter);
  59044. gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, magnificationFilter);
  59045. gl.texParameteri(target, gl.TEXTURE_WRAP_S, sampler.wrapS);
  59046. gl.texParameteri(target, gl.TEXTURE_WRAP_T, sampler.wrapT);
  59047. if (defined(this._textureFilterAnisotropic)) {
  59048. gl.texParameteri(target, this._textureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, sampler.maximumAnisotropy);
  59049. }
  59050. gl.bindTexture(target, null);
  59051. this._sampler = sampler;
  59052. }
  59053. },
  59054. pixelFormat: {
  59055. get : function() {
  59056. return this._pixelFormat;
  59057. }
  59058. },
  59059. pixelDatatype : {
  59060. get : function() {
  59061. return this._pixelDatatype;
  59062. }
  59063. },
  59064. width : {
  59065. get : function() {
  59066. return this._size;
  59067. }
  59068. },
  59069. height: {
  59070. get : function() {
  59071. return this._size;
  59072. }
  59073. },
  59074. preMultiplyAlpha : {
  59075. get : function() {
  59076. return this._preMultiplyAlpha;
  59077. }
  59078. },
  59079. flipY : {
  59080. get : function() {
  59081. return this._flipY;
  59082. }
  59083. },
  59084. _target : {
  59085. get : function() {
  59086. return this._textureTarget;
  59087. }
  59088. }
  59089. });
  59090. /**
  59091. * Generates a complete mipmap chain for each cubemap face.
  59092. *
  59093. * @param {MipmapHint} [hint=MipmapHint.DONT_CARE] A performance vs. quality hint.
  59094. *
  59095. * @exception {DeveloperError} hint is invalid.
  59096. * @exception {DeveloperError} This CubeMap's width must be a power of two to call generateMipmap().
  59097. * @exception {DeveloperError} This CubeMap's height must be a power of two to call generateMipmap().
  59098. * @exception {DeveloperError} This CubeMap was destroyed, i.e., destroy() was called.
  59099. *
  59100. * @example
  59101. * // Generate mipmaps, and then set the sampler so mipmaps are used for
  59102. * // minification when the cube map is sampled.
  59103. * cubeMap.generateMipmap();
  59104. * cubeMap.sampler = new Sampler({
  59105. * minificationFilter : Cesium.TextureMinificationFilter.NEAREST_MIPMAP_LINEAR
  59106. * });
  59107. */
  59108. CubeMap.prototype.generateMipmap = function(hint) {
  59109. hint = defaultValue(hint, MipmapHint.DONT_CARE);
  59110. if ((this._size > 1) && !CesiumMath.isPowerOfTwo(this._size)) {
  59111. throw new DeveloperError('width and height must be a power of two to call generateMipmap().');
  59112. }
  59113. if (!MipmapHint.validate(hint)) {
  59114. throw new DeveloperError('hint is invalid.');
  59115. }
  59116. var gl = this._gl;
  59117. var target = this._textureTarget;
  59118. gl.hint(gl.GENERATE_MIPMAP_HINT, hint);
  59119. gl.activeTexture(gl.TEXTURE0);
  59120. gl.bindTexture(target, this._texture);
  59121. gl.generateMipmap(target);
  59122. gl.bindTexture(target, null);
  59123. };
  59124. CubeMap.prototype.isDestroyed = function() {
  59125. return false;
  59126. };
  59127. CubeMap.prototype.destroy = function() {
  59128. this._gl.deleteTexture(this._texture);
  59129. this._positiveX = destroyObject(this._positiveX);
  59130. this._negativeX = destroyObject(this._negativeX);
  59131. this._positiveY = destroyObject(this._positiveY);
  59132. this._negativeY = destroyObject(this._negativeY);
  59133. this._positiveZ = destroyObject(this._positiveZ);
  59134. this._negativeZ = destroyObject(this._negativeZ);
  59135. return destroyObject(this);
  59136. };
  59137. return CubeMap;
  59138. });
  59139. /*global define*/
  59140. define('Renderer/Texture',[
  59141. '../Core/Cartesian2',
  59142. '../Core/defaultValue',
  59143. '../Core/defined',
  59144. '../Core/defineProperties',
  59145. '../Core/destroyObject',
  59146. '../Core/DeveloperError',
  59147. '../Core/Math',
  59148. '../Core/PixelFormat',
  59149. '../Core/WebGLConstants',
  59150. './ContextLimits',
  59151. './MipmapHint',
  59152. './PixelDatatype',
  59153. './Sampler',
  59154. './TextureMagnificationFilter',
  59155. './TextureMinificationFilter'
  59156. ], function(
  59157. Cartesian2,
  59158. defaultValue,
  59159. defined,
  59160. defineProperties,
  59161. destroyObject,
  59162. DeveloperError,
  59163. CesiumMath,
  59164. PixelFormat,
  59165. WebGLConstants,
  59166. ContextLimits,
  59167. MipmapHint,
  59168. PixelDatatype,
  59169. Sampler,
  59170. TextureMagnificationFilter,
  59171. TextureMinificationFilter) {
  59172. 'use strict';
  59173. function Texture(options) {
  59174. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  59175. if (!defined(options.context)) {
  59176. throw new DeveloperError('options.context is required.');
  59177. }
  59178. var context = options.context;
  59179. var width = options.width;
  59180. var height = options.height;
  59181. var source = options.source;
  59182. if (defined(source)) {
  59183. if (!defined(width)) {
  59184. width = defaultValue(source.videoWidth, source.width);
  59185. }
  59186. if (!defined(height)) {
  59187. height = defaultValue(source.videoHeight, source.height);
  59188. }
  59189. }
  59190. var pixelFormat = defaultValue(options.pixelFormat, PixelFormat.RGBA);
  59191. var pixelDatatype = defaultValue(options.pixelDatatype, PixelDatatype.UNSIGNED_BYTE);
  59192. var internalFormat = pixelFormat;
  59193. if (context.webgl2) {
  59194. if (pixelFormat === PixelFormat.DEPTH_STENCIL) {
  59195. internalFormat = WebGLConstants.DEPTH24_STENCIL8;
  59196. } else if (pixelFormat === PixelFormat.DEPTH_COMPONENT) {
  59197. if (pixelDatatype === PixelDatatype.UNSIGNED_SHORT) {
  59198. internalFormat = WebGLConstants.DEPTH_COMPONENT16;
  59199. } else if (pixelDatatype === PixelDatatype.UNSIGNED_INT) {
  59200. internalFormat = WebGLConstants.DEPTH_COMPONENT24;
  59201. }
  59202. }
  59203. }
  59204. if (!defined(width) || !defined(height)) {
  59205. throw new DeveloperError('options requires a source field to create an initialized texture or width and height fields to create a blank texture.');
  59206. }
  59207. if (width <= 0) {
  59208. throw new DeveloperError('Width must be greater than zero.');
  59209. }
  59210. if (width > ContextLimits.maximumTextureSize) {
  59211. throw new DeveloperError('Width must be less than or equal to the maximum texture size (' + ContextLimits.maximumTextureSize + '). Check maximumTextureSize.');
  59212. }
  59213. if (height <= 0) {
  59214. throw new DeveloperError('Height must be greater than zero.');
  59215. }
  59216. if (height > ContextLimits.maximumTextureSize) {
  59217. throw new DeveloperError('Height must be less than or equal to the maximum texture size (' + ContextLimits.maximumTextureSize + '). Check maximumTextureSize.');
  59218. }
  59219. if (!PixelFormat.validate(pixelFormat)) {
  59220. throw new DeveloperError('Invalid options.pixelFormat.');
  59221. }
  59222. if (!PixelDatatype.validate(pixelDatatype)) {
  59223. throw new DeveloperError('Invalid options.pixelDatatype.');
  59224. }
  59225. if ((pixelFormat === PixelFormat.DEPTH_COMPONENT) &&
  59226. ((pixelDatatype !== PixelDatatype.UNSIGNED_SHORT) && (pixelDatatype !== PixelDatatype.UNSIGNED_INT))) {
  59227. throw new DeveloperError('When options.pixelFormat is DEPTH_COMPONENT, options.pixelDatatype must be UNSIGNED_SHORT or UNSIGNED_INT.');
  59228. }
  59229. if ((pixelFormat === PixelFormat.DEPTH_STENCIL) && (pixelDatatype !== PixelDatatype.UNSIGNED_INT_24_8)) {
  59230. throw new DeveloperError('When options.pixelFormat is DEPTH_STENCIL, options.pixelDatatype must be UNSIGNED_INT_24_8.');
  59231. }
  59232. if ((pixelDatatype === PixelDatatype.FLOAT) && !context.floatingPointTexture) {
  59233. throw new DeveloperError('When options.pixelDatatype is FLOAT, this WebGL implementation must support the OES_texture_float extension. Check context.floatingPointTexture.');
  59234. }
  59235. if (PixelFormat.isDepthFormat(pixelFormat)) {
  59236. if (defined(source)) {
  59237. throw new DeveloperError('When options.pixelFormat is DEPTH_COMPONENT or DEPTH_STENCIL, source cannot be provided.');
  59238. }
  59239. if (!context.depthTexture) {
  59240. throw new DeveloperError('When options.pixelFormat is DEPTH_COMPONENT or DEPTH_STENCIL, this WebGL implementation must support WEBGL_depth_texture. Check context.depthTexture.');
  59241. }
  59242. }
  59243. // Use premultiplied alpha for opaque textures should perform better on Chrome:
  59244. // http://media.tojicode.com/webglCamp4/#20
  59245. var preMultiplyAlpha = options.preMultiplyAlpha || pixelFormat === PixelFormat.RGB || pixelFormat === PixelFormat.LUMINANCE;
  59246. var flipY = defaultValue(options.flipY, true);
  59247. var gl = context._gl;
  59248. var textureTarget = gl.TEXTURE_2D;
  59249. var texture = gl.createTexture();
  59250. gl.activeTexture(gl.TEXTURE0);
  59251. gl.bindTexture(textureTarget, texture);
  59252. if (defined(source)) {
  59253. // TODO: _gl.pixelStorei(_gl._UNPACK_ALIGNMENT, 4);
  59254. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, preMultiplyAlpha);
  59255. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
  59256. if (defined(source.arrayBufferView)) {
  59257. // Source: typed array
  59258. gl.texImage2D(textureTarget, 0, internalFormat, width, height, 0, pixelFormat, pixelDatatype, source.arrayBufferView);
  59259. } else if (defined(source.framebuffer)) {
  59260. // Source: framebuffer
  59261. if (source.framebuffer !== context.defaultFramebuffer) {
  59262. source.framebuffer._bind();
  59263. }
  59264. gl.copyTexImage2D(textureTarget, 0, internalFormat, source.xOffset, source.yOffset, width, height, 0);
  59265. if (source.framebuffer !== context.defaultFramebuffer) {
  59266. source.framebuffer._unBind();
  59267. }
  59268. } else {
  59269. // Source: ImageData, HTMLImageElement, HTMLCanvasElement, or HTMLVideoElement
  59270. gl.texImage2D(textureTarget, 0, internalFormat, pixelFormat, pixelDatatype, source);
  59271. }
  59272. } else {
  59273. gl.texImage2D(textureTarget, 0, internalFormat, width, height, 0, pixelFormat, pixelDatatype, null);
  59274. }
  59275. gl.bindTexture(textureTarget, null);
  59276. this._context = context;
  59277. this._textureFilterAnisotropic = context._textureFilterAnisotropic;
  59278. this._textureTarget = textureTarget;
  59279. this._texture = texture;
  59280. this._pixelFormat = pixelFormat;
  59281. this._pixelDatatype = pixelDatatype;
  59282. this._width = width;
  59283. this._height = height;
  59284. this._dimensions = new Cartesian2(width, height);
  59285. this._preMultiplyAlpha = preMultiplyAlpha;
  59286. this._flipY = flipY;
  59287. this._sampler = undefined;
  59288. this.sampler = defined(options.sampler) ? options.sampler : new Sampler();
  59289. }
  59290. /**
  59291. * Creates a texture, and copies a subimage of the framebuffer to it. When called without arguments,
  59292. * the texture is the same width and height as the framebuffer and contains its contents.
  59293. *
  59294. * @param {Object} options Object with the following properties:
  59295. * @param {Context} options.context The context in which the Texture gets created.
  59296. * @param {PixelFormat} [options.pixelFormat=PixelFormat.RGB] The texture's internal pixel format.
  59297. * @param {Number} [options.framebufferXOffset=0] An offset in the x direction in the framebuffer where copying begins from.
  59298. * @param {Number} [options.framebufferYOffset=0] An offset in the y direction in the framebuffer where copying begins from.
  59299. * @param {Number} [options.width=canvas.clientWidth] The width of the texture in texels.
  59300. * @param {Number} [options.height=canvas.clientHeight] The height of the texture in texels.
  59301. * @param {Framebuffer} [options.framebuffer=defaultFramebuffer] The framebuffer from which to create the texture. If this
  59302. * parameter is not specified, the default framebuffer is used.
  59303. * @returns {Texture} A texture with contents from the framebuffer.
  59304. *
  59305. * @exception {DeveloperError} Invalid pixelFormat.
  59306. * @exception {DeveloperError} pixelFormat cannot be DEPTH_COMPONENT or DEPTH_STENCIL.
  59307. * @exception {DeveloperError} framebufferXOffset must be greater than or equal to zero.
  59308. * @exception {DeveloperError} framebufferYOffset must be greater than or equal to zero.
  59309. * @exception {DeveloperError} framebufferXOffset + width must be less than or equal to canvas.clientWidth.
  59310. * @exception {DeveloperError} framebufferYOffset + height must be less than or equal to canvas.clientHeight.
  59311. *
  59312. *
  59313. * @example
  59314. * // Create a texture with the contents of the framebuffer.
  59315. * var t = Texture.fromFramebuffer({
  59316. * context : context
  59317. * });
  59318. *
  59319. * @see Sampler
  59320. *
  59321. * @private
  59322. */
  59323. Texture.fromFramebuffer = function(options) {
  59324. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  59325. if (!defined(options.context)) {
  59326. throw new DeveloperError('options.context is required.');
  59327. }
  59328. var context = options.context;
  59329. var gl = context._gl;
  59330. var pixelFormat = defaultValue(options.pixelFormat, PixelFormat.RGB);
  59331. var framebufferXOffset = defaultValue(options.framebufferXOffset, 0);
  59332. var framebufferYOffset = defaultValue(options.framebufferYOffset, 0);
  59333. var width = defaultValue(options.width, gl.drawingBufferWidth);
  59334. var height = defaultValue(options.height, gl.drawingBufferHeight);
  59335. var framebuffer = options.framebuffer;
  59336. if (!defined(options.context)) {
  59337. throw new DeveloperError('context is required.');
  59338. }
  59339. if (!PixelFormat.validate(pixelFormat)) {
  59340. throw new DeveloperError('Invalid pixelFormat.');
  59341. }
  59342. if (PixelFormat.isDepthFormat(pixelFormat)) {
  59343. throw new DeveloperError('pixelFormat cannot be DEPTH_COMPONENT or DEPTH_STENCIL.');
  59344. }
  59345. if (framebufferXOffset < 0) {
  59346. throw new DeveloperError('framebufferXOffset must be greater than or equal to zero.');
  59347. }
  59348. if (framebufferYOffset < 0) {
  59349. throw new DeveloperError('framebufferYOffset must be greater than or equal to zero.');
  59350. }
  59351. if (framebufferXOffset + width > gl.drawingBufferWidth) {
  59352. throw new DeveloperError('framebufferXOffset + width must be less than or equal to drawingBufferWidth');
  59353. }
  59354. if (framebufferYOffset + height > gl.drawingBufferHeight) {
  59355. throw new DeveloperError('framebufferYOffset + height must be less than or equal to drawingBufferHeight.');
  59356. }
  59357. var texture = new Texture({
  59358. context : context,
  59359. width : width,
  59360. height : height,
  59361. pixelFormat : pixelFormat,
  59362. source : {
  59363. framebuffer : defined(framebuffer) ? framebuffer : context.defaultFramebuffer,
  59364. xOffset : framebufferXOffset,
  59365. yOffset : framebufferYOffset,
  59366. width : width,
  59367. height : height
  59368. }
  59369. });
  59370. return texture;
  59371. };
  59372. defineProperties(Texture.prototype, {
  59373. /**
  59374. * The sampler to use when sampling this texture.
  59375. * Create a sampler by calling {@link Sampler}. If this
  59376. * parameter is not specified, a default sampler is used. The default sampler clamps texture
  59377. * coordinates in both directions, uses linear filtering for both magnification and minifcation,
  59378. * and uses a maximum anisotropy of 1.0.
  59379. * @memberof Texture.prototype
  59380. * @type {Object}
  59381. */
  59382. sampler : {
  59383. get : function() {
  59384. return this._sampler;
  59385. },
  59386. set : function(sampler) {
  59387. var minificationFilter = sampler.minificationFilter;
  59388. var magnificationFilter = sampler.magnificationFilter;
  59389. var mipmap =
  59390. (minificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST) ||
  59391. (minificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR) ||
  59392. (minificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_NEAREST) ||
  59393. (minificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_LINEAR);
  59394. // float textures only support nearest filtering, so override the sampler's settings
  59395. if (this._pixelDatatype === PixelDatatype.FLOAT) {
  59396. minificationFilter = mipmap ? TextureMinificationFilter.NEAREST_MIPMAP_NEAREST : TextureMinificationFilter.NEAREST;
  59397. magnificationFilter = TextureMagnificationFilter.NEAREST;
  59398. }
  59399. var gl = this._context._gl;
  59400. var target = this._textureTarget;
  59401. gl.activeTexture(gl.TEXTURE0);
  59402. gl.bindTexture(target, this._texture);
  59403. gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, minificationFilter);
  59404. gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, magnificationFilter);
  59405. gl.texParameteri(target, gl.TEXTURE_WRAP_S, sampler.wrapS);
  59406. gl.texParameteri(target, gl.TEXTURE_WRAP_T, sampler.wrapT);
  59407. if (defined(this._textureFilterAnisotropic)) {
  59408. gl.texParameteri(target, this._textureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, sampler.maximumAnisotropy);
  59409. }
  59410. gl.bindTexture(target, null);
  59411. this._sampler = sampler;
  59412. }
  59413. },
  59414. pixelFormat : {
  59415. get : function() {
  59416. return this._pixelFormat;
  59417. }
  59418. },
  59419. pixelDatatype : {
  59420. get : function() {
  59421. return this._pixelDatatype;
  59422. }
  59423. },
  59424. dimensions : {
  59425. get : function() {
  59426. return this._dimensions;
  59427. }
  59428. },
  59429. preMultiplyAlpha : {
  59430. get : function() {
  59431. return this._preMultiplyAlpha;
  59432. }
  59433. },
  59434. flipY : {
  59435. get : function() {
  59436. return this._flipY;
  59437. }
  59438. },
  59439. width : {
  59440. get : function() {
  59441. return this._width;
  59442. }
  59443. },
  59444. height : {
  59445. get : function() {
  59446. return this._height;
  59447. }
  59448. },
  59449. _target : {
  59450. get : function() {
  59451. return this._textureTarget;
  59452. }
  59453. }
  59454. });
  59455. /**
  59456. * Copy new image data into this texture, from a source {@link ImageData}, {@link Image}, {@link Canvas}, or {@link Video}.
  59457. * or an object with width, height, and arrayBufferView properties.
  59458. *
  59459. * @param {Object} source The source {@link ImageData}, {@link Image}, {@link Canvas}, or {@link Video},
  59460. * or an object with width, height, and arrayBufferView properties.
  59461. * @param {Number} [xOffset=0] The offset in the x direction within the texture to copy into.
  59462. * @param {Number} [yOffset=0] The offset in the y direction within the texture to copy into.
  59463. *
  59464. * @exception {DeveloperError} Cannot call copyFrom when the texture pixel format is DEPTH_COMPONENT or DEPTH_STENCIL.
  59465. * @exception {DeveloperError} xOffset must be greater than or equal to zero.
  59466. * @exception {DeveloperError} yOffset must be greater than or equal to zero.
  59467. * @exception {DeveloperError} xOffset + source.width must be less than or equal to width.
  59468. * @exception {DeveloperError} yOffset + source.height must be less than or equal to height.
  59469. * @exception {DeveloperError} This texture was destroyed, i.e., destroy() was called.
  59470. *
  59471. * @example
  59472. * texture.copyFrom({
  59473. * width : 1,
  59474. * height : 1,
  59475. * arrayBufferView : new Uint8Array([255, 0, 0, 255])
  59476. * });
  59477. */
  59478. Texture.prototype.copyFrom = function(source, xOffset, yOffset) {
  59479. xOffset = defaultValue(xOffset, 0);
  59480. yOffset = defaultValue(yOffset, 0);
  59481. if (!defined(source)) {
  59482. throw new DeveloperError('source is required.');
  59483. }
  59484. if (PixelFormat.isDepthFormat(this._pixelFormat)) {
  59485. throw new DeveloperError('Cannot call copyFrom when the texture pixel format is DEPTH_COMPONENT or DEPTH_STENCIL.');
  59486. }
  59487. if (xOffset < 0) {
  59488. throw new DeveloperError('xOffset must be greater than or equal to zero.');
  59489. }
  59490. if (yOffset < 0) {
  59491. throw new DeveloperError('yOffset must be greater than or equal to zero.');
  59492. }
  59493. if (xOffset + source.width > this._width) {
  59494. throw new DeveloperError('xOffset + source.width must be less than or equal to width.');
  59495. }
  59496. if (yOffset + source.height > this._height) {
  59497. throw new DeveloperError('yOffset + source.height must be less than or equal to height.');
  59498. }
  59499. var gl = this._context._gl;
  59500. var target = this._textureTarget;
  59501. // TODO: gl.pixelStorei(gl._UNPACK_ALIGNMENT, 4);
  59502. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this._preMultiplyAlpha);
  59503. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, this._flipY);
  59504. gl.activeTexture(gl.TEXTURE0);
  59505. gl.bindTexture(target, this._texture);
  59506. if (source.arrayBufferView) {
  59507. gl.texSubImage2D(target, 0, xOffset, yOffset, source.width, source.height, this._pixelFormat, this._pixelDatatype, source.arrayBufferView);
  59508. } else {
  59509. gl.texSubImage2D(target, 0, xOffset, yOffset, this._pixelFormat, this._pixelDatatype, source);
  59510. }
  59511. gl.bindTexture(target, null);
  59512. };
  59513. /**
  59514. * @param {Number} [xOffset=0] The offset in the x direction within the texture to copy into.
  59515. * @param {Number} [yOffset=0] The offset in the y direction within the texture to copy into.
  59516. * @param {Number} [framebufferXOffset=0] optional
  59517. * @param {Number} [framebufferYOffset=0] optional
  59518. * @param {Number} [width=width] optional
  59519. * @param {Number} [height=height] optional
  59520. *
  59521. * @exception {DeveloperError} Cannot call copyFromFramebuffer when the texture pixel format is DEPTH_COMPONENT or DEPTH_STENCIL.
  59522. * @exception {DeveloperError} Cannot call copyFromFramebuffer when the texture pixel data type is FLOAT.
  59523. * @exception {DeveloperError} This texture was destroyed, i.e., destroy() was called.
  59524. * @exception {DeveloperError} xOffset must be greater than or equal to zero.
  59525. * @exception {DeveloperError} yOffset must be greater than or equal to zero.
  59526. * @exception {DeveloperError} framebufferXOffset must be greater than or equal to zero.
  59527. * @exception {DeveloperError} framebufferYOffset must be greater than or equal to zero.
  59528. * @exception {DeveloperError} xOffset + width must be less than or equal to width.
  59529. * @exception {DeveloperError} yOffset + height must be less than or equal to height.
  59530. */
  59531. Texture.prototype.copyFromFramebuffer = function(xOffset, yOffset, framebufferXOffset, framebufferYOffset, width, height) {
  59532. xOffset = defaultValue(xOffset, 0);
  59533. yOffset = defaultValue(yOffset, 0);
  59534. framebufferXOffset = defaultValue(framebufferXOffset, 0);
  59535. framebufferYOffset = defaultValue(framebufferYOffset, 0);
  59536. width = defaultValue(width, this._width);
  59537. height = defaultValue(height, this._height);
  59538. if (PixelFormat.isDepthFormat(this._pixelFormat)) {
  59539. throw new DeveloperError('Cannot call copyFromFramebuffer when the texture pixel format is DEPTH_COMPONENT or DEPTH_STENCIL.');
  59540. }
  59541. if (this._pixelDatatype === PixelDatatype.FLOAT) {
  59542. throw new DeveloperError('Cannot call copyFromFramebuffer when the texture pixel data type is FLOAT.');
  59543. }
  59544. if (xOffset < 0) {
  59545. throw new DeveloperError('xOffset must be greater than or equal to zero.');
  59546. }
  59547. if (yOffset < 0) {
  59548. throw new DeveloperError('yOffset must be greater than or equal to zero.');
  59549. }
  59550. if (framebufferXOffset < 0) {
  59551. throw new DeveloperError('framebufferXOffset must be greater than or equal to zero.');
  59552. }
  59553. if (framebufferYOffset < 0) {
  59554. throw new DeveloperError('framebufferYOffset must be greater than or equal to zero.');
  59555. }
  59556. if (xOffset + width > this._width) {
  59557. throw new DeveloperError('xOffset + width must be less than or equal to width.');
  59558. }
  59559. if (yOffset + height > this._height) {
  59560. throw new DeveloperError('yOffset + height must be less than or equal to height.');
  59561. }
  59562. var gl = this._context._gl;
  59563. var target = this._textureTarget;
  59564. gl.activeTexture(gl.TEXTURE0);
  59565. gl.bindTexture(target, this._texture);
  59566. gl.copyTexSubImage2D(target, 0, xOffset, yOffset, framebufferXOffset, framebufferYOffset, width, height);
  59567. gl.bindTexture(target, null);
  59568. };
  59569. /**
  59570. * @param {MipmapHint} [hint=MipmapHint.DONT_CARE] optional.
  59571. *
  59572. * @exception {DeveloperError} Cannot call generateMipmap when the texture pixel format is DEPTH_COMPONENT or DEPTH_STENCIL.
  59573. * @exception {DeveloperError} hint is invalid.
  59574. * @exception {DeveloperError} This texture's width must be a power of two to call generateMipmap().
  59575. * @exception {DeveloperError} This texture's height must be a power of two to call generateMipmap().
  59576. * @exception {DeveloperError} This texture was destroyed, i.e., destroy() was called.
  59577. */
  59578. Texture.prototype.generateMipmap = function(hint) {
  59579. hint = defaultValue(hint, MipmapHint.DONT_CARE);
  59580. if (PixelFormat.isDepthFormat(this._pixelFormat)) {
  59581. throw new DeveloperError('Cannot call generateMipmap when the texture pixel format is DEPTH_COMPONENT or DEPTH_STENCIL.');
  59582. }
  59583. if (this._width > 1 && !CesiumMath.isPowerOfTwo(this._width)) {
  59584. throw new DeveloperError('width must be a power of two to call generateMipmap().');
  59585. }
  59586. if (this._height > 1 && !CesiumMath.isPowerOfTwo(this._height)) {
  59587. throw new DeveloperError('height must be a power of two to call generateMipmap().');
  59588. }
  59589. if (!MipmapHint.validate(hint)) {
  59590. throw new DeveloperError('hint is invalid.');
  59591. }
  59592. var gl = this._context._gl;
  59593. var target = this._textureTarget;
  59594. gl.hint(gl.GENERATE_MIPMAP_HINT, hint);
  59595. gl.activeTexture(gl.TEXTURE0);
  59596. gl.bindTexture(target, this._texture);
  59597. gl.generateMipmap(target);
  59598. gl.bindTexture(target, null);
  59599. };
  59600. Texture.prototype.isDestroyed = function() {
  59601. return false;
  59602. };
  59603. Texture.prototype.destroy = function() {
  59604. this._context._gl.deleteTexture(this._texture);
  59605. return destroyObject(this);
  59606. };
  59607. return Texture;
  59608. });
  59609. //This file is automatically rebuilt by the Cesium build process.
  59610. /*global define*/
  59611. define('Shaders/Materials/BumpMapMaterial',[],function() {
  59612. 'use strict';
  59613. return "uniform sampler2D image;\n\
  59614. uniform float strength;\n\
  59615. uniform vec2 repeat;\n\
  59616. czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  59617. {\n\
  59618. czm_material material = czm_getDefaultMaterial(materialInput);\n\
  59619. vec2 st = materialInput.st;\n\
  59620. vec2 centerPixel = fract(repeat * st);\n\
  59621. float centerBump = texture2D(image, centerPixel).channel;\n\
  59622. float imageWidth = float(imageDimensions.x);\n\
  59623. vec2 rightPixel = fract(repeat * (st + vec2(1.0 / imageWidth, 0.0)));\n\
  59624. float rightBump = texture2D(image, rightPixel).channel;\n\
  59625. float imageHeight = float(imageDimensions.y);\n\
  59626. vec2 leftPixel = fract(repeat * (st + vec2(0.0, 1.0 / imageHeight)));\n\
  59627. float topBump = texture2D(image, leftPixel).channel;\n\
  59628. vec3 normalTangentSpace = normalize(vec3(centerBump - rightBump, centerBump - topBump, clamp(1.0 - strength, 0.1, 1.0)));\n\
  59629. vec3 normalEC = materialInput.tangentToEyeMatrix * normalTangentSpace;\n\
  59630. material.normal = normalEC;\n\
  59631. material.diffuse = vec3(0.01);\n\
  59632. return material;\n\
  59633. }\n\
  59634. ";
  59635. });
  59636. //This file is automatically rebuilt by the Cesium build process.
  59637. /*global define*/
  59638. define('Shaders/Materials/CheckerboardMaterial',[],function() {
  59639. 'use strict';
  59640. return "uniform vec4 lightColor;\n\
  59641. uniform vec4 darkColor;\n\
  59642. uniform vec2 repeat;\n\
  59643. czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  59644. {\n\
  59645. czm_material material = czm_getDefaultMaterial(materialInput);\n\
  59646. vec2 st = materialInput.st;\n\
  59647. float b = mod(floor(repeat.s * st.s) + floor(repeat.t * st.t), 2.0);\n\
  59648. float scaledWidth = fract(repeat.s * st.s);\n\
  59649. scaledWidth = abs(scaledWidth - floor(scaledWidth + 0.5));\n\
  59650. float scaledHeight = fract(repeat.t * st.t);\n\
  59651. scaledHeight = abs(scaledHeight - floor(scaledHeight + 0.5));\n\
  59652. float value = min(scaledWidth, scaledHeight);\n\
  59653. vec4 currentColor = mix(lightColor, darkColor, b);\n\
  59654. vec4 color = czm_antialias(lightColor, darkColor, currentColor, value, 0.03);\n\
  59655. material.diffuse = color.rgb;\n\
  59656. material.alpha = color.a;\n\
  59657. return material;\n\
  59658. }\n\
  59659. ";
  59660. });
  59661. //This file is automatically rebuilt by the Cesium build process.
  59662. /*global define*/
  59663. define('Shaders/Materials/DotMaterial',[],function() {
  59664. 'use strict';
  59665. return "uniform vec4 lightColor;\n\
  59666. uniform vec4 darkColor;\n\
  59667. uniform vec2 repeat;\n\
  59668. czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  59669. {\n\
  59670. czm_material material = czm_getDefaultMaterial(materialInput);\n\
  59671. float b = smoothstep(0.3, 0.32, length(fract(repeat * materialInput.st) - 0.5));\n\
  59672. vec4 color = mix(lightColor, darkColor, b);\n\
  59673. material.diffuse = color.rgb;\n\
  59674. material.alpha = color.a;\n\
  59675. return material;\n\
  59676. }\n\
  59677. ";
  59678. });
  59679. //This file is automatically rebuilt by the Cesium build process.
  59680. /*global define*/
  59681. define('Shaders/Materials/FadeMaterial',[],function() {
  59682. 'use strict';
  59683. return "uniform vec4 fadeInColor;\n\
  59684. uniform vec4 fadeOutColor;\n\
  59685. uniform float maximumDistance;\n\
  59686. uniform bool repeat;\n\
  59687. uniform vec2 fadeDirection;\n\
  59688. uniform vec2 time;\n\
  59689. float getTime(float t, float coord)\n\
  59690. {\n\
  59691. float scalar = 1.0 / maximumDistance;\n\
  59692. float q = distance(t, coord) * scalar;\n\
  59693. if (repeat)\n\
  59694. {\n\
  59695. float r = distance(t, coord + 1.0) * scalar;\n\
  59696. float s = distance(t, coord - 1.0) * scalar;\n\
  59697. q = min(min(r, s), q);\n\
  59698. }\n\
  59699. return clamp(q, 0.0, 1.0);\n\
  59700. }\n\
  59701. czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  59702. {\n\
  59703. czm_material material = czm_getDefaultMaterial(materialInput);\n\
  59704. vec2 st = materialInput.st;\n\
  59705. float s = getTime(time.x, st.s) * fadeDirection.s;\n\
  59706. float t = getTime(time.y, st.t) * fadeDirection.t;\n\
  59707. float u = length(vec2(s, t));\n\
  59708. vec4 color = mix(fadeInColor, fadeOutColor, u);\n\
  59709. material.emission = color.rgb;\n\
  59710. material.alpha = color.a;\n\
  59711. return material;\n\
  59712. }\n\
  59713. ";
  59714. });
  59715. //This file is automatically rebuilt by the Cesium build process.
  59716. /*global define*/
  59717. define('Shaders/Materials/GridMaterial',[],function() {
  59718. 'use strict';
  59719. return "#ifdef GL_OES_standard_derivatives\n\
  59720. #extension GL_OES_standard_derivatives : enable\n\
  59721. #endif\n\
  59722. uniform vec4 color;\n\
  59723. uniform float cellAlpha;\n\
  59724. uniform vec2 lineCount;\n\
  59725. uniform vec2 lineThickness;\n\
  59726. uniform vec2 lineOffset;\n\
  59727. czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  59728. {\n\
  59729. czm_material material = czm_getDefaultMaterial(materialInput);\n\
  59730. vec2 st = materialInput.st;\n\
  59731. float scaledWidth = fract(lineCount.s * st.s - lineOffset.s);\n\
  59732. scaledWidth = abs(scaledWidth - floor(scaledWidth + 0.5));\n\
  59733. float scaledHeight = fract(lineCount.t * st.t - lineOffset.t);\n\
  59734. scaledHeight = abs(scaledHeight - floor(scaledHeight + 0.5));\n\
  59735. float value;\n\
  59736. #ifdef GL_OES_standard_derivatives\n\
  59737. const float fuzz = 1.2;\n\
  59738. vec2 thickness = (lineThickness * czm_resolutionScale) - 1.0;\n\
  59739. vec2 dx = abs(dFdx(st));\n\
  59740. vec2 dy = abs(dFdy(st));\n\
  59741. vec2 dF = vec2(max(dx.s, dy.s), max(dx.t, dy.t)) * lineCount;\n\
  59742. value = min(\n\
  59743. smoothstep(dF.s * thickness.s, dF.s * (fuzz + thickness.s), scaledWidth),\n\
  59744. smoothstep(dF.t * thickness.t, dF.t * (fuzz + thickness.t), scaledHeight));\n\
  59745. #else\n\
  59746. const float fuzz = 0.05;\n\
  59747. vec2 range = 0.5 - (lineThickness * 0.05);\n\
  59748. value = min(\n\
  59749. 1.0 - smoothstep(range.s, range.s + fuzz, scaledWidth),\n\
  59750. 1.0 - smoothstep(range.t, range.t + fuzz, scaledHeight));\n\
  59751. #endif\n\
  59752. float dRim = 1.0 - abs(dot(materialInput.normalEC, normalize(materialInput.positionToEyeEC)));\n\
  59753. float sRim = smoothstep(0.8, 1.0, dRim);\n\
  59754. value *= (1.0 - sRim);\n\
  59755. vec3 halfColor = color.rgb * 0.5;\n\
  59756. material.diffuse = halfColor;\n\
  59757. material.emission = halfColor;\n\
  59758. material.alpha = color.a * (1.0 - ((1.0 - cellAlpha) * value));\n\
  59759. return material;\n\
  59760. }\n\
  59761. ";
  59762. });
  59763. //This file is automatically rebuilt by the Cesium build process.
  59764. /*global define*/
  59765. define('Shaders/Materials/NormalMapMaterial',[],function() {
  59766. 'use strict';
  59767. return "uniform sampler2D image;\n\
  59768. uniform float strength;\n\
  59769. uniform vec2 repeat;\n\
  59770. czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  59771. {\n\
  59772. czm_material material = czm_getDefaultMaterial(materialInput);\n\
  59773. vec4 textureValue = texture2D(image, fract(repeat * materialInput.st));\n\
  59774. vec3 normalTangentSpace = textureValue.channels;\n\
  59775. normalTangentSpace.xy = normalTangentSpace.xy * 2.0 - 1.0;\n\
  59776. normalTangentSpace.z = clamp(1.0 - strength, 0.1, 1.0);\n\
  59777. normalTangentSpace = normalize(normalTangentSpace);\n\
  59778. vec3 normalEC = materialInput.tangentToEyeMatrix * normalTangentSpace;\n\
  59779. material.normal = normalEC;\n\
  59780. return material;\n\
  59781. }\n\
  59782. ";
  59783. });
  59784. //This file is automatically rebuilt by the Cesium build process.
  59785. /*global define*/
  59786. define('Shaders/Materials/PolylineArrowMaterial',[],function() {
  59787. 'use strict';
  59788. return "#extension GL_OES_standard_derivatives : enable\n\
  59789. uniform vec4 color;\n\
  59790. varying float v_width;\n\
  59791. float getPointOnLine(vec2 p0, vec2 p1, float x)\n\
  59792. {\n\
  59793. float slope = (p0.y - p1.y) / (p0.x - p1.x);\n\
  59794. return slope * (x - p0.x) + p0.y;\n\
  59795. }\n\
  59796. czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  59797. {\n\
  59798. czm_material material = czm_getDefaultMaterial(materialInput);\n\
  59799. vec2 st = materialInput.st;\n\
  59800. float base = 1.0 - abs(fwidth(st.s)) * 10.0;\n\
  59801. vec2 center = vec2(1.0, 0.5);\n\
  59802. float ptOnUpperLine = getPointOnLine(vec2(base, 1.0), center, st.s);\n\
  59803. float ptOnLowerLine = getPointOnLine(vec2(base, 0.0), center, st.s);\n\
  59804. float halfWidth = 0.15;\n\
  59805. float s = step(0.5 - halfWidth, st.t);\n\
  59806. s *= 1.0 - step(0.5 + halfWidth, st.t);\n\
  59807. s *= 1.0 - step(base, st.s);\n\
  59808. float t = step(base, materialInput.st.s);\n\
  59809. t *= 1.0 - step(ptOnUpperLine, st.t);\n\
  59810. t *= step(ptOnLowerLine, st.t);\n\
  59811. float dist;\n\
  59812. if (st.s < base)\n\
  59813. {\n\
  59814. float d1 = abs(st.t - (0.5 - halfWidth));\n\
  59815. float d2 = abs(st.t - (0.5 + halfWidth));\n\
  59816. dist = min(d1, d2);\n\
  59817. }\n\
  59818. else\n\
  59819. {\n\
  59820. float d1 = czm_infinity;\n\
  59821. if (st.t < 0.5 - halfWidth && st.t > 0.5 + halfWidth)\n\
  59822. {\n\
  59823. d1 = abs(st.s - base);\n\
  59824. }\n\
  59825. float d2 = abs(st.t - ptOnUpperLine);\n\
  59826. float d3 = abs(st.t - ptOnLowerLine);\n\
  59827. dist = min(min(d1, d2), d3);\n\
  59828. }\n\
  59829. vec4 outsideColor = vec4(0.0);\n\
  59830. vec4 currentColor = mix(outsideColor, color, clamp(s + t, 0.0, 1.0));\n\
  59831. vec4 outColor = czm_antialias(outsideColor, color, currentColor, dist);\n\
  59832. material.diffuse = outColor.rgb;\n\
  59833. material.alpha = outColor.a;\n\
  59834. return material;\n\
  59835. }\n\
  59836. ";
  59837. });
  59838. //This file is automatically rebuilt by the Cesium build process.
  59839. /*global define*/
  59840. define('Shaders/Materials/PolylineGlowMaterial',[],function() {
  59841. 'use strict';
  59842. return "uniform vec4 color;\n\
  59843. uniform float glowPower;\n\
  59844. varying float v_width;\n\
  59845. czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  59846. {\n\
  59847. czm_material material = czm_getDefaultMaterial(materialInput);\n\
  59848. vec2 st = materialInput.st;\n\
  59849. float glow = glowPower / abs(st.t - 0.5) - (glowPower / 0.5);\n\
  59850. material.emission = max(vec3(glow - 1.0 + color.rgb), color.rgb);\n\
  59851. material.alpha = clamp(0.0, 1.0, glow) * color.a;\n\
  59852. return material;\n\
  59853. }\n\
  59854. ";
  59855. });
  59856. //This file is automatically rebuilt by the Cesium build process.
  59857. /*global define*/
  59858. define('Shaders/Materials/PolylineOutlineMaterial',[],function() {
  59859. 'use strict';
  59860. return "uniform vec4 color;\n\
  59861. uniform vec4 outlineColor;\n\
  59862. uniform float outlineWidth;\n\
  59863. varying float v_width;\n\
  59864. czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  59865. {\n\
  59866. czm_material material = czm_getDefaultMaterial(materialInput);\n\
  59867. vec2 st = materialInput.st;\n\
  59868. float halfInteriorWidth = 0.5 * (v_width - outlineWidth) / v_width;\n\
  59869. float b = step(0.5 - halfInteriorWidth, st.t);\n\
  59870. b *= 1.0 - step(0.5 + halfInteriorWidth, st.t);\n\
  59871. float d1 = abs(st.t - (0.5 - halfInteriorWidth));\n\
  59872. float d2 = abs(st.t - (0.5 + halfInteriorWidth));\n\
  59873. float dist = min(d1, d2);\n\
  59874. vec4 currentColor = mix(outlineColor, color, b);\n\
  59875. vec4 outColor = czm_antialias(outlineColor, color, currentColor, dist);\n\
  59876. material.diffuse = outColor.rgb;\n\
  59877. material.alpha = outColor.a;\n\
  59878. return material;\n\
  59879. }\n\
  59880. ";
  59881. });
  59882. //This file is automatically rebuilt by the Cesium build process.
  59883. /*global define*/
  59884. define('Shaders/Materials/RimLightingMaterial',[],function() {
  59885. 'use strict';
  59886. return "uniform vec4 color;\n\
  59887. uniform vec4 rimColor;\n\
  59888. uniform float width;\n\
  59889. czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  59890. {\n\
  59891. czm_material material = czm_getDefaultMaterial(materialInput);\n\
  59892. float d = 1.0 - dot(materialInput.normalEC, normalize(materialInput.positionToEyeEC));\n\
  59893. float s = smoothstep(1.0 - width, 1.0, d);\n\
  59894. material.diffuse = color.rgb;\n\
  59895. material.emission = rimColor.rgb * s;\n\
  59896. material.alpha = mix(color.a, rimColor.a, s);\n\
  59897. return material;\n\
  59898. }\n\
  59899. ";
  59900. });
  59901. //This file is automatically rebuilt by the Cesium build process.
  59902. /*global define*/
  59903. define('Shaders/Materials/StripeMaterial',[],function() {
  59904. 'use strict';
  59905. return "uniform vec4 evenColor;\n\
  59906. uniform vec4 oddColor;\n\
  59907. uniform float offset;\n\
  59908. uniform float repeat;\n\
  59909. uniform bool horizontal;\n\
  59910. czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  59911. {\n\
  59912. czm_material material = czm_getDefaultMaterial(materialInput);\n\
  59913. float coord = mix(materialInput.st.s, materialInput.st.t, float(horizontal));\n\
  59914. float value = fract((coord - offset) * (repeat * 0.5));\n\
  59915. float dist = min(value, min(abs(value - 0.5), 1.0 - value));\n\
  59916. vec4 currentColor = mix(evenColor, oddColor, step(0.5, value));\n\
  59917. vec4 color = czm_antialias(evenColor, oddColor, currentColor, dist);\n\
  59918. material.diffuse = color.rgb;\n\
  59919. material.alpha = color.a;\n\
  59920. return material;\n\
  59921. }\n\
  59922. ";
  59923. });
  59924. //This file is automatically rebuilt by the Cesium build process.
  59925. /*global define*/
  59926. define('Shaders/Materials/Water',[],function() {
  59927. 'use strict';
  59928. return "uniform sampler2D specularMap;\n\
  59929. uniform sampler2D normalMap;\n\
  59930. uniform vec4 baseWaterColor;\n\
  59931. uniform vec4 blendColor;\n\
  59932. uniform float frequency;\n\
  59933. uniform float animationSpeed;\n\
  59934. uniform float amplitude;\n\
  59935. uniform float specularIntensity;\n\
  59936. uniform float fadeFactor;\n\
  59937. czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  59938. {\n\
  59939. czm_material material = czm_getDefaultMaterial(materialInput);\n\
  59940. float time = czm_frameNumber * animationSpeed;\n\
  59941. float fade = max(1.0, (length(materialInput.positionToEyeEC) / 10000000000.0) * frequency * fadeFactor);\n\
  59942. float specularMapValue = texture2D(specularMap, materialInput.st).r;\n\
  59943. vec4 noise = czm_getWaterNoise(normalMap, materialInput.st * frequency, time, 0.0);\n\
  59944. vec3 normalTangentSpace = noise.xyz * vec3(1.0, 1.0, (1.0 / amplitude));\n\
  59945. normalTangentSpace.xy /= fade;\n\
  59946. normalTangentSpace = mix(vec3(0.0, 0.0, 50.0), normalTangentSpace, specularMapValue);\n\
  59947. normalTangentSpace = normalize(normalTangentSpace);\n\
  59948. float tsPerturbationRatio = clamp(dot(normalTangentSpace, vec3(0.0, 0.0, 1.0)), 0.0, 1.0);\n\
  59949. material.alpha = specularMapValue;\n\
  59950. material.diffuse = mix(blendColor.rgb, baseWaterColor.rgb, specularMapValue);\n\
  59951. material.diffuse += (0.1 * tsPerturbationRatio);\n\
  59952. material.normal = normalize(materialInput.tangentToEyeMatrix * normalTangentSpace);\n\
  59953. material.specular = specularIntensity;\n\
  59954. material.shininess = 10.0;\n\
  59955. return material;\n\
  59956. }\n\
  59957. ";
  59958. });
  59959. /*global define*/
  59960. define('Scene/Material',[
  59961. '../Core/Cartesian2',
  59962. '../Core/clone',
  59963. '../Core/Color',
  59964. '../Core/combine',
  59965. '../Core/createGuid',
  59966. '../Core/defaultValue',
  59967. '../Core/defined',
  59968. '../Core/defineProperties',
  59969. '../Core/destroyObject',
  59970. '../Core/DeveloperError',
  59971. '../Core/isArray',
  59972. '../Core/loadImage',
  59973. '../Core/Matrix2',
  59974. '../Core/Matrix3',
  59975. '../Core/Matrix4',
  59976. '../Renderer/CubeMap',
  59977. '../Renderer/Texture',
  59978. '../Shaders/Materials/BumpMapMaterial',
  59979. '../Shaders/Materials/CheckerboardMaterial',
  59980. '../Shaders/Materials/DotMaterial',
  59981. '../Shaders/Materials/FadeMaterial',
  59982. '../Shaders/Materials/GridMaterial',
  59983. '../Shaders/Materials/NormalMapMaterial',
  59984. '../Shaders/Materials/PolylineArrowMaterial',
  59985. '../Shaders/Materials/PolylineGlowMaterial',
  59986. '../Shaders/Materials/PolylineOutlineMaterial',
  59987. '../Shaders/Materials/RimLightingMaterial',
  59988. '../Shaders/Materials/StripeMaterial',
  59989. '../Shaders/Materials/Water',
  59990. '../ThirdParty/when'
  59991. ], function(
  59992. Cartesian2,
  59993. clone,
  59994. Color,
  59995. combine,
  59996. createGuid,
  59997. defaultValue,
  59998. defined,
  59999. defineProperties,
  60000. destroyObject,
  60001. DeveloperError,
  60002. isArray,
  60003. loadImage,
  60004. Matrix2,
  60005. Matrix3,
  60006. Matrix4,
  60007. CubeMap,
  60008. Texture,
  60009. BumpMapMaterial,
  60010. CheckerboardMaterial,
  60011. DotMaterial,
  60012. FadeMaterial,
  60013. GridMaterial,
  60014. NormalMapMaterial,
  60015. PolylineArrowMaterial,
  60016. PolylineGlowMaterial,
  60017. PolylineOutlineMaterial,
  60018. RimLightingMaterial,
  60019. StripeMaterial,
  60020. WaterMaterial,
  60021. when) {
  60022. 'use strict';
  60023. /**
  60024. * A Material defines surface appearance through a combination of diffuse, specular,
  60025. * normal, emission, and alpha components. These values are specified using a
  60026. * JSON schema called Fabric which gets parsed and assembled into glsl shader code
  60027. * behind-the-scenes. Check out the {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|wiki page}
  60028. * for more details on Fabric.
  60029. * <br /><br />
  60030. * <style type="text/css">
  60031. * #materialDescriptions code {
  60032. * font-weight: normal;
  60033. * font-family: Consolas, 'Lucida Console', Monaco, monospace;
  60034. * color: #A35A00;
  60035. * }
  60036. * #materialDescriptions ul, #materialDescriptions ul ul {
  60037. * list-style-type: none;
  60038. * }
  60039. * #materialDescriptions ul ul {
  60040. * margin-bottom: 10px;
  60041. * }
  60042. * #materialDescriptions ul ul li {
  60043. * font-weight: normal;
  60044. * color: #000000;
  60045. * text-indent: -2em;
  60046. * margin-left: 2em;
  60047. * }
  60048. * #materialDescriptions ul li {
  60049. * font-weight: bold;
  60050. * color: #0053CF;
  60051. * }
  60052. * </style>
  60053. *
  60054. * Base material types and their uniforms:
  60055. * <div id='materialDescriptions'>
  60056. * <ul>
  60057. * <li>Color</li>
  60058. * <ul>
  60059. * <li><code>color</code>: rgba color object.</li>
  60060. * </ul>
  60061. * <li>Image</li>
  60062. * <ul>
  60063. * <li><code>image</code>: path to image.</li>
  60064. * <li><code>repeat</code>: Object with x and y values specifying the number of times to repeat the image.</li>
  60065. * </ul>
  60066. * <li>DiffuseMap</li>
  60067. * <ul>
  60068. * <li><code>image</code>: path to image.</li>
  60069. * <li><code>channels</code>: Three character string containing any combination of r, g, b, and a for selecting the desired image channels.</li>
  60070. * <li><code>repeat</code>: Object with x and y values specifying the number of times to repeat the image.</li>
  60071. * </ul>
  60072. * <li>AlphaMap</li>
  60073. * <ul>
  60074. * <li><code>image</code>: path to image.</li>
  60075. * <li><code>channel</code>: One character string containing r, g, b, or a for selecting the desired image channel. </li>
  60076. * <li><code>repeat</code>: Object with x and y values specifying the number of times to repeat the image.</li>
  60077. * </ul>
  60078. * <li>SpecularMap</li>
  60079. * <ul>
  60080. * <li><code>image</code>: path to image.</li>
  60081. * <li><code>channel</code>: One character string containing r, g, b, or a for selecting the desired image channel. </li>
  60082. * <li><code>repeat</code>: Object with x and y values specifying the number of times to repeat the image.</li>
  60083. * </ul>
  60084. * <li>EmissionMap</li>
  60085. * <ul>
  60086. * <li><code>image</code>: path to image.</li>
  60087. * <li><code>channels</code>: Three character string containing any combination of r, g, b, and a for selecting the desired image channels. </li>
  60088. * <li><code>repeat</code>: Object with x and y values specifying the number of times to repeat the image.</li>
  60089. * </ul>
  60090. * <li>BumpMap</li>
  60091. * <ul>
  60092. * <li><code>image</code>: path to image.</li>
  60093. * <li><code>channel</code>: One character string containing r, g, b, or a for selecting the desired image channel. </li>
  60094. * <li><code>repeat</code>: Object with x and y values specifying the number of times to repeat the image.</li>
  60095. * <li><code>strength</code>: Bump strength value between 0.0 and 1.0 where 0.0 is small bumps and 1.0 is large bumps.</li>
  60096. * </ul>
  60097. * <li>NormalMap</li>
  60098. * <ul>
  60099. * <li><code>image</code>: path to image.</li>
  60100. * <li><code>channels</code>: Three character string containing any combination of r, g, b, and a for selecting the desired image channels. </li>
  60101. * <li><code>repeat</code>: Object with x and y values specifying the number of times to repeat the image.</li>
  60102. * <li><code>strength</code>: Bump strength value between 0.0 and 1.0 where 0.0 is small bumps and 1.0 is large bumps.</li>
  60103. * </ul>
  60104. * <li>Grid</li>
  60105. * <ul>
  60106. * <li><code>color</code>: rgba color object for the whole material.</li>
  60107. * <li><code>cellAlpha</code>: Alpha value for the cells between grid lines. This will be combined with color.alpha.</li>
  60108. * <li><code>lineCount</code>: Object with x and y values specifying the number of columns and rows respectively.</li>
  60109. * <li><code>lineThickness</code>: Object with x and y values specifying the thickness of grid lines (in pixels where available).</li>
  60110. * <li><code>lineOffset</code>: Object with x and y values specifying the offset of grid lines (range is 0 to 1).</li>
  60111. * </ul>
  60112. * <li>Stripe</li>
  60113. * <ul>
  60114. * <li><code>horizontal</code>: Boolean that determines if the stripes are horizontal or vertical.</li>
  60115. * <li><code>evenColor</code>: rgba color object for the stripe's first color.</li>
  60116. * <li><code>oddColor</code>: rgba color object for the stripe's second color.</li>
  60117. * <li><code>offset</code>: Number that controls at which point into the pattern to begin drawing; with 0.0 being the beginning of the even color, 1.0 the beginning of the odd color, 2.0 being the even color again, and any multiple or fractional values being in between.</li>
  60118. * <li><code>repeat</code>: Number that controls the total number of stripes, half light and half dark.</li>
  60119. * </ul>
  60120. * <li>Checkerboard</li>
  60121. * <ul>
  60122. * <li><code>lightColor</code>: rgba color object for the checkerboard's light alternating color.</li>
  60123. * <li><code>darkColor</code>: rgba color object for the checkerboard's dark alternating color.</li>
  60124. * <li><code>repeat</code>: Object with x and y values specifying the number of columns and rows respectively.</li>
  60125. * </ul>
  60126. * <li>Dot</li>
  60127. * <ul>
  60128. * <li><code>lightColor</code>: rgba color object for the dot color.</li>
  60129. * <li><code>darkColor</code>: rgba color object for the background color.</li>
  60130. * <li><code>repeat</code>: Object with x and y values specifying the number of columns and rows of dots respectively.</li>
  60131. * </ul>
  60132. * <li>Water</li>
  60133. * <ul>
  60134. * <li><code>baseWaterColor</code>: rgba color object base color of the water.</li>
  60135. * <li><code>blendColor</code>: rgba color object used when blending from water to non-water areas.</li>
  60136. * <li><code>specularMap</code>: Single channel texture used to indicate areas of water.</li>
  60137. * <li><code>normalMap</code>: Normal map for water normal perturbation.</li>
  60138. * <li><code>frequency</code>: Number that controls the number of waves.</li>
  60139. * <li><code>normalMap</code>: Normal map for water normal perturbation.</li>
  60140. * <li><code>animationSpeed</code>: Number that controls the animations speed of the water.</li>
  60141. * <li><code>amplitude</code>: Number that controls the amplitude of water waves.</li>
  60142. * <li><code>specularIntensity</code>: Number that controls the intensity of specular reflections.</li>
  60143. * </ul>
  60144. * <li>RimLighting</li>
  60145. * <ul>
  60146. * <li><code>color</code>: diffuse color and alpha.</li>
  60147. * <li><code>rimColor</code>: diffuse color and alpha of the rim.</li>
  60148. * <li><code>width</code>: Number that determines the rim's width.</li>
  60149. * </ul>
  60150. * <li>Fade</li>
  60151. * <ul>
  60152. * <li><code>fadeInColor</code>: diffuse color and alpha at <code>time</code></li>
  60153. * <li><code>fadeOutColor</code>: diffuse color and alpha at <code>maximumDistance</code> from <code>time</code></li>
  60154. * <li><code>maximumDistance</code>: Number between 0.0 and 1.0 where the <code>fadeInColor</code> becomes the <code>fadeOutColor</code>. A value of 0.0 gives the entire material a color of <code>fadeOutColor</code> and a value of 1.0 gives the the entire material a color of <code>fadeInColor</code></li>
  60155. * <li><code>repeat</code>: true if the fade should wrap around the texture coodinates.</li>
  60156. * <li><code>fadeDirection</code>: Object with x and y values specifying if the fade should be in the x and y directions.</li>
  60157. * <li><code>time</code>: Object with x and y values between 0.0 and 1.0 of the <code>fadeInColor</code> position</li>
  60158. * </ul>
  60159. * <li>PolylineArrow</li>
  60160. * <ul>
  60161. * <li><code>color</code>: diffuse color and alpha.</li>
  60162. * </ul>
  60163. * <li>PolylineGlow</li>
  60164. * <ul>
  60165. * <li><code>color</code>: color and maximum alpha for the glow on the line.</li>
  60166. * <li><code>glowPower</code>: strength of the glow, as a percentage of the total line width (less than 1.0).</li>
  60167. * </ul>
  60168. * <li>PolylineOutline</li>
  60169. * <ul>
  60170. * <li><code>color</code>: diffuse color and alpha for the interior of the line.</li>
  60171. * <li><code>outlineColor</code>: diffuse color and alpha for the outline.</li>
  60172. * <li><code>outlineWidth</code>: width of the outline in pixels.</li>
  60173. * </ul>
  60174. * </ul>
  60175. * </div>
  60176. *
  60177. * @alias Material
  60178. *
  60179. * @param {Object} [options] Object with the following properties:
  60180. * @param {Boolean} [options.strict=false] Throws errors for issues that would normally be ignored, including unused uniforms or materials.
  60181. * @param {Boolean|Function} [options.translucent=true] When <code>true</code> or a function that returns <code>true</code>, the geometry
  60182. * with this material is expected to appear translucent.
  60183. * @param {Object} options.fabric The fabric JSON used to generate the material.
  60184. *
  60185. * @constructor
  60186. *
  60187. * @exception {DeveloperError} fabric: uniform has invalid type.
  60188. * @exception {DeveloperError} fabric: uniforms and materials cannot share the same property.
  60189. * @exception {DeveloperError} fabric: cannot have source and components in the same section.
  60190. * @exception {DeveloperError} fabric: property name is not valid. It should be 'type', 'materials', 'uniforms', 'components', or 'source'.
  60191. * @exception {DeveloperError} fabric: property name is not valid. It should be 'diffuse', 'specular', 'shininess', 'normal', 'emission', or 'alpha'.
  60192. * @exception {DeveloperError} strict: shader source does not use string.
  60193. * @exception {DeveloperError} strict: shader source does not use uniform.
  60194. * @exception {DeveloperError} strict: shader source does not use material.
  60195. *
  60196. * @see {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric wiki page} for a more detailed options of Fabric.
  60197. *
  60198. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Materials.html|Cesium Sandcastle Materials Demo}
  60199. *
  60200. * @example
  60201. * // Create a color material with fromType:
  60202. * polygon.material = Cesium.Material.fromType('Color');
  60203. * polygon.material.uniforms.color = new Cesium.Color(1.0, 1.0, 0.0, 1.0);
  60204. *
  60205. * // Create the default material:
  60206. * polygon.material = new Cesium.Material();
  60207. *
  60208. * // Create a color material with full Fabric notation:
  60209. * polygon.material = new Cesium.Material({
  60210. * fabric : {
  60211. * type : 'Color',
  60212. * uniforms : {
  60213. * color : new Cesium.Color(1.0, 1.0, 0.0, 1.0)
  60214. * }
  60215. * }
  60216. * });
  60217. */
  60218. function Material(options) {
  60219. /**
  60220. * The material type. Can be an existing type or a new type. If no type is specified in fabric, type is a GUID.
  60221. * @type {String}
  60222. * @default undefined
  60223. */
  60224. this.type = undefined;
  60225. /**
  60226. * The glsl shader source for this material.
  60227. * @type {String}
  60228. * @default undefined
  60229. */
  60230. this.shaderSource = undefined;
  60231. /**
  60232. * Maps sub-material names to Material objects.
  60233. * @type {Object}
  60234. * @default undefined
  60235. */
  60236. this.materials = undefined;
  60237. /**
  60238. * Maps uniform names to their values.
  60239. * @type {Object}
  60240. * @default undefined
  60241. */
  60242. this.uniforms = undefined;
  60243. this._uniforms = undefined;
  60244. /**
  60245. * When <code>true</code> or a function that returns <code>true</code>,
  60246. * the geometry is expected to appear translucent.
  60247. * @type {Boolean|Function}
  60248. * @default undefined
  60249. */
  60250. this.translucent = undefined;
  60251. this._strict = undefined;
  60252. this._template = undefined;
  60253. this._count = undefined;
  60254. this._texturePaths = {};
  60255. this._loadedImages = [];
  60256. this._loadedCubeMaps = [];
  60257. this._textures = {};
  60258. this._updateFunctions = [];
  60259. this._defaultTexture = undefined;
  60260. initializeMaterial(options, this);
  60261. defineProperties(this, {
  60262. type : {
  60263. value : this.type,
  60264. writable : false
  60265. }
  60266. });
  60267. if (!defined(Material._uniformList[this.type])) {
  60268. Material._uniformList[this.type] = Object.keys(this._uniforms);
  60269. }
  60270. }
  60271. // Cached list of combined uniform names indexed by type.
  60272. // Used to get the list of uniforms in the same order.
  60273. Material._uniformList = {};
  60274. /**
  60275. * Creates a new material using an existing material type.
  60276. * <br /><br />
  60277. * Shorthand for: new Material({fabric : {type : type}});
  60278. *
  60279. * @param {String} type The base material type.
  60280. * @param {Object} [uniforms] Overrides for the default uniforms.
  60281. * @returns {Material} New material object.
  60282. *
  60283. * @exception {DeveloperError} material with that type does not exist.
  60284. *
  60285. * @example
  60286. * var material = Cesium.Material.fromType('Color', {
  60287. * color : new Cesium.Color(1.0, 0.0, 0.0, 1.0)
  60288. * });
  60289. */
  60290. Material.fromType = function(type, uniforms) {
  60291. if (!defined(Material._materialCache.getMaterial(type))) {
  60292. throw new DeveloperError('material with type \'' + type + '\' does not exist.');
  60293. }
  60294. var material = new Material({
  60295. fabric : {
  60296. type : type
  60297. }
  60298. });
  60299. if (defined(uniforms)) {
  60300. for (var name in uniforms) {
  60301. if (uniforms.hasOwnProperty(name)) {
  60302. material.uniforms[name] = uniforms[name];
  60303. }
  60304. }
  60305. }
  60306. return material;
  60307. };
  60308. /**
  60309. * Gets whether or not this material is translucent.
  60310. * @returns <code>true</code> if this material is translucent, <code>false</code> otherwise.
  60311. */
  60312. Material.prototype.isTranslucent = function() {
  60313. if (defined(this.translucent)) {
  60314. if (typeof this.translucent === 'function') {
  60315. return this.translucent();
  60316. }
  60317. return this.translucent;
  60318. }
  60319. var translucent = true;
  60320. var funcs = this._translucentFunctions;
  60321. var length = funcs.length;
  60322. for (var i = 0; i < length; ++i) {
  60323. var func = funcs[i];
  60324. if (typeof func === 'function') {
  60325. translucent = translucent && func();
  60326. } else {
  60327. translucent = translucent && func;
  60328. }
  60329. if (!translucent) {
  60330. break;
  60331. }
  60332. }
  60333. return translucent;
  60334. };
  60335. /**
  60336. * @private
  60337. */
  60338. Material.prototype.update = function(context) {
  60339. var i;
  60340. var uniformId;
  60341. var loadedImages = this._loadedImages;
  60342. var length = loadedImages.length;
  60343. for (i = 0; i < length; ++i) {
  60344. var loadedImage = loadedImages[i];
  60345. uniformId = loadedImage.id;
  60346. var image = loadedImage.image;
  60347. var texture = new Texture({
  60348. context : context,
  60349. source : image
  60350. });
  60351. this._textures[uniformId] = texture;
  60352. var uniformDimensionsName = uniformId + 'Dimensions';
  60353. if (this.uniforms.hasOwnProperty(uniformDimensionsName)) {
  60354. var uniformDimensions = this.uniforms[uniformDimensionsName];
  60355. uniformDimensions.x = texture._width;
  60356. uniformDimensions.y = texture._height;
  60357. }
  60358. }
  60359. loadedImages.length = 0;
  60360. var loadedCubeMaps = this._loadedCubeMaps;
  60361. length = loadedCubeMaps.length;
  60362. for (i = 0; i < length; ++i) {
  60363. var loadedCubeMap = loadedCubeMaps[i];
  60364. uniformId = loadedCubeMap.id;
  60365. var images = loadedCubeMap.images;
  60366. var cubeMap = new CubeMap({
  60367. context : context,
  60368. source : {
  60369. positiveX : images[0],
  60370. negativeX : images[1],
  60371. positiveY : images[2],
  60372. negativeY : images[3],
  60373. positiveZ : images[4],
  60374. negativeZ : images[5]
  60375. }
  60376. });
  60377. this._textures[uniformId] = cubeMap;
  60378. }
  60379. loadedCubeMaps.length = 0;
  60380. var updateFunctions = this._updateFunctions;
  60381. length = updateFunctions.length;
  60382. for (i = 0; i < length; ++i) {
  60383. updateFunctions[i](this, context);
  60384. }
  60385. var subMaterials = this.materials;
  60386. for (var name in subMaterials) {
  60387. if (subMaterials.hasOwnProperty(name)) {
  60388. subMaterials[name].update(context);
  60389. }
  60390. }
  60391. };
  60392. /**
  60393. * Returns true if this object was destroyed; otherwise, false.
  60394. * <br /><br />
  60395. * If this object was destroyed, it should not be used; calling any function other than
  60396. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  60397. *
  60398. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  60399. *
  60400. * @see Material#destroy
  60401. */
  60402. Material.prototype.isDestroyed = function() {
  60403. return false;
  60404. };
  60405. /**
  60406. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  60407. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  60408. * <br /><br />
  60409. * Once an object is destroyed, it should not be used; calling any function other than
  60410. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  60411. * assign the return value (<code>undefined</code>) to the object as done in the example.
  60412. *
  60413. * @returns {undefined}
  60414. *
  60415. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  60416. *
  60417. *
  60418. * @example
  60419. * material = material && material.destroy();
  60420. *
  60421. * @see Material#isDestroyed
  60422. */
  60423. Material.prototype.destroy = function() {
  60424. var textures = this._textures;
  60425. for ( var texture in textures) {
  60426. if (textures.hasOwnProperty(texture)) {
  60427. var instance = textures[texture];
  60428. if (instance !== this._defaultTexture) {
  60429. instance.destroy();
  60430. }
  60431. }
  60432. }
  60433. var materials = this.materials;
  60434. for ( var material in materials) {
  60435. if (materials.hasOwnProperty(material)) {
  60436. materials[material].destroy();
  60437. }
  60438. }
  60439. return destroyObject(this);
  60440. };
  60441. function initializeMaterial(options, result) {
  60442. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  60443. result._strict = defaultValue(options.strict, false);
  60444. result._count = defaultValue(options.count, 0);
  60445. result._template = clone(defaultValue(options.fabric, defaultValue.EMPTY_OBJECT));
  60446. result._template.uniforms = clone(defaultValue(result._template.uniforms, defaultValue.EMPTY_OBJECT));
  60447. result._template.materials = clone(defaultValue(result._template.materials, defaultValue.EMPTY_OBJECT));
  60448. result.type = defined(result._template.type) ? result._template.type : createGuid();
  60449. result.shaderSource = '';
  60450. result.materials = {};
  60451. result.uniforms = {};
  60452. result._uniforms = {};
  60453. result._translucentFunctions = [];
  60454. var translucent;
  60455. // If the cache contains this material type, build the material template off of the stored template.
  60456. var cachedMaterial = Material._materialCache.getMaterial(result.type);
  60457. if (defined(cachedMaterial)) {
  60458. var template = clone(cachedMaterial.fabric, true);
  60459. result._template = combine(result._template, template, true);
  60460. translucent = cachedMaterial.translucent;
  60461. }
  60462. // Make sure the template has no obvious errors. More error checking happens later.
  60463. checkForTemplateErrors(result);
  60464. // If the material has a new type, add it to the cache.
  60465. if (!defined(cachedMaterial)) {
  60466. Material._materialCache.addMaterial(result.type, result);
  60467. }
  60468. createMethodDefinition(result);
  60469. createUniforms(result);
  60470. createSubMaterials(result);
  60471. var defaultTranslucent = result._translucentFunctions.length === 0 ? true : undefined;
  60472. translucent = defaultValue(translucent, defaultTranslucent);
  60473. translucent = defaultValue(options.translucent, translucent);
  60474. if (defined(translucent)) {
  60475. if (typeof translucent === 'function') {
  60476. var wrappedTranslucent = function() {
  60477. return translucent(result);
  60478. };
  60479. result._translucentFunctions.push(wrappedTranslucent);
  60480. } else {
  60481. result._translucentFunctions.push(translucent);
  60482. }
  60483. }
  60484. }
  60485. function checkForValidProperties(object, properties, result, throwNotFound) {
  60486. if (defined(object)) {
  60487. for ( var property in object) {
  60488. if (object.hasOwnProperty(property)) {
  60489. var hasProperty = properties.indexOf(property) !== -1;
  60490. if ((throwNotFound && !hasProperty) || (!throwNotFound && hasProperty)) {
  60491. result(property, properties);
  60492. }
  60493. }
  60494. }
  60495. }
  60496. }
  60497. function invalidNameError(property, properties) {
  60498. var errorString = 'fabric: property name \'' + property + '\' is not valid. It should be ';
  60499. for ( var i = 0; i < properties.length; i++) {
  60500. var propertyName = '\'' + properties[i] + '\'';
  60501. errorString += (i === properties.length - 1) ? ('or ' + propertyName + '.') : (propertyName + ', ');
  60502. }
  60503. throw new DeveloperError(errorString);
  60504. }
  60505. function duplicateNameError(property, properties) {
  60506. var errorString = 'fabric: uniforms and materials cannot share the same property \'' + property + '\'';
  60507. throw new DeveloperError(errorString);
  60508. }
  60509. var templateProperties = ['type', 'materials', 'uniforms', 'components', 'source'];
  60510. var componentProperties = ['diffuse', 'specular', 'shininess', 'normal', 'emission', 'alpha'];
  60511. function checkForTemplateErrors(material) {
  60512. var template = material._template;
  60513. var uniforms = template.uniforms;
  60514. var materials = template.materials;
  60515. var components = template.components;
  60516. // Make sure source and components do not exist in the same template.
  60517. if (defined(components) && defined(template.source)) {
  60518. throw new DeveloperError('fabric: cannot have source and components in the same template.');
  60519. }
  60520. // Make sure all template and components properties are valid.
  60521. checkForValidProperties(template, templateProperties, invalidNameError, true);
  60522. checkForValidProperties(components, componentProperties, invalidNameError, true);
  60523. // Make sure uniforms and materials do not share any of the same names.
  60524. var materialNames = [];
  60525. for ( var property in materials) {
  60526. if (materials.hasOwnProperty(property)) {
  60527. materialNames.push(property);
  60528. }
  60529. }
  60530. checkForValidProperties(uniforms, materialNames, duplicateNameError, false);
  60531. }
  60532. // Create the czm_getMaterial method body using source or components.
  60533. function createMethodDefinition(material) {
  60534. var components = material._template.components;
  60535. var source = material._template.source;
  60536. if (defined(source)) {
  60537. material.shaderSource += source + '\n';
  60538. } else {
  60539. material.shaderSource += 'czm_material czm_getMaterial(czm_materialInput materialInput)\n{\n';
  60540. material.shaderSource += 'czm_material material = czm_getDefaultMaterial(materialInput);\n';
  60541. if (defined(components)) {
  60542. for ( var component in components) {
  60543. if (components.hasOwnProperty(component)) {
  60544. material.shaderSource += 'material.' + component + ' = ' + components[component] + ';\n';
  60545. }
  60546. }
  60547. }
  60548. material.shaderSource += 'return material;\n}\n';
  60549. }
  60550. }
  60551. var matrixMap = {
  60552. 'mat2' : Matrix2,
  60553. 'mat3' : Matrix3,
  60554. 'mat4' : Matrix4
  60555. };
  60556. function createTexture2DUpdateFunction(uniformId) {
  60557. var oldUniformValue;
  60558. return function(material, context) {
  60559. var uniforms = material.uniforms;
  60560. var uniformValue = uniforms[uniformId];
  60561. var uniformChanged = oldUniformValue !== uniformValue;
  60562. oldUniformValue = uniformValue;
  60563. var texture = material._textures[uniformId];
  60564. var uniformDimensionsName;
  60565. var uniformDimensions;
  60566. if (uniformValue instanceof HTMLVideoElement) {
  60567. // HTMLVideoElement.readyState >=2 means we have enough data for the current frame.
  60568. // See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/readyState
  60569. if (uniformValue.readyState >= 2) {
  60570. if (uniformChanged && defined(texture)) {
  60571. if (texture !== context.defaultTexture) {
  60572. texture.destroy();
  60573. }
  60574. texture = undefined;
  60575. }
  60576. if (!defined(texture) || texture === context.defaultTexture) {
  60577. texture = new Texture({
  60578. context : context,
  60579. source : uniformValue
  60580. });
  60581. material._textures[uniformId] = texture;
  60582. return;
  60583. }
  60584. texture.copyFrom(uniformValue);
  60585. } else if (!defined(texture)) {
  60586. material._textures[uniformId] = context.defaultTexture;
  60587. }
  60588. return;
  60589. }
  60590. if (uniformValue instanceof Texture && uniformValue !== texture) {
  60591. material._texturePaths[uniformId] = undefined;
  60592. var tmp = material._textures[uniformId];
  60593. if (tmp !== material._defaultTexture) {
  60594. tmp.destroy();
  60595. }
  60596. material._textures[uniformId] = uniformValue;
  60597. uniformDimensionsName = uniformId + 'Dimensions';
  60598. if (uniforms.hasOwnProperty(uniformDimensionsName)) {
  60599. uniformDimensions = uniforms[uniformDimensionsName];
  60600. uniformDimensions.x = uniformValue._width;
  60601. uniformDimensions.y = uniformValue._height;
  60602. }
  60603. return;
  60604. }
  60605. if (!defined(texture)) {
  60606. material._texturePaths[uniformId] = undefined;
  60607. if (!defined(material._defaultTexture)) {
  60608. material._defaultTexture = context.defaultTexture;
  60609. }
  60610. texture = material._textures[uniformId] = material._defaultTexture;
  60611. uniformDimensionsName = uniformId + 'Dimensions';
  60612. if (uniforms.hasOwnProperty(uniformDimensionsName)) {
  60613. uniformDimensions = uniforms[uniformDimensionsName];
  60614. uniformDimensions.x = texture._width;
  60615. uniformDimensions.y = texture._height;
  60616. }
  60617. }
  60618. if (uniformValue === Material.DefaultImageId) {
  60619. return;
  60620. }
  60621. if (uniformValue !== material._texturePaths[uniformId]) {
  60622. if (typeof uniformValue === 'string') {
  60623. when(loadImage(uniformValue), function(image) {
  60624. material._loadedImages.push({
  60625. id : uniformId,
  60626. image : image
  60627. });
  60628. });
  60629. } else if (uniformValue instanceof HTMLCanvasElement) {
  60630. material._loadedImages.push({
  60631. id : uniformId,
  60632. image : uniformValue
  60633. });
  60634. }
  60635. material._texturePaths[uniformId] = uniformValue;
  60636. }
  60637. };
  60638. }
  60639. function createCubeMapUpdateFunction(uniformId) {
  60640. return function(material, context) {
  60641. var uniformValue = material.uniforms[uniformId];
  60642. if (uniformValue instanceof CubeMap) {
  60643. var tmp = material._textures[uniformId];
  60644. if (tmp !== material._defaultTexture) {
  60645. tmp.destroy();
  60646. }
  60647. material._texturePaths[uniformId] = undefined;
  60648. material._textures[uniformId] = uniformValue;
  60649. return;
  60650. }
  60651. if (!defined(material._textures[uniformId])) {
  60652. material._texturePaths[uniformId] = undefined;
  60653. material._textures[uniformId] = context.defaultCubeMap;
  60654. }
  60655. if (uniformValue === Material.DefaultCubeMapId) {
  60656. return;
  60657. }
  60658. var path =
  60659. uniformValue.positiveX + uniformValue.negativeX +
  60660. uniformValue.positiveY + uniformValue.negativeY +
  60661. uniformValue.positiveZ + uniformValue.negativeZ;
  60662. if (path !== material._texturePaths[uniformId]) {
  60663. var promises = [
  60664. loadImage(uniformValue.positiveX),
  60665. loadImage(uniformValue.negativeX),
  60666. loadImage(uniformValue.positiveY),
  60667. loadImage(uniformValue.negativeY),
  60668. loadImage(uniformValue.positiveZ),
  60669. loadImage(uniformValue.negativeZ)
  60670. ];
  60671. when.all(promises).then(function(images) {
  60672. material._loadedCubeMaps.push({
  60673. id : uniformId,
  60674. images : images
  60675. });
  60676. });
  60677. material._texturePaths[uniformId] = path;
  60678. }
  60679. };
  60680. }
  60681. function createUniforms(material) {
  60682. var uniforms = material._template.uniforms;
  60683. for ( var uniformId in uniforms) {
  60684. if (uniforms.hasOwnProperty(uniformId)) {
  60685. createUniform(material, uniformId);
  60686. }
  60687. }
  60688. }
  60689. // Writes uniform declarations to the shader file and connects uniform values with
  60690. // corresponding material properties through the returnUniforms function.
  60691. function createUniform(material, uniformId) {
  60692. var strict = material._strict;
  60693. var materialUniforms = material._template.uniforms;
  60694. var uniformValue = materialUniforms[uniformId];
  60695. var uniformType = getUniformType(uniformValue);
  60696. if (!defined(uniformType)) {
  60697. throw new DeveloperError('fabric: uniform \'' + uniformId + '\' has invalid type.');
  60698. }
  60699. var replacedTokenCount;
  60700. if (uniformType === 'channels') {
  60701. replacedTokenCount = replaceToken(material, uniformId, uniformValue, false);
  60702. if (replacedTokenCount === 0 && strict) {
  60703. throw new DeveloperError('strict: shader source does not use channels \'' + uniformId + '\'.');
  60704. }
  60705. } else {
  60706. // Since webgl doesn't allow texture dimension queries in glsl, create a uniform to do it.
  60707. // Check if the shader source actually uses texture dimensions before creating the uniform.
  60708. if (uniformType === 'sampler2D') {
  60709. var imageDimensionsUniformName = uniformId + 'Dimensions';
  60710. if (getNumberOfTokens(material, imageDimensionsUniformName) > 0) {
  60711. materialUniforms[imageDimensionsUniformName] = {
  60712. type : 'ivec3',
  60713. x : 1,
  60714. y : 1
  60715. };
  60716. createUniform(material, imageDimensionsUniformName);
  60717. }
  60718. }
  60719. // Add uniform declaration to source code.
  60720. var uniformDeclarationRegex = new RegExp('uniform\\s+' + uniformType + '\\s+' + uniformId + '\\s*;');
  60721. if (!uniformDeclarationRegex.test(material.shaderSource)) {
  60722. var uniformDeclaration = 'uniform ' + uniformType + ' ' + uniformId + ';';
  60723. material.shaderSource = uniformDeclaration + material.shaderSource;
  60724. }
  60725. var newUniformId = uniformId + '_' + material._count++;
  60726. replacedTokenCount = replaceToken(material, uniformId, newUniformId);
  60727. if (replacedTokenCount === 1 && strict) {
  60728. throw new DeveloperError('strict: shader source does not use uniform \'' + uniformId + '\'.');
  60729. }
  60730. // Set uniform value
  60731. material.uniforms[uniformId] = uniformValue;
  60732. if (uniformType === 'sampler2D') {
  60733. material._uniforms[newUniformId] = function() {
  60734. return material._textures[uniformId];
  60735. };
  60736. material._updateFunctions.push(createTexture2DUpdateFunction(uniformId));
  60737. } else if (uniformType === 'samplerCube') {
  60738. material._uniforms[newUniformId] = function() {
  60739. return material._textures[uniformId];
  60740. };
  60741. material._updateFunctions.push(createCubeMapUpdateFunction(uniformId));
  60742. } else if (uniformType.indexOf('mat') !== -1) {
  60743. var scratchMatrix = new matrixMap[uniformType]();
  60744. material._uniforms[newUniformId] = function() {
  60745. return matrixMap[uniformType].fromColumnMajorArray(material.uniforms[uniformId], scratchMatrix);
  60746. };
  60747. } else {
  60748. material._uniforms[newUniformId] = function() {
  60749. return material.uniforms[uniformId];
  60750. };
  60751. }
  60752. }
  60753. }
  60754. // Determines the uniform type based on the uniform in the template.
  60755. function getUniformType(uniformValue) {
  60756. var uniformType = uniformValue.type;
  60757. if (!defined(uniformType)) {
  60758. var type = typeof uniformValue;
  60759. if (type === 'number') {
  60760. uniformType = 'float';
  60761. } else if (type === 'boolean') {
  60762. uniformType = 'bool';
  60763. } else if (type === 'string' || uniformValue instanceof HTMLCanvasElement) {
  60764. if (/^([rgba]){1,4}$/i.test(uniformValue)) {
  60765. uniformType = 'channels';
  60766. } else if (uniformValue === Material.DefaultCubeMapId) {
  60767. uniformType = 'samplerCube';
  60768. } else {
  60769. uniformType = 'sampler2D';
  60770. }
  60771. } else if (type === 'object') {
  60772. if (isArray(uniformValue)) {
  60773. if (uniformValue.length === 4 || uniformValue.length === 9 || uniformValue.length === 16) {
  60774. uniformType = 'mat' + Math.sqrt(uniformValue.length);
  60775. }
  60776. } else {
  60777. var numAttributes = 0;
  60778. for ( var attribute in uniformValue) {
  60779. if (uniformValue.hasOwnProperty(attribute)) {
  60780. numAttributes += 1;
  60781. }
  60782. }
  60783. if (numAttributes >= 2 && numAttributes <= 4) {
  60784. uniformType = 'vec' + numAttributes;
  60785. } else if (numAttributes === 6) {
  60786. uniformType = 'samplerCube';
  60787. }
  60788. }
  60789. }
  60790. }
  60791. return uniformType;
  60792. }
  60793. // Create all sub-materials by combining source and uniforms together.
  60794. function createSubMaterials(material) {
  60795. var strict = material._strict;
  60796. var subMaterialTemplates = material._template.materials;
  60797. for ( var subMaterialId in subMaterialTemplates) {
  60798. if (subMaterialTemplates.hasOwnProperty(subMaterialId)) {
  60799. // Construct the sub-material.
  60800. var subMaterial = new Material({
  60801. strict : strict,
  60802. fabric : subMaterialTemplates[subMaterialId],
  60803. count : material._count
  60804. });
  60805. material._count = subMaterial._count;
  60806. material._uniforms = combine(material._uniforms, subMaterial._uniforms, true);
  60807. material.materials[subMaterialId] = subMaterial;
  60808. material._translucentFunctions = material._translucentFunctions.concat(subMaterial._translucentFunctions);
  60809. // Make the material's czm_getMaterial unique by appending the sub-material type.
  60810. var originalMethodName = 'czm_getMaterial';
  60811. var newMethodName = originalMethodName + '_' + material._count++;
  60812. replaceToken(subMaterial, originalMethodName, newMethodName);
  60813. material.shaderSource = subMaterial.shaderSource + material.shaderSource;
  60814. // Replace each material id with an czm_getMaterial method call.
  60815. var materialMethodCall = newMethodName + '(materialInput)';
  60816. var tokensReplacedCount = replaceToken(material, subMaterialId, materialMethodCall);
  60817. if (tokensReplacedCount === 0 && strict) {
  60818. throw new DeveloperError('strict: shader source does not use material \'' + subMaterialId + '\'.');
  60819. }
  60820. }
  60821. }
  60822. }
  60823. // Used for searching or replacing a token in a material's shader source with something else.
  60824. // If excludePeriod is true, do not accept tokens that are preceded by periods.
  60825. // http://stackoverflow.com/questions/641407/javascript-negative-lookbehind-equivalent
  60826. function replaceToken(material, token, newToken, excludePeriod) {
  60827. excludePeriod = defaultValue(excludePeriod, true);
  60828. var count = 0;
  60829. var suffixChars = '([\\w])?';
  60830. var prefixChars = '([\\w' + (excludePeriod ? '.' : '') + '])?';
  60831. var regExp = new RegExp(prefixChars + token + suffixChars, 'g');
  60832. material.shaderSource = material.shaderSource.replace(regExp, function($0, $1, $2) {
  60833. if ($1 || $2) {
  60834. return $0;
  60835. }
  60836. count += 1;
  60837. return newToken;
  60838. });
  60839. return count;
  60840. }
  60841. function getNumberOfTokens(material, token, excludePeriod) {
  60842. return replaceToken(material, token, token, excludePeriod);
  60843. }
  60844. Material._materialCache = {
  60845. _materials : {},
  60846. addMaterial : function(type, materialTemplate) {
  60847. this._materials[type] = materialTemplate;
  60848. },
  60849. getMaterial : function(type) {
  60850. return this._materials[type];
  60851. }
  60852. };
  60853. /**
  60854. * Gets or sets the default texture uniform value.
  60855. * @type {String}
  60856. */
  60857. Material.DefaultImageId = 'czm_defaultImage';
  60858. /**
  60859. * Gets or sets the default cube map texture uniform value.
  60860. * @type {String}
  60861. */
  60862. Material.DefaultCubeMapId = 'czm_defaultCubeMap';
  60863. /**
  60864. * Gets the name of the color material.
  60865. * @type {String}
  60866. * @readonly
  60867. */
  60868. Material.ColorType = 'Color';
  60869. Material._materialCache.addMaterial(Material.ColorType, {
  60870. fabric : {
  60871. type : Material.ColorType,
  60872. uniforms : {
  60873. color : new Color(1.0, 0.0, 0.0, 0.5)
  60874. },
  60875. components : {
  60876. diffuse : 'color.rgb',
  60877. alpha : 'color.a'
  60878. }
  60879. },
  60880. translucent : function(material) {
  60881. return material.uniforms.color.alpha < 1.0;
  60882. }
  60883. });
  60884. /**
  60885. * Gets the name of the image material.
  60886. * @type {String}
  60887. * @readonly
  60888. */
  60889. Material.ImageType = 'Image';
  60890. Material._materialCache.addMaterial(Material.ImageType, {
  60891. fabric : {
  60892. type : Material.ImageType,
  60893. uniforms : {
  60894. image : Material.DefaultImageId,
  60895. repeat : new Cartesian2(1.0, 1.0),
  60896. color: new Color(1.0, 1.0, 1.0, 1.0)
  60897. },
  60898. components : {
  60899. diffuse : 'texture2D(image, fract(repeat * materialInput.st)).rgb * color.rgb',
  60900. alpha : 'texture2D(image, fract(repeat * materialInput.st)).a * color.a'
  60901. }
  60902. },
  60903. translucent : function(material) {
  60904. return material.uniforms.color.alpha < 1.0;
  60905. }
  60906. });
  60907. /**
  60908. * Gets the name of the diffuce map material.
  60909. * @type {String}
  60910. * @readonly
  60911. */
  60912. Material.DiffuseMapType = 'DiffuseMap';
  60913. Material._materialCache.addMaterial(Material.DiffuseMapType, {
  60914. fabric : {
  60915. type : Material.DiffuseMapType,
  60916. uniforms : {
  60917. image : Material.DefaultImageId,
  60918. channels : 'rgb',
  60919. repeat : new Cartesian2(1.0, 1.0)
  60920. },
  60921. components : {
  60922. diffuse : 'texture2D(image, fract(repeat * materialInput.st)).channels'
  60923. }
  60924. },
  60925. translucent : false
  60926. });
  60927. /**
  60928. * Gets the name of the alpha map material.
  60929. * @type {String}
  60930. * @readonly
  60931. */
  60932. Material.AlphaMapType = 'AlphaMap';
  60933. Material._materialCache.addMaterial(Material.AlphaMapType, {
  60934. fabric : {
  60935. type : Material.AlphaMapType,
  60936. uniforms : {
  60937. image : Material.DefaultImageId,
  60938. channel : 'a',
  60939. repeat : new Cartesian2(1.0, 1.0)
  60940. },
  60941. components : {
  60942. alpha : 'texture2D(image, fract(repeat * materialInput.st)).channel'
  60943. }
  60944. },
  60945. translucent : true
  60946. });
  60947. /**
  60948. * Gets the name of the specular map material.
  60949. * @type {String}
  60950. * @readonly
  60951. */
  60952. Material.SpecularMapType = 'SpecularMap';
  60953. Material._materialCache.addMaterial(Material.SpecularMapType, {
  60954. fabric : {
  60955. type : Material.SpecularMapType,
  60956. uniforms : {
  60957. image : Material.DefaultImageId,
  60958. channel : 'r',
  60959. repeat : new Cartesian2(1.0, 1.0)
  60960. },
  60961. components : {
  60962. specular : 'texture2D(image, fract(repeat * materialInput.st)).channel'
  60963. }
  60964. },
  60965. translucent : false
  60966. });
  60967. /**
  60968. * Gets the name of the emmision map material.
  60969. * @type {String}
  60970. * @readonly
  60971. */
  60972. Material.EmissionMapType = 'EmissionMap';
  60973. Material._materialCache.addMaterial(Material.EmissionMapType, {
  60974. fabric : {
  60975. type : Material.EmissionMapType,
  60976. uniforms : {
  60977. image : Material.DefaultImageId,
  60978. channels : 'rgb',
  60979. repeat : new Cartesian2(1.0, 1.0)
  60980. },
  60981. components : {
  60982. emission : 'texture2D(image, fract(repeat * materialInput.st)).channels'
  60983. }
  60984. },
  60985. translucent : false
  60986. });
  60987. /**
  60988. * Gets the name of the bump map material.
  60989. * @type {String}
  60990. * @readonly
  60991. */
  60992. Material.BumpMapType = 'BumpMap';
  60993. Material._materialCache.addMaterial(Material.BumpMapType, {
  60994. fabric : {
  60995. type : Material.BumpMapType,
  60996. uniforms : {
  60997. image : Material.DefaultImageId,
  60998. channel : 'r',
  60999. strength : 0.8,
  61000. repeat : new Cartesian2(1.0, 1.0)
  61001. },
  61002. source : BumpMapMaterial
  61003. },
  61004. translucent : false
  61005. });
  61006. /**
  61007. * Gets the name of the normal map material.
  61008. * @type {String}
  61009. * @readonly
  61010. */
  61011. Material.NormalMapType = 'NormalMap';
  61012. Material._materialCache.addMaterial(Material.NormalMapType, {
  61013. fabric : {
  61014. type : Material.NormalMapType,
  61015. uniforms : {
  61016. image : Material.DefaultImageId,
  61017. channels : 'rgb',
  61018. strength : 0.8,
  61019. repeat : new Cartesian2(1.0, 1.0)
  61020. },
  61021. source : NormalMapMaterial
  61022. },
  61023. translucent : false
  61024. });
  61025. /**
  61026. * Gets the name of the grid material.
  61027. * @type {String}
  61028. * @readonly
  61029. */
  61030. Material.GridType = 'Grid';
  61031. Material._materialCache.addMaterial(Material.GridType, {
  61032. fabric : {
  61033. type : Material.GridType,
  61034. uniforms : {
  61035. color : new Color(0.0, 1.0, 0.0, 1.0),
  61036. cellAlpha : 0.1,
  61037. lineCount : new Cartesian2(8.0, 8.0),
  61038. lineThickness : new Cartesian2(1.0, 1.0),
  61039. lineOffset : new Cartesian2(0.0, 0.0)
  61040. },
  61041. source : GridMaterial
  61042. },
  61043. translucent : function(material) {
  61044. var uniforms = material.uniforms;
  61045. return (uniforms.color.alpha < 1.0) || (uniforms.cellAlpha < 1.0);
  61046. }
  61047. });
  61048. /**
  61049. * Gets the name of the stripe material.
  61050. * @type {String}
  61051. * @readonly
  61052. */
  61053. Material.StripeType = 'Stripe';
  61054. Material._materialCache.addMaterial(Material.StripeType, {
  61055. fabric : {
  61056. type : Material.StripeType,
  61057. uniforms : {
  61058. horizontal : true,
  61059. evenColor : new Color(1.0, 1.0, 1.0, 0.5),
  61060. oddColor : new Color(0.0, 0.0, 1.0, 0.5),
  61061. offset : 0.0,
  61062. repeat : 5.0
  61063. },
  61064. source : StripeMaterial
  61065. },
  61066. translucent : function(material) {
  61067. var uniforms = material.uniforms;
  61068. return (uniforms.evenColor.alpha < 1.0) || (uniforms.oddColor.alpha < 0.0);
  61069. }
  61070. });
  61071. /**
  61072. * Gets the name of the checkerboard material.
  61073. * @type {String}
  61074. * @readonly
  61075. */
  61076. Material.CheckerboardType = 'Checkerboard';
  61077. Material._materialCache.addMaterial(Material.CheckerboardType, {
  61078. fabric : {
  61079. type : Material.CheckerboardType,
  61080. uniforms : {
  61081. lightColor : new Color(1.0, 1.0, 1.0, 0.5),
  61082. darkColor : new Color(0.0, 0.0, 0.0, 0.5),
  61083. repeat : new Cartesian2(5.0, 5.0)
  61084. },
  61085. source : CheckerboardMaterial
  61086. },
  61087. translucent : function(material) {
  61088. var uniforms = material.uniforms;
  61089. return (uniforms.lightColor.alpha < 1.0) || (uniforms.darkColor.alpha < 0.0);
  61090. }
  61091. });
  61092. /**
  61093. * Gets the name of the dot material.
  61094. * @type {String}
  61095. * @readonly
  61096. */
  61097. Material.DotType = 'Dot';
  61098. Material._materialCache.addMaterial(Material.DotType, {
  61099. fabric : {
  61100. type : Material.DotType,
  61101. uniforms : {
  61102. lightColor : new Color(1.0, 1.0, 0.0, 0.75),
  61103. darkColor : new Color(0.0, 1.0, 1.0, 0.75),
  61104. repeat : new Cartesian2(5.0, 5.0)
  61105. },
  61106. source : DotMaterial
  61107. },
  61108. translucent : function(material) {
  61109. var uniforms = material.uniforms;
  61110. return (uniforms.lightColor.alpha < 1.0) || (uniforms.darkColor.alpha < 0.0);
  61111. }
  61112. });
  61113. /**
  61114. * Gets the name of the water material.
  61115. * @type {String}
  61116. * @readonly
  61117. */
  61118. Material.WaterType = 'Water';
  61119. Material._materialCache.addMaterial(Material.WaterType, {
  61120. fabric : {
  61121. type : Material.WaterType,
  61122. uniforms : {
  61123. baseWaterColor : new Color(0.2, 0.3, 0.6, 1.0),
  61124. blendColor : new Color(0.0, 1.0, 0.699, 1.0),
  61125. specularMap : Material.DefaultImageId,
  61126. normalMap : Material.DefaultImageId,
  61127. frequency : 10.0,
  61128. animationSpeed : 0.01,
  61129. amplitude : 1.0,
  61130. specularIntensity : 0.5,
  61131. fadeFactor : 1.0
  61132. },
  61133. source : WaterMaterial
  61134. },
  61135. translucent : function(material) {
  61136. var uniforms = material.uniforms;
  61137. return (uniforms.baseWaterColor.alpha < 1.0) || (uniforms.blendColor.alpha < 0.0);
  61138. }
  61139. });
  61140. /**
  61141. * Gets the name of the rim lighting material.
  61142. * @type {String}
  61143. * @readonly
  61144. */
  61145. Material.RimLightingType = 'RimLighting';
  61146. Material._materialCache.addMaterial(Material.RimLightingType, {
  61147. fabric : {
  61148. type : Material.RimLightingType,
  61149. uniforms : {
  61150. color : new Color(1.0, 0.0, 0.0, 0.7),
  61151. rimColor : new Color(1.0, 1.0, 1.0, 0.4),
  61152. width : 0.3
  61153. },
  61154. source : RimLightingMaterial
  61155. },
  61156. translucent : function(material) {
  61157. var uniforms = material.uniforms;
  61158. return (uniforms.color.alpha < 1.0) || (uniforms.rimColor.alpha < 0.0);
  61159. }
  61160. });
  61161. /**
  61162. * Gets the name of the fade material.
  61163. * @type {String}
  61164. * @readonly
  61165. */
  61166. Material.FadeType = 'Fade';
  61167. Material._materialCache.addMaterial(Material.FadeType, {
  61168. fabric : {
  61169. type : Material.FadeType,
  61170. uniforms : {
  61171. fadeInColor : new Color(1.0, 0.0, 0.0, 1.0),
  61172. fadeOutColor : new Color(0.0, 0.0, 0.0, 0.0),
  61173. maximumDistance : 0.5,
  61174. repeat : true,
  61175. fadeDirection : {
  61176. x : true,
  61177. y : true
  61178. },
  61179. time : new Cartesian2(0.5, 0.5)
  61180. },
  61181. source : FadeMaterial
  61182. },
  61183. translucent : function(material) {
  61184. var uniforms = material.uniforms;
  61185. return (uniforms.fadeInColor.alpha < 1.0) || (uniforms.fadeOutColor.alpha < 0.0);
  61186. }
  61187. });
  61188. /**
  61189. * Gets the name of the polyline arrow material.
  61190. * @type {String}
  61191. * @readonly
  61192. */
  61193. Material.PolylineArrowType = 'PolylineArrow';
  61194. Material._materialCache.addMaterial(Material.PolylineArrowType, {
  61195. fabric : {
  61196. type : Material.PolylineArrowType,
  61197. uniforms : {
  61198. color : new Color(1.0, 1.0, 1.0, 1.0)
  61199. },
  61200. source : PolylineArrowMaterial
  61201. },
  61202. translucent : true
  61203. });
  61204. /**
  61205. * Gets the name of the polyline glow material.
  61206. * @type {String}
  61207. * @readonly
  61208. */
  61209. Material.PolylineGlowType = 'PolylineGlow';
  61210. Material._materialCache.addMaterial(Material.PolylineGlowType, {
  61211. fabric : {
  61212. type : Material.PolylineGlowType,
  61213. uniforms : {
  61214. color : new Color(0.0, 0.5, 1.0, 1.0),
  61215. glowPower : 0.25
  61216. },
  61217. source : PolylineGlowMaterial
  61218. },
  61219. translucent : true
  61220. });
  61221. /**
  61222. * Gets the name of the polyline outline material.
  61223. * @type {String}
  61224. * @readonly
  61225. */
  61226. Material.PolylineOutlineType = 'PolylineOutline';
  61227. Material._materialCache.addMaterial(Material.PolylineOutlineType, {
  61228. fabric : {
  61229. type : Material.PolylineOutlineType,
  61230. uniforms : {
  61231. color : new Color(1.0, 1.0, 1.0, 1.0),
  61232. outlineColor : new Color(1.0, 0.0, 0.0, 1.0),
  61233. outlineWidth : 1.0
  61234. },
  61235. source : PolylineOutlineMaterial
  61236. },
  61237. translucent : function(material) {
  61238. var uniforms = material.uniforms;
  61239. return (uniforms.color.alpha < 1.0) || (uniforms.outlineColor.alpha < 1.0);
  61240. }
  61241. });
  61242. return Material;
  61243. });
  61244. /*global define*/
  61245. define('Scene/MaterialAppearance',[
  61246. '../Core/defaultValue',
  61247. '../Core/defined',
  61248. '../Core/defineProperties',
  61249. '../Core/freezeObject',
  61250. '../Core/VertexFormat',
  61251. '../Shaders/Appearances/AllMaterialAppearanceFS',
  61252. '../Shaders/Appearances/AllMaterialAppearanceVS',
  61253. '../Shaders/Appearances/BasicMaterialAppearanceFS',
  61254. '../Shaders/Appearances/BasicMaterialAppearanceVS',
  61255. '../Shaders/Appearances/TexturedMaterialAppearanceFS',
  61256. '../Shaders/Appearances/TexturedMaterialAppearanceVS',
  61257. './Appearance',
  61258. './Material'
  61259. ], function(
  61260. defaultValue,
  61261. defined,
  61262. defineProperties,
  61263. freezeObject,
  61264. VertexFormat,
  61265. AllMaterialAppearanceFS,
  61266. AllMaterialAppearanceVS,
  61267. BasicMaterialAppearanceFS,
  61268. BasicMaterialAppearanceVS,
  61269. TexturedMaterialAppearanceFS,
  61270. TexturedMaterialAppearanceVS,
  61271. Appearance,
  61272. Material) {
  61273. 'use strict';
  61274. /**
  61275. * An appearance for arbitrary geometry (as opposed to {@link EllipsoidSurfaceAppearance}, for example)
  61276. * that supports shading with materials.
  61277. *
  61278. * @alias MaterialAppearance
  61279. * @constructor
  61280. *
  61281. * @param {Object} [options] Object with the following properties:
  61282. * @param {Boolean} [options.flat=false] When <code>true</code>, flat shading is used in the fragment shader, which means lighting is not taking into account.
  61283. * @param {Boolean} [options.faceForward=!options.closed] When <code>true</code>, the fragment shader flips the surface normal as needed to ensure that the normal faces the viewer to avoid dark spots. This is useful when both sides of a geometry should be shaded like {@link WallGeometry}.
  61284. * @param {Boolean} [options.translucent=true] When <code>true</code>, the geometry is expected to appear translucent so {@link MaterialAppearance#renderState} has alpha blending enabled.
  61285. * @param {Boolean} [options.closed=false] When <code>true</code>, the geometry is expected to be closed so {@link MaterialAppearance#renderState} has backface culling enabled.
  61286. * @param {MaterialAppearance.MaterialSupport} [options.materialSupport=MaterialAppearance.MaterialSupport.TEXTURED] The type of materials that will be supported.
  61287. * @param {Material} [options.material=Material.ColorType] The material used to determine the fragment color.
  61288. * @param {String} [options.vertexShaderSource] Optional GLSL vertex shader source to override the default vertex shader.
  61289. * @param {String} [options.fragmentShaderSource] Optional GLSL fragment shader source to override the default fragment shader.
  61290. * @param {RenderState} [options.renderState] Optional render state to override the default render state.
  61291. *
  61292. * @see {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}
  61293. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Materials.html|Cesium Sandcastle Material Appearance Demo}
  61294. *
  61295. * @example
  61296. * var primitive = new Cesium.Primitive({
  61297. * geometryInstances : new Cesium.GeometryInstance({
  61298. * geometry : new Cesium.WallGeometry({
  61299. materialSupport : Cesium.MaterialAppearance.MaterialSupport.BASIC.vertexFormat,
  61300. * // ...
  61301. * })
  61302. * }),
  61303. * appearance : new Cesium.MaterialAppearance({
  61304. * material : Cesium.Material.fromType('Color'),
  61305. * faceForward : true
  61306. * })
  61307. *
  61308. * });
  61309. */
  61310. function MaterialAppearance(options) {
  61311. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  61312. var translucent = defaultValue(options.translucent, true);
  61313. var closed = defaultValue(options.closed, false);
  61314. var materialSupport = defaultValue(options.materialSupport, MaterialAppearance.MaterialSupport.TEXTURED);
  61315. /**
  61316. * The material used to determine the fragment color. Unlike other {@link MaterialAppearance}
  61317. * properties, this is not read-only, so an appearance's material can change on the fly.
  61318. *
  61319. * @type Material
  61320. *
  61321. * @default {@link Material.ColorType}
  61322. *
  61323. * @see {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}
  61324. */
  61325. this.material = (defined(options.material)) ? options.material : Material.fromType(Material.ColorType);
  61326. /**
  61327. * When <code>true</code>, the geometry is expected to appear translucent.
  61328. *
  61329. * @type {Boolean}
  61330. *
  61331. * @default true
  61332. */
  61333. this.translucent = translucent;
  61334. this._vertexShaderSource = defaultValue(options.vertexShaderSource, materialSupport.vertexShaderSource);
  61335. this._fragmentShaderSource = defaultValue(options.fragmentShaderSource, materialSupport.fragmentShaderSource);
  61336. this._renderState = Appearance.getDefaultRenderState(translucent, closed, options.renderState);
  61337. this._closed = closed;
  61338. // Non-derived members
  61339. this._materialSupport = materialSupport;
  61340. this._vertexFormat = materialSupport.vertexFormat;
  61341. this._flat = defaultValue(options.flat, false);
  61342. this._faceForward = defaultValue(options.faceForward, !closed);
  61343. }
  61344. defineProperties(MaterialAppearance.prototype, {
  61345. /**
  61346. * The GLSL source code for the vertex shader.
  61347. *
  61348. * @memberof MaterialAppearance.prototype
  61349. *
  61350. * @type {String}
  61351. * @readonly
  61352. */
  61353. vertexShaderSource : {
  61354. get : function() {
  61355. return this._vertexShaderSource;
  61356. }
  61357. },
  61358. /**
  61359. * The GLSL source code for the fragment shader. The full fragment shader
  61360. * source is built procedurally taking into account {@link MaterialAppearance#material},
  61361. * {@link MaterialAppearance#flat}, and {@link MaterialAppearance#faceForward}.
  61362. * Use {@link MaterialAppearance#getFragmentShaderSource} to get the full source.
  61363. *
  61364. * @memberof MaterialAppearance.prototype
  61365. *
  61366. * @type {String}
  61367. * @readonly
  61368. */
  61369. fragmentShaderSource : {
  61370. get : function() {
  61371. return this._fragmentShaderSource;
  61372. }
  61373. },
  61374. /**
  61375. * The WebGL fixed-function state to use when rendering the geometry.
  61376. * <p>
  61377. * The render state can be explicitly defined when constructing a {@link MaterialAppearance}
  61378. * instance, or it is set implicitly via {@link MaterialAppearance#translucent}
  61379. * and {@link MaterialAppearance#closed}.
  61380. * </p>
  61381. *
  61382. * @memberof MaterialAppearance.prototype
  61383. *
  61384. * @type {Object}
  61385. * @readonly
  61386. */
  61387. renderState : {
  61388. get : function() {
  61389. return this._renderState;
  61390. }
  61391. },
  61392. /**
  61393. * When <code>true</code>, the geometry is expected to be closed so
  61394. * {@link MaterialAppearance#renderState} has backface culling enabled.
  61395. * If the viewer enters the geometry, it will not be visible.
  61396. *
  61397. * @memberof MaterialAppearance.prototype
  61398. *
  61399. * @type {Boolean}
  61400. * @readonly
  61401. *
  61402. * @default false
  61403. */
  61404. closed : {
  61405. get : function() {
  61406. return this._closed;
  61407. }
  61408. },
  61409. /**
  61410. * The type of materials supported by this instance. This impacts the required
  61411. * {@link VertexFormat} and the complexity of the vertex and fragment shaders.
  61412. *
  61413. * @memberof MaterialAppearance.prototype
  61414. *
  61415. * @type {MaterialAppearance.MaterialSupport}
  61416. * @readonly
  61417. *
  61418. * @default {@link MaterialAppearance.MaterialSupport.TEXTURED}
  61419. */
  61420. materialSupport : {
  61421. get : function() {
  61422. return this._materialSupport;
  61423. }
  61424. },
  61425. /**
  61426. * The {@link VertexFormat} that this appearance instance is compatible with.
  61427. * A geometry can have more vertex attributes and still be compatible - at a
  61428. * potential performance cost - but it can't have less.
  61429. *
  61430. * @memberof MaterialAppearance.prototype
  61431. *
  61432. * @type VertexFormat
  61433. * @readonly
  61434. *
  61435. * @default {@link MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat}
  61436. */
  61437. vertexFormat : {
  61438. get : function() {
  61439. return this._vertexFormat;
  61440. }
  61441. },
  61442. /**
  61443. * When <code>true</code>, flat shading is used in the fragment shader,
  61444. * which means lighting is not taking into account.
  61445. *
  61446. * @memberof MaterialAppearance.prototype
  61447. *
  61448. * @type {Boolean}
  61449. * @readonly
  61450. *
  61451. * @default false
  61452. */
  61453. flat : {
  61454. get : function() {
  61455. return this._flat;
  61456. }
  61457. },
  61458. /**
  61459. * When <code>true</code>, the fragment shader flips the surface normal
  61460. * as needed to ensure that the normal faces the viewer to avoid
  61461. * dark spots. This is useful when both sides of a geometry should be
  61462. * shaded like {@link WallGeometry}.
  61463. *
  61464. * @memberof MaterialAppearance.prototype
  61465. *
  61466. * @type {Boolean}
  61467. * @readonly
  61468. *
  61469. * @default true
  61470. */
  61471. faceForward : {
  61472. get : function() {
  61473. return this._faceForward;
  61474. }
  61475. }
  61476. });
  61477. /**
  61478. * Procedurally creates the full GLSL fragment shader source. For {@link MaterialAppearance},
  61479. * this is derived from {@link MaterialAppearance#fragmentShaderSource}, {@link MaterialAppearance#material},
  61480. * {@link MaterialAppearance#flat}, and {@link MaterialAppearance#faceForward}.
  61481. *
  61482. * @function
  61483. *
  61484. * @returns {String} The full GLSL fragment shader source.
  61485. */
  61486. MaterialAppearance.prototype.getFragmentShaderSource = Appearance.prototype.getFragmentShaderSource;
  61487. /**
  61488. * Determines if the geometry is translucent based on {@link MaterialAppearance#translucent} and {@link Material#isTranslucent}.
  61489. *
  61490. * @function
  61491. *
  61492. * @returns {Boolean} <code>true</code> if the appearance is translucent.
  61493. */
  61494. MaterialAppearance.prototype.isTranslucent = Appearance.prototype.isTranslucent;
  61495. /**
  61496. * Creates a render state. This is not the final render state instance; instead,
  61497. * it can contain a subset of render state properties identical to the render state
  61498. * created in the context.
  61499. *
  61500. * @function
  61501. *
  61502. * @returns {Object} The render state.
  61503. */
  61504. MaterialAppearance.prototype.getRenderState = Appearance.prototype.getRenderState;
  61505. /**
  61506. * Determines the type of {@link Material} that is supported by a
  61507. * {@link MaterialAppearance} instance. This is a trade-off between
  61508. * flexibility (a wide array of materials) and memory/performance
  61509. * (required vertex format and GLSL shader complexity.
  61510. */
  61511. MaterialAppearance.MaterialSupport = {
  61512. /**
  61513. * Only basic materials, which require just <code>position</code> and
  61514. * <code>normal</code> vertex attributes, are supported.
  61515. *
  61516. * @constant
  61517. */
  61518. BASIC : freezeObject({
  61519. vertexFormat : VertexFormat.POSITION_AND_NORMAL,
  61520. vertexShaderSource : BasicMaterialAppearanceVS,
  61521. fragmentShaderSource : BasicMaterialAppearanceFS
  61522. }),
  61523. /**
  61524. * Materials with textures, which require <code>position</code>,
  61525. * <code>normal</code>, and <code>st</code> vertex attributes,
  61526. * are supported. The vast majority of materials fall into this category.
  61527. *
  61528. * @constant
  61529. */
  61530. TEXTURED : freezeObject({
  61531. vertexFormat : VertexFormat.POSITION_NORMAL_AND_ST,
  61532. vertexShaderSource : TexturedMaterialAppearanceVS,
  61533. fragmentShaderSource : TexturedMaterialAppearanceFS
  61534. }),
  61535. /**
  61536. * All materials, including those that work in tangent space, are supported.
  61537. * This requires <code>position</code>, <code>normal</code>, <code>st</code>,
  61538. * <code>binormal</code>, and <code>tangent</code> vertex attributes.
  61539. *
  61540. * @constant
  61541. */
  61542. ALL : freezeObject({
  61543. vertexFormat : VertexFormat.ALL,
  61544. vertexShaderSource : AllMaterialAppearanceVS,
  61545. fragmentShaderSource : AllMaterialAppearanceFS
  61546. })
  61547. };
  61548. return MaterialAppearance;
  61549. });
  61550. //This file is automatically rebuilt by the Cesium build process.
  61551. /*global define*/
  61552. define('Shaders/Appearances/PerInstanceColorAppearanceFS',[],function() {
  61553. 'use strict';
  61554. return "varying vec3 v_positionEC;\n\
  61555. varying vec3 v_normalEC;\n\
  61556. varying vec4 v_color;\n\
  61557. void main()\n\
  61558. {\n\
  61559. vec3 positionToEyeEC = -v_positionEC;\n\
  61560. vec3 normalEC = normalize(v_normalEC);\n\
  61561. #ifdef FACE_FORWARD\n\
  61562. normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n\
  61563. #endif\n\
  61564. czm_materialInput materialInput;\n\
  61565. materialInput.normalEC = normalEC;\n\
  61566. materialInput.positionToEyeEC = positionToEyeEC;\n\
  61567. czm_material material = czm_getDefaultMaterial(materialInput);\n\
  61568. material.diffuse = v_color.rgb;\n\
  61569. material.alpha = v_color.a;\n\
  61570. gl_FragColor = czm_phong(normalize(positionToEyeEC), material);\n\
  61571. }\n\
  61572. ";
  61573. });
  61574. //This file is automatically rebuilt by the Cesium build process.
  61575. /*global define*/
  61576. define('Shaders/Appearances/PerInstanceColorAppearanceVS',[],function() {
  61577. 'use strict';
  61578. return "attribute vec3 position3DHigh;\n\
  61579. attribute vec3 position3DLow;\n\
  61580. attribute vec3 normal;\n\
  61581. attribute vec4 color;\n\
  61582. attribute float batchId;\n\
  61583. varying vec3 v_positionEC;\n\
  61584. varying vec3 v_normalEC;\n\
  61585. varying vec4 v_color;\n\
  61586. void main()\n\
  61587. {\n\
  61588. vec4 p = czm_computePosition();\n\
  61589. v_positionEC = (czm_modelViewRelativeToEye * p).xyz;\n\
  61590. v_normalEC = czm_normal * normal;\n\
  61591. v_color = color;\n\
  61592. gl_Position = czm_modelViewProjectionRelativeToEye * p;\n\
  61593. }\n\
  61594. ";
  61595. });
  61596. //This file is automatically rebuilt by the Cesium build process.
  61597. /*global define*/
  61598. define('Shaders/Appearances/PerInstanceFlatColorAppearanceFS',[],function() {
  61599. 'use strict';
  61600. return "varying vec4 v_color;\n\
  61601. void main()\n\
  61602. {\n\
  61603. gl_FragColor = v_color;\n\
  61604. }\n\
  61605. ";
  61606. });
  61607. //This file is automatically rebuilt by the Cesium build process.
  61608. /*global define*/
  61609. define('Shaders/Appearances/PerInstanceFlatColorAppearanceVS',[],function() {
  61610. 'use strict';
  61611. return "attribute vec3 position3DHigh;\n\
  61612. attribute vec3 position3DLow;\n\
  61613. attribute vec4 color;\n\
  61614. attribute float batchId;\n\
  61615. varying vec4 v_color;\n\
  61616. void main()\n\
  61617. {\n\
  61618. vec4 p = czm_computePosition();\n\
  61619. v_color = color;\n\
  61620. gl_Position = czm_modelViewProjectionRelativeToEye * p;\n\
  61621. }\n\
  61622. ";
  61623. });
  61624. /*global define*/
  61625. define('Scene/PerInstanceColorAppearance',[
  61626. '../Core/defaultValue',
  61627. '../Core/defineProperties',
  61628. '../Core/VertexFormat',
  61629. '../Shaders/Appearances/PerInstanceColorAppearanceFS',
  61630. '../Shaders/Appearances/PerInstanceColorAppearanceVS',
  61631. '../Shaders/Appearances/PerInstanceFlatColorAppearanceFS',
  61632. '../Shaders/Appearances/PerInstanceFlatColorAppearanceVS',
  61633. './Appearance'
  61634. ], function(
  61635. defaultValue,
  61636. defineProperties,
  61637. VertexFormat,
  61638. PerInstanceColorAppearanceFS,
  61639. PerInstanceColorAppearanceVS,
  61640. PerInstanceFlatColorAppearanceFS,
  61641. PerInstanceFlatColorAppearanceVS,
  61642. Appearance) {
  61643. 'use strict';
  61644. /**
  61645. * An appearance for {@link GeometryInstance} instances with color attributes.
  61646. * This allows several geometry instances, each with a different color, to
  61647. * be drawn with the same {@link Primitive} as shown in the second example below.
  61648. *
  61649. * @alias PerInstanceColorAppearance
  61650. * @constructor
  61651. *
  61652. * @param {Object} [options] Object with the following properties:
  61653. * @param {Boolean} [options.flat=false] When <code>true</code>, flat shading is used in the fragment shader, which means lighting is not taking into account.
  61654. * @param {Boolean} [options.faceForward=!options.closed] When <code>true</code>, the fragment shader flips the surface normal as needed to ensure that the normal faces the viewer to avoid dark spots. This is useful when both sides of a geometry should be shaded like {@link WallGeometry}.
  61655. * @param {Boolean} [options.translucent=true] When <code>true</code>, the geometry is expected to appear translucent so {@link PerInstanceColorAppearance#renderState} has alpha blending enabled.
  61656. * @param {Boolean} [options.closed=false] When <code>true</code>, the geometry is expected to be closed so {@link PerInstanceColorAppearance#renderState} has backface culling enabled.
  61657. * @param {String} [options.vertexShaderSource] Optional GLSL vertex shader source to override the default vertex shader.
  61658. * @param {String} [options.fragmentShaderSource] Optional GLSL fragment shader source to override the default fragment shader.
  61659. * @param {RenderState} [options.renderState] Optional render state to override the default render state.
  61660. *
  61661. * @example
  61662. * // A solid white line segment
  61663. * var primitive = new Cesium.Primitive({
  61664. * geometryInstances : new Cesium.GeometryInstance({
  61665. * geometry : new Cesium.SimplePolylineGeometry({
  61666. * positions : Cesium.Cartesian3.fromDegreesArray([
  61667. * 0.0, 0.0,
  61668. * 5.0, 0.0
  61669. * ])
  61670. * }),
  61671. * attributes : {
  61672. * color : Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(1.0, 1.0, 1.0, 1.0))
  61673. * }
  61674. * }),
  61675. * appearance : new Cesium.PerInstanceColorAppearance({
  61676. * flat : true,
  61677. * translucent : false
  61678. * })
  61679. * });
  61680. *
  61681. * // Two rectangles in a primitive, each with a different color
  61682. * var instance = new Cesium.GeometryInstance({
  61683. * geometry : new Cesium.RectangleGeometry({
  61684. * rectangle : Cesium.Rectangle.fromDegrees(0.0, 20.0, 10.0, 30.0)
  61685. * }),
  61686. * attributes : {
  61687. * color : new Cesium.Color(1.0, 0.0, 0.0, 0.5)
  61688. * }
  61689. * });
  61690. *
  61691. * var anotherInstance = new Cesium.GeometryInstance({
  61692. * geometry : new Cesium.RectangleGeometry({
  61693. * rectangle : Cesium.Rectangle.fromDegrees(0.0, 40.0, 10.0, 50.0)
  61694. * }),
  61695. * attributes : {
  61696. * color : new Cesium.Color(0.0, 0.0, 1.0, 0.5)
  61697. * }
  61698. * });
  61699. *
  61700. * var rectanglePrimitive = new Cesium.Primitive({
  61701. * geometryInstances : [instance, anotherInstance],
  61702. * appearance : new Cesium.PerInstanceColorAppearance()
  61703. * });
  61704. */
  61705. function PerInstanceColorAppearance(options) {
  61706. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  61707. var translucent = defaultValue(options.translucent, true);
  61708. var closed = defaultValue(options.closed, false);
  61709. var flat = defaultValue(options.flat, false);
  61710. var vs = flat ? PerInstanceFlatColorAppearanceVS : PerInstanceColorAppearanceVS;
  61711. var fs = flat ? PerInstanceFlatColorAppearanceFS : PerInstanceColorAppearanceFS;
  61712. var vertexFormat = flat ? PerInstanceColorAppearance.FLAT_VERTEX_FORMAT : PerInstanceColorAppearance.VERTEX_FORMAT;
  61713. /**
  61714. * This property is part of the {@link Appearance} interface, but is not
  61715. * used by {@link PerInstanceColorAppearance} since a fully custom fragment shader is used.
  61716. *
  61717. * @type Material
  61718. *
  61719. * @default undefined
  61720. */
  61721. this.material = undefined;
  61722. /**
  61723. * When <code>true</code>, the geometry is expected to appear translucent so
  61724. * {@link PerInstanceColorAppearance#renderState} has alpha blending enabled.
  61725. *
  61726. * @type {Boolean}
  61727. *
  61728. * @default true
  61729. */
  61730. this.translucent = translucent;
  61731. this._vertexShaderSource = defaultValue(options.vertexShaderSource, vs);
  61732. this._fragmentShaderSource = defaultValue(options.fragmentShaderSource, fs);
  61733. this._renderState = Appearance.getDefaultRenderState(translucent, closed, options.renderState);
  61734. this._closed = closed;
  61735. // Non-derived members
  61736. this._vertexFormat = vertexFormat;
  61737. this._flat = flat;
  61738. this._faceForward = defaultValue(options.faceForward, !closed);
  61739. }
  61740. defineProperties(PerInstanceColorAppearance.prototype, {
  61741. /**
  61742. * The GLSL source code for the vertex shader.
  61743. *
  61744. * @memberof PerInstanceColorAppearance.prototype
  61745. *
  61746. * @type {String}
  61747. * @readonly
  61748. */
  61749. vertexShaderSource : {
  61750. get : function() {
  61751. return this._vertexShaderSource;
  61752. }
  61753. },
  61754. /**
  61755. * The GLSL source code for the fragment shader.
  61756. *
  61757. * @memberof PerInstanceColorAppearance.prototype
  61758. *
  61759. * @type {String}
  61760. * @readonly
  61761. */
  61762. fragmentShaderSource : {
  61763. get : function() {
  61764. return this._fragmentShaderSource;
  61765. }
  61766. },
  61767. /**
  61768. * The WebGL fixed-function state to use when rendering the geometry.
  61769. * <p>
  61770. * The render state can be explicitly defined when constructing a {@link PerInstanceColorAppearance}
  61771. * instance, or it is set implicitly via {@link PerInstanceColorAppearance#translucent}
  61772. * and {@link PerInstanceColorAppearance#closed}.
  61773. * </p>
  61774. *
  61775. * @memberof PerInstanceColorAppearance.prototype
  61776. *
  61777. * @type {Object}
  61778. * @readonly
  61779. */
  61780. renderState : {
  61781. get : function() {
  61782. return this._renderState;
  61783. }
  61784. },
  61785. /**
  61786. * When <code>true</code>, the geometry is expected to be closed so
  61787. * {@link PerInstanceColorAppearance#renderState} has backface culling enabled.
  61788. * If the viewer enters the geometry, it will not be visible.
  61789. *
  61790. * @memberof PerInstanceColorAppearance.prototype
  61791. *
  61792. * @type {Boolean}
  61793. * @readonly
  61794. *
  61795. * @default false
  61796. */
  61797. closed : {
  61798. get : function() {
  61799. return this._closed;
  61800. }
  61801. },
  61802. /**
  61803. * The {@link VertexFormat} that this appearance instance is compatible with.
  61804. * A geometry can have more vertex attributes and still be compatible - at a
  61805. * potential performance cost - but it can't have less.
  61806. *
  61807. * @memberof PerInstanceColorAppearance.prototype
  61808. *
  61809. * @type VertexFormat
  61810. * @readonly
  61811. */
  61812. vertexFormat : {
  61813. get : function() {
  61814. return this._vertexFormat;
  61815. }
  61816. },
  61817. /**
  61818. * When <code>true</code>, flat shading is used in the fragment shader,
  61819. * which means lighting is not taking into account.
  61820. *
  61821. * @memberof PerInstanceColorAppearance.prototype
  61822. *
  61823. * @type {Boolean}
  61824. * @readonly
  61825. *
  61826. * @default false
  61827. */
  61828. flat : {
  61829. get : function() {
  61830. return this._flat;
  61831. }
  61832. },
  61833. /**
  61834. * When <code>true</code>, the fragment shader flips the surface normal
  61835. * as needed to ensure that the normal faces the viewer to avoid
  61836. * dark spots. This is useful when both sides of a geometry should be
  61837. * shaded like {@link WallGeometry}.
  61838. *
  61839. * @memberof PerInstanceColorAppearance.prototype
  61840. *
  61841. * @type {Boolean}
  61842. * @readonly
  61843. *
  61844. * @default true
  61845. */
  61846. faceForward : {
  61847. get : function() {
  61848. return this._faceForward;
  61849. }
  61850. }
  61851. });
  61852. /**
  61853. * The {@link VertexFormat} that all {@link PerInstanceColorAppearance} instances
  61854. * are compatible with. This requires only <code>position</code> and <code>st</code>
  61855. * attributes.
  61856. *
  61857. * @type VertexFormat
  61858. *
  61859. * @constant
  61860. */
  61861. PerInstanceColorAppearance.VERTEX_FORMAT = VertexFormat.POSITION_AND_NORMAL;
  61862. /**
  61863. * The {@link VertexFormat} that all {@link PerInstanceColorAppearance} instances
  61864. * are compatible with when {@link PerInstanceColorAppearance#flat} is <code>false</code>.
  61865. * This requires only a <code>position</code> attribute.
  61866. *
  61867. * @type VertexFormat
  61868. *
  61869. * @constant
  61870. */
  61871. PerInstanceColorAppearance.FLAT_VERTEX_FORMAT = VertexFormat.POSITION_ONLY;
  61872. /**
  61873. * Procedurally creates the full GLSL fragment shader source. For {@link PerInstanceColorAppearance},
  61874. * this is derived from {@link PerInstanceColorAppearance#fragmentShaderSource}, {@link PerInstanceColorAppearance#flat},
  61875. * and {@link PerInstanceColorAppearance#faceForward}.
  61876. *
  61877. * @function
  61878. *
  61879. * @returns {String} The full GLSL fragment shader source.
  61880. */
  61881. PerInstanceColorAppearance.prototype.getFragmentShaderSource = Appearance.prototype.getFragmentShaderSource;
  61882. /**
  61883. * Determines if the geometry is translucent based on {@link PerInstanceColorAppearance#translucent}.
  61884. *
  61885. * @function
  61886. *
  61887. * @returns {Boolean} <code>true</code> if the appearance is translucent.
  61888. */
  61889. PerInstanceColorAppearance.prototype.isTranslucent = Appearance.prototype.isTranslucent;
  61890. /**
  61891. * Creates a render state. This is not the final render state instance; instead,
  61892. * it can contain a subset of render state properties identical to the render state
  61893. * created in the context.
  61894. *
  61895. * @function
  61896. *
  61897. * @returns {Object} The render state.
  61898. */
  61899. PerInstanceColorAppearance.prototype.getRenderState = Appearance.prototype.getRenderState;
  61900. return PerInstanceColorAppearance;
  61901. });
  61902. /*global define*/
  61903. define('Renderer/BufferUsage',[
  61904. '../Core/freezeObject',
  61905. '../Core/WebGLConstants'
  61906. ], function(
  61907. freezeObject,
  61908. WebGLConstants) {
  61909. 'use strict';
  61910. /**
  61911. * @private
  61912. */
  61913. var BufferUsage = {
  61914. STREAM_DRAW : WebGLConstants.STREAM_DRAW,
  61915. STATIC_DRAW : WebGLConstants.STATIC_DRAW,
  61916. DYNAMIC_DRAW : WebGLConstants.DYNAMIC_DRAW,
  61917. validate : function(bufferUsage) {
  61918. return ((bufferUsage === BufferUsage.STREAM_DRAW) ||
  61919. (bufferUsage === BufferUsage.STATIC_DRAW) ||
  61920. (bufferUsage === BufferUsage.DYNAMIC_DRAW));
  61921. }
  61922. };
  61923. return freezeObject(BufferUsage);
  61924. });
  61925. /*global define*/
  61926. define('Renderer/DrawCommand',[
  61927. '../Core/defaultValue',
  61928. '../Core/defined',
  61929. '../Core/defineProperties',
  61930. '../Core/PrimitiveType'
  61931. ], function(
  61932. defaultValue,
  61933. defined,
  61934. defineProperties,
  61935. PrimitiveType) {
  61936. 'use strict';
  61937. /**
  61938. * Represents a command to the renderer for drawing.
  61939. *
  61940. * @private
  61941. */
  61942. function DrawCommand(options) {
  61943. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  61944. this._boundingVolume = options.boundingVolume;
  61945. this._orientedBoundingBox = options.orientedBoundingBox;
  61946. this._cull = defaultValue(options.cull, true);
  61947. this._modelMatrix = options.modelMatrix;
  61948. this._primitiveType = defaultValue(options.primitiveType, PrimitiveType.TRIANGLES);
  61949. this._vertexArray = options.vertexArray;
  61950. this._count = options.count;
  61951. this._offset = defaultValue(options.offset, 0);
  61952. this._instanceCount = defaultValue(options.instanceCount, 0);
  61953. this._shaderProgram = options.shaderProgram;
  61954. this._uniformMap = options.uniformMap;
  61955. this._renderState = options.renderState;
  61956. this._framebuffer = options.framebuffer;
  61957. this._pass = options.pass;
  61958. this._executeInClosestFrustum = defaultValue(options.executeInClosestFrustum, false);
  61959. this._owner = options.owner;
  61960. this._debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false);
  61961. this._debugOverlappingFrustums = 0;
  61962. this._castShadows = defaultValue(options.castShadows, false);
  61963. this._receiveShadows = defaultValue(options.receiveShadows, false);
  61964. this.dirty = true;
  61965. this.lastDirtyTime = 0;
  61966. /**
  61967. * @private
  61968. */
  61969. this.derivedCommands = {};
  61970. }
  61971. defineProperties(DrawCommand.prototype, {
  61972. /**
  61973. * The bounding volume of the geometry in world space. This is used for culling and frustum selection.
  61974. * <p>
  61975. * For best rendering performance, use the tightest possible bounding volume. Although
  61976. * <code>undefined</code> is allowed, always try to provide a bounding volume to
  61977. * allow the tightest possible near and far planes to be computed for the scene, and
  61978. * minimize the number of frustums needed.
  61979. * </p>
  61980. *
  61981. * @memberof DrawCommand.prototype
  61982. * @type {Object}
  61983. * @default undefined
  61984. *
  61985. * @see DrawCommand#debugShowBoundingVolume
  61986. */
  61987. boundingVolume : {
  61988. get : function() {
  61989. return this._boundingVolume;
  61990. },
  61991. set : function(value) {
  61992. if (this._boundingVolume !== value) {
  61993. this._boundingVolume = value;
  61994. this.dirty = true;
  61995. }
  61996. }
  61997. },
  61998. /**
  61999. * The oriented bounding box of the geometry in world space. If this is defined, it is used instead of
  62000. * {@link DrawCommand#boundingVolume} for plane intersection testing.
  62001. *
  62002. * @memberof DrawCommand.prototype
  62003. * @type {OrientedBoundingBox}
  62004. * @default undefined
  62005. *
  62006. * @see DrawCommand#debugShowBoundingVolume
  62007. */
  62008. orientedBoundingBox : {
  62009. get : function() {
  62010. return this._orientedBoundingBox;
  62011. },
  62012. set : function(value) {
  62013. if (this._orientedBoundingBox !== value) {
  62014. this._orientedBoundingBox = value;
  62015. this.dirty = true;
  62016. }
  62017. }
  62018. },
  62019. /**
  62020. * When <code>true</code>, the renderer frustum and horizon culls the command based on its {@link DrawCommand#boundingVolume}.
  62021. * If the command was already culled, set this to <code>false</code> for a performance improvement.
  62022. *
  62023. * @memberof DrawCommand.prototype
  62024. * @type {Boolean}
  62025. * @default true
  62026. */
  62027. cull : {
  62028. get : function() {
  62029. return this._cull;
  62030. },
  62031. set : function(value) {
  62032. if (this._cull !== value) {
  62033. this._cull = value;
  62034. this.dirty = true;
  62035. }
  62036. }
  62037. },
  62038. /**
  62039. * The transformation from the geometry in model space to world space.
  62040. * <p>
  62041. * When <code>undefined</code>, the geometry is assumed to be defined in world space.
  62042. * </p>
  62043. *
  62044. * @memberof DrawCommand.prototype
  62045. * @type {Matrix4}
  62046. * @default undefined
  62047. */
  62048. modelMatrix : {
  62049. get : function() {
  62050. return this._modelMatrix;
  62051. },
  62052. set : function(value) {
  62053. if (this._modelMatrix !== value) {
  62054. this._modelMatrix = value;
  62055. this.dirty = true;
  62056. }
  62057. }
  62058. },
  62059. /**
  62060. * The type of geometry in the vertex array.
  62061. *
  62062. * @memberof DrawCommand.prototype
  62063. * @type {PrimitiveType}
  62064. * @default PrimitiveType.TRIANGLES
  62065. */
  62066. primitiveType : {
  62067. get : function() {
  62068. return this._primitiveType;
  62069. },
  62070. set : function(value) {
  62071. if (this._primitiveType !== value) {
  62072. this._primitiveType = value;
  62073. this.dirty = true;
  62074. }
  62075. }
  62076. },
  62077. /**
  62078. * The vertex array.
  62079. *
  62080. * @memberof DrawCommand.prototype
  62081. * @type {VertexArray}
  62082. * @default undefined
  62083. */
  62084. vertexArray : {
  62085. get : function() {
  62086. return this._vertexArray;
  62087. },
  62088. set : function(value) {
  62089. if (this._vertexArray !== value) {
  62090. this._vertexArray = value;
  62091. this.dirty = true;
  62092. }
  62093. }
  62094. },
  62095. /**
  62096. * The number of vertices to draw in the vertex array.
  62097. *
  62098. * @memberof DrawCommand.prototype
  62099. * @type {Number}
  62100. * @default undefined
  62101. */
  62102. count : {
  62103. get : function() {
  62104. return this._count;
  62105. },
  62106. set : function(value) {
  62107. if (this._count !== value) {
  62108. this._count = value;
  62109. this.dirty = true;
  62110. }
  62111. }
  62112. },
  62113. /**
  62114. * The offset to start drawing in the vertex array.
  62115. *
  62116. * @memberof DrawCommand.prototype
  62117. * @type {Number}
  62118. * @default 0
  62119. */
  62120. offset : {
  62121. get : function() {
  62122. return this._offset;
  62123. },
  62124. set : function(value) {
  62125. if (this._offset !== value) {
  62126. this._offset = value;
  62127. this.dirty = true;
  62128. }
  62129. }
  62130. },
  62131. /**
  62132. * The number of instances to draw.
  62133. *
  62134. * @memberof DrawCommand.prototype
  62135. * @type {Number}
  62136. * @default 0
  62137. */
  62138. instanceCount : {
  62139. get : function() {
  62140. return this._instanceCount;
  62141. },
  62142. set : function(value) {
  62143. if (this._instanceCount !== value) {
  62144. this._instanceCount = value;
  62145. this.dirty = true;
  62146. }
  62147. }
  62148. },
  62149. /**
  62150. * The shader program to apply.
  62151. *
  62152. * @memberof DrawCommand.prototype
  62153. * @type {ShaderProgram}
  62154. * @default undefined
  62155. */
  62156. shaderProgram : {
  62157. get : function() {
  62158. return this._shaderProgram;
  62159. },
  62160. set : function(value) {
  62161. if (this._shaderProgram !== value) {
  62162. this._shaderProgram = value;
  62163. this.dirty = true;
  62164. }
  62165. }
  62166. },
  62167. /**
  62168. * Whether this command should cast shadows when shadowing is enabled.
  62169. *
  62170. * @memberof DrawCommand.prototype
  62171. * @type {Boolean}
  62172. * @default false
  62173. */
  62174. castShadows : {
  62175. get : function() {
  62176. return this._castShadows;
  62177. },
  62178. set : function(value) {
  62179. if (this._castShadows !== value) {
  62180. this._castShadows = value;
  62181. this.dirty = true;
  62182. }
  62183. }
  62184. },
  62185. /**
  62186. * Whether this command should receive shadows when shadowing is enabled.
  62187. *
  62188. * @memberof DrawCommand.prototype
  62189. * @type {Boolean}
  62190. * @default false
  62191. */
  62192. receiveShadows : {
  62193. get : function() {
  62194. return this._receiveShadows;
  62195. },
  62196. set : function(value) {
  62197. if (this._receiveShadows !== value) {
  62198. this._receiveShadows = value;
  62199. this.dirty = true;
  62200. }
  62201. }
  62202. },
  62203. /**
  62204. * An object with functions whose names match the uniforms in the shader program
  62205. * and return values to set those uniforms.
  62206. *
  62207. * @memberof DrawCommand.prototype
  62208. * @type {Object}
  62209. * @default undefined
  62210. */
  62211. uniformMap : {
  62212. get : function() {
  62213. return this._uniformMap;
  62214. },
  62215. set : function(value) {
  62216. if (this._uniformMap !== value) {
  62217. this._uniformMap = value;
  62218. this.dirty = true;
  62219. }
  62220. }
  62221. },
  62222. /**
  62223. * The render state.
  62224. *
  62225. * @memberof DrawCommand.prototype
  62226. * @type {RenderState}
  62227. * @default undefined
  62228. */
  62229. renderState : {
  62230. get : function() {
  62231. return this._renderState;
  62232. },
  62233. set : function(value) {
  62234. if (this._renderState !== value) {
  62235. this._renderState = value;
  62236. this.dirty = true;
  62237. }
  62238. }
  62239. },
  62240. /**
  62241. * The framebuffer to draw to.
  62242. *
  62243. * @memberof DrawCommand.prototype
  62244. * @type {Framebuffer}
  62245. * @default undefined
  62246. */
  62247. framebuffer : {
  62248. get : function() {
  62249. return this._framebuffer;
  62250. },
  62251. set : function(value) {
  62252. if (this._framebuffer !== value) {
  62253. this._framebuffer = value;
  62254. this.dirty = true;
  62255. }
  62256. }
  62257. },
  62258. /**
  62259. * The pass when to render.
  62260. *
  62261. * @memberof DrawCommand.prototype
  62262. * @type {Pass}
  62263. * @default undefined
  62264. */
  62265. pass : {
  62266. get : function() {
  62267. return this._pass;
  62268. },
  62269. set : function(value) {
  62270. if (this._pass !== value) {
  62271. this._pass = value;
  62272. this.dirty = true;
  62273. }
  62274. }
  62275. },
  62276. /**
  62277. * Specifies if this command is only to be executed in the frustum closest
  62278. * to the eye containing the bounding volume. Defaults to <code>false</code>.
  62279. *
  62280. * @memberof DrawCommand.prototype
  62281. * @type {Boolean}
  62282. * @default false
  62283. */
  62284. executeInClosestFrustum : {
  62285. get : function() {
  62286. return this._executeInClosestFrustum;
  62287. },
  62288. set : function(value) {
  62289. if (this._executeInClosestFrustum !== value) {
  62290. this._executeInClosestFrustum = value;
  62291. this.dirty = true;
  62292. }
  62293. }
  62294. },
  62295. /**
  62296. * The object who created this command. This is useful for debugging command
  62297. * execution; it allows us to see who created a command when we only have a
  62298. * reference to the command, and can be used to selectively execute commands
  62299. * with {@link Scene#debugCommandFilter}.
  62300. *
  62301. * @memberof DrawCommand.prototype
  62302. * @type {Object}
  62303. * @default undefined
  62304. *
  62305. * @see Scene#debugCommandFilter
  62306. */
  62307. owner : {
  62308. get : function() {
  62309. return this._owner;
  62310. },
  62311. set : function(value) {
  62312. if (this._owner !== value) {
  62313. this._owner = value;
  62314. this.dirty = true;
  62315. }
  62316. }
  62317. },
  62318. /**
  62319. * This property is for debugging only; it is not for production use nor is it optimized.
  62320. * <p>
  62321. * Draws the {@link DrawCommand#boundingVolume} for this command, assuming it is a sphere, when the command executes.
  62322. * </p>
  62323. *
  62324. * @memberof DrawCommand.prototype
  62325. * @type {Boolean}
  62326. * @default false
  62327. *
  62328. * @see DrawCommand#boundingVolume
  62329. */
  62330. debugShowBoundingVolume : {
  62331. get : function() {
  62332. return this._debugShowBoundingVolume;
  62333. },
  62334. set : function(value) {
  62335. if (this._debugShowBoundingVolume !== value) {
  62336. this._debugShowBoundingVolume = value;
  62337. this.dirty = true;
  62338. }
  62339. }
  62340. },
  62341. /**
  62342. * Used to implement Scene.debugShowFrustums.
  62343. * @private
  62344. */
  62345. debugOverlappingFrustums : {
  62346. get : function() {
  62347. return this._debugOverlappingFrustums;
  62348. },
  62349. set : function(value) {
  62350. if (this._debugOverlappingFrustums !== value) {
  62351. this._debugOverlappingFrustums = value;
  62352. this.dirty = true;
  62353. }
  62354. }
  62355. }
  62356. });
  62357. /**
  62358. * @private
  62359. */
  62360. DrawCommand.shallowClone = function(command, result) {
  62361. if (!defined(command)) {
  62362. return undefined;
  62363. }
  62364. if (!defined(result)) {
  62365. result = new DrawCommand();
  62366. }
  62367. result._boundingVolume = command._boundingVolume;
  62368. result._orientedBoundingBox = command._orientedBoundingBox;
  62369. result._cull = command._cull;
  62370. result._modelMatrix = command._modelMatrix;
  62371. result._primitiveType = command._primitiveType;
  62372. result._vertexArray = command._vertexArray;
  62373. result._count = command._count;
  62374. result._offset = command._offset;
  62375. result._instanceCount = command._instanceCount;
  62376. result._shaderProgram = command._shaderProgram;
  62377. result._uniformMap = command._uniformMap;
  62378. result._renderState = command._renderState;
  62379. result._framebuffer = command._framebuffer;
  62380. result._pass = command._pass;
  62381. result._executeInClosestFrustum = command._executeInClosestFrustum;
  62382. result._owner = command._owner;
  62383. result._debugShowBoundingVolume = command._debugShowBoundingVolume;
  62384. result._debugOverlappingFrustums = command._debugOverlappingFrustums;
  62385. result._castShadows = command._castShadows;
  62386. result._receiveShadows = command._receiveShadows;
  62387. result.dirty = true;
  62388. result.lastDirtyTime = 0;
  62389. return result;
  62390. };
  62391. /**
  62392. * Executes the draw command.
  62393. *
  62394. * @param {Context} context The renderer context in which to draw.
  62395. * @param {PassState} [passState] The state for the current render pass.
  62396. */
  62397. DrawCommand.prototype.execute = function(context, passState) {
  62398. context.draw(this, passState);
  62399. };
  62400. return DrawCommand;
  62401. });
  62402. /*global define*/
  62403. define('Renderer/Pass',[
  62404. '../Core/freezeObject'
  62405. ], function(
  62406. freezeObject) {
  62407. 'use strict';
  62408. /**
  62409. * The render pass for a command.
  62410. *
  62411. * @private
  62412. */
  62413. var Pass = {
  62414. // If you add/modify/remove Pass constants, also change the automatic GLSL constants
  62415. // that start with 'czm_pass'
  62416. //
  62417. // Commands are executed in order by pass up to the translucent pass.
  62418. // Translucent geometry needs special handling (sorting/OIT). The compute pass
  62419. // is executed first and the overlay pass is executed last. Both are not sorted
  62420. // by frustum.
  62421. ENVIRONMENT : 0,
  62422. COMPUTE : 1,
  62423. GLOBE : 2,
  62424. GROUND : 3,
  62425. OPAQUE : 4,
  62426. TRANSLUCENT : 5,
  62427. OVERLAY : 6,
  62428. NUMBER_OF_PASSES : 7
  62429. };
  62430. return freezeObject(Pass);
  62431. });
  62432. /*global define*/
  62433. define('Renderer/RenderState',[
  62434. '../Core/BoundingRectangle',
  62435. '../Core/Color',
  62436. '../Core/defaultValue',
  62437. '../Core/defined',
  62438. '../Core/DeveloperError',
  62439. '../Core/WebGLConstants',
  62440. '../Core/WindingOrder',
  62441. './ContextLimits'
  62442. ], function(
  62443. BoundingRectangle,
  62444. Color,
  62445. defaultValue,
  62446. defined,
  62447. DeveloperError,
  62448. WebGLConstants,
  62449. WindingOrder,
  62450. ContextLimits) {
  62451. 'use strict';
  62452. function validateBlendEquation(blendEquation) {
  62453. return ((blendEquation === WebGLConstants.FUNC_ADD) ||
  62454. (blendEquation === WebGLConstants.FUNC_SUBTRACT) ||
  62455. (blendEquation === WebGLConstants.FUNC_REVERSE_SUBTRACT));
  62456. }
  62457. function validateBlendFunction(blendFunction) {
  62458. return ((blendFunction === WebGLConstants.ZERO) ||
  62459. (blendFunction === WebGLConstants.ONE) ||
  62460. (blendFunction === WebGLConstants.SRC_COLOR) ||
  62461. (blendFunction === WebGLConstants.ONE_MINUS_SRC_COLOR) ||
  62462. (blendFunction === WebGLConstants.DST_COLOR) ||
  62463. (blendFunction === WebGLConstants.ONE_MINUS_DST_COLOR) ||
  62464. (blendFunction === WebGLConstants.SRC_ALPHA) ||
  62465. (blendFunction === WebGLConstants.ONE_MINUS_SRC_ALPHA) ||
  62466. (blendFunction === WebGLConstants.DST_ALPHA) ||
  62467. (blendFunction === WebGLConstants.ONE_MINUS_DST_ALPHA) ||
  62468. (blendFunction === WebGLConstants.CONSTANT_COLOR) ||
  62469. (blendFunction === WebGLConstants.ONE_MINUS_CONSTANT_COLOR) ||
  62470. (blendFunction === WebGLConstants.CONSTANT_ALPHA) ||
  62471. (blendFunction === WebGLConstants.ONE_MINUS_CONSTANT_ALPHA) ||
  62472. (blendFunction === WebGLConstants.SRC_ALPHA_SATURATE));
  62473. }
  62474. function validateCullFace(cullFace) {
  62475. return ((cullFace === WebGLConstants.FRONT) ||
  62476. (cullFace === WebGLConstants.BACK) ||
  62477. (cullFace === WebGLConstants.FRONT_AND_BACK));
  62478. }
  62479. function validateDepthFunction(depthFunction) {
  62480. return ((depthFunction === WebGLConstants.NEVER) ||
  62481. (depthFunction === WebGLConstants.LESS) ||
  62482. (depthFunction === WebGLConstants.EQUAL) ||
  62483. (depthFunction === WebGLConstants.LEQUAL) ||
  62484. (depthFunction === WebGLConstants.GREATER) ||
  62485. (depthFunction === WebGLConstants.NOTEQUAL) ||
  62486. (depthFunction === WebGLConstants.GEQUAL) ||
  62487. (depthFunction === WebGLConstants.ALWAYS));
  62488. }
  62489. function validateStencilFunction (stencilFunction) {
  62490. return ((stencilFunction === WebGLConstants.NEVER) ||
  62491. (stencilFunction === WebGLConstants.LESS) ||
  62492. (stencilFunction === WebGLConstants.EQUAL) ||
  62493. (stencilFunction === WebGLConstants.LEQUAL) ||
  62494. (stencilFunction === WebGLConstants.GREATER) ||
  62495. (stencilFunction === WebGLConstants.NOTEQUAL) ||
  62496. (stencilFunction === WebGLConstants.GEQUAL) ||
  62497. (stencilFunction === WebGLConstants.ALWAYS));
  62498. }
  62499. function validateStencilOperation(stencilOperation) {
  62500. return ((stencilOperation === WebGLConstants.ZERO) ||
  62501. (stencilOperation === WebGLConstants.KEEP) ||
  62502. (stencilOperation === WebGLConstants.REPLACE) ||
  62503. (stencilOperation === WebGLConstants.INCR) ||
  62504. (stencilOperation === WebGLConstants.DECR) ||
  62505. (stencilOperation === WebGLConstants.INVERT) ||
  62506. (stencilOperation === WebGLConstants.INCR_WRAP) ||
  62507. (stencilOperation === WebGLConstants.DECR_WRAP));
  62508. }
  62509. /**
  62510. * @private
  62511. */
  62512. function RenderState(renderState) {
  62513. var rs = defaultValue(renderState, {});
  62514. var cull = defaultValue(rs.cull, {});
  62515. var polygonOffset = defaultValue(rs.polygonOffset, {});
  62516. var scissorTest = defaultValue(rs.scissorTest, {});
  62517. var scissorTestRectangle = defaultValue(scissorTest.rectangle, {});
  62518. var depthRange = defaultValue(rs.depthRange, {});
  62519. var depthTest = defaultValue(rs.depthTest, {});
  62520. var colorMask = defaultValue(rs.colorMask, {});
  62521. var blending = defaultValue(rs.blending, {});
  62522. var blendingColor = defaultValue(blending.color, {});
  62523. var stencilTest = defaultValue(rs.stencilTest, {});
  62524. var stencilTestFrontOperation = defaultValue(stencilTest.frontOperation, {});
  62525. var stencilTestBackOperation = defaultValue(stencilTest.backOperation, {});
  62526. var sampleCoverage = defaultValue(rs.sampleCoverage, {});
  62527. var viewport = rs.viewport;
  62528. this.frontFace = defaultValue(rs.frontFace, WindingOrder.COUNTER_CLOCKWISE);
  62529. this.cull = {
  62530. enabled : defaultValue(cull.enabled, false),
  62531. face : defaultValue(cull.face, WebGLConstants.BACK)
  62532. };
  62533. this.lineWidth = defaultValue(rs.lineWidth, 1.0);
  62534. this.polygonOffset = {
  62535. enabled : defaultValue(polygonOffset.enabled, false),
  62536. factor : defaultValue(polygonOffset.factor, 0),
  62537. units : defaultValue(polygonOffset.units, 0)
  62538. };
  62539. this.scissorTest = {
  62540. enabled : defaultValue(scissorTest.enabled, false),
  62541. rectangle : BoundingRectangle.clone(scissorTestRectangle)
  62542. };
  62543. this.depthRange = {
  62544. near : defaultValue(depthRange.near, 0),
  62545. far : defaultValue(depthRange.far, 1)
  62546. };
  62547. this.depthTest = {
  62548. enabled : defaultValue(depthTest.enabled, false),
  62549. func : defaultValue(depthTest.func, WebGLConstants.LESS) // func, because function is a JavaScript keyword
  62550. };
  62551. this.colorMask = {
  62552. red : defaultValue(colorMask.red, true),
  62553. green : defaultValue(colorMask.green, true),
  62554. blue : defaultValue(colorMask.blue, true),
  62555. alpha : defaultValue(colorMask.alpha, true)
  62556. };
  62557. this.depthMask = defaultValue(rs.depthMask, true);
  62558. this.stencilMask = defaultValue(rs.stencilMask, ~0);
  62559. this.blending = {
  62560. enabled : defaultValue(blending.enabled, false),
  62561. color : new Color(
  62562. defaultValue(blendingColor.red, 0.0),
  62563. defaultValue(blendingColor.green, 0.0),
  62564. defaultValue(blendingColor.blue, 0.0),
  62565. defaultValue(blendingColor.alpha, 0.0)
  62566. ),
  62567. equationRgb : defaultValue(blending.equationRgb, WebGLConstants.FUNC_ADD),
  62568. equationAlpha : defaultValue(blending.equationAlpha, WebGLConstants.FUNC_ADD),
  62569. functionSourceRgb : defaultValue(blending.functionSourceRgb, WebGLConstants.ONE),
  62570. functionSourceAlpha : defaultValue(blending.functionSourceAlpha, WebGLConstants.ONE),
  62571. functionDestinationRgb : defaultValue(blending.functionDestinationRgb, WebGLConstants.ZERO),
  62572. functionDestinationAlpha : defaultValue(blending.functionDestinationAlpha, WebGLConstants.ZERO)
  62573. };
  62574. this.stencilTest = {
  62575. enabled : defaultValue(stencilTest.enabled, false),
  62576. frontFunction : defaultValue(stencilTest.frontFunction, WebGLConstants.ALWAYS),
  62577. backFunction : defaultValue(stencilTest.backFunction, WebGLConstants.ALWAYS),
  62578. reference : defaultValue(stencilTest.reference, 0),
  62579. mask : defaultValue(stencilTest.mask, ~0),
  62580. frontOperation : {
  62581. fail : defaultValue(stencilTestFrontOperation.fail, WebGLConstants.KEEP),
  62582. zFail : defaultValue(stencilTestFrontOperation.zFail, WebGLConstants.KEEP),
  62583. zPass : defaultValue(stencilTestFrontOperation.zPass, WebGLConstants.KEEP)
  62584. },
  62585. backOperation : {
  62586. fail : defaultValue(stencilTestBackOperation.fail, WebGLConstants.KEEP),
  62587. zFail : defaultValue(stencilTestBackOperation.zFail, WebGLConstants.KEEP),
  62588. zPass : defaultValue(stencilTestBackOperation.zPass, WebGLConstants.KEEP)
  62589. }
  62590. };
  62591. this.sampleCoverage = {
  62592. enabled : defaultValue(sampleCoverage.enabled, false),
  62593. value : defaultValue(sampleCoverage.value, 1.0),
  62594. invert : defaultValue(sampleCoverage.invert, false)
  62595. };
  62596. this.viewport = (defined(viewport)) ? new BoundingRectangle(viewport.x, viewport.y, viewport.width, viewport.height) : undefined;
  62597. if ((this.lineWidth < ContextLimits.minimumAliasedLineWidth) ||
  62598. (this.lineWidth > ContextLimits.maximumAliasedLineWidth)) {
  62599. throw new DeveloperError('renderState.lineWidth is out of range. Check minimumAliasedLineWidth and maximumAliasedLineWidth.');
  62600. }
  62601. if (!WindingOrder.validate(this.frontFace)) {
  62602. throw new DeveloperError('Invalid renderState.frontFace.');
  62603. }
  62604. if (!validateCullFace(this.cull.face)) {
  62605. throw new DeveloperError('Invalid renderState.cull.face.');
  62606. }
  62607. if ((this.scissorTest.rectangle.width < 0) ||
  62608. (this.scissorTest.rectangle.height < 0)) {
  62609. throw new DeveloperError('renderState.scissorTest.rectangle.width and renderState.scissorTest.rectangle.height must be greater than or equal to zero.');
  62610. }
  62611. if (this.depthRange.near > this.depthRange.far) {
  62612. // WebGL specific - not an error in GL ES
  62613. throw new DeveloperError('renderState.depthRange.near can not be greater than renderState.depthRange.far.');
  62614. }
  62615. if (this.depthRange.near < 0) {
  62616. // Would be clamped by GL
  62617. throw new DeveloperError('renderState.depthRange.near must be greater than or equal to zero.');
  62618. }
  62619. if (this.depthRange.far > 1) {
  62620. // Would be clamped by GL
  62621. throw new DeveloperError('renderState.depthRange.far must be less than or equal to one.');
  62622. }
  62623. if (!validateDepthFunction(this.depthTest.func)) {
  62624. throw new DeveloperError('Invalid renderState.depthTest.func.');
  62625. }
  62626. if ((this.blending.color.red < 0.0) || (this.blending.color.red > 1.0) ||
  62627. (this.blending.color.green < 0.0) || (this.blending.color.green > 1.0) ||
  62628. (this.blending.color.blue < 0.0) || (this.blending.color.blue > 1.0) ||
  62629. (this.blending.color.alpha < 0.0) || (this.blending.color.alpha > 1.0)) {
  62630. // Would be clamped by GL
  62631. throw new DeveloperError('renderState.blending.color components must be greater than or equal to zero and less than or equal to one.');
  62632. }
  62633. if (!validateBlendEquation(this.blending.equationRgb)) {
  62634. throw new DeveloperError('Invalid renderState.blending.equationRgb.');
  62635. }
  62636. if (!validateBlendEquation(this.blending.equationAlpha)) {
  62637. throw new DeveloperError('Invalid renderState.blending.equationAlpha.');
  62638. }
  62639. if (!validateBlendFunction(this.blending.functionSourceRgb)) {
  62640. throw new DeveloperError('Invalid renderState.blending.functionSourceRgb.');
  62641. }
  62642. if (!validateBlendFunction(this.blending.functionSourceAlpha)) {
  62643. throw new DeveloperError('Invalid renderState.blending.functionSourceAlpha.');
  62644. }
  62645. if (!validateBlendFunction(this.blending.functionDestinationRgb)) {
  62646. throw new DeveloperError('Invalid renderState.blending.functionDestinationRgb.');
  62647. }
  62648. if (!validateBlendFunction(this.blending.functionDestinationAlpha)) {
  62649. throw new DeveloperError('Invalid renderState.blending.functionDestinationAlpha.');
  62650. }
  62651. if (!validateStencilFunction(this.stencilTest.frontFunction)) {
  62652. throw new DeveloperError('Invalid renderState.stencilTest.frontFunction.');
  62653. }
  62654. if (!validateStencilFunction(this.stencilTest.backFunction)) {
  62655. throw new DeveloperError('Invalid renderState.stencilTest.backFunction.');
  62656. }
  62657. if (!validateStencilOperation(this.stencilTest.frontOperation.fail)) {
  62658. throw new DeveloperError('Invalid renderState.stencilTest.frontOperation.fail.');
  62659. }
  62660. if (!validateStencilOperation(this.stencilTest.frontOperation.zFail)) {
  62661. throw new DeveloperError('Invalid renderState.stencilTest.frontOperation.zFail.');
  62662. }
  62663. if (!validateStencilOperation(this.stencilTest.frontOperation.zPass)) {
  62664. throw new DeveloperError('Invalid renderState.stencilTest.frontOperation.zPass.');
  62665. }
  62666. if (!validateStencilOperation(this.stencilTest.backOperation.fail)) {
  62667. throw new DeveloperError('Invalid renderState.stencilTest.backOperation.fail.');
  62668. }
  62669. if (!validateStencilOperation(this.stencilTest.backOperation.zFail)) {
  62670. throw new DeveloperError('Invalid renderState.stencilTest.backOperation.zFail.');
  62671. }
  62672. if (!validateStencilOperation(this.stencilTest.backOperation.zPass)) {
  62673. throw new DeveloperError('Invalid renderState.stencilTest.backOperation.zPass.');
  62674. }
  62675. if (defined(this.viewport)) {
  62676. if (this.viewport.width < 0) {
  62677. throw new DeveloperError('renderState.viewport.width must be greater than or equal to zero.');
  62678. }
  62679. if (this.viewport.height < 0) {
  62680. throw new DeveloperError('renderState.viewport.height must be greater than or equal to zero.');
  62681. }
  62682. if (this.viewport.width > ContextLimits.maximumViewportWidth) {
  62683. throw new DeveloperError('renderState.viewport.width must be less than or equal to the maximum viewport width (' + ContextLimits.maximumViewportWidth.toString() + '). Check maximumViewportWidth.');
  62684. }
  62685. if (this.viewport.height > ContextLimits.maximumViewportHeight) {
  62686. throw new DeveloperError('renderState.viewport.height must be less than or equal to the maximum viewport height (' + ContextLimits.maximumViewportHeight.toString() + '). Check maximumViewportHeight.');
  62687. }
  62688. }
  62689. this.id = 0;
  62690. this._applyFunctions = [];
  62691. }
  62692. var nextRenderStateId = 0;
  62693. var renderStateCache = {};
  62694. /**
  62695. * Validates and then finds or creates an immutable render state, which defines the pipeline
  62696. * state for a {@link DrawCommand} or {@link ClearCommand}. All inputs states are optional. Omitted states
  62697. * use the defaults shown in the example below.
  62698. *
  62699. * @param {Object} [renderState] The states defining the render state as shown in the example below.
  62700. *
  62701. * @exception {RuntimeError} renderState.lineWidth is out of range.
  62702. * @exception {DeveloperError} Invalid renderState.frontFace.
  62703. * @exception {DeveloperError} Invalid renderState.cull.face.
  62704. * @exception {DeveloperError} scissorTest.rectangle.width and scissorTest.rectangle.height must be greater than or equal to zero.
  62705. * @exception {DeveloperError} renderState.depthRange.near can't be greater than renderState.depthRange.far.
  62706. * @exception {DeveloperError} renderState.depthRange.near must be greater than or equal to zero.
  62707. * @exception {DeveloperError} renderState.depthRange.far must be less than or equal to zero.
  62708. * @exception {DeveloperError} Invalid renderState.depthTest.func.
  62709. * @exception {DeveloperError} renderState.blending.color components must be greater than or equal to zero and less than or equal to one
  62710. * @exception {DeveloperError} Invalid renderState.blending.equationRgb.
  62711. * @exception {DeveloperError} Invalid renderState.blending.equationAlpha.
  62712. * @exception {DeveloperError} Invalid renderState.blending.functionSourceRgb.
  62713. * @exception {DeveloperError} Invalid renderState.blending.functionSourceAlpha.
  62714. * @exception {DeveloperError} Invalid renderState.blending.functionDestinationRgb.
  62715. * @exception {DeveloperError} Invalid renderState.blending.functionDestinationAlpha.
  62716. * @exception {DeveloperError} Invalid renderState.stencilTest.frontFunction.
  62717. * @exception {DeveloperError} Invalid renderState.stencilTest.backFunction.
  62718. * @exception {DeveloperError} Invalid renderState.stencilTest.frontOperation.fail.
  62719. * @exception {DeveloperError} Invalid renderState.stencilTest.frontOperation.zFail.
  62720. * @exception {DeveloperError} Invalid renderState.stencilTest.frontOperation.zPass.
  62721. * @exception {DeveloperError} Invalid renderState.stencilTest.backOperation.fail.
  62722. * @exception {DeveloperError} Invalid renderState.stencilTest.backOperation.zFail.
  62723. * @exception {DeveloperError} Invalid renderState.stencilTest.backOperation.zPass.
  62724. * @exception {DeveloperError} renderState.viewport.width must be greater than or equal to zero.
  62725. * @exception {DeveloperError} renderState.viewport.width must be less than or equal to the maximum viewport width.
  62726. * @exception {DeveloperError} renderState.viewport.height must be greater than or equal to zero.
  62727. * @exception {DeveloperError} renderState.viewport.height must be less than or equal to the maximum viewport height.
  62728. *
  62729. *
  62730. * @example
  62731. * var defaults = {
  62732. * frontFace : WindingOrder.COUNTER_CLOCKWISE,
  62733. * cull : {
  62734. * enabled : false,
  62735. * face : CullFace.BACK
  62736. * },
  62737. * lineWidth : 1,
  62738. * polygonOffset : {
  62739. * enabled : false,
  62740. * factor : 0,
  62741. * units : 0
  62742. * },
  62743. * scissorTest : {
  62744. * enabled : false,
  62745. * rectangle : {
  62746. * x : 0,
  62747. * y : 0,
  62748. * width : 0,
  62749. * height : 0
  62750. * }
  62751. * },
  62752. * depthRange : {
  62753. * near : 0,
  62754. * far : 1
  62755. * },
  62756. * depthTest : {
  62757. * enabled : false,
  62758. * func : DepthFunction.LESS
  62759. * },
  62760. * colorMask : {
  62761. * red : true,
  62762. * green : true,
  62763. * blue : true,
  62764. * alpha : true
  62765. * },
  62766. * depthMask : true,
  62767. * stencilMask : ~0,
  62768. * blending : {
  62769. * enabled : false,
  62770. * color : {
  62771. * red : 0.0,
  62772. * green : 0.0,
  62773. * blue : 0.0,
  62774. * alpha : 0.0
  62775. * },
  62776. * equationRgb : BlendEquation.ADD,
  62777. * equationAlpha : BlendEquation.ADD,
  62778. * functionSourceRgb : BlendFunction.ONE,
  62779. * functionSourceAlpha : BlendFunction.ONE,
  62780. * functionDestinationRgb : BlendFunction.ZERO,
  62781. * functionDestinationAlpha : BlendFunction.ZERO
  62782. * },
  62783. * stencilTest : {
  62784. * enabled : false,
  62785. * frontFunction : StencilFunction.ALWAYS,
  62786. * backFunction : StencilFunction.ALWAYS,
  62787. * reference : 0,
  62788. * mask : ~0,
  62789. * frontOperation : {
  62790. * fail : StencilOperation.KEEP,
  62791. * zFail : StencilOperation.KEEP,
  62792. * zPass : StencilOperation.KEEP
  62793. * },
  62794. * backOperation : {
  62795. * fail : StencilOperation.KEEP,
  62796. * zFail : StencilOperation.KEEP,
  62797. * zPass : StencilOperation.KEEP
  62798. * }
  62799. * },
  62800. * sampleCoverage : {
  62801. * enabled : false,
  62802. * value : 1.0,
  62803. * invert : false
  62804. * }
  62805. * };
  62806. *
  62807. * var rs = RenderState.fromCache(defaults);
  62808. *
  62809. * @see DrawCommand
  62810. * @see ClearCommand
  62811. *
  62812. * @private
  62813. */
  62814. RenderState.fromCache = function(renderState) {
  62815. var partialKey = JSON.stringify(renderState);
  62816. var cachedState = renderStateCache[partialKey];
  62817. if (defined(cachedState)) {
  62818. ++cachedState.referenceCount;
  62819. return cachedState.state;
  62820. }
  62821. // Cache miss. Fully define render state and try again.
  62822. var states = new RenderState(renderState);
  62823. var fullKey = JSON.stringify(states);
  62824. cachedState = renderStateCache[fullKey];
  62825. if (!defined(cachedState)) {
  62826. states.id = nextRenderStateId++;
  62827. cachedState = {
  62828. referenceCount : 0,
  62829. state : states
  62830. };
  62831. // Cache full render state. Multiple partially defined render states may map to this.
  62832. renderStateCache[fullKey] = cachedState;
  62833. }
  62834. ++cachedState.referenceCount;
  62835. // Cache partial render state so we can skip validation on a cache hit for a partially defined render state
  62836. renderStateCache[partialKey] = {
  62837. referenceCount : 1,
  62838. state : cachedState.state
  62839. };
  62840. return cachedState.state;
  62841. };
  62842. /**
  62843. * @private
  62844. */
  62845. RenderState.removeFromCache = function(renderState) {
  62846. var states = new RenderState(renderState);
  62847. var fullKey = JSON.stringify(states);
  62848. var fullCachedState = renderStateCache[fullKey];
  62849. // decrement partial key reference count
  62850. var partialKey = JSON.stringify(renderState);
  62851. var cachedState = renderStateCache[partialKey];
  62852. if (defined(cachedState)) {
  62853. --cachedState.referenceCount;
  62854. if (cachedState.referenceCount === 0) {
  62855. // remove partial key
  62856. delete renderStateCache[partialKey];
  62857. // decrement full key reference count
  62858. if (defined(fullCachedState)) {
  62859. --fullCachedState.referenceCount;
  62860. }
  62861. }
  62862. }
  62863. // remove full key if reference count is zero
  62864. if (defined(fullCachedState) && (fullCachedState.referenceCount === 0)) {
  62865. delete renderStateCache[fullKey];
  62866. }
  62867. };
  62868. /**
  62869. * This function is for testing purposes only.
  62870. * @private
  62871. */
  62872. RenderState.getCache = function() {
  62873. return renderStateCache;
  62874. };
  62875. /**
  62876. * This function is for testing purposes only.
  62877. * @private
  62878. */
  62879. RenderState.clearCache = function() {
  62880. renderStateCache = {};
  62881. };
  62882. function enableOrDisable(gl, glEnum, enable) {
  62883. if (enable) {
  62884. gl.enable(glEnum);
  62885. } else {
  62886. gl.disable(glEnum);
  62887. }
  62888. }
  62889. function applyFrontFace(gl, renderState) {
  62890. gl.frontFace(renderState.frontFace);
  62891. }
  62892. function applyCull(gl, renderState) {
  62893. var cull = renderState.cull;
  62894. var enabled = cull.enabled;
  62895. enableOrDisable(gl, gl.CULL_FACE, enabled);
  62896. if (enabled) {
  62897. gl.cullFace(cull.face);
  62898. }
  62899. }
  62900. function applyLineWidth(gl, renderState) {
  62901. gl.lineWidth(renderState.lineWidth);
  62902. }
  62903. function applyPolygonOffset(gl, renderState) {
  62904. var polygonOffset = renderState.polygonOffset;
  62905. var enabled = polygonOffset.enabled;
  62906. enableOrDisable(gl, gl.POLYGON_OFFSET_FILL, enabled);
  62907. if (enabled) {
  62908. gl.polygonOffset(polygonOffset.factor, polygonOffset.units);
  62909. }
  62910. }
  62911. function applyScissorTest(gl, renderState, passState) {
  62912. var scissorTest = renderState.scissorTest;
  62913. var enabled = (defined(passState.scissorTest)) ? passState.scissorTest.enabled : scissorTest.enabled;
  62914. enableOrDisable(gl, gl.SCISSOR_TEST, enabled);
  62915. if (enabled) {
  62916. var rectangle = (defined(passState.scissorTest)) ? passState.scissorTest.rectangle : scissorTest.rectangle;
  62917. gl.scissor(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
  62918. }
  62919. }
  62920. function applyDepthRange(gl, renderState) {
  62921. var depthRange = renderState.depthRange;
  62922. gl.depthRange(depthRange.near, depthRange.far);
  62923. }
  62924. function applyDepthTest(gl, renderState) {
  62925. var depthTest = renderState.depthTest;
  62926. var enabled = depthTest.enabled;
  62927. enableOrDisable(gl, gl.DEPTH_TEST, enabled);
  62928. if (enabled) {
  62929. gl.depthFunc(depthTest.func);
  62930. }
  62931. }
  62932. function applyColorMask(gl, renderState) {
  62933. var colorMask = renderState.colorMask;
  62934. gl.colorMask(colorMask.red, colorMask.green, colorMask.blue, colorMask.alpha);
  62935. }
  62936. function applyDepthMask(gl, renderState) {
  62937. gl.depthMask(renderState.depthMask);
  62938. }
  62939. function applyStencilMask(gl, renderState) {
  62940. gl.stencilMask(renderState.stencilMask);
  62941. }
  62942. function applyBlendingColor(gl, color) {
  62943. gl.blendColor(color.red, color.green, color.blue, color.alpha);
  62944. }
  62945. function applyBlending(gl, renderState, passState) {
  62946. var blending = renderState.blending;
  62947. var enabled = (defined(passState.blendingEnabled)) ? passState.blendingEnabled : blending.enabled;
  62948. enableOrDisable(gl, gl.BLEND, enabled);
  62949. if (enabled) {
  62950. applyBlendingColor(gl, blending.color);
  62951. gl.blendEquationSeparate(blending.equationRgb, blending.equationAlpha);
  62952. gl.blendFuncSeparate(blending.functionSourceRgb, blending.functionDestinationRgb, blending.functionSourceAlpha, blending.functionDestinationAlpha);
  62953. }
  62954. }
  62955. function applyStencilTest(gl, renderState) {
  62956. var stencilTest = renderState.stencilTest;
  62957. var enabled = stencilTest.enabled;
  62958. enableOrDisable(gl, gl.STENCIL_TEST, enabled);
  62959. if (enabled) {
  62960. var frontFunction = stencilTest.frontFunction;
  62961. var backFunction = stencilTest.backFunction;
  62962. var reference = stencilTest.reference;
  62963. var mask = stencilTest.mask;
  62964. // Section 6.8 of the WebGL spec requires the reference and masks to be the same for
  62965. // front- and back-face tests. This call prevents invalid operation errors when calling
  62966. // stencilFuncSeparate on Firefox. Perhaps they should delay validation to avoid requiring this.
  62967. gl.stencilFunc(frontFunction, reference, mask);
  62968. gl.stencilFuncSeparate(gl.BACK, backFunction, reference, mask);
  62969. gl.stencilFuncSeparate(gl.FRONT, frontFunction, reference, mask);
  62970. var frontOperation = stencilTest.frontOperation;
  62971. var frontOperationFail = frontOperation.fail;
  62972. var frontOperationZFail = frontOperation.zFail;
  62973. var frontOperationZPass = frontOperation.zPass;
  62974. gl.stencilOpSeparate(gl.FRONT, frontOperationFail, frontOperationZFail, frontOperationZPass);
  62975. var backOperation = stencilTest.backOperation;
  62976. var backOperationFail = backOperation.fail;
  62977. var backOperationZFail = backOperation.zFail;
  62978. var backOperationZPass = backOperation.zPass;
  62979. gl.stencilOpSeparate(gl.BACK, backOperationFail, backOperationZFail, backOperationZPass);
  62980. }
  62981. }
  62982. function applySampleCoverage(gl, renderState) {
  62983. var sampleCoverage = renderState.sampleCoverage;
  62984. var enabled = sampleCoverage.enabled;
  62985. enableOrDisable(gl, gl.SAMPLE_COVERAGE, enabled);
  62986. if (enabled) {
  62987. gl.sampleCoverage(sampleCoverage.value, sampleCoverage.invert);
  62988. }
  62989. }
  62990. var scratchViewport = new BoundingRectangle();
  62991. function applyViewport(gl, renderState, passState) {
  62992. var viewport = defaultValue(renderState.viewport, passState.viewport);
  62993. if (!defined(viewport)) {
  62994. viewport = scratchViewport;
  62995. viewport.width = passState.context.drawingBufferWidth;
  62996. viewport.height = passState.context.drawingBufferHeight;
  62997. }
  62998. passState.context.uniformState.viewport = viewport;
  62999. gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
  63000. }
  63001. RenderState.apply = function(gl, renderState, passState) {
  63002. applyFrontFace(gl, renderState);
  63003. applyCull(gl, renderState);
  63004. applyLineWidth(gl, renderState);
  63005. applyPolygonOffset(gl, renderState);
  63006. applyDepthRange(gl, renderState);
  63007. applyDepthTest(gl, renderState);
  63008. applyColorMask(gl, renderState);
  63009. applyDepthMask(gl, renderState);
  63010. applyStencilMask(gl, renderState);
  63011. applyStencilTest(gl, renderState);
  63012. applySampleCoverage(gl, renderState);
  63013. applyScissorTest(gl, renderState, passState);
  63014. applyBlending(gl, renderState, passState);
  63015. applyViewport(gl, renderState, passState);
  63016. };
  63017. function createFuncs(previousState, nextState) {
  63018. var funcs = [];
  63019. if (previousState.frontFace !== nextState.frontFace) {
  63020. funcs.push(applyFrontFace);
  63021. }
  63022. if ((previousState.cull.enabled !== nextState.cull.enabled) || (previousState.cull.face !== nextState.cull.face)) {
  63023. funcs.push(applyCull);
  63024. }
  63025. if (previousState.lineWidth !== nextState.lineWidth) {
  63026. funcs.push(applyLineWidth);
  63027. }
  63028. if ((previousState.polygonOffset.enabled !== nextState.polygonOffset.enabled) ||
  63029. (previousState.polygonOffset.factor !== nextState.polygonOffset.factor) ||
  63030. (previousState.polygonOffset.units !== nextState.polygonOffset.units)) {
  63031. funcs.push(applyPolygonOffset);
  63032. }
  63033. if ((previousState.depthRange.near !== nextState.depthRange.near) || (previousState.depthRange.far !== nextState.depthRange.far)) {
  63034. funcs.push(applyDepthRange);
  63035. }
  63036. if ((previousState.depthTest.enabled !== nextState.depthTest.enabled) || (previousState.depthTest.func !== nextState.depthTest.func)) {
  63037. funcs.push(applyDepthTest);
  63038. }
  63039. if ((previousState.colorMask.red !== nextState.colorMask.red) ||
  63040. (previousState.colorMask.green !== nextState.colorMask.green) ||
  63041. (previousState.colorMask.blue !== nextState.colorMask.blue) ||
  63042. (previousState.colorMask.alpha !== nextState.colorMask.alpha)) {
  63043. funcs.push(applyColorMask);
  63044. }
  63045. if (previousState.depthMask !== nextState.depthMask) {
  63046. funcs.push(applyDepthMask);
  63047. }
  63048. if (previousState.stencilMask !== nextState.stencilMask) {
  63049. funcs.push(applyStencilMask);
  63050. }
  63051. if ((previousState.stencilTest.enabled !== nextState.stencilTest.enabled) ||
  63052. (previousState.stencilTest.frontFunction !== nextState.stencilTest.frontFunction) ||
  63053. (previousState.stencilTest.backFunction !== nextState.stencilTest.backFunction) ||
  63054. (previousState.stencilTest.reference !== nextState.stencilTest.reference) ||
  63055. (previousState.stencilTest.mask !== nextState.stencilTest.mask) ||
  63056. (previousState.stencilTest.frontOperation.fail !== nextState.stencilTest.frontOperation.fail) ||
  63057. (previousState.stencilTest.frontOperation.zFail !== nextState.stencilTest.frontOperation.zFail) ||
  63058. (previousState.stencilTest.backOperation.fail !== nextState.stencilTest.backOperation.fail) ||
  63059. (previousState.stencilTest.backOperation.zFail !== nextState.stencilTest.backOperation.zFail) ||
  63060. (previousState.stencilTest.backOperation.zPass !== nextState.stencilTest.backOperation.zPass)) {
  63061. funcs.push(applyStencilTest);
  63062. }
  63063. if ((previousState.sampleCoverage.enabled !== nextState.sampleCoverage.enabled) ||
  63064. (previousState.sampleCoverage.value !== nextState.sampleCoverage.value) ||
  63065. (previousState.sampleCoverage.invert !== nextState.sampleCoverage.invert)) {
  63066. funcs.push(applySampleCoverage);
  63067. }
  63068. return funcs;
  63069. }
  63070. RenderState.partialApply = function(gl, previousRenderState, renderState, previousPassState, passState, clear) {
  63071. if (previousRenderState !== renderState) {
  63072. // When a new render state is applied, instead of making WebGL calls for all the states or first
  63073. // comparing the states one-by-one with the previous state (basically a linear search), we take
  63074. // advantage of RenderState's immutability, and store a dynamically populated sparse data structure
  63075. // containing functions that make the minimum number of WebGL calls when transitioning from one state
  63076. // to the other. In practice, this works well since state-to-state transitions generally only require a
  63077. // few WebGL calls, especially if commands are stored by state.
  63078. var funcs = renderState._applyFunctions[previousRenderState.id];
  63079. if (!defined(funcs)) {
  63080. funcs = createFuncs(previousRenderState, renderState);
  63081. renderState._applyFunctions[previousRenderState.id] = funcs;
  63082. }
  63083. var len = funcs.length;
  63084. for (var i = 0; i < len; ++i) {
  63085. funcs[i](gl, renderState);
  63086. }
  63087. }
  63088. var previousScissorTest = (defined(previousPassState.scissorTest)) ? previousPassState.scissorTest : previousRenderState.scissorTest;
  63089. var scissorTest = (defined(passState.scissorTest)) ? passState.scissorTest : renderState.scissorTest;
  63090. // Our scissor rectangle can get out of sync with the GL scissor rectangle on clears.
  63091. // Seems to be a problem only on ANGLE. See https://github.com/AnalyticalGraphicsInc/cesium/issues/2994
  63092. if ((previousScissorTest !== scissorTest) || clear) {
  63093. applyScissorTest(gl, renderState, passState);
  63094. }
  63095. var previousBlendingEnabled = (defined(previousPassState.blendingEnabled)) ? previousPassState.blendingEnabled : previousRenderState.blending.enabled;
  63096. var blendingEnabled = (defined(passState.blendingEnabled)) ? passState.blendingEnabled : renderState.blending.enabled;
  63097. if ((previousBlendingEnabled !== blendingEnabled) ||
  63098. (blendingEnabled && (previousRenderState.blending !== renderState.blending))) {
  63099. applyBlending(gl, renderState, passState);
  63100. }
  63101. if (previousRenderState !== renderState || previousPassState !== passState || previousPassState.context !== passState.context) {
  63102. applyViewport(gl, renderState, passState);
  63103. }
  63104. };
  63105. RenderState.getState = function(renderState) {
  63106. if (!defined(renderState)) {
  63107. throw new DeveloperError('renderState is required.');
  63108. }
  63109. return {
  63110. frontFace : renderState.frontFace,
  63111. cull : {
  63112. enabled : renderState.cull.enabled,
  63113. face : renderState.cull.face
  63114. },
  63115. lineWidth : renderState.lineWidth,
  63116. polygonOffset : {
  63117. enabled : renderState.polygonOffset.enabled,
  63118. factor : renderState.polygonOffset.factor,
  63119. units : renderState.polygonOffset.units
  63120. },
  63121. scissorTest : {
  63122. enabled : renderState.scissorTest.enabled,
  63123. rectangle : BoundingRectangle.clone(renderState.scissorTest.rectangle)
  63124. },
  63125. depthRange : {
  63126. near : renderState.depthRange.near,
  63127. far : renderState.depthRange.far
  63128. },
  63129. depthTest : {
  63130. enabled : renderState.depthTest.enabled,
  63131. func : renderState.depthTest.func
  63132. },
  63133. colorMask : {
  63134. red : renderState.colorMask.red,
  63135. green : renderState.colorMask.green,
  63136. blue : renderState.colorMask.blue,
  63137. alpha : renderState.colorMask.alpha
  63138. },
  63139. depthMask : renderState.depthMask,
  63140. stencilMask : renderState.stencilMask,
  63141. blending : {
  63142. enabled : renderState.blending.enabled,
  63143. color : Color.clone(renderState.blending.color),
  63144. equationRgb : renderState.blending.equationRgb,
  63145. equationAlpha : renderState.blending.equationAlpha,
  63146. functionSourceRgb : renderState.blending.functionSourceRgb,
  63147. functionSourceAlpha : renderState.blending.functionSourceAlpha,
  63148. functionDestinationRgb : renderState.blending.functionDestinationRgb,
  63149. functionDestinationAlpha : renderState.blending.functionDestinationAlpha
  63150. },
  63151. stencilTest : {
  63152. enabled : renderState.stencilTest.enabled,
  63153. frontFunction : renderState.stencilTest.frontFunction,
  63154. backFunction : renderState.stencilTest.backFunction,
  63155. reference : renderState.stencilTest.reference,
  63156. mask : renderState.stencilTest.mask,
  63157. frontOperation : {
  63158. fail : renderState.stencilTest.frontOperation.fail,
  63159. zFail : renderState.stencilTest.frontOperation.zFail,
  63160. zPass : renderState.stencilTest.frontOperation.zPass
  63161. },
  63162. backOperation : {
  63163. fail : renderState.stencilTest.backOperation.fail,
  63164. zFail : renderState.stencilTest.backOperation.zFail,
  63165. zPass : renderState.stencilTest.backOperation.zPass
  63166. }
  63167. },
  63168. sampleCoverage : {
  63169. enabled : renderState.sampleCoverage.enabled,
  63170. value : renderState.sampleCoverage.value,
  63171. invert : renderState.sampleCoverage.invert
  63172. },
  63173. viewport : defined(renderState.viewport) ? BoundingRectangle.clone(renderState.viewport) : undefined
  63174. };
  63175. };
  63176. return RenderState;
  63177. });
  63178. /*global define*/
  63179. define('Renderer/AutomaticUniforms',[
  63180. '../Core/Cartesian3',
  63181. '../Core/Matrix4',
  63182. '../Core/WebGLConstants'
  63183. ], function(
  63184. Cartesian3,
  63185. Matrix4,
  63186. WebGLConstants) {
  63187. 'use strict';
  63188. /*global WebGLRenderingContext*/
  63189. var viewerPositionWCScratch = new Cartesian3();
  63190. function AutomaticUniform(options) {
  63191. this._size = options.size;
  63192. this._datatype = options.datatype;
  63193. this.getValue = options.getValue;
  63194. }
  63195. // this check must use typeof, not defined, because defined doesn't work with undeclared variables.
  63196. if (typeof WebGLRenderingContext === 'undefined') {
  63197. return {};
  63198. }
  63199. var datatypeToGlsl = {};
  63200. datatypeToGlsl[WebGLConstants.FLOAT] = 'float';
  63201. datatypeToGlsl[WebGLConstants.FLOAT_VEC2] = 'vec2';
  63202. datatypeToGlsl[WebGLConstants.FLOAT_VEC3] = 'vec3';
  63203. datatypeToGlsl[WebGLConstants.FLOAT_VEC4] = 'vec4';
  63204. datatypeToGlsl[WebGLConstants.INT] = 'int';
  63205. datatypeToGlsl[WebGLConstants.INT_VEC2] = 'ivec2';
  63206. datatypeToGlsl[WebGLConstants.INT_VEC3] = 'ivec3';
  63207. datatypeToGlsl[WebGLConstants.INT_VEC4] = 'ivec4';
  63208. datatypeToGlsl[WebGLConstants.BOOL] = 'bool';
  63209. datatypeToGlsl[WebGLConstants.BOOL_VEC2] = 'bvec2';
  63210. datatypeToGlsl[WebGLConstants.BOOL_VEC3] = 'bvec3';
  63211. datatypeToGlsl[WebGLConstants.BOOL_VEC4] = 'bvec4';
  63212. datatypeToGlsl[WebGLConstants.FLOAT_MAT2] = 'mat2';
  63213. datatypeToGlsl[WebGLConstants.FLOAT_MAT3] = 'mat3';
  63214. datatypeToGlsl[WebGLConstants.FLOAT_MAT4] = 'mat4';
  63215. datatypeToGlsl[WebGLConstants.SAMPLER_2D] = 'sampler2D';
  63216. datatypeToGlsl[WebGLConstants.SAMPLER_CUBE] = 'samplerCube';
  63217. AutomaticUniform.prototype.getDeclaration = function(name) {
  63218. var declaration = 'uniform ' + datatypeToGlsl[this._datatype] + ' ' + name;
  63219. var size = this._size;
  63220. if (size === 1) {
  63221. declaration += ';';
  63222. } else {
  63223. declaration += '[' + size.toString() + '];';
  63224. }
  63225. return declaration;
  63226. };
  63227. /**
  63228. * @private
  63229. */
  63230. var AutomaticUniforms = {
  63231. /**
  63232. * An automatic GLSL uniform containing the viewport's <code>x</code>, <code>y</code>, <code>width</code>,
  63233. * and <code>height</code> properties in an <code>vec4</code>'s <code>x</code>, <code>y</code>, <code>z</code>,
  63234. * and <code>w</code> components, respectively.
  63235. *
  63236. * @alias czm_viewport
  63237. * @glslUniform
  63238. *
  63239. *
  63240. * @example
  63241. * // GLSL declaration
  63242. * uniform vec4 czm_viewport;
  63243. *
  63244. * // Scale the window coordinate components to [0, 1] by dividing
  63245. * // by the viewport's width and height.
  63246. * vec2 v = gl_FragCoord.xy / czm_viewport.zw;
  63247. *
  63248. * @see Context#getViewport
  63249. */
  63250. czm_viewport : new AutomaticUniform({
  63251. size : 1,
  63252. datatype : WebGLConstants.FLOAT_VEC4,
  63253. getValue : function(uniformState) {
  63254. return uniformState.viewportCartesian4;
  63255. }
  63256. }),
  63257. /**
  63258. * An automatic GLSL uniform representing a 4x4 orthographic projection matrix that
  63259. * transforms window coordinates to clip coordinates. Clip coordinates is the
  63260. * coordinate system for a vertex shader's <code>gl_Position</code> output.
  63261. * <br /><br />
  63262. * This transform is useful when a vertex shader inputs or manipulates window coordinates
  63263. * as done by {@link BillboardCollection}.
  63264. * <br /><br />
  63265. * Do not confuse {@link czm_viewportTransformation} with <code>czm_viewportOrthographic</code>.
  63266. * The former transforms from normalized device coordinates to window coordinates; the later transforms
  63267. * from window coordinates to clip coordinates, and is often used to assign to <code>gl_Position</code>.
  63268. *
  63269. * @alias czm_viewportOrthographic
  63270. * @glslUniform
  63271. *
  63272. *
  63273. * @example
  63274. * // GLSL declaration
  63275. * uniform mat4 czm_viewportOrthographic;
  63276. *
  63277. * // Example
  63278. * gl_Position = czm_viewportOrthographic * vec4(windowPosition, 0.0, 1.0);
  63279. *
  63280. * @see UniformState#viewportOrthographic
  63281. * @see czm_viewport
  63282. * @see czm_viewportTransformation
  63283. * @see BillboardCollection
  63284. */
  63285. czm_viewportOrthographic : new AutomaticUniform({
  63286. size : 1,
  63287. datatype : WebGLConstants.FLOAT_MAT4,
  63288. getValue : function(uniformState) {
  63289. return uniformState.viewportOrthographic;
  63290. }
  63291. }),
  63292. /**
  63293. * An automatic GLSL uniform representing a 4x4 transformation matrix that
  63294. * transforms normalized device coordinates to window coordinates. The context's
  63295. * full viewport is used, and the depth range is assumed to be <code>near = 0</code>
  63296. * and <code>far = 1</code>.
  63297. * <br /><br />
  63298. * This transform is useful when there is a need to manipulate window coordinates
  63299. * in a vertex shader as done by {@link BillboardCollection}. In many cases,
  63300. * this matrix will not be used directly; instead, {@link czm_modelToWindowCoordinates}
  63301. * will be used to transform directly from model to window coordinates.
  63302. * <br /><br />
  63303. * Do not confuse <code>czm_viewportTransformation</code> with {@link czm_viewportOrthographic}.
  63304. * The former transforms from normalized device coordinates to window coordinates; the later transforms
  63305. * from window coordinates to clip coordinates, and is often used to assign to <code>gl_Position</code>.
  63306. *
  63307. * @alias czm_viewportTransformation
  63308. * @glslUniform
  63309. *
  63310. *
  63311. * @example
  63312. * // GLSL declaration
  63313. * uniform mat4 czm_viewportTransformation;
  63314. *
  63315. * // Use czm_viewportTransformation as part of the
  63316. * // transform from model to window coordinates.
  63317. * vec4 q = czm_modelViewProjection * positionMC; // model to clip coordinates
  63318. * q.xyz /= q.w; // clip to normalized device coordinates (ndc)
  63319. * q.xyz = (czm_viewportTransformation * vec4(q.xyz, 1.0)).xyz; // ndc to window coordinates
  63320. *
  63321. * @see UniformState#viewportTransformation
  63322. * @see czm_viewport
  63323. * @see czm_viewportOrthographic
  63324. * @see czm_modelToWindowCoordinates
  63325. * @see BillboardCollection
  63326. */
  63327. czm_viewportTransformation : new AutomaticUniform({
  63328. size : 1,
  63329. datatype : WebGLConstants.FLOAT_MAT4,
  63330. getValue : function(uniformState) {
  63331. return uniformState.viewportTransformation;
  63332. }
  63333. }),
  63334. /**
  63335. * An automatic GLSL uniform representing the depth after
  63336. * only the globe has been rendered and packed into an RGBA texture.
  63337. *
  63338. * @private
  63339. *
  63340. * @alias czm_globeDepthTexture
  63341. * @glslUniform
  63342. *
  63343. * @example
  63344. * // GLSL declaration
  63345. * uniform sampler2D czm_globeDepthTexture;
  63346. *
  63347. * // Get the depth at the current fragment
  63348. * vec2 coords = gl_FragCoord.xy / czm_viewport.zw;
  63349. * float depth = czm_unpackDepth(texture2D(czm_globeDepthTexture, coords));
  63350. */
  63351. czm_globeDepthTexture : new AutomaticUniform({
  63352. size : 1,
  63353. datatype : WebGLConstants.SAMPLER_2D,
  63354. getValue : function(uniformState) {
  63355. return uniformState.globeDepthTexture;
  63356. }
  63357. }),
  63358. /**
  63359. * An automatic GLSL uniform representing a 4x4 model transformation matrix that
  63360. * transforms model coordinates to world coordinates.
  63361. *
  63362. * @alias czm_model
  63363. * @glslUniform
  63364. *
  63365. *
  63366. * @example
  63367. * // GLSL declaration
  63368. * uniform mat4 czm_model;
  63369. *
  63370. * // Example
  63371. * vec4 worldPosition = czm_model * modelPosition;
  63372. *
  63373. * @see UniformState#model
  63374. * @see czm_inverseModel
  63375. * @see czm_modelView
  63376. * @see czm_modelViewProjection
  63377. */
  63378. czm_model : new AutomaticUniform({
  63379. size : 1,
  63380. datatype : WebGLConstants.FLOAT_MAT4,
  63381. getValue : function(uniformState) {
  63382. return uniformState.model;
  63383. }
  63384. }),
  63385. /**
  63386. * An automatic GLSL uniform representing a 4x4 model transformation matrix that
  63387. * transforms world coordinates to model coordinates.
  63388. *
  63389. * @alias czm_inverseModel
  63390. * @glslUniform
  63391. *
  63392. *
  63393. * @example
  63394. * // GLSL declaration
  63395. * uniform mat4 czm_inverseModel;
  63396. *
  63397. * // Example
  63398. * vec4 modelPosition = czm_inverseModel * worldPosition;
  63399. *
  63400. * @see UniformState#inverseModel
  63401. * @see czm_model
  63402. * @see czm_inverseModelView
  63403. */
  63404. czm_inverseModel : new AutomaticUniform({
  63405. size : 1,
  63406. datatype : WebGLConstants.FLOAT_MAT4,
  63407. getValue : function(uniformState) {
  63408. return uniformState.inverseModel;
  63409. }
  63410. }),
  63411. /**
  63412. * An automatic GLSL uniform representing a 4x4 view transformation matrix that
  63413. * transforms world coordinates to eye coordinates.
  63414. *
  63415. * @alias czm_view
  63416. * @glslUniform
  63417. *
  63418. *
  63419. * @example
  63420. * // GLSL declaration
  63421. * uniform mat4 czm_view;
  63422. *
  63423. * // Example
  63424. * vec4 eyePosition = czm_view * worldPosition;
  63425. *
  63426. * @see UniformState#view
  63427. * @see czm_viewRotation
  63428. * @see czm_modelView
  63429. * @see czm_viewProjection
  63430. * @see czm_modelViewProjection
  63431. * @see czm_inverseView
  63432. */
  63433. czm_view : new AutomaticUniform({
  63434. size : 1,
  63435. datatype : WebGLConstants.FLOAT_MAT4,
  63436. getValue : function(uniformState) {
  63437. return uniformState.view;
  63438. }
  63439. }),
  63440. /**
  63441. * An automatic GLSL uniform representing a 4x4 view transformation matrix that
  63442. * transforms 3D world coordinates to eye coordinates. In 3D mode, this is identical to
  63443. * {@link czm_view}, but in 2D and Columbus View it represents the view matrix
  63444. * as if the camera were at an equivalent location in 3D mode. This is useful for lighting
  63445. * 2D and Columbus View in the same way that 3D is lit.
  63446. *
  63447. * @alias czm_view3D
  63448. * @glslUniform
  63449. *
  63450. *
  63451. * @example
  63452. * // GLSL declaration
  63453. * uniform mat4 czm_view3D;
  63454. *
  63455. * // Example
  63456. * vec4 eyePosition3D = czm_view3D * worldPosition3D;
  63457. *
  63458. * @see UniformState#view3D
  63459. * @see czm_view
  63460. */
  63461. czm_view3D : new AutomaticUniform({
  63462. size : 1,
  63463. datatype : WebGLConstants.FLOAT_MAT4,
  63464. getValue : function(uniformState) {
  63465. return uniformState.view3D;
  63466. }
  63467. }),
  63468. /**
  63469. * An automatic GLSL uniform representing a 3x3 view rotation matrix that
  63470. * transforms vectors in world coordinates to eye coordinates.
  63471. *
  63472. * @alias czm_viewRotation
  63473. * @glslUniform
  63474. *
  63475. *
  63476. * @example
  63477. * // GLSL declaration
  63478. * uniform mat3 czm_viewRotation;
  63479. *
  63480. * // Example
  63481. * vec3 eyeVector = czm_viewRotation * worldVector;
  63482. *
  63483. * @see UniformState#viewRotation
  63484. * @see czm_view
  63485. * @see czm_inverseView
  63486. * @see czm_inverseViewRotation
  63487. */
  63488. czm_viewRotation : new AutomaticUniform({
  63489. size : 1,
  63490. datatype : WebGLConstants.FLOAT_MAT3,
  63491. getValue : function(uniformState) {
  63492. return uniformState.viewRotation;
  63493. }
  63494. }),
  63495. /**
  63496. * An automatic GLSL uniform representing a 3x3 view rotation matrix that
  63497. * transforms vectors in 3D world coordinates to eye coordinates. In 3D mode, this is identical to
  63498. * {@link czm_viewRotation}, but in 2D and Columbus View it represents the view matrix
  63499. * as if the camera were at an equivalent location in 3D mode. This is useful for lighting
  63500. * 2D and Columbus View in the same way that 3D is lit.
  63501. *
  63502. * @alias czm_viewRotation3D
  63503. * @glslUniform
  63504. *
  63505. *
  63506. * @example
  63507. * // GLSL declaration
  63508. * uniform mat3 czm_viewRotation3D;
  63509. *
  63510. * // Example
  63511. * vec3 eyeVector = czm_viewRotation3D * worldVector;
  63512. *
  63513. * @see UniformState#viewRotation3D
  63514. * @see czm_viewRotation
  63515. */
  63516. czm_viewRotation3D : new AutomaticUniform({
  63517. size : 1,
  63518. datatype : WebGLConstants.FLOAT_MAT3,
  63519. getValue : function(uniformState) {
  63520. return uniformState.viewRotation3D;
  63521. }
  63522. }),
  63523. /**
  63524. * An automatic GLSL uniform representing a 4x4 transformation matrix that
  63525. * transforms from eye coordinates to world coordinates.
  63526. *
  63527. * @alias czm_inverseView
  63528. * @glslUniform
  63529. *
  63530. *
  63531. * @example
  63532. * // GLSL declaration
  63533. * uniform mat4 czm_inverseView;
  63534. *
  63535. * // Example
  63536. * vec4 worldPosition = czm_inverseView * eyePosition;
  63537. *
  63538. * @see UniformState#inverseView
  63539. * @see czm_view
  63540. * @see czm_inverseNormal
  63541. */
  63542. czm_inverseView : new AutomaticUniform({
  63543. size : 1,
  63544. datatype : WebGLConstants.FLOAT_MAT4,
  63545. getValue : function(uniformState) {
  63546. return uniformState.inverseView;
  63547. }
  63548. }),
  63549. /**
  63550. * An automatic GLSL uniform representing a 4x4 transformation matrix that
  63551. * transforms from 3D eye coordinates to world coordinates. In 3D mode, this is identical to
  63552. * {@link czm_inverseView}, but in 2D and Columbus View it represents the inverse view matrix
  63553. * as if the camera were at an equivalent location in 3D mode. This is useful for lighting
  63554. * 2D and Columbus View in the same way that 3D is lit.
  63555. *
  63556. * @alias czm_inverseView3D
  63557. * @glslUniform
  63558. *
  63559. *
  63560. * @example
  63561. * // GLSL declaration
  63562. * uniform mat4 czm_inverseView3D;
  63563. *
  63564. * // Example
  63565. * vec4 worldPosition = czm_inverseView3D * eyePosition;
  63566. *
  63567. * @see UniformState#inverseView3D
  63568. * @see czm_inverseView
  63569. */
  63570. czm_inverseView3D : new AutomaticUniform({
  63571. size : 1,
  63572. datatype : WebGLConstants.FLOAT_MAT4,
  63573. getValue : function(uniformState) {
  63574. return uniformState.inverseView3D;
  63575. }
  63576. }),
  63577. /**
  63578. * An automatic GLSL uniform representing a 3x3 rotation matrix that
  63579. * transforms vectors from eye coordinates to world coordinates.
  63580. *
  63581. * @alias czm_inverseViewRotation
  63582. * @glslUniform
  63583. *
  63584. *
  63585. * @example
  63586. * // GLSL declaration
  63587. * uniform mat3 czm_inverseViewRotation;
  63588. *
  63589. * // Example
  63590. * vec4 worldVector = czm_inverseViewRotation * eyeVector;
  63591. *
  63592. * @see UniformState#inverseView
  63593. * @see czm_view
  63594. * @see czm_viewRotation
  63595. * @see czm_inverseViewRotation
  63596. */
  63597. czm_inverseViewRotation : new AutomaticUniform({
  63598. size : 1,
  63599. datatype : WebGLConstants.FLOAT_MAT3,
  63600. getValue : function(uniformState) {
  63601. return uniformState.inverseViewRotation;
  63602. }
  63603. }),
  63604. /**
  63605. * An automatic GLSL uniform representing a 3x3 rotation matrix that
  63606. * transforms vectors from 3D eye coordinates to world coordinates. In 3D mode, this is identical to
  63607. * {@link czm_inverseViewRotation}, but in 2D and Columbus View it represents the inverse view matrix
  63608. * as if the camera were at an equivalent location in 3D mode. This is useful for lighting
  63609. * 2D and Columbus View in the same way that 3D is lit.
  63610. *
  63611. * @alias czm_inverseViewRotation3D
  63612. * @glslUniform
  63613. *
  63614. *
  63615. * @example
  63616. * // GLSL declaration
  63617. * uniform mat3 czm_inverseViewRotation3D;
  63618. *
  63619. * // Example
  63620. * vec4 worldVector = czm_inverseViewRotation3D * eyeVector;
  63621. *
  63622. * @see UniformState#inverseView3D
  63623. * @see czm_inverseViewRotation
  63624. */
  63625. czm_inverseViewRotation3D : new AutomaticUniform({
  63626. size : 1,
  63627. datatype : WebGLConstants.FLOAT_MAT3,
  63628. getValue : function(uniformState) {
  63629. return uniformState.inverseViewRotation3D;
  63630. }
  63631. }),
  63632. /**
  63633. * An automatic GLSL uniform representing a 4x4 projection transformation matrix that
  63634. * transforms eye coordinates to clip coordinates. Clip coordinates is the
  63635. * coordinate system for a vertex shader's <code>gl_Position</code> output.
  63636. *
  63637. * @alias czm_projection
  63638. * @glslUniform
  63639. *
  63640. *
  63641. * @example
  63642. * // GLSL declaration
  63643. * uniform mat4 czm_projection;
  63644. *
  63645. * // Example
  63646. * gl_Position = czm_projection * eyePosition;
  63647. *
  63648. * @see UniformState#projection
  63649. * @see czm_viewProjection
  63650. * @see czm_modelViewProjection
  63651. * @see czm_infiniteProjection
  63652. */
  63653. czm_projection : new AutomaticUniform({
  63654. size : 1,
  63655. datatype : WebGLConstants.FLOAT_MAT4,
  63656. getValue : function(uniformState) {
  63657. return uniformState.projection;
  63658. }
  63659. }),
  63660. /**
  63661. * An automatic GLSL uniform representing a 4x4 inverse projection transformation matrix that
  63662. * transforms from clip coordinates to eye coordinates. Clip coordinates is the
  63663. * coordinate system for a vertex shader's <code>gl_Position</code> output.
  63664. *
  63665. * @alias czm_inverseProjection
  63666. * @glslUniform
  63667. *
  63668. *
  63669. * @example
  63670. * // GLSL declaration
  63671. * uniform mat4 czm_inverseProjection;
  63672. *
  63673. * // Example
  63674. * vec4 eyePosition = czm_inverseProjection * clipPosition;
  63675. *
  63676. * @see UniformState#inverseProjection
  63677. * @see czm_projection
  63678. */
  63679. czm_inverseProjection : new AutomaticUniform({
  63680. size : 1,
  63681. datatype : WebGLConstants.FLOAT_MAT4,
  63682. getValue : function(uniformState) {
  63683. return uniformState.inverseProjection;
  63684. }
  63685. }),
  63686. /**
  63687. * @private
  63688. */
  63689. czm_inverseProjectionOIT : new AutomaticUniform({
  63690. size : 1,
  63691. datatype : WebGLConstants.FLOAT_MAT4,
  63692. getValue : function(uniformState) {
  63693. return uniformState.inverseProjectionOIT;
  63694. }
  63695. }),
  63696. /**
  63697. * An automatic GLSL uniform representing a 4x4 projection transformation matrix with the far plane at infinity,
  63698. * that transforms eye coordinates to clip coordinates. Clip coordinates is the
  63699. * coordinate system for a vertex shader's <code>gl_Position</code> output. An infinite far plane is used
  63700. * in algorithms like shadow volumes and GPU ray casting with proxy geometry to ensure that triangles
  63701. * are not clipped by the far plane.
  63702. *
  63703. * @alias czm_infiniteProjection
  63704. * @glslUniform
  63705. *
  63706. *
  63707. * @example
  63708. * // GLSL declaration
  63709. * uniform mat4 czm_infiniteProjection;
  63710. *
  63711. * // Example
  63712. * gl_Position = czm_infiniteProjection * eyePosition;
  63713. *
  63714. * @see UniformState#infiniteProjection
  63715. * @see czm_projection
  63716. * @see czm_modelViewInfiniteProjection
  63717. */
  63718. czm_infiniteProjection : new AutomaticUniform({
  63719. size : 1,
  63720. datatype : WebGLConstants.FLOAT_MAT4,
  63721. getValue : function(uniformState) {
  63722. return uniformState.infiniteProjection;
  63723. }
  63724. }),
  63725. /**
  63726. * An automatic GLSL uniform representing a 4x4 model-view transformation matrix that
  63727. * transforms model coordinates to eye coordinates.
  63728. * <br /><br />
  63729. * Positions should be transformed to eye coordinates using <code>czm_modelView</code> and
  63730. * normals should be transformed using {@link czm_normal}.
  63731. *
  63732. * @alias czm_modelView
  63733. * @glslUniform
  63734. *
  63735. *
  63736. * @example
  63737. * // GLSL declaration
  63738. * uniform mat4 czm_modelView;
  63739. *
  63740. * // Example
  63741. * vec4 eyePosition = czm_modelView * modelPosition;
  63742. *
  63743. * // The above is equivalent to, but more efficient than:
  63744. * vec4 eyePosition = czm_view * czm_model * modelPosition;
  63745. *
  63746. * @see UniformState#modelView
  63747. * @see czm_model
  63748. * @see czm_view
  63749. * @see czm_modelViewProjection
  63750. * @see czm_normal
  63751. */
  63752. czm_modelView : new AutomaticUniform({
  63753. size : 1,
  63754. datatype : WebGLConstants.FLOAT_MAT4,
  63755. getValue : function(uniformState) {
  63756. return uniformState.modelView;
  63757. }
  63758. }),
  63759. /**
  63760. * An automatic GLSL uniform representing a 4x4 model-view transformation matrix that
  63761. * transforms 3D model coordinates to eye coordinates. In 3D mode, this is identical to
  63762. * {@link czm_modelView}, but in 2D and Columbus View it represents the model-view matrix
  63763. * as if the camera were at an equivalent location in 3D mode. This is useful for lighting
  63764. * 2D and Columbus View in the same way that 3D is lit.
  63765. * <br /><br />
  63766. * Positions should be transformed to eye coordinates using <code>czm_modelView3D</code> and
  63767. * normals should be transformed using {@link czm_normal3D}.
  63768. *
  63769. * @alias czm_modelView3D
  63770. * @glslUniform
  63771. *
  63772. *
  63773. * @example
  63774. * // GLSL declaration
  63775. * uniform mat4 czm_modelView3D;
  63776. *
  63777. * // Example
  63778. * vec4 eyePosition = czm_modelView3D * modelPosition;
  63779. *
  63780. * // The above is equivalent to, but more efficient than:
  63781. * vec4 eyePosition = czm_view3D * czm_model * modelPosition;
  63782. *
  63783. * @see UniformState#modelView3D
  63784. * @see czm_modelView
  63785. */
  63786. czm_modelView3D : new AutomaticUniform({
  63787. size : 1,
  63788. datatype : WebGLConstants.FLOAT_MAT4,
  63789. getValue : function(uniformState) {
  63790. return uniformState.modelView3D;
  63791. }
  63792. }),
  63793. /**
  63794. * An automatic GLSL uniform representing a 4x4 model-view transformation matrix that
  63795. * transforms model coordinates, relative to the eye, to eye coordinates. This is used
  63796. * in conjunction with {@link czm_translateRelativeToEye}.
  63797. *
  63798. * @alias czm_modelViewRelativeToEye
  63799. * @glslUniform
  63800. *
  63801. * @example
  63802. * // GLSL declaration
  63803. * uniform mat4 czm_modelViewRelativeToEye;
  63804. *
  63805. * // Example
  63806. * attribute vec3 positionHigh;
  63807. * attribute vec3 positionLow;
  63808. *
  63809. * void main()
  63810. * {
  63811. * vec4 p = czm_translateRelativeToEye(positionHigh, positionLow);
  63812. * gl_Position = czm_projection * (czm_modelViewRelativeToEye * p);
  63813. * }
  63814. *
  63815. * @see czm_modelViewProjectionRelativeToEye
  63816. * @see czm_translateRelativeToEye
  63817. * @see EncodedCartesian3
  63818. */
  63819. czm_modelViewRelativeToEye : new AutomaticUniform({
  63820. size : 1,
  63821. datatype : WebGLConstants.FLOAT_MAT4,
  63822. getValue : function(uniformState) {
  63823. return uniformState.modelViewRelativeToEye;
  63824. }
  63825. }),
  63826. /**
  63827. * An automatic GLSL uniform representing a 4x4 transformation matrix that
  63828. * transforms from eye coordinates to model coordinates.
  63829. *
  63830. * @alias czm_inverseModelView
  63831. * @glslUniform
  63832. *
  63833. *
  63834. * @example
  63835. * // GLSL declaration
  63836. * uniform mat4 czm_inverseModelView;
  63837. *
  63838. * // Example
  63839. * vec4 modelPosition = czm_inverseModelView * eyePosition;
  63840. *
  63841. * @see UniformState#inverseModelView
  63842. * @see czm_modelView
  63843. */
  63844. czm_inverseModelView : new AutomaticUniform({
  63845. size : 1,
  63846. datatype : WebGLConstants.FLOAT_MAT4,
  63847. getValue : function(uniformState) {
  63848. return uniformState.inverseModelView;
  63849. }
  63850. }),
  63851. /**
  63852. * An automatic GLSL uniform representing a 4x4 transformation matrix that
  63853. * transforms from eye coordinates to 3D model coordinates. In 3D mode, this is identical to
  63854. * {@link czm_inverseModelView}, but in 2D and Columbus View it represents the inverse model-view matrix
  63855. * as if the camera were at an equivalent location in 3D mode. This is useful for lighting
  63856. * 2D and Columbus View in the same way that 3D is lit.
  63857. *
  63858. * @alias czm_inverseModelView3D
  63859. * @glslUniform
  63860. *
  63861. *
  63862. * @example
  63863. * // GLSL declaration
  63864. * uniform mat4 czm_inverseModelView3D;
  63865. *
  63866. * // Example
  63867. * vec4 modelPosition = czm_inverseModelView3D * eyePosition;
  63868. *
  63869. * @see UniformState#inverseModelView
  63870. * @see czm_inverseModelView
  63871. * @see czm_modelView3D
  63872. */
  63873. czm_inverseModelView3D : new AutomaticUniform({
  63874. size : 1,
  63875. datatype : WebGLConstants.FLOAT_MAT4,
  63876. getValue : function(uniformState) {
  63877. return uniformState.inverseModelView3D;
  63878. }
  63879. }),
  63880. /**
  63881. * An automatic GLSL uniform representing a 4x4 view-projection transformation matrix that
  63882. * transforms world coordinates to clip coordinates. Clip coordinates is the
  63883. * coordinate system for a vertex shader's <code>gl_Position</code> output.
  63884. *
  63885. * @alias czm_viewProjection
  63886. * @glslUniform
  63887. *
  63888. *
  63889. * @example
  63890. * // GLSL declaration
  63891. * uniform mat4 czm_viewProjection;
  63892. *
  63893. * // Example
  63894. * vec4 gl_Position = czm_viewProjection * czm_model * modelPosition;
  63895. *
  63896. * // The above is equivalent to, but more efficient than:
  63897. * gl_Position = czm_projection * czm_view * czm_model * modelPosition;
  63898. *
  63899. * @see UniformState#viewProjection
  63900. * @see czm_view
  63901. * @see czm_projection
  63902. * @see czm_modelViewProjection
  63903. * @see czm_inverseViewProjection
  63904. */
  63905. czm_viewProjection : new AutomaticUniform({
  63906. size : 1,
  63907. datatype : WebGLConstants.FLOAT_MAT4,
  63908. getValue : function(uniformState) {
  63909. return uniformState.viewProjection;
  63910. }
  63911. }),
  63912. /**
  63913. * An automatic GLSL uniform representing a 4x4 view-projection transformation matrix that
  63914. * transforms clip coordinates to world coordinates. Clip coordinates is the
  63915. * coordinate system for a vertex shader's <code>gl_Position</code> output.
  63916. *
  63917. * @alias czm_inverseViewProjection
  63918. * @glslUniform
  63919. *
  63920. *
  63921. * @example
  63922. * // GLSL declaration
  63923. * uniform mat4 czm_inverseViewProjection;
  63924. *
  63925. * // Example
  63926. * vec4 worldPosition = czm_inverseViewProjection * clipPosition;
  63927. *
  63928. * @see UniformState#inverseViewProjection
  63929. * @see czm_viewProjection
  63930. */
  63931. czm_inverseViewProjection : new AutomaticUniform({
  63932. size : 1,
  63933. datatype : WebGLConstants.FLOAT_MAT4,
  63934. getValue : function(uniformState) {
  63935. return uniformState.inverseViewProjection;
  63936. }
  63937. }),
  63938. /**
  63939. * An automatic GLSL uniform representing a 4x4 model-view-projection transformation matrix that
  63940. * transforms model coordinates to clip coordinates. Clip coordinates is the
  63941. * coordinate system for a vertex shader's <code>gl_Position</code> output.
  63942. *
  63943. * @alias czm_modelViewProjection
  63944. * @glslUniform
  63945. *
  63946. *
  63947. * @example
  63948. * // GLSL declaration
  63949. * uniform mat4 czm_modelViewProjection;
  63950. *
  63951. * // Example
  63952. * vec4 gl_Position = czm_modelViewProjection * modelPosition;
  63953. *
  63954. * // The above is equivalent to, but more efficient than:
  63955. * gl_Position = czm_projection * czm_view * czm_model * modelPosition;
  63956. *
  63957. * @see UniformState#modelViewProjection
  63958. * @see czm_model
  63959. * @see czm_view
  63960. * @see czm_projection
  63961. * @see czm_modelView
  63962. * @see czm_viewProjection
  63963. * @see czm_modelViewInfiniteProjection
  63964. * @see czm_inverseModelViewProjection
  63965. */
  63966. czm_modelViewProjection : new AutomaticUniform({
  63967. size : 1,
  63968. datatype : WebGLConstants.FLOAT_MAT4,
  63969. getValue : function(uniformState) {
  63970. return uniformState.modelViewProjection;
  63971. }
  63972. }),
  63973. /**
  63974. * An automatic GLSL uniform representing a 4x4 inverse model-view-projection transformation matrix that
  63975. * transforms clip coordinates to model coordinates. Clip coordinates is the
  63976. * coordinate system for a vertex shader's <code>gl_Position</code> output.
  63977. *
  63978. * @alias czm_inverseModelViewProjection
  63979. * @glslUniform
  63980. *
  63981. *
  63982. * @example
  63983. * // GLSL declaration
  63984. * uniform mat4 czm_inverseModelViewProjection;
  63985. *
  63986. * // Example
  63987. * vec4 modelPosition = czm_inverseModelViewProjection * clipPosition;
  63988. *
  63989. * @see UniformState#modelViewProjection
  63990. * @see czm_modelViewProjection
  63991. */
  63992. czm_inverseModelViewProjection : new AutomaticUniform({
  63993. size : 1,
  63994. datatype : WebGLConstants.FLOAT_MAT4,
  63995. getValue : function(uniformState) {
  63996. return uniformState.inverseModelViewProjection;
  63997. }
  63998. }),
  63999. /**
  64000. * An automatic GLSL uniform representing a 4x4 model-view-projection transformation matrix that
  64001. * transforms model coordinates, relative to the eye, to clip coordinates. Clip coordinates is the
  64002. * coordinate system for a vertex shader's <code>gl_Position</code> output. This is used in
  64003. * conjunction with {@link czm_translateRelativeToEye}.
  64004. *
  64005. * @alias czm_modelViewProjectionRelativeToEye
  64006. * @glslUniform
  64007. *
  64008. * @example
  64009. * // GLSL declaration
  64010. * uniform mat4 czm_modelViewProjectionRelativeToEye;
  64011. *
  64012. * // Example
  64013. * attribute vec3 positionHigh;
  64014. * attribute vec3 positionLow;
  64015. *
  64016. * void main()
  64017. * {
  64018. * vec4 p = czm_translateRelativeToEye(positionHigh, positionLow);
  64019. * gl_Position = czm_modelViewProjectionRelativeToEye * p;
  64020. * }
  64021. *
  64022. * @see czm_modelViewRelativeToEye
  64023. * @see czm_translateRelativeToEye
  64024. * @see EncodedCartesian3
  64025. */
  64026. czm_modelViewProjectionRelativeToEye : new AutomaticUniform({
  64027. size : 1,
  64028. datatype : WebGLConstants.FLOAT_MAT4,
  64029. getValue : function(uniformState) {
  64030. return uniformState.modelViewProjectionRelativeToEye;
  64031. }
  64032. }),
  64033. /**
  64034. * An automatic GLSL uniform representing a 4x4 model-view-projection transformation matrix that
  64035. * transforms model coordinates to clip coordinates. Clip coordinates is the
  64036. * coordinate system for a vertex shader's <code>gl_Position</code> output. The projection matrix places
  64037. * the far plane at infinity. This is useful in algorithms like shadow volumes and GPU ray casting with
  64038. * proxy geometry to ensure that triangles are not clipped by the far plane.
  64039. *
  64040. * @alias czm_modelViewInfiniteProjection
  64041. * @glslUniform
  64042. *
  64043. *
  64044. * @example
  64045. * // GLSL declaration
  64046. * uniform mat4 czm_modelViewInfiniteProjection;
  64047. *
  64048. * // Example
  64049. * vec4 gl_Position = czm_modelViewInfiniteProjection * modelPosition;
  64050. *
  64051. * // The above is equivalent to, but more efficient than:
  64052. * gl_Position = czm_infiniteProjection * czm_view * czm_model * modelPosition;
  64053. *
  64054. * @see UniformState#modelViewInfiniteProjection
  64055. * @see czm_model
  64056. * @see czm_view
  64057. * @see czm_infiniteProjection
  64058. * @see czm_modelViewProjection
  64059. */
  64060. czm_modelViewInfiniteProjection : new AutomaticUniform({
  64061. size : 1,
  64062. datatype : WebGLConstants.FLOAT_MAT4,
  64063. getValue : function(uniformState) {
  64064. return uniformState.modelViewInfiniteProjection;
  64065. }
  64066. }),
  64067. /**
  64068. * An automatic GLSL uniform representing a 3x3 normal transformation matrix that
  64069. * transforms normal vectors in model coordinates to eye coordinates.
  64070. * <br /><br />
  64071. * Positions should be transformed to eye coordinates using {@link czm_modelView} and
  64072. * normals should be transformed using <code>czm_normal</code>.
  64073. *
  64074. * @alias czm_normal
  64075. * @glslUniform
  64076. *
  64077. *
  64078. * @example
  64079. * // GLSL declaration
  64080. * uniform mat3 czm_normal;
  64081. *
  64082. * // Example
  64083. * vec3 eyeNormal = czm_normal * normal;
  64084. *
  64085. * @see UniformState#normal
  64086. * @see czm_inverseNormal
  64087. * @see czm_modelView
  64088. */
  64089. czm_normal : new AutomaticUniform({
  64090. size : 1,
  64091. datatype : WebGLConstants.FLOAT_MAT3,
  64092. getValue : function(uniformState) {
  64093. return uniformState.normal;
  64094. }
  64095. }),
  64096. /**
  64097. * An automatic GLSL uniform representing a 3x3 normal transformation matrix that
  64098. * transforms normal vectors in 3D model coordinates to eye coordinates.
  64099. * In 3D mode, this is identical to
  64100. * {@link czm_normal}, but in 2D and Columbus View it represents the normal transformation
  64101. * matrix as if the camera were at an equivalent location in 3D mode. This is useful for lighting
  64102. * 2D and Columbus View in the same way that 3D is lit.
  64103. * <br /><br />
  64104. * Positions should be transformed to eye coordinates using {@link czm_modelView3D} and
  64105. * normals should be transformed using <code>czm_normal3D</code>.
  64106. *
  64107. * @alias czm_normal3D
  64108. * @glslUniform
  64109. *
  64110. *
  64111. * @example
  64112. * // GLSL declaration
  64113. * uniform mat3 czm_normal3D;
  64114. *
  64115. * // Example
  64116. * vec3 eyeNormal = czm_normal3D * normal;
  64117. *
  64118. * @see UniformState#normal3D
  64119. * @see czm_normal
  64120. */
  64121. czm_normal3D : new AutomaticUniform({
  64122. size : 1,
  64123. datatype : WebGLConstants.FLOAT_MAT3,
  64124. getValue : function(uniformState) {
  64125. return uniformState.normal3D;
  64126. }
  64127. }),
  64128. /**
  64129. * An automatic GLSL uniform representing a 3x3 normal transformation matrix that
  64130. * transforms normal vectors in eye coordinates to model coordinates. This is
  64131. * the opposite of the transform provided by {@link czm_normal}.
  64132. *
  64133. * @alias czm_inverseNormal
  64134. * @glslUniform
  64135. *
  64136. *
  64137. * @example
  64138. * // GLSL declaration
  64139. * uniform mat3 czm_inverseNormal;
  64140. *
  64141. * // Example
  64142. * vec3 normalMC = czm_inverseNormal * normalEC;
  64143. *
  64144. * @see UniformState#inverseNormal
  64145. * @see czm_normal
  64146. * @see czm_modelView
  64147. * @see czm_inverseView
  64148. */
  64149. czm_inverseNormal : new AutomaticUniform({
  64150. size : 1,
  64151. datatype : WebGLConstants.FLOAT_MAT3,
  64152. getValue : function(uniformState) {
  64153. return uniformState.inverseNormal;
  64154. }
  64155. }),
  64156. /**
  64157. * An automatic GLSL uniform representing a 3x3 normal transformation matrix that
  64158. * transforms normal vectors in eye coordinates to 3D model coordinates. This is
  64159. * the opposite of the transform provided by {@link czm_normal}.
  64160. * In 3D mode, this is identical to
  64161. * {@link czm_inverseNormal}, but in 2D and Columbus View it represents the inverse normal transformation
  64162. * matrix as if the camera were at an equivalent location in 3D mode. This is useful for lighting
  64163. * 2D and Columbus View in the same way that 3D is lit.
  64164. *
  64165. * @alias czm_inverseNormal3D
  64166. * @glslUniform
  64167. *
  64168. *
  64169. * @example
  64170. * // GLSL declaration
  64171. * uniform mat3 czm_inverseNormal3D;
  64172. *
  64173. * // Example
  64174. * vec3 normalMC = czm_inverseNormal3D * normalEC;
  64175. *
  64176. * @see UniformState#inverseNormal3D
  64177. * @see czm_inverseNormal
  64178. */
  64179. czm_inverseNormal3D : new AutomaticUniform({
  64180. size : 1,
  64181. datatype : WebGLConstants.FLOAT_MAT3,
  64182. getValue : function(uniformState) {
  64183. return uniformState.inverseNormal3D;
  64184. }
  64185. }),
  64186. /**
  64187. * An automatic GLSL uniform containing height (<code>x</code>) and height squared (<code>y</code>)
  64188. * of the eye (camera) in the 2D scene in meters.
  64189. *
  64190. * @alias czm_eyeHeight2D
  64191. * @glslUniform
  64192. *
  64193. * @see UniformState#eyeHeight2D
  64194. */
  64195. czm_eyeHeight2D : new AutomaticUniform({
  64196. size : 1,
  64197. datatype : WebGLConstants.FLOAT_VEC2,
  64198. getValue : function(uniformState) {
  64199. return uniformState.eyeHeight2D;
  64200. }
  64201. }),
  64202. /**
  64203. * An automatic GLSL uniform containing the near distance (<code>x</code>) and the far distance (<code>y</code>)
  64204. * of the frustum defined by the camera. This is the largest possible frustum, not an individual
  64205. * frustum used for multi-frustum rendering.
  64206. *
  64207. * @alias czm_entireFrustum
  64208. * @glslUniform
  64209. *
  64210. *
  64211. * @example
  64212. * // GLSL declaration
  64213. * uniform vec2 czm_entireFrustum;
  64214. *
  64215. * // Example
  64216. * float frustumLength = czm_entireFrustum.y - czm_entireFrustum.x;
  64217. *
  64218. * @see UniformState#entireFrustum
  64219. * @see czm_currentFrustum
  64220. */
  64221. czm_entireFrustum : new AutomaticUniform({
  64222. size : 1,
  64223. datatype : WebGLConstants.FLOAT_VEC2,
  64224. getValue : function(uniformState) {
  64225. return uniformState.entireFrustum;
  64226. }
  64227. }),
  64228. /**
  64229. * An automatic GLSL uniform containing the near distance (<code>x</code>) and the far distance (<code>y</code>)
  64230. * of the frustum defined by the camera. This is the individual
  64231. * frustum used for multi-frustum rendering.
  64232. *
  64233. * @alias czm_currentFrustum
  64234. * @glslUniform
  64235. *
  64236. *
  64237. * @example
  64238. * // GLSL declaration
  64239. * uniform vec2 czm_currentFrustum;
  64240. *
  64241. * // Example
  64242. * float frustumLength = czm_currentFrustum.y - czm_currentFrustum.x;
  64243. *
  64244. * @see UniformState#currentFrustum
  64245. * @see czm_entireFrustum
  64246. */
  64247. czm_currentFrustum : new AutomaticUniform({
  64248. size : 1,
  64249. datatype : WebGLConstants.FLOAT_VEC2,
  64250. getValue : function(uniformState) {
  64251. return uniformState.currentFrustum;
  64252. }
  64253. }),
  64254. /**
  64255. * The distances to the frustum planes. The top, bottom, left and right distances are
  64256. * the x, y, z, and w components, respectively.
  64257. *
  64258. * @alias czm_frustumPlanes
  64259. * @glslUniform
  64260. */
  64261. czm_frustumPlanes : new AutomaticUniform({
  64262. size : 1,
  64263. datatype : WebGLConstants.FLOAT_VEC4,
  64264. getValue : function(uniformState) {
  64265. return uniformState.frustumPlanes;
  64266. }
  64267. }),
  64268. /**
  64269. * An automatic GLSL uniform representing the sun position in world coordinates.
  64270. *
  64271. * @alias czm_sunPositionWC
  64272. * @glslUniform
  64273. *
  64274. *
  64275. * @example
  64276. * // GLSL declaration
  64277. * uniform vec3 czm_sunPositionWC;
  64278. *
  64279. * @see UniformState#sunPositionWC
  64280. * @see czm_sunPositionColumbusView
  64281. * @see czm_sunDirectionWC
  64282. */
  64283. czm_sunPositionWC : new AutomaticUniform({
  64284. size : 1,
  64285. datatype : WebGLConstants.FLOAT_VEC3,
  64286. getValue : function(uniformState) {
  64287. return uniformState.sunPositionWC;
  64288. }
  64289. }),
  64290. /**
  64291. * An automatic GLSL uniform representing the sun position in Columbus view world coordinates.
  64292. *
  64293. * @alias czm_sunPositionColumbusView
  64294. * @glslUniform
  64295. *
  64296. *
  64297. * @example
  64298. * // GLSL declaration
  64299. * uniform vec3 czm_sunPositionColumbusView;
  64300. *
  64301. * @see UniformState#sunPositionColumbusView
  64302. * @see czm_sunPositionWC
  64303. */
  64304. czm_sunPositionColumbusView : new AutomaticUniform({
  64305. size : 1,
  64306. datatype : WebGLConstants.FLOAT_VEC3,
  64307. getValue : function(uniformState) {
  64308. return uniformState.sunPositionColumbusView;
  64309. }
  64310. }),
  64311. /**
  64312. * An automatic GLSL uniform representing the normalized direction to the sun in eye coordinates.
  64313. * This is commonly used for directional lighting computations.
  64314. *
  64315. * @alias czm_sunDirectionEC
  64316. * @glslUniform
  64317. *
  64318. *
  64319. * @example
  64320. * // GLSL declaration
  64321. * uniform vec3 czm_sunDirectionEC;
  64322. *
  64323. * // Example
  64324. * float diffuse = max(dot(czm_sunDirectionEC, normalEC), 0.0);
  64325. *
  64326. * @see UniformState#sunDirectionEC
  64327. * @see czm_moonDirectionEC
  64328. * @see czm_sunDirectionWC
  64329. */
  64330. czm_sunDirectionEC : new AutomaticUniform({
  64331. size : 1,
  64332. datatype : WebGLConstants.FLOAT_VEC3,
  64333. getValue : function(uniformState) {
  64334. return uniformState.sunDirectionEC;
  64335. }
  64336. }),
  64337. /**
  64338. * An automatic GLSL uniform representing the normalized direction to the sun in world coordinates.
  64339. * This is commonly used for directional lighting computations.
  64340. *
  64341. * @alias czm_sunDirectionWC
  64342. * @glslUniform
  64343. *
  64344. *
  64345. * @example
  64346. * // GLSL declaration
  64347. * uniform vec3 czm_sunDirectionWC;
  64348. *
  64349. * @see UniformState#sunDirectionWC
  64350. * @see czm_sunPositionWC
  64351. * @see czm_sunDirectionEC
  64352. */
  64353. czm_sunDirectionWC : new AutomaticUniform({
  64354. size : 1,
  64355. datatype : WebGLConstants.FLOAT_VEC3,
  64356. getValue : function(uniformState) {
  64357. return uniformState.sunDirectionWC;
  64358. }
  64359. }),
  64360. /**
  64361. * An automatic GLSL uniform representing the normalized direction to the moon in eye coordinates.
  64362. * This is commonly used for directional lighting computations.
  64363. *
  64364. * @alias czm_moonDirectionEC
  64365. * @glslUniform
  64366. *
  64367. *
  64368. * @example
  64369. * // GLSL declaration
  64370. * uniform vec3 czm_moonDirectionEC;
  64371. *
  64372. * // Example
  64373. * float diffuse = max(dot(czm_moonDirectionEC, normalEC), 0.0);
  64374. *
  64375. * @see UniformState#moonDirectionEC
  64376. * @see czm_sunDirectionEC
  64377. */
  64378. czm_moonDirectionEC : new AutomaticUniform({
  64379. size : 1,
  64380. datatype : WebGLConstants.FLOAT_VEC3,
  64381. getValue : function(uniformState) {
  64382. return uniformState.moonDirectionEC;
  64383. }
  64384. }),
  64385. /**
  64386. * An automatic GLSL uniform representing the high bits of the camera position in model
  64387. * coordinates. This is used for GPU RTE to eliminate jittering artifacts when rendering
  64388. * as described in {@link http://blogs.agi.com/insight3d/index.php/2008/09/03/precisions-precisions/|Precisions, Precisions}.
  64389. *
  64390. * @alias czm_encodedCameraPositionMCHigh
  64391. * @glslUniform
  64392. *
  64393. *
  64394. * @example
  64395. * // GLSL declaration
  64396. * uniform vec3 czm_encodedCameraPositionMCHigh;
  64397. *
  64398. * @see czm_encodedCameraPositionMCLow
  64399. * @see czm_modelViewRelativeToEye
  64400. * @see czm_modelViewProjectionRelativeToEye
  64401. */
  64402. czm_encodedCameraPositionMCHigh : new AutomaticUniform({
  64403. size : 1,
  64404. datatype : WebGLConstants.FLOAT_VEC3,
  64405. getValue : function(uniformState) {
  64406. return uniformState.encodedCameraPositionMCHigh;
  64407. }
  64408. }),
  64409. /**
  64410. * An automatic GLSL uniform representing the low bits of the camera position in model
  64411. * coordinates. This is used for GPU RTE to eliminate jittering artifacts when rendering
  64412. * as described in {@link http://blogs.agi.com/insight3d/index.php/2008/09/03/precisions-precisions/|Precisions, Precisions}.
  64413. *
  64414. * @alias czm_encodedCameraPositionMCLow
  64415. * @glslUniform
  64416. *
  64417. *
  64418. * @example
  64419. * // GLSL declaration
  64420. * uniform vec3 czm_encodedCameraPositionMCLow;
  64421. *
  64422. * @see czm_encodedCameraPositionMCHigh
  64423. * @see czm_modelViewRelativeToEye
  64424. * @see czm_modelViewProjectionRelativeToEye
  64425. */
  64426. czm_encodedCameraPositionMCLow : new AutomaticUniform({
  64427. size : 1,
  64428. datatype : WebGLConstants.FLOAT_VEC3,
  64429. getValue : function(uniformState) {
  64430. return uniformState.encodedCameraPositionMCLow;
  64431. }
  64432. }),
  64433. /**
  64434. * An automatic GLSL uniform representing the position of the viewer (camera) in world coordinates.
  64435. *
  64436. * @alias czm_viewerPositionWC
  64437. * @glslUniform
  64438. *
  64439. * @example
  64440. * // GLSL declaration
  64441. * uniform vec3 czm_viewerPositionWC;
  64442. */
  64443. czm_viewerPositionWC : new AutomaticUniform({
  64444. size : 1,
  64445. datatype : WebGLConstants.FLOAT_VEC3,
  64446. getValue : function(uniformState) {
  64447. return Matrix4.getTranslation(uniformState.inverseView, viewerPositionWCScratch);
  64448. }
  64449. }),
  64450. /**
  64451. * An automatic GLSL uniform representing the frame number. This uniform is automatically incremented
  64452. * every frame.
  64453. *
  64454. * @alias czm_frameNumber
  64455. * @glslUniform
  64456. *
  64457. * @example
  64458. * // GLSL declaration
  64459. * uniform float czm_frameNumber;
  64460. */
  64461. czm_frameNumber : new AutomaticUniform({
  64462. size : 1,
  64463. datatype : WebGLConstants.FLOAT,
  64464. getValue : function(uniformState) {
  64465. return uniformState.frameState.frameNumber;
  64466. }
  64467. }),
  64468. /**
  64469. * An automatic GLSL uniform representing the current morph transition time between
  64470. * 2D/Columbus View and 3D, with 0.0 being 2D or Columbus View and 1.0 being 3D.
  64471. *
  64472. * @alias czm_morphTime
  64473. * @glslUniform
  64474. *
  64475. * @example
  64476. * // GLSL declaration
  64477. * uniform float czm_morphTime;
  64478. *
  64479. * // Example
  64480. * vec4 p = czm_columbusViewMorph(position2D, position3D, czm_morphTime);
  64481. */
  64482. czm_morphTime : new AutomaticUniform({
  64483. size : 1,
  64484. datatype : WebGLConstants.FLOAT,
  64485. getValue : function(uniformState) {
  64486. return uniformState.frameState.morphTime;
  64487. }
  64488. }),
  64489. /**
  64490. * An automatic GLSL uniform representing the current {@link SceneMode}, expressed
  64491. * as a float.
  64492. *
  64493. * @alias czm_sceneMode
  64494. * @glslUniform
  64495. *
  64496. *
  64497. * @example
  64498. * // GLSL declaration
  64499. * uniform float czm_sceneMode;
  64500. *
  64501. * // Example
  64502. * if (czm_sceneMode == czm_sceneMode2D)
  64503. * {
  64504. * eyeHeightSq = czm_eyeHeight2D.y;
  64505. * }
  64506. *
  64507. * @see czm_sceneMode2D
  64508. * @see czm_sceneModeColumbusView
  64509. * @see czm_sceneMode3D
  64510. * @see czm_sceneModeMorphing
  64511. */
  64512. czm_sceneMode : new AutomaticUniform({
  64513. size : 1,
  64514. datatype : WebGLConstants.FLOAT,
  64515. getValue : function(uniformState) {
  64516. return uniformState.frameState.mode;
  64517. }
  64518. }),
  64519. /**
  64520. * An automatic GLSL uniform representing the current rendering pass.
  64521. *
  64522. * @alias czm_pass
  64523. * @glslUniform
  64524. *
  64525. * @example
  64526. * // GLSL declaration
  64527. * uniform float czm_pass;
  64528. *
  64529. * // Example
  64530. * if ((czm_pass == czm_passTranslucent) && isOpaque())
  64531. * {
  64532. * gl_Position *= 0.0; // Cull opaque geometry in the translucent pass
  64533. * }
  64534. */
  64535. czm_pass : new AutomaticUniform({
  64536. size : 1,
  64537. datatype : WebGLConstants.FLOAT,
  64538. getValue : function(uniformState) {
  64539. return uniformState.pass;
  64540. }
  64541. }),
  64542. /**
  64543. * An automatic GLSL uniform representing a 3x3 rotation matrix that transforms
  64544. * from True Equator Mean Equinox (TEME) axes to the pseudo-fixed axes at the current scene time.
  64545. *
  64546. * @alias czm_temeToPseudoFixed
  64547. * @glslUniform
  64548. *
  64549. *
  64550. * @example
  64551. * // GLSL declaration
  64552. * uniform mat3 czm_temeToPseudoFixed;
  64553. *
  64554. * // Example
  64555. * vec3 pseudoFixed = czm_temeToPseudoFixed * teme;
  64556. *
  64557. * @see UniformState#temeToPseudoFixedMatrix
  64558. * @see Transforms.computeTemeToPseudoFixedMatrix
  64559. */
  64560. czm_temeToPseudoFixed : new AutomaticUniform({
  64561. size : 1,
  64562. datatype : WebGLConstants.FLOAT_MAT3,
  64563. getValue : function(uniformState) {
  64564. return uniformState.temeToPseudoFixedMatrix;
  64565. }
  64566. }),
  64567. /**
  64568. * An automatic GLSL uniform representing the ratio of canvas coordinate space to canvas pixel space.
  64569. *
  64570. * @alias czm_resolutionScale
  64571. * @glslUniform
  64572. *
  64573. * @example
  64574. * uniform float czm_resolutionScale;
  64575. */
  64576. czm_resolutionScale : new AutomaticUniform({
  64577. size : 1,
  64578. datatype : WebGLConstants.FLOAT,
  64579. getValue : function(uniformState) {
  64580. return uniformState.resolutionScale;
  64581. }
  64582. }),
  64583. /**
  64584. * An automatic GLSL uniform scalar used to mix a color with the fog color based on the distance to the camera.
  64585. *
  64586. * @alias czm_fogDensity
  64587. * @glslUniform
  64588. *
  64589. * @see czm_fog
  64590. */
  64591. czm_fogDensity : new AutomaticUniform({
  64592. size : 1,
  64593. datatype : WebGLConstants.FLOAT,
  64594. getValue : function(uniformState) {
  64595. return uniformState.fogDensity;
  64596. }
  64597. })
  64598. };
  64599. return AutomaticUniforms;
  64600. });
  64601. /*global define*/
  64602. define('Renderer/createUniform',[
  64603. '../Core/Cartesian2',
  64604. '../Core/Cartesian3',
  64605. '../Core/Cartesian4',
  64606. '../Core/Color',
  64607. '../Core/defined',
  64608. '../Core/DeveloperError',
  64609. '../Core/Matrix2',
  64610. '../Core/Matrix3',
  64611. '../Core/Matrix4',
  64612. '../Core/RuntimeError'
  64613. ], function(
  64614. Cartesian2,
  64615. Cartesian3,
  64616. Cartesian4,
  64617. Color,
  64618. defined,
  64619. DeveloperError,
  64620. Matrix2,
  64621. Matrix3,
  64622. Matrix4,
  64623. RuntimeError) {
  64624. 'use strict';
  64625. /**
  64626. * @private
  64627. */
  64628. function createUniform(gl, activeUniform, uniformName, location) {
  64629. switch (activeUniform.type) {
  64630. case gl.FLOAT:
  64631. return new UniformFloat(gl, activeUniform, uniformName, location);
  64632. case gl.FLOAT_VEC2:
  64633. return new UniformFloatVec2(gl, activeUniform, uniformName, location);
  64634. case gl.FLOAT_VEC3:
  64635. return new UniformFloatVec3(gl, activeUniform, uniformName, location);
  64636. case gl.FLOAT_VEC4:
  64637. return new UniformFloatVec4(gl, activeUniform, uniformName, location);
  64638. case gl.SAMPLER_2D:
  64639. case gl.SAMPLER_CUBE:
  64640. return new UniformSampler(gl, activeUniform, uniformName, location);
  64641. case gl.INT:
  64642. case gl.BOOL:
  64643. return new UniformInt(gl, activeUniform, uniformName, location);
  64644. case gl.INT_VEC2:
  64645. case gl.BOOL_VEC2:
  64646. return new UniformIntVec2(gl, activeUniform, uniformName, location);
  64647. case gl.INT_VEC3:
  64648. case gl.BOOL_VEC3:
  64649. return new UniformIntVec3(gl, activeUniform, uniformName, location);
  64650. case gl.INT_VEC4:
  64651. case gl.BOOL_VEC4:
  64652. return new UniformIntVec4(gl, activeUniform, uniformName, location);
  64653. case gl.FLOAT_MAT2:
  64654. return new UniformMat2(gl, activeUniform, uniformName, location);
  64655. case gl.FLOAT_MAT3:
  64656. return new UniformMat3(gl, activeUniform, uniformName, location);
  64657. case gl.FLOAT_MAT4:
  64658. return new UniformMat4(gl, activeUniform, uniformName, location);
  64659. default:
  64660. throw new RuntimeError('Unrecognized uniform type: ' + activeUniform.type + ' for uniform "' + uniformName + '".');
  64661. }
  64662. }
  64663. function UniformFloat(gl, activeUniform, uniformName, location) {
  64664. /**
  64665. * @readonly
  64666. */
  64667. this.name = uniformName;
  64668. this.value = undefined;
  64669. this._value = 0.0;
  64670. this._gl = gl;
  64671. this._location = location;
  64672. }
  64673. UniformFloat.prototype.set = function() {
  64674. if (this.value !== this._value) {
  64675. this._value = this.value;
  64676. this._gl.uniform1f(this._location, this.value);
  64677. }
  64678. };
  64679. ///////////////////////////////////////////////////////////////////////////
  64680. function UniformFloatVec2(gl, activeUniform, uniformName, location) {
  64681. /**
  64682. * @readonly
  64683. */
  64684. this.name = uniformName;
  64685. this.value = undefined;
  64686. this._value = new Cartesian2();
  64687. this._gl = gl;
  64688. this._location = location;
  64689. }
  64690. UniformFloatVec2.prototype.set = function() {
  64691. var v = this.value;
  64692. if (!Cartesian2.equals(v, this._value)) {
  64693. Cartesian2.clone(v, this._value);
  64694. this._gl.uniform2f(this._location, v.x, v.y);
  64695. }
  64696. };
  64697. ///////////////////////////////////////////////////////////////////////////
  64698. function UniformFloatVec3(gl, activeUniform, uniformName, location) {
  64699. /**
  64700. * @readonly
  64701. */
  64702. this.name = uniformName;
  64703. this.value = undefined;
  64704. this._value = undefined;
  64705. this._gl = gl;
  64706. this._location = location;
  64707. }
  64708. UniformFloatVec3.prototype.set = function() {
  64709. var v = this.value;
  64710. if (defined(v.red)) {
  64711. if (!Color.equals(v, this._value)) {
  64712. this._value = Color.clone(v, this._value);
  64713. this._gl.uniform3f(this._location, v.red, v.green, v.blue);
  64714. }
  64715. } else if (defined(v.x)) {
  64716. if (!Cartesian3.equals(v, this._value)) {
  64717. this._value = Cartesian3.clone(v, this._value);
  64718. this._gl.uniform3f(this._location, v.x, v.y, v.z);
  64719. }
  64720. } else {
  64721. throw new DeveloperError('Invalid vec3 value for uniform "' + this._activethis.name + '".');
  64722. }
  64723. };
  64724. ///////////////////////////////////////////////////////////////////////////
  64725. function UniformFloatVec4(gl, activeUniform, uniformName, location) {
  64726. /**
  64727. * @readonly
  64728. */
  64729. this.name = uniformName;
  64730. this.value = undefined;
  64731. this._value = undefined;
  64732. this._gl = gl;
  64733. this._location = location;
  64734. }
  64735. UniformFloatVec4.prototype.set = function() {
  64736. var v = this.value;
  64737. if (defined(v.red)) {
  64738. if (!Color.equals(v, this._value)) {
  64739. this._value = Color.clone(v, this._value);
  64740. this._gl.uniform4f(this._location, v.red, v.green, v.blue, v.alpha);
  64741. }
  64742. } else if (defined(v.x)) {
  64743. if (!Cartesian4.equals(v, this._value)) {
  64744. this._value = Cartesian4.clone(v, this._value);
  64745. this._gl.uniform4f(this._location, v.x, v.y, v.z, v.w);
  64746. }
  64747. } else {
  64748. throw new DeveloperError('Invalid vec4 value for uniform "' + this._activethis.name + '".');
  64749. }
  64750. };
  64751. ///////////////////////////////////////////////////////////////////////////
  64752. function UniformSampler(gl, activeUniform, uniformName, location) {
  64753. /**
  64754. * @readonly
  64755. */
  64756. this.name = uniformName;
  64757. this.value = undefined;
  64758. this._gl = gl;
  64759. this._location = location;
  64760. this.textureUnitIndex = undefined;
  64761. }
  64762. UniformSampler.prototype.set = function() {
  64763. var gl = this._gl;
  64764. gl.activeTexture(gl.TEXTURE0 + this.textureUnitIndex);
  64765. var v = this.value;
  64766. gl.bindTexture(v._target, v._texture);
  64767. };
  64768. UniformSampler.prototype._setSampler = function(textureUnitIndex) {
  64769. this.textureUnitIndex = textureUnitIndex;
  64770. this._gl.uniform1i(this._location, textureUnitIndex);
  64771. return textureUnitIndex + 1;
  64772. };
  64773. ///////////////////////////////////////////////////////////////////////////
  64774. function UniformInt(gl, activeUniform, uniformName, location) {
  64775. /**
  64776. * @readonly
  64777. */
  64778. this.name = uniformName;
  64779. this.value = undefined;
  64780. this._value = 0.0;
  64781. this._gl = gl;
  64782. this._location = location;
  64783. }
  64784. UniformInt.prototype.set = function() {
  64785. if (this.value !== this._value) {
  64786. this._value = this.value;
  64787. this._gl.uniform1i(this._location, this.value);
  64788. }
  64789. };
  64790. ///////////////////////////////////////////////////////////////////////////
  64791. function UniformIntVec2(gl, activeUniform, uniformName, location) {
  64792. /**
  64793. * @readonly
  64794. */
  64795. this.name = uniformName;
  64796. this.value = undefined;
  64797. this._value = new Cartesian2();
  64798. this._gl = gl;
  64799. this._location = location;
  64800. }
  64801. UniformIntVec2.prototype.set = function() {
  64802. var v = this.value;
  64803. if (!Cartesian2.equals(v, this._value)) {
  64804. Cartesian2.clone(v, this._value);
  64805. this._gl.uniform2i(this._location, v.x, v.y);
  64806. }
  64807. };
  64808. ///////////////////////////////////////////////////////////////////////////
  64809. function UniformIntVec3(gl, activeUniform, uniformName, location) {
  64810. /**
  64811. * @readonly
  64812. */
  64813. this.name = uniformName;
  64814. this.value = undefined;
  64815. this._value = new Cartesian3();
  64816. this._gl = gl;
  64817. this._location = location;
  64818. }
  64819. UniformIntVec3.prototype.set = function() {
  64820. var v = this.value;
  64821. if (!Cartesian3.equals(v, this._value)) {
  64822. Cartesian3.clone(v, this._value);
  64823. this._gl.uniform3i(this._location, v.x, v.y, v.z);
  64824. }
  64825. };
  64826. ///////////////////////////////////////////////////////////////////////////
  64827. function UniformIntVec4(gl, activeUniform, uniformName, location) {
  64828. /**
  64829. * @readonly
  64830. */
  64831. this.name = uniformName;
  64832. this.value = undefined;
  64833. this._value = new Cartesian4();
  64834. this._gl = gl;
  64835. this._location = location;
  64836. }
  64837. UniformIntVec4.prototype.set = function() {
  64838. var v = this.value;
  64839. if (!Cartesian4.equals(v, this._value)) {
  64840. Cartesian4.clone(v, this._value);
  64841. this._gl.uniform4i(this._location, v.x, v.y, v.z, v.w);
  64842. }
  64843. };
  64844. ///////////////////////////////////////////////////////////////////////////
  64845. function UniformMat2(gl, activeUniform, uniformName, location) {
  64846. /**
  64847. * @readonly
  64848. */
  64849. this.name = uniformName;
  64850. this.value = undefined;
  64851. this._value = new Float32Array(4);
  64852. this._gl = gl;
  64853. this._location = location;
  64854. }
  64855. UniformMat2.prototype.set = function() {
  64856. if (!Matrix2.equalsArray(this.value, this._value, 0)) {
  64857. Matrix2.toArray(this.value, this._value);
  64858. this._gl.uniformMatrix2fv(this._location, false, this._value);
  64859. }
  64860. };
  64861. ///////////////////////////////////////////////////////////////////////////
  64862. function UniformMat3(gl, activeUniform, uniformName, location) {
  64863. /**
  64864. * @readonly
  64865. */
  64866. this.name = uniformName;
  64867. this.value = undefined;
  64868. this._value = new Float32Array(9);
  64869. this._gl = gl;
  64870. this._location = location;
  64871. }
  64872. UniformMat3.prototype.set = function() {
  64873. if (!Matrix3.equalsArray(this.value, this._value, 0)) {
  64874. Matrix3.toArray(this.value, this._value);
  64875. this._gl.uniformMatrix3fv(this._location, false, this._value);
  64876. }
  64877. };
  64878. ///////////////////////////////////////////////////////////////////////////
  64879. function UniformMat4(gl, activeUniform, uniformName, location) {
  64880. /**
  64881. * @readonly
  64882. */
  64883. this.name = uniformName;
  64884. this.value = undefined;
  64885. this._value = new Float32Array(16);
  64886. this._gl = gl;
  64887. this._location = location;
  64888. }
  64889. UniformMat4.prototype.set = function() {
  64890. if (!Matrix4.equalsArray(this.value, this._value, 0)) {
  64891. Matrix4.toArray(this.value, this._value);
  64892. this._gl.uniformMatrix4fv(this._location, false, this._value);
  64893. }
  64894. };
  64895. return createUniform;
  64896. });
  64897. /*global define*/
  64898. define('Renderer/createUniformArray',[
  64899. '../Core/Cartesian2',
  64900. '../Core/Cartesian3',
  64901. '../Core/Cartesian4',
  64902. '../Core/Color',
  64903. '../Core/defined',
  64904. '../Core/DeveloperError',
  64905. '../Core/Matrix2',
  64906. '../Core/Matrix3',
  64907. '../Core/Matrix4',
  64908. '../Core/RuntimeError'
  64909. ], function(
  64910. Cartesian2,
  64911. Cartesian3,
  64912. Cartesian4,
  64913. Color,
  64914. defined,
  64915. DeveloperError,
  64916. Matrix2,
  64917. Matrix3,
  64918. Matrix4,
  64919. RuntimeError) {
  64920. 'use strict';
  64921. /**
  64922. * @private
  64923. */
  64924. function createUniformArray(gl, activeUniform, uniformName, locations) {
  64925. switch (activeUniform.type) {
  64926. case gl.FLOAT:
  64927. return new UniformArrayFloat(gl, activeUniform, uniformName, locations);
  64928. case gl.FLOAT_VEC2:
  64929. return new UniformArrayFloatVec2(gl, activeUniform, uniformName, locations);
  64930. case gl.FLOAT_VEC3:
  64931. return new UniformArrayFloatVec3(gl, activeUniform, uniformName, locations);
  64932. case gl.FLOAT_VEC4:
  64933. return new UniformArrayFloatVec4(gl, activeUniform, uniformName, locations);
  64934. case gl.SAMPLER_2D:
  64935. case gl.SAMPLER_CUBE:
  64936. return new UniformArraySampler(gl, activeUniform, uniformName, locations);
  64937. case gl.INT:
  64938. case gl.BOOL:
  64939. return new UniformArrayInt(gl, activeUniform, uniformName, locations);
  64940. case gl.INT_VEC2:
  64941. case gl.BOOL_VEC2:
  64942. return new UniformArrayIntVec2(gl, activeUniform, uniformName, locations);
  64943. case gl.INT_VEC3:
  64944. case gl.BOOL_VEC3:
  64945. return new UniformArrayIntVec3(gl, activeUniform, uniformName, locations);
  64946. case gl.INT_VEC4:
  64947. case gl.BOOL_VEC4:
  64948. return new UniformArrayIntVec4(gl, activeUniform, uniformName, locations);
  64949. case gl.FLOAT_MAT2:
  64950. return new UniformArrayMat2(gl, activeUniform, uniformName, locations);
  64951. case gl.FLOAT_MAT3:
  64952. return new UniformArrayMat3(gl, activeUniform, uniformName, locations);
  64953. case gl.FLOAT_MAT4:
  64954. return new UniformArrayMat4(gl, activeUniform, uniformName, locations);
  64955. default:
  64956. throw new RuntimeError('Unrecognized uniform type: ' + activeUniform.type + ' for uniform "' + uniformName + '".');
  64957. }
  64958. }
  64959. function UniformArrayFloat(gl, activeUniform, uniformName, locations) {
  64960. var length = locations.length;
  64961. /**
  64962. * @readonly
  64963. */
  64964. this.name = uniformName;
  64965. this.value = new Array(length);
  64966. this._value = new Float32Array(length);
  64967. this._gl = gl;
  64968. this._location = locations[0];
  64969. }
  64970. UniformArrayFloat.prototype.set = function() {
  64971. var value = this.value;
  64972. var length = value.length;
  64973. var arraybuffer = this._value;
  64974. var changed = false;
  64975. for (var i = 0; i < length; ++i) {
  64976. var v = value[i];
  64977. if (v !== arraybuffer[i]) {
  64978. arraybuffer[i] = v;
  64979. changed = true;
  64980. }
  64981. }
  64982. if (changed) {
  64983. this._gl.uniform1fv(this._location, arraybuffer);
  64984. }
  64985. };
  64986. ///////////////////////////////////////////////////////////////////////////
  64987. function UniformArrayFloatVec2(gl, activeUniform, uniformName, locations) {
  64988. var length = locations.length;
  64989. /**
  64990. * @readonly
  64991. */
  64992. this.name = uniformName;
  64993. this.value = new Array(length);
  64994. this._value = new Float32Array(length * 2);
  64995. this._gl = gl;
  64996. this._location = locations[0];
  64997. }
  64998. UniformArrayFloatVec2.prototype.set = function() {
  64999. var value = this.value;
  65000. var length = value.length;
  65001. var arraybuffer = this._value;
  65002. var changed = false;
  65003. var j = 0;
  65004. for (var i = 0; i < length; ++i) {
  65005. var v = value[i];
  65006. if (!Cartesian2.equalsArray(v, arraybuffer, j)) {
  65007. Cartesian2.pack(v, arraybuffer, j);
  65008. changed = true;
  65009. }
  65010. j += 2;
  65011. }
  65012. if (changed) {
  65013. this._gl.uniform2fv(this._location, arraybuffer);
  65014. }
  65015. };
  65016. ///////////////////////////////////////////////////////////////////////////
  65017. function UniformArrayFloatVec3(gl, activeUniform, uniformName, locations) {
  65018. var length = locations.length;
  65019. /**
  65020. * @readonly
  65021. */
  65022. this.name = uniformName;
  65023. this.value = new Array(length);
  65024. this._value = new Float32Array(length * 3);
  65025. this._gl = gl;
  65026. this._location = locations[0];
  65027. }
  65028. UniformArrayFloatVec3.prototype.set = function() {
  65029. var value = this.value;
  65030. var length = value.length;
  65031. var arraybuffer = this._value;
  65032. var changed = false;
  65033. var j = 0;
  65034. for (var i = 0; i < length; ++i) {
  65035. var v = value[i];
  65036. if (defined(v.red)) {
  65037. if ((v.red !== arraybuffer[j]) ||
  65038. (v.green !== arraybuffer[j + 1]) ||
  65039. (v.blue !== arraybuffer[j + 2])) {
  65040. arraybuffer[j] = v.red;
  65041. arraybuffer[j + 1] = v.green;
  65042. arraybuffer[j + 2] = v.blue;
  65043. changed = true;
  65044. }
  65045. } else if (defined(v.x)) {
  65046. if (!Cartesian3.equalsArray(v, arraybuffer, j)) {
  65047. Cartesian3.pack(v, arraybuffer, j);
  65048. changed = true;
  65049. }
  65050. } else {
  65051. throw new DeveloperError('Invalid vec3 value.');
  65052. }
  65053. j += 3;
  65054. }
  65055. if (changed) {
  65056. this._gl.uniform3fv(this._location, arraybuffer);
  65057. }
  65058. };
  65059. ///////////////////////////////////////////////////////////////////////////
  65060. function UniformArrayFloatVec4(gl, activeUniform, uniformName, locations) {
  65061. var length = locations.length;
  65062. /**
  65063. * @readonly
  65064. */
  65065. this.name = uniformName;
  65066. this.value = new Array(length);
  65067. this._value = new Float32Array(length * 4);
  65068. this._gl = gl;
  65069. this._location = locations[0];
  65070. }
  65071. UniformArrayFloatVec4.prototype.set = function() {
  65072. // PERFORMANCE_IDEA: if it is a common case that only a few elements
  65073. // in a uniform array change, we could use heuristics to determine
  65074. // when it is better to call uniform4f for each element that changed
  65075. // vs. call uniform4fv once to set the entire array. This applies
  65076. // to all uniform array types, not just vec4. We might not care
  65077. // once we have uniform buffers since that will be the fast path.
  65078. // PERFORMANCE_IDEA: Micro-optimization (I bet it works though):
  65079. // As soon as changed is true, break into a separate loop that
  65080. // does the copy without the equals check.
  65081. var value = this.value;
  65082. var length = value.length;
  65083. var arraybuffer = this._value;
  65084. var changed = false;
  65085. var j = 0;
  65086. for (var i = 0; i < length; ++i) {
  65087. var v = value[i];
  65088. if (defined(v.red)) {
  65089. if (!Color.equalsArray(v, arraybuffer, j)) {
  65090. Color.pack(v, arraybuffer, j);
  65091. changed = true;
  65092. }
  65093. } else if (defined(v.x)) {
  65094. if (!Cartesian4.equalsArray(v, arraybuffer, j)) {
  65095. Cartesian4.pack(v, arraybuffer, j);
  65096. changed = true;
  65097. }
  65098. } else {
  65099. throw new DeveloperError('Invalid vec4 value.');
  65100. }
  65101. j += 4;
  65102. }
  65103. if (changed) {
  65104. this._gl.uniform4fv(this._location, arraybuffer);
  65105. }
  65106. };
  65107. ///////////////////////////////////////////////////////////////////////////
  65108. function UniformArraySampler(gl, activeUniform, uniformName, locations) {
  65109. var length = locations.length;
  65110. /**
  65111. * @readonly
  65112. */
  65113. this.name = uniformName;
  65114. this.value = new Array(length);
  65115. this._value = new Float32Array(length);
  65116. this._gl = gl;
  65117. this._locations = locations;
  65118. this.textureUnitIndex = undefined;
  65119. }
  65120. UniformArraySampler.prototype.set = function() {
  65121. var gl = this._gl;
  65122. var textureUnitIndex = gl.TEXTURE0 + this.textureUnitIndex;
  65123. var value = this.value;
  65124. var length = value.length;
  65125. for (var i = 0; i < length; ++i) {
  65126. var v = value[i];
  65127. gl.activeTexture(textureUnitIndex + i);
  65128. gl.bindTexture(v._target, v._texture);
  65129. }
  65130. };
  65131. UniformArraySampler.prototype._setSampler = function(textureUnitIndex) {
  65132. this.textureUnitIndex = textureUnitIndex;
  65133. var locations = this._locations;
  65134. var length = locations.length;
  65135. for (var i = 0; i < length; ++i) {
  65136. var index = textureUnitIndex + i;
  65137. this._gl.uniform1i(locations[i], index);
  65138. }
  65139. return textureUnitIndex + length;
  65140. };
  65141. ///////////////////////////////////////////////////////////////////////////
  65142. function UniformArrayInt(gl, activeUniform, uniformName, locations) {
  65143. var length = locations.length;
  65144. /**
  65145. * @readonly
  65146. */
  65147. this.name = uniformName;
  65148. this.value = new Array(length);
  65149. this._value = new Int32Array(length);
  65150. this._gl = gl;
  65151. this._location = locations[0];
  65152. }
  65153. UniformArrayInt.prototype.set = function() {
  65154. var value = this.value;
  65155. var length = value.length;
  65156. var arraybuffer = this._value;
  65157. var changed = false;
  65158. for (var i = 0; i < length; ++i) {
  65159. var v = value[i];
  65160. if (v !== arraybuffer[i]) {
  65161. arraybuffer[i] = v;
  65162. changed = true;
  65163. }
  65164. }
  65165. if (changed) {
  65166. this._gl.uniform1iv(this._location, arraybuffer);
  65167. }
  65168. };
  65169. ///////////////////////////////////////////////////////////////////////////
  65170. function UniformArrayIntVec2(gl, activeUniform, uniformName, locations) {
  65171. var length = locations.length;
  65172. /**
  65173. * @readonly
  65174. */
  65175. this.name = uniformName;
  65176. this.value = new Array(length);
  65177. this._value = new Int32Array(length * 2);
  65178. this._gl = gl;
  65179. this._location = locations[0];
  65180. }
  65181. UniformArrayIntVec2.prototype.set = function() {
  65182. var value = this.value;
  65183. var length = value.length;
  65184. var arraybuffer = this._value;
  65185. var changed = false;
  65186. var j = 0;
  65187. for (var i = 0; i < length; ++i) {
  65188. var v = value[i];
  65189. if (!Cartesian2.equalsArray(v, arraybuffer, j)) {
  65190. Cartesian2.pack(v, arraybuffer, j);
  65191. changed = true;
  65192. }
  65193. j += 2;
  65194. }
  65195. if (changed) {
  65196. this._gl.uniform2iv(this._location, arraybuffer);
  65197. }
  65198. };
  65199. ///////////////////////////////////////////////////////////////////////////
  65200. function UniformArrayIntVec3(gl, activeUniform, uniformName, locations) {
  65201. var length = locations.length;
  65202. /**
  65203. * @readonly
  65204. */
  65205. this.name = uniformName;
  65206. this.value = new Array(length);
  65207. this._value = new Int32Array(length * 3);
  65208. this._gl = gl;
  65209. this._location = locations[0];
  65210. }
  65211. UniformArrayIntVec3.prototype.set = function() {
  65212. var value = this.value;
  65213. var length = value.length;
  65214. var arraybuffer = this._value;
  65215. var changed = false;
  65216. var j = 0;
  65217. for (var i = 0; i < length; ++i) {
  65218. var v = value[i];
  65219. if (!Cartesian3.equalsArray(v, arraybuffer, j)) {
  65220. Cartesian3.pack(v, arraybuffer, j);
  65221. changed = true;
  65222. }
  65223. j += 3;
  65224. }
  65225. if (changed) {
  65226. this._gl.uniform3iv(this._location, arraybuffer);
  65227. }
  65228. };
  65229. ///////////////////////////////////////////////////////////////////////////
  65230. function UniformArrayIntVec4(gl, activeUniform, uniformName, locations) {
  65231. var length = locations.length;
  65232. /**
  65233. * @readonly
  65234. */
  65235. this.name = uniformName;
  65236. this.value = new Array(length);
  65237. this._value = new Int32Array(length * 4);
  65238. this._gl = gl;
  65239. this._location = locations[0];
  65240. }
  65241. UniformArrayIntVec4.prototype.set = function() {
  65242. var value = this.value;
  65243. var length = value.length;
  65244. var arraybuffer = this._value;
  65245. var changed = false;
  65246. var j = 0;
  65247. for (var i = 0; i < length; ++i) {
  65248. var v = value[i];
  65249. if (!Cartesian4.equalsArray(v, arraybuffer, j)) {
  65250. Cartesian4.pack(v, arraybuffer, j);
  65251. changed = true;
  65252. }
  65253. j += 4;
  65254. }
  65255. if (changed) {
  65256. this._gl.uniform4iv(this._location, arraybuffer);
  65257. }
  65258. };
  65259. ///////////////////////////////////////////////////////////////////////////
  65260. function UniformArrayMat2(gl, activeUniform, uniformName, locations) {
  65261. var length = locations.length;
  65262. /**
  65263. * @readonly
  65264. */
  65265. this.name = uniformName;
  65266. this.value = new Array(length);
  65267. this._value = new Float32Array(length * 4);
  65268. this._gl = gl;
  65269. this._location = locations[0];
  65270. }
  65271. UniformArrayMat2.prototype.set = function() {
  65272. var value = this.value;
  65273. var length = value.length;
  65274. var arraybuffer = this._value;
  65275. var changed = false;
  65276. var j = 0;
  65277. for (var i = 0; i < length; ++i) {
  65278. var v = value[i];
  65279. if (!Matrix2.equalsArray(v, arraybuffer, j)) {
  65280. Matrix2.pack(v, arraybuffer, j);
  65281. changed = true;
  65282. }
  65283. j += 4;
  65284. }
  65285. if (changed) {
  65286. this._gl.uniformMatrix2fv(this._location, false, arraybuffer);
  65287. }
  65288. };
  65289. ///////////////////////////////////////////////////////////////////////////
  65290. function UniformArrayMat3(gl, activeUniform, uniformName, locations) {
  65291. var length = locations.length;
  65292. /**
  65293. * @readonly
  65294. */
  65295. this.name = uniformName;
  65296. this.value = new Array(length);
  65297. this._value = new Float32Array(length * 9);
  65298. this._gl = gl;
  65299. this._location = locations[0];
  65300. }
  65301. UniformArrayMat3.prototype.set = function() {
  65302. var value = this.value;
  65303. var length = value.length;
  65304. var arraybuffer = this._value;
  65305. var changed = false;
  65306. var j = 0;
  65307. for (var i = 0; i < length; ++i) {
  65308. var v = value[i];
  65309. if (!Matrix3.equalsArray(v, arraybuffer, j)) {
  65310. Matrix3.pack(v, arraybuffer, j);
  65311. changed = true;
  65312. }
  65313. j += 9;
  65314. }
  65315. if (changed) {
  65316. this._gl.uniformMatrix3fv(this._location, false, arraybuffer);
  65317. }
  65318. };
  65319. ///////////////////////////////////////////////////////////////////////////
  65320. function UniformArrayMat4(gl, activeUniform, uniformName, locations) {
  65321. var length = locations.length;
  65322. /**
  65323. * @readonly
  65324. */
  65325. this.name = uniformName;
  65326. this.value = new Array(length);
  65327. this._value = new Float32Array(length * 16);
  65328. this._gl = gl;
  65329. this._location = locations[0];
  65330. }
  65331. UniformArrayMat4.prototype.set = function() {
  65332. var value = this.value;
  65333. var length = value.length;
  65334. var arraybuffer = this._value;
  65335. var changed = false;
  65336. var j = 0;
  65337. for (var i = 0; i < length; ++i) {
  65338. var v = value[i];
  65339. if (!Matrix4.equalsArray(v, arraybuffer, j)) {
  65340. Matrix4.pack(v, arraybuffer, j);
  65341. changed = true;
  65342. }
  65343. j += 16;
  65344. }
  65345. if (changed) {
  65346. this._gl.uniformMatrix4fv(this._location, false, arraybuffer);
  65347. }
  65348. };
  65349. return createUniformArray;
  65350. });
  65351. /*global define*/
  65352. define('Renderer/ShaderProgram',[
  65353. '../Core/defaultValue',
  65354. '../Core/defined',
  65355. '../Core/defineProperties',
  65356. '../Core/destroyObject',
  65357. '../Core/DeveloperError',
  65358. '../Core/RuntimeError',
  65359. './AutomaticUniforms',
  65360. './ContextLimits',
  65361. './createUniform',
  65362. './createUniformArray'
  65363. ], function(
  65364. defaultValue,
  65365. defined,
  65366. defineProperties,
  65367. destroyObject,
  65368. DeveloperError,
  65369. RuntimeError,
  65370. AutomaticUniforms,
  65371. ContextLimits,
  65372. createUniform,
  65373. createUniformArray) {
  65374. 'use strict';
  65375. var nextShaderProgramId = 0;
  65376. /**
  65377. * @private
  65378. */
  65379. function ShaderProgram(options) {
  65380. var modifiedFS = handleUniformPrecisionMismatches(options.vertexShaderText, options.fragmentShaderText);
  65381. this._gl = options.gl;
  65382. this._logShaderCompilation = options.logShaderCompilation;
  65383. this._debugShaders = options.debugShaders;
  65384. this._attributeLocations = options.attributeLocations;
  65385. this._program = undefined;
  65386. this._numberOfVertexAttributes = undefined;
  65387. this._vertexAttributes = undefined;
  65388. this._uniformsByName = undefined;
  65389. this._uniforms = undefined;
  65390. this._automaticUniforms = undefined;
  65391. this._manualUniforms = undefined;
  65392. this._duplicateUniformNames = modifiedFS.duplicateUniformNames;
  65393. this._cachedShader = undefined; // Used by ShaderCache
  65394. /**
  65395. * @private
  65396. */
  65397. this.maximumTextureUnitIndex = undefined;
  65398. this._vertexShaderSource = options.vertexShaderSource;
  65399. this._vertexShaderText = options.vertexShaderText;
  65400. this._fragmentShaderSource = options.fragmentShaderSource;
  65401. this._fragmentShaderText = modifiedFS.fragmentShaderText;
  65402. /**
  65403. * @private
  65404. */
  65405. this.id = nextShaderProgramId++;
  65406. }
  65407. ShaderProgram.fromCache = function(options) {
  65408. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  65409. if (!defined(options.context)) {
  65410. throw new DeveloperError('options.context is required.');
  65411. }
  65412. return options.context.shaderCache.getShaderProgram(options);
  65413. };
  65414. ShaderProgram.replaceCache = function(options) {
  65415. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  65416. if (!defined(options.context)) {
  65417. throw new DeveloperError('options.context is required.');
  65418. }
  65419. return options.context.shaderCache.replaceShaderProgram(options);
  65420. };
  65421. defineProperties(ShaderProgram.prototype, {
  65422. /**
  65423. * GLSL source for the shader program's vertex shader.
  65424. * @memberof ShaderProgram.prototype
  65425. *
  65426. * @type {ShaderSource}
  65427. * @readonly
  65428. */
  65429. vertexShaderSource : {
  65430. get : function() {
  65431. return this._vertexShaderSource;
  65432. }
  65433. },
  65434. /**
  65435. * GLSL source for the shader program's fragment shader.
  65436. * @memberof ShaderProgram.prototype
  65437. *
  65438. * @type {ShaderSource}
  65439. * @readonly
  65440. */
  65441. fragmentShaderSource : {
  65442. get : function() {
  65443. return this._fragmentShaderSource;
  65444. }
  65445. },
  65446. vertexAttributes : {
  65447. get : function() {
  65448. initialize(this);
  65449. return this._vertexAttributes;
  65450. }
  65451. },
  65452. numberOfVertexAttributes : {
  65453. get : function() {
  65454. initialize(this);
  65455. return this._numberOfVertexAttributes;
  65456. }
  65457. },
  65458. allUniforms : {
  65459. get : function() {
  65460. initialize(this);
  65461. return this._uniformsByName;
  65462. }
  65463. }
  65464. });
  65465. function extractUniforms(shaderText) {
  65466. var uniformNames = [];
  65467. var uniformLines = shaderText.match(/uniform.*?(?![^{]*})(?=[=\[;])/g);
  65468. if (defined(uniformLines)) {
  65469. var len = uniformLines.length;
  65470. for (var i = 0; i < len; i++) {
  65471. var line = uniformLines[i].trim();
  65472. var name = line.slice(line.lastIndexOf(' ') + 1);
  65473. uniformNames.push(name);
  65474. }
  65475. }
  65476. return uniformNames;
  65477. }
  65478. function handleUniformPrecisionMismatches(vertexShaderText, fragmentShaderText) {
  65479. // If a uniform exists in both the vertex and fragment shader but with different precision qualifiers,
  65480. // give the fragment shader uniform a different name. This fixes shader compilation errors on devices
  65481. // that only support mediump in the fragment shader.
  65482. var duplicateUniformNames = {};
  65483. if (!ContextLimits.highpFloatSupported || !ContextLimits.highpIntSupported) {
  65484. var i, j;
  65485. var uniformName;
  65486. var duplicateName;
  65487. var vertexShaderUniforms = extractUniforms(vertexShaderText);
  65488. var fragmentShaderUniforms = extractUniforms(fragmentShaderText);
  65489. var vertexUniformsCount = vertexShaderUniforms.length;
  65490. var fragmentUniformsCount = fragmentShaderUniforms.length;
  65491. for (i = 0; i < vertexUniformsCount; i++) {
  65492. for (j = 0; j < fragmentUniformsCount; j++) {
  65493. if (vertexShaderUniforms[i] === fragmentShaderUniforms[j]) {
  65494. uniformName = vertexShaderUniforms[i];
  65495. duplicateName = 'czm_mediump_' + uniformName;
  65496. // Update fragmentShaderText with renamed uniforms
  65497. var re = new RegExp(uniformName + '\\b', 'g');
  65498. fragmentShaderText = fragmentShaderText.replace(re, duplicateName);
  65499. duplicateUniformNames[duplicateName] = uniformName;
  65500. }
  65501. }
  65502. }
  65503. }
  65504. return {
  65505. fragmentShaderText : fragmentShaderText,
  65506. duplicateUniformNames : duplicateUniformNames
  65507. };
  65508. }
  65509. var consolePrefix = '[Cesium WebGL] ';
  65510. function createAndLinkProgram(gl, shader) {
  65511. var vsSource = shader._vertexShaderText;
  65512. var fsSource = shader._fragmentShaderText;
  65513. var vertexShader = gl.createShader(gl.VERTEX_SHADER);
  65514. gl.shaderSource(vertexShader, vsSource);
  65515. gl.compileShader(vertexShader);
  65516. var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  65517. gl.shaderSource(fragmentShader, fsSource);
  65518. gl.compileShader(fragmentShader);
  65519. var program = gl.createProgram();
  65520. gl.attachShader(program, vertexShader);
  65521. gl.attachShader(program, fragmentShader);
  65522. gl.deleteShader(vertexShader);
  65523. gl.deleteShader(fragmentShader);
  65524. var attributeLocations = shader._attributeLocations;
  65525. if (defined(attributeLocations)) {
  65526. for ( var attribute in attributeLocations) {
  65527. if (attributeLocations.hasOwnProperty(attribute)) {
  65528. gl.bindAttribLocation(program, attributeLocations[attribute], attribute);
  65529. }
  65530. }
  65531. }
  65532. gl.linkProgram(program);
  65533. var log;
  65534. if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
  65535. var debugShaders = shader._debugShaders;
  65536. // For performance, only check compile errors if there is a linker error.
  65537. if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
  65538. log = gl.getShaderInfoLog(fragmentShader);
  65539. console.error(consolePrefix + 'Fragment shader compile log: ' + log);
  65540. if (defined(debugShaders)) {
  65541. var fragmentSourceTranslation = debugShaders.getTranslatedShaderSource(fragmentShader);
  65542. if (fragmentSourceTranslation !== '') {
  65543. console.error(consolePrefix + 'Translated fragment shader source:\n' + fragmentSourceTranslation);
  65544. } else {
  65545. console.error(consolePrefix + 'Fragment shader translation failed.');
  65546. }
  65547. }
  65548. gl.deleteProgram(program);
  65549. throw new RuntimeError('Fragment shader failed to compile. Compile log: ' + log);
  65550. }
  65551. if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
  65552. log = gl.getShaderInfoLog(vertexShader);
  65553. console.error(consolePrefix + 'Vertex shader compile log: ' + log);
  65554. if (defined(debugShaders)) {
  65555. var vertexSourceTranslation = debugShaders.getTranslatedShaderSource(vertexShader);
  65556. if (vertexSourceTranslation !== '') {
  65557. console.error(consolePrefix + 'Translated vertex shader source:\n' + vertexSourceTranslation);
  65558. } else {
  65559. console.error(consolePrefix + 'Vertex shader translation failed.');
  65560. }
  65561. }
  65562. gl.deleteProgram(program);
  65563. throw new RuntimeError('Vertex shader failed to compile. Compile log: ' + log);
  65564. }
  65565. log = gl.getProgramInfoLog(program);
  65566. console.error(consolePrefix + 'Shader program link log: ' + log);
  65567. if (defined(debugShaders)) {
  65568. console.error(consolePrefix + 'Translated vertex shader source:\n' + debugShaders.getTranslatedShaderSource(vertexShader));
  65569. console.error(consolePrefix + 'Translated fragment shader source:\n' + debugShaders.getTranslatedShaderSource(fragmentShader));
  65570. }
  65571. gl.deleteProgram(program);
  65572. throw new RuntimeError('Program failed to link. Link log: ' + log);
  65573. }
  65574. var logShaderCompilation = shader._logShaderCompilation;
  65575. if (logShaderCompilation) {
  65576. log = gl.getShaderInfoLog(vertexShader);
  65577. if (defined(log) && (log.length > 0)) {
  65578. console.log(consolePrefix + 'Vertex shader compile log: ' + log);
  65579. }
  65580. }
  65581. if (logShaderCompilation) {
  65582. log = gl.getShaderInfoLog(fragmentShader);
  65583. if (defined(log) && (log.length > 0)) {
  65584. console.log(consolePrefix + 'Fragment shader compile log: ' + log);
  65585. }
  65586. }
  65587. if (logShaderCompilation) {
  65588. log = gl.getProgramInfoLog(program);
  65589. if (defined(log) && (log.length > 0)) {
  65590. console.log(consolePrefix + 'Shader program link log: ' + log);
  65591. }
  65592. }
  65593. return program;
  65594. }
  65595. function findVertexAttributes(gl, program, numberOfAttributes) {
  65596. var attributes = {};
  65597. for (var i = 0; i < numberOfAttributes; ++i) {
  65598. var attr = gl.getActiveAttrib(program, i);
  65599. var location = gl.getAttribLocation(program, attr.name);
  65600. attributes[attr.name] = {
  65601. name : attr.name,
  65602. type : attr.type,
  65603. index : location
  65604. };
  65605. }
  65606. return attributes;
  65607. }
  65608. function findUniforms(gl, program) {
  65609. var uniformsByName = {};
  65610. var uniforms = [];
  65611. var samplerUniforms = [];
  65612. var numberOfUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
  65613. for (var i = 0; i < numberOfUniforms; ++i) {
  65614. var activeUniform = gl.getActiveUniform(program, i);
  65615. var suffix = '[0]';
  65616. var uniformName = activeUniform.name.indexOf(suffix, activeUniform.name.length - suffix.length) !== -1 ? activeUniform.name.slice(0, activeUniform.name.length - 3) : activeUniform.name;
  65617. // Ignore GLSL built-in uniforms returned in Firefox.
  65618. if (uniformName.indexOf('gl_') !== 0) {
  65619. if (activeUniform.name.indexOf('[') < 0) {
  65620. // Single uniform
  65621. var location = gl.getUniformLocation(program, uniformName);
  65622. // IE 11.0.9 needs this check since getUniformLocation can return null
  65623. // if the uniform is not active (e.g., it is optimized out). Looks like
  65624. // getActiveUniform() above returns uniforms that are not actually active.
  65625. if (location !== null) {
  65626. var uniform = createUniform(gl, activeUniform, uniformName, location);
  65627. uniformsByName[uniformName] = uniform;
  65628. uniforms.push(uniform);
  65629. if (uniform._setSampler) {
  65630. samplerUniforms.push(uniform);
  65631. }
  65632. }
  65633. } else {
  65634. // Uniform array
  65635. var uniformArray;
  65636. var locations;
  65637. var value;
  65638. var loc;
  65639. // On some platforms - Nexus 4 in Firefox for one - an array of sampler2D ends up being represented
  65640. // as separate uniforms, one for each array element. Check for and handle that case.
  65641. var indexOfBracket = uniformName.indexOf('[');
  65642. if (indexOfBracket >= 0) {
  65643. // We're assuming the array elements show up in numerical order - it seems to be true.
  65644. uniformArray = uniformsByName[uniformName.slice(0, indexOfBracket)];
  65645. // Nexus 4 with Android 4.3 needs this check, because it reports a uniform
  65646. // with the strange name webgl_3467e0265d05c3c1[1] in our globe surface shader.
  65647. if (!defined(uniformArray)) {
  65648. continue;
  65649. }
  65650. locations = uniformArray._locations;
  65651. // On the Nexus 4 in Chrome, we get one uniform per sampler, just like in Firefox,
  65652. // but the size is not 1 like it is in Firefox. So if we push locations here,
  65653. // we'll end up adding too many locations.
  65654. if (locations.length <= 1) {
  65655. value = uniformArray.value;
  65656. loc = gl.getUniformLocation(program, uniformName);
  65657. // Workaround for IE 11.0.9. See above.
  65658. if (loc !== null) {
  65659. locations.push(loc);
  65660. value.push(gl.getUniform(program, loc));
  65661. }
  65662. }
  65663. } else {
  65664. locations = [];
  65665. for (var j = 0; j < activeUniform.size; ++j) {
  65666. loc = gl.getUniformLocation(program, uniformName + '[' + j + ']');
  65667. // Workaround for IE 11.0.9. See above.
  65668. if (loc !== null) {
  65669. locations.push(loc);
  65670. }
  65671. }
  65672. uniformArray = createUniformArray(gl, activeUniform, uniformName, locations);
  65673. uniformsByName[uniformName] = uniformArray;
  65674. uniforms.push(uniformArray);
  65675. if (uniformArray._setSampler) {
  65676. samplerUniforms.push(uniformArray);
  65677. }
  65678. }
  65679. }
  65680. }
  65681. }
  65682. return {
  65683. uniformsByName : uniformsByName,
  65684. uniforms : uniforms,
  65685. samplerUniforms : samplerUniforms
  65686. };
  65687. }
  65688. function partitionUniforms(shader, uniforms) {
  65689. var automaticUniforms = [];
  65690. var manualUniforms = [];
  65691. for (var uniform in uniforms) {
  65692. if (uniforms.hasOwnProperty(uniform)) {
  65693. var uniformObject = uniforms[uniform];
  65694. var uniformName = uniform;
  65695. // if it's a duplicate uniform, use its original name so it is updated correctly
  65696. var duplicateUniform = shader._duplicateUniformNames[uniformName];
  65697. if (defined(duplicateUniform)) {
  65698. uniformObject.name = duplicateUniform;
  65699. uniformName = duplicateUniform;
  65700. }
  65701. var automaticUniform = AutomaticUniforms[uniformName];
  65702. if (defined(automaticUniform)) {
  65703. automaticUniforms.push({
  65704. uniform : uniformObject,
  65705. automaticUniform : automaticUniform
  65706. });
  65707. } else {
  65708. manualUniforms.push(uniformObject);
  65709. }
  65710. }
  65711. }
  65712. return {
  65713. automaticUniforms : automaticUniforms,
  65714. manualUniforms : manualUniforms
  65715. };
  65716. }
  65717. function setSamplerUniforms(gl, program, samplerUniforms) {
  65718. gl.useProgram(program);
  65719. var textureUnitIndex = 0;
  65720. var length = samplerUniforms.length;
  65721. for (var i = 0; i < length; ++i) {
  65722. textureUnitIndex = samplerUniforms[i]._setSampler(textureUnitIndex);
  65723. }
  65724. gl.useProgram(null);
  65725. return textureUnitIndex;
  65726. }
  65727. function initialize(shader) {
  65728. if (defined(shader._program)) {
  65729. return;
  65730. }
  65731. var gl = shader._gl;
  65732. var program = createAndLinkProgram(gl, shader, shader._debugShaders);
  65733. var numberOfVertexAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
  65734. var uniforms = findUniforms(gl, program);
  65735. var partitionedUniforms = partitionUniforms(shader, uniforms.uniformsByName);
  65736. shader._program = program;
  65737. shader._numberOfVertexAttributes = numberOfVertexAttributes;
  65738. shader._vertexAttributes = findVertexAttributes(gl, program, numberOfVertexAttributes);
  65739. shader._uniformsByName = uniforms.uniformsByName;
  65740. shader._uniforms = uniforms.uniforms;
  65741. shader._automaticUniforms = partitionedUniforms.automaticUniforms;
  65742. shader._manualUniforms = partitionedUniforms.manualUniforms;
  65743. shader.maximumTextureUnitIndex = setSamplerUniforms(gl, program, uniforms.samplerUniforms);
  65744. }
  65745. ShaderProgram.prototype._bind = function() {
  65746. initialize(this);
  65747. this._gl.useProgram(this._program);
  65748. };
  65749. ShaderProgram.prototype._setUniforms = function(uniformMap, uniformState, validate) {
  65750. var len;
  65751. var i;
  65752. if (defined(uniformMap)) {
  65753. var manualUniforms = this._manualUniforms;
  65754. len = manualUniforms.length;
  65755. for (i = 0; i < len; ++i) {
  65756. var mu = manualUniforms[i];
  65757. mu.value = uniformMap[mu.name]();
  65758. }
  65759. }
  65760. var automaticUniforms = this._automaticUniforms;
  65761. len = automaticUniforms.length;
  65762. for (i = 0; i < len; ++i) {
  65763. var au = automaticUniforms[i];
  65764. au.uniform.value = au.automaticUniform.getValue(uniformState);
  65765. }
  65766. ///////////////////////////////////////////////////////////////////
  65767. // It appears that assigning the uniform values above and then setting them here
  65768. // (which makes the GL calls) is faster than removing this loop and making
  65769. // the GL calls above. I suspect this is because each GL call pollutes the
  65770. // L2 cache making our JavaScript and the browser/driver ping-pong cache lines.
  65771. var uniforms = this._uniforms;
  65772. len = uniforms.length;
  65773. for (i = 0; i < len; ++i) {
  65774. uniforms[i].set();
  65775. }
  65776. if (validate) {
  65777. var gl = this._gl;
  65778. var program = this._program;
  65779. gl.validateProgram(program);
  65780. if (!gl.getProgramParameter(program, gl.VALIDATE_STATUS)) {
  65781. throw new DeveloperError('Program validation failed. Program info log: ' + gl.getProgramInfoLog(program));
  65782. }
  65783. }
  65784. };
  65785. ShaderProgram.prototype.isDestroyed = function() {
  65786. return false;
  65787. };
  65788. ShaderProgram.prototype.destroy = function() {
  65789. this._cachedShader.cache.releaseShaderProgram(this);
  65790. return undefined;
  65791. };
  65792. ShaderProgram.prototype.finalDestroy = function() {
  65793. this._gl.deleteProgram(this._program);
  65794. return destroyObject(this);
  65795. };
  65796. return ShaderProgram;
  65797. });
  65798. //This file is automatically rebuilt by the Cesium build process.
  65799. /*global define*/
  65800. define('Shaders/Builtin/Constants/degreesPerRadian',[],function() {
  65801. 'use strict';
  65802. return "const float czm_degreesPerRadian = 57.29577951308232;\n\
  65803. ";
  65804. });
  65805. //This file is automatically rebuilt by the Cesium build process.
  65806. /*global define*/
  65807. define('Shaders/Builtin/Constants/depthRange',[],function() {
  65808. 'use strict';
  65809. return "const czm_depthRangeStruct czm_depthRange = czm_depthRangeStruct(0.0, 1.0);\n\
  65810. ";
  65811. });
  65812. //This file is automatically rebuilt by the Cesium build process.
  65813. /*global define*/
  65814. define('Shaders/Builtin/Constants/epsilon1',[],function() {
  65815. 'use strict';
  65816. return "const float czm_epsilon1 = 0.1;\n\
  65817. ";
  65818. });
  65819. //This file is automatically rebuilt by the Cesium build process.
  65820. /*global define*/
  65821. define('Shaders/Builtin/Constants/epsilon2',[],function() {
  65822. 'use strict';
  65823. return "const float czm_epsilon2 = 0.01;\n\
  65824. ";
  65825. });
  65826. //This file is automatically rebuilt by the Cesium build process.
  65827. /*global define*/
  65828. define('Shaders/Builtin/Constants/epsilon3',[],function() {
  65829. 'use strict';
  65830. return "const float czm_epsilon3 = 0.001;\n\
  65831. ";
  65832. });
  65833. //This file is automatically rebuilt by the Cesium build process.
  65834. /*global define*/
  65835. define('Shaders/Builtin/Constants/epsilon4',[],function() {
  65836. 'use strict';
  65837. return "const float czm_epsilon4 = 0.0001;\n\
  65838. ";
  65839. });
  65840. //This file is automatically rebuilt by the Cesium build process.
  65841. /*global define*/
  65842. define('Shaders/Builtin/Constants/epsilon5',[],function() {
  65843. 'use strict';
  65844. return "const float czm_epsilon5 = 0.00001;\n\
  65845. ";
  65846. });
  65847. //This file is automatically rebuilt by the Cesium build process.
  65848. /*global define*/
  65849. define('Shaders/Builtin/Constants/epsilon6',[],function() {
  65850. 'use strict';
  65851. return "const float czm_epsilon6 = 0.000001;\n\
  65852. ";
  65853. });
  65854. //This file is automatically rebuilt by the Cesium build process.
  65855. /*global define*/
  65856. define('Shaders/Builtin/Constants/epsilon7',[],function() {
  65857. 'use strict';
  65858. return "const float czm_epsilon7 = 0.0000001;\n\
  65859. ";
  65860. });
  65861. //This file is automatically rebuilt by the Cesium build process.
  65862. /*global define*/
  65863. define('Shaders/Builtin/Constants/infinity',[],function() {
  65864. 'use strict';
  65865. return "const float czm_infinity = 5906376272000.0;\n\
  65866. ";
  65867. });
  65868. //This file is automatically rebuilt by the Cesium build process.
  65869. /*global define*/
  65870. define('Shaders/Builtin/Constants/oneOverPi',[],function() {
  65871. 'use strict';
  65872. return "const float czm_oneOverPi = 0.3183098861837907;\n\
  65873. ";
  65874. });
  65875. //This file is automatically rebuilt by the Cesium build process.
  65876. /*global define*/
  65877. define('Shaders/Builtin/Constants/oneOverTwoPi',[],function() {
  65878. 'use strict';
  65879. return "const float czm_oneOverTwoPi = 0.15915494309189535;\n\
  65880. ";
  65881. });
  65882. //This file is automatically rebuilt by the Cesium build process.
  65883. /*global define*/
  65884. define('Shaders/Builtin/Constants/passCompute',[],function() {
  65885. 'use strict';
  65886. return "const float czm_passCompute = 1.0;\n\
  65887. ";
  65888. });
  65889. //This file is automatically rebuilt by the Cesium build process.
  65890. /*global define*/
  65891. define('Shaders/Builtin/Constants/passEnvironment',[],function() {
  65892. 'use strict';
  65893. return "const float czm_passEnvironment = 0.0;\n\
  65894. ";
  65895. });
  65896. //This file is automatically rebuilt by the Cesium build process.
  65897. /*global define*/
  65898. define('Shaders/Builtin/Constants/passGlobe',[],function() {
  65899. 'use strict';
  65900. return "const float czm_passGlobe = 2.0;\n\
  65901. ";
  65902. });
  65903. //This file is automatically rebuilt by the Cesium build process.
  65904. /*global define*/
  65905. define('Shaders/Builtin/Constants/passGround',[],function() {
  65906. 'use strict';
  65907. return "const float czm_passGround = 3.0;\n\
  65908. ";
  65909. });
  65910. //This file is automatically rebuilt by the Cesium build process.
  65911. /*global define*/
  65912. define('Shaders/Builtin/Constants/passOpaque',[],function() {
  65913. 'use strict';
  65914. return "const float czm_passOpaque = 4.0;\n\
  65915. ";
  65916. });
  65917. //This file is automatically rebuilt by the Cesium build process.
  65918. /*global define*/
  65919. define('Shaders/Builtin/Constants/passOverlay',[],function() {
  65920. 'use strict';
  65921. return "const float czm_passOverlay = 6.0;\n\
  65922. ";
  65923. });
  65924. //This file is automatically rebuilt by the Cesium build process.
  65925. /*global define*/
  65926. define('Shaders/Builtin/Constants/passTranslucent',[],function() {
  65927. 'use strict';
  65928. return "const float czm_passTranslucent = 5.0;\n\
  65929. ";
  65930. });
  65931. //This file is automatically rebuilt by the Cesium build process.
  65932. /*global define*/
  65933. define('Shaders/Builtin/Constants/pi',[],function() {
  65934. 'use strict';
  65935. return "const float czm_pi = 3.141592653589793;\n\
  65936. ";
  65937. });
  65938. //This file is automatically rebuilt by the Cesium build process.
  65939. /*global define*/
  65940. define('Shaders/Builtin/Constants/piOverFour',[],function() {
  65941. 'use strict';
  65942. return "const float czm_piOverFour = 0.7853981633974483;\n\
  65943. ";
  65944. });
  65945. //This file is automatically rebuilt by the Cesium build process.
  65946. /*global define*/
  65947. define('Shaders/Builtin/Constants/piOverSix',[],function() {
  65948. 'use strict';
  65949. return "const float czm_piOverSix = 0.5235987755982988;\n\
  65950. ";
  65951. });
  65952. //This file is automatically rebuilt by the Cesium build process.
  65953. /*global define*/
  65954. define('Shaders/Builtin/Constants/piOverThree',[],function() {
  65955. 'use strict';
  65956. return "const float czm_piOverThree = 1.0471975511965976;\n\
  65957. ";
  65958. });
  65959. //This file is automatically rebuilt by the Cesium build process.
  65960. /*global define*/
  65961. define('Shaders/Builtin/Constants/piOverTwo',[],function() {
  65962. 'use strict';
  65963. return "const float czm_piOverTwo = 1.5707963267948966;\n\
  65964. ";
  65965. });
  65966. //This file is automatically rebuilt by the Cesium build process.
  65967. /*global define*/
  65968. define('Shaders/Builtin/Constants/radiansPerDegree',[],function() {
  65969. 'use strict';
  65970. return "const float czm_radiansPerDegree = 0.017453292519943295;\n\
  65971. ";
  65972. });
  65973. //This file is automatically rebuilt by the Cesium build process.
  65974. /*global define*/
  65975. define('Shaders/Builtin/Constants/sceneMode2D',[],function() {
  65976. 'use strict';
  65977. return "const float czm_sceneMode2D = 2.0;\n\
  65978. ";
  65979. });
  65980. //This file is automatically rebuilt by the Cesium build process.
  65981. /*global define*/
  65982. define('Shaders/Builtin/Constants/sceneMode3D',[],function() {
  65983. 'use strict';
  65984. return "const float czm_sceneMode3D = 3.0;\n\
  65985. ";
  65986. });
  65987. //This file is automatically rebuilt by the Cesium build process.
  65988. /*global define*/
  65989. define('Shaders/Builtin/Constants/sceneModeColumbusView',[],function() {
  65990. 'use strict';
  65991. return "const float czm_sceneModeColumbusView = 1.0;\n\
  65992. ";
  65993. });
  65994. //This file is automatically rebuilt by the Cesium build process.
  65995. /*global define*/
  65996. define('Shaders/Builtin/Constants/sceneModeMorphing',[],function() {
  65997. 'use strict';
  65998. return "const float czm_sceneModeMorphing = 0.0;\n\
  65999. ";
  66000. });
  66001. //This file is automatically rebuilt by the Cesium build process.
  66002. /*global define*/
  66003. define('Shaders/Builtin/Constants/solarRadius',[],function() {
  66004. 'use strict';
  66005. return "const float czm_solarRadius = 695500000.0;\n\
  66006. ";
  66007. });
  66008. //This file is automatically rebuilt by the Cesium build process.
  66009. /*global define*/
  66010. define('Shaders/Builtin/Constants/threePiOver2',[],function() {
  66011. 'use strict';
  66012. return "const float czm_threePiOver2 = 4.71238898038469;\n\
  66013. ";
  66014. });
  66015. //This file is automatically rebuilt by the Cesium build process.
  66016. /*global define*/
  66017. define('Shaders/Builtin/Constants/twoPi',[],function() {
  66018. 'use strict';
  66019. return "const float czm_twoPi = 6.283185307179586;\n\
  66020. ";
  66021. });
  66022. //This file is automatically rebuilt by the Cesium build process.
  66023. /*global define*/
  66024. define('Shaders/Builtin/Constants/webMercatorMaxLatitude',[],function() {
  66025. 'use strict';
  66026. return "const float czm_webMercatorMaxLatitude = 1.4844222297453324;\n\
  66027. ";
  66028. });
  66029. //This file is automatically rebuilt by the Cesium build process.
  66030. /*global define*/
  66031. define('Shaders/Builtin/Structs/depthRangeStruct',[],function() {
  66032. 'use strict';
  66033. return "struct czm_depthRangeStruct\n\
  66034. {\n\
  66035. float near;\n\
  66036. float far;\n\
  66037. };\n\
  66038. ";
  66039. });
  66040. //This file is automatically rebuilt by the Cesium build process.
  66041. /*global define*/
  66042. define('Shaders/Builtin/Structs/ellipsoid',[],function() {
  66043. 'use strict';
  66044. return "struct czm_ellipsoid\n\
  66045. {\n\
  66046. vec3 center;\n\
  66047. vec3 radii;\n\
  66048. vec3 inverseRadii;\n\
  66049. vec3 inverseRadiiSquared;\n\
  66050. };\n\
  66051. ";
  66052. });
  66053. //This file is automatically rebuilt by the Cesium build process.
  66054. /*global define*/
  66055. define('Shaders/Builtin/Structs/material',[],function() {
  66056. 'use strict';
  66057. return "struct czm_material\n\
  66058. {\n\
  66059. vec3 diffuse;\n\
  66060. float specular;\n\
  66061. float shininess;\n\
  66062. vec3 normal;\n\
  66063. vec3 emission;\n\
  66064. float alpha;\n\
  66065. };\n\
  66066. ";
  66067. });
  66068. //This file is automatically rebuilt by the Cesium build process.
  66069. /*global define*/
  66070. define('Shaders/Builtin/Structs/materialInput',[],function() {
  66071. 'use strict';
  66072. return "struct czm_materialInput\n\
  66073. {\n\
  66074. float s;\n\
  66075. vec2 st;\n\
  66076. vec3 str;\n\
  66077. vec3 normalEC;\n\
  66078. mat3 tangentToEyeMatrix;\n\
  66079. vec3 positionToEyeEC;\n\
  66080. };\n\
  66081. ";
  66082. });
  66083. //This file is automatically rebuilt by the Cesium build process.
  66084. /*global define*/
  66085. define('Shaders/Builtin/Structs/ray',[],function() {
  66086. 'use strict';
  66087. return "struct czm_ray\n\
  66088. {\n\
  66089. vec3 origin;\n\
  66090. vec3 direction;\n\
  66091. };\n\
  66092. ";
  66093. });
  66094. //This file is automatically rebuilt by the Cesium build process.
  66095. /*global define*/
  66096. define('Shaders/Builtin/Structs/raySegment',[],function() {
  66097. 'use strict';
  66098. return "struct czm_raySegment\n\
  66099. {\n\
  66100. float start;\n\
  66101. float stop;\n\
  66102. };\n\
  66103. const czm_raySegment czm_emptyRaySegment = czm_raySegment(-czm_infinity, -czm_infinity);\n\
  66104. const czm_raySegment czm_fullRaySegment = czm_raySegment(0.0, czm_infinity);\n\
  66105. ";
  66106. });
  66107. //This file is automatically rebuilt by the Cesium build process.
  66108. /*global define*/
  66109. define('Shaders/Builtin/Structs/shadowParameters',[],function() {
  66110. 'use strict';
  66111. return "struct czm_shadowParameters\n\
  66112. {\n\
  66113. #ifdef USE_CUBE_MAP_SHADOW\n\
  66114. vec3 texCoords;\n\
  66115. #else\n\
  66116. vec2 texCoords;\n\
  66117. #endif\n\
  66118. float depthBias;\n\
  66119. float depth;\n\
  66120. float nDotL;\n\
  66121. vec2 texelStepSize;\n\
  66122. float normalShadingSmooth;\n\
  66123. float darkness;\n\
  66124. };\n\
  66125. ";
  66126. });
  66127. //This file is automatically rebuilt by the Cesium build process.
  66128. /*global define*/
  66129. define('Shaders/Builtin/Functions/alphaWeight',[],function() {
  66130. 'use strict';
  66131. return "float czm_alphaWeight(float a)\n\
  66132. {\n\
  66133. float z;\n\
  66134. if (czm_sceneMode != czm_sceneMode2D)\n\
  66135. {\n\
  66136. float x = 2.0 * (gl_FragCoord.x - czm_viewport.x) / czm_viewport.z - 1.0;\n\
  66137. float y = 2.0 * (gl_FragCoord.y - czm_viewport.y) / czm_viewport.w - 1.0;\n\
  66138. z = (gl_FragCoord.z - czm_viewportTransformation[3][2]) / czm_viewportTransformation[2][2];\n\
  66139. vec4 q = vec4(x, y, z, 0.0);\n\
  66140. q /= gl_FragCoord.w;\n\
  66141. z = (czm_inverseProjectionOIT * q).z;\n\
  66142. }\n\
  66143. else\n\
  66144. {\n\
  66145. z = gl_FragCoord.z * (czm_currentFrustum.y - czm_currentFrustum.x) + czm_currentFrustum.x;\n\
  66146. }\n\
  66147. return pow(a + 0.01, 4.0) + max(1e-2, min(3.0 * 1e3, 100.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0))));\n\
  66148. }\n\
  66149. ";
  66150. });
  66151. //This file is automatically rebuilt by the Cesium build process.
  66152. /*global define*/
  66153. define('Shaders/Builtin/Functions/antialias',[],function() {
  66154. 'use strict';
  66155. return "vec4 czm_antialias(vec4 color1, vec4 color2, vec4 currentColor, float dist, float fuzzFactor)\n\
  66156. {\n\
  66157. float val1 = clamp(dist / fuzzFactor, 0.0, 1.0);\n\
  66158. float val2 = clamp((dist - 0.5) / fuzzFactor, 0.0, 1.0);\n\
  66159. val1 = val1 * (1.0 - val2);\n\
  66160. val1 = val1 * val1 * (3.0 - (2.0 * val1));\n\
  66161. val1 = pow(val1, 0.5);\n\
  66162. vec4 midColor = (color1 + color2) * 0.5;\n\
  66163. return mix(midColor, currentColor, val1);\n\
  66164. }\n\
  66165. vec4 czm_antialias(vec4 color1, vec4 color2, vec4 currentColor, float dist)\n\
  66166. {\n\
  66167. return czm_antialias(color1, color2, currentColor, dist, 0.1);\n\
  66168. }\n\
  66169. ";
  66170. });
  66171. //This file is automatically rebuilt by the Cesium build process.
  66172. /*global define*/
  66173. define('Shaders/Builtin/Functions/cascadeColor',[],function() {
  66174. 'use strict';
  66175. return "vec4 czm_cascadeColor(vec4 weights)\n\
  66176. {\n\
  66177. return vec4(1.0, 0.0, 0.0, 1.0) * weights.x +\n\
  66178. vec4(0.0, 1.0, 0.0, 1.0) * weights.y +\n\
  66179. vec4(0.0, 0.0, 1.0, 1.0) * weights.z +\n\
  66180. vec4(1.0, 0.0, 1.0, 1.0) * weights.w;\n\
  66181. }\n\
  66182. ";
  66183. });
  66184. //This file is automatically rebuilt by the Cesium build process.
  66185. /*global define*/
  66186. define('Shaders/Builtin/Functions/cascadeDistance',[],function() {
  66187. 'use strict';
  66188. return "uniform vec4 shadowMap_cascadeDistances;\n\
  66189. float czm_cascadeDistance(vec4 weights)\n\
  66190. {\n\
  66191. return dot(shadowMap_cascadeDistances, weights);\n\
  66192. }\n\
  66193. ";
  66194. });
  66195. //This file is automatically rebuilt by the Cesium build process.
  66196. /*global define*/
  66197. define('Shaders/Builtin/Functions/cascadeMatrix',[],function() {
  66198. 'use strict';
  66199. return "uniform mat4 shadowMap_cascadeMatrices[4];\n\
  66200. mat4 czm_cascadeMatrix(vec4 weights)\n\
  66201. {\n\
  66202. return shadowMap_cascadeMatrices[0] * weights.x +\n\
  66203. shadowMap_cascadeMatrices[1] * weights.y +\n\
  66204. shadowMap_cascadeMatrices[2] * weights.z +\n\
  66205. shadowMap_cascadeMatrices[3] * weights.w;\n\
  66206. }\n\
  66207. ";
  66208. });
  66209. //This file is automatically rebuilt by the Cesium build process.
  66210. /*global define*/
  66211. define('Shaders/Builtin/Functions/cascadeWeights',[],function() {
  66212. 'use strict';
  66213. return "uniform vec4 shadowMap_cascadeSplits[2];\n\
  66214. vec4 czm_cascadeWeights(float depthEye)\n\
  66215. {\n\
  66216. vec4 near = step(shadowMap_cascadeSplits[0], vec4(depthEye));\n\
  66217. vec4 far = step(depthEye, shadowMap_cascadeSplits[1]);\n\
  66218. return near * far;\n\
  66219. }\n\
  66220. ";
  66221. });
  66222. //This file is automatically rebuilt by the Cesium build process.
  66223. /*global define*/
  66224. define('Shaders/Builtin/Functions/columbusViewMorph',[],function() {
  66225. 'use strict';
  66226. return "vec4 czm_columbusViewMorph(vec4 position2D, vec4 position3D, float time)\n\
  66227. {\n\
  66228. vec3 p = mix(position2D.xyz, position3D.xyz, time);\n\
  66229. return vec4(p, 1.0);\n\
  66230. }\n\
  66231. ";
  66232. });
  66233. //This file is automatically rebuilt by the Cesium build process.
  66234. /*global define*/
  66235. define('Shaders/Builtin/Functions/computePosition',[],function() {
  66236. 'use strict';
  66237. return "vec4 czm_computePosition();\n\
  66238. ";
  66239. });
  66240. //This file is automatically rebuilt by the Cesium build process.
  66241. /*global define*/
  66242. define('Shaders/Builtin/Functions/cosineAndSine',[],function() {
  66243. 'use strict';
  66244. return "vec2 cordic(float angle)\n\
  66245. {\n\
  66246. vec2 vector = vec2(6.0725293500888267e-1, 0.0);\n\
  66247. float sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66248. mat2 rotation = mat2(1.0, sense, -sense, 1.0);\n\
  66249. vector = rotation * vector;\n\
  66250. angle -= sense * 7.8539816339744828e-1;\n\
  66251. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66252. float factor = sense * 5.0e-1;\n\
  66253. rotation[0][1] = factor;\n\
  66254. rotation[1][0] = -factor;\n\
  66255. vector = rotation * vector;\n\
  66256. angle -= sense * 4.6364760900080609e-1;\n\
  66257. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66258. factor = sense * 2.5e-1;\n\
  66259. rotation[0][1] = factor;\n\
  66260. rotation[1][0] = -factor;\n\
  66261. vector = rotation * vector;\n\
  66262. angle -= sense * 2.4497866312686414e-1;\n\
  66263. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66264. factor = sense * 1.25e-1;\n\
  66265. rotation[0][1] = factor;\n\
  66266. rotation[1][0] = -factor;\n\
  66267. vector = rotation * vector;\n\
  66268. angle -= sense * 1.2435499454676144e-1;\n\
  66269. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66270. factor = sense * 6.25e-2;\n\
  66271. rotation[0][1] = factor;\n\
  66272. rotation[1][0] = -factor;\n\
  66273. vector = rotation * vector;\n\
  66274. angle -= sense * 6.2418809995957350e-2;\n\
  66275. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66276. factor = sense * 3.125e-2;\n\
  66277. rotation[0][1] = factor;\n\
  66278. rotation[1][0] = -factor;\n\
  66279. vector = rotation * vector;\n\
  66280. angle -= sense * 3.1239833430268277e-2;\n\
  66281. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66282. factor = sense * 1.5625e-2;\n\
  66283. rotation[0][1] = factor;\n\
  66284. rotation[1][0] = -factor;\n\
  66285. vector = rotation * vector;\n\
  66286. angle -= sense * 1.5623728620476831e-2;\n\
  66287. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66288. factor = sense * 7.8125e-3;\n\
  66289. rotation[0][1] = factor;\n\
  66290. rotation[1][0] = -factor;\n\
  66291. vector = rotation * vector;\n\
  66292. angle -= sense * 7.8123410601011111e-3;\n\
  66293. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66294. factor = sense * 3.90625e-3;\n\
  66295. rotation[0][1] = factor;\n\
  66296. rotation[1][0] = -factor;\n\
  66297. vector = rotation * vector;\n\
  66298. angle -= sense * 3.9062301319669718e-3;\n\
  66299. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66300. factor = sense * 1.953125e-3;\n\
  66301. rotation[0][1] = factor;\n\
  66302. rotation[1][0] = -factor;\n\
  66303. vector = rotation * vector;\n\
  66304. angle -= sense * 1.9531225164788188e-3;\n\
  66305. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66306. factor = sense * 9.765625e-4;\n\
  66307. rotation[0][1] = factor;\n\
  66308. rotation[1][0] = -factor;\n\
  66309. vector = rotation * vector;\n\
  66310. angle -= sense * 9.7656218955931946e-4;\n\
  66311. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66312. factor = sense * 4.8828125e-4;\n\
  66313. rotation[0][1] = factor;\n\
  66314. rotation[1][0] = -factor;\n\
  66315. vector = rotation * vector;\n\
  66316. angle -= sense * 4.8828121119489829e-4;\n\
  66317. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66318. factor = sense * 2.44140625e-4;\n\
  66319. rotation[0][1] = factor;\n\
  66320. rotation[1][0] = -factor;\n\
  66321. vector = rotation * vector;\n\
  66322. angle -= sense * 2.4414062014936177e-4;\n\
  66323. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66324. factor = sense * 1.220703125e-4;\n\
  66325. rotation[0][1] = factor;\n\
  66326. rotation[1][0] = -factor;\n\
  66327. vector = rotation * vector;\n\
  66328. angle -= sense * 1.2207031189367021e-4;\n\
  66329. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66330. factor = sense * 6.103515625e-5;\n\
  66331. rotation[0][1] = factor;\n\
  66332. rotation[1][0] = -factor;\n\
  66333. vector = rotation * vector;\n\
  66334. angle -= sense * 6.1035156174208773e-5;\n\
  66335. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66336. factor = sense * 3.0517578125e-5;\n\
  66337. rotation[0][1] = factor;\n\
  66338. rotation[1][0] = -factor;\n\
  66339. vector = rotation * vector;\n\
  66340. angle -= sense * 3.0517578115526096e-5;\n\
  66341. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66342. factor = sense * 1.52587890625e-5;\n\
  66343. rotation[0][1] = factor;\n\
  66344. rotation[1][0] = -factor;\n\
  66345. vector = rotation * vector;\n\
  66346. angle -= sense * 1.5258789061315762e-5;\n\
  66347. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66348. factor = sense * 7.62939453125e-6;\n\
  66349. rotation[0][1] = factor;\n\
  66350. rotation[1][0] = -factor;\n\
  66351. vector = rotation * vector;\n\
  66352. angle -= sense * 7.6293945311019700e-6;\n\
  66353. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66354. factor = sense * 3.814697265625e-6;\n\
  66355. rotation[0][1] = factor;\n\
  66356. rotation[1][0] = -factor;\n\
  66357. vector = rotation * vector;\n\
  66358. angle -= sense * 3.8146972656064961e-6;\n\
  66359. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66360. factor = sense * 1.9073486328125e-6;\n\
  66361. rotation[0][1] = factor;\n\
  66362. rotation[1][0] = -factor;\n\
  66363. vector = rotation * vector;\n\
  66364. angle -= sense * 1.9073486328101870e-6;\n\
  66365. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66366. factor = sense * 9.5367431640625e-7;\n\
  66367. rotation[0][1] = factor;\n\
  66368. rotation[1][0] = -factor;\n\
  66369. vector = rotation * vector;\n\
  66370. angle -= sense * 9.5367431640596084e-7;\n\
  66371. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66372. factor = sense * 4.76837158203125e-7;\n\
  66373. rotation[0][1] = factor;\n\
  66374. rotation[1][0] = -factor;\n\
  66375. vector = rotation * vector;\n\
  66376. angle -= sense * 4.7683715820308884e-7;\n\
  66377. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66378. factor = sense * 2.384185791015625e-7;\n\
  66379. rotation[0][1] = factor;\n\
  66380. rotation[1][0] = -factor;\n\
  66381. vector = rotation * vector;\n\
  66382. angle -= sense * 2.3841857910155797e-7;\n\
  66383. sense = (angle < 0.0) ? -1.0 : 1.0;\n\
  66384. factor = sense * 1.1920928955078125e-7;\n\
  66385. rotation[0][1] = factor;\n\
  66386. rotation[1][0] = -factor;\n\
  66387. vector = rotation * vector;\n\
  66388. return vector;\n\
  66389. }\n\
  66390. vec2 czm_cosineAndSine(float angle)\n\
  66391. {\n\
  66392. if (angle < -czm_piOverTwo || angle > czm_piOverTwo)\n\
  66393. {\n\
  66394. if (angle < 0.0)\n\
  66395. {\n\
  66396. return -cordic(angle + czm_pi);\n\
  66397. }\n\
  66398. else\n\
  66399. {\n\
  66400. return -cordic(angle - czm_pi);\n\
  66401. }\n\
  66402. }\n\
  66403. else\n\
  66404. {\n\
  66405. return cordic(angle);\n\
  66406. }\n\
  66407. }\n\
  66408. ";
  66409. });
  66410. //This file is automatically rebuilt by the Cesium build process.
  66411. /*global define*/
  66412. define('Shaders/Builtin/Functions/decompressTextureCoordinates',[],function() {
  66413. 'use strict';
  66414. return "vec2 czm_decompressTextureCoordinates(float encoded)\n\
  66415. {\n\
  66416. float temp = encoded / 4096.0;\n\
  66417. float xZeroTo4095 = floor(temp);\n\
  66418. float stx = xZeroTo4095 / 4095.0;\n\
  66419. float sty = (encoded - xZeroTo4095 * 4096.0) / 4095.0;\n\
  66420. return vec2(stx, sty);\n\
  66421. }\n\
  66422. ";
  66423. });
  66424. //This file is automatically rebuilt by the Cesium build process.
  66425. /*global define*/
  66426. define('Shaders/Builtin/Functions/eastNorthUpToEyeCoordinates',[],function() {
  66427. 'use strict';
  66428. return "mat3 czm_eastNorthUpToEyeCoordinates(vec3 positionMC, vec3 normalEC)\n\
  66429. {\n\
  66430. vec3 tangentMC = normalize(vec3(-positionMC.y, positionMC.x, 0.0));\n\
  66431. vec3 tangentEC = normalize(czm_normal3D * tangentMC);\n\
  66432. vec3 bitangentEC = normalize(cross(normalEC, tangentEC));\n\
  66433. return mat3(\n\
  66434. tangentEC.x, tangentEC.y, tangentEC.z,\n\
  66435. bitangentEC.x, bitangentEC.y, bitangentEC.z,\n\
  66436. normalEC.x, normalEC.y, normalEC.z);\n\
  66437. }\n\
  66438. ";
  66439. });
  66440. //This file is automatically rebuilt by the Cesium build process.
  66441. /*global define*/
  66442. define('Shaders/Builtin/Functions/ellipsoidContainsPoint',[],function() {
  66443. 'use strict';
  66444. return "bool czm_ellipsoidContainsPoint(czm_ellipsoid ellipsoid, vec3 point)\n\
  66445. {\n\
  66446. vec3 scaled = ellipsoid.inverseRadii * (czm_inverseModelView * vec4(point, 1.0)).xyz;\n\
  66447. return (dot(scaled, scaled) <= 1.0);\n\
  66448. }\n\
  66449. ";
  66450. });
  66451. //This file is automatically rebuilt by the Cesium build process.
  66452. /*global define*/
  66453. define('Shaders/Builtin/Functions/ellipsoidNew',[],function() {
  66454. 'use strict';
  66455. return "czm_ellipsoid czm_ellipsoidNew(vec3 center, vec3 radii)\n\
  66456. {\n\
  66457. vec3 inverseRadii = vec3(1.0 / radii.x, 1.0 / radii.y, 1.0 / radii.z);\n\
  66458. vec3 inverseRadiiSquared = inverseRadii * inverseRadii;\n\
  66459. czm_ellipsoid temp = czm_ellipsoid(center, radii, inverseRadii, inverseRadiiSquared);\n\
  66460. return temp;\n\
  66461. }\n\
  66462. ";
  66463. });
  66464. //This file is automatically rebuilt by the Cesium build process.
  66465. /*global define*/
  66466. define('Shaders/Builtin/Functions/ellipsoidWgs84TextureCoordinates',[],function() {
  66467. 'use strict';
  66468. return "vec2 czm_ellipsoidWgs84TextureCoordinates(vec3 normal)\n\
  66469. {\n\
  66470. return vec2(atan(normal.y, normal.x) * czm_oneOverTwoPi + 0.5, asin(normal.z) * czm_oneOverPi + 0.5);\n\
  66471. }\n\
  66472. ";
  66473. });
  66474. //This file is automatically rebuilt by the Cesium build process.
  66475. /*global define*/
  66476. define('Shaders/Builtin/Functions/equalsEpsilon',[],function() {
  66477. 'use strict';
  66478. return "bool czm_equalsEpsilon(vec4 left, vec4 right, float epsilon) {\n\
  66479. return all(lessThanEqual(abs(left - right), vec4(epsilon)));\n\
  66480. }\n\
  66481. bool czm_equalsEpsilon(vec3 left, vec3 right, float epsilon) {\n\
  66482. return all(lessThanEqual(abs(left - right), vec3(epsilon)));\n\
  66483. }\n\
  66484. bool czm_equalsEpsilon(vec2 left, vec2 right, float epsilon) {\n\
  66485. return all(lessThanEqual(abs(left - right), vec2(epsilon)));\n\
  66486. }\n\
  66487. bool czm_equalsEpsilon(float left, float right, float epsilon) {\n\
  66488. return (abs(left - right) <= epsilon);\n\
  66489. }\n\
  66490. ";
  66491. });
  66492. //This file is automatically rebuilt by the Cesium build process.
  66493. /*global define*/
  66494. define('Shaders/Builtin/Functions/eyeOffset',[],function() {
  66495. 'use strict';
  66496. return "vec4 czm_eyeOffset(vec4 positionEC, vec3 eyeOffset)\n\
  66497. {\n\
  66498. vec4 p = positionEC;\n\
  66499. vec4 zEyeOffset = normalize(p) * eyeOffset.z;\n\
  66500. p.xy += eyeOffset.xy + zEyeOffset.xy;\n\
  66501. p.z += zEyeOffset.z;\n\
  66502. return p;\n\
  66503. }\n\
  66504. ";
  66505. });
  66506. //This file is automatically rebuilt by the Cesium build process.
  66507. /*global define*/
  66508. define('Shaders/Builtin/Functions/eyeToWindowCoordinates',[],function() {
  66509. 'use strict';
  66510. return "vec4 czm_eyeToWindowCoordinates(vec4 positionEC)\n\
  66511. {\n\
  66512. vec4 q = czm_projection * positionEC;\n\
  66513. q.xyz /= q.w;\n\
  66514. q.xyz = (czm_viewportTransformation * vec4(q.xyz, 1.0)).xyz;\n\
  66515. return q;\n\
  66516. }\n\
  66517. ";
  66518. });
  66519. //This file is automatically rebuilt by the Cesium build process.
  66520. /*global define*/
  66521. define('Shaders/Builtin/Functions/fog',[],function() {
  66522. 'use strict';
  66523. return "vec3 czm_fog(float distanceToCamera, vec3 color, vec3 fogColor)\n\
  66524. {\n\
  66525. float scalar = distanceToCamera * czm_fogDensity;\n\
  66526. float fog = 1.0 - exp(-(scalar * scalar));\n\
  66527. return mix(color, fogColor, fog);\n\
  66528. }\n\
  66529. ";
  66530. });
  66531. //This file is automatically rebuilt by the Cesium build process.
  66532. /*global define*/
  66533. define('Shaders/Builtin/Functions/geodeticSurfaceNormal',[],function() {
  66534. 'use strict';
  66535. return "vec3 czm_geodeticSurfaceNormal(vec3 positionOnEllipsoid, vec3 ellipsoidCenter, vec3 oneOverEllipsoidRadiiSquared)\n\
  66536. {\n\
  66537. return normalize((positionOnEllipsoid - ellipsoidCenter) * oneOverEllipsoidRadiiSquared);\n\
  66538. }\n\
  66539. ";
  66540. });
  66541. //This file is automatically rebuilt by the Cesium build process.
  66542. /*global define*/
  66543. define('Shaders/Builtin/Functions/getDefaultMaterial',[],function() {
  66544. 'use strict';
  66545. return "czm_material czm_getDefaultMaterial(czm_materialInput materialInput)\n\
  66546. {\n\
  66547. czm_material material;\n\
  66548. material.diffuse = vec3(0.0);\n\
  66549. material.specular = 0.0;\n\
  66550. material.shininess = 1.0;\n\
  66551. material.normal = materialInput.normalEC;\n\
  66552. material.emission = vec3(0.0);\n\
  66553. material.alpha = 1.0;\n\
  66554. return material;\n\
  66555. }\n\
  66556. ";
  66557. });
  66558. //This file is automatically rebuilt by the Cesium build process.
  66559. /*global define*/
  66560. define('Shaders/Builtin/Functions/getLambertDiffuse',[],function() {
  66561. 'use strict';
  66562. return "float czm_getLambertDiffuse(vec3 lightDirectionEC, vec3 normalEC)\n\
  66563. {\n\
  66564. return max(dot(lightDirectionEC, normalEC), 0.0);\n\
  66565. }\n\
  66566. ";
  66567. });
  66568. //This file is automatically rebuilt by the Cesium build process.
  66569. /*global define*/
  66570. define('Shaders/Builtin/Functions/getSpecular',[],function() {
  66571. 'use strict';
  66572. return "float czm_getSpecular(vec3 lightDirectionEC, vec3 toEyeEC, vec3 normalEC, float shininess)\n\
  66573. {\n\
  66574. vec3 toReflectedLight = reflect(-lightDirectionEC, normalEC);\n\
  66575. float specular = max(dot(toReflectedLight, toEyeEC), 0.0);\n\
  66576. return pow(specular, max(shininess, czm_epsilon2));\n\
  66577. }\n\
  66578. ";
  66579. });
  66580. //This file is automatically rebuilt by the Cesium build process.
  66581. /*global define*/
  66582. define('Shaders/Builtin/Functions/getWaterNoise',[],function() {
  66583. 'use strict';
  66584. return "vec4 czm_getWaterNoise(sampler2D normalMap, vec2 uv, float time, float angleInRadians)\n\
  66585. {\n\
  66586. float cosAngle = cos(angleInRadians);\n\
  66587. float sinAngle = sin(angleInRadians);\n\
  66588. vec2 s0 = vec2(1.0/17.0, 0.0);\n\
  66589. vec2 s1 = vec2(-1.0/29.0, 0.0);\n\
  66590. vec2 s2 = vec2(1.0/101.0, 1.0/59.0);\n\
  66591. vec2 s3 = vec2(-1.0/109.0, -1.0/57.0);\n\
  66592. s0 = vec2((cosAngle * s0.x) - (sinAngle * s0.y), (sinAngle * s0.x) + (cosAngle * s0.y));\n\
  66593. s1 = vec2((cosAngle * s1.x) - (sinAngle * s1.y), (sinAngle * s1.x) + (cosAngle * s1.y));\n\
  66594. s2 = vec2((cosAngle * s2.x) - (sinAngle * s2.y), (sinAngle * s2.x) + (cosAngle * s2.y));\n\
  66595. s3 = vec2((cosAngle * s3.x) - (sinAngle * s3.y), (sinAngle * s3.x) + (cosAngle * s3.y));\n\
  66596. vec2 uv0 = (uv/103.0) + (time * s0);\n\
  66597. vec2 uv1 = uv/107.0 + (time * s1) + vec2(0.23);\n\
  66598. vec2 uv2 = uv/vec2(897.0, 983.0) + (time * s2) + vec2(0.51);\n\
  66599. vec2 uv3 = uv/vec2(991.0, 877.0) + (time * s3) + vec2(0.71);\n\
  66600. uv0 = fract(uv0);\n\
  66601. uv1 = fract(uv1);\n\
  66602. uv2 = fract(uv2);\n\
  66603. uv3 = fract(uv3);\n\
  66604. vec4 noise = (texture2D(normalMap, uv0)) +\n\
  66605. (texture2D(normalMap, uv1)) +\n\
  66606. (texture2D(normalMap, uv2)) +\n\
  66607. (texture2D(normalMap, uv3));\n\
  66608. return ((noise / 4.0) - 0.5) * 2.0;\n\
  66609. }\n\
  66610. ";
  66611. });
  66612. //This file is automatically rebuilt by the Cesium build process.
  66613. /*global define*/
  66614. define('Shaders/Builtin/Functions/getWgs84EllipsoidEC',[],function() {
  66615. 'use strict';
  66616. return "czm_ellipsoid czm_getWgs84EllipsoidEC()\n\
  66617. {\n\
  66618. vec3 radii = vec3(6378137.0, 6378137.0, 6356752.314245);\n\
  66619. vec3 inverseRadii = vec3(1.0 / radii.x, 1.0 / radii.y, 1.0 / radii.z);\n\
  66620. vec3 inverseRadiiSquared = inverseRadii * inverseRadii;\n\
  66621. czm_ellipsoid temp = czm_ellipsoid(czm_view[3].xyz, radii, inverseRadii, inverseRadiiSquared);\n\
  66622. return temp;\n\
  66623. }\n\
  66624. ";
  66625. });
  66626. //This file is automatically rebuilt by the Cesium build process.
  66627. /*global define*/
  66628. define('Shaders/Builtin/Functions/hue',[],function() {
  66629. 'use strict';
  66630. return "vec3 czm_hue(vec3 rgb, float adjustment)\n\
  66631. {\n\
  66632. const mat3 toYIQ = mat3(0.299, 0.587, 0.114,\n\
  66633. 0.595716, -0.274453, -0.321263,\n\
  66634. 0.211456, -0.522591, 0.311135);\n\
  66635. const mat3 toRGB = mat3(1.0, 0.9563, 0.6210,\n\
  66636. 1.0, -0.2721, -0.6474,\n\
  66637. 1.0, -1.107, 1.7046);\n\
  66638. vec3 yiq = toYIQ * rgb;\n\
  66639. float hue = atan(yiq.z, yiq.y) + adjustment;\n\
  66640. float chroma = sqrt(yiq.z * yiq.z + yiq.y * yiq.y);\n\
  66641. vec3 color = vec3(yiq.x, chroma * cos(hue), chroma * sin(hue));\n\
  66642. return toRGB * color;\n\
  66643. }\n\
  66644. ";
  66645. });
  66646. //This file is automatically rebuilt by the Cesium build process.
  66647. /*global define*/
  66648. define('Shaders/Builtin/Functions/isEmpty',[],function() {
  66649. 'use strict';
  66650. return "bool czm_isEmpty(czm_raySegment interval)\n\
  66651. {\n\
  66652. return (interval.stop < 0.0);\n\
  66653. }\n\
  66654. ";
  66655. });
  66656. //This file is automatically rebuilt by the Cesium build process.
  66657. /*global define*/
  66658. define('Shaders/Builtin/Functions/isFull',[],function() {
  66659. 'use strict';
  66660. return "bool czm_isFull(czm_raySegment interval)\n\
  66661. {\n\
  66662. return (interval.start == 0.0 && interval.stop == czm_infinity);\n\
  66663. }\n\
  66664. ";
  66665. });
  66666. //This file is automatically rebuilt by the Cesium build process.
  66667. /*global define*/
  66668. define('Shaders/Builtin/Functions/latitudeToWebMercatorFraction',[],function() {
  66669. 'use strict';
  66670. return "float czm_latitudeToWebMercatorFraction(float latitude, float southMercatorY, float oneOverMercatorHeight)\n\
  66671. {\n\
  66672. float sinLatitude = sin(latitude);\n\
  66673. float mercatorY = 0.5 * log((1.0 + sinLatitude) / (1.0 - sinLatitude));\n\
  66674. return (mercatorY - southMercatorY) * oneOverMercatorHeight;\n\
  66675. }\n\
  66676. ";
  66677. });
  66678. //This file is automatically rebuilt by the Cesium build process.
  66679. /*global define*/
  66680. define('Shaders/Builtin/Functions/luminance',[],function() {
  66681. 'use strict';
  66682. return "float czm_luminance(vec3 rgb)\n\
  66683. {\n\
  66684. const vec3 W = vec3(0.2125, 0.7154, 0.0721);\n\
  66685. return dot(rgb, W);\n\
  66686. }\n\
  66687. ";
  66688. });
  66689. //This file is automatically rebuilt by the Cesium build process.
  66690. /*global define*/
  66691. define('Shaders/Builtin/Functions/metersPerPixel',[],function() {
  66692. 'use strict';
  66693. return "float czm_metersPerPixel(vec4 positionEC)\n\
  66694. {\n\
  66695. float width = czm_viewport.z;\n\
  66696. float height = czm_viewport.w;\n\
  66697. float pixelWidth;\n\
  66698. float pixelHeight;\n\
  66699. float top = czm_frustumPlanes.x;\n\
  66700. float bottom = czm_frustumPlanes.y;\n\
  66701. float left = czm_frustumPlanes.z;\n\
  66702. float right = czm_frustumPlanes.w;\n\
  66703. if (czm_sceneMode == czm_sceneMode2D)\n\
  66704. {\n\
  66705. float frustumWidth = right - left;\n\
  66706. float frustumHeight = top - bottom;\n\
  66707. pixelWidth = frustumWidth / width;\n\
  66708. pixelHeight = frustumHeight / height;\n\
  66709. }\n\
  66710. else\n\
  66711. {\n\
  66712. float distanceToPixel = -positionEC.z;\n\
  66713. float inverseNear = 1.0 / czm_currentFrustum.x;\n\
  66714. float tanTheta = top * inverseNear;\n\
  66715. pixelHeight = 2.0 * distanceToPixel * tanTheta / height;\n\
  66716. tanTheta = right * inverseNear;\n\
  66717. pixelWidth = 2.0 * distanceToPixel * tanTheta / width;\n\
  66718. }\n\
  66719. return max(pixelWidth, pixelHeight);\n\
  66720. }\n\
  66721. ";
  66722. });
  66723. //This file is automatically rebuilt by the Cesium build process.
  66724. /*global define*/
  66725. define('Shaders/Builtin/Functions/modelToWindowCoordinates',[],function() {
  66726. 'use strict';
  66727. return "vec4 czm_modelToWindowCoordinates(vec4 position)\n\
  66728. {\n\
  66729. vec4 q = czm_modelViewProjection * position;\n\
  66730. q.xyz /= q.w;\n\
  66731. q.xyz = (czm_viewportTransformation * vec4(q.xyz, 1.0)).xyz;\n\
  66732. return q;\n\
  66733. }\n\
  66734. ";
  66735. });
  66736. //This file is automatically rebuilt by the Cesium build process.
  66737. /*global define*/
  66738. define('Shaders/Builtin/Functions/multiplyWithColorBalance',[],function() {
  66739. 'use strict';
  66740. return "vec3 czm_multiplyWithColorBalance(vec3 left, vec3 right)\n\
  66741. {\n\
  66742. const vec3 W = vec3(0.2125, 0.7154, 0.0721);\n\
  66743. vec3 target = left * right;\n\
  66744. float leftLuminance = dot(left, W);\n\
  66745. float rightLuminance = dot(right, W);\n\
  66746. float targetLuminance = dot(target, W);\n\
  66747. return ((leftLuminance + rightLuminance) / (2.0 * targetLuminance)) * target;\n\
  66748. }\n\
  66749. ";
  66750. });
  66751. //This file is automatically rebuilt by the Cesium build process.
  66752. /*global define*/
  66753. define('Shaders/Builtin/Functions/nearFarScalar',[],function() {
  66754. 'use strict';
  66755. return "float czm_nearFarScalar(vec4 nearFarScalar, float cameraDistSq)\n\
  66756. {\n\
  66757. float valueAtMin = nearFarScalar.y;\n\
  66758. float valueAtMax = nearFarScalar.w;\n\
  66759. float nearDistanceSq = nearFarScalar.x * nearFarScalar.x;\n\
  66760. float farDistanceSq = nearFarScalar.z * nearFarScalar.z;\n\
  66761. float t = (cameraDistSq - nearDistanceSq) / (farDistanceSq - nearDistanceSq);\n\
  66762. t = pow(clamp(t, 0.0, 1.0), 0.2);\n\
  66763. return mix(valueAtMin, valueAtMax, t);\n\
  66764. }\n\
  66765. ";
  66766. });
  66767. //This file is automatically rebuilt by the Cesium build process.
  66768. /*global define*/
  66769. define('Shaders/Builtin/Functions/octDecode',[],function() {
  66770. 'use strict';
  66771. return "vec3 czm_octDecode(vec2 encoded)\n\
  66772. {\n\
  66773. encoded = encoded / 255.0 * 2.0 - 1.0;\n\
  66774. vec3 v = vec3(encoded.x, encoded.y, 1.0 - abs(encoded.x) - abs(encoded.y));\n\
  66775. if (v.z < 0.0)\n\
  66776. {\n\
  66777. v.xy = (1.0 - abs(v.yx)) * czm_signNotZero(v.xy);\n\
  66778. }\n\
  66779. return normalize(v);\n\
  66780. }\n\
  66781. vec3 czm_octDecode(float encoded)\n\
  66782. {\n\
  66783. float temp = encoded / 256.0;\n\
  66784. float x = floor(temp);\n\
  66785. float y = (temp - x) * 256.0;\n\
  66786. return czm_octDecode(vec2(x, y));\n\
  66787. }\n\
  66788. void czm_octDecode(vec2 encoded, out vec3 vector1, out vec3 vector2, out vec3 vector3)\n\
  66789. {\n\
  66790. float temp = encoded.x / 65536.0;\n\
  66791. float x = floor(temp);\n\
  66792. float encodedFloat1 = (temp - x) * 65536.0;\n\
  66793. temp = encoded.y / 65536.0;\n\
  66794. float y = floor(temp);\n\
  66795. float encodedFloat2 = (temp - y) * 65536.0;\n\
  66796. vector1 = czm_octDecode(encodedFloat1);\n\
  66797. vector2 = czm_octDecode(encodedFloat2);\n\
  66798. vector3 = czm_octDecode(vec2(x, y));\n\
  66799. }\n\
  66800. ";
  66801. });
  66802. //This file is automatically rebuilt by the Cesium build process.
  66803. /*global define*/
  66804. define('Shaders/Builtin/Functions/packDepth',[],function() {
  66805. 'use strict';
  66806. return "vec4 czm_packDepth(float depth)\n\
  66807. {\n\
  66808. vec4 enc = vec4(1.0, 255.0, 65025.0, 16581375.0) * depth;\n\
  66809. enc = fract(enc);\n\
  66810. enc -= enc.yzww * vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 0.0);\n\
  66811. return enc;\n\
  66812. }\n\
  66813. ";
  66814. });
  66815. //This file is automatically rebuilt by the Cesium build process.
  66816. /*global define*/
  66817. define('Shaders/Builtin/Functions/phong',[],function() {
  66818. 'use strict';
  66819. return "float czm_private_getLambertDiffuseOfMaterial(vec3 lightDirectionEC, czm_material material)\n\
  66820. {\n\
  66821. return czm_getLambertDiffuse(lightDirectionEC, material.normal);\n\
  66822. }\n\
  66823. float czm_private_getSpecularOfMaterial(vec3 lightDirectionEC, vec3 toEyeEC, czm_material material)\n\
  66824. {\n\
  66825. return czm_getSpecular(lightDirectionEC, toEyeEC, material.normal, material.shininess);\n\
  66826. }\n\
  66827. vec4 czm_phong(vec3 toEye, czm_material material)\n\
  66828. {\n\
  66829. float diffuse = czm_private_getLambertDiffuseOfMaterial(vec3(0.0, 0.0, 1.0), material);\n\
  66830. if (czm_sceneMode == czm_sceneMode3D) {\n\
  66831. diffuse += czm_private_getLambertDiffuseOfMaterial(vec3(0.0, 1.0, 0.0), material);\n\
  66832. }\n\
  66833. float specular = czm_private_getSpecularOfMaterial(czm_sunDirectionEC, toEye, material) + czm_private_getSpecularOfMaterial(czm_moonDirectionEC, toEye, material);\n\
  66834. vec3 materialDiffuse = material.diffuse * 0.5;\n\
  66835. vec3 ambient = materialDiffuse;\n\
  66836. vec3 color = ambient + material.emission;\n\
  66837. color += materialDiffuse * diffuse;\n\
  66838. color += material.specular * specular;\n\
  66839. return vec4(color, material.alpha);\n\
  66840. }\n\
  66841. vec4 czm_private_phong(vec3 toEye, czm_material material)\n\
  66842. {\n\
  66843. float diffuse = czm_private_getLambertDiffuseOfMaterial(czm_sunDirectionEC, material);\n\
  66844. float specular = czm_private_getSpecularOfMaterial(czm_sunDirectionEC, toEye, material);\n\
  66845. vec3 ambient = vec3(0.0);\n\
  66846. vec3 color = ambient + material.emission;\n\
  66847. color += material.diffuse * diffuse;\n\
  66848. color += material.specular * specular;\n\
  66849. return vec4(color, material.alpha);\n\
  66850. }\n\
  66851. ";
  66852. });
  66853. //This file is automatically rebuilt by the Cesium build process.
  66854. /*global define*/
  66855. define('Shaders/Builtin/Functions/pointAlongRay',[],function() {
  66856. 'use strict';
  66857. return "vec3 czm_pointAlongRay(czm_ray ray, float time)\n\
  66858. {\n\
  66859. return ray.origin + (time * ray.direction);\n\
  66860. }\n\
  66861. ";
  66862. });
  66863. //This file is automatically rebuilt by the Cesium build process.
  66864. /*global define*/
  66865. define('Shaders/Builtin/Functions/rayEllipsoidIntersectionInterval',[],function() {
  66866. 'use strict';
  66867. return "czm_raySegment czm_rayEllipsoidIntersectionInterval(czm_ray ray, czm_ellipsoid ellipsoid)\n\
  66868. {\n\
  66869. vec3 q = ellipsoid.inverseRadii * (czm_inverseModelView * vec4(ray.origin, 1.0)).xyz;\n\
  66870. vec3 w = ellipsoid.inverseRadii * (czm_inverseModelView * vec4(ray.direction, 0.0)).xyz;\n\
  66871. q = q - ellipsoid.inverseRadii * (czm_inverseModelView * vec4(ellipsoid.center, 1.0)).xyz;\n\
  66872. float q2 = dot(q, q);\n\
  66873. float qw = dot(q, w);\n\
  66874. if (q2 > 1.0)\n\
  66875. {\n\
  66876. if (qw >= 0.0)\n\
  66877. {\n\
  66878. return czm_emptyRaySegment;\n\
  66879. }\n\
  66880. else\n\
  66881. {\n\
  66882. float qw2 = qw * qw;\n\
  66883. float difference = q2 - 1.0;\n\
  66884. float w2 = dot(w, w);\n\
  66885. float product = w2 * difference;\n\
  66886. if (qw2 < product)\n\
  66887. {\n\
  66888. return czm_emptyRaySegment;\n\
  66889. }\n\
  66890. else if (qw2 > product)\n\
  66891. {\n\
  66892. float discriminant = qw * qw - product;\n\
  66893. float temp = -qw + sqrt(discriminant);\n\
  66894. float root0 = temp / w2;\n\
  66895. float root1 = difference / temp;\n\
  66896. if (root0 < root1)\n\
  66897. {\n\
  66898. czm_raySegment i = czm_raySegment(root0, root1);\n\
  66899. return i;\n\
  66900. }\n\
  66901. else\n\
  66902. {\n\
  66903. czm_raySegment i = czm_raySegment(root1, root0);\n\
  66904. return i;\n\
  66905. }\n\
  66906. }\n\
  66907. else\n\
  66908. {\n\
  66909. float root = sqrt(difference / w2);\n\
  66910. czm_raySegment i = czm_raySegment(root, root);\n\
  66911. return i;\n\
  66912. }\n\
  66913. }\n\
  66914. }\n\
  66915. else if (q2 < 1.0)\n\
  66916. {\n\
  66917. float difference = q2 - 1.0;\n\
  66918. float w2 = dot(w, w);\n\
  66919. float product = w2 * difference;\n\
  66920. float discriminant = qw * qw - product;\n\
  66921. float temp = -qw + sqrt(discriminant);\n\
  66922. czm_raySegment i = czm_raySegment(0.0, temp / w2);\n\
  66923. return i;\n\
  66924. }\n\
  66925. else\n\
  66926. {\n\
  66927. if (qw < 0.0)\n\
  66928. {\n\
  66929. float w2 = dot(w, w);\n\
  66930. czm_raySegment i = czm_raySegment(0.0, -qw / w2);\n\
  66931. return i;\n\
  66932. }\n\
  66933. else\n\
  66934. {\n\
  66935. return czm_emptyRaySegment;\n\
  66936. }\n\
  66937. }\n\
  66938. }\n\
  66939. ";
  66940. });
  66941. //This file is automatically rebuilt by the Cesium build process.
  66942. /*global define*/
  66943. define('Shaders/Builtin/Functions/RGBToXYZ',[],function() {
  66944. 'use strict';
  66945. return "vec3 czm_RGBToXYZ(vec3 rgb)\n\
  66946. {\n\
  66947. const mat3 RGB2XYZ = mat3(0.4124, 0.2126, 0.0193,\n\
  66948. 0.3576, 0.7152, 0.1192,\n\
  66949. 0.1805, 0.0722, 0.9505);\n\
  66950. vec3 xyz = RGB2XYZ * rgb;\n\
  66951. vec3 Yxy;\n\
  66952. Yxy.r = xyz.g;\n\
  66953. float temp = dot(vec3(1.0), xyz);\n\
  66954. Yxy.gb = xyz.rg / temp;\n\
  66955. return Yxy;\n\
  66956. }\n\
  66957. ";
  66958. });
  66959. //This file is automatically rebuilt by the Cesium build process.
  66960. /*global define*/
  66961. define('Shaders/Builtin/Functions/saturation',[],function() {
  66962. 'use strict';
  66963. return "vec3 czm_saturation(vec3 rgb, float adjustment)\n\
  66964. {\n\
  66965. const vec3 W = vec3(0.2125, 0.7154, 0.0721);\n\
  66966. vec3 intensity = vec3(dot(rgb, W));\n\
  66967. return mix(intensity, rgb, adjustment);\n\
  66968. }\n\
  66969. ";
  66970. });
  66971. //This file is automatically rebuilt by the Cesium build process.
  66972. /*global define*/
  66973. define('Shaders/Builtin/Functions/shadowDepthCompare',[],function() {
  66974. 'use strict';
  66975. return "float czm_sampleShadowMap(samplerCube shadowMap, vec3 d)\n\
  66976. {\n\
  66977. return czm_unpackDepth(textureCube(shadowMap, d));\n\
  66978. }\n\
  66979. float czm_sampleShadowMap(sampler2D shadowMap, vec2 uv)\n\
  66980. {\n\
  66981. #ifdef USE_SHADOW_DEPTH_TEXTURE\n\
  66982. return texture2D(shadowMap, uv).r;\n\
  66983. #else\n\
  66984. return czm_unpackDepth(texture2D(shadowMap, uv));\n\
  66985. #endif\n\
  66986. }\n\
  66987. float czm_shadowDepthCompare(samplerCube shadowMap, vec3 uv, float depth)\n\
  66988. {\n\
  66989. return step(depth, czm_sampleShadowMap(shadowMap, uv));\n\
  66990. }\n\
  66991. float czm_shadowDepthCompare(sampler2D shadowMap, vec2 uv, float depth)\n\
  66992. {\n\
  66993. return step(depth, czm_sampleShadowMap(shadowMap, uv));\n\
  66994. }\n\
  66995. ";
  66996. });
  66997. //This file is automatically rebuilt by the Cesium build process.
  66998. /*global define*/
  66999. define('Shaders/Builtin/Functions/shadowVisibility',[],function() {
  67000. 'use strict';
  67001. return "float czm_private_shadowVisibility(float visibility, float nDotL, float normalShadingSmooth, float darkness)\n\
  67002. {\n\
  67003. #ifdef USE_NORMAL_SHADING\n\
  67004. #ifdef USE_NORMAL_SHADING_SMOOTH\n\
  67005. float strength = clamp(nDotL / normalShadingSmooth, 0.0, 1.0);\n\
  67006. #else\n\
  67007. float strength = step(0.0, nDotL);\n\
  67008. #endif\n\
  67009. visibility *= strength;\n\
  67010. #endif\n\
  67011. visibility = max(visibility, darkness);\n\
  67012. return visibility;\n\
  67013. }\n\
  67014. #ifdef USE_CUBE_MAP_SHADOW\n\
  67015. float czm_shadowVisibility(samplerCube shadowMap, czm_shadowParameters shadowParameters)\n\
  67016. {\n\
  67017. float depthBias = shadowParameters.depthBias;\n\
  67018. float depth = shadowParameters.depth;\n\
  67019. float nDotL = shadowParameters.nDotL;\n\
  67020. float normalShadingSmooth = shadowParameters.normalShadingSmooth;\n\
  67021. float darkness = shadowParameters.darkness;\n\
  67022. vec3 uvw = shadowParameters.texCoords;\n\
  67023. depth -= depthBias;\n\
  67024. float visibility = czm_shadowDepthCompare(shadowMap, uvw, depth);\n\
  67025. return czm_private_shadowVisibility(visibility, nDotL, normalShadingSmooth, darkness);\n\
  67026. }\n\
  67027. #else\n\
  67028. float czm_shadowVisibility(sampler2D shadowMap, czm_shadowParameters shadowParameters)\n\
  67029. {\n\
  67030. float depthBias = shadowParameters.depthBias;\n\
  67031. float depth = shadowParameters.depth;\n\
  67032. float nDotL = shadowParameters.nDotL;\n\
  67033. float normalShadingSmooth = shadowParameters.normalShadingSmooth;\n\
  67034. float darkness = shadowParameters.darkness;\n\
  67035. vec2 uv = shadowParameters.texCoords;\n\
  67036. depth -= depthBias;\n\
  67037. #ifdef USE_SOFT_SHADOWS\n\
  67038. vec2 texelStepSize = shadowParameters.texelStepSize;\n\
  67039. float radius = 1.0;\n\
  67040. float dx0 = -texelStepSize.x * radius;\n\
  67041. float dy0 = -texelStepSize.y * radius;\n\
  67042. float dx1 = texelStepSize.x * radius;\n\
  67043. float dy1 = texelStepSize.y * radius;\n\
  67044. float visibility = (\n\
  67045. czm_shadowDepthCompare(shadowMap, uv, depth) +\n\
  67046. czm_shadowDepthCompare(shadowMap, uv + vec2(dx0, dy0), depth) +\n\
  67047. czm_shadowDepthCompare(shadowMap, uv + vec2(0.0, dy0), depth) +\n\
  67048. czm_shadowDepthCompare(shadowMap, uv + vec2(dx1, dy0), depth) +\n\
  67049. czm_shadowDepthCompare(shadowMap, uv + vec2(dx0, 0.0), depth) +\n\
  67050. czm_shadowDepthCompare(shadowMap, uv + vec2(dx1, 0.0), depth) +\n\
  67051. czm_shadowDepthCompare(shadowMap, uv + vec2(dx0, dy1), depth) +\n\
  67052. czm_shadowDepthCompare(shadowMap, uv + vec2(0.0, dy1), depth) +\n\
  67053. czm_shadowDepthCompare(shadowMap, uv + vec2(dx1, dy1), depth)\n\
  67054. ) * (1.0 / 9.0);\n\
  67055. #else\n\
  67056. float visibility = czm_shadowDepthCompare(shadowMap, uv, depth);\n\
  67057. #endif\n\
  67058. return czm_private_shadowVisibility(visibility, nDotL, normalShadingSmooth, darkness);\n\
  67059. }\n\
  67060. #endif\n\
  67061. ";
  67062. });
  67063. //This file is automatically rebuilt by the Cesium build process.
  67064. /*global define*/
  67065. define('Shaders/Builtin/Functions/signNotZero',[],function() {
  67066. 'use strict';
  67067. return "float czm_signNotZero(float value)\n\
  67068. {\n\
  67069. return value >= 0.0 ? 1.0 : -1.0;\n\
  67070. }\n\
  67071. vec2 czm_signNotZero(vec2 value)\n\
  67072. {\n\
  67073. return vec2(czm_signNotZero(value.x), czm_signNotZero(value.y));\n\
  67074. }\n\
  67075. vec3 czm_signNotZero(vec3 value)\n\
  67076. {\n\
  67077. return vec3(czm_signNotZero(value.x), czm_signNotZero(value.y), czm_signNotZero(value.z));\n\
  67078. }\n\
  67079. vec4 czm_signNotZero(vec4 value)\n\
  67080. {\n\
  67081. return vec4(czm_signNotZero(value.x), czm_signNotZero(value.y), czm_signNotZero(value.z), czm_signNotZero(value.w));\n\
  67082. }\n\
  67083. ";
  67084. });
  67085. //This file is automatically rebuilt by the Cesium build process.
  67086. /*global define*/
  67087. define('Shaders/Builtin/Functions/tangentToEyeSpaceMatrix',[],function() {
  67088. 'use strict';
  67089. return "mat3 czm_tangentToEyeSpaceMatrix(vec3 normalEC, vec3 tangentEC, vec3 binormalEC)\n\
  67090. {\n\
  67091. vec3 normal = normalize(normalEC);\n\
  67092. vec3 tangent = normalize(tangentEC);\n\
  67093. vec3 binormal = normalize(binormalEC);\n\
  67094. return mat3(tangent.x, tangent.y, tangent.z,\n\
  67095. binormal.x, binormal.y, binormal.z,\n\
  67096. normal.x, normal.y, normal.z);\n\
  67097. }\n\
  67098. ";
  67099. });
  67100. //This file is automatically rebuilt by the Cesium build process.
  67101. /*global define*/
  67102. define('Shaders/Builtin/Functions/translateRelativeToEye',[],function() {
  67103. 'use strict';
  67104. return "vec4 czm_translateRelativeToEye(vec3 high, vec3 low)\n\
  67105. {\n\
  67106. vec3 highDifference = high - czm_encodedCameraPositionMCHigh;\n\
  67107. vec3 lowDifference = low - czm_encodedCameraPositionMCLow;\n\
  67108. return vec4(highDifference + lowDifference, 1.0);\n\
  67109. }\n\
  67110. ";
  67111. });
  67112. //This file is automatically rebuilt by the Cesium build process.
  67113. /*global define*/
  67114. define('Shaders/Builtin/Functions/translucentPhong',[],function() {
  67115. 'use strict';
  67116. return "vec4 czm_translucentPhong(vec3 toEye, czm_material material)\n\
  67117. {\n\
  67118. float diffuse = czm_getLambertDiffuse(vec3(0.0, 0.0, 1.0), material.normal);\n\
  67119. if (czm_sceneMode == czm_sceneMode3D) {\n\
  67120. diffuse += czm_getLambertDiffuse(vec3(0.0, 1.0, 0.0), material.normal);\n\
  67121. }\n\
  67122. diffuse = clamp(diffuse, 0.0, 1.0);\n\
  67123. float specular = czm_getSpecular(czm_sunDirectionEC, toEye, material.normal, material.shininess);\n\
  67124. specular += czm_getSpecular(czm_moonDirectionEC, toEye, material.normal, material.shininess);\n\
  67125. vec3 materialDiffuse = material.diffuse * 0.5;\n\
  67126. vec3 ambient = materialDiffuse;\n\
  67127. vec3 color = ambient + material.emission;\n\
  67128. color += materialDiffuse * diffuse;\n\
  67129. color += material.specular * specular;\n\
  67130. return vec4(color, material.alpha);\n\
  67131. }\n\
  67132. ";
  67133. });
  67134. //This file is automatically rebuilt by the Cesium build process.
  67135. /*global define*/
  67136. define('Shaders/Builtin/Functions/transpose',[],function() {
  67137. 'use strict';
  67138. return "mat2 czm_transpose(mat2 matrix)\n\
  67139. {\n\
  67140. return mat2(\n\
  67141. matrix[0][0], matrix[1][0],\n\
  67142. matrix[0][1], matrix[1][1]);\n\
  67143. }\n\
  67144. mat3 czm_transpose(mat3 matrix)\n\
  67145. {\n\
  67146. return mat3(\n\
  67147. matrix[0][0], matrix[1][0], matrix[2][0],\n\
  67148. matrix[0][1], matrix[1][1], matrix[2][1],\n\
  67149. matrix[0][2], matrix[1][2], matrix[2][2]);\n\
  67150. }\n\
  67151. mat4 czm_transpose(mat4 matrix)\n\
  67152. {\n\
  67153. return mat4(\n\
  67154. matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],\n\
  67155. matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1],\n\
  67156. matrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2],\n\
  67157. matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);\n\
  67158. }\n\
  67159. ";
  67160. });
  67161. //This file is automatically rebuilt by the Cesium build process.
  67162. /*global define*/
  67163. define('Shaders/Builtin/Functions/unpackDepth',[],function() {
  67164. 'use strict';
  67165. return "float czm_unpackDepth(vec4 packedDepth)\n\
  67166. {\n\
  67167. return dot(packedDepth, vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0));\n\
  67168. }\n\
  67169. ";
  67170. });
  67171. //This file is automatically rebuilt by the Cesium build process.
  67172. /*global define*/
  67173. define('Shaders/Builtin/Functions/windowToEyeCoordinates',[],function() {
  67174. 'use strict';
  67175. return "vec4 czm_windowToEyeCoordinates(vec4 fragmentCoordinate)\n\
  67176. {\n\
  67177. float x = 2.0 * (fragmentCoordinate.x - czm_viewport.x) / czm_viewport.z - 1.0;\n\
  67178. float y = 2.0 * (fragmentCoordinate.y - czm_viewport.y) / czm_viewport.w - 1.0;\n\
  67179. float z = (fragmentCoordinate.z - czm_viewportTransformation[3][2]) / czm_viewportTransformation[2][2];\n\
  67180. vec4 q = vec4(x, y, z, 1.0);\n\
  67181. q /= fragmentCoordinate.w;\n\
  67182. q = czm_inverseProjection * q;\n\
  67183. return q;\n\
  67184. }\n\
  67185. ";
  67186. });
  67187. //This file is automatically rebuilt by the Cesium build process.
  67188. /*global define*/
  67189. define('Shaders/Builtin/Functions/XYZToRGB',[],function() {
  67190. 'use strict';
  67191. return "vec3 czm_XYZToRGB(vec3 Yxy)\n\
  67192. {\n\
  67193. const mat3 XYZ2RGB = mat3( 3.2405, -0.9693, 0.0556,\n\
  67194. -1.5371, 1.8760, -0.2040,\n\
  67195. -0.4985, 0.0416, 1.0572);\n\
  67196. vec3 xyz;\n\
  67197. xyz.r = Yxy.r * Yxy.g / Yxy.b;\n\
  67198. xyz.g = Yxy.r;\n\
  67199. xyz.b = Yxy.r * (1.0 - Yxy.g - Yxy.b) / Yxy.b;\n\
  67200. return XYZ2RGB * xyz;\n\
  67201. }\n\
  67202. ";
  67203. });
  67204. //This file is automatically rebuilt by the Cesium build process.
  67205. /*global define*/
  67206. define('Shaders/Builtin/CzmBuiltins',[
  67207. './Constants/degreesPerRadian',
  67208. './Constants/depthRange',
  67209. './Constants/epsilon1',
  67210. './Constants/epsilon2',
  67211. './Constants/epsilon3',
  67212. './Constants/epsilon4',
  67213. './Constants/epsilon5',
  67214. './Constants/epsilon6',
  67215. './Constants/epsilon7',
  67216. './Constants/infinity',
  67217. './Constants/oneOverPi',
  67218. './Constants/oneOverTwoPi',
  67219. './Constants/passCompute',
  67220. './Constants/passEnvironment',
  67221. './Constants/passGlobe',
  67222. './Constants/passGround',
  67223. './Constants/passOpaque',
  67224. './Constants/passOverlay',
  67225. './Constants/passTranslucent',
  67226. './Constants/pi',
  67227. './Constants/piOverFour',
  67228. './Constants/piOverSix',
  67229. './Constants/piOverThree',
  67230. './Constants/piOverTwo',
  67231. './Constants/radiansPerDegree',
  67232. './Constants/sceneMode2D',
  67233. './Constants/sceneMode3D',
  67234. './Constants/sceneModeColumbusView',
  67235. './Constants/sceneModeMorphing',
  67236. './Constants/solarRadius',
  67237. './Constants/threePiOver2',
  67238. './Constants/twoPi',
  67239. './Constants/webMercatorMaxLatitude',
  67240. './Structs/depthRangeStruct',
  67241. './Structs/ellipsoid',
  67242. './Structs/material',
  67243. './Structs/materialInput',
  67244. './Structs/ray',
  67245. './Structs/raySegment',
  67246. './Structs/shadowParameters',
  67247. './Functions/alphaWeight',
  67248. './Functions/antialias',
  67249. './Functions/cascadeColor',
  67250. './Functions/cascadeDistance',
  67251. './Functions/cascadeMatrix',
  67252. './Functions/cascadeWeights',
  67253. './Functions/columbusViewMorph',
  67254. './Functions/computePosition',
  67255. './Functions/cosineAndSine',
  67256. './Functions/decompressTextureCoordinates',
  67257. './Functions/eastNorthUpToEyeCoordinates',
  67258. './Functions/ellipsoidContainsPoint',
  67259. './Functions/ellipsoidNew',
  67260. './Functions/ellipsoidWgs84TextureCoordinates',
  67261. './Functions/equalsEpsilon',
  67262. './Functions/eyeOffset',
  67263. './Functions/eyeToWindowCoordinates',
  67264. './Functions/fog',
  67265. './Functions/geodeticSurfaceNormal',
  67266. './Functions/getDefaultMaterial',
  67267. './Functions/getLambertDiffuse',
  67268. './Functions/getSpecular',
  67269. './Functions/getWaterNoise',
  67270. './Functions/getWgs84EllipsoidEC',
  67271. './Functions/hue',
  67272. './Functions/isEmpty',
  67273. './Functions/isFull',
  67274. './Functions/latitudeToWebMercatorFraction',
  67275. './Functions/luminance',
  67276. './Functions/metersPerPixel',
  67277. './Functions/modelToWindowCoordinates',
  67278. './Functions/multiplyWithColorBalance',
  67279. './Functions/nearFarScalar',
  67280. './Functions/octDecode',
  67281. './Functions/packDepth',
  67282. './Functions/phong',
  67283. './Functions/pointAlongRay',
  67284. './Functions/rayEllipsoidIntersectionInterval',
  67285. './Functions/RGBToXYZ',
  67286. './Functions/saturation',
  67287. './Functions/shadowDepthCompare',
  67288. './Functions/shadowVisibility',
  67289. './Functions/signNotZero',
  67290. './Functions/tangentToEyeSpaceMatrix',
  67291. './Functions/translateRelativeToEye',
  67292. './Functions/translucentPhong',
  67293. './Functions/transpose',
  67294. './Functions/unpackDepth',
  67295. './Functions/windowToEyeCoordinates',
  67296. './Functions/XYZToRGB'
  67297. ], function(
  67298. czm_degreesPerRadian,
  67299. czm_depthRange,
  67300. czm_epsilon1,
  67301. czm_epsilon2,
  67302. czm_epsilon3,
  67303. czm_epsilon4,
  67304. czm_epsilon5,
  67305. czm_epsilon6,
  67306. czm_epsilon7,
  67307. czm_infinity,
  67308. czm_oneOverPi,
  67309. czm_oneOverTwoPi,
  67310. czm_passCompute,
  67311. czm_passEnvironment,
  67312. czm_passGlobe,
  67313. czm_passGround,
  67314. czm_passOpaque,
  67315. czm_passOverlay,
  67316. czm_passTranslucent,
  67317. czm_pi,
  67318. czm_piOverFour,
  67319. czm_piOverSix,
  67320. czm_piOverThree,
  67321. czm_piOverTwo,
  67322. czm_radiansPerDegree,
  67323. czm_sceneMode2D,
  67324. czm_sceneMode3D,
  67325. czm_sceneModeColumbusView,
  67326. czm_sceneModeMorphing,
  67327. czm_solarRadius,
  67328. czm_threePiOver2,
  67329. czm_twoPi,
  67330. czm_webMercatorMaxLatitude,
  67331. czm_depthRangeStruct,
  67332. czm_ellipsoid,
  67333. czm_material,
  67334. czm_materialInput,
  67335. czm_ray,
  67336. czm_raySegment,
  67337. czm_shadowParameters,
  67338. czm_alphaWeight,
  67339. czm_antialias,
  67340. czm_cascadeColor,
  67341. czm_cascadeDistance,
  67342. czm_cascadeMatrix,
  67343. czm_cascadeWeights,
  67344. czm_columbusViewMorph,
  67345. czm_computePosition,
  67346. czm_cosineAndSine,
  67347. czm_decompressTextureCoordinates,
  67348. czm_eastNorthUpToEyeCoordinates,
  67349. czm_ellipsoidContainsPoint,
  67350. czm_ellipsoidNew,
  67351. czm_ellipsoidWgs84TextureCoordinates,
  67352. czm_equalsEpsilon,
  67353. czm_eyeOffset,
  67354. czm_eyeToWindowCoordinates,
  67355. czm_fog,
  67356. czm_geodeticSurfaceNormal,
  67357. czm_getDefaultMaterial,
  67358. czm_getLambertDiffuse,
  67359. czm_getSpecular,
  67360. czm_getWaterNoise,
  67361. czm_getWgs84EllipsoidEC,
  67362. czm_hue,
  67363. czm_isEmpty,
  67364. czm_isFull,
  67365. czm_latitudeToWebMercatorFraction,
  67366. czm_luminance,
  67367. czm_metersPerPixel,
  67368. czm_modelToWindowCoordinates,
  67369. czm_multiplyWithColorBalance,
  67370. czm_nearFarScalar,
  67371. czm_octDecode,
  67372. czm_packDepth,
  67373. czm_phong,
  67374. czm_pointAlongRay,
  67375. czm_rayEllipsoidIntersectionInterval,
  67376. czm_RGBToXYZ,
  67377. czm_saturation,
  67378. czm_shadowDepthCompare,
  67379. czm_shadowVisibility,
  67380. czm_signNotZero,
  67381. czm_tangentToEyeSpaceMatrix,
  67382. czm_translateRelativeToEye,
  67383. czm_translucentPhong,
  67384. czm_transpose,
  67385. czm_unpackDepth,
  67386. czm_windowToEyeCoordinates,
  67387. czm_XYZToRGB) {
  67388. 'use strict';
  67389. return {
  67390. czm_degreesPerRadian : czm_degreesPerRadian,
  67391. czm_depthRange : czm_depthRange,
  67392. czm_epsilon1 : czm_epsilon1,
  67393. czm_epsilon2 : czm_epsilon2,
  67394. czm_epsilon3 : czm_epsilon3,
  67395. czm_epsilon4 : czm_epsilon4,
  67396. czm_epsilon5 : czm_epsilon5,
  67397. czm_epsilon6 : czm_epsilon6,
  67398. czm_epsilon7 : czm_epsilon7,
  67399. czm_infinity : czm_infinity,
  67400. czm_oneOverPi : czm_oneOverPi,
  67401. czm_oneOverTwoPi : czm_oneOverTwoPi,
  67402. czm_passCompute : czm_passCompute,
  67403. czm_passEnvironment : czm_passEnvironment,
  67404. czm_passGlobe : czm_passGlobe,
  67405. czm_passGround : czm_passGround,
  67406. czm_passOpaque : czm_passOpaque,
  67407. czm_passOverlay : czm_passOverlay,
  67408. czm_passTranslucent : czm_passTranslucent,
  67409. czm_pi : czm_pi,
  67410. czm_piOverFour : czm_piOverFour,
  67411. czm_piOverSix : czm_piOverSix,
  67412. czm_piOverThree : czm_piOverThree,
  67413. czm_piOverTwo : czm_piOverTwo,
  67414. czm_radiansPerDegree : czm_radiansPerDegree,
  67415. czm_sceneMode2D : czm_sceneMode2D,
  67416. czm_sceneMode3D : czm_sceneMode3D,
  67417. czm_sceneModeColumbusView : czm_sceneModeColumbusView,
  67418. czm_sceneModeMorphing : czm_sceneModeMorphing,
  67419. czm_solarRadius : czm_solarRadius,
  67420. czm_threePiOver2 : czm_threePiOver2,
  67421. czm_twoPi : czm_twoPi,
  67422. czm_webMercatorMaxLatitude : czm_webMercatorMaxLatitude,
  67423. czm_depthRangeStruct : czm_depthRangeStruct,
  67424. czm_ellipsoid : czm_ellipsoid,
  67425. czm_material : czm_material,
  67426. czm_materialInput : czm_materialInput,
  67427. czm_ray : czm_ray,
  67428. czm_raySegment : czm_raySegment,
  67429. czm_shadowParameters : czm_shadowParameters,
  67430. czm_alphaWeight : czm_alphaWeight,
  67431. czm_antialias : czm_antialias,
  67432. czm_cascadeColor : czm_cascadeColor,
  67433. czm_cascadeDistance : czm_cascadeDistance,
  67434. czm_cascadeMatrix : czm_cascadeMatrix,
  67435. czm_cascadeWeights : czm_cascadeWeights,
  67436. czm_columbusViewMorph : czm_columbusViewMorph,
  67437. czm_computePosition : czm_computePosition,
  67438. czm_cosineAndSine : czm_cosineAndSine,
  67439. czm_decompressTextureCoordinates : czm_decompressTextureCoordinates,
  67440. czm_eastNorthUpToEyeCoordinates : czm_eastNorthUpToEyeCoordinates,
  67441. czm_ellipsoidContainsPoint : czm_ellipsoidContainsPoint,
  67442. czm_ellipsoidNew : czm_ellipsoidNew,
  67443. czm_ellipsoidWgs84TextureCoordinates : czm_ellipsoidWgs84TextureCoordinates,
  67444. czm_equalsEpsilon : czm_equalsEpsilon,
  67445. czm_eyeOffset : czm_eyeOffset,
  67446. czm_eyeToWindowCoordinates : czm_eyeToWindowCoordinates,
  67447. czm_fog : czm_fog,
  67448. czm_geodeticSurfaceNormal : czm_geodeticSurfaceNormal,
  67449. czm_getDefaultMaterial : czm_getDefaultMaterial,
  67450. czm_getLambertDiffuse : czm_getLambertDiffuse,
  67451. czm_getSpecular : czm_getSpecular,
  67452. czm_getWaterNoise : czm_getWaterNoise,
  67453. czm_getWgs84EllipsoidEC : czm_getWgs84EllipsoidEC,
  67454. czm_hue : czm_hue,
  67455. czm_isEmpty : czm_isEmpty,
  67456. czm_isFull : czm_isFull,
  67457. czm_latitudeToWebMercatorFraction : czm_latitudeToWebMercatorFraction,
  67458. czm_luminance : czm_luminance,
  67459. czm_metersPerPixel : czm_metersPerPixel,
  67460. czm_modelToWindowCoordinates : czm_modelToWindowCoordinates,
  67461. czm_multiplyWithColorBalance : czm_multiplyWithColorBalance,
  67462. czm_nearFarScalar : czm_nearFarScalar,
  67463. czm_octDecode : czm_octDecode,
  67464. czm_packDepth : czm_packDepth,
  67465. czm_phong : czm_phong,
  67466. czm_pointAlongRay : czm_pointAlongRay,
  67467. czm_rayEllipsoidIntersectionInterval : czm_rayEllipsoidIntersectionInterval,
  67468. czm_RGBToXYZ : czm_RGBToXYZ,
  67469. czm_saturation : czm_saturation,
  67470. czm_shadowDepthCompare : czm_shadowDepthCompare,
  67471. czm_shadowVisibility : czm_shadowVisibility,
  67472. czm_signNotZero : czm_signNotZero,
  67473. czm_tangentToEyeSpaceMatrix : czm_tangentToEyeSpaceMatrix,
  67474. czm_translateRelativeToEye : czm_translateRelativeToEye,
  67475. czm_translucentPhong : czm_translucentPhong,
  67476. czm_transpose : czm_transpose,
  67477. czm_unpackDepth : czm_unpackDepth,
  67478. czm_windowToEyeCoordinates : czm_windowToEyeCoordinates,
  67479. czm_XYZToRGB : czm_XYZToRGB};
  67480. });
  67481. /*global define*/
  67482. define('Renderer/ShaderSource',[
  67483. '../Core/defaultValue',
  67484. '../Core/defined',
  67485. '../Core/DeveloperError',
  67486. '../Shaders/Builtin/CzmBuiltins',
  67487. './AutomaticUniforms'
  67488. ], function(
  67489. defaultValue,
  67490. defined,
  67491. DeveloperError,
  67492. CzmBuiltins,
  67493. AutomaticUniforms) {
  67494. 'use strict';
  67495. function removeComments(source) {
  67496. // remove inline comments
  67497. source = source.replace(/\/\/.*/g, '');
  67498. // remove multiline comment block
  67499. return source.replace(/\/\*\*[\s\S]*?\*\//gm, function(match) {
  67500. // preserve the number of lines in the comment block so the line numbers will be correct when debugging shaders
  67501. var numberOfLines = match.match(/\n/gm).length;
  67502. var replacement = '';
  67503. for (var lineNumber = 0; lineNumber < numberOfLines; ++lineNumber) {
  67504. replacement += '\n';
  67505. }
  67506. return replacement;
  67507. });
  67508. }
  67509. function getDependencyNode(name, glslSource, nodes) {
  67510. var dependencyNode;
  67511. // check if already loaded
  67512. for (var i = 0; i < nodes.length; ++i) {
  67513. if (nodes[i].name === name) {
  67514. dependencyNode = nodes[i];
  67515. }
  67516. }
  67517. if (!defined(dependencyNode)) {
  67518. // strip doc comments so we don't accidentally try to determine a dependency for something found
  67519. // in a comment
  67520. glslSource = removeComments(glslSource);
  67521. // create new node
  67522. dependencyNode = {
  67523. name : name,
  67524. glslSource : glslSource,
  67525. dependsOn : [],
  67526. requiredBy : [],
  67527. evaluated : false
  67528. };
  67529. nodes.push(dependencyNode);
  67530. }
  67531. return dependencyNode;
  67532. }
  67533. function generateDependencies(currentNode, dependencyNodes) {
  67534. if (currentNode.evaluated) {
  67535. return;
  67536. }
  67537. currentNode.evaluated = true;
  67538. // identify all dependencies that are referenced from this glsl source code
  67539. var czmMatches = currentNode.glslSource.match(/\bczm_[a-zA-Z0-9_]*/g);
  67540. if (defined(czmMatches) && czmMatches !== null) {
  67541. // remove duplicates
  67542. czmMatches = czmMatches.filter(function(elem, pos) {
  67543. return czmMatches.indexOf(elem) === pos;
  67544. });
  67545. czmMatches.forEach(function(element) {
  67546. if (element !== currentNode.name && ShaderSource._czmBuiltinsAndUniforms.hasOwnProperty(element)) {
  67547. var referencedNode = getDependencyNode(element, ShaderSource._czmBuiltinsAndUniforms[element], dependencyNodes);
  67548. currentNode.dependsOn.push(referencedNode);
  67549. referencedNode.requiredBy.push(currentNode);
  67550. // recursive call to find any dependencies of the new node
  67551. generateDependencies(referencedNode, dependencyNodes);
  67552. }
  67553. });
  67554. }
  67555. }
  67556. function sortDependencies(dependencyNodes) {
  67557. var nodesWithoutIncomingEdges = [];
  67558. var allNodes = [];
  67559. while (dependencyNodes.length > 0) {
  67560. var node = dependencyNodes.pop();
  67561. allNodes.push(node);
  67562. if (node.requiredBy.length === 0) {
  67563. nodesWithoutIncomingEdges.push(node);
  67564. }
  67565. }
  67566. while (nodesWithoutIncomingEdges.length > 0) {
  67567. var currentNode = nodesWithoutIncomingEdges.shift();
  67568. dependencyNodes.push(currentNode);
  67569. for (var i = 0; i < currentNode.dependsOn.length; ++i) {
  67570. // remove the edge from the graph
  67571. var referencedNode = currentNode.dependsOn[i];
  67572. var index = referencedNode.requiredBy.indexOf(currentNode);
  67573. referencedNode.requiredBy.splice(index, 1);
  67574. // if referenced node has no more incoming edges, add to list
  67575. if (referencedNode.requiredBy.length === 0) {
  67576. nodesWithoutIncomingEdges.push(referencedNode);
  67577. }
  67578. }
  67579. }
  67580. // if there are any nodes left with incoming edges, then there was a circular dependency somewhere in the graph
  67581. var badNodes = [];
  67582. for (var j = 0; j < allNodes.length; ++j) {
  67583. if (allNodes[j].requiredBy.length !== 0) {
  67584. badNodes.push(allNodes[j]);
  67585. }
  67586. }
  67587. if (badNodes.length !== 0) {
  67588. var message = 'A circular dependency was found in the following built-in functions/structs/constants: \n';
  67589. for (j = 0; j < badNodes.length; ++j) {
  67590. message = message + badNodes[j].name + '\n';
  67591. }
  67592. throw new DeveloperError(message);
  67593. }
  67594. }
  67595. function getBuiltinsAndAutomaticUniforms(shaderSource) {
  67596. // generate a dependency graph for builtin functions
  67597. var dependencyNodes = [];
  67598. var root = getDependencyNode('main', shaderSource, dependencyNodes);
  67599. generateDependencies(root, dependencyNodes);
  67600. sortDependencies(dependencyNodes);
  67601. // Concatenate the source code for the function dependencies.
  67602. // Iterate in reverse so that dependent items are declared before they are used.
  67603. var builtinsSource = '';
  67604. for (var i = dependencyNodes.length - 1; i >= 0; --i) {
  67605. builtinsSource = builtinsSource + dependencyNodes[i].glslSource + '\n';
  67606. }
  67607. return builtinsSource.replace(root.glslSource, '');
  67608. }
  67609. function combineShader(shaderSource, isFragmentShader) {
  67610. var i;
  67611. var length;
  67612. // Combine shader sources, generally for pseudo-polymorphism, e.g., czm_getMaterial.
  67613. var combinedSources = '';
  67614. var sources = shaderSource.sources;
  67615. if (defined(sources)) {
  67616. for (i = 0, length = sources.length; i < length; ++i) {
  67617. // #line needs to be on its own line.
  67618. combinedSources += '\n#line 0\n' + sources[i];
  67619. }
  67620. }
  67621. combinedSources = removeComments(combinedSources);
  67622. // Extract existing shader version from sources
  67623. var version;
  67624. combinedSources = combinedSources.replace(/#version\s+(.*?)\n/gm, function(match, group1) {
  67625. if (defined(version) && version !== group1) {
  67626. throw new DeveloperError('inconsistent versions found: ' + version + ' and ' + group1);
  67627. }
  67628. // Extract #version to put at the top
  67629. version = group1;
  67630. // Replace original #version directive with a new line so the line numbers
  67631. // are not off by one. There can be only one #version directive
  67632. // and it must appear at the top of the source, only preceded by
  67633. // whitespace and comments.
  67634. return '\n';
  67635. });
  67636. // Remove precision qualifier
  67637. combinedSources = combinedSources.replace(/precision\s(lowp|mediump|highp)\s(float|int);/, '');
  67638. // Replace main() for picked if desired.
  67639. var pickColorQualifier = shaderSource.pickColorQualifier;
  67640. if (defined(pickColorQualifier)) {
  67641. combinedSources = ShaderSource.createPickFragmentShaderSource(combinedSources, pickColorQualifier);
  67642. }
  67643. // combine into single string
  67644. var result = '';
  67645. // #version must be first
  67646. // defaults to #version 100 if not specified
  67647. if (defined(version)) {
  67648. result = '#version ' + version;
  67649. }
  67650. if (isFragmentShader) {
  67651. result += '\
  67652. #ifdef GL_FRAGMENT_PRECISION_HIGH\n\
  67653. precision highp float;\n\
  67654. #else\n\
  67655. precision mediump float;\n\
  67656. #endif\n\n';
  67657. }
  67658. // Prepend #defines for uber-shaders
  67659. var defines = shaderSource.defines;
  67660. if (defined(defines)) {
  67661. for (i = 0, length = defines.length; i < length; ++i) {
  67662. var define = defines[i];
  67663. if (define.length !== 0) {
  67664. result += '#define ' + define + '\n';
  67665. }
  67666. }
  67667. }
  67668. // append built-ins
  67669. if (shaderSource.includeBuiltIns) {
  67670. result += getBuiltinsAndAutomaticUniforms(combinedSources);
  67671. }
  67672. // reset line number
  67673. result += '\n#line 0\n';
  67674. // append actual source
  67675. result += combinedSources;
  67676. return result;
  67677. }
  67678. /**
  67679. * An object containing various inputs that will be combined to form a final GLSL shader string.
  67680. *
  67681. * @param {Object} [options] Object with the following properties:
  67682. * @param {String[]} [options.sources] An array of strings to combine containing GLSL code for the shader.
  67683. * @param {String[]} [options.defines] An array of strings containing GLSL identifiers to <code>#define</code>.
  67684. * @param {String} [options.pickColorQualifier] The GLSL qualifier, <code>uniform</code> or <code>varying</code>, for the input <code>czm_pickColor</code>. When defined, a pick fragment shader is generated.
  67685. * @param {Boolean} [options.includeBuiltIns=true] If true, referenced built-in functions will be included with the combined shader. Set to false if this shader will become a source in another shader, to avoid duplicating functions.
  67686. *
  67687. * @exception {DeveloperError} options.pickColorQualifier must be 'uniform' or 'varying'.
  67688. *
  67689. * @example
  67690. * // 1. Prepend #defines to a shader
  67691. * var source = new Cesium.ShaderSource({
  67692. * defines : ['WHITE'],
  67693. * sources : ['void main() { \n#ifdef WHITE\n gl_FragColor = vec4(1.0); \n#else\n gl_FragColor = vec4(0.0); \n#endif\n }']
  67694. * });
  67695. *
  67696. * // 2. Modify a fragment shader for picking
  67697. * var source = new Cesium.ShaderSource({
  67698. * sources : ['void main() { gl_FragColor = vec4(1.0); }'],
  67699. * pickColorQualifier : 'uniform'
  67700. * });
  67701. *
  67702. * @private
  67703. */
  67704. function ShaderSource(options) {
  67705. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  67706. var pickColorQualifier = options.pickColorQualifier;
  67707. if (defined(pickColorQualifier) && pickColorQualifier !== 'uniform' && pickColorQualifier !== 'varying') {
  67708. throw new DeveloperError('options.pickColorQualifier must be \'uniform\' or \'varying\'.');
  67709. }
  67710. this.defines = defined(options.defines) ? options.defines.slice(0) : [];
  67711. this.sources = defined(options.sources) ? options.sources.slice(0) : [];
  67712. this.pickColorQualifier = pickColorQualifier;
  67713. this.includeBuiltIns = defaultValue(options.includeBuiltIns, true);
  67714. }
  67715. ShaderSource.prototype.clone = function() {
  67716. return new ShaderSource({
  67717. sources : this.sources,
  67718. defines : this.defines,
  67719. pickColorQuantifier : this.pickColorQualifier,
  67720. includeBuiltIns : this.includeBuiltIns
  67721. });
  67722. };
  67723. ShaderSource.replaceMain = function(source, renamedMain) {
  67724. renamedMain = 'void ' + renamedMain + '()';
  67725. return source.replace(/void\s+main\s*\(\s*(?:void)?\s*\)/g, renamedMain);
  67726. };
  67727. /**
  67728. * Create a single string containing the full, combined vertex shader with all dependencies and defines.
  67729. *
  67730. * @returns {String} The combined shader string.
  67731. */
  67732. ShaderSource.prototype.createCombinedVertexShader = function() {
  67733. return combineShader(this, false);
  67734. };
  67735. /**
  67736. * Create a single string containing the full, combined fragment shader with all dependencies and defines.
  67737. *
  67738. * @returns {String} The combined shader string.
  67739. */
  67740. ShaderSource.prototype.createCombinedFragmentShader = function() {
  67741. return combineShader(this, true);
  67742. };
  67743. /**
  67744. * For ShaderProgram testing
  67745. * @private
  67746. */
  67747. ShaderSource._czmBuiltinsAndUniforms = {};
  67748. // combine automatic uniforms and Cesium built-ins
  67749. for ( var builtinName in CzmBuiltins) {
  67750. if (CzmBuiltins.hasOwnProperty(builtinName)) {
  67751. ShaderSource._czmBuiltinsAndUniforms[builtinName] = CzmBuiltins[builtinName];
  67752. }
  67753. }
  67754. for ( var uniformName in AutomaticUniforms) {
  67755. if (AutomaticUniforms.hasOwnProperty(uniformName)) {
  67756. var uniform = AutomaticUniforms[uniformName];
  67757. if (typeof uniform.getDeclaration === 'function') {
  67758. ShaderSource._czmBuiltinsAndUniforms[uniformName] = uniform.getDeclaration(uniformName);
  67759. }
  67760. }
  67761. }
  67762. ShaderSource.createPickVertexShaderSource = function(vertexShaderSource) {
  67763. var renamedVS = ShaderSource.replaceMain(vertexShaderSource, 'czm_old_main');
  67764. var pickMain = 'attribute vec4 pickColor; \n' +
  67765. 'varying vec4 czm_pickColor; \n' +
  67766. 'void main() \n' +
  67767. '{ \n' +
  67768. ' czm_old_main(); \n' +
  67769. ' czm_pickColor = pickColor; \n' +
  67770. '}';
  67771. return renamedVS + '\n' + pickMain;
  67772. };
  67773. ShaderSource.createPickFragmentShaderSource = function(fragmentShaderSource, pickColorQualifier) {
  67774. var renamedFS = ShaderSource.replaceMain(fragmentShaderSource, 'czm_old_main');
  67775. var pickMain = pickColorQualifier + ' vec4 czm_pickColor; \n' +
  67776. 'void main() \n' +
  67777. '{ \n' +
  67778. ' czm_old_main(); \n' +
  67779. ' if (gl_FragColor.a == 0.0) { \n' +
  67780. ' discard; \n' +
  67781. ' } \n' +
  67782. ' gl_FragColor = czm_pickColor; \n' +
  67783. '}';
  67784. return renamedFS + '\n' + pickMain;
  67785. };
  67786. ShaderSource.findVarying = function(shaderSource, names) {
  67787. var sources = shaderSource.sources;
  67788. var namesLength = names.length;
  67789. for (var i = 0; i < namesLength; ++i) {
  67790. var name = names[i];
  67791. var sourcesLength = sources.length;
  67792. for (var j = 0; j < sourcesLength; ++j) {
  67793. if (sources[j].indexOf(name) !== -1) {
  67794. return name;
  67795. }
  67796. }
  67797. }
  67798. return undefined;
  67799. };
  67800. var normalVaryingNames = ['v_normalEC', 'v_normal'];
  67801. ShaderSource.findNormalVarying = function(shaderSource) {
  67802. return ShaderSource.findVarying(shaderSource, normalVaryingNames);
  67803. };
  67804. var positionVaryingNames = ['v_positionEC'];
  67805. ShaderSource.findPositionVarying = function(shaderSource) {
  67806. return ShaderSource.findVarying(shaderSource, positionVaryingNames);
  67807. };
  67808. return ShaderSource;
  67809. });
  67810. /*global define*/
  67811. define('Renderer/Buffer',[
  67812. '../Core/defaultValue',
  67813. '../Core/defined',
  67814. '../Core/defineProperties',
  67815. '../Core/destroyObject',
  67816. '../Core/DeveloperError',
  67817. '../Core/IndexDatatype',
  67818. '../Core/WebGLConstants',
  67819. './BufferUsage'
  67820. ], function(
  67821. defaultValue,
  67822. defined,
  67823. defineProperties,
  67824. destroyObject,
  67825. DeveloperError,
  67826. IndexDatatype,
  67827. WebGLConstants,
  67828. BufferUsage) {
  67829. 'use strict';
  67830. /**
  67831. * @private
  67832. */
  67833. function Buffer(options) {
  67834. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  67835. if (!defined(options.context)) {
  67836. throw new DeveloperError('options.context is required.');
  67837. }
  67838. if (!defined(options.typedArray) && !defined(options.sizeInBytes)) {
  67839. throw new DeveloperError('Either options.sizeInBytes or options.typedArray is required.');
  67840. }
  67841. if (defined(options.typedArray) && defined(options.sizeInBytes)) {
  67842. throw new DeveloperError('Cannot pass in both options.sizeInBytes and options.typedArray.');
  67843. }
  67844. if (defined(options.typedArray) && !(typeof options.typedArray === 'object' && typeof options.typedArray.byteLength === 'number')) {
  67845. throw new DeveloperError('options.typedArray must be a typed array');
  67846. }
  67847. if (!BufferUsage.validate(options.usage)) {
  67848. throw new DeveloperError('usage is invalid.');
  67849. }
  67850. var gl = options.context._gl;
  67851. var bufferTarget = options.bufferTarget;
  67852. var typedArray = options.typedArray;
  67853. var sizeInBytes = options.sizeInBytes;
  67854. var usage = options.usage;
  67855. var hasArray = defined(typedArray);
  67856. if (hasArray) {
  67857. sizeInBytes = typedArray.byteLength;
  67858. }
  67859. if (sizeInBytes <= 0) {
  67860. throw new DeveloperError('Buffer size must be greater than zero.');
  67861. }
  67862. var buffer = gl.createBuffer();
  67863. gl.bindBuffer(bufferTarget, buffer);
  67864. gl.bufferData(bufferTarget, hasArray ? typedArray : sizeInBytes, usage);
  67865. gl.bindBuffer(bufferTarget, null);
  67866. this._gl = gl;
  67867. this._bufferTarget = bufferTarget;
  67868. this._sizeInBytes = sizeInBytes;
  67869. this._usage = usage;
  67870. this._buffer = buffer;
  67871. this.vertexArrayDestroyable = true;
  67872. }
  67873. /**
  67874. * Creates a vertex buffer, which contains untyped vertex data in GPU-controlled memory.
  67875. * <br /><br />
  67876. * A vertex array defines the actual makeup of a vertex, e.g., positions, normals, texture coordinates,
  67877. * etc., by interpreting the raw data in one or more vertex buffers.
  67878. *
  67879. * @param {Object} options An object containing the following properties:
  67880. * @param {Context} options.context The context in which to create the buffer
  67881. * @param {ArrayBufferView} [options.typedArray] A typed array containing the data to copy to the buffer.
  67882. * @param {Number} [options.sizeInBytes] A <code>Number</code> defining the size of the buffer in bytes. Required if options.typedArray is not given.
  67883. * @param {BufferUsage} options.usage Specifies the expected usage pattern of the buffer. On some GL implementations, this can significantly affect performance. See {@link BufferUsage}.
  67884. * @returns {VertexBuffer} The vertex buffer, ready to be attached to a vertex array.
  67885. *
  67886. * @exception {DeveloperError} Must specify either <options.typedArray> or <options.sizeInBytes>, but not both.
  67887. * @exception {DeveloperError} The buffer size must be greater than zero.
  67888. * @exception {DeveloperError} Invalid <code>usage</code>.
  67889. *
  67890. *
  67891. * @example
  67892. * // Example 1. Create a dynamic vertex buffer 16 bytes in size.
  67893. * var buffer = Buffer.createVertexBuffer({
  67894. * context : context,
  67895. * sizeInBytes : 16,
  67896. * usage : BufferUsage.DYNAMIC_DRAW
  67897. * });
  67898. *
  67899. * @example
  67900. * // Example 2. Create a dynamic vertex buffer from three floating-point values.
  67901. * // The data copied to the vertex buffer is considered raw bytes until it is
  67902. * // interpreted as vertices using a vertex array.
  67903. * var positionBuffer = buffer.createVertexBuffer({
  67904. * context : context,
  67905. * typedArray : new Float32Array([0, 0, 0]),
  67906. * usage : BufferUsage.STATIC_DRAW
  67907. * });
  67908. *
  67909. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGenBuffer.xml|glGenBuffer}
  67910. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBindBuffer.xml|glBindBuffer} with <code>ARRAY_BUFFER</code>
  67911. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBufferData.xml|glBufferData} with <code>ARRAY_BUFFER</code>
  67912. */
  67913. Buffer.createVertexBuffer = function(options) {
  67914. if (!defined(options.context)) {
  67915. throw new DeveloperError('options.context is required.');
  67916. }
  67917. return new Buffer({
  67918. context: options.context,
  67919. bufferTarget: WebGLConstants.ARRAY_BUFFER,
  67920. typedArray: options.typedArray,
  67921. sizeInBytes: options.sizeInBytes,
  67922. usage: options.usage
  67923. });
  67924. };
  67925. /**
  67926. * Creates an index buffer, which contains typed indices in GPU-controlled memory.
  67927. * <br /><br />
  67928. * An index buffer can be attached to a vertex array to select vertices for rendering.
  67929. * <code>Context.draw</code> can render using the entire index buffer or a subset
  67930. * of the index buffer defined by an offset and count.
  67931. *
  67932. * @param {Object} options An object containing the following properties:
  67933. * @param {Context} options.context The context in which to create the buffer
  67934. * @param {ArrayBufferView} [options.typedArray] A typed array containing the data to copy to the buffer.
  67935. * @param {Number} [options.sizeInBytes] A <code>Number</code> defining the size of the buffer in bytes. Required if options.typedArray is not given.
  67936. * @param {BufferUsage} options.usage Specifies the expected usage pattern of the buffer. On some GL implementations, this can significantly affect performance. See {@link BufferUsage}.
  67937. * @param {IndexDatatype} indexDatatype The datatype of indices in the buffer.
  67938. * @returns {IndexBuffer} The index buffer, ready to be attached to a vertex array.
  67939. *
  67940. * @exception {DeveloperError} Must specify either <options.typedArray> or <options.sizeInBytes>, but not both.
  67941. * @exception {DeveloperError} IndexDatatype.UNSIGNED_INT requires OES_element_index_uint, which is not supported on this system. Check context.elementIndexUint.
  67942. * @exception {DeveloperError} The size in bytes must be greater than zero.
  67943. * @exception {DeveloperError} Invalid <code>usage</code>.
  67944. * @exception {DeveloperError} Invalid <code>indexDatatype</code>.
  67945. *
  67946. *
  67947. * @example
  67948. * // Example 1. Create a stream index buffer of unsigned shorts that is
  67949. * // 16 bytes in size.
  67950. * var buffer = Buffer.createIndexBuffer({
  67951. * context : context,
  67952. * sizeInBytes : 16,
  67953. * usage : BufferUsage.STREAM_DRAW,
  67954. * indexDatatype : IndexDatatype.UNSIGNED_SHORT
  67955. * });
  67956. *
  67957. * @example
  67958. * // Example 2. Create a static index buffer containing three unsigned shorts.
  67959. * var buffer = Buffer.createIndexBuffer({
  67960. * context : context,
  67961. * typedArray : new Uint16Array([0, 1, 2]),
  67962. * usage : BufferUsage.STATIC_DRAW,
  67963. * indexDatatype : IndexDatatype.UNSIGNED_SHORT
  67964. * });
  67965. *
  67966. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGenBuffer.xml|glGenBuffer}
  67967. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBindBuffer.xml|glBindBuffer} with <code>ELEMENT_ARRAY_BUFFER</code>
  67968. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBufferData.xml|glBufferData} with <code>ELEMENT_ARRAY_BUFFER</code>
  67969. */
  67970. Buffer.createIndexBuffer = function(options) {
  67971. if (!defined(options.context)) {
  67972. throw new DeveloperError('options.context is required.');
  67973. }
  67974. if (!IndexDatatype.validate(options.indexDatatype)) {
  67975. throw new DeveloperError('Invalid indexDatatype.');
  67976. }
  67977. if ((options.indexDatatype === IndexDatatype.UNSIGNED_INT) && !options.context.elementIndexUint) {
  67978. throw new DeveloperError('IndexDatatype.UNSIGNED_INT requires OES_element_index_uint, which is not supported on this system. Check context.elementIndexUint.');
  67979. }
  67980. var context = options.context;
  67981. var indexDatatype = options.indexDatatype;
  67982. var bytesPerIndex = IndexDatatype.getSizeInBytes(indexDatatype);
  67983. var buffer = new Buffer({
  67984. context : context,
  67985. bufferTarget : WebGLConstants.ELEMENT_ARRAY_BUFFER,
  67986. typedArray : options.typedArray,
  67987. sizeInBytes : options.sizeInBytes,
  67988. usage : options.usage
  67989. });
  67990. var numberOfIndices = buffer.sizeInBytes / bytesPerIndex;
  67991. defineProperties(buffer, {
  67992. indexDatatype: {
  67993. get : function() {
  67994. return indexDatatype;
  67995. }
  67996. },
  67997. bytesPerIndex : {
  67998. get : function() {
  67999. return bytesPerIndex;
  68000. }
  68001. },
  68002. numberOfIndices : {
  68003. get : function() {
  68004. return numberOfIndices;
  68005. }
  68006. }
  68007. });
  68008. return buffer;
  68009. };
  68010. defineProperties(Buffer.prototype, {
  68011. sizeInBytes : {
  68012. get : function() {
  68013. return this._sizeInBytes;
  68014. }
  68015. },
  68016. usage: {
  68017. get : function() {
  68018. return this._usage;
  68019. }
  68020. }
  68021. });
  68022. Buffer.prototype._getBuffer = function() {
  68023. return this._buffer;
  68024. };
  68025. Buffer.prototype.copyFromArrayView = function(arrayView, offsetInBytes) {
  68026. offsetInBytes = defaultValue(offsetInBytes, 0);
  68027. if (!arrayView) {
  68028. throw new DeveloperError('arrayView is required.');
  68029. }
  68030. if (offsetInBytes + arrayView.byteLength > this._sizeInBytes) {
  68031. throw new DeveloperError('This buffer is not large enough.');
  68032. }
  68033. var gl = this._gl;
  68034. var target = this._bufferTarget;
  68035. gl.bindBuffer(target, this._buffer);
  68036. gl.bufferSubData(target, offsetInBytes, arrayView);
  68037. gl.bindBuffer(target, null);
  68038. };
  68039. Buffer.prototype.isDestroyed = function() {
  68040. return false;
  68041. };
  68042. Buffer.prototype.destroy = function() {
  68043. this._gl.deleteBuffer(this._buffer);
  68044. return destroyObject(this);
  68045. };
  68046. return Buffer;
  68047. });
  68048. /*global define*/
  68049. define('Renderer/VertexArray',[
  68050. '../Core/ComponentDatatype',
  68051. '../Core/defaultValue',
  68052. '../Core/defined',
  68053. '../Core/defineProperties',
  68054. '../Core/destroyObject',
  68055. '../Core/DeveloperError',
  68056. '../Core/Geometry',
  68057. '../Core/IndexDatatype',
  68058. '../Core/Math',
  68059. '../Core/RuntimeError',
  68060. './Buffer',
  68061. './BufferUsage',
  68062. './ContextLimits'
  68063. ], function(
  68064. ComponentDatatype,
  68065. defaultValue,
  68066. defined,
  68067. defineProperties,
  68068. destroyObject,
  68069. DeveloperError,
  68070. Geometry,
  68071. IndexDatatype,
  68072. CesiumMath,
  68073. RuntimeError,
  68074. Buffer,
  68075. BufferUsage,
  68076. ContextLimits) {
  68077. 'use strict';
  68078. function addAttribute(attributes, attribute, index, context) {
  68079. var hasVertexBuffer = defined(attribute.vertexBuffer);
  68080. var hasValue = defined(attribute.value);
  68081. var componentsPerAttribute = attribute.value ? attribute.value.length : attribute.componentsPerAttribute;
  68082. if (!hasVertexBuffer && !hasValue) {
  68083. throw new DeveloperError('attribute must have a vertexBuffer or a value.');
  68084. }
  68085. if (hasVertexBuffer && hasValue) {
  68086. throw new DeveloperError('attribute cannot have both a vertexBuffer and a value. It must have either a vertexBuffer property defining per-vertex data or a value property defining data for all vertices.');
  68087. }
  68088. if ((componentsPerAttribute !== 1) &&
  68089. (componentsPerAttribute !== 2) &&
  68090. (componentsPerAttribute !== 3) &&
  68091. (componentsPerAttribute !== 4)) {
  68092. if (hasValue) {
  68093. throw new DeveloperError('attribute.value.length must be in the range [1, 4].');
  68094. }
  68095. throw new DeveloperError('attribute.componentsPerAttribute must be in the range [1, 4].');
  68096. }
  68097. if (defined(attribute.componentDatatype) && !ComponentDatatype.validate(attribute.componentDatatype)) {
  68098. throw new DeveloperError('attribute must have a valid componentDatatype or not specify it.');
  68099. }
  68100. if (defined(attribute.strideInBytes) && (attribute.strideInBytes > 255)) {
  68101. // WebGL limit. Not in GL ES.
  68102. throw new DeveloperError('attribute must have a strideInBytes less than or equal to 255 or not specify it.');
  68103. }
  68104. if (defined(attribute.instanceDivisor) && (attribute.instanceDivisor > 0) && !context.instancedArrays) {
  68105. throw new DeveloperError('instanced arrays is not supported');
  68106. }
  68107. if (defined(attribute.instanceDivisor) && (attribute.instanceDivisor < 0)) {
  68108. throw new DeveloperError('attribute must have an instanceDivisor greater than or equal to zero');
  68109. }
  68110. if (defined(attribute.instanceDivisor) && hasValue) {
  68111. throw new DeveloperError('attribute cannot have have an instanceDivisor if it is not backed by a buffer');
  68112. }
  68113. if (defined(attribute.instanceDivisor) && (attribute.instanceDivisor > 0) && (attribute.index === 0)) {
  68114. throw new DeveloperError('attribute zero cannot have an instanceDivisor greater than 0');
  68115. }
  68116. // Shallow copy the attribute; we do not want to copy the vertex buffer.
  68117. var attr = {
  68118. index : defaultValue(attribute.index, index),
  68119. enabled : defaultValue(attribute.enabled, true),
  68120. vertexBuffer : attribute.vertexBuffer,
  68121. value : hasValue ? attribute.value.slice(0) : undefined,
  68122. componentsPerAttribute : componentsPerAttribute,
  68123. componentDatatype : defaultValue(attribute.componentDatatype, ComponentDatatype.FLOAT),
  68124. normalize : defaultValue(attribute.normalize, false),
  68125. offsetInBytes : defaultValue(attribute.offsetInBytes, 0),
  68126. strideInBytes : defaultValue(attribute.strideInBytes, 0),
  68127. instanceDivisor : defaultValue(attribute.instanceDivisor, 0)
  68128. };
  68129. if (hasVertexBuffer) {
  68130. // Common case: vertex buffer for per-vertex data
  68131. attr.vertexAttrib = function(gl) {
  68132. var index = this.index;
  68133. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer._getBuffer());
  68134. gl.vertexAttribPointer(index, this.componentsPerAttribute, this.componentDatatype, this.normalize, this.strideInBytes, this.offsetInBytes);
  68135. gl.enableVertexAttribArray(index);
  68136. if (this.instanceDivisor > 0) {
  68137. context.glVertexAttribDivisor(index, this.instanceDivisor);
  68138. context._vertexAttribDivisors[index] = this.instanceDivisor;
  68139. context._previousDrawInstanced = true;
  68140. }
  68141. };
  68142. attr.disableVertexAttribArray = function(gl) {
  68143. gl.disableVertexAttribArray(this.index);
  68144. if (this.instanceDivisor > 0) {
  68145. context.glVertexAttribDivisor(index, 0);
  68146. }
  68147. };
  68148. } else {
  68149. // Less common case: value array for the same data for each vertex
  68150. switch (attr.componentsPerAttribute) {
  68151. case 1:
  68152. attr.vertexAttrib = function(gl) {
  68153. gl.vertexAttrib1fv(this.index, this.value);
  68154. };
  68155. break;
  68156. case 2:
  68157. attr.vertexAttrib = function(gl) {
  68158. gl.vertexAttrib2fv(this.index, this.value);
  68159. };
  68160. break;
  68161. case 3:
  68162. attr.vertexAttrib = function(gl) {
  68163. gl.vertexAttrib3fv(this.index, this.value);
  68164. };
  68165. break;
  68166. case 4:
  68167. attr.vertexAttrib = function(gl) {
  68168. gl.vertexAttrib4fv(this.index, this.value);
  68169. };
  68170. break;
  68171. }
  68172. attr.disableVertexAttribArray = function(gl) {
  68173. };
  68174. }
  68175. attributes.push(attr);
  68176. }
  68177. function bind(gl, attributes, indexBuffer) {
  68178. for ( var i = 0; i < attributes.length; ++i) {
  68179. var attribute = attributes[i];
  68180. if (attribute.enabled) {
  68181. attribute.vertexAttrib(gl);
  68182. }
  68183. }
  68184. if (defined(indexBuffer)) {
  68185. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer._getBuffer());
  68186. }
  68187. }
  68188. /**
  68189. * Creates a vertex array, which defines the attributes making up a vertex, and contains an optional index buffer
  68190. * to select vertices for rendering. Attributes are defined using object literals as shown in Example 1 below.
  68191. *
  68192. * @param {Object} options Object with the following properties:
  68193. * @param {Context} options.context The context in which the VertexArray gets created.
  68194. * @param {Object[]} options.attributes An array of attributes.
  68195. * @param {IndexBuffer} [options.indexBuffer] An optional index buffer.
  68196. *
  68197. * @returns {VertexArray} The vertex array, ready for use with drawing.
  68198. *
  68199. * @exception {DeveloperError} Attribute must have a <code>vertexBuffer</code>.
  68200. * @exception {DeveloperError} Attribute must have a <code>componentsPerAttribute</code>.
  68201. * @exception {DeveloperError} Attribute must have a valid <code>componentDatatype</code> or not specify it.
  68202. * @exception {DeveloperError} Attribute must have a <code>strideInBytes</code> less than or equal to 255 or not specify it.
  68203. * @exception {DeveloperError} Index n is used by more than one attribute.
  68204. *
  68205. *
  68206. * @example
  68207. * // Example 1. Create a vertex array with vertices made up of three floating point
  68208. * // values, e.g., a position, from a single vertex buffer. No index buffer is used.
  68209. * var positionBuffer = Buffer.createVertexBuffer({
  68210. * context : context,
  68211. * sizeInBytes : 12,
  68212. * usage : BufferUsage.STATIC_DRAW
  68213. * });
  68214. * var attributes = [
  68215. * {
  68216. * index : 0,
  68217. * enabled : true,
  68218. * vertexBuffer : positionBuffer,
  68219. * componentsPerAttribute : 3,
  68220. * componentDatatype : ComponentDatatype.FLOAT,
  68221. * normalize : false,
  68222. * offsetInBytes : 0,
  68223. * strideInBytes : 0 // tightly packed
  68224. * instanceDivisor : 0 // not instanced
  68225. * }
  68226. * ];
  68227. * var va = new VertexArray({
  68228. * context : context,
  68229. * attributes : attributes
  68230. * });
  68231. *
  68232. * @example
  68233. * // Example 2. Create a vertex array with vertices from two different vertex buffers.
  68234. * // Each vertex has a three-component position and three-component normal.
  68235. * var positionBuffer = Buffer.createVertexBuffer({
  68236. * context : context,
  68237. * sizeInBytes : 12,
  68238. * usage : BufferUsage.STATIC_DRAW
  68239. * });
  68240. * var normalBuffer = Buffer.createVertexBuffer({
  68241. * context : context,
  68242. * sizeInBytes : 12,
  68243. * usage : BufferUsage.STATIC_DRAW
  68244. * });
  68245. * var attributes = [
  68246. * {
  68247. * index : 0,
  68248. * vertexBuffer : positionBuffer,
  68249. * componentsPerAttribute : 3,
  68250. * componentDatatype : ComponentDatatype.FLOAT
  68251. * },
  68252. * {
  68253. * index : 1,
  68254. * vertexBuffer : normalBuffer,
  68255. * componentsPerAttribute : 3,
  68256. * componentDatatype : ComponentDatatype.FLOAT
  68257. * }
  68258. * ];
  68259. * var va = new VertexArray({
  68260. * context : context,
  68261. * attributes : attributes
  68262. * });
  68263. *
  68264. * @example
  68265. * // Example 3. Creates the same vertex layout as Example 2 using a single
  68266. * // vertex buffer, instead of two.
  68267. * var buffer = Buffer.createVertexBuffer({
  68268. * context : context,
  68269. * sizeInBytes : 24,
  68270. * usage : BufferUsage.STATIC_DRAW
  68271. * });
  68272. * var attributes = [
  68273. * {
  68274. * vertexBuffer : buffer,
  68275. * componentsPerAttribute : 3,
  68276. * componentDatatype : ComponentDatatype.FLOAT,
  68277. * offsetInBytes : 0,
  68278. * strideInBytes : 24
  68279. * },
  68280. * {
  68281. * vertexBuffer : buffer,
  68282. * componentsPerAttribute : 3,
  68283. * componentDatatype : ComponentDatatype.FLOAT,
  68284. * normalize : true,
  68285. * offsetInBytes : 12,
  68286. * strideInBytes : 24
  68287. * }
  68288. * ];
  68289. * var va = new VertexArray({
  68290. * context : context,
  68291. * attributes : attributes
  68292. * });
  68293. *
  68294. * @see Buffer#createVertexBuffer
  68295. * @see Buffer#createIndexBuffer
  68296. * @see Context#draw
  68297. *
  68298. * @private
  68299. */
  68300. function VertexArray(options) {
  68301. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  68302. if (!defined(options.context)) {
  68303. throw new DeveloperError('options.context is required.');
  68304. }
  68305. if (!defined(options.attributes)) {
  68306. throw new DeveloperError('options.attributes is required.');
  68307. }
  68308. var context = options.context;
  68309. var gl = context._gl;
  68310. var attributes = options.attributes;
  68311. var indexBuffer = options.indexBuffer;
  68312. var i;
  68313. var vaAttributes = [];
  68314. var numberOfVertices = 1; // if every attribute is backed by a single value
  68315. var hasInstancedAttributes = false;
  68316. var length = attributes.length;
  68317. for (i = 0; i < length; ++i) {
  68318. addAttribute(vaAttributes, attributes[i], i, context);
  68319. }
  68320. length = vaAttributes.length;
  68321. for (i = 0; i < length; ++i) {
  68322. var attribute = vaAttributes[i];
  68323. if (defined(attribute.vertexBuffer) && (attribute.instanceDivisor === 0)) {
  68324. // This assumes that each vertex buffer in the vertex array has the same number of vertices.
  68325. var bytes = attribute.strideInBytes || (attribute.componentsPerAttribute * ComponentDatatype.getSizeInBytes(attribute.componentDatatype));
  68326. numberOfVertices = attribute.vertexBuffer.sizeInBytes / bytes;
  68327. break;
  68328. }
  68329. }
  68330. for (i = 0; i < length; ++i) {
  68331. if (vaAttributes[i].instanceDivisor > 0) {
  68332. hasInstancedAttributes = true;
  68333. break;
  68334. }
  68335. }
  68336. // Verify all attribute names are unique
  68337. var uniqueIndices = {};
  68338. for (i = 0; i < length; ++i) {
  68339. var index = vaAttributes[i].index;
  68340. if (uniqueIndices[index]) {
  68341. throw new DeveloperError('Index ' + index + ' is used by more than one attribute.');
  68342. }
  68343. uniqueIndices[index] = true;
  68344. }
  68345. var vao;
  68346. // Setup VAO if supported
  68347. if (context.vertexArrayObject) {
  68348. vao = context.glCreateVertexArray();
  68349. context.glBindVertexArray(vao);
  68350. bind(gl, vaAttributes, indexBuffer);
  68351. context.glBindVertexArray(null);
  68352. }
  68353. this._numberOfVertices = numberOfVertices;
  68354. this._hasInstancedAttributes = hasInstancedAttributes;
  68355. this._context = context;
  68356. this._gl = gl;
  68357. this._vao = vao;
  68358. this._attributes = vaAttributes;
  68359. this._indexBuffer = indexBuffer;
  68360. }
  68361. function computeNumberOfVertices(attribute) {
  68362. return attribute.values.length / attribute.componentsPerAttribute;
  68363. }
  68364. function computeAttributeSizeInBytes(attribute) {
  68365. return ComponentDatatype.getSizeInBytes(attribute.componentDatatype) * attribute.componentsPerAttribute;
  68366. }
  68367. function interleaveAttributes(attributes) {
  68368. var j;
  68369. var name;
  68370. var attribute;
  68371. // Extract attribute names.
  68372. var names = [];
  68373. for (name in attributes) {
  68374. // Attribute needs to have per-vertex values; not a constant value for all vertices.
  68375. if (attributes.hasOwnProperty(name) &&
  68376. defined(attributes[name]) &&
  68377. defined(attributes[name].values)) {
  68378. names.push(name);
  68379. if (attributes[name].componentDatatype === ComponentDatatype.DOUBLE) {
  68380. attributes[name].componentDatatype = ComponentDatatype.FLOAT;
  68381. attributes[name].values = ComponentDatatype.createTypedArray(ComponentDatatype.FLOAT, attributes[name].values);
  68382. }
  68383. }
  68384. }
  68385. // Validation. Compute number of vertices.
  68386. var numberOfVertices;
  68387. var namesLength = names.length;
  68388. if (namesLength > 0) {
  68389. numberOfVertices = computeNumberOfVertices(attributes[names[0]]);
  68390. for (j = 1; j < namesLength; ++j) {
  68391. var currentNumberOfVertices = computeNumberOfVertices(attributes[names[j]]);
  68392. if (currentNumberOfVertices !== numberOfVertices) {
  68393. throw new RuntimeError(
  68394. 'Each attribute list must have the same number of vertices. ' +
  68395. 'Attribute ' + names[j] + ' has a different number of vertices ' +
  68396. '(' + currentNumberOfVertices.toString() + ')' +
  68397. ' than attribute ' + names[0] +
  68398. ' (' + numberOfVertices.toString() + ').');
  68399. }
  68400. }
  68401. }
  68402. // Sort attributes by the size of their components. From left to right, a vertex stores floats, shorts, and then bytes.
  68403. names.sort(function(left, right) {
  68404. return ComponentDatatype.getSizeInBytes(attributes[right].componentDatatype) - ComponentDatatype.getSizeInBytes(attributes[left].componentDatatype);
  68405. });
  68406. // Compute sizes and strides.
  68407. var vertexSizeInBytes = 0;
  68408. var offsetsInBytes = {};
  68409. for (j = 0; j < namesLength; ++j) {
  68410. name = names[j];
  68411. attribute = attributes[name];
  68412. offsetsInBytes[name] = vertexSizeInBytes;
  68413. vertexSizeInBytes += computeAttributeSizeInBytes(attribute);
  68414. }
  68415. if (vertexSizeInBytes > 0) {
  68416. // Pad each vertex to be a multiple of the largest component datatype so each
  68417. // attribute can be addressed using typed arrays.
  68418. var maxComponentSizeInBytes = ComponentDatatype.getSizeInBytes(attributes[names[0]].componentDatatype); // Sorted large to small
  68419. var remainder = vertexSizeInBytes % maxComponentSizeInBytes;
  68420. if (remainder !== 0) {
  68421. vertexSizeInBytes += (maxComponentSizeInBytes - remainder);
  68422. }
  68423. // Total vertex buffer size in bytes, including per-vertex padding.
  68424. var vertexBufferSizeInBytes = numberOfVertices * vertexSizeInBytes;
  68425. // Create array for interleaved vertices. Each attribute has a different view (pointer) into the array.
  68426. var buffer = new ArrayBuffer(vertexBufferSizeInBytes);
  68427. var views = {};
  68428. for (j = 0; j < namesLength; ++j) {
  68429. name = names[j];
  68430. var sizeInBytes = ComponentDatatype.getSizeInBytes(attributes[name].componentDatatype);
  68431. views[name] = {
  68432. pointer : ComponentDatatype.createTypedArray(attributes[name].componentDatatype, buffer),
  68433. index : offsetsInBytes[name] / sizeInBytes, // Offset in ComponentType
  68434. strideInComponentType : vertexSizeInBytes / sizeInBytes
  68435. };
  68436. }
  68437. // Copy attributes into one interleaved array.
  68438. // PERFORMANCE_IDEA: Can we optimize these loops?
  68439. for (j = 0; j < numberOfVertices; ++j) {
  68440. for ( var n = 0; n < namesLength; ++n) {
  68441. name = names[n];
  68442. attribute = attributes[name];
  68443. var values = attribute.values;
  68444. var view = views[name];
  68445. var pointer = view.pointer;
  68446. var numberOfComponents = attribute.componentsPerAttribute;
  68447. for ( var k = 0; k < numberOfComponents; ++k) {
  68448. pointer[view.index + k] = values[(j * numberOfComponents) + k];
  68449. }
  68450. view.index += view.strideInComponentType;
  68451. }
  68452. }
  68453. return {
  68454. buffer : buffer,
  68455. offsetsInBytes : offsetsInBytes,
  68456. vertexSizeInBytes : vertexSizeInBytes
  68457. };
  68458. }
  68459. // No attributes to interleave.
  68460. return undefined;
  68461. }
  68462. /**
  68463. * Creates a vertex array from a geometry. A geometry contains vertex attributes and optional index data
  68464. * in system memory, whereas a vertex array contains vertex buffers and an optional index buffer in WebGL
  68465. * memory for use with rendering.
  68466. * <br /><br />
  68467. * The <code>geometry</code> argument should use the standard layout like the geometry returned by {@link BoxGeometry}.
  68468. * <br /><br />
  68469. * <code>options</code> can have four properties:
  68470. * <ul>
  68471. * <li><code>geometry</code>: The source geometry containing data used to create the vertex array.</li>
  68472. * <li><code>attributeLocations</code>: An object that maps geometry attribute names to vertex shader attribute locations.</li>
  68473. * <li><code>bufferUsage</code>: The expected usage pattern of the vertex array's buffers. On some WebGL implementations, this can significantly affect performance. See {@link BufferUsage}. Default: <code>BufferUsage.DYNAMIC_DRAW</code>.</li>
  68474. * <li><code>interleave</code>: Determines if all attributes are interleaved in a single vertex buffer or if each attribute is stored in a separate vertex buffer. Default: <code>false</code>.</li>
  68475. * </ul>
  68476. * <br />
  68477. * If <code>options</code> is not specified or the <code>geometry</code> contains no data, the returned vertex array is empty.
  68478. *
  68479. * @param {Object} options An object defining the geometry, attribute indices, buffer usage, and vertex layout used to create the vertex array.
  68480. *
  68481. * @exception {RuntimeError} Each attribute list must have the same number of vertices.
  68482. * @exception {DeveloperError} The geometry must have zero or one index lists.
  68483. * @exception {DeveloperError} Index n is used by more than one attribute.
  68484. *
  68485. *
  68486. * @example
  68487. * // Example 1. Creates a vertex array for rendering a box. The default dynamic draw
  68488. * // usage is used for the created vertex and index buffer. The attributes are not
  68489. * // interleaved by default.
  68490. * var geometry = new BoxGeometry();
  68491. * var va = VertexArray.fromGeometry({
  68492. * context : context,
  68493. * geometry : geometry,
  68494. * attributeLocations : GeometryPipeline.createAttributeLocations(geometry),
  68495. * });
  68496. *
  68497. * @example
  68498. * // Example 2. Creates a vertex array with interleaved attributes in a
  68499. * // single vertex buffer. The vertex and index buffer have static draw usage.
  68500. * var va = VertexArray.fromGeometry({
  68501. * context : context,
  68502. * geometry : geometry,
  68503. * attributeLocations : GeometryPipeline.createAttributeLocations(geometry),
  68504. * bufferUsage : BufferUsage.STATIC_DRAW,
  68505. * interleave : true
  68506. * });
  68507. *
  68508. * @example
  68509. * // Example 3. When the caller destroys the vertex array, it also destroys the
  68510. * // attached vertex buffer(s) and index buffer.
  68511. * va = va.destroy();
  68512. *
  68513. * @see Buffer#createVertexBuffer
  68514. * @see Buffer#createIndexBuffer
  68515. * @see GeometryPipeline.createAttributeLocations
  68516. * @see ShaderProgram
  68517. */
  68518. VertexArray.fromGeometry = function(options) {
  68519. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  68520. if (!defined(options.context)) {
  68521. throw new DeveloperError('options.context is required.');
  68522. }
  68523. var context = options.context;
  68524. var geometry = defaultValue(options.geometry, defaultValue.EMPTY_OBJECT);
  68525. var bufferUsage = defaultValue(options.bufferUsage, BufferUsage.DYNAMIC_DRAW);
  68526. var attributeLocations = defaultValue(options.attributeLocations, defaultValue.EMPTY_OBJECT);
  68527. var interleave = defaultValue(options.interleave, false);
  68528. var createdVAAttributes = options.vertexArrayAttributes;
  68529. var name;
  68530. var attribute;
  68531. var vertexBuffer;
  68532. var vaAttributes = (defined(createdVAAttributes)) ? createdVAAttributes : [];
  68533. var attributes = geometry.attributes;
  68534. if (interleave) {
  68535. // Use a single vertex buffer with interleaved vertices.
  68536. var interleavedAttributes = interleaveAttributes(attributes);
  68537. if (defined(interleavedAttributes)) {
  68538. vertexBuffer = Buffer.createVertexBuffer({
  68539. context : context,
  68540. typedArray : interleavedAttributes.buffer,
  68541. usage : bufferUsage
  68542. });
  68543. var offsetsInBytes = interleavedAttributes.offsetsInBytes;
  68544. var strideInBytes = interleavedAttributes.vertexSizeInBytes;
  68545. for (name in attributes) {
  68546. if (attributes.hasOwnProperty(name) && defined(attributes[name])) {
  68547. attribute = attributes[name];
  68548. if (defined(attribute.values)) {
  68549. // Common case: per-vertex attributes
  68550. vaAttributes.push({
  68551. index : attributeLocations[name],
  68552. vertexBuffer : vertexBuffer,
  68553. componentDatatype : attribute.componentDatatype,
  68554. componentsPerAttribute : attribute.componentsPerAttribute,
  68555. normalize : attribute.normalize,
  68556. offsetInBytes : offsetsInBytes[name],
  68557. strideInBytes : strideInBytes
  68558. });
  68559. } else {
  68560. // Constant attribute for all vertices
  68561. vaAttributes.push({
  68562. index : attributeLocations[name],
  68563. value : attribute.value,
  68564. componentDatatype : attribute.componentDatatype,
  68565. normalize : attribute.normalize
  68566. });
  68567. }
  68568. }
  68569. }
  68570. }
  68571. } else {
  68572. // One vertex buffer per attribute.
  68573. for (name in attributes) {
  68574. if (attributes.hasOwnProperty(name) && defined(attributes[name])) {
  68575. attribute = attributes[name];
  68576. var componentDatatype = attribute.componentDatatype;
  68577. if (componentDatatype === ComponentDatatype.DOUBLE) {
  68578. componentDatatype = ComponentDatatype.FLOAT;
  68579. }
  68580. vertexBuffer = undefined;
  68581. if (defined(attribute.values)) {
  68582. vertexBuffer = Buffer.createVertexBuffer({
  68583. context : context,
  68584. typedArray : ComponentDatatype.createTypedArray(componentDatatype, attribute.values),
  68585. usage : bufferUsage
  68586. });
  68587. }
  68588. vaAttributes.push({
  68589. index : attributeLocations[name],
  68590. vertexBuffer : vertexBuffer,
  68591. value : attribute.value,
  68592. componentDatatype : componentDatatype,
  68593. componentsPerAttribute : attribute.componentsPerAttribute,
  68594. normalize : attribute.normalize
  68595. });
  68596. }
  68597. }
  68598. }
  68599. var indexBuffer;
  68600. var indices = geometry.indices;
  68601. if (defined(indices)) {
  68602. if ((Geometry.computeNumberOfVertices(geometry) >= CesiumMath.SIXTY_FOUR_KILOBYTES) && context.elementIndexUint) {
  68603. indexBuffer = Buffer.createIndexBuffer({
  68604. context : context,
  68605. typedArray : new Uint32Array(indices),
  68606. usage : bufferUsage,
  68607. indexDatatype : IndexDatatype.UNSIGNED_INT
  68608. });
  68609. } else{
  68610. indexBuffer = Buffer.createIndexBuffer({
  68611. context : context,
  68612. typedArray : new Uint16Array(indices),
  68613. usage : bufferUsage,
  68614. indexDatatype : IndexDatatype.UNSIGNED_SHORT
  68615. });
  68616. }
  68617. }
  68618. return new VertexArray({
  68619. context : context,
  68620. attributes : vaAttributes,
  68621. indexBuffer : indexBuffer
  68622. });
  68623. };
  68624. defineProperties(VertexArray.prototype, {
  68625. numberOfAttributes : {
  68626. get : function() {
  68627. return this._attributes.length;
  68628. }
  68629. },
  68630. numberOfVertices : {
  68631. get : function() {
  68632. return this._numberOfVertices;
  68633. }
  68634. },
  68635. indexBuffer : {
  68636. get : function() {
  68637. return this._indexBuffer;
  68638. }
  68639. }
  68640. });
  68641. /**
  68642. * index is the location in the array of attributes, not the index property of an attribute.
  68643. */
  68644. VertexArray.prototype.getAttribute = function(index) {
  68645. if (!defined(index)) {
  68646. throw new DeveloperError('index is required.');
  68647. }
  68648. return this._attributes[index];
  68649. };
  68650. // Workaround for ANGLE, where the attribute divisor seems to be part of the global state instead
  68651. // of the VAO state. This function is called when the vao is bound, and should be removed
  68652. // once the ANGLE issue is resolved. Setting the divisor should normally happen in vertexAttrib and
  68653. // disableVertexAttribArray.
  68654. function setVertexAttribDivisor(vertexArray) {
  68655. var context = vertexArray._context;
  68656. var hasInstancedAttributes = vertexArray._hasInstancedAttributes;
  68657. if (!hasInstancedAttributes && !context._previousDrawInstanced) {
  68658. return;
  68659. }
  68660. context._previousDrawInstanced = hasInstancedAttributes;
  68661. var divisors = context._vertexAttribDivisors;
  68662. var attributes = vertexArray._attributes;
  68663. var maxAttributes = ContextLimits.maximumVertexAttributes;
  68664. var i;
  68665. if (hasInstancedAttributes) {
  68666. var length = attributes.length;
  68667. for (i = 0; i < length; ++i) {
  68668. var attribute = attributes[i];
  68669. if (attribute.enabled) {
  68670. var divisor = attribute.instanceDivisor;
  68671. var index = attribute.index;
  68672. if (divisor !== divisors[index]) {
  68673. context.glVertexAttribDivisor(index, divisor);
  68674. divisors[index] = divisor;
  68675. }
  68676. }
  68677. }
  68678. } else {
  68679. for (i = 0; i < maxAttributes; ++i) {
  68680. if (divisors[i] > 0) {
  68681. context.glVertexAttribDivisor(i, 0);
  68682. divisors[i] = 0;
  68683. }
  68684. }
  68685. }
  68686. }
  68687. VertexArray.prototype._bind = function() {
  68688. if (defined(this._vao)) {
  68689. this._context.glBindVertexArray(this._vao);
  68690. if (this._context.instancedArrays) {
  68691. setVertexAttribDivisor(this);
  68692. }
  68693. } else {
  68694. bind(this._gl, this._attributes, this._indexBuffer);
  68695. }
  68696. };
  68697. VertexArray.prototype._unBind = function() {
  68698. if (defined(this._vao)) {
  68699. this._context.glBindVertexArray(null);
  68700. } else {
  68701. var attributes = this._attributes;
  68702. var gl = this._gl;
  68703. for ( var i = 0; i < attributes.length; ++i) {
  68704. var attribute = attributes[i];
  68705. if (attribute.enabled) {
  68706. attribute.disableVertexAttribArray(gl);
  68707. }
  68708. }
  68709. if (this._indexBuffer) {
  68710. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
  68711. }
  68712. }
  68713. };
  68714. VertexArray.prototype.isDestroyed = function() {
  68715. return false;
  68716. };
  68717. VertexArray.prototype.destroy = function() {
  68718. var attributes = this._attributes;
  68719. for ( var i = 0; i < attributes.length; ++i) {
  68720. var vertexBuffer = attributes[i].vertexBuffer;
  68721. if (defined(vertexBuffer) && !vertexBuffer.isDestroyed() && vertexBuffer.vertexArrayDestroyable) {
  68722. vertexBuffer.destroy();
  68723. }
  68724. }
  68725. var indexBuffer = this._indexBuffer;
  68726. if (defined(indexBuffer) && !indexBuffer.isDestroyed() && indexBuffer.vertexArrayDestroyable) {
  68727. indexBuffer.destroy();
  68728. }
  68729. if (defined(this._vao)) {
  68730. this._context.glDeleteVertexArray(this._vao);
  68731. }
  68732. return destroyObject(this);
  68733. };
  68734. return VertexArray;
  68735. });
  68736. /*global define*/
  68737. define('Scene/BatchTable',[
  68738. '../Core/Cartesian2',
  68739. '../Core/Cartesian3',
  68740. '../Core/Cartesian4',
  68741. '../Core/combine',
  68742. '../Core/ComponentDatatype',
  68743. '../Core/defined',
  68744. '../Core/defineProperties',
  68745. '../Core/destroyObject',
  68746. '../Core/DeveloperError',
  68747. '../Core/Math',
  68748. '../Core/PixelFormat',
  68749. '../Core/RuntimeError',
  68750. '../Renderer/ContextLimits',
  68751. '../Renderer/PixelDatatype',
  68752. '../Renderer/Sampler',
  68753. '../Renderer/Texture',
  68754. '../Renderer/TextureMagnificationFilter',
  68755. '../Renderer/TextureMinificationFilter'
  68756. ], function(
  68757. Cartesian2,
  68758. Cartesian3,
  68759. Cartesian4,
  68760. combine,
  68761. ComponentDatatype,
  68762. defined,
  68763. defineProperties,
  68764. destroyObject,
  68765. DeveloperError,
  68766. CesiumMath,
  68767. PixelFormat,
  68768. RuntimeError,
  68769. ContextLimits,
  68770. PixelDatatype,
  68771. Sampler,
  68772. Texture,
  68773. TextureMagnificationFilter,
  68774. TextureMinificationFilter) {
  68775. 'use strict';
  68776. /**
  68777. * Creates a texture to look up per instance attributes for batched primitives. For example, store each primitive's pick color in the texture.
  68778. *
  68779. * @alias BatchTable
  68780. * @constructor
  68781. * @private
  68782. *
  68783. * @param {Context} context The context in which the batch table is created.
  68784. * @param {Object[]} attributes An array of objects describing a per instance attribute. Each object contains a datatype, components per attributes, whether it is normalized and a function name
  68785. * to retrieve the value in the vertex shader.
  68786. * @param {Number} numberOfInstances The number of instances in a batch table.
  68787. *
  68788. * @example
  68789. * // create the batch table
  68790. * var attributes = [{
  68791. * functionName : 'getShow',
  68792. * componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
  68793. * componentsPerAttribute : 1
  68794. * }, {
  68795. * functionName : 'getPickColor',
  68796. * componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
  68797. * componentsPerAttribute : 4,
  68798. * normalize : true
  68799. * }];
  68800. * var batchTable = new BatchTable(context, attributes, 5);
  68801. *
  68802. * // when creating the draw commands, update the uniform map and the vertex shader
  68803. * vertexShaderSource = batchTable.getVertexShaderCallback()(vertexShaderSource);
  68804. * var shaderProgram = ShaderProgram.fromCache({
  68805. * // ...
  68806. * vertexShaderSource : vertexShaderSource,
  68807. * });
  68808. *
  68809. * drawCommand.shaderProgram = shaderProgram;
  68810. * drawCommand.uniformMap = batchTable.getUniformMapCallback()(uniformMap);
  68811. *
  68812. * // use the attribute function names in the shader to retrieve the instance values
  68813. * // ...
  68814. * attribute float batchId;
  68815. *
  68816. * void main() {
  68817. * // ...
  68818. * float show = getShow(batchId);
  68819. * vec3 pickColor = getPickColor(batchId);
  68820. * // ...
  68821. * }
  68822. */
  68823. function BatchTable(context, attributes, numberOfInstances) {
  68824. if (!defined(context)) {
  68825. throw new DeveloperError('context is required');
  68826. }
  68827. if (!defined(attributes)) {
  68828. throw new DeveloperError('attributes is required');
  68829. }
  68830. if (!defined(numberOfInstances)) {
  68831. throw new DeveloperError('numberOfInstances is required');
  68832. }
  68833. this._attributes = attributes;
  68834. this._numberOfInstances = numberOfInstances;
  68835. if (attributes.length === 0) {
  68836. return;
  68837. }
  68838. // PERFORMANCE_IDEA: We may be able to arrange the attributes so they can be packing into fewer texels.
  68839. // Right now, an attribute with one component uses an entire texel when 4 single component attributes can
  68840. // be packed into a texel.
  68841. //
  68842. // Packing floats into unsigned byte textures makes the problem worse. A single component float attribute
  68843. // will be packed into a single texel leaving 3 texels unused. 4 texels are reserved for each float attribute
  68844. // regardless of how many components it has.
  68845. var pixelDatatype = getDatatype(attributes);
  68846. var textureFloatSupported = context.floatingPointTexture;
  68847. var packFloats = pixelDatatype === PixelDatatype.FLOAT && !textureFloatSupported;
  68848. var offsets = createOffsets(attributes, packFloats);
  68849. var stride = getStride(offsets, attributes, packFloats);
  68850. var maxNumberOfInstancesPerRow = Math.floor(ContextLimits.maximumTextureSize / stride);
  68851. var instancesPerWidth = Math.min(numberOfInstances, maxNumberOfInstancesPerRow);
  68852. var width = stride * instancesPerWidth;
  68853. var height = Math.ceil(numberOfInstances / instancesPerWidth);
  68854. var stepX = 1.0 / width;
  68855. var centerX = stepX * 0.5;
  68856. var stepY = 1.0 / height;
  68857. var centerY = stepY * 0.5;
  68858. this._textureDimensions = new Cartesian2(width, height);
  68859. this._textureStep = new Cartesian4(stepX, centerX, stepY, centerY);
  68860. this._pixelDatatype = !packFloats ? pixelDatatype : PixelDatatype.UNSIGNED_BYTE;
  68861. this._packFloats = packFloats;
  68862. this._offsets = offsets;
  68863. this._stride = stride;
  68864. this._texture = undefined;
  68865. var batchLength = 4 * width * height;
  68866. this._batchValues = pixelDatatype === PixelDatatype.FLOAT && !packFloats ? new Float32Array(batchLength) : new Uint8Array(batchLength);
  68867. this._batchValuesDirty = false;
  68868. }
  68869. defineProperties(BatchTable.prototype, {
  68870. /**
  68871. * The attribute descriptions.
  68872. * @memberOf BatchTable.prototype
  68873. * @type {Object[]}
  68874. * @readonly
  68875. */
  68876. attributes : {
  68877. get : function() {
  68878. return this._attributes;
  68879. }
  68880. },
  68881. /**
  68882. * The number of instances.
  68883. * @memberOf BatchTable.prototype
  68884. * @type {Number}
  68885. * @readonly
  68886. */
  68887. numberOfInstances : {
  68888. get : function () {
  68889. return this._numberOfInstances;
  68890. }
  68891. }
  68892. });
  68893. function getDatatype(attributes) {
  68894. var foundFloatDatatype = false;
  68895. var length = attributes.length;
  68896. for (var i = 0; i < length; ++i) {
  68897. if (attributes[i].componentDatatype !== ComponentDatatype.UNSIGNED_BYTE) {
  68898. foundFloatDatatype = true;
  68899. break;
  68900. }
  68901. }
  68902. return foundFloatDatatype ? PixelDatatype.FLOAT : PixelDatatype.UNSIGNED_BYTE;
  68903. }
  68904. function getAttributeType(attributes, attributeIndex) {
  68905. var componentsPerAttribute = attributes[attributeIndex].componentsPerAttribute;
  68906. if (componentsPerAttribute === 2) {
  68907. return Cartesian2;
  68908. } else if (componentsPerAttribute === 3) {
  68909. return Cartesian3;
  68910. } else if (componentsPerAttribute === 4) {
  68911. return Cartesian4;
  68912. }
  68913. return Number;
  68914. }
  68915. function createOffsets(attributes, packFloats) {
  68916. var offsets = new Array(attributes.length);
  68917. var currentOffset = 0;
  68918. var attributesLength = attributes.length;
  68919. for (var i = 0; i < attributesLength; ++i) {
  68920. var attribute = attributes[i];
  68921. var componentDatatype = attribute.componentDatatype;
  68922. offsets[i] = currentOffset;
  68923. if (componentDatatype !== ComponentDatatype.UNSIGNED_BYTE && packFloats) {
  68924. currentOffset += 4;
  68925. } else {
  68926. ++currentOffset;
  68927. }
  68928. }
  68929. return offsets;
  68930. }
  68931. function getStride(offsets, attributes, packFloats) {
  68932. var length = offsets.length;
  68933. var lastOffset = offsets[length - 1];
  68934. var lastAttribute = attributes[length - 1];
  68935. var componentDatatype = lastAttribute.componentDatatype;
  68936. if (componentDatatype !== ComponentDatatype.UNSIGNED_BYTE && packFloats) {
  68937. return lastOffset + 4;
  68938. }
  68939. return lastOffset + 1;
  68940. }
  68941. var scratchPackedFloatCartesian4 = new Cartesian4();
  68942. var SHIFT_LEFT_8 = 256.0;
  68943. var SHIFT_LEFT_16 = 65536.0;
  68944. var SHIFT_LEFT_24 = 16777216.0;
  68945. var SHIFT_RIGHT_8 = 1.0 / SHIFT_LEFT_8;
  68946. var SHIFT_RIGHT_16 = 1.0 / SHIFT_LEFT_16;
  68947. var SHIFT_RIGHT_24 = 1.0 / SHIFT_LEFT_24;
  68948. var BIAS = 38.0;
  68949. function unpackFloat(value) {
  68950. var temp = value.w / 2.0;
  68951. var exponent = Math.floor(temp);
  68952. var sign = (temp - exponent) * 2.0;
  68953. exponent = exponent - BIAS;
  68954. sign = sign * 2.0 - 1.0;
  68955. sign = -sign;
  68956. if (exponent >= BIAS) {
  68957. return sign < 0.0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;
  68958. }
  68959. var unpacked = sign * value.x * SHIFT_RIGHT_8;
  68960. unpacked += sign * value.y * SHIFT_RIGHT_16;
  68961. unpacked += sign * value.z * SHIFT_RIGHT_24;
  68962. return unpacked * Math.pow(10.0, exponent);
  68963. }
  68964. function getPackedFloat(array, index, result) {
  68965. var packed = Cartesian4.unpack(array, index, scratchPackedFloatCartesian4);
  68966. var x = unpackFloat(packed);
  68967. packed = Cartesian4.unpack(array, index + 4, scratchPackedFloatCartesian4);
  68968. var y = unpackFloat(packed);
  68969. packed = Cartesian4.unpack(array, index + 8, scratchPackedFloatCartesian4);
  68970. var z = unpackFloat(packed);
  68971. packed = Cartesian4.unpack(array, index + 12, scratchPackedFloatCartesian4);
  68972. var w = unpackFloat(packed);
  68973. return Cartesian4.fromElements(x, y, z, w, result);
  68974. }
  68975. var scratchFloatArray = new Float32Array(1);
  68976. function packFloat(value, result) {
  68977. scratchFloatArray[0] = value;
  68978. value = scratchFloatArray[0];
  68979. if (value === 0.0) {
  68980. return Cartesian4.clone(Cartesian4.ZERO, result);
  68981. }
  68982. var sign = value < 0.0 ? 1.0 : 0.0;
  68983. var exponent;
  68984. if (!isFinite(value)) {
  68985. value = 0.1;
  68986. exponent = BIAS;
  68987. } else {
  68988. value = Math.abs(value);
  68989. exponent = Math.floor(CesiumMath.logBase(value, 10)) + 1.0;
  68990. value = value / Math.pow(10.0, exponent);
  68991. }
  68992. var temp = value * SHIFT_LEFT_8;
  68993. result.x = Math.floor(temp);
  68994. temp = (temp - result.x) * SHIFT_LEFT_8;
  68995. result.y = Math.floor(temp);
  68996. temp = (temp - result.y) * SHIFT_LEFT_8;
  68997. result.z = Math.floor(temp);
  68998. result.w = (exponent + BIAS) * 2.0 + sign;
  68999. return result;
  69000. }
  69001. function setPackedAttribute(value, array, index) {
  69002. var packed = packFloat(value.x, scratchPackedFloatCartesian4);
  69003. Cartesian4.pack(packed, array, index);
  69004. packed = packFloat(value.y, packed);
  69005. Cartesian4.pack(packed, array, index + 4);
  69006. packed = packFloat(value.z, packed);
  69007. Cartesian4.pack(packed, array, index + 8);
  69008. packed = packFloat(value.w, packed);
  69009. Cartesian4.pack(packed, array, index + 12);
  69010. }
  69011. var scratchGetAttributeCartesian4 = new Cartesian4();
  69012. /**
  69013. * Gets the value of an attribute in the table.
  69014. *
  69015. * @param {Number} instanceIndex The index of the instance.
  69016. * @param {Number} attributeIndex The index of the attribute.
  69017. * @param {undefined|Cartesian2|Cartesian3|Cartesian4} [result] The object onto which to store the result. The type is dependent on the attribute's number of components.
  69018. * @returns {Number|Cartesian2|Cartesian3|Cartesian4} The attribute value stored for the instance.
  69019. *
  69020. * @exception {DeveloperError} instanceIndex is out of range.
  69021. * @exception {DeveloperError} attributeIndex is out of range.
  69022. */
  69023. BatchTable.prototype.getBatchedAttribute = function(instanceIndex, attributeIndex, result) {
  69024. if (instanceIndex < 0 || instanceIndex >= this._numberOfInstances) {
  69025. throw new DeveloperError('instanceIndex is out of range.');
  69026. }
  69027. if (attributeIndex < 0 || attributeIndex >= this._attributes.length) {
  69028. throw new DeveloperError('attributeIndex is out of range');
  69029. }
  69030. var attributes = this._attributes;
  69031. var offset = this._offsets[attributeIndex];
  69032. var stride = this._stride;
  69033. var index = 4 * stride * instanceIndex + 4 * offset;
  69034. var value;
  69035. if (this._packFloats && attributes[attributeIndex].componentDatatype !== PixelDatatype.UNSIGNED_BYTE) {
  69036. value = getPackedFloat(this._batchValues, index, scratchGetAttributeCartesian4);
  69037. } else {
  69038. value = Cartesian4.unpack(this._batchValues, index, scratchGetAttributeCartesian4);
  69039. }
  69040. var attributeType = getAttributeType(attributes, attributeIndex);
  69041. if (defined(attributeType.fromCartesian4)) {
  69042. return attributeType.fromCartesian4(value, result);
  69043. } else if (defined(attributeType.clone)) {
  69044. return attributeType.clone(value, result);
  69045. }
  69046. return value.x;
  69047. };
  69048. var setAttributeScratchValues = [undefined, undefined, new Cartesian2(), new Cartesian3(), new Cartesian4()];
  69049. var setAttributeScratchCartesian4 = new Cartesian4();
  69050. /**
  69051. * Sets the value of an attribute in the table.
  69052. *
  69053. * @param {Number} instanceIndex The index of the instance.
  69054. * @param {Number} attributeIndex The index of the attribute.
  69055. * @param {Number|Cartesian2|Cartesian3|Cartesian4} value The value to be stored in the table. The type of value will depend on the number of components of the attribute.
  69056. *
  69057. * @exception {DeveloperError} instanceIndex is out of range.
  69058. * @exception {DeveloperError} attributeIndex is out of range.
  69059. */
  69060. BatchTable.prototype.setBatchedAttribute = function(instanceIndex, attributeIndex, value) {
  69061. if (instanceIndex < 0 || instanceIndex >= this._numberOfInstances) {
  69062. throw new DeveloperError('instanceIndex is out of range.');
  69063. }
  69064. if (attributeIndex < 0 || attributeIndex >= this._attributes.length) {
  69065. throw new DeveloperError('attributeIndex is out of range');
  69066. }
  69067. if (!defined(value)) {
  69068. throw new DeveloperError('value is required.');
  69069. }
  69070. var attributes = this._attributes;
  69071. var result = setAttributeScratchValues[attributes[attributeIndex].componentsPerAttribute];
  69072. var currentAttribute = this.getBatchedAttribute(instanceIndex, attributeIndex, result);
  69073. var attributeType = getAttributeType(this._attributes, attributeIndex);
  69074. var entriesEqual = defined(attributeType.equals) ? attributeType.equals(currentAttribute, value) : currentAttribute === value;
  69075. if (entriesEqual) {
  69076. return;
  69077. }
  69078. var attributeValue = setAttributeScratchCartesian4;
  69079. attributeValue.x = defined(value.x) ? value.x : value;
  69080. attributeValue.y = defined(value.y) ? value.y : 0.0;
  69081. attributeValue.z = defined(value.z) ? value.z : 0.0;
  69082. attributeValue.w = defined(value.w) ? value.w : 0.0;
  69083. var offset = this._offsets[attributeIndex];
  69084. var stride = this._stride;
  69085. var index = 4 * stride * instanceIndex + 4 * offset;
  69086. if (this._packFloats && attributes[attributeIndex].componentDatatype !== PixelDatatype.UNSIGNED_BYTE) {
  69087. setPackedAttribute(attributeValue, this._batchValues, index);
  69088. } else {
  69089. Cartesian4.pack(attributeValue, this._batchValues, index);
  69090. }
  69091. this._batchValuesDirty = true;
  69092. };
  69093. function createTexture(batchTable, context) {
  69094. var dimensions = batchTable._textureDimensions;
  69095. batchTable._texture = new Texture({
  69096. context : context,
  69097. pixelFormat : PixelFormat.RGBA,
  69098. pixelDatatype : batchTable._pixelDatatype,
  69099. width : dimensions.x,
  69100. height : dimensions.y,
  69101. sampler : new Sampler({
  69102. minificationFilter : TextureMinificationFilter.NEAREST,
  69103. magnificationFilter : TextureMagnificationFilter.NEAREST
  69104. })
  69105. });
  69106. }
  69107. function updateTexture(batchTable) {
  69108. var dimensions = batchTable._textureDimensions;
  69109. batchTable._texture.copyFrom({
  69110. width : dimensions.x,
  69111. height : dimensions.y,
  69112. arrayBufferView : batchTable._batchValues
  69113. });
  69114. }
  69115. /**
  69116. * Creates/updates the batch table texture.
  69117. * @param {FrameState} frameState The frame state.
  69118. *
  69119. * @exception {RuntimeError} The floating point texture extension is required but not supported.
  69120. */
  69121. BatchTable.prototype.update = function(frameState) {
  69122. if ((defined(this._texture) && !this._batchValuesDirty) || this._attributes.length === 0) {
  69123. return;
  69124. }
  69125. this._batchValuesDirty = false;
  69126. if (!defined(this._texture)) {
  69127. createTexture(this, frameState.context);
  69128. }
  69129. updateTexture(this);
  69130. };
  69131. /**
  69132. * Gets a function that will update a uniform map to contain values for looking up values in the batch table.
  69133. *
  69134. * @returns {BatchTable~updateUniformMapCallback} A callback for updating uniform maps.
  69135. */
  69136. BatchTable.prototype.getUniformMapCallback = function() {
  69137. var that = this;
  69138. return function(uniformMap) {
  69139. if (that._attributes.length === 0) {
  69140. return uniformMap;
  69141. }
  69142. var batchUniformMap = {
  69143. batchTexture : function() {
  69144. return that._texture;
  69145. },
  69146. batchTextureDimensions : function() {
  69147. return that._textureDimensions;
  69148. },
  69149. batchTextureStep : function() {
  69150. return that._textureStep;
  69151. }
  69152. };
  69153. return combine(uniformMap, batchUniformMap);
  69154. };
  69155. };
  69156. function getGlslComputeSt(batchTable) {
  69157. var stride = batchTable._stride;
  69158. // GLSL batchId is zero-based: [0, numberOfInstances - 1]
  69159. if (batchTable._textureDimensions.y === 1) {
  69160. return 'uniform vec4 batchTextureStep; \n' +
  69161. 'vec2 computeSt(float batchId) \n' +
  69162. '{ \n' +
  69163. ' float stepX = batchTextureStep.x; \n' +
  69164. ' float centerX = batchTextureStep.y; \n' +
  69165. ' float numberOfAttributes = float('+ stride + '); \n' +
  69166. ' return vec2(centerX + (batchId * numberOfAttributes * stepX), 0.5); \n' +
  69167. '} \n';
  69168. }
  69169. return 'uniform vec4 batchTextureStep; \n' +
  69170. 'uniform vec2 batchTextureDimensions; \n' +
  69171. 'vec2 computeSt(float batchId) \n' +
  69172. '{ \n' +
  69173. ' float stepX = batchTextureStep.x; \n' +
  69174. ' float centerX = batchTextureStep.y; \n' +
  69175. ' float stepY = batchTextureStep.z; \n' +
  69176. ' float centerY = batchTextureStep.w; \n' +
  69177. ' float numberOfAttributes = float('+ stride + '); \n' +
  69178. ' float xId = mod(batchId * numberOfAttributes, batchTextureDimensions.x); \n' +
  69179. ' float yId = floor(batchId * numberOfAttributes / batchTextureDimensions.x); \n' +
  69180. ' return vec2(centerX + (xId * stepX), 1.0 - (centerY + (yId * stepY))); \n' +
  69181. '} \n';
  69182. }
  69183. function getGlslUnpackFloat(batchTable) {
  69184. if (!batchTable._packFloats) {
  69185. return '';
  69186. }
  69187. return 'float unpackFloat(vec4 value) \n' +
  69188. '{ \n' +
  69189. ' value *= 255.0; \n' +
  69190. ' float temp = value.w / 2.0; \n' +
  69191. ' float exponent = floor(temp); \n' +
  69192. ' float sign = (temp - exponent) * 2.0; \n' +
  69193. ' exponent = exponent - float(' + BIAS + '); \n' +
  69194. ' sign = sign * 2.0 - 1.0; \n' +
  69195. ' sign = -sign; \n' +
  69196. ' float unpacked = sign * value.x * float(' + SHIFT_RIGHT_8 + '); \n' +
  69197. ' unpacked += sign * value.y * float(' + SHIFT_RIGHT_16 + '); \n' +
  69198. ' unpacked += sign * value.z * float(' + SHIFT_RIGHT_24 + '); \n' +
  69199. ' return unpacked * pow(10.0, exponent); \n' +
  69200. '} \n';
  69201. }
  69202. function getComponentType(componentsPerAttribute) {
  69203. if (componentsPerAttribute === 1) {
  69204. return 'float';
  69205. }
  69206. return 'vec' + componentsPerAttribute;
  69207. }
  69208. function getComponentSwizzle(componentsPerAttribute) {
  69209. if (componentsPerAttribute === 1) {
  69210. return '.x';
  69211. } else if (componentsPerAttribute === 2) {
  69212. return '.xy';
  69213. } else if (componentsPerAttribute === 3) {
  69214. return '.xyz';
  69215. }
  69216. return '';
  69217. }
  69218. function getGlslAttributeFunction(batchTable, attributeIndex) {
  69219. var attributes = batchTable._attributes;
  69220. var attribute = attributes[attributeIndex];
  69221. var componentsPerAttribute = attribute.componentsPerAttribute;
  69222. var functionName = attribute.functionName;
  69223. var functionReturnType = getComponentType(componentsPerAttribute);
  69224. var functionReturnValue = getComponentSwizzle(componentsPerAttribute);
  69225. var offset = batchTable._offsets[attributeIndex];
  69226. var glslFunction =
  69227. functionReturnType + ' ' + functionName + '(float batchId) \n' +
  69228. '{ \n' +
  69229. ' vec2 st = computeSt(batchId); \n' +
  69230. ' st.x += batchTextureStep.x * float(' + offset + '); \n';
  69231. if (batchTable._packFloats && attribute.componentDatatype !== PixelDatatype.UNSIGNED_BYTE) {
  69232. glslFunction += 'vec4 textureValue; \n' +
  69233. 'textureValue.x = unpackFloat(texture2D(batchTexture, st)); \n' +
  69234. 'textureValue.y = unpackFloat(texture2D(batchTexture, st + vec2(batchTextureStep.x, 0.0))); \n' +
  69235. 'textureValue.z = unpackFloat(texture2D(batchTexture, st + vec2(batchTextureStep.x * 2.0, 0.0))); \n' +
  69236. 'textureValue.w = unpackFloat(texture2D(batchTexture, st + vec2(batchTextureStep.x * 3.0, 0.0))); \n';
  69237. } else {
  69238. glslFunction += ' vec4 textureValue = texture2D(batchTexture, st); \n';
  69239. }
  69240. glslFunction += ' ' + functionReturnType + ' value = textureValue' + functionReturnValue + '; \n';
  69241. if (batchTable._pixelDatatype === PixelDatatype.UNSIGNED_BYTE && attribute.componentDatatype === ComponentDatatype.UNSIGNED_BYTE && !attribute.normalize) {
  69242. glslFunction += 'value *= 255.0; \n';
  69243. } else if (batchTable._pixelDatatype === PixelDatatype.FLOAT && attribute.componentDatatype === ComponentDatatype.UNSIGNED_BYTE && attribute.normalize) {
  69244. glslFunction += 'value /= 255.0; \n';
  69245. }
  69246. glslFunction +=
  69247. ' return value; \n' +
  69248. '} \n';
  69249. return glslFunction;
  69250. }
  69251. /**
  69252. * Gets a function that will update a vertex shader to contain functions for looking up values in the batch table.
  69253. *
  69254. * @returns {BatchTable~updateVertexShaderSourceCallback} A callback for updating a vertex shader source.
  69255. */
  69256. BatchTable.prototype.getVertexShaderCallback = function() {
  69257. var attributes = this._attributes;
  69258. if (attributes.length === 0) {
  69259. return function(source) {
  69260. return source;
  69261. };
  69262. }
  69263. var batchTableShader = 'uniform sampler2D batchTexture; \n';
  69264. batchTableShader += getGlslComputeSt(this) + '\n';
  69265. batchTableShader += getGlslUnpackFloat(this) + '\n';
  69266. var length = attributes.length;
  69267. for (var i = 0; i < length; ++i) {
  69268. batchTableShader += getGlslAttributeFunction(this, i);
  69269. }
  69270. return function(source) {
  69271. var mainIndex = source.indexOf('void main');
  69272. var beforeMain = source.substring(0, mainIndex);
  69273. var afterMain = source.substring(mainIndex);
  69274. return beforeMain + '\n' + batchTableShader + '\n' + afterMain;
  69275. };
  69276. };
  69277. /**
  69278. * Returns true if this object was destroyed; otherwise, false.
  69279. * <br /><br />
  69280. * If this object was destroyed, it should not be used; calling any function other than
  69281. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  69282. *
  69283. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  69284. *
  69285. * @see BatchTable#destroy
  69286. */
  69287. BatchTable.prototype.isDestroyed = function() {
  69288. return false;
  69289. };
  69290. /**
  69291. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  69292. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  69293. * <br /><br />
  69294. * Once an object is destroyed, it should not be used; calling any function other than
  69295. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  69296. * assign the return value (<code>undefined</code>) to the object as done in the example.
  69297. *
  69298. * @returns {undefined}
  69299. *
  69300. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  69301. *
  69302. * @see BatchTable#isDestroyed
  69303. */
  69304. BatchTable.prototype.destroy = function() {
  69305. this._texture = this._texture && this._texture.destroy();
  69306. return destroyObject(this);
  69307. };
  69308. /**
  69309. * A callback for updating uniform maps.
  69310. * @callback BatchTable~updateUniformMapCallback
  69311. *
  69312. * @param {Object} uniformMap The uniform map.
  69313. * @returns {Object} The new uniform map with properties for retrieving values from the batch table.
  69314. */
  69315. /**
  69316. * A callback for updating a vertex shader source.
  69317. * @callback BatchTable~updateVertexShaderSourceCallback
  69318. *
  69319. * @param {String} vertexShaderSource The vertex shader source.
  69320. * @returns {String} The new vertex shader source with the functions for retrieving batch table values injected.
  69321. */
  69322. return BatchTable;
  69323. });
  69324. /*global define*/
  69325. define('Scene/PrimitivePipeline',[
  69326. '../Core/BoundingSphere',
  69327. '../Core/ComponentDatatype',
  69328. '../Core/defined',
  69329. '../Core/DeveloperError',
  69330. '../Core/Ellipsoid',
  69331. '../Core/FeatureDetection',
  69332. '../Core/GeographicProjection',
  69333. '../Core/Geometry',
  69334. '../Core/GeometryAttribute',
  69335. '../Core/GeometryAttributes',
  69336. '../Core/GeometryPipeline',
  69337. '../Core/IndexDatatype',
  69338. '../Core/Matrix4',
  69339. '../Core/WebMercatorProjection'
  69340. ], function(
  69341. BoundingSphere,
  69342. ComponentDatatype,
  69343. defined,
  69344. DeveloperError,
  69345. Ellipsoid,
  69346. FeatureDetection,
  69347. GeographicProjection,
  69348. Geometry,
  69349. GeometryAttribute,
  69350. GeometryAttributes,
  69351. GeometryPipeline,
  69352. IndexDatatype,
  69353. Matrix4,
  69354. WebMercatorProjection) {
  69355. 'use strict';
  69356. // Bail out if the browser doesn't support typed arrays, to prevent the setup function
  69357. // from failing, since we won't be able to create a WebGL context anyway.
  69358. if (!FeatureDetection.supportsTypedArrays()) {
  69359. return {};
  69360. }
  69361. function transformToWorldCoordinates(instances, primitiveModelMatrix, scene3DOnly) {
  69362. var toWorld = !scene3DOnly;
  69363. var length = instances.length;
  69364. var i;
  69365. if (!toWorld && (length > 1)) {
  69366. var modelMatrix = instances[0].modelMatrix;
  69367. for (i = 1; i < length; ++i) {
  69368. if (!Matrix4.equals(modelMatrix, instances[i].modelMatrix)) {
  69369. toWorld = true;
  69370. break;
  69371. }
  69372. }
  69373. }
  69374. if (toWorld) {
  69375. for (i = 0; i < length; ++i) {
  69376. if (defined(instances[i].geometry)) {
  69377. GeometryPipeline.transformToWorldCoordinates(instances[i]);
  69378. }
  69379. }
  69380. } else {
  69381. // Leave geometry in local coordinate system; auto update model-matrix.
  69382. Matrix4.multiplyTransformation(primitiveModelMatrix, instances[0].modelMatrix, primitiveModelMatrix);
  69383. }
  69384. }
  69385. function addGeometryBatchId(geometry, batchId) {
  69386. var attributes = geometry.attributes;
  69387. var positionAttr = attributes.position;
  69388. var numberOfComponents = positionAttr.values.length / positionAttr.componentsPerAttribute;
  69389. attributes.batchId = new GeometryAttribute({
  69390. componentDatatype : ComponentDatatype.FLOAT,
  69391. componentsPerAttribute : 1,
  69392. values : new Float32Array(numberOfComponents)
  69393. });
  69394. var values = attributes.batchId.values;
  69395. for (var j = 0; j < numberOfComponents; ++j) {
  69396. values[j] = batchId;
  69397. }
  69398. }
  69399. function addBatchIds(instances) {
  69400. var length = instances.length;
  69401. for (var i = 0; i < length; ++i) {
  69402. var instance = instances[i];
  69403. if (defined(instance.geometry)) {
  69404. addGeometryBatchId(instance.geometry, i);
  69405. } else if (defined(instance.westHemisphereGeometry) && defined(instance.eastHemisphereGeometry)) {
  69406. addGeometryBatchId(instance.westHemisphereGeometry, i);
  69407. addGeometryBatchId(instance.eastHemisphereGeometry, i);
  69408. }
  69409. }
  69410. }
  69411. function geometryPipeline(parameters) {
  69412. var instances = parameters.instances;
  69413. var projection = parameters.projection;
  69414. var uintIndexSupport = parameters.elementIndexUintSupported;
  69415. var scene3DOnly = parameters.scene3DOnly;
  69416. var vertexCacheOptimize = parameters.vertexCacheOptimize;
  69417. var compressVertices = parameters.compressVertices;
  69418. var modelMatrix = parameters.modelMatrix;
  69419. var i;
  69420. var geometry;
  69421. var primitiveType;
  69422. var length = instances.length;
  69423. for (i = 0 ; i < length; ++i) {
  69424. if (defined(instances[i].geometry)) {
  69425. primitiveType = instances[i].geometry.primitiveType;
  69426. break;
  69427. }
  69428. }
  69429. for (i = 1; i < length; ++i) {
  69430. if (defined(instances[i].geometry) && instances[i].geometry.primitiveType !== primitiveType) {
  69431. throw new DeveloperError('All instance geometries must have the same primitiveType.');
  69432. }
  69433. }
  69434. // Unify to world coordinates before combining.
  69435. transformToWorldCoordinates(instances, modelMatrix, scene3DOnly);
  69436. // Clip to IDL
  69437. if (!scene3DOnly) {
  69438. for (i = 0; i < length; ++i) {
  69439. if (defined(instances[i].geometry)) {
  69440. GeometryPipeline.splitLongitude(instances[i]);
  69441. }
  69442. }
  69443. }
  69444. addBatchIds(instances);
  69445. // Optimize for vertex shader caches
  69446. if (vertexCacheOptimize) {
  69447. for (i = 0; i < length; ++i) {
  69448. var instance = instances[i];
  69449. if (defined(instance.geometry)) {
  69450. GeometryPipeline.reorderForPostVertexCache(instance.geometry);
  69451. GeometryPipeline.reorderForPreVertexCache(instance.geometry);
  69452. } else if (defined(instance.westHemisphereGeometry) && defined(instance.eastHemisphereGeometry)) {
  69453. GeometryPipeline.reorderForPostVertexCache(instance.westHemisphereGeometry);
  69454. GeometryPipeline.reorderForPreVertexCache(instance.westHemisphereGeometry);
  69455. GeometryPipeline.reorderForPostVertexCache(instance.eastHemisphereGeometry);
  69456. GeometryPipeline.reorderForPreVertexCache(instance.eastHemisphereGeometry);
  69457. }
  69458. }
  69459. }
  69460. // Combine into single geometry for better rendering performance.
  69461. var geometries = GeometryPipeline.combineInstances(instances);
  69462. length = geometries.length;
  69463. for (i = 0; i < length; ++i) {
  69464. geometry = geometries[i];
  69465. // Split positions for GPU RTE
  69466. var attributes = geometry.attributes;
  69467. var name;
  69468. if (!scene3DOnly) {
  69469. for (name in attributes) {
  69470. if (attributes.hasOwnProperty(name) && attributes[name].componentDatatype === ComponentDatatype.DOUBLE) {
  69471. var name3D = name + '3D';
  69472. var name2D = name + '2D';
  69473. // Compute 2D positions
  69474. GeometryPipeline.projectTo2D(geometry, name, name3D, name2D, projection);
  69475. if (defined(geometry.boundingSphere) && name === 'position') {
  69476. geometry.boundingSphereCV = BoundingSphere.fromVertices(geometry.attributes.position2D.values);
  69477. }
  69478. GeometryPipeline.encodeAttribute(geometry, name3D, name3D + 'High', name3D + 'Low');
  69479. GeometryPipeline.encodeAttribute(geometry, name2D, name2D + 'High', name2D + 'Low');
  69480. }
  69481. }
  69482. } else {
  69483. for (name in attributes) {
  69484. if (attributes.hasOwnProperty(name) && attributes[name].componentDatatype === ComponentDatatype.DOUBLE) {
  69485. GeometryPipeline.encodeAttribute(geometry, name, name + '3DHigh', name + '3DLow');
  69486. }
  69487. }
  69488. }
  69489. // oct encode and pack normals, compress texture coordinates
  69490. if (compressVertices) {
  69491. GeometryPipeline.compressVertices(geometry);
  69492. }
  69493. }
  69494. if (!uintIndexSupport) {
  69495. // Break into multiple geometries to fit within unsigned short indices if needed
  69496. var splitGeometries = [];
  69497. length = geometries.length;
  69498. for (i = 0; i < length; ++i) {
  69499. geometry = geometries[i];
  69500. splitGeometries = splitGeometries.concat(GeometryPipeline.fitToUnsignedShortIndices(geometry));
  69501. }
  69502. geometries = splitGeometries;
  69503. }
  69504. return geometries;
  69505. }
  69506. function createPickOffsets(instances, geometryName, geometries, pickOffsets) {
  69507. var offset;
  69508. var indexCount;
  69509. var geometryIndex;
  69510. var offsetIndex = pickOffsets.length - 1;
  69511. if (offsetIndex >= 0) {
  69512. var pickOffset = pickOffsets[offsetIndex];
  69513. offset = pickOffset.offset + pickOffset.count;
  69514. geometryIndex = pickOffset.index;
  69515. indexCount = geometries[geometryIndex].indices.length;
  69516. } else {
  69517. offset = 0;
  69518. geometryIndex = 0;
  69519. indexCount = geometries[geometryIndex].indices.length;
  69520. }
  69521. var length = instances.length;
  69522. for (var i = 0; i < length; ++i) {
  69523. var instance = instances[i];
  69524. var geometry = instance[geometryName];
  69525. if (!defined(geometry)) {
  69526. continue;
  69527. }
  69528. var count = geometry.indices.length;
  69529. if (offset + count > indexCount) {
  69530. offset = 0;
  69531. indexCount = geometries[++geometryIndex].indices.length;
  69532. }
  69533. pickOffsets.push({
  69534. index : geometryIndex,
  69535. offset : offset,
  69536. count : count
  69537. });
  69538. offset += count;
  69539. }
  69540. }
  69541. function createInstancePickOffsets(instances, geometries) {
  69542. var pickOffsets = [];
  69543. createPickOffsets(instances, 'geometry', geometries, pickOffsets);
  69544. createPickOffsets(instances, 'westHemisphereGeometry', geometries, pickOffsets);
  69545. createPickOffsets(instances, 'eastHemisphereGeometry', geometries, pickOffsets);
  69546. return pickOffsets;
  69547. }
  69548. /**
  69549. * @private
  69550. */
  69551. var PrimitivePipeline = {};
  69552. /**
  69553. * @private
  69554. */
  69555. PrimitivePipeline.combineGeometry = function(parameters) {
  69556. var geometries;
  69557. var attributeLocations;
  69558. var instances = parameters.instances;
  69559. var length = instances.length;
  69560. if (length > 0) {
  69561. geometries = geometryPipeline(parameters);
  69562. if (geometries.length > 0) {
  69563. attributeLocations = GeometryPipeline.createAttributeLocations(geometries[0]);
  69564. }
  69565. }
  69566. var pickOffsets;
  69567. if (parameters.createPickOffsets && geometries.length > 0) {
  69568. pickOffsets = createInstancePickOffsets(instances, geometries);
  69569. }
  69570. var boundingSpheres = new Array(length);
  69571. var boundingSpheresCV = new Array(length);
  69572. for (var i = 0; i < length; ++i) {
  69573. var instance = instances[i];
  69574. var geometry = instance.geometry;
  69575. if (defined(geometry)) {
  69576. boundingSpheres[i] = geometry.boundingSphere;
  69577. boundingSpheresCV[i] = geometry.boundingSphereCV;
  69578. }
  69579. var eastHemisphereGeometry = instance.eastHemisphereGeometry;
  69580. var westHemisphereGeometry = instance.westHemisphereGeometry;
  69581. if (defined(eastHemisphereGeometry) && defined(westHemisphereGeometry)) {
  69582. if (defined(eastHemisphereGeometry.boundingSphere) && defined(westHemisphereGeometry.boundingSphere)) {
  69583. boundingSpheres[i] = BoundingSphere.union(eastHemisphereGeometry.boundingSphere, westHemisphereGeometry.boundingSphere);
  69584. }
  69585. if (defined(eastHemisphereGeometry.boundingSphereCV) && defined(westHemisphereGeometry.boundingSphereCV)) {
  69586. boundingSpheresCV[i] = BoundingSphere.union(eastHemisphereGeometry.boundingSphereCV, westHemisphereGeometry.boundingSphereCV);
  69587. }
  69588. }
  69589. }
  69590. return {
  69591. geometries : geometries,
  69592. modelMatrix : parameters.modelMatrix,
  69593. attributeLocations : attributeLocations,
  69594. pickOffsets : pickOffsets,
  69595. boundingSpheres : boundingSpheres,
  69596. boundingSpheresCV : boundingSpheresCV
  69597. };
  69598. };
  69599. function transferGeometry(geometry, transferableObjects) {
  69600. var attributes = geometry.attributes;
  69601. for ( var name in attributes) {
  69602. if (attributes.hasOwnProperty(name)) {
  69603. var attribute = attributes[name];
  69604. if (defined(attribute) && defined(attribute.values)) {
  69605. transferableObjects.push(attribute.values.buffer);
  69606. }
  69607. }
  69608. }
  69609. if (defined(geometry.indices)) {
  69610. transferableObjects.push(geometry.indices.buffer);
  69611. }
  69612. }
  69613. function transferGeometries(geometries, transferableObjects) {
  69614. var length = geometries.length;
  69615. for (var i = 0; i < length; ++i) {
  69616. transferGeometry(geometries[i], transferableObjects);
  69617. }
  69618. }
  69619. // This function was created by simplifying packCreateGeometryResults into a count-only operation.
  69620. function countCreateGeometryResults(items) {
  69621. var count = 1;
  69622. var length = items.length;
  69623. for (var i = 0; i < length; i++) {
  69624. var geometry = items[i];
  69625. ++count;
  69626. if (!defined(geometry)) {
  69627. continue;
  69628. }
  69629. var attributes = geometry.attributes;
  69630. count += 6 + 2 * BoundingSphere.packedLength + (defined(geometry.indices) ? geometry.indices.length : 0);
  69631. for ( var property in attributes) {
  69632. if (attributes.hasOwnProperty(property) && defined(attributes[property])) {
  69633. var attribute = attributes[property];
  69634. count += 5 + attribute.values.length;
  69635. }
  69636. }
  69637. }
  69638. return count;
  69639. }
  69640. /**
  69641. * @private
  69642. */
  69643. PrimitivePipeline.packCreateGeometryResults = function(items, transferableObjects) {
  69644. var packedData = new Float64Array(countCreateGeometryResults(items));
  69645. var stringTable = [];
  69646. var stringHash = {};
  69647. var length = items.length;
  69648. var count = 0;
  69649. packedData[count++] = length;
  69650. for (var i = 0; i < length; i++) {
  69651. var geometry = items[i];
  69652. var validGeometry = defined(geometry);
  69653. packedData[count++] = validGeometry ? 1.0 : 0.0;
  69654. if (!validGeometry) {
  69655. continue;
  69656. }
  69657. packedData[count++] = geometry.primitiveType;
  69658. packedData[count++] = geometry.geometryType;
  69659. var validBoundingSphere = defined(geometry.boundingSphere) ? 1.0 : 0.0;
  69660. packedData[count++] = validBoundingSphere;
  69661. if (validBoundingSphere) {
  69662. BoundingSphere.pack(geometry.boundingSphere, packedData, count);
  69663. }
  69664. count += BoundingSphere.packedLength;
  69665. var validBoundingSphereCV = defined(geometry.boundingSphereCV) ? 1.0 : 0.0;
  69666. packedData[count++] = validBoundingSphereCV;
  69667. if (validBoundingSphereCV) {
  69668. BoundingSphere.pack(geometry.boundingSphereCV, packedData, count);
  69669. }
  69670. count += BoundingSphere.packedLength;
  69671. var attributes = geometry.attributes;
  69672. var attributesToWrite = [];
  69673. for ( var property in attributes) {
  69674. if (attributes.hasOwnProperty(property) && defined(attributes[property])) {
  69675. attributesToWrite.push(property);
  69676. if (!defined(stringHash[property])) {
  69677. stringHash[property] = stringTable.length;
  69678. stringTable.push(property);
  69679. }
  69680. }
  69681. }
  69682. packedData[count++] = attributesToWrite.length;
  69683. for (var q = 0; q < attributesToWrite.length; q++) {
  69684. var name = attributesToWrite[q];
  69685. var attribute = attributes[name];
  69686. packedData[count++] = stringHash[name];
  69687. packedData[count++] = attribute.componentDatatype;
  69688. packedData[count++] = attribute.componentsPerAttribute;
  69689. packedData[count++] = attribute.normalize ? 1 : 0;
  69690. packedData[count++] = attribute.values.length;
  69691. packedData.set(attribute.values, count);
  69692. count += attribute.values.length;
  69693. }
  69694. var indicesLength = defined(geometry.indices) ? geometry.indices.length : 0;
  69695. packedData[count++] = indicesLength;
  69696. if (indicesLength > 0) {
  69697. packedData.set(geometry.indices, count);
  69698. count += indicesLength;
  69699. }
  69700. }
  69701. transferableObjects.push(packedData.buffer);
  69702. return {
  69703. stringTable : stringTable,
  69704. packedData : packedData
  69705. };
  69706. };
  69707. /**
  69708. * @private
  69709. */
  69710. PrimitivePipeline.unpackCreateGeometryResults = function(createGeometryResult) {
  69711. var stringTable = createGeometryResult.stringTable;
  69712. var packedGeometry = createGeometryResult.packedData;
  69713. var i;
  69714. var result = new Array(packedGeometry[0]);
  69715. var resultIndex = 0;
  69716. var packedGeometryIndex = 1;
  69717. while (packedGeometryIndex < packedGeometry.length) {
  69718. var valid = packedGeometry[packedGeometryIndex++] === 1.0;
  69719. if (!valid) {
  69720. result[resultIndex++] = undefined;
  69721. continue;
  69722. }
  69723. var primitiveType = packedGeometry[packedGeometryIndex++];
  69724. var geometryType = packedGeometry[packedGeometryIndex++];
  69725. var boundingSphere;
  69726. var boundingSphereCV;
  69727. var validBoundingSphere = packedGeometry[packedGeometryIndex++] === 1.0;
  69728. if (validBoundingSphere) {
  69729. boundingSphere = BoundingSphere.unpack(packedGeometry, packedGeometryIndex);
  69730. }
  69731. packedGeometryIndex += BoundingSphere.packedLength;
  69732. var validBoundingSphereCV = packedGeometry[packedGeometryIndex++] === 1.0;
  69733. if (validBoundingSphereCV) {
  69734. boundingSphereCV = BoundingSphere.unpack(packedGeometry, packedGeometryIndex);
  69735. }
  69736. packedGeometryIndex += BoundingSphere.packedLength;
  69737. var length;
  69738. var values;
  69739. var componentsPerAttribute;
  69740. var attributes = new GeometryAttributes();
  69741. var numAttributes = packedGeometry[packedGeometryIndex++];
  69742. for (i = 0; i < numAttributes; i++) {
  69743. var name = stringTable[packedGeometry[packedGeometryIndex++]];
  69744. var componentDatatype = packedGeometry[packedGeometryIndex++];
  69745. componentsPerAttribute = packedGeometry[packedGeometryIndex++];
  69746. var normalize = packedGeometry[packedGeometryIndex++] !== 0;
  69747. length = packedGeometry[packedGeometryIndex++];
  69748. values = ComponentDatatype.createTypedArray(componentDatatype, length);
  69749. for (var valuesIndex = 0; valuesIndex < length; valuesIndex++) {
  69750. values[valuesIndex] = packedGeometry[packedGeometryIndex++];
  69751. }
  69752. attributes[name] = new GeometryAttribute({
  69753. componentDatatype : componentDatatype,
  69754. componentsPerAttribute : componentsPerAttribute,
  69755. normalize : normalize,
  69756. values : values
  69757. });
  69758. }
  69759. var indices;
  69760. length = packedGeometry[packedGeometryIndex++];
  69761. if (length > 0) {
  69762. var numberOfVertices = values.length / componentsPerAttribute;
  69763. indices = IndexDatatype.createTypedArray(numberOfVertices, length);
  69764. for (i = 0; i < length; i++) {
  69765. indices[i] = packedGeometry[packedGeometryIndex++];
  69766. }
  69767. }
  69768. result[resultIndex++] = new Geometry({
  69769. primitiveType : primitiveType,
  69770. geometryType : geometryType,
  69771. boundingSphere : boundingSphere,
  69772. boundingSphereCV : boundingSphereCV,
  69773. indices : indices,
  69774. attributes : attributes
  69775. });
  69776. }
  69777. return result;
  69778. };
  69779. function packInstancesForCombine(instances, transferableObjects) {
  69780. var length = instances.length;
  69781. var packedData = new Float64Array(1 + (length * 16));
  69782. var count = 0;
  69783. packedData[count++] = length;
  69784. for (var i = 0; i < length; i++) {
  69785. var instance = instances[i];
  69786. Matrix4.pack(instance.modelMatrix, packedData, count);
  69787. count += Matrix4.packedLength;
  69788. }
  69789. transferableObjects.push(packedData.buffer);
  69790. return packedData;
  69791. }
  69792. function unpackInstancesForCombine(data) {
  69793. var packedInstances = data;
  69794. var result = new Array(packedInstances[0]);
  69795. var count = 0;
  69796. var i = 1;
  69797. while (i < packedInstances.length) {
  69798. var modelMatrix = Matrix4.unpack(packedInstances, i);
  69799. i += Matrix4.packedLength;
  69800. result[count++] = {
  69801. modelMatrix : modelMatrix
  69802. };
  69803. }
  69804. return result;
  69805. }
  69806. /**
  69807. * @private
  69808. */
  69809. PrimitivePipeline.packCombineGeometryParameters = function(parameters, transferableObjects) {
  69810. var createGeometryResults = parameters.createGeometryResults;
  69811. var length = createGeometryResults.length;
  69812. for (var i = 0; i < length; i++) {
  69813. transferableObjects.push(createGeometryResults[i].packedData.buffer);
  69814. }
  69815. return {
  69816. createGeometryResults : parameters.createGeometryResults,
  69817. packedInstances : packInstancesForCombine(parameters.instances, transferableObjects),
  69818. ellipsoid : parameters.ellipsoid,
  69819. isGeographic : parameters.projection instanceof GeographicProjection,
  69820. elementIndexUintSupported : parameters.elementIndexUintSupported,
  69821. scene3DOnly : parameters.scene3DOnly,
  69822. vertexCacheOptimize : parameters.vertexCacheOptimize,
  69823. compressVertices : parameters.compressVertices,
  69824. modelMatrix : parameters.modelMatrix,
  69825. createPickOffsets : parameters.createPickOffsets
  69826. };
  69827. };
  69828. /**
  69829. * @private
  69830. */
  69831. PrimitivePipeline.unpackCombineGeometryParameters = function(packedParameters) {
  69832. var instances = unpackInstancesForCombine(packedParameters.packedInstances);
  69833. var createGeometryResults = packedParameters.createGeometryResults;
  69834. var length = createGeometryResults.length;
  69835. var instanceIndex = 0;
  69836. for (var resultIndex = 0; resultIndex < length; resultIndex++) {
  69837. var geometries = PrimitivePipeline.unpackCreateGeometryResults(createGeometryResults[resultIndex]);
  69838. var geometriesLength = geometries.length;
  69839. for (var geometryIndex = 0; geometryIndex < geometriesLength; geometryIndex++) {
  69840. var geometry = geometries[geometryIndex];
  69841. var instance = instances[instanceIndex];
  69842. instance.geometry = geometry;
  69843. ++instanceIndex;
  69844. }
  69845. }
  69846. var ellipsoid = Ellipsoid.clone(packedParameters.ellipsoid);
  69847. var projection = packedParameters.isGeographic ? new GeographicProjection(ellipsoid) : new WebMercatorProjection(ellipsoid);
  69848. return {
  69849. instances : instances,
  69850. ellipsoid : ellipsoid,
  69851. projection : projection,
  69852. elementIndexUintSupported : packedParameters.elementIndexUintSupported,
  69853. scene3DOnly : packedParameters.scene3DOnly,
  69854. vertexCacheOptimize : packedParameters.vertexCacheOptimize,
  69855. compressVertices : packedParameters.compressVertices,
  69856. modelMatrix : Matrix4.clone(packedParameters.modelMatrix),
  69857. createPickOffsets : packedParameters.createPickOffsets
  69858. };
  69859. };
  69860. function packBoundingSpheres(boundingSpheres) {
  69861. var length = boundingSpheres.length;
  69862. var bufferLength = 1 + (BoundingSphere.packedLength + 1) * length;
  69863. var buffer = new Float32Array(bufferLength);
  69864. var bufferIndex = 0;
  69865. buffer[bufferIndex++] = length;
  69866. for (var i = 0; i < length; ++i) {
  69867. var bs = boundingSpheres[i];
  69868. if (!defined(bs)) {
  69869. buffer[bufferIndex++] = 0.0;
  69870. } else {
  69871. buffer[bufferIndex++] = 1.0;
  69872. BoundingSphere.pack(boundingSpheres[i], buffer, bufferIndex);
  69873. }
  69874. bufferIndex += BoundingSphere.packedLength;
  69875. }
  69876. return buffer;
  69877. }
  69878. function unpackBoundingSpheres(buffer) {
  69879. var result = new Array(buffer[0]);
  69880. var count = 0;
  69881. var i = 1;
  69882. while (i < buffer.length) {
  69883. if (buffer[i++] === 1.0) {
  69884. result[count] = BoundingSphere.unpack(buffer, i);
  69885. }
  69886. ++count;
  69887. i += BoundingSphere.packedLength;
  69888. }
  69889. return result;
  69890. }
  69891. /**
  69892. * @private
  69893. */
  69894. PrimitivePipeline.packCombineGeometryResults = function(results, transferableObjects) {
  69895. if (defined(results.geometries)) {
  69896. transferGeometries(results.geometries, transferableObjects);
  69897. }
  69898. var packedBoundingSpheres = packBoundingSpheres(results.boundingSpheres);
  69899. var packedBoundingSpheresCV = packBoundingSpheres(results.boundingSpheresCV);
  69900. transferableObjects.push(packedBoundingSpheres.buffer, packedBoundingSpheresCV.buffer);
  69901. return {
  69902. geometries : results.geometries,
  69903. attributeLocations : results.attributeLocations,
  69904. modelMatrix : results.modelMatrix,
  69905. pickOffsets : results.pickOffsets,
  69906. boundingSpheres : packedBoundingSpheres,
  69907. boundingSpheresCV : packedBoundingSpheresCV
  69908. };
  69909. };
  69910. /**
  69911. * @private
  69912. */
  69913. PrimitivePipeline.unpackCombineGeometryResults = function(packedResult) {
  69914. return {
  69915. geometries : packedResult.geometries,
  69916. attributeLocations : packedResult.attributeLocations,
  69917. modelMatrix : packedResult.modelMatrix,
  69918. pickOffsets : packedResult.pickOffsets,
  69919. boundingSpheres : unpackBoundingSpheres(packedResult.boundingSpheres),
  69920. boundingSpheresCV : unpackBoundingSpheres(packedResult.boundingSpheresCV)
  69921. };
  69922. };
  69923. return PrimitivePipeline;
  69924. });
  69925. /*global define*/
  69926. define('Scene/PrimitiveState',[
  69927. '../Core/freezeObject'
  69928. ], function(
  69929. freezeObject) {
  69930. 'use strict';
  69931. /**
  69932. * @private
  69933. */
  69934. var PrimitiveState = {
  69935. READY : 0,
  69936. CREATING : 1,
  69937. CREATED : 2,
  69938. COMBINING : 3,
  69939. COMBINED : 4,
  69940. COMPLETE : 5,
  69941. FAILED : 6
  69942. };
  69943. return freezeObject(PrimitiveState);
  69944. });
  69945. /*global define*/
  69946. define('Scene/SceneMode',[
  69947. '../Core/freezeObject'
  69948. ], function(
  69949. freezeObject) {
  69950. 'use strict';
  69951. /**
  69952. * Indicates if the scene is viewed in 3D, 2D, or 2.5D Columbus view.
  69953. *
  69954. * @exports SceneMode
  69955. *
  69956. * @see Scene#mode
  69957. */
  69958. var SceneMode = {
  69959. /**
  69960. * Morphing between mode, e.g., 3D to 2D.
  69961. *
  69962. * @type {Number}
  69963. * @constant
  69964. */
  69965. MORPHING : 0,
  69966. /**
  69967. * Columbus View mode. A 2.5D perspective view where the map is laid out
  69968. * flat and objects with non-zero height are drawn above it.
  69969. *
  69970. * @type {Number}
  69971. * @constant
  69972. */
  69973. COLUMBUS_VIEW : 1,
  69974. /**
  69975. * 2D mode. The map is viewed top-down with an orthographic projection.
  69976. *
  69977. * @type {Number}
  69978. * @constant
  69979. */
  69980. SCENE2D : 2,
  69981. /**
  69982. * 3D mode. A traditional 3D perspective view of the globe.
  69983. *
  69984. * @type {Number}
  69985. * @constant
  69986. */
  69987. SCENE3D : 3
  69988. };
  69989. /**
  69990. * Returns the morph time for the given scene mode.
  69991. *
  69992. * @param {SceneMode} value The scene mode
  69993. * @returns {Number} The morph time
  69994. */
  69995. SceneMode.getMorphTime = function(value) {
  69996. if (value === SceneMode.SCENE3D) {
  69997. return 1.0;
  69998. } else if (value === SceneMode.MORPHING) {
  69999. return undefined;
  70000. }
  70001. return 0.0;
  70002. };
  70003. return freezeObject(SceneMode);
  70004. });
  70005. /*global define*/
  70006. define('Scene/ShadowMode',[
  70007. '../Core/freezeObject'
  70008. ], function(
  70009. freezeObject) {
  70010. 'use strict';
  70011. /**
  70012. * Specifies whether the object casts or receives shadows from each light source when
  70013. * shadows are enabled.
  70014. *
  70015. * @exports ShadowMode
  70016. */
  70017. var ShadowMode = {
  70018. /**
  70019. * The object does not cast or receive shadows.
  70020. *
  70021. * @type {Number}
  70022. * @constant
  70023. */
  70024. DISABLED : 0,
  70025. /**
  70026. * The object casts and receives shadows.
  70027. *
  70028. * @type {Number}
  70029. * @constant
  70030. */
  70031. ENABLED : 1,
  70032. /**
  70033. * The object casts shadows only.
  70034. *
  70035. * @type {Number}
  70036. * @constant
  70037. */
  70038. CAST_ONLY : 2,
  70039. /**
  70040. * The object receives shadows only.
  70041. *
  70042. * @type {Number}
  70043. * @constant
  70044. */
  70045. RECEIVE_ONLY : 3,
  70046. /**
  70047. * @private
  70048. */
  70049. NUMBER_OF_SHADOW_MODES : 4
  70050. };
  70051. /**
  70052. * @private
  70053. */
  70054. ShadowMode.castShadows = function(shadowMode) {
  70055. return (shadowMode === ShadowMode.ENABLED) || (shadowMode === ShadowMode.CAST_ONLY);
  70056. };
  70057. /**
  70058. * @private
  70059. */
  70060. ShadowMode.receiveShadows = function(shadowMode) {
  70061. return (shadowMode === ShadowMode.ENABLED) || (shadowMode === ShadowMode.RECEIVE_ONLY);
  70062. };
  70063. /**
  70064. * @private
  70065. */
  70066. ShadowMode.fromCastReceive = function(castShadows, receiveShadows) {
  70067. if (castShadows && receiveShadows) {
  70068. return ShadowMode.ENABLED;
  70069. } else if (castShadows) {
  70070. return ShadowMode.CAST_ONLY;
  70071. } else if (receiveShadows) {
  70072. return ShadowMode.RECEIVE_ONLY;
  70073. } else {
  70074. return ShadowMode.DISABLED;
  70075. }
  70076. };
  70077. return freezeObject(ShadowMode);
  70078. });
  70079. /*global define*/
  70080. define('Scene/Primitive',[
  70081. '../Core/BoundingSphere',
  70082. '../Core/Cartesian2',
  70083. '../Core/Cartesian3',
  70084. '../Core/Cartesian4',
  70085. '../Core/Cartographic',
  70086. '../Core/clone',
  70087. '../Core/Color',
  70088. '../Core/combine',
  70089. '../Core/ComponentDatatype',
  70090. '../Core/defaultValue',
  70091. '../Core/defined',
  70092. '../Core/defineProperties',
  70093. '../Core/destroyObject',
  70094. '../Core/DeveloperError',
  70095. '../Core/EncodedCartesian3',
  70096. '../Core/FeatureDetection',
  70097. '../Core/Geometry',
  70098. '../Core/GeometryAttribute',
  70099. '../Core/GeometryAttributes',
  70100. '../Core/isArray',
  70101. '../Core/Matrix4',
  70102. '../Core/RuntimeError',
  70103. '../Core/subdivideArray',
  70104. '../Core/TaskProcessor',
  70105. '../Renderer/BufferUsage',
  70106. '../Renderer/ContextLimits',
  70107. '../Renderer/DrawCommand',
  70108. '../Renderer/Pass',
  70109. '../Renderer/RenderState',
  70110. '../Renderer/ShaderProgram',
  70111. '../Renderer/ShaderSource',
  70112. '../Renderer/VertexArray',
  70113. '../ThirdParty/when',
  70114. './BatchTable',
  70115. './CullFace',
  70116. './PrimitivePipeline',
  70117. './PrimitiveState',
  70118. './SceneMode',
  70119. './ShadowMode'
  70120. ], function(
  70121. BoundingSphere,
  70122. Cartesian2,
  70123. Cartesian3,
  70124. Cartesian4,
  70125. Cartographic,
  70126. clone,
  70127. Color,
  70128. combine,
  70129. ComponentDatatype,
  70130. defaultValue,
  70131. defined,
  70132. defineProperties,
  70133. destroyObject,
  70134. DeveloperError,
  70135. EncodedCartesian3,
  70136. FeatureDetection,
  70137. Geometry,
  70138. GeometryAttribute,
  70139. GeometryAttributes,
  70140. isArray,
  70141. Matrix4,
  70142. RuntimeError,
  70143. subdivideArray,
  70144. TaskProcessor,
  70145. BufferUsage,
  70146. ContextLimits,
  70147. DrawCommand,
  70148. Pass,
  70149. RenderState,
  70150. ShaderProgram,
  70151. ShaderSource,
  70152. VertexArray,
  70153. when,
  70154. BatchTable,
  70155. CullFace,
  70156. PrimitivePipeline,
  70157. PrimitiveState,
  70158. SceneMode,
  70159. ShadowMode) {
  70160. 'use strict';
  70161. /**
  70162. * A primitive represents geometry in the {@link Scene}. The geometry can be from a single {@link GeometryInstance}
  70163. * as shown in example 1 below, or from an array of instances, even if the geometry is from different
  70164. * geometry types, e.g., an {@link RectangleGeometry} and an {@link EllipsoidGeometry} as shown in Code Example 2.
  70165. * <p>
  70166. * A primitive combines geometry instances with an {@link Appearance} that describes the full shading, including
  70167. * {@link Material} and {@link RenderState}. Roughly, the geometry instance defines the structure and placement,
  70168. * and the appearance defines the visual characteristics. Decoupling geometry and appearance allows us to mix
  70169. * and match most of them and add a new geometry or appearance independently of each other.
  70170. * </p>
  70171. * <p>
  70172. * Combining multiple instances into one primitive is called batching, and significantly improves performance for static data.
  70173. * Instances can be individually picked; {@link Scene#pick} returns their {@link GeometryInstance#id}. Using
  70174. * per-instance appearances like {@link PerInstanceColorAppearance}, each instance can also have a unique color.
  70175. * </p>
  70176. * <p>
  70177. * {@link Geometry} can either be created and batched on a web worker or the main thread. The first two examples
  70178. * show geometry that will be created on a web worker by using the descriptions of the geometry. The third example
  70179. * shows how to create the geometry on the main thread by explicitly calling the <code>createGeometry</code> method.
  70180. * </p>
  70181. *
  70182. * @alias Primitive
  70183. * @constructor
  70184. *
  70185. * @param {Object} [options] Object with the following properties:
  70186. * @param {GeometryInstance[]|GeometryInstance} [options.geometryInstances] The geometry instances - or a single geometry instance - to render.
  70187. * @param {Appearance} [options.appearance] The appearance used to render the primitive.
  70188. * @param {Boolean} [options.show=true] Determines if this primitive will be shown.
  70189. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms the primitive (all geometry instances) from model to world coordinates.
  70190. * @param {Boolean} [options.vertexCacheOptimize=false] When <code>true</code>, geometry vertices are optimized for the pre and post-vertex-shader caches.
  70191. * @param {Boolean} [options.interleave=false] When <code>true</code>, geometry vertex attributes are interleaved, which can slightly improve rendering performance but increases load time.
  70192. * @param {Boolean} [options.compressVertices=true] When <code>true</code>, the geometry vertices are compressed, which will save memory.
  70193. * @param {Boolean} [options.releaseGeometryInstances=true] When <code>true</code>, the primitive does not keep a reference to the input <code>geometryInstances</code> to save memory.
  70194. * @param {Boolean} [options.allowPicking=true] When <code>true</code>, each geometry instance will only be pickable with {@link Scene#pick}. When <code>false</code>, GPU memory is saved.
  70195. * @param {Boolean} [options.cull=true] When <code>true</code>, the renderer frustum culls and horizon culls the primitive's commands based on their bounding volume. Set this to <code>false</code> for a small performance gain if you are manually culling the primitive.
  70196. * @param {Boolean} [options.asynchronous=true] Determines if the primitive will be created asynchronously or block until ready.
  70197. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
  70198. * @param {ShadowMode} [options.shadows=ShadowMode.DISABLED] Determines whether this primitive casts or receives shadows from each light source.
  70199. *
  70200. * @example
  70201. * // 1. Draw a translucent ellipse on the surface with a checkerboard pattern
  70202. * var instance = new Cesium.GeometryInstance({
  70203. * geometry : new Cesium.EllipseGeometry({
  70204. * center : Cesium.Cartesian3.fromDegrees(-100.0, 20.0),
  70205. * semiMinorAxis : 500000.0,
  70206. * semiMajorAxis : 1000000.0,
  70207. * rotation : Cesium.Math.PI_OVER_FOUR,
  70208. * vertexFormat : Cesium.VertexFormat.POSITION_AND_ST
  70209. * }),
  70210. * id : 'object returned when this instance is picked and to get/set per-instance attributes'
  70211. * });
  70212. * scene.primitives.add(new Cesium.Primitive({
  70213. * geometryInstances : instance,
  70214. * appearance : new Cesium.EllipsoidSurfaceAppearance({
  70215. * material : Cesium.Material.fromType('Checkerboard')
  70216. * })
  70217. * }));
  70218. *
  70219. * @example
  70220. * // 2. Draw different instances each with a unique color
  70221. * var rectangleInstance = new Cesium.GeometryInstance({
  70222. * geometry : new Cesium.RectangleGeometry({
  70223. * rectangle : Cesium.Rectangle.fromDegrees(-140.0, 30.0, -100.0, 40.0),
  70224. * vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
  70225. * }),
  70226. * id : 'rectangle',
  70227. * attributes : {
  70228. * color : new Cesium.ColorGeometryInstanceAttribute(0.0, 1.0, 1.0, 0.5)
  70229. * }
  70230. * });
  70231. * var ellipsoidInstance = new Cesium.GeometryInstance({
  70232. * geometry : new Cesium.EllipsoidGeometry({
  70233. * radii : new Cesium.Cartesian3(500000.0, 500000.0, 1000000.0),
  70234. * vertexFormat : Cesium.VertexFormat.POSITION_AND_NORMAL
  70235. * }),
  70236. * modelMatrix : Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(
  70237. * Cesium.Cartesian3.fromDegrees(-95.59777, 40.03883)), new Cesium.Cartesian3(0.0, 0.0, 500000.0), new Cesium.Matrix4()),
  70238. * id : 'ellipsoid',
  70239. * attributes : {
  70240. * color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.AQUA)
  70241. * }
  70242. * });
  70243. * scene.primitives.add(new Cesium.Primitive({
  70244. * geometryInstances : [rectangleInstance, ellipsoidInstance],
  70245. * appearance : new Cesium.PerInstanceColorAppearance()
  70246. * }));
  70247. *
  70248. * @example
  70249. * // 3. Create the geometry on the main thread.
  70250. * scene.primitives.add(new Cesium.Primitive({
  70251. * geometryInstances : new Cesium.GeometryInstance({
  70252. * geometry : Cesium.EllipsoidGeometry.createGeometry(new Cesium.EllipsoidGeometry({
  70253. * radii : new Cesium.Cartesian3(500000.0, 500000.0, 1000000.0),
  70254. * vertexFormat : Cesium.VertexFormat.POSITION_AND_NORMAL
  70255. * })),
  70256. * modelMatrix : Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(
  70257. * Cesium.Cartesian3.fromDegrees(-95.59777, 40.03883)), new Cesium.Cartesian3(0.0, 0.0, 500000.0), new Cesium.Matrix4()),
  70258. * id : 'ellipsoid',
  70259. * attributes : {
  70260. * color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.AQUA)
  70261. * }
  70262. * }),
  70263. * appearance : new Cesium.PerInstanceColorAppearance()
  70264. * }));
  70265. *
  70266. * @see GeometryInstance
  70267. * @see Appearance
  70268. */
  70269. function Primitive(options) {
  70270. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  70271. /**
  70272. * The geometry instances rendered with this primitive. This may
  70273. * be <code>undefined</code> if <code>options.releaseGeometryInstances</code>
  70274. * is <code>true</code> when the primitive is constructed.
  70275. * <p>
  70276. * Changing this property after the primitive is rendered has no effect.
  70277. * </p>
  70278. *
  70279. * @type GeometryInstance[]|GeometryInstance
  70280. *
  70281. * @default undefined
  70282. */
  70283. this.geometryInstances = options.geometryInstances;
  70284. /**
  70285. * The {@link Appearance} used to shade this primitive. Each geometry
  70286. * instance is shaded with the same appearance. Some appearances, like
  70287. * {@link PerInstanceColorAppearance} allow giving each instance unique
  70288. * properties.
  70289. *
  70290. * @type Appearance
  70291. *
  70292. * @default undefined
  70293. */
  70294. this.appearance = options.appearance;
  70295. this._appearance = undefined;
  70296. this._material = undefined;
  70297. /**
  70298. * The 4x4 transformation matrix that transforms the primitive (all geometry instances) from model to world coordinates.
  70299. * When this is the identity matrix, the primitive is drawn in world coordinates, i.e., Earth's WGS84 coordinates.
  70300. * Local reference frames can be used by providing a different transformation matrix, like that returned
  70301. * by {@link Transforms.eastNorthUpToFixedFrame}.
  70302. *
  70303. * <p>
  70304. * This property is only supported in 3D mode.
  70305. * </p>
  70306. *
  70307. * @type Matrix4
  70308. *
  70309. * @default Matrix4.IDENTITY
  70310. *
  70311. * @example
  70312. * var origin = Cesium.Cartesian3.fromDegrees(-95.0, 40.0, 200000.0);
  70313. * p.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin);
  70314. */
  70315. this.modelMatrix = Matrix4.clone(defaultValue(options.modelMatrix, Matrix4.IDENTITY));
  70316. this._modelMatrix = new Matrix4();
  70317. /**
  70318. * Determines if the primitive will be shown. This affects all geometry
  70319. * instances in the primitive.
  70320. *
  70321. * @type Boolean
  70322. *
  70323. * @default true
  70324. */
  70325. this.show = defaultValue(options.show, true);
  70326. this._vertexCacheOptimize = defaultValue(options.vertexCacheOptimize, false);
  70327. this._interleave = defaultValue(options.interleave, false);
  70328. this._releaseGeometryInstances = defaultValue(options.releaseGeometryInstances, true);
  70329. this._allowPicking = defaultValue(options.allowPicking, true);
  70330. this._asynchronous = defaultValue(options.asynchronous, true);
  70331. this._compressVertices = defaultValue(options.compressVertices, true);
  70332. /**
  70333. * When <code>true</code>, the renderer frustum culls and horizon culls the primitive's commands
  70334. * based on their bounding volume. Set this to <code>false</code> for a small performance gain
  70335. * if you are manually culling the primitive.
  70336. *
  70337. * @type {Boolean}
  70338. *
  70339. * @default true
  70340. */
  70341. this.cull = defaultValue(options.cull, true);
  70342. /**
  70343. * This property is for debugging only; it is not for production use nor is it optimized.
  70344. * <p>
  70345. * Draws the bounding sphere for each draw command in the primitive.
  70346. * </p>
  70347. *
  70348. * @type {Boolean}
  70349. *
  70350. * @default false
  70351. */
  70352. this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false);
  70353. /**
  70354. * @private
  70355. */
  70356. this.rtcCenter = options.rtcCenter;
  70357. if (defined(this.rtcCenter) && (!defined(this.geometryInstances) || (isArray(this.geometryInstances) && this.geometryInstances !== 1))) {
  70358. throw new DeveloperError('Relative-to-center rendering only supports one geometry instance.');
  70359. }
  70360. /**
  70361. * Determines whether this primitive casts or receives shadows from each light source.
  70362. *
  70363. * @type {ShadowMode}
  70364. *
  70365. * @default ShadowMode.DISABLED
  70366. */
  70367. this.shadows = defaultValue(options.shadows, ShadowMode.DISABLED);
  70368. this._translucent = undefined;
  70369. this._state = PrimitiveState.READY;
  70370. this._geometries = [];
  70371. this._error = undefined;
  70372. this._numberOfInstances = 0;
  70373. this._boundingSpheres = [];
  70374. this._boundingSphereWC = [];
  70375. this._boundingSphereCV = [];
  70376. this._boundingSphere2D = [];
  70377. this._boundingSphereMorph = [];
  70378. this._perInstanceAttributeCache = [];
  70379. this._instanceIds = [];
  70380. this._lastPerInstanceAttributeIndex = 0;
  70381. this._va = [];
  70382. this._attributeLocations = undefined;
  70383. this._primitiveType = undefined;
  70384. this._frontFaceRS = undefined;
  70385. this._backFaceRS = undefined;
  70386. this._sp = undefined;
  70387. this._pickRS = undefined;
  70388. this._pickSP = undefined;
  70389. this._pickIds = [];
  70390. this._colorCommands = [];
  70391. this._pickCommands = [];
  70392. this._readOnlyInstanceAttributes = options._readOnlyInstanceAttributes;
  70393. this._createBoundingVolumeFunction = options._createBoundingVolumeFunction;
  70394. this._createRenderStatesFunction = options._createRenderStatesFunction;
  70395. this._createShaderProgramFunction = options._createShaderProgramFunction;
  70396. this._createCommandsFunction = options._createCommandsFunction;
  70397. this._updateAndQueueCommandsFunction = options._updateAndQueueCommandsFunction;
  70398. this._createPickOffsets = options._createPickOffsets;
  70399. this._pickOffsets = undefined;
  70400. this._createGeometryResults = undefined;
  70401. this._ready = false;
  70402. this._readyPromise = when.defer();
  70403. this._batchTable = undefined;
  70404. this._batchTableAttributeIndices = undefined;
  70405. this._instanceBoundingSpheres = undefined;
  70406. this._instanceBoundingSpheresCV = undefined;
  70407. this._batchTableBoundingSpheresUpdated = false;
  70408. this._batchTableBoundingSphereAttributeIndices = undefined;
  70409. }
  70410. defineProperties(Primitive.prototype, {
  70411. /**
  70412. * When <code>true</code>, geometry vertices are optimized for the pre and post-vertex-shader caches.
  70413. *
  70414. * @memberof Primitive.prototype
  70415. *
  70416. * @type {Boolean}
  70417. * @readonly
  70418. *
  70419. * @default true
  70420. */
  70421. vertexCacheOptimize : {
  70422. get : function() {
  70423. return this._vertexCacheOptimize;
  70424. }
  70425. },
  70426. /**
  70427. * Determines if geometry vertex attributes are interleaved, which can slightly improve rendering performance.
  70428. *
  70429. * @memberof Primitive.prototype
  70430. *
  70431. * @type {Boolean}
  70432. * @readonly
  70433. *
  70434. * @default false
  70435. */
  70436. interleave : {
  70437. get : function() {
  70438. return this._interleave;
  70439. }
  70440. },
  70441. /**
  70442. * When <code>true</code>, the primitive does not keep a reference to the input <code>geometryInstances</code> to save memory.
  70443. *
  70444. * @memberof Primitive.prototype
  70445. *
  70446. * @type {Boolean}
  70447. * @readonly
  70448. *
  70449. * @default true
  70450. */
  70451. releaseGeometryInstances : {
  70452. get : function() {
  70453. return this._releaseGeometryInstances;
  70454. }
  70455. },
  70456. /**
  70457. * When <code>true</code>, each geometry instance will only be pickable with {@link Scene#pick}. When <code>false</code>, GPU memory is saved. *
  70458. *
  70459. * @memberof Primitive.prototype
  70460. *
  70461. * @type {Boolean}
  70462. * @readonly
  70463. *
  70464. * @default true
  70465. */
  70466. allowPicking : {
  70467. get : function() {
  70468. return this._allowPicking;
  70469. }
  70470. },
  70471. /**
  70472. * Determines if the geometry instances will be created and batched on a web worker.
  70473. *
  70474. * @memberof Primitive.prototype
  70475. *
  70476. * @type {Boolean}
  70477. * @readonly
  70478. *
  70479. * @default true
  70480. */
  70481. asynchronous : {
  70482. get : function() {
  70483. return this._asynchronous;
  70484. }
  70485. },
  70486. /**
  70487. * When <code>true</code>, geometry vertices are compressed, which will save memory.
  70488. *
  70489. * @memberof Primitive.prototype
  70490. *
  70491. * @type {Boolean}
  70492. * @readonly
  70493. *
  70494. * @default true
  70495. */
  70496. compressVertices : {
  70497. get : function() {
  70498. return this._compressVertices;
  70499. }
  70500. },
  70501. /**
  70502. * Determines if the primitive is complete and ready to render. If this property is
  70503. * true, the primitive will be rendered the next time that {@link Primitive#update}
  70504. * is called.
  70505. *
  70506. * @memberof Primitive.prototype
  70507. *
  70508. * @type {Boolean}
  70509. * @readonly
  70510. */
  70511. ready : {
  70512. get : function() {
  70513. return this._ready;
  70514. }
  70515. },
  70516. /**
  70517. * Gets a promise that resolves when the primitive is ready to render.
  70518. * @memberof Primitive.prototype
  70519. * @type {Promise.<Primitive>}
  70520. * @readonly
  70521. */
  70522. readyPromise : {
  70523. get : function() {
  70524. return this._readyPromise.promise;
  70525. }
  70526. }
  70527. });
  70528. function getCommonPerInstanceAttributeNames(instances) {
  70529. var length = instances.length;
  70530. var attributesInAllInstances = [];
  70531. var attributes0 = instances[0].attributes;
  70532. var name;
  70533. for (name in attributes0) {
  70534. if (attributes0.hasOwnProperty(name)) {
  70535. var attribute = attributes0[name];
  70536. var inAllInstances = true;
  70537. // Does this same attribute exist in all instances?
  70538. for (var i = 1; i < length; ++i) {
  70539. var otherAttribute = instances[i].attributes[name];
  70540. if (!defined(otherAttribute) ||
  70541. (attribute.componentDatatype !== otherAttribute.componentDatatype) ||
  70542. (attribute.componentsPerAttribute !== otherAttribute.componentsPerAttribute) ||
  70543. (attribute.normalize !== otherAttribute.normalize)) {
  70544. inAllInstances = false;
  70545. break;
  70546. }
  70547. }
  70548. if (inAllInstances) {
  70549. attributesInAllInstances.push(name);
  70550. }
  70551. }
  70552. }
  70553. return attributesInAllInstances;
  70554. }
  70555. var scratchGetAttributeCartesian2 = new Cartesian2();
  70556. var scratchGetAttributeCartesian3 = new Cartesian3();
  70557. var scratchGetAttributeCartesian4 = new Cartesian4();
  70558. function getAttributeValue(value) {
  70559. var componentsPerAttribute = value.length;
  70560. if (componentsPerAttribute === 1) {
  70561. return value[0];
  70562. } else if (componentsPerAttribute === 2) {
  70563. return Cartesian2.unpack(value, 0, scratchGetAttributeCartesian2);
  70564. } else if (componentsPerAttribute === 3) {
  70565. return Cartesian3.unpack(value, 0, scratchGetAttributeCartesian3);
  70566. } else if (componentsPerAttribute === 4) {
  70567. return Cartesian4.unpack(value, 0, scratchGetAttributeCartesian4);
  70568. }
  70569. }
  70570. function createBatchTable(primitive, context) {
  70571. var geometryInstances = primitive.geometryInstances;
  70572. var instances = (isArray(geometryInstances)) ? geometryInstances : [geometryInstances];
  70573. var numberOfInstances = instances.length;
  70574. if (numberOfInstances === 0) {
  70575. return;
  70576. }
  70577. var names = getCommonPerInstanceAttributeNames(instances);
  70578. var length = names.length;
  70579. var allowPicking = primitive.allowPicking;
  70580. var attributes = [];
  70581. var attributeIndices = {};
  70582. var boundingSphereAttributeIndices = {};
  70583. var firstInstance = instances[0];
  70584. var instanceAttributes = firstInstance.attributes;
  70585. var i;
  70586. var name;
  70587. var attribute;
  70588. for (i = 0; i < length; ++i) {
  70589. name = names[i];
  70590. attribute = instanceAttributes[name];
  70591. attributeIndices[name] = i;
  70592. attributes.push({
  70593. functionName : 'czm_batchTable_' + name,
  70594. componentDatatype : attribute.componentDatatype,
  70595. componentsPerAttribute : attribute.componentsPerAttribute,
  70596. normalize : attribute.normalize
  70597. });
  70598. }
  70599. if (names.indexOf('distanceDisplayCondition') !== -1) {
  70600. attributes.push({
  70601. functionName : 'czm_batchTable_boundingSphereCenter3DHigh',
  70602. componentDatatype : ComponentDatatype.FLOAT,
  70603. componentsPerAttribute : 3
  70604. },{
  70605. functionName : 'czm_batchTable_boundingSphereCenter3DLow',
  70606. componentDatatype : ComponentDatatype.FLOAT,
  70607. componentsPerAttribute : 3
  70608. },{
  70609. functionName : 'czm_batchTable_boundingSphereCenter2DHigh',
  70610. componentDatatype : ComponentDatatype.FLOAT,
  70611. componentsPerAttribute : 3
  70612. },{
  70613. functionName : 'czm_batchTable_boundingSphereCenter2DLow',
  70614. componentDatatype : ComponentDatatype.FLOAT,
  70615. componentsPerAttribute : 3
  70616. },{
  70617. functionName : 'czm_batchTable_boundingSphereRadius',
  70618. componentDatatype : ComponentDatatype.FLOAT,
  70619. componentsPerAttribute : 1
  70620. });
  70621. boundingSphereAttributeIndices.center3DHigh = attributes.length - 5;
  70622. boundingSphereAttributeIndices.center3DLow = attributes.length - 4;
  70623. boundingSphereAttributeIndices.center2DHigh = attributes.length - 3;
  70624. boundingSphereAttributeIndices.center2DLow = attributes.length - 2;
  70625. boundingSphereAttributeIndices.radius = attributes.length - 1;
  70626. }
  70627. if (allowPicking) {
  70628. attributes.push({
  70629. functionName : 'czm_batchTable_pickColor',
  70630. componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
  70631. componentsPerAttribute : 4,
  70632. normalize : true
  70633. });
  70634. }
  70635. var attributesLength = attributes.length;
  70636. var batchTable = new BatchTable(context, attributes, numberOfInstances);
  70637. for (i = 0; i < numberOfInstances; ++i) {
  70638. var instance = instances[i];
  70639. instanceAttributes = instance.attributes;
  70640. for (var j = 0; j < length; ++j) {
  70641. name = names[j];
  70642. attribute = instanceAttributes[name];
  70643. var value = getAttributeValue(attribute.value);
  70644. var attributeIndex = attributeIndices[name];
  70645. batchTable.setBatchedAttribute(i, attributeIndex, value);
  70646. }
  70647. if (allowPicking) {
  70648. var pickObject = {
  70649. primitive : defaultValue(instance.pickPrimitive, primitive)
  70650. };
  70651. if (defined(instance.id)) {
  70652. pickObject.id = instance.id;
  70653. }
  70654. var pickId = context.createPickId(pickObject);
  70655. primitive._pickIds.push(pickId);
  70656. var pickColor = pickId.color;
  70657. var color = scratchGetAttributeCartesian4;
  70658. color.x = Color.floatToByte(pickColor.red);
  70659. color.y = Color.floatToByte(pickColor.green);
  70660. color.z = Color.floatToByte(pickColor.blue);
  70661. color.w = Color.floatToByte(pickColor.alpha);
  70662. batchTable.setBatchedAttribute(i, attributesLength - 1, color);
  70663. }
  70664. }
  70665. primitive._batchTable = batchTable;
  70666. primitive._batchTableAttributeIndices = attributeIndices;
  70667. primitive._batchTableBoundingSphereAttributeIndices = boundingSphereAttributeIndices;
  70668. }
  70669. function cloneAttribute(attribute) {
  70670. var clonedValues;
  70671. if (isArray(attribute.values)) {
  70672. clonedValues = attribute.values.slice(0);
  70673. } else {
  70674. clonedValues = new attribute.values.constructor(attribute.values);
  70675. }
  70676. return new GeometryAttribute({
  70677. componentDatatype : attribute.componentDatatype,
  70678. componentsPerAttribute : attribute.componentsPerAttribute,
  70679. normalize : attribute.normalize,
  70680. values : clonedValues
  70681. });
  70682. }
  70683. function cloneGeometry(geometry) {
  70684. var attributes = geometry.attributes;
  70685. var newAttributes = new GeometryAttributes();
  70686. for (var property in attributes) {
  70687. if (attributes.hasOwnProperty(property) && defined(attributes[property])) {
  70688. newAttributes[property] = cloneAttribute(attributes[property]);
  70689. }
  70690. }
  70691. var indices;
  70692. if (defined(geometry.indices)) {
  70693. var sourceValues = geometry.indices;
  70694. if (isArray(sourceValues)) {
  70695. indices = sourceValues.slice(0);
  70696. } else {
  70697. indices = new sourceValues.constructor(sourceValues);
  70698. }
  70699. }
  70700. return new Geometry({
  70701. attributes : newAttributes,
  70702. indices : indices,
  70703. primitiveType : geometry.primitiveType,
  70704. boundingSphere : BoundingSphere.clone(geometry.boundingSphere)
  70705. });
  70706. }
  70707. function cloneInstance(instance, geometry) {
  70708. return {
  70709. geometry : geometry,
  70710. modelMatrix : Matrix4.clone(instance.modelMatrix),
  70711. pickPrimitive : instance.pickPrimitive,
  70712. id : instance.id
  70713. };
  70714. }
  70715. var positionRegex = /attribute\s+vec(?:3|4)\s+(.*)3DHigh;/g;
  70716. Primitive._modifyShaderPosition = function(primitive, vertexShaderSource, scene3DOnly) {
  70717. var match;
  70718. var forwardDecl = '';
  70719. var attributes = '';
  70720. var computeFunctions = '';
  70721. while ((match = positionRegex.exec(vertexShaderSource)) !== null) {
  70722. var name = match[1];
  70723. var functionName = 'vec4 czm_compute' + name[0].toUpperCase() + name.substr(1) + '()';
  70724. // Don't forward-declare czm_computePosition because computePosition.glsl already does.
  70725. if (functionName !== 'vec4 czm_computePosition()') {
  70726. forwardDecl += functionName + ';\n';
  70727. }
  70728. if (!defined(primitive.rtcCenter)) {
  70729. // Use GPU RTE
  70730. if (!scene3DOnly) {
  70731. attributes +=
  70732. 'attribute vec3 ' + name + '2DHigh;\n' +
  70733. 'attribute vec3 ' + name + '2DLow;\n';
  70734. computeFunctions +=
  70735. functionName + '\n' +
  70736. '{\n' +
  70737. ' vec4 p;\n' +
  70738. ' if (czm_morphTime == 1.0)\n' +
  70739. ' {\n' +
  70740. ' p = czm_translateRelativeToEye(' + name + '3DHigh, ' + name + '3DLow);\n' +
  70741. ' }\n' +
  70742. ' else if (czm_morphTime == 0.0)\n' +
  70743. ' {\n' +
  70744. ' p = czm_translateRelativeToEye(' + name + '2DHigh.zxy, ' + name + '2DLow.zxy);\n' +
  70745. ' }\n' +
  70746. ' else\n' +
  70747. ' {\n' +
  70748. ' p = czm_columbusViewMorph(\n' +
  70749. ' czm_translateRelativeToEye(' + name + '2DHigh.zxy, ' + name + '2DLow.zxy),\n' +
  70750. ' czm_translateRelativeToEye(' + name + '3DHigh, ' + name + '3DLow),\n' +
  70751. ' czm_morphTime);\n' +
  70752. ' }\n' +
  70753. ' return p;\n' +
  70754. '}\n\n';
  70755. } else {
  70756. computeFunctions +=
  70757. functionName + '\n' +
  70758. '{\n' +
  70759. ' return czm_translateRelativeToEye(' + name + '3DHigh, ' + name + '3DLow);\n' +
  70760. '}\n\n';
  70761. }
  70762. } else {
  70763. // Use RTC
  70764. vertexShaderSource = vertexShaderSource.replace(/attribute\s+vec(?:3|4)\s+position3DHigh;/g, '');
  70765. vertexShaderSource = vertexShaderSource.replace(/attribute\s+vec(?:3|4)\s+position3DLow;/g, '');
  70766. forwardDecl += 'uniform mat4 u_modifiedModelView;\n';
  70767. attributes += 'attribute vec4 position;\n';
  70768. computeFunctions +=
  70769. functionName + '\n' +
  70770. '{\n' +
  70771. ' return u_modifiedModelView * position;\n' +
  70772. '}\n\n';
  70773. vertexShaderSource = vertexShaderSource.replace(/czm_modelViewRelativeToEye\s+\*\s+/g, '');
  70774. vertexShaderSource = vertexShaderSource.replace(/czm_modelViewProjectionRelativeToEye/g, 'czm_projection');
  70775. }
  70776. }
  70777. return [forwardDecl, attributes, vertexShaderSource, computeFunctions].join('\n');
  70778. };
  70779. Primitive._appendShowToShader = function(primitive, vertexShaderSource) {
  70780. if (!defined(primitive._batchTableAttributeIndices.show)) {
  70781. return vertexShaderSource;
  70782. }
  70783. var renamedVS = ShaderSource.replaceMain(vertexShaderSource, 'czm_non_show_main');
  70784. var showMain =
  70785. 'void main() \n' +
  70786. '{ \n' +
  70787. ' czm_non_show_main(); \n' +
  70788. ' gl_Position *= czm_batchTable_show(batchId); \n' +
  70789. '}';
  70790. return renamedVS + '\n' + showMain;
  70791. };
  70792. Primitive._updateColorAttribute = function(primitive, vertexShaderSource) {
  70793. // some appearances have a color attribute for per vertex color.
  70794. // only remove if color is a per instance attribute.
  70795. if (!defined(primitive._batchTableAttributeIndices.color)) {
  70796. return vertexShaderSource;
  70797. }
  70798. if (vertexShaderSource.search(/attribute\s+vec4\s+color;/g) === -1) {
  70799. return vertexShaderSource;
  70800. }
  70801. var modifiedVS = vertexShaderSource;
  70802. modifiedVS = modifiedVS.replace(/attribute\s+vec4\s+color;/g, '');
  70803. modifiedVS = modifiedVS.replace(/(\b)color(\b)/g, '$1czm_batchTable_color(batchId)$2');
  70804. return modifiedVS;
  70805. };
  70806. Primitive._updatePickColorAttribute = function(source) {
  70807. var vsPick = source.replace(/attribute\s+vec4\s+pickColor;/g, '');
  70808. vsPick = vsPick.replace(/(\b)pickColor(\b)/g, '$1czm_batchTable_pickColor(batchId)$2');
  70809. return vsPick;
  70810. };
  70811. Primitive._appendDistanceDisplayConditionToShader = function(primitive, vertexShaderSource, scene3DOnly) {
  70812. if (!defined(primitive._batchTableAttributeIndices.distanceDisplayCondition)) {
  70813. return vertexShaderSource;
  70814. }
  70815. var renamedVS = ShaderSource.replaceMain(vertexShaderSource, 'czm_non_distanceDisplayCondition_main');
  70816. var distanceDisplayConditionMain =
  70817. 'void main() \n' +
  70818. '{ \n' +
  70819. ' czm_non_distanceDisplayCondition_main(); \n' +
  70820. ' vec2 distanceDisplayCondition = czm_batchTable_distanceDisplayCondition(batchId);\n' +
  70821. ' vec3 boundingSphereCenter3DHigh = czm_batchTable_boundingSphereCenter3DHigh(batchId);\n' +
  70822. ' vec3 boundingSphereCenter3DLow = czm_batchTable_boundingSphereCenter3DLow(batchId);\n' +
  70823. ' vec3 boundingSphereCenter2DHigh = czm_batchTable_boundingSphereCenter2DHigh(batchId);\n' +
  70824. ' vec3 boundingSphereCenter2DLow = czm_batchTable_boundingSphereCenter2DLow(batchId);\n' +
  70825. ' float boundingSphereRadius = czm_batchTable_boundingSphereRadius(batchId);\n';
  70826. if (!scene3DOnly) {
  70827. distanceDisplayConditionMain +=
  70828. ' vec4 centerRTE;\n' +
  70829. ' if (czm_morphTime == 1.0)\n' +
  70830. ' {\n' +
  70831. ' centerRTE = czm_translateRelativeToEye(boundingSphereCenter3DHigh, boundingSphereCenter3DLow);\n' +
  70832. ' }\n' +
  70833. ' else if (czm_morphTime == 0.0)\n' +
  70834. ' {\n' +
  70835. ' centerRTE = czm_translateRelativeToEye(boundingSphereCenter2DHigh.zxy, boundingSphereCenter2DLow.zxy);\n' +
  70836. ' }\n' +
  70837. ' else\n' +
  70838. ' {\n' +
  70839. ' centerRTE = czm_columbusViewMorph(\n' +
  70840. ' czm_translateRelativeToEye(boundingSphereCenter2DHigh.zxy, boundingSphereCenter2DLow.zxy),\n' +
  70841. ' czm_translateRelativeToEye(boundingSphereCenter3DHigh, boundingSphereCenter3DLow),\n' +
  70842. ' czm_morphTime);\n' +
  70843. ' }\n';
  70844. } else {
  70845. distanceDisplayConditionMain +=
  70846. ' vec4 centerRTE = czm_translateRelativeToEye(boundingSphereCenter3DHigh, boundingSphereCenter3DLow);\n';
  70847. }
  70848. distanceDisplayConditionMain +=
  70849. ' float radiusSq = boundingSphereRadius * boundingSphereRadius; \n' +
  70850. ' float distanceSq; \n' +
  70851. ' if (czm_sceneMode == czm_sceneMode2D) \n' +
  70852. ' { \n' +
  70853. ' distanceSq = czm_eyeHeight2D.y - radiusSq; \n' +
  70854. ' } \n' +
  70855. ' else \n' +
  70856. ' { \n' +
  70857. ' distanceSq = dot(centerRTE.xyz, centerRTE.xyz) - radiusSq; \n' +
  70858. ' } \n' +
  70859. ' distanceSq = max(distanceSq, 0.0); \n' +
  70860. ' float nearSq = distanceDisplayCondition.x * distanceDisplayCondition.x; \n' +
  70861. ' float farSq = distanceDisplayCondition.y * distanceDisplayCondition.y; \n' +
  70862. ' float show = (distanceSq >= nearSq && distanceSq <= farSq) ? 1.0 : 0.0; \n' +
  70863. ' gl_Position *= show; \n' +
  70864. '}';
  70865. return renamedVS + '\n' + distanceDisplayConditionMain;
  70866. };
  70867. function modifyForEncodedNormals(primitive, vertexShaderSource) {
  70868. if (!primitive.compressVertices) {
  70869. return vertexShaderSource;
  70870. }
  70871. var containsNormal = vertexShaderSource.search(/attribute\s+vec3\s+normal;/g) !== -1;
  70872. var containsSt = vertexShaderSource.search(/attribute\s+vec2\s+st;/g) !== -1;
  70873. if (!containsNormal && !containsSt) {
  70874. return vertexShaderSource;
  70875. }
  70876. var containsTangent = vertexShaderSource.search(/attribute\s+vec3\s+tangent;/g) !== -1;
  70877. var containsBinormal = vertexShaderSource.search(/attribute\s+vec3\s+binormal;/g) !== -1;
  70878. var numComponents = containsSt && containsNormal ? 2.0 : 1.0;
  70879. numComponents += containsTangent || containsBinormal ? 1 : 0;
  70880. var type = (numComponents > 1) ? 'vec' + numComponents : 'float';
  70881. var attributeName = 'compressedAttributes';
  70882. var attributeDecl = 'attribute ' + type + ' ' + attributeName + ';';
  70883. var globalDecl = '';
  70884. var decode = '';
  70885. if (containsSt) {
  70886. globalDecl += 'vec2 st;\n';
  70887. var stComponent = numComponents > 1 ? attributeName + '.x' : attributeName;
  70888. decode += ' st = czm_decompressTextureCoordinates(' + stComponent + ');\n';
  70889. }
  70890. if (containsNormal && containsTangent && containsBinormal) {
  70891. globalDecl +=
  70892. 'vec3 normal;\n' +
  70893. 'vec3 tangent;\n' +
  70894. 'vec3 binormal;\n';
  70895. decode += ' czm_octDecode(' + attributeName + '.' + (containsSt ? 'yz' : 'xy') + ', normal, tangent, binormal);\n';
  70896. } else {
  70897. if (containsNormal) {
  70898. globalDecl += 'vec3 normal;\n';
  70899. decode += ' normal = czm_octDecode(' + attributeName + (numComponents > 1 ? '.' + (containsSt ? 'y' : 'x') : '') + ');\n';
  70900. }
  70901. if (containsTangent) {
  70902. globalDecl += 'vec3 tangent;\n';
  70903. decode += ' tangent = czm_octDecode(' + attributeName + '.' + (containsSt && containsNormal ? 'z' : 'y') + ');\n';
  70904. }
  70905. if (containsBinormal) {
  70906. globalDecl += 'vec3 binormal;\n';
  70907. decode += ' binormal = czm_octDecode(' + attributeName + '.' + (containsSt && containsNormal ? 'z' : 'y') + ');\n';
  70908. }
  70909. }
  70910. var modifiedVS = vertexShaderSource;
  70911. modifiedVS = modifiedVS.replace(/attribute\s+vec3\s+normal;/g, '');
  70912. modifiedVS = modifiedVS.replace(/attribute\s+vec2\s+st;/g, '');
  70913. modifiedVS = modifiedVS.replace(/attribute\s+vec3\s+tangent;/g, '');
  70914. modifiedVS = modifiedVS.replace(/attribute\s+vec3\s+binormal;/g, '');
  70915. modifiedVS = ShaderSource.replaceMain(modifiedVS, 'czm_non_compressed_main');
  70916. var compressedMain =
  70917. 'void main() \n' +
  70918. '{ \n' +
  70919. decode +
  70920. ' czm_non_compressed_main(); \n' +
  70921. '}';
  70922. return [attributeDecl, globalDecl, modifiedVS, compressedMain].join('\n');
  70923. }
  70924. function validateShaderMatching(shaderProgram, attributeLocations) {
  70925. // For a VAO and shader program to be compatible, the VAO must have
  70926. // all active attribute in the shader program. The VAO may have
  70927. // extra attributes with the only concern being a potential
  70928. // performance hit due to extra memory bandwidth and cache pollution.
  70929. // The shader source could have extra attributes that are not used,
  70930. // but there is no guarantee they will be optimized out.
  70931. //
  70932. // Here, we validate that the VAO has all attributes required
  70933. // to match the shader program.
  70934. var shaderAttributes = shaderProgram.vertexAttributes;
  70935. for (var name in shaderAttributes) {
  70936. if (shaderAttributes.hasOwnProperty(name)) {
  70937. if (!defined(attributeLocations[name])) {
  70938. throw new DeveloperError('Appearance/Geometry mismatch. The appearance requires vertex shader attribute input \'' + name +
  70939. '\', which was not computed as part of the Geometry. Use the appearance\'s vertexFormat property when constructing the geometry.');
  70940. }
  70941. }
  70942. }
  70943. }
  70944. function getUniformFunction(uniforms, name) {
  70945. return function() {
  70946. return uniforms[name];
  70947. };
  70948. }
  70949. var numberOfCreationWorkers = Math.max(FeatureDetection.hardwareConcurrency - 1, 1);
  70950. var createGeometryTaskProcessors;
  70951. var combineGeometryTaskProcessor = new TaskProcessor('combineGeometry', Number.POSITIVE_INFINITY);
  70952. function loadAsynchronous(primitive, frameState) {
  70953. var instances;
  70954. var geometry;
  70955. var i;
  70956. var j;
  70957. var instanceIds = primitive._instanceIds;
  70958. if (primitive._state === PrimitiveState.READY) {
  70959. instances = (isArray(primitive.geometryInstances)) ? primitive.geometryInstances : [primitive.geometryInstances];
  70960. var length = primitive._numberOfInstances = instances.length;
  70961. var promises = [];
  70962. var subTasks = [];
  70963. for (i = 0; i < length; ++i) {
  70964. geometry = instances[i].geometry;
  70965. instanceIds.push(instances[i].id);
  70966. if (!defined(geometry._workerName)) {
  70967. throw new DeveloperError('_workerName must be defined for asynchronous geometry.');
  70968. }
  70969. subTasks.push({
  70970. moduleName : geometry._workerName,
  70971. geometry : geometry
  70972. });
  70973. }
  70974. if (!defined(createGeometryTaskProcessors)) {
  70975. createGeometryTaskProcessors = new Array(numberOfCreationWorkers);
  70976. for (i = 0; i < numberOfCreationWorkers; i++) {
  70977. createGeometryTaskProcessors[i] = new TaskProcessor('createGeometry', Number.POSITIVE_INFINITY);
  70978. }
  70979. }
  70980. var subTask;
  70981. subTasks = subdivideArray(subTasks, numberOfCreationWorkers);
  70982. for (i = 0; i < subTasks.length; i++) {
  70983. var packedLength = 0;
  70984. var workerSubTasks = subTasks[i];
  70985. var workerSubTasksLength = workerSubTasks.length;
  70986. for (j = 0; j < workerSubTasksLength; ++j) {
  70987. subTask = workerSubTasks[j];
  70988. geometry = subTask.geometry;
  70989. if (defined(geometry.constructor.pack)) {
  70990. subTask.offset = packedLength;
  70991. packedLength += defaultValue(geometry.constructor.packedLength, geometry.packedLength);
  70992. }
  70993. }
  70994. var subTaskTransferableObjects;
  70995. if (packedLength > 0) {
  70996. var array = new Float64Array(packedLength);
  70997. subTaskTransferableObjects = [array.buffer];
  70998. for (j = 0; j < workerSubTasksLength; ++j) {
  70999. subTask = workerSubTasks[j];
  71000. geometry = subTask.geometry;
  71001. if (defined(geometry.constructor.pack)) {
  71002. geometry.constructor.pack(geometry, array, subTask.offset);
  71003. subTask.geometry = array;
  71004. }
  71005. }
  71006. }
  71007. promises.push(createGeometryTaskProcessors[i].scheduleTask({
  71008. subTasks : subTasks[i]
  71009. }, subTaskTransferableObjects));
  71010. }
  71011. primitive._state = PrimitiveState.CREATING;
  71012. when.all(promises, function(results) {
  71013. primitive._createGeometryResults = results;
  71014. primitive._state = PrimitiveState.CREATED;
  71015. }).otherwise(function(error) {
  71016. setReady(primitive, frameState, PrimitiveState.FAILED, error);
  71017. });
  71018. } else if (primitive._state === PrimitiveState.CREATED) {
  71019. var transferableObjects = [];
  71020. instances = (isArray(primitive.geometryInstances)) ? primitive.geometryInstances : [primitive.geometryInstances];
  71021. var scene3DOnly = frameState.scene3DOnly;
  71022. var projection = frameState.mapProjection;
  71023. var promise = combineGeometryTaskProcessor.scheduleTask(PrimitivePipeline.packCombineGeometryParameters({
  71024. createGeometryResults : primitive._createGeometryResults,
  71025. instances : instances,
  71026. ellipsoid : projection.ellipsoid,
  71027. projection : projection,
  71028. elementIndexUintSupported : frameState.context.elementIndexUint,
  71029. scene3DOnly : scene3DOnly,
  71030. vertexCacheOptimize : primitive.vertexCacheOptimize,
  71031. compressVertices : primitive.compressVertices,
  71032. modelMatrix : primitive.modelMatrix,
  71033. createPickOffsets : primitive._createPickOffsets
  71034. }, transferableObjects), transferableObjects);
  71035. primitive._createGeometryResults = undefined;
  71036. primitive._state = PrimitiveState.COMBINING;
  71037. when(promise, function(packedResult) {
  71038. var result = PrimitivePipeline.unpackCombineGeometryResults(packedResult);
  71039. primitive._geometries = result.geometries;
  71040. primitive._attributeLocations = result.attributeLocations;
  71041. primitive.modelMatrix = Matrix4.clone(result.modelMatrix, primitive.modelMatrix);
  71042. primitive._pickOffsets = result.pickOffsets;
  71043. primitive._instanceBoundingSpheres = result.boundingSpheres;
  71044. primitive._instanceBoundingSpheresCV = result.boundingSpheresCV;
  71045. if (defined(primitive._geometries) && primitive._geometries.length > 0) {
  71046. primitive._state = PrimitiveState.COMBINED;
  71047. } else {
  71048. setReady(primitive, frameState, PrimitiveState.FAILED, undefined);
  71049. }
  71050. }).otherwise(function(error) {
  71051. setReady(primitive, frameState, PrimitiveState.FAILED, error);
  71052. });
  71053. }
  71054. }
  71055. function loadSynchronous(primitive, frameState) {
  71056. var instances = (isArray(primitive.geometryInstances)) ? primitive.geometryInstances : [primitive.geometryInstances];
  71057. var length = primitive._numberOfInstances = instances.length;
  71058. var clonedInstances = new Array(length);
  71059. var instanceIds = primitive._instanceIds;
  71060. var instance;
  71061. var i;
  71062. var geometryIndex = 0;
  71063. for (i = 0; i < length; i++) {
  71064. instance = instances[i];
  71065. var geometry = instance.geometry;
  71066. var createdGeometry;
  71067. if (defined(geometry.attributes) && defined(geometry.primitiveType)) {
  71068. createdGeometry = cloneGeometry(geometry);
  71069. } else {
  71070. createdGeometry = geometry.constructor.createGeometry(geometry);
  71071. }
  71072. clonedInstances[geometryIndex++] = cloneInstance(instance, createdGeometry);
  71073. instanceIds.push(instance.id);
  71074. }
  71075. clonedInstances.length = geometryIndex;
  71076. var scene3DOnly = frameState.scene3DOnly;
  71077. var projection = frameState.mapProjection;
  71078. var result = PrimitivePipeline.combineGeometry({
  71079. instances : clonedInstances,
  71080. ellipsoid : projection.ellipsoid,
  71081. projection : projection,
  71082. elementIndexUintSupported : frameState.context.elementIndexUint,
  71083. scene3DOnly : scene3DOnly,
  71084. vertexCacheOptimize : primitive.vertexCacheOptimize,
  71085. compressVertices : primitive.compressVertices,
  71086. modelMatrix : primitive.modelMatrix,
  71087. createPickOffsets : primitive._createPickOffsets
  71088. });
  71089. primitive._geometries = result.geometries;
  71090. primitive._attributeLocations = result.attributeLocations;
  71091. primitive.modelMatrix = Matrix4.clone(result.modelMatrix, primitive.modelMatrix);
  71092. primitive._pickOffsets = result.pickOffsets;
  71093. primitive._instanceBoundingSpheres = result.boundingSpheres;
  71094. primitive._instanceBoundingSpheresCV = result.boundingSpheresCV;
  71095. if (defined(primitive._geometries) && primitive._geometries.length > 0) {
  71096. primitive._state = PrimitiveState.COMBINED;
  71097. } else {
  71098. setReady(primitive, frameState, PrimitiveState.FAILED, undefined);
  71099. }
  71100. }
  71101. var scratchBoundingSphereCenterEncoded = new EncodedCartesian3();
  71102. var scratchBoundingSphereCartographic = new Cartographic();
  71103. var scratchBoundingSphereCenter2D = new Cartesian3();
  71104. function updateBatchTableBoundingSpheres(primitive, frameState) {
  71105. var hasDistanceDisplayCondition = defined(primitive._batchTableAttributeIndices.distanceDisplayCondition);
  71106. if (!hasDistanceDisplayCondition && primitive._batchTableBoundingSpheresUpdated) {
  71107. return;
  71108. }
  71109. var indices = primitive._batchTableBoundingSphereAttributeIndices;
  71110. var center3DHighIndex = indices.center3DHigh;
  71111. var center3DLowIndex = indices.center3DLow;
  71112. var center2DHighIndex = indices.center2DHigh;
  71113. var center2DLowIndex = indices.center2DLow;
  71114. var radiusIndex = indices.radius;
  71115. var projection = frameState.mapProjection;
  71116. var ellipsoid = projection.ellipsoid;
  71117. var batchTable = primitive._batchTable;
  71118. var boundingSpheres = primitive._instanceBoundingSpheres;
  71119. var length = boundingSpheres.length;
  71120. for (var i = 0; i < length; ++i) {
  71121. var boundingSphere = boundingSpheres[i];
  71122. if (!defined(boundingSphere)) {
  71123. continue;
  71124. }
  71125. var modelMatrix = primitive.modelMatrix;
  71126. if (defined(modelMatrix)) {
  71127. boundingSphere = BoundingSphere.transform(boundingSphere, modelMatrix, boundingSphere);
  71128. }
  71129. if (hasDistanceDisplayCondition) {
  71130. var center = boundingSphere.center;
  71131. var radius = boundingSphere.radius;
  71132. var encodedCenter = EncodedCartesian3.fromCartesian(center, scratchBoundingSphereCenterEncoded);
  71133. batchTable.setBatchedAttribute(i, center3DHighIndex, encodedCenter.high);
  71134. batchTable.setBatchedAttribute(i, center3DLowIndex, encodedCenter.low);
  71135. var cartographic = ellipsoid.cartesianToCartographic(center, scratchBoundingSphereCartographic);
  71136. var center2D = projection.project(cartographic, scratchBoundingSphereCenter2D);
  71137. encodedCenter = EncodedCartesian3.fromCartesian(center2D, scratchBoundingSphereCenterEncoded);
  71138. batchTable.setBatchedAttribute(i, center2DHighIndex, encodedCenter.high);
  71139. batchTable.setBatchedAttribute(i, center2DLowIndex, encodedCenter.low);
  71140. batchTable.setBatchedAttribute(i, radiusIndex, radius);
  71141. }
  71142. }
  71143. primitive._batchTableBoundingSpheresUpdated = true;
  71144. }
  71145. function createVertexArray(primitive, frameState) {
  71146. var attributeLocations = primitive._attributeLocations;
  71147. var geometries = primitive._geometries;
  71148. var scene3DOnly = frameState.scene3DOnly;
  71149. var context = frameState.context;
  71150. var va = [];
  71151. var length = geometries.length;
  71152. for (var i = 0; i < length; ++i) {
  71153. var geometry = geometries[i];
  71154. va.push(VertexArray.fromGeometry({
  71155. context : context,
  71156. geometry : geometry,
  71157. attributeLocations : attributeLocations,
  71158. bufferUsage : BufferUsage.STATIC_DRAW,
  71159. interleave : primitive._interleave
  71160. }));
  71161. if (defined(primitive._createBoundingVolumeFunction)) {
  71162. primitive._createBoundingVolumeFunction(frameState, geometry);
  71163. } else {
  71164. primitive._boundingSpheres.push(BoundingSphere.clone(geometry.boundingSphere));
  71165. primitive._boundingSphereWC.push(new BoundingSphere());
  71166. if (!scene3DOnly) {
  71167. var center = geometry.boundingSphereCV.center;
  71168. var x = center.x;
  71169. var y = center.y;
  71170. var z = center.z;
  71171. center.x = z;
  71172. center.y = x;
  71173. center.z = y;
  71174. primitive._boundingSphereCV.push(BoundingSphere.clone(geometry.boundingSphereCV));
  71175. primitive._boundingSphere2D.push(new BoundingSphere());
  71176. primitive._boundingSphereMorph.push(new BoundingSphere());
  71177. }
  71178. }
  71179. }
  71180. primitive._va = va;
  71181. primitive._primitiveType = geometries[0].primitiveType;
  71182. if (primitive.releaseGeometryInstances) {
  71183. primitive.geometryInstances = undefined;
  71184. }
  71185. primitive._geometries = undefined;
  71186. setReady(primitive, frameState, PrimitiveState.COMPLETE, undefined);
  71187. }
  71188. function createRenderStates(primitive, context, appearance, twoPasses) {
  71189. var renderState = appearance.getRenderState();
  71190. var rs;
  71191. if (twoPasses) {
  71192. rs = clone(renderState, false);
  71193. rs.cull = {
  71194. enabled : true,
  71195. face : CullFace.BACK
  71196. };
  71197. primitive._frontFaceRS = RenderState.fromCache(rs);
  71198. rs.cull.face = CullFace.FRONT;
  71199. primitive._backFaceRS = RenderState.fromCache(rs);
  71200. } else {
  71201. primitive._frontFaceRS = RenderState.fromCache(renderState);
  71202. primitive._backFaceRS = primitive._frontFaceRS;
  71203. }
  71204. if (primitive.allowPicking) {
  71205. if (twoPasses) {
  71206. rs = clone(renderState, false);
  71207. rs.cull = {
  71208. enabled : false
  71209. };
  71210. primitive._pickRS = RenderState.fromCache(rs);
  71211. } else {
  71212. primitive._pickRS = primitive._frontFaceRS;
  71213. }
  71214. } else {
  71215. rs = clone(renderState, false);
  71216. rs.colorMask = {
  71217. red : false,
  71218. green : false,
  71219. blue : false,
  71220. alpha : false
  71221. };
  71222. if (twoPasses) {
  71223. rs.cull = {
  71224. enabled : false
  71225. };
  71226. primitive._pickRS = RenderState.fromCache(rs);
  71227. } else {
  71228. primitive._pickRS = RenderState.fromCache(rs);
  71229. }
  71230. }
  71231. }
  71232. function createShaderProgram(primitive, frameState, appearance) {
  71233. var context = frameState.context;
  71234. var attributeLocations = primitive._attributeLocations;
  71235. var vs = primitive._batchTable.getVertexShaderCallback()(appearance.vertexShaderSource);
  71236. vs = Primitive._appendShowToShader(primitive, vs);
  71237. vs = Primitive._appendDistanceDisplayConditionToShader(primitive, vs, frameState.scene3DOnly);
  71238. vs = Primitive._updateColorAttribute(primitive, vs);
  71239. vs = modifyForEncodedNormals(primitive, vs);
  71240. vs = Primitive._modifyShaderPosition(primitive, vs, frameState.scene3DOnly);
  71241. var fs = appearance.getFragmentShaderSource();
  71242. // Create pick program
  71243. if (primitive.allowPicking) {
  71244. var vsPick = ShaderSource.createPickVertexShaderSource(vs);
  71245. vsPick = Primitive._updatePickColorAttribute(vsPick);
  71246. primitive._pickSP = ShaderProgram.replaceCache({
  71247. context : context,
  71248. shaderProgram : primitive._pickSP,
  71249. vertexShaderSource : vsPick,
  71250. fragmentShaderSource : ShaderSource.createPickFragmentShaderSource(fs, 'varying'),
  71251. attributeLocations : attributeLocations
  71252. });
  71253. } else {
  71254. primitive._pickSP = ShaderProgram.fromCache({
  71255. context : context,
  71256. vertexShaderSource : vs,
  71257. fragmentShaderSource : fs,
  71258. attributeLocations : attributeLocations
  71259. });
  71260. }
  71261. validateShaderMatching(primitive._pickSP, attributeLocations);
  71262. primitive._sp = ShaderProgram.replaceCache({
  71263. context : context,
  71264. shaderProgram : primitive._sp,
  71265. vertexShaderSource : vs,
  71266. fragmentShaderSource : fs,
  71267. attributeLocations : attributeLocations
  71268. });
  71269. validateShaderMatching(primitive._sp, attributeLocations);
  71270. }
  71271. var modifiedModelViewScratch = new Matrix4();
  71272. var rtcScratch = new Cartesian3();
  71273. function createCommands(primitive, appearance, material, translucent, twoPasses, colorCommands, pickCommands, frameState) {
  71274. // Create uniform map by combining uniforms from the appearance and material if either have uniforms.
  71275. var materialUniformMap = defined(material) ? material._uniforms : undefined;
  71276. var appearanceUniformMap = {};
  71277. var appearanceUniforms = appearance.uniforms;
  71278. if (defined(appearanceUniforms)) {
  71279. // Convert to uniform map of functions for the renderer
  71280. for (var name in appearanceUniforms) {
  71281. if (appearanceUniforms.hasOwnProperty(name)) {
  71282. if (defined(materialUniformMap) && defined(materialUniformMap[name])) {
  71283. // Later, we could rename uniforms behind-the-scenes if needed.
  71284. throw new DeveloperError('Appearance and material have a uniform with the same name: ' + name);
  71285. }
  71286. appearanceUniformMap[name] = getUniformFunction(appearanceUniforms, name);
  71287. }
  71288. }
  71289. }
  71290. var uniforms = combine(appearanceUniformMap, materialUniformMap);
  71291. uniforms = primitive._batchTable.getUniformMapCallback()(uniforms);
  71292. if (defined(primitive.rtcCenter)) {
  71293. uniforms.u_modifiedModelView = function() {
  71294. var viewMatrix = frameState.context.uniformState.view;
  71295. Matrix4.multiply(viewMatrix, primitive._modelMatrix, modifiedModelViewScratch);
  71296. Matrix4.multiplyByPoint(modifiedModelViewScratch, primitive.rtcCenter, rtcScratch);
  71297. Matrix4.setTranslation(modifiedModelViewScratch, rtcScratch, modifiedModelViewScratch);
  71298. return modifiedModelViewScratch;
  71299. };
  71300. }
  71301. var pass = translucent ? Pass.TRANSLUCENT : Pass.OPAQUE;
  71302. colorCommands.length = primitive._va.length * (twoPasses ? 2 : 1);
  71303. pickCommands.length = primitive._va.length;
  71304. var length = colorCommands.length;
  71305. var m = 0;
  71306. var vaIndex = 0;
  71307. for (var i = 0; i < length; ++i) {
  71308. var colorCommand;
  71309. if (twoPasses) {
  71310. colorCommand = colorCommands[i];
  71311. if (!defined(colorCommand)) {
  71312. colorCommand = colorCommands[i] = new DrawCommand({
  71313. owner : primitive,
  71314. primitiveType : primitive._primitiveType
  71315. });
  71316. }
  71317. colorCommand.vertexArray = primitive._va[vaIndex];
  71318. colorCommand.renderState = primitive._backFaceRS;
  71319. colorCommand.shaderProgram = primitive._sp;
  71320. colorCommand.uniformMap = uniforms;
  71321. colorCommand.pass = pass;
  71322. ++i;
  71323. }
  71324. colorCommand = colorCommands[i];
  71325. if (!defined(colorCommand)) {
  71326. colorCommand = colorCommands[i] = new DrawCommand({
  71327. owner : primitive,
  71328. primitiveType : primitive._primitiveType
  71329. });
  71330. }
  71331. colorCommand.vertexArray = primitive._va[vaIndex];
  71332. colorCommand.renderState = primitive._frontFaceRS;
  71333. colorCommand.shaderProgram = primitive._sp;
  71334. colorCommand.uniformMap = uniforms;
  71335. colorCommand.pass = pass;
  71336. var pickCommand = pickCommands[m];
  71337. if (!defined(pickCommand)) {
  71338. pickCommand = pickCommands[m] = new DrawCommand({
  71339. owner : primitive,
  71340. primitiveType : primitive._primitiveType
  71341. });
  71342. }
  71343. pickCommand.vertexArray = primitive._va[vaIndex];
  71344. pickCommand.renderState = primitive._pickRS;
  71345. pickCommand.shaderProgram = primitive._pickSP;
  71346. pickCommand.uniformMap = uniforms;
  71347. pickCommand.pass = pass;
  71348. ++m;
  71349. ++vaIndex;
  71350. }
  71351. }
  71352. function updateBoundingVolumes(primitive, frameState) {
  71353. // Update bounding volumes for primitives that are sized in pixels.
  71354. // The pixel size in meters varies based on the distance from the camera.
  71355. var pixelSize = primitive.appearance.pixelSize;
  71356. if (defined(pixelSize)) {
  71357. var length = primitive._boundingSpheres.length;
  71358. for (var i = 0; i < length; ++i) {
  71359. var boundingSphere = primitive._boundingSpheres[i];
  71360. var boundingSphereWC = primitive._boundingSphereWC[i];
  71361. var pixelSizeInMeters = frameState.camera.getPixelSize(boundingSphere, frameState.context.drawingBufferWidth, frameState.context.drawingBufferHeight);
  71362. var sizeInMeters = pixelSizeInMeters * pixelSize;
  71363. boundingSphereWC.radius = boundingSphere.radius + sizeInMeters;
  71364. }
  71365. }
  71366. }
  71367. function updateAndQueueCommands(primitive, frameState, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume, twoPasses) {
  71368. if (frameState.mode !== SceneMode.SCENE3D && !Matrix4.equals(modelMatrix, Matrix4.IDENTITY)) {
  71369. throw new DeveloperError('Primitive.modelMatrix is only supported in 3D mode.');
  71370. }
  71371. updateBoundingVolumes(primitive, frameState);
  71372. if (!Matrix4.equals(modelMatrix, primitive._modelMatrix)) {
  71373. Matrix4.clone(modelMatrix, primitive._modelMatrix);
  71374. var length = primitive._boundingSpheres.length;
  71375. for (var i = 0; i < length; ++i) {
  71376. var boundingSphere = primitive._boundingSpheres[i];
  71377. if (defined(boundingSphere)) {
  71378. primitive._boundingSphereWC[i] = BoundingSphere.transform(boundingSphere, modelMatrix, primitive._boundingSphereWC[i]);
  71379. if (!frameState.scene3DOnly) {
  71380. primitive._boundingSphere2D[i] = BoundingSphere.clone(primitive._boundingSphereCV[i], primitive._boundingSphere2D[i]);
  71381. primitive._boundingSphere2D[i].center.x = 0.0;
  71382. primitive._boundingSphereMorph[i] = BoundingSphere.union(primitive._boundingSphereWC[i], primitive._boundingSphereCV[i]);
  71383. }
  71384. }
  71385. }
  71386. }
  71387. var boundingSpheres;
  71388. if (frameState.mode === SceneMode.SCENE3D) {
  71389. boundingSpheres = primitive._boundingSphereWC;
  71390. } else if (frameState.mode === SceneMode.COLUMBUS_VIEW) {
  71391. boundingSpheres = primitive._boundingSphereCV;
  71392. } else if (frameState.mode === SceneMode.SCENE2D && defined(primitive._boundingSphere2D)) {
  71393. boundingSpheres = primitive._boundingSphere2D;
  71394. } else if (defined(primitive._boundingSphereMorph)) {
  71395. boundingSpheres = primitive._boundingSphereMorph;
  71396. }
  71397. var commandList = frameState.commandList;
  71398. var passes = frameState.passes;
  71399. if (passes.render) {
  71400. var castShadows = ShadowMode.castShadows(primitive.shadows);
  71401. var receiveShadows = ShadowMode.receiveShadows(primitive.shadows);
  71402. var colorLength = colorCommands.length;
  71403. for (var j = 0; j < colorLength; ++j) {
  71404. var sphereIndex = twoPasses ? Math.floor(j / 2) : j;
  71405. var colorCommand = colorCommands[j];
  71406. colorCommand.modelMatrix = modelMatrix;
  71407. colorCommand.boundingVolume = boundingSpheres[sphereIndex];
  71408. colorCommand.cull = cull;
  71409. colorCommand.debugShowBoundingVolume = debugShowBoundingVolume;
  71410. colorCommand.castShadows = castShadows;
  71411. colorCommand.receiveShadows = receiveShadows;
  71412. commandList.push(colorCommand);
  71413. }
  71414. }
  71415. if (passes.pick) {
  71416. var pickLength = pickCommands.length;
  71417. for (var k = 0; k < pickLength; ++k) {
  71418. var pickCommand = pickCommands[k];
  71419. pickCommand.modelMatrix = modelMatrix;
  71420. pickCommand.boundingVolume = boundingSpheres[k];
  71421. pickCommand.cull = cull;
  71422. commandList.push(pickCommand);
  71423. }
  71424. }
  71425. }
  71426. /**
  71427. * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
  71428. * get the draw commands needed to render this primitive.
  71429. * <p>
  71430. * Do not call this function directly. This is documented just to
  71431. * list the exceptions that may be propagated when the scene is rendered:
  71432. * </p>
  71433. *
  71434. * @exception {DeveloperError} All instance geometries must have the same primitiveType.
  71435. * @exception {DeveloperError} Appearance and material have a uniform with the same name.
  71436. * @exception {DeveloperError} Primitive.modelMatrix is only supported in 3D mode.
  71437. * @exception {RuntimeError} Vertex texture fetch support is required to render primitives with per-instance attributes. The maximum number of vertex texture image units must be greater than zero.
  71438. */
  71439. Primitive.prototype.update = function(frameState) {
  71440. if (((!defined(this.geometryInstances)) && (this._va.length === 0)) ||
  71441. (defined(this.geometryInstances) && isArray(this.geometryInstances) && this.geometryInstances.length === 0) ||
  71442. (!defined(this.appearance)) ||
  71443. (frameState.mode !== SceneMode.SCENE3D && frameState.scene3DOnly) ||
  71444. (!frameState.passes.render && !frameState.passes.pick)) {
  71445. return;
  71446. }
  71447. if (defined(this._error)) {
  71448. throw this._error;
  71449. }
  71450. if (defined(this.rtcCenter) && !frameState.scene3DOnly) {
  71451. throw new DeveloperError('RTC rendering is only available for 3D only scenes.');
  71452. }
  71453. if (this._state === PrimitiveState.FAILED) {
  71454. return;
  71455. }
  71456. var context = frameState.context;
  71457. if (!defined(this._batchTable)) {
  71458. createBatchTable(this, context);
  71459. }
  71460. if (this._batchTable.attributes.length > 0) {
  71461. if (ContextLimits.maximumVertexTextureImageUnits === 0) {
  71462. throw new RuntimeError('Vertex texture fetch support is required to render primitives with per-instance attributes. The maximum number of vertex texture image units must be greater than zero.');
  71463. }
  71464. this._batchTable.update(frameState);
  71465. }
  71466. if (this._state !== PrimitiveState.COMPLETE && this._state !== PrimitiveState.COMBINED) {
  71467. if (this.asynchronous) {
  71468. loadAsynchronous(this, frameState);
  71469. } else {
  71470. loadSynchronous(this, frameState);
  71471. }
  71472. }
  71473. if (this._state === PrimitiveState.COMBINED) {
  71474. updateBatchTableBoundingSpheres(this, frameState);
  71475. createVertexArray(this, frameState);
  71476. }
  71477. if (!this.show || this._state !== PrimitiveState.COMPLETE) {
  71478. return;
  71479. }
  71480. // Create or recreate render state and shader program if appearance/material changed
  71481. var appearance = this.appearance;
  71482. var material = appearance.material;
  71483. var createRS = false;
  71484. var createSP = false;
  71485. if (this._appearance !== appearance) {
  71486. this._appearance = appearance;
  71487. this._material = material;
  71488. createRS = true;
  71489. createSP = true;
  71490. } else if (this._material !== material ) {
  71491. this._material = material;
  71492. createSP = true;
  71493. }
  71494. var translucent = this._appearance.isTranslucent();
  71495. if (this._translucent !== translucent) {
  71496. this._translucent = translucent;
  71497. createRS = true;
  71498. }
  71499. if (defined(this._material)) {
  71500. this._material.update(context);
  71501. }
  71502. var twoPasses = appearance.closed && translucent;
  71503. if (createRS) {
  71504. var rsFunc = defaultValue(this._createRenderStatesFunction, createRenderStates);
  71505. rsFunc(this, context, appearance, twoPasses);
  71506. }
  71507. if (createSP) {
  71508. var spFunc = defaultValue(this._createShaderProgramFunction, createShaderProgram);
  71509. spFunc(this, frameState, appearance);
  71510. }
  71511. if (createRS || createSP) {
  71512. var commandFunc = defaultValue(this._createCommandsFunction, createCommands);
  71513. commandFunc(this, appearance, material, translucent, twoPasses, this._colorCommands, this._pickCommands, frameState);
  71514. }
  71515. var updateAndQueueCommandsFunc = defaultValue(this._updateAndQueueCommandsFunction, updateAndQueueCommands);
  71516. updateAndQueueCommandsFunc(this, frameState, this._colorCommands, this._pickCommands, this.modelMatrix, this.cull, this.debugShowBoundingVolume, twoPasses);
  71517. };
  71518. function createGetFunction(batchTable, instanceIndex, attributeIndex) {
  71519. return function() {
  71520. var attributeValue = batchTable.getBatchedAttribute(instanceIndex, attributeIndex);
  71521. var attribute = batchTable.attributes[attributeIndex];
  71522. var componentsPerAttribute = attribute.componentsPerAttribute;
  71523. var value = ComponentDatatype.createTypedArray(attribute.componentDatatype, componentsPerAttribute);
  71524. if (defined(attributeValue.constructor.pack)) {
  71525. attributeValue.constructor.pack(attributeValue, value, 0);
  71526. } else {
  71527. value[0] = attributeValue;
  71528. }
  71529. return value;
  71530. };
  71531. }
  71532. function createSetFunction(batchTable, instanceIndex, attributeIndex) {
  71533. return function(value) {
  71534. if (!defined(value) || !defined(value.length) || value.length < 1 || value.length > 4) {
  71535. throw new DeveloperError('value must be and array with length between 1 and 4.');
  71536. }
  71537. var attributeValue = getAttributeValue(value);
  71538. batchTable.setBatchedAttribute(instanceIndex, attributeIndex, attributeValue);
  71539. };
  71540. }
  71541. function createBoundingSphereProperties(primitive, properties, index) {
  71542. properties.boundingSphere = {
  71543. get : function() {
  71544. return primitive._instanceBoundingSpheres[index];
  71545. }
  71546. };
  71547. properties.boundingSphereCV = {
  71548. get : function() {
  71549. return primitive._instanceBoundingSpheresCV[index];
  71550. }
  71551. };
  71552. }
  71553. /**
  71554. * Returns the modifiable per-instance attributes for a {@link GeometryInstance}.
  71555. *
  71556. * @param {Object} id The id of the {@link GeometryInstance}.
  71557. * @returns {Object} The typed array in the attribute's format or undefined if the is no instance with id.
  71558. *
  71559. * @exception {DeveloperError} must call update before calling getGeometryInstanceAttributes.
  71560. *
  71561. * @example
  71562. * var attributes = primitive.getGeometryInstanceAttributes('an id');
  71563. * attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.AQUA);
  71564. * attributes.show = Cesium.ShowGeometryInstanceAttribute.toValue(true);
  71565. * attributes.distanceDisplayCondition = Cesium.DistanceDisplayConditionGeometryInstanceAttribute.toValue(100.0, 10000.0);
  71566. */
  71567. Primitive.prototype.getGeometryInstanceAttributes = function(id) {
  71568. if (!defined(id)) {
  71569. throw new DeveloperError('id is required');
  71570. }
  71571. if (!defined(this._batchTable)) {
  71572. throw new DeveloperError('must call update before calling getGeometryInstanceAttributes');
  71573. }
  71574. var index = -1;
  71575. var lastIndex = this._lastPerInstanceAttributeIndex;
  71576. var ids = this._instanceIds;
  71577. var length = ids.length;
  71578. for (var i = 0; i < length; ++i) {
  71579. var curIndex = (lastIndex + i) % length;
  71580. if (id === ids[curIndex]) {
  71581. index = curIndex;
  71582. break;
  71583. }
  71584. }
  71585. if (index === -1) {
  71586. return undefined;
  71587. }
  71588. var attributes = this._perInstanceAttributeCache[index];
  71589. if (defined(attributes)) {
  71590. return attributes;
  71591. }
  71592. var batchTable = this._batchTable;
  71593. var perInstanceAttributeIndices = this._batchTableAttributeIndices;
  71594. attributes = {};
  71595. var properties = {};
  71596. for (var name in perInstanceAttributeIndices) {
  71597. if (perInstanceAttributeIndices.hasOwnProperty(name)) {
  71598. var attributeIndex = perInstanceAttributeIndices[name];
  71599. properties[name] = {
  71600. get : createGetFunction(batchTable, index, attributeIndex)
  71601. };
  71602. var createSetter = true;
  71603. var readOnlyAttributes = this._readOnlyInstanceAttributes;
  71604. if (createSetter && defined(readOnlyAttributes)) {
  71605. length = readOnlyAttributes.length;
  71606. for (var k = 0; k < length; ++k) {
  71607. if (name === readOnlyAttributes[k]) {
  71608. createSetter = false;
  71609. break;
  71610. }
  71611. }
  71612. }
  71613. if (createSetter) {
  71614. properties[name].set = createSetFunction(batchTable, index, attributeIndex);
  71615. }
  71616. }
  71617. }
  71618. createBoundingSphereProperties(this, properties, index);
  71619. defineProperties(attributes, properties);
  71620. this._lastPerInstanceAttributeIndex = index;
  71621. this._perInstanceAttributeCache[index] = attributes;
  71622. return attributes;
  71623. };
  71624. /**
  71625. * Returns true if this object was destroyed; otherwise, false.
  71626. * <p>
  71627. * If this object was destroyed, it should not be used; calling any function other than
  71628. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  71629. * </p>
  71630. *
  71631. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  71632. *
  71633. * @see Primitive#destroy
  71634. */
  71635. Primitive.prototype.isDestroyed = function() {
  71636. return false;
  71637. };
  71638. /**
  71639. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  71640. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  71641. * <p>
  71642. * Once an object is destroyed, it should not be used; calling any function other than
  71643. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  71644. * assign the return value (<code>undefined</code>) to the object as done in the example.
  71645. * </p>
  71646. *
  71647. * @returns {undefined}
  71648. *
  71649. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  71650. *
  71651. *
  71652. * @example
  71653. * e = e && e.destroy();
  71654. *
  71655. * @see Primitive#isDestroyed
  71656. */
  71657. Primitive.prototype.destroy = function() {
  71658. var length;
  71659. var i;
  71660. this._sp = this._sp && this._sp.destroy();
  71661. this._pickSP = this._pickSP && this._pickSP.destroy();
  71662. var va = this._va;
  71663. length = va.length;
  71664. for (i = 0; i < length; ++i) {
  71665. va[i].destroy();
  71666. }
  71667. this._va = undefined;
  71668. var pickIds = this._pickIds;
  71669. length = pickIds.length;
  71670. for (i = 0; i < length; ++i) {
  71671. pickIds[i].destroy();
  71672. }
  71673. this._pickIds = undefined;
  71674. this._batchTable = this._batchTable && this._batchTable.destroy();
  71675. //These objects may be fairly large and reference other large objects (like Entities)
  71676. //We explicitly set them to undefined here so that the memory can be freed
  71677. //even if a reference to the destroyed Primitive has been kept around.
  71678. this._instanceIds = undefined;
  71679. this._perInstanceAttributeCache = undefined;
  71680. this._attributeLocations = undefined;
  71681. return destroyObject(this);
  71682. };
  71683. function setReady(primitive, frameState, state, error) {
  71684. primitive._error = error;
  71685. primitive._state = state;
  71686. frameState.afterRender.push(function() {
  71687. primitive._ready = primitive._state === PrimitiveState.COMPLETE || primitive._state === PrimitiveState.FAILED;
  71688. if (!defined(error)) {
  71689. primitive._readyPromise.resolve(primitive);
  71690. } else {
  71691. primitive._readyPromise.reject(error);
  71692. }
  71693. });
  71694. }
  71695. return Primitive;
  71696. });
  71697. /*global define*/
  71698. define('DataSources/ColorMaterialProperty',[
  71699. '../Core/Color',
  71700. '../Core/defined',
  71701. '../Core/defineProperties',
  71702. '../Core/Event',
  71703. './createPropertyDescriptor',
  71704. './Property'
  71705. ], function(
  71706. Color,
  71707. defined,
  71708. defineProperties,
  71709. Event,
  71710. createPropertyDescriptor,
  71711. Property) {
  71712. 'use strict';
  71713. /**
  71714. * A {@link MaterialProperty} that maps to solid color {@link Material} uniforms.
  71715. *
  71716. * @param {Property} [color=Color.WHITE] The {@link Color} Property to be used.
  71717. *
  71718. * @alias ColorMaterialProperty
  71719. * @constructor
  71720. */
  71721. function ColorMaterialProperty(color) {
  71722. this._definitionChanged = new Event();
  71723. this._color = undefined;
  71724. this._colorSubscription = undefined;
  71725. this.color = color;
  71726. }
  71727. defineProperties(ColorMaterialProperty.prototype, {
  71728. /**
  71729. * Gets a value indicating if this property is constant. A property is considered
  71730. * constant if getValue always returns the same result for the current definition.
  71731. * @memberof ColorMaterialProperty.prototype
  71732. *
  71733. * @type {Boolean}
  71734. * @readonly
  71735. */
  71736. isConstant : {
  71737. get : function() {
  71738. return Property.isConstant(this._color);
  71739. }
  71740. },
  71741. /**
  71742. * Gets the event that is raised whenever the definition of this property changes.
  71743. * The definition is considered to have changed if a call to getValue would return
  71744. * a different result for the same time.
  71745. * @memberof ColorMaterialProperty.prototype
  71746. *
  71747. * @type {Event}
  71748. * @readonly
  71749. */
  71750. definitionChanged : {
  71751. get : function() {
  71752. return this._definitionChanged;
  71753. }
  71754. },
  71755. /**
  71756. * Gets or sets the {@link Color} {@link Property}.
  71757. * @memberof ColorMaterialProperty.prototype
  71758. * @type {Property}
  71759. * @default Color.WHITE
  71760. */
  71761. color : createPropertyDescriptor('color')
  71762. });
  71763. /**
  71764. * Gets the {@link Material} type at the provided time.
  71765. *
  71766. * @param {JulianDate} time The time for which to retrieve the type.
  71767. * @returns {String} The type of material.
  71768. */
  71769. ColorMaterialProperty.prototype.getType = function(time) {
  71770. return 'Color';
  71771. };
  71772. /**
  71773. * Gets the value of the property at the provided time.
  71774. *
  71775. * @param {JulianDate} time The time for which to retrieve the value.
  71776. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  71777. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  71778. */
  71779. ColorMaterialProperty.prototype.getValue = function(time, result) {
  71780. if (!defined(result)) {
  71781. result = {};
  71782. }
  71783. result.color = Property.getValueOrClonedDefault(this._color, time, Color.WHITE, result.color);
  71784. return result;
  71785. };
  71786. /**
  71787. * Compares this property to the provided property and returns
  71788. * <code>true</code> if they are equal, <code>false</code> otherwise.
  71789. *
  71790. * @param {Property} [other] The other property.
  71791. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  71792. */
  71793. ColorMaterialProperty.prototype.equals = function(other) {
  71794. return this === other || //
  71795. (other instanceof ColorMaterialProperty && //
  71796. Property.equals(this._color, other._color));
  71797. };
  71798. return ColorMaterialProperty;
  71799. });
  71800. /*global define*/
  71801. define('DataSources/dynamicGeometryGetBoundingSphere',[
  71802. '../Core/BoundingSphere',
  71803. '../Core/defaultValue',
  71804. '../Core/defined',
  71805. '../Core/DeveloperError',
  71806. '../Core/Matrix4',
  71807. './BoundingSphereState'
  71808. ], function(
  71809. BoundingSphere,
  71810. defaultValue,
  71811. defined,
  71812. DeveloperError,
  71813. Matrix4,
  71814. BoundingSphereState) {
  71815. 'use strict';
  71816. /**
  71817. * @private
  71818. */
  71819. function dynamicGeometryGetBoundingSphere(entity, primitive, outlinePrimitive, result) {
  71820. if (!defined(entity)) {
  71821. throw new DeveloperError('entity is required.');
  71822. }
  71823. if (!defined(result)) {
  71824. throw new DeveloperError('result is required.');
  71825. }
  71826. var attributes;
  71827. var modelMatrix;
  71828. //Outline and Fill geometries have the same bounding sphere, so just use whichever one is defined and ready
  71829. if (defined(primitive) && primitive.show && primitive.ready) {
  71830. attributes = primitive.getGeometryInstanceAttributes(entity);
  71831. if (defined(attributes) && defined(attributes.boundingSphere)) {
  71832. modelMatrix = defaultValue(primitive.modelMatrix, Matrix4.IDENTITY);
  71833. BoundingSphere.transform(attributes.boundingSphere, modelMatrix, result);
  71834. return BoundingSphereState.DONE;
  71835. }
  71836. }
  71837. if (defined(outlinePrimitive) && outlinePrimitive.show && outlinePrimitive.ready) {
  71838. attributes = outlinePrimitive.getGeometryInstanceAttributes(entity);
  71839. if (defined(attributes) && defined(attributes.boundingSphere)) {
  71840. modelMatrix = defaultValue(outlinePrimitive.modelMatrix, Matrix4.IDENTITY);
  71841. BoundingSphere.transform(attributes.boundingSphere, modelMatrix, result);
  71842. return BoundingSphereState.DONE;
  71843. }
  71844. }
  71845. if ((defined(primitive) && !primitive.ready) || (defined(outlinePrimitive) && !outlinePrimitive.ready)) {
  71846. return BoundingSphereState.PENDING;
  71847. }
  71848. return BoundingSphereState.FAILED;
  71849. }
  71850. return dynamicGeometryGetBoundingSphere;
  71851. });
  71852. /*global define*/
  71853. define('DataSources/MaterialProperty',[
  71854. '../Core/Color',
  71855. '../Core/defined',
  71856. '../Core/defineProperties',
  71857. '../Core/DeveloperError',
  71858. '../Scene/Material'
  71859. ], function(
  71860. Color,
  71861. defined,
  71862. defineProperties,
  71863. DeveloperError,
  71864. Material) {
  71865. 'use strict';
  71866. /**
  71867. * The interface for all {@link Property} objects that represent {@link Material} uniforms.
  71868. * This type defines an interface and cannot be instantiated directly.
  71869. *
  71870. * @alias MaterialProperty
  71871. * @constructor
  71872. *
  71873. * @see ColorMaterialProperty
  71874. * @see CompositeMaterialProperty
  71875. * @see GridMaterialProperty
  71876. * @see ImageMaterialProperty
  71877. * @see PolylineGlowMaterialProperty
  71878. * @see PolylineOutlineMaterialProperty
  71879. * @see StripeMaterialProperty
  71880. */
  71881. function MaterialProperty() {
  71882. DeveloperError.throwInstantiationError();
  71883. }
  71884. defineProperties(MaterialProperty.prototype, {
  71885. /**
  71886. * Gets a value indicating if this property is constant. A property is considered
  71887. * constant if getValue always returns the same result for the current definition.
  71888. * @memberof MaterialProperty.prototype
  71889. *
  71890. * @type {Boolean}
  71891. * @readonly
  71892. */
  71893. isConstant : {
  71894. get : DeveloperError.throwInstantiationError
  71895. },
  71896. /**
  71897. * Gets the event that is raised whenever the definition of this property changes.
  71898. * The definition is considered to have changed if a call to getValue would return
  71899. * a different result for the same time.
  71900. * @memberof MaterialProperty.prototype
  71901. *
  71902. * @type {Event}
  71903. * @readonly
  71904. */
  71905. definitionChanged : {
  71906. get : DeveloperError.throwInstantiationError
  71907. }
  71908. });
  71909. /**
  71910. * Gets the {@link Material} type at the provided time.
  71911. * @function
  71912. *
  71913. * @param {JulianDate} time The time for which to retrieve the type.
  71914. * @returns {String} The type of material.
  71915. */
  71916. MaterialProperty.prototype.getType = DeveloperError.throwInstantiationError;
  71917. /**
  71918. * Gets the value of the property at the provided time.
  71919. * @function
  71920. *
  71921. * @param {JulianDate} time The time for which to retrieve the value.
  71922. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  71923. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  71924. */
  71925. MaterialProperty.prototype.getValue = DeveloperError.throwInstantiationError;
  71926. /**
  71927. * Compares this property to the provided property and returns
  71928. * <code>true</code> if they are equal, <code>false</code> otherwise.
  71929. * @function
  71930. *
  71931. * @param {Property} [other] The other property.
  71932. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  71933. */
  71934. MaterialProperty.prototype.equals = DeveloperError.throwInstantiationError;
  71935. /**
  71936. * @private
  71937. */
  71938. MaterialProperty.getValue = function(time, materialProperty, material) {
  71939. var type;
  71940. if (defined(materialProperty)) {
  71941. type = materialProperty.getType(time);
  71942. if (defined(type)) {
  71943. if (!defined(material) || (material.type !== type)) {
  71944. material = Material.fromType(type);
  71945. }
  71946. materialProperty.getValue(time, material.uniforms);
  71947. return material;
  71948. }
  71949. }
  71950. if (!defined(material) || (material.type !== Material.ColorType)) {
  71951. material = Material.fromType(Material.ColorType);
  71952. }
  71953. Color.clone(Color.WHITE, material.uniforms.color);
  71954. return material;
  71955. };
  71956. return MaterialProperty;
  71957. });
  71958. /*global define*/
  71959. define('DataSources/BoxGeometryUpdater',[
  71960. '../Core/BoxGeometry',
  71961. '../Core/BoxOutlineGeometry',
  71962. '../Core/Color',
  71963. '../Core/ColorGeometryInstanceAttribute',
  71964. '../Core/defaultValue',
  71965. '../Core/defined',
  71966. '../Core/defineProperties',
  71967. '../Core/destroyObject',
  71968. '../Core/DeveloperError',
  71969. '../Core/DistanceDisplayCondition',
  71970. '../Core/DistanceDisplayConditionGeometryInstanceAttribute',
  71971. '../Core/Event',
  71972. '../Core/GeometryInstance',
  71973. '../Core/Iso8601',
  71974. '../Core/ShowGeometryInstanceAttribute',
  71975. '../Scene/MaterialAppearance',
  71976. '../Scene/PerInstanceColorAppearance',
  71977. '../Scene/Primitive',
  71978. '../Scene/ShadowMode',
  71979. './ColorMaterialProperty',
  71980. './ConstantProperty',
  71981. './dynamicGeometryGetBoundingSphere',
  71982. './MaterialProperty',
  71983. './Property'
  71984. ], function(
  71985. BoxGeometry,
  71986. BoxOutlineGeometry,
  71987. Color,
  71988. ColorGeometryInstanceAttribute,
  71989. defaultValue,
  71990. defined,
  71991. defineProperties,
  71992. destroyObject,
  71993. DeveloperError,
  71994. DistanceDisplayCondition,
  71995. DistanceDisplayConditionGeometryInstanceAttribute,
  71996. Event,
  71997. GeometryInstance,
  71998. Iso8601,
  71999. ShowGeometryInstanceAttribute,
  72000. MaterialAppearance,
  72001. PerInstanceColorAppearance,
  72002. Primitive,
  72003. ShadowMode,
  72004. ColorMaterialProperty,
  72005. ConstantProperty,
  72006. dynamicGeometryGetBoundingSphere,
  72007. MaterialProperty,
  72008. Property) {
  72009. 'use strict';
  72010. var defaultMaterial = new ColorMaterialProperty(Color.WHITE);
  72011. var defaultShow = new ConstantProperty(true);
  72012. var defaultFill = new ConstantProperty(true);
  72013. var defaultOutline = new ConstantProperty(false);
  72014. var defaultOutlineColor = new ConstantProperty(Color.BLACK);
  72015. var defaultShadows = new ConstantProperty(ShadowMode.DISABLED);
  72016. var defaultDistanceDisplayCondition = new ConstantProperty(new DistanceDisplayCondition());
  72017. var scratchColor = new Color();
  72018. function GeometryOptions(entity) {
  72019. this.id = entity;
  72020. this.vertexFormat = undefined;
  72021. this.dimensions = undefined;
  72022. }
  72023. /**
  72024. * A {@link GeometryUpdater} for boxes.
  72025. * Clients do not normally create this class directly, but instead rely on {@link DataSourceDisplay}.
  72026. * @alias BoxGeometryUpdater
  72027. * @constructor
  72028. *
  72029. * @param {Entity} entity The entity containing the geometry to be visualized.
  72030. * @param {Scene} scene The scene where visualization is taking place.
  72031. */
  72032. function BoxGeometryUpdater(entity, scene) {
  72033. if (!defined(entity)) {
  72034. throw new DeveloperError('entity is required');
  72035. }
  72036. if (!defined(scene)) {
  72037. throw new DeveloperError('scene is required');
  72038. }
  72039. this._entity = entity;
  72040. this._scene = scene;
  72041. this._entitySubscription = entity.definitionChanged.addEventListener(BoxGeometryUpdater.prototype._onEntityPropertyChanged, this);
  72042. this._fillEnabled = false;
  72043. this._dynamic = false;
  72044. this._outlineEnabled = false;
  72045. this._geometryChanged = new Event();
  72046. this._showProperty = undefined;
  72047. this._materialProperty = undefined;
  72048. this._hasConstantOutline = true;
  72049. this._showOutlineProperty = undefined;
  72050. this._outlineColorProperty = undefined;
  72051. this._outlineWidth = 1.0;
  72052. this._shadowsProperty = undefined;
  72053. this._distanceDisplayConditionProperty = undefined;
  72054. this._options = new GeometryOptions(entity);
  72055. this._onEntityPropertyChanged(entity, 'box', entity.box, undefined);
  72056. }
  72057. defineProperties(BoxGeometryUpdater, {
  72058. /**
  72059. * Gets the type of Appearance to use for simple color-based geometry.
  72060. * @memberof BoxGeometryUpdater
  72061. * @type {Appearance}
  72062. */
  72063. perInstanceColorAppearanceType : {
  72064. value : PerInstanceColorAppearance
  72065. },
  72066. /**
  72067. * Gets the type of Appearance to use for material-based geometry.
  72068. * @memberof BoxGeometryUpdater
  72069. * @type {Appearance}
  72070. */
  72071. materialAppearanceType : {
  72072. value : MaterialAppearance
  72073. }
  72074. });
  72075. defineProperties(BoxGeometryUpdater.prototype, {
  72076. /**
  72077. * Gets the entity associated with this geometry.
  72078. * @memberof BoxGeometryUpdater.prototype
  72079. *
  72080. * @type {Entity}
  72081. * @readonly
  72082. */
  72083. entity : {
  72084. get : function() {
  72085. return this._entity;
  72086. }
  72087. },
  72088. /**
  72089. * Gets a value indicating if the geometry has a fill component.
  72090. * @memberof BoxGeometryUpdater.prototype
  72091. *
  72092. * @type {Boolean}
  72093. * @readonly
  72094. */
  72095. fillEnabled : {
  72096. get : function() {
  72097. return this._fillEnabled;
  72098. }
  72099. },
  72100. /**
  72101. * Gets a value indicating if fill visibility varies with simulation time.
  72102. * @memberof BoxGeometryUpdater.prototype
  72103. *
  72104. * @type {Boolean}
  72105. * @readonly
  72106. */
  72107. hasConstantFill : {
  72108. get : function() {
  72109. return !this._fillEnabled ||
  72110. (!defined(this._entity.availability) &&
  72111. Property.isConstant(this._showProperty) &&
  72112. Property.isConstant(this._fillProperty));
  72113. }
  72114. },
  72115. /**
  72116. * Gets the material property used to fill the geometry.
  72117. * @memberof BoxGeometryUpdater.prototype
  72118. *
  72119. * @type {MaterialProperty}
  72120. * @readonly
  72121. */
  72122. fillMaterialProperty : {
  72123. get : function() {
  72124. return this._materialProperty;
  72125. }
  72126. },
  72127. /**
  72128. * Gets a value indicating if the geometry has an outline component.
  72129. * @memberof BoxGeometryUpdater.prototype
  72130. *
  72131. * @type {Boolean}
  72132. * @readonly
  72133. */
  72134. outlineEnabled : {
  72135. get : function() {
  72136. return this._outlineEnabled;
  72137. }
  72138. },
  72139. /**
  72140. * Gets a value indicating if the geometry has an outline component.
  72141. * @memberof BoxGeometryUpdater.prototype
  72142. *
  72143. * @type {Boolean}
  72144. * @readonly
  72145. */
  72146. hasConstantOutline : {
  72147. get : function() {
  72148. return !this._outlineEnabled ||
  72149. (!defined(this._entity.availability) &&
  72150. Property.isConstant(this._showProperty) &&
  72151. Property.isConstant(this._showOutlineProperty));
  72152. }
  72153. },
  72154. /**
  72155. * Gets the {@link Color} property for the geometry outline.
  72156. * @memberof BoxGeometryUpdater.prototype
  72157. *
  72158. * @type {Property}
  72159. * @readonly
  72160. */
  72161. outlineColorProperty : {
  72162. get : function() {
  72163. return this._outlineColorProperty;
  72164. }
  72165. },
  72166. /**
  72167. * Gets the constant with of the geometry outline, in pixels.
  72168. * This value is only valid if isDynamic is false.
  72169. * @memberof BoxGeometryUpdater.prototype
  72170. *
  72171. * @type {Number}
  72172. * @readonly
  72173. */
  72174. outlineWidth : {
  72175. get : function() {
  72176. return this._outlineWidth;
  72177. }
  72178. },
  72179. /**
  72180. * Gets the property specifying whether the geometry
  72181. * casts or receives shadows from each light source.
  72182. * @memberof BoxGeometryUpdater.prototype
  72183. *
  72184. * @type {Property}
  72185. * @readonly
  72186. */
  72187. shadowsProperty : {
  72188. get : function() {
  72189. return this._shadowsProperty;
  72190. }
  72191. },
  72192. /**
  72193. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this geometry will be displayed.
  72194. * @memberof BoxGeometryUpdater.prototype
  72195. *
  72196. * @type {Property}
  72197. * @readonly
  72198. */
  72199. distanceDisplayConditionProperty : {
  72200. get : function() {
  72201. return this._distanceDisplayConditionProperty;
  72202. }
  72203. },
  72204. /**
  72205. * Gets a value indicating if the geometry is time-varying.
  72206. * If true, all visualization is delegated to the {@link DynamicGeometryUpdater}
  72207. * returned by GeometryUpdater#createDynamicUpdater.
  72208. * @memberof BoxGeometryUpdater.prototype
  72209. *
  72210. * @type {Boolean}
  72211. * @readonly
  72212. */
  72213. isDynamic : {
  72214. get : function() {
  72215. return this._dynamic;
  72216. }
  72217. },
  72218. /**
  72219. * Gets a value indicating if the geometry is closed.
  72220. * This property is only valid for static geometry.
  72221. * @memberof BoxGeometryUpdater.prototype
  72222. *
  72223. * @type {Boolean}
  72224. * @readonly
  72225. */
  72226. isClosed : {
  72227. value : true
  72228. },
  72229. /**
  72230. * Gets an event that is raised whenever the public properties
  72231. * of this updater change.
  72232. * @memberof BoxGeometryUpdater.prototype
  72233. *
  72234. * @type {Boolean}
  72235. * @readonly
  72236. */
  72237. geometryChanged : {
  72238. get : function() {
  72239. return this._geometryChanged;
  72240. }
  72241. }
  72242. });
  72243. /**
  72244. * Checks if the geometry is outlined at the provided time.
  72245. *
  72246. * @param {JulianDate} time The time for which to retrieve visibility.
  72247. * @returns {Boolean} true if geometry is outlined at the provided time, false otherwise.
  72248. */
  72249. BoxGeometryUpdater.prototype.isOutlineVisible = function(time) {
  72250. var entity = this._entity;
  72251. return this._outlineEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time);
  72252. };
  72253. /**
  72254. * Checks if the geometry is filled at the provided time.
  72255. *
  72256. * @param {JulianDate} time The time for which to retrieve visibility.
  72257. * @returns {Boolean} true if geometry is filled at the provided time, false otherwise.
  72258. */
  72259. BoxGeometryUpdater.prototype.isFilled = function(time) {
  72260. var entity = this._entity;
  72261. return this._fillEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._fillProperty.getValue(time);
  72262. };
  72263. /**
  72264. * Creates the geometry instance which represents the fill of the geometry.
  72265. *
  72266. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  72267. * @returns {GeometryInstance} The geometry instance representing the filled portion of the geometry.
  72268. *
  72269. * @exception {DeveloperError} This instance does not represent a filled geometry.
  72270. */
  72271. BoxGeometryUpdater.prototype.createFillGeometryInstance = function(time) {
  72272. if (!defined(time)) {
  72273. throw new DeveloperError('time is required.');
  72274. }
  72275. if (!this._fillEnabled) {
  72276. throw new DeveloperError('This instance does not represent a filled geometry.');
  72277. }
  72278. var entity = this._entity;
  72279. var isAvailable = entity.isAvailable(time);
  72280. var attributes;
  72281. var color;
  72282. var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time));
  72283. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  72284. var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
  72285. if (this._materialProperty instanceof ColorMaterialProperty) {
  72286. var currentColor = Color.WHITE;
  72287. if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) {
  72288. currentColor = this._materialProperty.color.getValue(time);
  72289. }
  72290. color = ColorGeometryInstanceAttribute.fromColor(currentColor);
  72291. attributes = {
  72292. show : show,
  72293. distanceDisplayCondition : distanceDisplayConditionAttribute,
  72294. color : color
  72295. };
  72296. } else {
  72297. attributes = {
  72298. show : show,
  72299. distanceDisplayCondition : distanceDisplayConditionAttribute
  72300. };
  72301. }
  72302. return new GeometryInstance({
  72303. id : entity,
  72304. geometry : BoxGeometry.fromDimensions(this._options),
  72305. modelMatrix : entity._getModelMatrix(Iso8601.MINIMUM_VALUE),
  72306. attributes : attributes
  72307. });
  72308. };
  72309. /**
  72310. * Creates the geometry instance which represents the outline of the geometry.
  72311. *
  72312. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  72313. * @returns {GeometryInstance} The geometry instance representing the outline portion of the geometry.
  72314. *
  72315. * @exception {DeveloperError} This instance does not represent an outlined geometry.
  72316. */
  72317. BoxGeometryUpdater.prototype.createOutlineGeometryInstance = function(time) {
  72318. if (!defined(time)) {
  72319. throw new DeveloperError('time is required.');
  72320. }
  72321. if (!this._outlineEnabled) {
  72322. throw new DeveloperError('This instance does not represent an outlined geometry.');
  72323. }
  72324. var entity = this._entity;
  72325. var isAvailable = entity.isAvailable(time);
  72326. var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK);
  72327. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  72328. return new GeometryInstance({
  72329. id : entity,
  72330. geometry : BoxOutlineGeometry.fromDimensions(this._options),
  72331. modelMatrix : entity._getModelMatrix(Iso8601.MINIMUM_VALUE),
  72332. attributes : {
  72333. show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
  72334. color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
  72335. distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition)
  72336. }
  72337. });
  72338. };
  72339. /**
  72340. * Returns true if this object was destroyed; otherwise, false.
  72341. *
  72342. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  72343. */
  72344. BoxGeometryUpdater.prototype.isDestroyed = function() {
  72345. return false;
  72346. };
  72347. /**
  72348. * Destroys and resources used by the object. Once an object is destroyed, it should not be used.
  72349. *
  72350. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  72351. */
  72352. BoxGeometryUpdater.prototype.destroy = function() {
  72353. this._entitySubscription();
  72354. destroyObject(this);
  72355. };
  72356. BoxGeometryUpdater.prototype._onEntityPropertyChanged = function(entity, propertyName, newValue, oldValue) {
  72357. if (!(propertyName === 'availability' || propertyName === 'position' || propertyName === 'orientation' || propertyName === 'box')) {
  72358. return;
  72359. }
  72360. var box = this._entity.box;
  72361. if (!defined(box)) {
  72362. if (this._fillEnabled || this._outlineEnabled) {
  72363. this._fillEnabled = false;
  72364. this._outlineEnabled = false;
  72365. this._geometryChanged.raiseEvent(this);
  72366. }
  72367. return;
  72368. }
  72369. var fillProperty = box.fill;
  72370. var fillEnabled = defined(fillProperty) && fillProperty.isConstant ? fillProperty.getValue(Iso8601.MINIMUM_VALUE) : true;
  72371. var outlineProperty = box.outline;
  72372. var outlineEnabled = defined(outlineProperty);
  72373. if (outlineEnabled && outlineProperty.isConstant) {
  72374. outlineEnabled = outlineProperty.getValue(Iso8601.MINIMUM_VALUE);
  72375. }
  72376. if (!fillEnabled && !outlineEnabled) {
  72377. if (this._fillEnabled || this._outlineEnabled) {
  72378. this._fillEnabled = false;
  72379. this._outlineEnabled = false;
  72380. this._geometryChanged.raiseEvent(this);
  72381. }
  72382. return;
  72383. }
  72384. var dimensions = box.dimensions;
  72385. var position = entity.position;
  72386. var show = box.show;
  72387. if (!defined(dimensions) || !defined(position) || (defined(show) && show.isConstant && !show.getValue(Iso8601.MINIMUM_VALUE))) {
  72388. if (this._fillEnabled || this._outlineEnabled) {
  72389. this._fillEnabled = false;
  72390. this._outlineEnabled = false;
  72391. this._geometryChanged.raiseEvent(this);
  72392. }
  72393. return;
  72394. }
  72395. var material = defaultValue(box.material, defaultMaterial);
  72396. var isColorMaterial = material instanceof ColorMaterialProperty;
  72397. this._materialProperty = material;
  72398. this._fillProperty = defaultValue(fillProperty, defaultFill);
  72399. this._showProperty = defaultValue(show, defaultShow);
  72400. this._showOutlineProperty = defaultValue(box.outline, defaultOutline);
  72401. this._outlineColorProperty = outlineEnabled ? defaultValue(box.outlineColor, defaultOutlineColor) : undefined;
  72402. this._shadowsProperty = defaultValue(box.shadows, defaultShadows);
  72403. this._distanceDisplayConditionProperty = defaultValue(box.distanceDisplayCondition, defaultDistanceDisplayCondition);
  72404. var outlineWidth = box.outlineWidth;
  72405. this._fillEnabled = fillEnabled;
  72406. this._outlineEnabled = outlineEnabled;
  72407. if (!position.isConstant || //
  72408. !Property.isConstant(entity.orientation) || //
  72409. !dimensions.isConstant || //
  72410. !Property.isConstant(outlineWidth)) {
  72411. if (!this._dynamic) {
  72412. this._dynamic = true;
  72413. this._geometryChanged.raiseEvent(this);
  72414. }
  72415. } else {
  72416. var options = this._options;
  72417. options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat;
  72418. options.dimensions = dimensions.getValue(Iso8601.MINIMUM_VALUE, options.dimensions);
  72419. this._outlineWidth = defined(outlineWidth) ? outlineWidth.getValue(Iso8601.MINIMUM_VALUE) : 1.0;
  72420. this._dynamic = false;
  72421. this._geometryChanged.raiseEvent(this);
  72422. }
  72423. };
  72424. /**
  72425. * Creates the dynamic updater to be used when GeometryUpdater#isDynamic is true.
  72426. *
  72427. * @param {PrimitiveCollection} primitives The primitive collection to use.
  72428. * @returns {DynamicGeometryUpdater} The dynamic updater used to update the geometry each frame.
  72429. *
  72430. * @exception {DeveloperError} This instance does not represent dynamic geometry.
  72431. */
  72432. BoxGeometryUpdater.prototype.createDynamicUpdater = function(primitives) {
  72433. if (!this._dynamic) {
  72434. throw new DeveloperError('This instance does not represent dynamic geometry.');
  72435. }
  72436. if (!defined(primitives)) {
  72437. throw new DeveloperError('primitives is required.');
  72438. }
  72439. return new DynamicGeometryUpdater(primitives, this);
  72440. };
  72441. /**
  72442. * @private
  72443. */
  72444. function DynamicGeometryUpdater(primitives, geometryUpdater) {
  72445. this._primitives = primitives;
  72446. this._primitive = undefined;
  72447. this._outlinePrimitive = undefined;
  72448. this._geometryUpdater = geometryUpdater;
  72449. this._options = new GeometryOptions(geometryUpdater._entity);
  72450. }
  72451. DynamicGeometryUpdater.prototype.update = function(time) {
  72452. if (!defined(time)) {
  72453. throw new DeveloperError('time is required.');
  72454. }
  72455. var primitives = this._primitives;
  72456. primitives.removeAndDestroy(this._primitive);
  72457. primitives.removeAndDestroy(this._outlinePrimitive);
  72458. this._primitive = undefined;
  72459. this._outlinePrimitive = undefined;
  72460. var geometryUpdater = this._geometryUpdater;
  72461. var entity = geometryUpdater._entity;
  72462. var box = entity.box;
  72463. if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(box.show, time, true)) {
  72464. return;
  72465. }
  72466. var options = this._options;
  72467. var modelMatrix = entity._getModelMatrix(time);
  72468. var dimensions = Property.getValueOrUndefined(box.dimensions, time, options.dimensions);
  72469. if (!defined(modelMatrix) || !defined(dimensions)) {
  72470. return;
  72471. }
  72472. options.dimensions = dimensions;
  72473. var shadows = this._geometryUpdater.shadowsProperty.getValue(time);
  72474. var distanceDisplayConditionProperty = this._geometryUpdater.distanceDisplayConditionProperty;
  72475. var distanceDisplayCondition = distanceDisplayConditionProperty.getValue(time);
  72476. var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
  72477. if (Property.getValueOrDefault(box.fill, time, true)) {
  72478. var material = MaterialProperty.getValue(time, geometryUpdater.fillMaterialProperty, this._material);
  72479. this._material = material;
  72480. var appearance = new MaterialAppearance({
  72481. material : material,
  72482. translucent : material.isTranslucent(),
  72483. closed : true
  72484. });
  72485. options.vertexFormat = appearance.vertexFormat;
  72486. this._primitive = primitives.add(new Primitive({
  72487. geometryInstances : new GeometryInstance({
  72488. id : entity,
  72489. geometry : BoxGeometry.fromDimensions(options),
  72490. modelMatrix : modelMatrix,
  72491. attributes : {
  72492. distanceDisplayCondition : distanceDisplayConditionAttribute
  72493. }
  72494. }),
  72495. appearance : appearance,
  72496. asynchronous : false,
  72497. shadows : shadows
  72498. }));
  72499. }
  72500. if (Property.getValueOrDefault(box.outline, time, false)) {
  72501. options.vertexFormat = PerInstanceColorAppearance.VERTEX_FORMAT;
  72502. var outlineColor = Property.getValueOrClonedDefault(box.outlineColor, time, Color.BLACK, scratchColor);
  72503. var outlineWidth = Property.getValueOrDefault(box.outlineWidth, time, 1.0);
  72504. var translucent = outlineColor.alpha !== 1.0;
  72505. this._outlinePrimitive = primitives.add(new Primitive({
  72506. geometryInstances : new GeometryInstance({
  72507. id : entity,
  72508. geometry : BoxOutlineGeometry.fromDimensions(options),
  72509. modelMatrix : modelMatrix,
  72510. attributes : {
  72511. color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
  72512. distanceDisplayCondition : distanceDisplayConditionAttribute
  72513. }
  72514. }),
  72515. appearance : new PerInstanceColorAppearance({
  72516. flat : true,
  72517. translucent : translucent,
  72518. renderState : {
  72519. lineWidth : geometryUpdater._scene.clampLineWidth(outlineWidth)
  72520. }
  72521. }),
  72522. asynchronous : false,
  72523. shadows : shadows
  72524. }));
  72525. }
  72526. };
  72527. DynamicGeometryUpdater.prototype.getBoundingSphere = function(entity, result) {
  72528. return dynamicGeometryGetBoundingSphere(entity, this._primitive, this._outlinePrimitive, result);
  72529. };
  72530. DynamicGeometryUpdater.prototype.isDestroyed = function() {
  72531. return false;
  72532. };
  72533. DynamicGeometryUpdater.prototype.destroy = function() {
  72534. var primitives = this._primitives;
  72535. primitives.removeAndDestroy(this._primitive);
  72536. primitives.removeAndDestroy(this._outlinePrimitive);
  72537. destroyObject(this);
  72538. };
  72539. return BoxGeometryUpdater;
  72540. });
  72541. /*global define*/
  72542. define('DataSources/ImageMaterialProperty',[
  72543. '../Core/Cartesian2',
  72544. '../Core/Color',
  72545. '../Core/defaultValue',
  72546. '../Core/defined',
  72547. '../Core/defineProperties',
  72548. '../Core/Event',
  72549. './createPropertyDescriptor',
  72550. './Property'
  72551. ], function(
  72552. Cartesian2,
  72553. Color,
  72554. defaultValue,
  72555. defined,
  72556. defineProperties,
  72557. Event,
  72558. createPropertyDescriptor,
  72559. Property) {
  72560. 'use strict';
  72561. var defaultRepeat = new Cartesian2(1, 1);
  72562. var defaultTransparent = false;
  72563. var defaultColor = Color.WHITE;
  72564. /**
  72565. * A {@link MaterialProperty} that maps to image {@link Material} uniforms.
  72566. * @alias ImageMaterialProperty
  72567. * @constructor
  72568. *
  72569. * @param {Object} [options] Object with the following properties:
  72570. * @param {Property} [options.image] A Property specifying the Image, URL, Canvas, or Video.
  72571. * @param {Property} [options.repeat=new Cartesian2(1.0, 1.0)] A {@link Cartesian2} Property specifying the number of times the image repeats in each direction.
  72572. * @param {Property} [options.color=Color.WHITE] The color applied to the image
  72573. * @param {Property} [options.transparent=false] Set to true when the image has transparency (for example, when a png has transparent sections)
  72574. */
  72575. function ImageMaterialProperty(options) {
  72576. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  72577. this._definitionChanged = new Event();
  72578. this._image = undefined;
  72579. this._imageSubscription = undefined;
  72580. this._repeat = undefined;
  72581. this._repeatSubscription = undefined;
  72582. this._color = undefined;
  72583. this._colorSubscription = undefined;
  72584. this._transparent = undefined;
  72585. this._transparentSubscription = undefined;
  72586. this.image = options.image;
  72587. this.repeat = options.repeat;
  72588. this.color = options.color;
  72589. this.transparent = options.transparent;
  72590. }
  72591. defineProperties(ImageMaterialProperty.prototype, {
  72592. /**
  72593. * Gets a value indicating if this property is constant. A property is considered
  72594. * constant if getValue always returns the same result for the current definition.
  72595. * @memberof ImageMaterialProperty.prototype
  72596. *
  72597. * @type {Boolean}
  72598. * @readonly
  72599. */
  72600. isConstant : {
  72601. get : function() {
  72602. return Property.isConstant(this._image) && Property.isConstant(this._repeat);
  72603. }
  72604. },
  72605. /**
  72606. * Gets the event that is raised whenever the definition of this property changes.
  72607. * The definition is considered to have changed if a call to getValue would return
  72608. * a different result for the same time.
  72609. * @memberof ImageMaterialProperty.prototype
  72610. *
  72611. * @type {Event}
  72612. * @readonly
  72613. */
  72614. definitionChanged : {
  72615. get : function() {
  72616. return this._definitionChanged;
  72617. }
  72618. },
  72619. /**
  72620. * Gets or sets the Property specifying Image, URL, Canvas, or Video to use.
  72621. * @memberof ImageMaterialProperty.prototype
  72622. * @type {Property}
  72623. */
  72624. image : createPropertyDescriptor('image'),
  72625. /**
  72626. * Gets or sets the {@link Cartesian2} Property specifying the number of times the image repeats in each direction.
  72627. * @memberof ImageMaterialProperty.prototype
  72628. * @type {Property}
  72629. * @default new Cartesian2(1, 1)
  72630. */
  72631. repeat : createPropertyDescriptor('repeat'),
  72632. /**
  72633. * Gets or sets the Color Property specifying the desired color applied to the image.
  72634. * @memberof ImageMaterialProperty.prototype
  72635. * @type {Property}
  72636. * @default 1.0
  72637. */
  72638. color : createPropertyDescriptor('color'),
  72639. /**
  72640. * Gets or sets the Boolean Property specifying whether the image has transparency
  72641. * @memberof ImageMaterialProperty.prototype
  72642. * @type {Property}
  72643. * @default 1.0
  72644. */
  72645. transparent : createPropertyDescriptor('transparent')
  72646. });
  72647. /**
  72648. * Gets the {@link Material} type at the provided time.
  72649. *
  72650. * @param {JulianDate} time The time for which to retrieve the type.
  72651. * @returns {String} The type of material.
  72652. */
  72653. ImageMaterialProperty.prototype.getType = function(time) {
  72654. return 'Image';
  72655. };
  72656. /**
  72657. * Gets the value of the property at the provided time.
  72658. *
  72659. * @param {JulianDate} time The time for which to retrieve the value.
  72660. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  72661. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  72662. */
  72663. ImageMaterialProperty.prototype.getValue = function(time, result) {
  72664. if (!defined(result)) {
  72665. result = {};
  72666. }
  72667. result.image = Property.getValueOrUndefined(this._image, time);
  72668. result.repeat = Property.getValueOrClonedDefault(this._repeat, time, defaultRepeat, result.repeat);
  72669. result.color = Property.getValueOrClonedDefault(this._color, time, defaultColor, result.color);
  72670. if (Property.getValueOrDefault(this._transparent, time, defaultTransparent)) {
  72671. result.color.alpha = Math.min(0.99, result.color.alpha);
  72672. }
  72673. return result;
  72674. };
  72675. /**
  72676. * Compares this property to the provided property and returns
  72677. * <code>true</code> if they are equal, <code>false</code> otherwise.
  72678. *
  72679. * @param {Property} [other] The other property.
  72680. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  72681. */
  72682. ImageMaterialProperty.prototype.equals = function(other) {
  72683. return this === other ||
  72684. (other instanceof ImageMaterialProperty &&
  72685. Property.equals(this._image, other._image) &&
  72686. Property.equals(this._color, other._color) &&
  72687. Property.equals(this._transparent, other._transparent) &&
  72688. Property.equals(this._repeat, other._repeat));
  72689. };
  72690. return ImageMaterialProperty;
  72691. });
  72692. /*global define*/
  72693. define('DataSources/createMaterialPropertyDescriptor',[
  72694. '../Core/Color',
  72695. '../Core/DeveloperError',
  72696. './ColorMaterialProperty',
  72697. './createPropertyDescriptor',
  72698. './ImageMaterialProperty'
  72699. ], function(
  72700. Color,
  72701. DeveloperError,
  72702. ColorMaterialProperty,
  72703. createPropertyDescriptor,
  72704. ImageMaterialProperty) {
  72705. 'use strict';
  72706. function createMaterialProperty(value) {
  72707. if (value instanceof Color) {
  72708. return new ColorMaterialProperty(value);
  72709. }
  72710. if (typeof value === 'string' || value instanceof HTMLCanvasElement || value instanceof HTMLVideoElement) {
  72711. var result = new ImageMaterialProperty();
  72712. result.image = value;
  72713. return result;
  72714. }
  72715. throw new DeveloperError('Unable to infer material type: ' + value);
  72716. }
  72717. /**
  72718. * @private
  72719. */
  72720. function createMaterialPropertyDescriptor(name, configurable) {
  72721. return createPropertyDescriptor(name, configurable, createMaterialProperty);
  72722. }
  72723. return createMaterialPropertyDescriptor;
  72724. });
  72725. /*global define*/
  72726. define('DataSources/BoxGraphics',[
  72727. '../Core/defaultValue',
  72728. '../Core/defined',
  72729. '../Core/defineProperties',
  72730. '../Core/DeveloperError',
  72731. '../Core/Event',
  72732. './createMaterialPropertyDescriptor',
  72733. './createPropertyDescriptor'
  72734. ], function(
  72735. defaultValue,
  72736. defined,
  72737. defineProperties,
  72738. DeveloperError,
  72739. Event,
  72740. createMaterialPropertyDescriptor,
  72741. createPropertyDescriptor) {
  72742. 'use strict';
  72743. /**
  72744. * Describes a box. The center position and orientation are determined by the containing {@link Entity}.
  72745. *
  72746. * @alias BoxGraphics
  72747. * @constructor
  72748. *
  72749. * @param {Object} [options] Object with the following properties:
  72750. * @param {Property} [options.dimensions] A {@link Cartesian3} Property specifying the length, width, and height of the box.
  72751. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the box.
  72752. * @param {Property} [options.fill=true] A boolean Property specifying whether the box is filled with the provided material.
  72753. * @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to fill the box.
  72754. * @param {Property} [options.outline=false] A boolean Property specifying whether the box is outlined.
  72755. * @param {Property} [options.outlineColor=Color.BLACK] A Property specifying the {@link Color} of the outline.
  72756. * @param {Property} [options.outlineWidth=1.0] A numeric Property specifying the width of the outline.
  72757. * @param {Property} [options.shadows=ShadowMode.DISABLED] An enum Property specifying whether the box casts or receives shadows from each light source.
  72758. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this box will be displayed.
  72759. *
  72760. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Box.html|Cesium Sandcastle Box Demo}
  72761. */
  72762. function BoxGraphics(options) {
  72763. this._dimensions = undefined;
  72764. this._dimensionsSubscription = undefined;
  72765. this._show = undefined;
  72766. this._showSubscription = undefined;
  72767. this._fill = undefined;
  72768. this._fillSubscription = undefined;
  72769. this._material = undefined;
  72770. this._materialSubscription = undefined;
  72771. this._outline = undefined;
  72772. this._outlineSubscription = undefined;
  72773. this._outlineColor = undefined;
  72774. this._outlineColorSubscription = undefined;
  72775. this._outlineWidth = undefined;
  72776. this._outlineWidthSubscription = undefined;
  72777. this._shadows = undefined;
  72778. this._shadowsSubscription = undefined;
  72779. this._distanceDisplayCondition = undefined;
  72780. this._distanceDisplayConditionSubscription = undefined;
  72781. this._definitionChanged = new Event();
  72782. this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
  72783. }
  72784. defineProperties(BoxGraphics.prototype, {
  72785. /**
  72786. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  72787. * @memberof BoxGraphics.prototype
  72788. * @type {Event}
  72789. * @readonly
  72790. */
  72791. definitionChanged : {
  72792. get : function() {
  72793. return this._definitionChanged;
  72794. }
  72795. },
  72796. /**
  72797. * Gets or sets the boolean Property specifying the visibility of the box.
  72798. * @memberof BoxGraphics.prototype
  72799. * @type {Property}
  72800. * @default true
  72801. */
  72802. show : createPropertyDescriptor('show'),
  72803. /**
  72804. * Gets or sets {@link Cartesian3} Property property specifying the length, width, and height of the box.
  72805. * @memberof BoxGraphics.prototype
  72806. * @type {Property}
  72807. */
  72808. dimensions : createPropertyDescriptor('dimensions'),
  72809. /**
  72810. * Gets or sets the material used to fill the box.
  72811. * @memberof BoxGraphics.prototype
  72812. * @type {MaterialProperty}
  72813. * @default Color.WHITE
  72814. */
  72815. material : createMaterialPropertyDescriptor('material'),
  72816. /**
  72817. * Gets or sets the boolean Property specifying whether the box is filled with the provided material.
  72818. * @memberof BoxGraphics.prototype
  72819. * @type {Property}
  72820. * @default true
  72821. */
  72822. fill : createPropertyDescriptor('fill'),
  72823. /**
  72824. * Gets or sets the Property specifying whether the box is outlined.
  72825. * @memberof BoxGraphics.prototype
  72826. * @type {Property}
  72827. * @default false
  72828. */
  72829. outline : createPropertyDescriptor('outline'),
  72830. /**
  72831. * Gets or sets the Property specifying the {@link Color} of the outline.
  72832. * @memberof BoxGraphics.prototype
  72833. * @type {Property}
  72834. * @default Color.BLACK
  72835. */
  72836. outlineColor : createPropertyDescriptor('outlineColor'),
  72837. /**
  72838. * Gets or sets the numeric Property specifying the width of the outline.
  72839. * @memberof BoxGraphics.prototype
  72840. * @type {Property}
  72841. * @default 1.0
  72842. */
  72843. outlineWidth : createPropertyDescriptor('outlineWidth'),
  72844. /**
  72845. * Get or sets the enum Property specifying whether the box
  72846. * casts or receives shadows from each light source.
  72847. * @memberof BoxGraphics.prototype
  72848. * @type {Property}
  72849. * @default ShadowMode.DISABLED
  72850. */
  72851. shadows : createPropertyDescriptor('shadows'),
  72852. /**
  72853. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this box will be displayed.
  72854. * @memberof BoxGraphics.prototype
  72855. * @type {Property}
  72856. */
  72857. distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition')
  72858. });
  72859. /**
  72860. * Duplicates this instance.
  72861. *
  72862. * @param {BoxGraphics} [result] The object onto which to store the result.
  72863. * @returns {BoxGraphics} The modified result parameter or a new instance if one was not provided.
  72864. */
  72865. BoxGraphics.prototype.clone = function(result) {
  72866. if (!defined(result)) {
  72867. return new BoxGraphics(this);
  72868. }
  72869. result.dimensions = this.dimensions;
  72870. result.show = this.show;
  72871. result.material = this.material;
  72872. result.fill = this.fill;
  72873. result.outline = this.outline;
  72874. result.outlineColor = this.outlineColor;
  72875. result.outlineWidth = this.outlineWidth;
  72876. result.shadows = this.shadows;
  72877. result.distanceDisplayCondition = this.distanceDisplayCondition;
  72878. return result;
  72879. };
  72880. /**
  72881. * Assigns each unassigned property on this object to the value
  72882. * of the same property on the provided source object.
  72883. *
  72884. * @param {BoxGraphics} source The object to be merged into this object.
  72885. */
  72886. BoxGraphics.prototype.merge = function(source) {
  72887. if (!defined(source)) {
  72888. throw new DeveloperError('source is required.');
  72889. }
  72890. this.dimensions = defaultValue(this.dimensions, source.dimensions);
  72891. this.show = defaultValue(this.show, source.show);
  72892. this.material = defaultValue(this.material, source.material);
  72893. this.fill = defaultValue(this.fill, source.fill);
  72894. this.outline = defaultValue(this.outline, source.outline);
  72895. this.outlineColor = defaultValue(this.outlineColor, source.outlineColor);
  72896. this.outlineWidth = defaultValue(this.outlineWidth, source.outlineWidth);
  72897. this.shadows = defaultValue(this.shadows, source.shadows);
  72898. this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
  72899. };
  72900. return BoxGraphics;
  72901. });
  72902. /*global define*/
  72903. define('DataSources/CallbackProperty',[
  72904. '../Core/defined',
  72905. '../Core/defineProperties',
  72906. '../Core/DeveloperError',
  72907. '../Core/Event'
  72908. ], function(
  72909. defined,
  72910. defineProperties,
  72911. DeveloperError,
  72912. Event) {
  72913. 'use strict';
  72914. /**
  72915. * A {@link Property} whose value is lazily evaluated by a callback function.
  72916. *
  72917. * @alias CallbackProperty
  72918. * @constructor
  72919. *
  72920. * @param {CallbackProperty~Callback} callback The function to be called when the property is evaluated.
  72921. * @param {Boolean} isConstant <code>true</code> when the callback function returns the same value every time, <code>false</code> if the value will change.
  72922. */
  72923. function CallbackProperty(callback, isConstant) {
  72924. this._callback = undefined;
  72925. this._isConstant = undefined;
  72926. this._definitionChanged = new Event();
  72927. this.setCallback(callback, isConstant);
  72928. }
  72929. defineProperties(CallbackProperty.prototype, {
  72930. /**
  72931. * Gets a value indicating if this property is constant.
  72932. * @memberof CallbackProperty.prototype
  72933. *
  72934. * @type {Boolean}
  72935. * @readonly
  72936. */
  72937. isConstant : {
  72938. get : function() {
  72939. return this._isConstant;
  72940. }
  72941. },
  72942. /**
  72943. * Gets the event that is raised whenever the definition of this property changes.
  72944. * The definition is changed whenever setCallback is called.
  72945. * @memberof CallbackProperty.prototype
  72946. *
  72947. * @type {Event}
  72948. * @readonly
  72949. */
  72950. definitionChanged : {
  72951. get : function() {
  72952. return this._definitionChanged;
  72953. }
  72954. }
  72955. });
  72956. /**
  72957. * Gets the value of the property.
  72958. *
  72959. * @param {JulianDate} [time] The time for which to retrieve the value. This parameter is unused since the value does not change with respect to time.
  72960. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  72961. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied or is unsupported.
  72962. */
  72963. CallbackProperty.prototype.getValue = function(time, result) {
  72964. return this._callback(time, result);
  72965. };
  72966. /**
  72967. * Sets the callback to be used.
  72968. *
  72969. * @param {CallbackProperty~Callback} callback The function to be called when the property is evaluated.
  72970. * @param {Boolean} isConstant <code>true</code> when the callback function returns the same value every time, <code>false</code> if the value will change.
  72971. */
  72972. CallbackProperty.prototype.setCallback = function(callback, isConstant) {
  72973. if (!defined(callback)) {
  72974. throw new DeveloperError('callback is required.');
  72975. }
  72976. if (!defined(isConstant)) {
  72977. throw new DeveloperError('isConstant is required.');
  72978. }
  72979. var changed = this._callback !== callback || this._isConstant !== isConstant;
  72980. this._callback = callback;
  72981. this._isConstant = isConstant;
  72982. if (changed) {
  72983. this._definitionChanged.raiseEvent(this);
  72984. }
  72985. };
  72986. /**
  72987. * Compares this property to the provided property and returns
  72988. * <code>true</code> if they are equal, <code>false</code> otherwise.
  72989. *
  72990. * @param {Property} [other] The other property.
  72991. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  72992. */
  72993. CallbackProperty.prototype.equals = function(other) {
  72994. return this === other || (other instanceof CallbackProperty && this._callback === other._callback && this._isConstant === other._isConstant);
  72995. };
  72996. /**
  72997. * A function that returns the value of the property.
  72998. * @callback CallbackProperty~Callback
  72999. *
  73000. * @param {JulianDate} [time] The time for which to retrieve the value.
  73001. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  73002. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied or is unsupported.
  73003. */
  73004. return CallbackProperty;
  73005. });
  73006. /*global define*/
  73007. define('DataSources/CheckerboardMaterialProperty',[
  73008. '../Core/Cartesian2',
  73009. '../Core/Color',
  73010. '../Core/defaultValue',
  73011. '../Core/defined',
  73012. '../Core/defineProperties',
  73013. '../Core/Event',
  73014. './createPropertyDescriptor',
  73015. './Property'
  73016. ], function(
  73017. Cartesian2,
  73018. Color,
  73019. defaultValue,
  73020. defined,
  73021. defineProperties,
  73022. Event,
  73023. createPropertyDescriptor,
  73024. Property) {
  73025. 'use strict';
  73026. var defaultEvenColor = Color.WHITE;
  73027. var defaultOddColor = Color.BLACK;
  73028. var defaultRepeat = new Cartesian2(2.0, 2.0);
  73029. /**
  73030. * A {@link MaterialProperty} that maps to checkerboard {@link Material} uniforms.
  73031. * @alias CheckerboardMaterialProperty
  73032. * @constructor
  73033. *
  73034. * @param {Object} [options] Object with the following properties:
  73035. * @param {Property} [options.evenColor=Color.WHITE] A Property specifying the first {@link Color}.
  73036. * @param {Property} [options.oddColor=Color.BLACK] A Property specifying the second {@link Color}.
  73037. * @param {Property} [options.repeat=new Cartesian2(2.0, 2.0)] A {@link Cartesian2} Property specifying how many times the tiles repeat in each direction.
  73038. */
  73039. function CheckerboardMaterialProperty(options) {
  73040. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  73041. this._definitionChanged = new Event();
  73042. this._evenColor = undefined;
  73043. this._evenColorSubscription = undefined;
  73044. this._oddColor = undefined;
  73045. this._oddColorSubscription = undefined;
  73046. this._repeat = undefined;
  73047. this._repeatSubscription = undefined;
  73048. this.evenColor = options.evenColor;
  73049. this.oddColor = options.oddColor;
  73050. this.repeat = options.repeat;
  73051. }
  73052. defineProperties(CheckerboardMaterialProperty.prototype, {
  73053. /**
  73054. * Gets a value indicating if this property is constant. A property is considered
  73055. * constant if getValue always returns the same result for the current definition.
  73056. * @memberof CheckerboardMaterialProperty.prototype
  73057. *
  73058. * @type {Boolean}
  73059. * @readonly
  73060. */
  73061. isConstant : {
  73062. get : function() {
  73063. return Property.isConstant(this._evenColor) && //
  73064. Property.isConstant(this._oddColor) && //
  73065. Property.isConstant(this._repeat);
  73066. }
  73067. },
  73068. /**
  73069. * Gets the event that is raised whenever the definition of this property changes.
  73070. * The definition is considered to have changed if a call to getValue would return
  73071. * a different result for the same time.
  73072. * @memberof CheckerboardMaterialProperty.prototype
  73073. *
  73074. * @type {Event}
  73075. * @readonly
  73076. */
  73077. definitionChanged : {
  73078. get : function() {
  73079. return this._definitionChanged;
  73080. }
  73081. },
  73082. /**
  73083. * Gets or sets the Property specifying the first {@link Color}.
  73084. * @memberof CheckerboardMaterialProperty.prototype
  73085. * @type {Property}
  73086. * @default Color.WHITE
  73087. */
  73088. evenColor : createPropertyDescriptor('evenColor'),
  73089. /**
  73090. * Gets or sets the Property specifying the second {@link Color}.
  73091. * @memberof CheckerboardMaterialProperty.prototype
  73092. * @type {Property}
  73093. * @default Color.BLACK
  73094. */
  73095. oddColor : createPropertyDescriptor('oddColor'),
  73096. /**
  73097. * Gets or sets the {@link Cartesian2} Property specifying how many times the tiles repeat in each direction.
  73098. * @memberof CheckerboardMaterialProperty.prototype
  73099. * @type {Property}
  73100. * @default new Cartesian2(2.0, 2.0)
  73101. */
  73102. repeat : createPropertyDescriptor('repeat')
  73103. });
  73104. /**
  73105. * Gets the {@link Material} type at the provided time.
  73106. *
  73107. * @param {JulianDate} time The time for which to retrieve the type.
  73108. * @returns {String} The type of material.
  73109. */
  73110. CheckerboardMaterialProperty.prototype.getType = function(time) {
  73111. return 'Checkerboard';
  73112. };
  73113. /**
  73114. * Gets the value of the property at the provided time.
  73115. *
  73116. * @param {JulianDate} time The time for which to retrieve the value.
  73117. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  73118. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  73119. */
  73120. CheckerboardMaterialProperty.prototype.getValue = function(time, result) {
  73121. if (!defined(result)) {
  73122. result = {};
  73123. }
  73124. result.lightColor = Property.getValueOrClonedDefault(this._evenColor, time, defaultEvenColor, result.lightColor);
  73125. result.darkColor = Property.getValueOrClonedDefault(this._oddColor, time, defaultOddColor, result.darkColor);
  73126. result.repeat = Property.getValueOrDefault(this._repeat, time, defaultRepeat);
  73127. return result;
  73128. };
  73129. /**
  73130. * Compares this property to the provided property and returns
  73131. * <code>true</code> if they are equal, <code>false</code> otherwise.
  73132. *
  73133. * @param {Property} [other] The other property.
  73134. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  73135. */
  73136. CheckerboardMaterialProperty.prototype.equals = function(other) {
  73137. return this === other || //
  73138. (other instanceof CheckerboardMaterialProperty && //
  73139. Property.equals(this._evenColor, other._evenColor) && //
  73140. Property.equals(this._oddColor, other._oddColor) && //
  73141. Property.equals(this._repeat, other._repeat));
  73142. };
  73143. return CheckerboardMaterialProperty;
  73144. });
  73145. /*global define*/
  73146. define('DataSources/PositionProperty',[
  73147. '../Core/Cartesian3',
  73148. '../Core/defined',
  73149. '../Core/defineProperties',
  73150. '../Core/DeveloperError',
  73151. '../Core/Matrix3',
  73152. '../Core/ReferenceFrame',
  73153. '../Core/Transforms'
  73154. ], function(
  73155. Cartesian3,
  73156. defined,
  73157. defineProperties,
  73158. DeveloperError,
  73159. Matrix3,
  73160. ReferenceFrame,
  73161. Transforms) {
  73162. 'use strict';
  73163. /**
  73164. * The interface for all {@link Property} objects that define a world
  73165. * location as a {@link Cartesian3} with an associated {@link ReferenceFrame}.
  73166. * This type defines an interface and cannot be instantiated directly.
  73167. *
  73168. * @alias PositionProperty
  73169. * @constructor
  73170. *
  73171. * @see CompositePositionProperty
  73172. * @see ConstantPositionProperty
  73173. * @see SampledPositionProperty
  73174. * @see TimeIntervalCollectionPositionProperty
  73175. */
  73176. function PositionProperty() {
  73177. DeveloperError.throwInstantiationError();
  73178. }
  73179. defineProperties(PositionProperty.prototype, {
  73180. /**
  73181. * Gets a value indicating if this property is constant. A property is considered
  73182. * constant if getValue always returns the same result for the current definition.
  73183. * @memberof PositionProperty.prototype
  73184. *
  73185. * @type {Boolean}
  73186. * @readonly
  73187. */
  73188. isConstant : {
  73189. get : DeveloperError.throwInstantiationError
  73190. },
  73191. /**
  73192. * Gets the event that is raised whenever the definition of this property changes.
  73193. * The definition is considered to have changed if a call to getValue would return
  73194. * a different result for the same time.
  73195. * @memberof PositionProperty.prototype
  73196. *
  73197. * @type {Event}
  73198. * @readonly
  73199. */
  73200. definitionChanged : {
  73201. get : DeveloperError.throwInstantiationError
  73202. },
  73203. /**
  73204. * Gets the reference frame that the position is defined in.
  73205. * @memberof PositionProperty.prototype
  73206. * @type {ReferenceFrame}
  73207. */
  73208. referenceFrame : {
  73209. get : DeveloperError.throwInstantiationError
  73210. }
  73211. });
  73212. /**
  73213. * Gets the value of the property at the provided time in the fixed frame.
  73214. * @function
  73215. *
  73216. * @param {JulianDate} time The time for which to retrieve the value.
  73217. * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
  73218. * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
  73219. */
  73220. PositionProperty.prototype.getValue = DeveloperError.throwInstantiationError;
  73221. /**
  73222. * Gets the value of the property at the provided time and in the provided reference frame.
  73223. * @function
  73224. *
  73225. * @param {JulianDate} time The time for which to retrieve the value.
  73226. * @param {ReferenceFrame} referenceFrame The desired referenceFrame of the result.
  73227. * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
  73228. * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
  73229. */
  73230. PositionProperty.prototype.getValueInReferenceFrame = DeveloperError.throwInstantiationError;
  73231. /**
  73232. * Compares this property to the provided property and returns
  73233. * <code>true</code> if they are equal, <code>false</code> otherwise.
  73234. * @function
  73235. *
  73236. * @param {Property} [other] The other property.
  73237. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  73238. */
  73239. PositionProperty.prototype.equals = DeveloperError.throwInstantiationError;
  73240. var scratchMatrix3 = new Matrix3();
  73241. /**
  73242. * @private
  73243. */
  73244. PositionProperty.convertToReferenceFrame = function(time, value, inputFrame, outputFrame, result) {
  73245. if (!defined(value)) {
  73246. return value;
  73247. }
  73248. if (!defined(result)){
  73249. result = new Cartesian3();
  73250. }
  73251. if (inputFrame === outputFrame) {
  73252. return Cartesian3.clone(value, result);
  73253. }
  73254. var icrfToFixed = Transforms.computeIcrfToFixedMatrix(time, scratchMatrix3);
  73255. if (!defined(icrfToFixed)) {
  73256. icrfToFixed = Transforms.computeTemeToPseudoFixedMatrix(time, scratchMatrix3);
  73257. }
  73258. if (inputFrame === ReferenceFrame.INERTIAL) {
  73259. return Matrix3.multiplyByVector(icrfToFixed, value, result);
  73260. }
  73261. if (inputFrame === ReferenceFrame.FIXED) {
  73262. return Matrix3.multiplyByVector(Matrix3.transpose(icrfToFixed, scratchMatrix3), value, result);
  73263. }
  73264. };
  73265. return PositionProperty;
  73266. });
  73267. /*global define*/
  73268. define('DataSources/ConstantPositionProperty',[
  73269. '../Core/Cartesian3',
  73270. '../Core/defaultValue',
  73271. '../Core/defined',
  73272. '../Core/defineProperties',
  73273. '../Core/DeveloperError',
  73274. '../Core/Event',
  73275. '../Core/ReferenceFrame',
  73276. './PositionProperty'
  73277. ], function(
  73278. Cartesian3,
  73279. defaultValue,
  73280. defined,
  73281. defineProperties,
  73282. DeveloperError,
  73283. Event,
  73284. ReferenceFrame,
  73285. PositionProperty) {
  73286. 'use strict';
  73287. /**
  73288. * A {@link PositionProperty} whose value does not change in respect to the
  73289. * {@link ReferenceFrame} in which is it defined.
  73290. *
  73291. * @alias ConstantPositionProperty
  73292. * @constructor
  73293. *
  73294. * @param {Cartesian3} [value] The property value.
  73295. * @param {ReferenceFrame} [referenceFrame=ReferenceFrame.FIXED] The reference frame in which the position is defined.
  73296. */
  73297. function ConstantPositionProperty(value, referenceFrame) {
  73298. this._definitionChanged = new Event();
  73299. this._value = Cartesian3.clone(value);
  73300. this._referenceFrame = defaultValue(referenceFrame, ReferenceFrame.FIXED);
  73301. }
  73302. defineProperties(ConstantPositionProperty.prototype, {
  73303. /**
  73304. * Gets a value indicating if this property is constant. A property is considered
  73305. * constant if getValue always returns the same result for the current definition.
  73306. * @memberof ConstantPositionProperty.prototype
  73307. *
  73308. * @type {Boolean}
  73309. * @readonly
  73310. */
  73311. isConstant : {
  73312. get : function() {
  73313. return !defined(this._value) || this._referenceFrame === ReferenceFrame.FIXED;
  73314. }
  73315. },
  73316. /**
  73317. * Gets the event that is raised whenever the definition of this property changes.
  73318. * The definition is considered to have changed if a call to getValue would return
  73319. * a different result for the same time.
  73320. * @memberof ConstantPositionProperty.prototype
  73321. *
  73322. * @type {Event}
  73323. * @readonly
  73324. */
  73325. definitionChanged : {
  73326. get : function() {
  73327. return this._definitionChanged;
  73328. }
  73329. },
  73330. /**
  73331. * Gets the reference frame in which the position is defined.
  73332. * @memberof ConstantPositionProperty.prototype
  73333. * @type {ReferenceFrame}
  73334. * @default ReferenceFrame.FIXED;
  73335. */
  73336. referenceFrame : {
  73337. get : function() {
  73338. return this._referenceFrame;
  73339. }
  73340. }
  73341. });
  73342. /**
  73343. * Gets the value of the property at the provided time in the fixed frame.
  73344. *
  73345. * @param {JulianDate} time The time for which to retrieve the value.
  73346. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  73347. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  73348. */
  73349. ConstantPositionProperty.prototype.getValue = function(time, result) {
  73350. return this.getValueInReferenceFrame(time, ReferenceFrame.FIXED, result);
  73351. };
  73352. /**
  73353. * Sets the value of the property.
  73354. *
  73355. * @param {Cartesian3} value The property value.
  73356. * @param {ReferenceFrame} [referenceFrame=this.referenceFrame] The reference frame in which the position is defined.
  73357. */
  73358. ConstantPositionProperty.prototype.setValue = function(value, referenceFrame) {
  73359. var definitionChanged = false;
  73360. if (!Cartesian3.equals(this._value, value)) {
  73361. definitionChanged = true;
  73362. this._value = Cartesian3.clone(value);
  73363. }
  73364. if (defined(referenceFrame) && this._referenceFrame !== referenceFrame) {
  73365. definitionChanged = true;
  73366. this._referenceFrame = referenceFrame;
  73367. }
  73368. if (definitionChanged) {
  73369. this._definitionChanged.raiseEvent(this);
  73370. }
  73371. };
  73372. /**
  73373. * Gets the value of the property at the provided time and in the provided reference frame.
  73374. *
  73375. * @param {JulianDate} time The time for which to retrieve the value.
  73376. * @param {ReferenceFrame} referenceFrame The desired referenceFrame of the result.
  73377. * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
  73378. * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
  73379. */
  73380. ConstantPositionProperty.prototype.getValueInReferenceFrame = function(time, referenceFrame, result) {
  73381. if (!defined(time)) {
  73382. throw new DeveloperError('time is required.');
  73383. }
  73384. if (!defined(referenceFrame)) {
  73385. throw new DeveloperError('referenceFrame is required.');
  73386. }
  73387. return PositionProperty.convertToReferenceFrame(time, this._value, this._referenceFrame, referenceFrame, result);
  73388. };
  73389. /**
  73390. * Compares this property to the provided property and returns
  73391. * <code>true</code> if they are equal, <code>false</code> otherwise.
  73392. *
  73393. * @param {Property} [other] The other property.
  73394. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  73395. */
  73396. ConstantPositionProperty.prototype.equals = function(other) {
  73397. return this === other ||
  73398. (other instanceof ConstantPositionProperty &&
  73399. Cartesian3.equals(this._value, other._value) &&
  73400. this._referenceFrame === other._referenceFrame);
  73401. };
  73402. return ConstantPositionProperty;
  73403. });
  73404. /*global define*/
  73405. define('DataSources/CorridorGraphics',[
  73406. '../Core/defaultValue',
  73407. '../Core/defined',
  73408. '../Core/defineProperties',
  73409. '../Core/DeveloperError',
  73410. '../Core/Event',
  73411. './createMaterialPropertyDescriptor',
  73412. './createPropertyDescriptor'
  73413. ], function(
  73414. defaultValue,
  73415. defined,
  73416. defineProperties,
  73417. DeveloperError,
  73418. Event,
  73419. createMaterialPropertyDescriptor,
  73420. createPropertyDescriptor) {
  73421. 'use strict';
  73422. /**
  73423. * Describes a corridor, which is a shape defined by a centerline and width that
  73424. * conforms to the curvature of the globe. It can be placed on the surface or at altitude
  73425. * and can optionally be extruded into a volume.
  73426. *
  73427. * @alias CorridorGraphics
  73428. * @constructor
  73429. *
  73430. * @param {Object} [options] Object with the following properties:
  73431. * @param {Property} [options.positions] A Property specifying the array of {@link Cartesian3} positions that define the centerline of the corridor.
  73432. * @param {Property} [options.width] A numeric Property specifying the distance between the edges of the corridor.
  73433. * @param {Property} [options.cornerType=CornerType.ROUNDED] A {@link CornerType} Property specifying the style of the corners.
  73434. * @param {Property} [options.height=0] A numeric Property specifying the altitude of the corridor relative to the ellipsoid surface.
  73435. * @param {Property} [options.extrudedHeight] A numeric Property specifying the altitude of the corridor's extruded face relative to the ellipsoid surface.
  73436. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the corridor.
  73437. * @param {Property} [options.fill=true] A boolean Property specifying whether the corridor is filled with the provided material.
  73438. * @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to fill the corridor.
  73439. * @param {Property} [options.outline=false] A boolean Property specifying whether the corridor is outlined.
  73440. * @param {Property} [options.outlineColor=Color.BLACK] A Property specifying the {@link Color} of the outline.
  73441. * @param {Property} [options.outlineWidth=1.0] A numeric Property specifying the width of the outline.
  73442. * @param {Property} [options.granularity=Cesium.Math.RADIANS_PER_DEGREE] A numeric Property specifying the distance between each latitude and longitude.
  73443. * @param {Property} [options.shadows=ShadowMode.DISABLED] An enum Property specifying whether the corridor casts or receives shadows from each light source.
  73444. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this corridor will be displayed.
  73445. *
  73446. * @see Entity
  73447. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Corridor.html|Cesium Sandcastle Corridor Demo}
  73448. */
  73449. function CorridorGraphics(options) {
  73450. this._show = undefined;
  73451. this._showSubscription = undefined;
  73452. this._material = undefined;
  73453. this._materialSubscription = undefined;
  73454. this._positions = undefined;
  73455. this._positionsSubscription = undefined;
  73456. this._height = undefined;
  73457. this._heightSubscription = undefined;
  73458. this._extrudedHeight = undefined;
  73459. this._extrudedHeightSubscription = undefined;
  73460. this._granularity = undefined;
  73461. this._granularitySubscription = undefined;
  73462. this._width = undefined;
  73463. this._widthSubscription = undefined;
  73464. this._cornerType = undefined;
  73465. this._cornerTypeSubscription = undefined;
  73466. this._fill = undefined;
  73467. this._fillSubscription = undefined;
  73468. this._outline = undefined;
  73469. this._outlineSubscription = undefined;
  73470. this._outlineColor = undefined;
  73471. this._outlineColorSubscription = undefined;
  73472. this._outlineWidth = undefined;
  73473. this._outlineWidthSubscription = undefined;
  73474. this._shadows = undefined;
  73475. this._shadowsSubscription = undefined;
  73476. this._distanceDisplayCondition = undefined;
  73477. this._distanceDisplayConditionSubscription = undefined;
  73478. this._definitionChanged = new Event();
  73479. this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
  73480. }
  73481. defineProperties(CorridorGraphics.prototype, {
  73482. /**
  73483. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  73484. * @memberof CorridorGraphics.prototype
  73485. * @type {Event}
  73486. * @readonly
  73487. */
  73488. definitionChanged : {
  73489. get : function() {
  73490. return this._definitionChanged;
  73491. }
  73492. },
  73493. /**
  73494. * Gets or sets the boolean Property specifying the visibility of the corridor.
  73495. * @memberof CorridorGraphics.prototype
  73496. * @type {Property}
  73497. * @default true
  73498. */
  73499. show : createPropertyDescriptor('show'),
  73500. /**
  73501. * Gets or sets the Property specifying the material used to fill the corridor.
  73502. * @memberof CorridorGraphics.prototype
  73503. * @type {MaterialProperty}
  73504. * @default Color.WHITE
  73505. */
  73506. material : createMaterialPropertyDescriptor('material'),
  73507. /**
  73508. * Gets or sets a Property specifying the array of {@link Cartesian3} positions that define the centerline of the corridor.
  73509. * @memberof CorridorGraphics.prototype
  73510. * @type {Property}
  73511. */
  73512. positions : createPropertyDescriptor('positions'),
  73513. /**
  73514. * Gets or sets the numeric Property specifying the altitude of the corridor.
  73515. * @memberof CorridorGraphics.prototype
  73516. * @type {Property}
  73517. * @default 0.0
  73518. */
  73519. height : createPropertyDescriptor('height'),
  73520. /**
  73521. * Gets or sets the numeric Property specifying the altitude of the corridor extrusion.
  73522. * Setting this property creates a corridor shaped volume starting at height and ending
  73523. * at this altitude.
  73524. * @memberof CorridorGraphics.prototype
  73525. * @type {Property}
  73526. */
  73527. extrudedHeight : createPropertyDescriptor('extrudedHeight'),
  73528. /**
  73529. * Gets or sets the numeric Property specifying the sampling distance between each latitude and longitude point.
  73530. * @memberof CorridorGraphics.prototype
  73531. * @type {Property}
  73532. * @default {CesiumMath.RADIANS_PER_DEGREE}
  73533. */
  73534. granularity : createPropertyDescriptor('granularity'),
  73535. /**
  73536. * Gets or sets the numeric Property specifying the width of the corridor.
  73537. * @memberof CorridorGraphics.prototype
  73538. * @type {Property}
  73539. */
  73540. width : createPropertyDescriptor('width'),
  73541. /**
  73542. * Gets or sets the boolean Property specifying whether the corridor is filled with the provided material.
  73543. * @memberof CorridorGraphics.prototype
  73544. * @type {Property}
  73545. * @default true
  73546. */
  73547. fill : createPropertyDescriptor('fill'),
  73548. /**
  73549. * Gets or sets the Property specifying whether the corridor is outlined.
  73550. * @memberof CorridorGraphics.prototype
  73551. * @type {Property}
  73552. * @default false
  73553. */
  73554. outline : createPropertyDescriptor('outline'),
  73555. /**
  73556. * Gets or sets the Property specifying the {@link Color} of the outline.
  73557. * @memberof CorridorGraphics.prototype
  73558. * @type {Property}
  73559. * @default Color.BLACK
  73560. */
  73561. outlineColor : createPropertyDescriptor('outlineColor'),
  73562. /**
  73563. * Gets or sets the numeric Property specifying the width of the outline.
  73564. * @memberof CorridorGraphics.prototype
  73565. * @type {Property}
  73566. * @default 1.0
  73567. */
  73568. outlineWidth : createPropertyDescriptor('outlineWidth'),
  73569. /**
  73570. * Gets or sets the {@link CornerType} Property specifying how corners are styled.
  73571. * @memberof CorridorGraphics.prototype
  73572. * @type {Property}
  73573. * @default CornerType.ROUNDED
  73574. */
  73575. cornerType : createPropertyDescriptor('cornerType'),
  73576. /**
  73577. * Get or sets the enum Property specifying whether the corridor
  73578. * casts or receives shadows from each light source.
  73579. * @memberof CorridorGraphics.prototype
  73580. * @type {Property}
  73581. * @default ShadowMode.DISABLED
  73582. */
  73583. shadows : createPropertyDescriptor('shadows'),
  73584. /**
  73585. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this corridor will be displayed.
  73586. * @memberof CorridorGraphics.prototype
  73587. * @type {Property}
  73588. */
  73589. distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition')
  73590. });
  73591. /**
  73592. * Duplicates this instance.
  73593. *
  73594. * @param {CorridorGraphics} [result] The object onto which to store the result.
  73595. * @returns {CorridorGraphics} The modified result parameter or a new instance if one was not provided.
  73596. */
  73597. CorridorGraphics.prototype.clone = function(result) {
  73598. if (!defined(result)) {
  73599. return new CorridorGraphics(this);
  73600. }
  73601. result.show = this.show;
  73602. result.material = this.material;
  73603. result.positions = this.positions;
  73604. result.height = this.height;
  73605. result.extrudedHeight = this.extrudedHeight;
  73606. result.granularity = this.granularity;
  73607. result.width = this.width;
  73608. result.fill = this.fill;
  73609. result.outline = this.outline;
  73610. result.outlineColor = this.outlineColor;
  73611. result.outlineWidth = this.outlineWidth;
  73612. result.cornerType = this.cornerType;
  73613. result.shadows = this.shadows;
  73614. result.distanceDisplayCondition = this.distanceDisplayCondition;
  73615. return result;
  73616. };
  73617. /**
  73618. * Assigns each unassigned property on this object to the value
  73619. * of the same property on the provided source object.
  73620. *
  73621. * @param {CorridorGraphics} source The object to be merged into this object.
  73622. */
  73623. CorridorGraphics.prototype.merge = function(source) {
  73624. if (!defined(source)) {
  73625. throw new DeveloperError('source is required.');
  73626. }
  73627. this.show = defaultValue(this.show, source.show);
  73628. this.material = defaultValue(this.material, source.material);
  73629. this.positions = defaultValue(this.positions, source.positions);
  73630. this.height = defaultValue(this.height, source.height);
  73631. this.extrudedHeight = defaultValue(this.extrudedHeight, source.extrudedHeight);
  73632. this.granularity = defaultValue(this.granularity, source.granularity);
  73633. this.width = defaultValue(this.width, source.width);
  73634. this.fill = defaultValue(this.fill, source.fill);
  73635. this.outline = defaultValue(this.outline, source.outline);
  73636. this.outlineColor = defaultValue(this.outlineColor, source.outlineColor);
  73637. this.outlineWidth = defaultValue(this.outlineWidth, source.outlineWidth);
  73638. this.cornerType = defaultValue(this.cornerType, source.cornerType);
  73639. this.shadows = defaultValue(this.shadows, source.shadows);
  73640. this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
  73641. };
  73642. return CorridorGraphics;
  73643. });
  73644. /*global define*/
  73645. define('DataSources/createRawPropertyDescriptor',[
  73646. './createPropertyDescriptor'
  73647. ], function(
  73648. createPropertyDescriptor) {
  73649. 'use strict';
  73650. function createRawProperty(value) {
  73651. return value;
  73652. }
  73653. /**
  73654. * @private
  73655. */
  73656. function createRawPropertyDescriptor(name, configurable) {
  73657. return createPropertyDescriptor(name, configurable, createRawProperty);
  73658. }
  73659. return createRawPropertyDescriptor;
  73660. });
  73661. /*global define*/
  73662. define('DataSources/CylinderGraphics',[
  73663. '../Core/defaultValue',
  73664. '../Core/defined',
  73665. '../Core/defineProperties',
  73666. '../Core/DeveloperError',
  73667. '../Core/Event',
  73668. './createMaterialPropertyDescriptor',
  73669. './createPropertyDescriptor'
  73670. ], function(
  73671. defaultValue,
  73672. defined,
  73673. defineProperties,
  73674. DeveloperError,
  73675. Event,
  73676. createMaterialPropertyDescriptor,
  73677. createPropertyDescriptor) {
  73678. 'use strict';
  73679. /**
  73680. * Describes a cylinder, truncated cone, or cone defined by a length, top radius, and bottom radius.
  73681. * The center position and orientation are determined by the containing {@link Entity}.
  73682. *
  73683. * @alias CylinderGraphics
  73684. * @constructor
  73685. *
  73686. * @param {Object} [options] Object with the following properties:
  73687. * @param {Property} [options.length] A numeric Property specifying the length of the cylinder.
  73688. * @param {Property} [options.topRadius] A numeric Property specifying the radius of the top of the cylinder.
  73689. * @param {Property} [options.bottomRadius] A numeric Property specifying the radius of the bottom of the cylinder.
  73690. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the cylinder.
  73691. * @param {Property} [options.fill=true] A boolean Property specifying whether the cylinder is filled with the provided material.
  73692. * @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to fill the cylinder.
  73693. * @param {Property} [options.outline=false] A boolean Property specifying whether the cylinder is outlined.
  73694. * @param {Property} [options.outlineColor=Color.BLACK] A Property specifying the {@link Color} of the outline.
  73695. * @param {Property} [options.outlineWidth=1.0] A numeric Property specifying the width of the outline.
  73696. * @param {Property} [options.numberOfVerticalLines=16] A numeric Property specifying the number of vertical lines to draw along the perimeter for the outline.
  73697. * @param {Property} [options.slices=128] The number of edges around the perimeter of the cylinder.
  73698. * @param {Property} [options.shadows=ShadowMode.DISABLED] An enum Property specifying whether the cylinder casts or receives shadows from each light source.
  73699. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this cylinder will be displayed.
  73700. */
  73701. function CylinderGraphics(options) {
  73702. this._length = undefined;
  73703. this._lengthSubscription = undefined;
  73704. this._topRadius = undefined;
  73705. this._topRadiusSubscription = undefined;
  73706. this._bottomRadius = undefined;
  73707. this._bottomRadiusSubscription = undefined;
  73708. this._numberOfVerticalLines = undefined;
  73709. this._numberOfVerticalLinesSubscription = undefined;
  73710. this._slices = undefined;
  73711. this._slicesSubscription = undefined;
  73712. this._show = undefined;
  73713. this._showSubscription = undefined;
  73714. this._material = undefined;
  73715. this._materialSubscription = undefined;
  73716. this._fill = undefined;
  73717. this._fillSubscription = undefined;
  73718. this._outline = undefined;
  73719. this._outlineSubscription = undefined;
  73720. this._outlineColor = undefined;
  73721. this._outlineColorSubscription = undefined;
  73722. this._outlineWidth = undefined;
  73723. this._outlineWidthSubscription = undefined;
  73724. this._shadows = undefined;
  73725. this._shadowsSubscription = undefined;
  73726. this._distanceDisplayCondition = undefined;
  73727. this._distanceDisplayConditionSubscription = undefined;
  73728. this._definitionChanged = new Event();
  73729. this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
  73730. }
  73731. defineProperties(CylinderGraphics.prototype, {
  73732. /**
  73733. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  73734. * @memberof CylinderGraphics.prototype
  73735. *
  73736. * @type {Event}
  73737. * @readonly
  73738. */
  73739. definitionChanged : {
  73740. get : function() {
  73741. return this._definitionChanged;
  73742. }
  73743. },
  73744. /**
  73745. * Gets or sets the numeric Property specifying the length of the cylinder.
  73746. * @memberof CylinderGraphics.prototype
  73747. * @type {Property}
  73748. */
  73749. length : createPropertyDescriptor('length'),
  73750. /**
  73751. * Gets or sets the numeric Property specifying the radius of the top of the cylinder.
  73752. * @memberof CylinderGraphics.prototype
  73753. * @type {Property}
  73754. */
  73755. topRadius : createPropertyDescriptor('topRadius'),
  73756. /**
  73757. * Gets or sets the numeric Property specifying the radius of the bottom of the cylinder.
  73758. * @memberof CylinderGraphics.prototype
  73759. * @type {Property}
  73760. */
  73761. bottomRadius : createPropertyDescriptor('bottomRadius'),
  73762. /**
  73763. * Gets or sets the Property specifying the number of vertical lines to draw along the perimeter for the outline.
  73764. * @memberof CylinderGraphics.prototype
  73765. * @type {Property}
  73766. * @default 16
  73767. */
  73768. numberOfVerticalLines : createPropertyDescriptor('numberOfVerticalLines'),
  73769. /**
  73770. * Gets or sets the Property specifying the number of edges around the perimeter of the cylinder.
  73771. * @memberof CylinderGraphics.prototype
  73772. * @type {Property}
  73773. * @default 16
  73774. */
  73775. slices : createPropertyDescriptor('slices'),
  73776. /**
  73777. * Gets or sets the boolean Property specifying the visibility of the cylinder.
  73778. * @memberof CylinderGraphics.prototype
  73779. * @type {Property}
  73780. * @default true
  73781. */
  73782. show : createPropertyDescriptor('show'),
  73783. /**
  73784. * Gets or sets the Property specifying the material used to fill the cylinder.
  73785. * @memberof CylinderGraphics.prototype
  73786. * @type {MaterialProperty}
  73787. * @default Color.WHITE
  73788. */
  73789. material : createMaterialPropertyDescriptor('material'),
  73790. /**
  73791. * Gets or sets the boolean Property specifying whether the cylinder is filled with the provided material.
  73792. * @memberof CylinderGraphics.prototype
  73793. * @type {Property}
  73794. * @default true
  73795. */
  73796. fill : createPropertyDescriptor('fill'),
  73797. /**
  73798. * Gets or sets the boolean Property specifying whether the cylinder is outlined.
  73799. * @memberof CylinderGraphics.prototype
  73800. * @type {Property}
  73801. * @default false
  73802. */
  73803. outline : createPropertyDescriptor('outline'),
  73804. /**
  73805. * Gets or sets the Property specifying the {@link Color} of the outline.
  73806. * @memberof CylinderGraphics.prototype
  73807. * @type {Property}
  73808. * @default Color.BLACK
  73809. */
  73810. outlineColor : createPropertyDescriptor('outlineColor'),
  73811. /**
  73812. * Gets or sets the numeric Property specifying the width of the outline.
  73813. * @memberof CylinderGraphics.prototype
  73814. * @type {Property}
  73815. * @default 1.0
  73816. */
  73817. outlineWidth : createPropertyDescriptor('outlineWidth'),
  73818. /**
  73819. * Get or sets the enum Property specifying whether the cylinder
  73820. * casts or receives shadows from each light source.
  73821. * @memberof CylinderGraphics.prototype
  73822. * @type {Property}
  73823. * @default ShadowMode.DISABLED
  73824. */
  73825. shadows : createPropertyDescriptor('shadows'),
  73826. /**
  73827. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this cylinder will be displayed.
  73828. * @memberof CylinderGraphics.prototype
  73829. * @type {Property}
  73830. */
  73831. distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition')
  73832. });
  73833. /**
  73834. * Duplicates this instance.
  73835. *
  73836. * @param {CylinderGraphics} [result] The object onto which to store the result.
  73837. * @returns {CylinderGraphics} The modified result parameter or a new instance if one was not provided.
  73838. */
  73839. CylinderGraphics.prototype.clone = function(result) {
  73840. if (!defined(result)) {
  73841. return new CylinderGraphics(this);
  73842. }
  73843. result.bottomRadius = this.bottomRadius;
  73844. result.length = this.length;
  73845. result.topRadius = this.topRadius;
  73846. result.show = this.show;
  73847. result.material = this.material;
  73848. result.numberOfVerticalLines = this.numberOfVerticalLines;
  73849. result.slices = this.slices;
  73850. result.fill = this.fill;
  73851. result.outline = this.outline;
  73852. result.outlineColor = this.outlineColor;
  73853. result.outlineWidth = this.outlineWidth;
  73854. result.shadows = this.shadows;
  73855. result.distanceDisplayCondition = this.distanceDisplayCondition;
  73856. return result;
  73857. };
  73858. /**
  73859. * Assigns each unassigned property on this object to the value
  73860. * of the same property on the provided source object.
  73861. *
  73862. * @param {CylinderGraphics} source The object to be merged into this object.
  73863. */
  73864. CylinderGraphics.prototype.merge = function(source) {
  73865. if (!defined(source)) {
  73866. throw new DeveloperError('source is required.');
  73867. }
  73868. this.bottomRadius = defaultValue(this.bottomRadius, source.bottomRadius);
  73869. this.length = defaultValue(this.length, source.length);
  73870. this.topRadius = defaultValue(this.topRadius, source.topRadius);
  73871. this.show = defaultValue(this.show, source.show);
  73872. this.material = defaultValue(this.material, source.material);
  73873. this.numberOfVerticalLines = defaultValue(this.numberOfVerticalLines, source.numberOfVerticalLines);
  73874. this.slices = defaultValue(this.slices, source.slices);
  73875. this.fill = defaultValue(this.fill, source.fill);
  73876. this.outline = defaultValue(this.outline, source.outline);
  73877. this.outlineColor = defaultValue(this.outlineColor, source.outlineColor);
  73878. this.outlineWidth = defaultValue(this.outlineWidth, source.outlineWidth);
  73879. this.shadows = defaultValue(this.shadows, source.shadows);
  73880. this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
  73881. };
  73882. return CylinderGraphics;
  73883. });
  73884. /*global define*/
  73885. define('DataSources/EllipseGraphics',[
  73886. '../Core/defaultValue',
  73887. '../Core/defined',
  73888. '../Core/defineProperties',
  73889. '../Core/DeveloperError',
  73890. '../Core/Event',
  73891. './createMaterialPropertyDescriptor',
  73892. './createPropertyDescriptor'
  73893. ], function(
  73894. defaultValue,
  73895. defined,
  73896. defineProperties,
  73897. DeveloperError,
  73898. Event,
  73899. createMaterialPropertyDescriptor,
  73900. createPropertyDescriptor) {
  73901. 'use strict';
  73902. /**
  73903. * Describes an ellipse defined by a center point and semi-major and semi-minor axes.
  73904. * The ellipse conforms to the curvature of the globe and can be placed on the surface or
  73905. * at altitude and can optionally be extruded into a volume.
  73906. * The center point is determined by the containing {@link Entity}.
  73907. *
  73908. * @alias EllipseGraphics
  73909. * @constructor
  73910. *
  73911. * @param {Object} [options] Object with the following properties:
  73912. * @param {Property} [options.semiMajorAxis] The numeric Property specifying the semi-major axis.
  73913. * @param {Property} [options.semiMinorAxis] The numeric Property specifying the semi-minor axis.
  73914. * @param {Property} [options.height=0] A numeric Property specifying the altitude of the ellipse relative to the ellipsoid surface.
  73915. * @param {Property} [options.extrudedHeight] A numeric Property specifying the altitude of the ellipse's extruded face relative to the ellipsoid surface.
  73916. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the ellipse.
  73917. * @param {Property} [options.fill=true] A boolean Property specifying whether the ellipse is filled with the provided material.
  73918. * @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to fill the ellipse.
  73919. * @param {Property} [options.outline=false] A boolean Property specifying whether the ellipse is outlined.
  73920. * @param {Property} [options.outlineColor=Color.BLACK] A Property specifying the {@link Color} of the outline.
  73921. * @param {Property} [options.outlineWidth=1.0] A numeric Property specifying the width of the outline.
  73922. * @param {Property} [options.numberOfVerticalLines=16] A numeric Property specifying the number of vertical lines to draw along the perimeter for the outline.
  73923. * @param {Property} [options.rotation=0.0] A numeric property specifying the rotation of the ellipse counter-clockwise from north.
  73924. * @param {Property} [options.stRotation=0.0] A numeric property specifying the rotation of the ellipse texture counter-clockwise from north.
  73925. * @param {Property} [options.granularity=Cesium.Math.RADIANS_PER_DEGREE] A numeric Property specifying the angular distance between points on the ellipse.
  73926. * @param {Property} [options.shadows=ShadowMode.DISABLED] An enum Property specifying whether the ellipse casts or receives shadows from each light source.
  73927. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this ellipse will be displayed.
  73928. *
  73929. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Circles and Ellipses.html|Cesium Sandcastle Circles and Ellipses Demo}
  73930. */
  73931. function EllipseGraphics(options) {
  73932. this._semiMajorAxis = undefined;
  73933. this._semiMajorAxisSubscription = undefined;
  73934. this._semiMinorAxis = undefined;
  73935. this._semiMinorAxisSubscription = undefined;
  73936. this._rotation = undefined;
  73937. this._rotationSubscription = undefined;
  73938. this._show = undefined;
  73939. this._showSubscription = undefined;
  73940. this._material = undefined;
  73941. this._materialSubscription = undefined;
  73942. this._height = undefined;
  73943. this._heightSubscription = undefined;
  73944. this._extrudedHeight = undefined;
  73945. this._extrudedHeightSubscription = undefined;
  73946. this._granularity = undefined;
  73947. this._granularitySubscription = undefined;
  73948. this._stRotation = undefined;
  73949. this._stRotationSubscription = undefined;
  73950. this._fill = undefined;
  73951. this._fillSubscription = undefined;
  73952. this._outline = undefined;
  73953. this._outlineSubscription = undefined;
  73954. this._outlineColor = undefined;
  73955. this._outlineColorSubscription = undefined;
  73956. this._outlineWidth = undefined;
  73957. this._outlineWidthSubscription = undefined;
  73958. this._numberOfVerticalLines = undefined;
  73959. this._numberOfVerticalLinesSubscription = undefined;
  73960. this._shadows = undefined;
  73961. this._shadowsSubscription = undefined;
  73962. this._distanceDisplayCondition = undefined;
  73963. this._distanceDisplayConditionSubscription = undefined;
  73964. this._definitionChanged = new Event();
  73965. this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
  73966. }
  73967. defineProperties(EllipseGraphics.prototype, {
  73968. /**
  73969. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  73970. * @memberof EllipseGraphics.prototype
  73971. *
  73972. * @type {Event}
  73973. * @readonly
  73974. */
  73975. definitionChanged : {
  73976. get : function() {
  73977. return this._definitionChanged;
  73978. }
  73979. },
  73980. /**
  73981. * Gets or sets the numeric Property specifying the semi-major axis.
  73982. * @memberof EllipseGraphics.prototype
  73983. * @type {Property}
  73984. */
  73985. semiMajorAxis : createPropertyDescriptor('semiMajorAxis'),
  73986. /**
  73987. * Gets or sets the numeric Property specifying the semi-minor axis.
  73988. * @memberof EllipseGraphics.prototype
  73989. * @type {Property}
  73990. */
  73991. semiMinorAxis : createPropertyDescriptor('semiMinorAxis'),
  73992. /**
  73993. * Gets or sets the numeric property specifying the rotation of the ellipse clockwise from north.
  73994. * @memberof EllipseGraphics.prototype
  73995. * @type {Property}
  73996. * @default 0
  73997. */
  73998. rotation : createPropertyDescriptor('rotation'),
  73999. /**
  74000. * Gets or sets the boolean Property specifying the visibility of the ellipse.
  74001. * @memberof EllipseGraphics.prototype
  74002. * @type {Property}
  74003. * @default true
  74004. */
  74005. show : createPropertyDescriptor('show'),
  74006. /**
  74007. * Gets or sets the Property specifying the material used to fill the ellipse.
  74008. * @memberof EllipseGraphics.prototype
  74009. * @type {MaterialProperty}
  74010. * @default Color.WHITE
  74011. */
  74012. material : createMaterialPropertyDescriptor('material'),
  74013. /**
  74014. * Gets or sets the numeric Property specifying the altitude of the ellipse.
  74015. * @memberof EllipseGraphics.prototype
  74016. * @type {Property}
  74017. * @default 0.0
  74018. */
  74019. height : createPropertyDescriptor('height'),
  74020. /**
  74021. * Gets or sets the numeric Property specifying the altitude of the ellipse extrusion.
  74022. * Setting this property creates volume starting at height and ending at this altitude.
  74023. * @memberof EllipseGraphics.prototype
  74024. * @type {Property}
  74025. */
  74026. extrudedHeight : createPropertyDescriptor('extrudedHeight'),
  74027. /**
  74028. * Gets or sets the numeric Property specifying the angular distance between points on the ellipse.
  74029. * @memberof EllipseGraphics.prototype
  74030. * @type {Property}
  74031. * @default {CesiumMath.RADIANS_PER_DEGREE}
  74032. */
  74033. granularity : createPropertyDescriptor('granularity'),
  74034. /**
  74035. * Gets or sets the numeric property specifying the rotation of the ellipse texture counter-clockwise from north.
  74036. * @memberof EllipseGraphics.prototype
  74037. * @type {Property}
  74038. * @default 0
  74039. */
  74040. stRotation : createPropertyDescriptor('stRotation'),
  74041. /**
  74042. * Gets or sets the boolean Property specifying whether the ellipse is filled with the provided material.
  74043. * @memberof EllipseGraphics.prototype
  74044. * @type {Property}
  74045. * @default true
  74046. */
  74047. fill : createPropertyDescriptor('fill'),
  74048. /**
  74049. * Gets or sets the Property specifying whether the ellipse is outlined.
  74050. * @memberof EllipseGraphics.prototype
  74051. * @type {Property}
  74052. * @default false
  74053. */
  74054. outline : createPropertyDescriptor('outline'),
  74055. /**
  74056. * Gets or sets the Property specifying the {@link Color} of the outline.
  74057. * @memberof EllipseGraphics.prototype
  74058. * @type {Property}
  74059. * @default Color.BLACK
  74060. */
  74061. outlineColor : createPropertyDescriptor('outlineColor'),
  74062. /**
  74063. * Gets or sets the numeric Property specifying the width of the outline.
  74064. * @memberof EllipseGraphics.prototype
  74065. * @type {Property}
  74066. * @default 1.0
  74067. */
  74068. outlineWidth : createPropertyDescriptor('outlineWidth'),
  74069. /**
  74070. * Gets or sets the numeric Property specifying the number of vertical lines to draw along the perimeter for the outline.
  74071. * @memberof EllipseGraphics.prototype
  74072. * @type {Property}
  74073. * @default 16
  74074. */
  74075. numberOfVerticalLines : createPropertyDescriptor('numberOfVerticalLines'),
  74076. /**
  74077. * Get or sets the enum Property specifying whether the ellipse
  74078. * casts or receives shadows from each light source.
  74079. * @memberof EllipseGraphics.prototype
  74080. * @type {Property}
  74081. * @default ShadowMode.DISABLED
  74082. */
  74083. shadows : createPropertyDescriptor('shadows'),
  74084. /**
  74085. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this ellipse will be displayed.
  74086. * @memberof EllipseGraphics.prototype
  74087. * @type {Property}
  74088. */
  74089. distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition')
  74090. });
  74091. /**
  74092. * Duplicates this instance.
  74093. *
  74094. * @param {EllipseGraphics} [result] The object onto which to store the result.
  74095. * @returns {EllipseGraphics} The modified result parameter or a new instance if one was not provided.
  74096. */
  74097. EllipseGraphics.prototype.clone = function(result) {
  74098. if (!defined(result)) {
  74099. return new EllipseGraphics(this);
  74100. }
  74101. result.rotation = this.rotation;
  74102. result.semiMajorAxis = this.semiMajorAxis;
  74103. result.semiMinorAxis = this.semiMinorAxis;
  74104. result.show = this.show;
  74105. result.material = this.material;
  74106. result.height = this.height;
  74107. result.extrudedHeight = this.extrudedHeight;
  74108. result.granularity = this.granularity;
  74109. result.stRotation = this.stRotation;
  74110. result.fill = this.fill;
  74111. result.outline = this.outline;
  74112. result.outlineColor = this.outlineColor;
  74113. result.outlineWidth = this.outlineWidth;
  74114. result.numberOfVerticalLines = this.numberOfVerticalLines;
  74115. result.shadows = this.shadows;
  74116. result.distanceDisplayCondition = this.distanceDisplayCondition;
  74117. return result;
  74118. };
  74119. /**
  74120. * Assigns each unassigned property on this object to the value
  74121. * of the same property on the provided source object.
  74122. *
  74123. * @param {EllipseGraphics} source The object to be merged into this object.
  74124. */
  74125. EllipseGraphics.prototype.merge = function(source) {
  74126. if (!defined(source)) {
  74127. throw new DeveloperError('source is required.');
  74128. }
  74129. this.rotation = defaultValue(this.rotation, source.rotation);
  74130. this.semiMajorAxis = defaultValue(this.semiMajorAxis, source.semiMajorAxis);
  74131. this.semiMinorAxis = defaultValue(this.semiMinorAxis, source.semiMinorAxis);
  74132. this.show = defaultValue(this.show, source.show);
  74133. this.material = defaultValue(this.material, source.material);
  74134. this.height = defaultValue(this.height, source.height);
  74135. this.extrudedHeight = defaultValue(this.extrudedHeight, source.extrudedHeight);
  74136. this.granularity = defaultValue(this.granularity, source.granularity);
  74137. this.stRotation = defaultValue(this.stRotation, source.stRotation);
  74138. this.fill = defaultValue(this.fill, source.fill);
  74139. this.outline = defaultValue(this.outline, source.outline);
  74140. this.outlineColor = defaultValue(this.outlineColor, source.outlineColor);
  74141. this.outlineWidth = defaultValue(this.outlineWidth, source.outlineWidth);
  74142. this.numberOfVerticalLines = defaultValue(this.numberOfVerticalLines, source.numberOfVerticalLines);
  74143. this.shadows = defaultValue(this.shadows, source.shadows);
  74144. this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
  74145. };
  74146. return EllipseGraphics;
  74147. });
  74148. /*global define*/
  74149. define('DataSources/EllipsoidGraphics',[
  74150. '../Core/defaultValue',
  74151. '../Core/defined',
  74152. '../Core/defineProperties',
  74153. '../Core/DeveloperError',
  74154. '../Core/Event',
  74155. './createMaterialPropertyDescriptor',
  74156. './createPropertyDescriptor'
  74157. ], function(
  74158. defaultValue,
  74159. defined,
  74160. defineProperties,
  74161. DeveloperError,
  74162. Event,
  74163. createMaterialPropertyDescriptor,
  74164. createPropertyDescriptor) {
  74165. 'use strict';
  74166. /**
  74167. * Describe an ellipsoid or sphere. The center position and orientation are determined by the containing {@link Entity}.
  74168. *
  74169. * @alias EllipsoidGraphics
  74170. * @constructor
  74171. *
  74172. * @param {Object} [options] Object with the following properties:
  74173. * @param {Property} [options.radii] A {@link Cartesian3} Property specifying the radii of the ellipsoid.
  74174. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the ellipsoid.
  74175. * @param {Property} [options.fill=true] A boolean Property specifying whether the ellipsoid is filled with the provided material.
  74176. * @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to fill the ellipsoid.
  74177. * @param {Property} [options.outline=false] A boolean Property specifying whether the ellipsoid is outlined.
  74178. * @param {Property} [options.outlineColor=Color.BLACK] A Property specifying the {@link Color} of the outline.
  74179. * @param {Property} [options.outlineWidth=1.0] A numeric Property specifying the width of the outline.
  74180. * @param {Property} [options.subdivisions=128] A Property specifying the number of samples per outline ring, determining the granularity of the curvature.
  74181. * @param {Property} [options.stackPartitions=64] A Property specifying the number of stacks.
  74182. * @param {Property} [options.slicePartitions=64] A Property specifying the number of radial slices.
  74183. * @param {Property} [options.shadows=ShadowMode.DISABLED] An enum Property specifying whether the ellipsoid casts or receives shadows from each light source.
  74184. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this ellipsoid will be displayed.
  74185. *
  74186. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Spheres%20and%20Ellipsoids.html|Cesium Sandcastle Spheres and Ellipsoids Demo}
  74187. */
  74188. function EllipsoidGraphics(options) {
  74189. this._show = undefined;
  74190. this._showSubscription = undefined;
  74191. this._radii = undefined;
  74192. this._radiiSubscription = undefined;
  74193. this._material = undefined;
  74194. this._materialSubscription = undefined;
  74195. this._stackPartitions = undefined;
  74196. this._stackPartitionsSubscription = undefined;
  74197. this._slicePartitions = undefined;
  74198. this._slicePartitionsSubscription = undefined;
  74199. this._subdivisions = undefined;
  74200. this._subdivisionsSubscription = undefined;
  74201. this._fill = undefined;
  74202. this._fillSubscription = undefined;
  74203. this._outline = undefined;
  74204. this._outlineSubscription = undefined;
  74205. this._outlineColor = undefined;
  74206. this._outlineColorSubscription = undefined;
  74207. this._outlineWidth = undefined;
  74208. this._outlineWidthSubscription = undefined;
  74209. this._shadows = undefined;
  74210. this._shadowsSubscription = undefined;
  74211. this._distanceDisplayCondition = undefined;
  74212. this._distanceDisplayConditionSubscription = undefined;
  74213. this._definitionChanged = new Event();
  74214. this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
  74215. }
  74216. defineProperties(EllipsoidGraphics.prototype, {
  74217. /**
  74218. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  74219. * @memberof EllipsoidGraphics.prototype
  74220. *
  74221. * @type {Event}
  74222. * @readonly
  74223. */
  74224. definitionChanged : {
  74225. get : function() {
  74226. return this._definitionChanged;
  74227. }
  74228. },
  74229. /**
  74230. * Gets or sets the boolean Property specifying the visibility of the ellipsoid.
  74231. * @memberof EllipsoidGraphics.prototype
  74232. * @type {Property}
  74233. * @default true
  74234. */
  74235. show : createPropertyDescriptor('show'),
  74236. /**
  74237. * Gets or sets the {@link Cartesian3} {@link Property} specifying the radii of the ellipsoid.
  74238. * @memberof EllipsoidGraphics.prototype
  74239. * @type {Property}
  74240. */
  74241. radii : createPropertyDescriptor('radii'),
  74242. /**
  74243. * Gets or sets the Property specifying the material used to fill the ellipsoid.
  74244. * @memberof EllipsoidGraphics.prototype
  74245. * @type {MaterialProperty}
  74246. * @default Color.WHITE
  74247. */
  74248. material : createMaterialPropertyDescriptor('material'),
  74249. /**
  74250. * Gets or sets the boolean Property specifying whether the ellipsoid is filled with the provided material.
  74251. * @memberof EllipsoidGraphics.prototype
  74252. * @type {Property}
  74253. * @default true
  74254. */
  74255. fill : createPropertyDescriptor('fill'),
  74256. /**
  74257. * Gets or sets the Property specifying whether the ellipsoid is outlined.
  74258. * @memberof EllipsoidGraphics.prototype
  74259. * @type {Property}
  74260. * @default false
  74261. */
  74262. outline : createPropertyDescriptor('outline'),
  74263. /**
  74264. * Gets or sets the Property specifying the {@link Color} of the outline.
  74265. * @memberof EllipsoidGraphics.prototype
  74266. * @type {Property}
  74267. * @default Color.BLACK
  74268. */
  74269. outlineColor : createPropertyDescriptor('outlineColor'),
  74270. /**
  74271. * Gets or sets the numeric Property specifying the width of the outline.
  74272. * @memberof EllipsoidGraphics.prototype
  74273. * @type {Property}
  74274. * @default 1.0
  74275. */
  74276. outlineWidth : createPropertyDescriptor('outlineWidth'),
  74277. /**
  74278. * Gets or sets the Property specifying the number of stacks.
  74279. * @memberof EllipsoidGraphics.prototype
  74280. * @type {Property}
  74281. * @default 64
  74282. */
  74283. stackPartitions : createPropertyDescriptor('stackPartitions'),
  74284. /**
  74285. * Gets or sets the Property specifying the number of radial slices.
  74286. * @memberof EllipsoidGraphics.prototype
  74287. * @type {Property}
  74288. * @default 64
  74289. */
  74290. slicePartitions : createPropertyDescriptor('slicePartitions'),
  74291. /**
  74292. * Gets or sets the Property specifying the number of samples per outline ring, determining the granularity of the curvature.
  74293. * @memberof EllipsoidGraphics.prototype
  74294. * @type {Property}
  74295. * @default 128
  74296. */
  74297. subdivisions : createPropertyDescriptor('subdivisions'),
  74298. /**
  74299. * Get or sets the enum Property specifying whether the ellipsoid
  74300. * casts or receives shadows from each light source.
  74301. * @memberof EllipsoidGraphics.prototype
  74302. * @type {Property}
  74303. * @default ShadowMode.DISABLED
  74304. */
  74305. shadows : createPropertyDescriptor('shadows'),
  74306. /**
  74307. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this ellipsoid will be displayed.
  74308. * @memberof EllipsoidGraphics.prototype
  74309. * @type {Property}
  74310. */
  74311. distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition')
  74312. });
  74313. /**
  74314. * Duplicates this instance.
  74315. *
  74316. * @param {EllipsoidGraphics} [result] The object onto which to store the result.
  74317. * @returns {EllipsoidGraphics} The modified result parameter or a new instance if one was not provided.
  74318. */
  74319. EllipsoidGraphics.prototype.clone = function(result) {
  74320. if (!defined(result)) {
  74321. return new EllipsoidGraphics(this);
  74322. }
  74323. result.show = this.show;
  74324. result.radii = this.radii;
  74325. result.material = this.material;
  74326. result.fill = this.fill;
  74327. result.outline = this.outline;
  74328. result.outlineColor = this.outlineColor;
  74329. result.outlineWidth = this.outlineWidth;
  74330. result.stackPartitions = this.stackPartitions;
  74331. result.slicePartitions = this.slicePartitions;
  74332. result.subdivisions = this.subdivisions;
  74333. result.shadows = this.shadows;
  74334. result.distanceDisplayCondition = this.distanceDisplayCondition;
  74335. return result;
  74336. };
  74337. /**
  74338. * Assigns each unassigned property on this object to the value
  74339. * of the same property on the provided source object.
  74340. *
  74341. * @param {EllipsoidGraphics} source The object to be merged into this object.
  74342. */
  74343. EllipsoidGraphics.prototype.merge = function(source) {
  74344. if (!defined(source)) {
  74345. throw new DeveloperError('source is required.');
  74346. }
  74347. this.show = defaultValue(this.show, source.show);
  74348. this.radii = defaultValue(this.radii, source.radii);
  74349. this.material = defaultValue(this.material, source.material);
  74350. this.fill = defaultValue(this.fill, source.fill);
  74351. this.outline = defaultValue(this.outline, source.outline);
  74352. this.outlineColor = defaultValue(this.outlineColor, source.outlineColor);
  74353. this.outlineWidth = defaultValue(this.outlineWidth, source.outlineWidth);
  74354. this.stackPartitions = defaultValue(this.stackPartitions, source.stackPartitions);
  74355. this.slicePartitions = defaultValue(this.slicePartitions, source.slicePartitions);
  74356. this.subdivisions = defaultValue(this.subdivisions, source.subdivisions);
  74357. this.shadows = defaultValue(this.shadows, source.shadows);
  74358. this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
  74359. };
  74360. return EllipsoidGraphics;
  74361. });
  74362. /*global define*/
  74363. define('DataSources/LabelGraphics',[
  74364. '../Core/defaultValue',
  74365. '../Core/defined',
  74366. '../Core/defineProperties',
  74367. '../Core/DeveloperError',
  74368. '../Core/Event',
  74369. './createPropertyDescriptor'
  74370. ], function(
  74371. defaultValue,
  74372. defined,
  74373. defineProperties,
  74374. DeveloperError,
  74375. Event,
  74376. createPropertyDescriptor) {
  74377. 'use strict';
  74378. /**
  74379. * Describes a two dimensional label located at the position of the containing {@link Entity}.
  74380. * <p>
  74381. * <div align='center'>
  74382. * <img src='images/Label.png' width='400' height='300' /><br />
  74383. * Example labels
  74384. * </div>
  74385. * </p>
  74386. *
  74387. * @alias LabelGraphics
  74388. * @constructor
  74389. *
  74390. * @param {Object} [options] Object with the following properties:
  74391. * @param {Property} [options.text] A Property specifying the text. Explicit newlines '\n' are supported.
  74392. * @param {Property} [options.font='10px sans-serif'] A Property specifying the CSS font.
  74393. * @param {Property} [options.style=LabelStyle.FILL] A Property specifying the {@link LabelStyle}.
  74394. * @param {Property} [options.fillColor=Color.WHITE] A Property specifying the fill {@link Color}.
  74395. * @param {Property} [options.outlineColor=Color.BLACK] A Property specifying the outline {@link Color}.
  74396. * @param {Property} [options.outlineWidth=1.0] A numeric Property specifying the outline width.
  74397. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the label.
  74398. * @param {Property} [options.showBackground=false] A boolean Property specifying the visibility of the background behind the label.
  74399. * @param {Property} [options.backgroundColor=new Color(0.165, 0.165, 0.165, 0.8)] A Property specifying the background {@link Color}.
  74400. * @param {Property} [options.backgroundPadding=new Cartesian2(7, 5)] A {@link Cartesian2} Property specifying the horizontal and vertical background padding in pixels.
  74401. * @param {Property} [options.scale=1.0] A numeric Property specifying the scale to apply to the text.
  74402. * @param {Property} [options.horizontalOrigin=HorizontalOrigin.CENTER] A Property specifying the {@link HorizontalOrigin}.
  74403. * @param {Property} [options.verticalOrigin=VerticalOrigin.CENTER] A Property specifying the {@link VerticalOrigin}.
  74404. * @param {Property} [options.eyeOffset=Cartesian3.ZERO] A {@link Cartesian3} Property specifying the eye offset.
  74405. * @param {Property} [options.pixelOffset=Cartesian2.ZERO] A {@link Cartesian2} Property specifying the pixel offset.
  74406. * @param {Property} [options.translucencyByDistance] A {@link NearFarScalar} Property used to set translucency based on distance from the camera.
  74407. * @param {Property} [options.pixelOffsetScaleByDistance] A {@link NearFarScalar} Property used to set pixelOffset based on distance from the camera.
  74408. * @param {Property} [options.heightReference=HeightReference.NONE] A Property specifying what the height is relative to.
  74409. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this label will be displayed.
  74410. *
  74411. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Labels.html|Cesium Sandcastle Labels Demo}
  74412. */
  74413. function LabelGraphics(options) {
  74414. this._text = undefined;
  74415. this._textSubscription = undefined;
  74416. this._font = undefined;
  74417. this._fontSubscription = undefined;
  74418. this._style = undefined;
  74419. this._styleSubscription = undefined;
  74420. this._fillColor = undefined;
  74421. this._fillColorSubscription = undefined;
  74422. this._outlineColor = undefined;
  74423. this._outlineColorSubscription = undefined;
  74424. this._outlineWidth = undefined;
  74425. this._outlineWidthSubscription = undefined;
  74426. this._horizontalOrigin = undefined;
  74427. this._horizontalOriginSubscription = undefined;
  74428. this._verticalOrigin = undefined;
  74429. this._verticalOriginSubscription = undefined;
  74430. this._eyeOffset = undefined;
  74431. this._eyeOffsetSubscription = undefined;
  74432. this._heightReference = undefined;
  74433. this._heightReferenceSubscription = undefined;
  74434. this._pixelOffset = undefined;
  74435. this._pixelOffsetSubscription = undefined;
  74436. this._scale = undefined;
  74437. this._scaleSubscription = undefined;
  74438. this._show = undefined;
  74439. this._showSubscription = undefined;
  74440. this._showBackground = undefined;
  74441. this._showBackgroundSubscription = undefined;
  74442. this._backgroundColor = undefined;
  74443. this._backgroundColorSubscription = undefined;
  74444. this._backgroundPadding = undefined;
  74445. this._backgroundPaddingSubscription = undefined;
  74446. this._translucencyByDistance = undefined;
  74447. this._translucencyByDistanceSubscription = undefined;
  74448. this._pixelOffsetScaleByDistance = undefined;
  74449. this._pixelOffsetScaleByDistanceSubscription = undefined;
  74450. this._distanceDisplayCondition = undefined;
  74451. this._distanceDisplayConditionSubscription = undefined;
  74452. this._definitionChanged = new Event();
  74453. this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
  74454. }
  74455. defineProperties(LabelGraphics.prototype, {
  74456. /**
  74457. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  74458. * @memberof LabelGraphics.prototype
  74459. *
  74460. * @type {Event}
  74461. * @readonly
  74462. */
  74463. definitionChanged : {
  74464. get : function() {
  74465. return this._definitionChanged;
  74466. }
  74467. },
  74468. /**
  74469. * Gets or sets the string Property specifying the text of the label.
  74470. * Explicit newlines '\n' are supported.
  74471. * @memberof LabelGraphics.prototype
  74472. * @type {Property}
  74473. */
  74474. text : createPropertyDescriptor('text'),
  74475. /**
  74476. * Gets or sets the string Property specifying the font in CSS syntax.
  74477. * @memberof LabelGraphics.prototype
  74478. * @type {Property}
  74479. * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/font|CSS font on MDN}
  74480. */
  74481. font : createPropertyDescriptor('font'),
  74482. /**
  74483. * Gets or sets the Property specifying the {@link LabelStyle}.
  74484. * @memberof LabelGraphics.prototype
  74485. * @type {Property}
  74486. */
  74487. style : createPropertyDescriptor('style'),
  74488. /**
  74489. * Gets or sets the Property specifying the fill {@link Color}.
  74490. * @memberof LabelGraphics.prototype
  74491. * @type {Property}
  74492. */
  74493. fillColor : createPropertyDescriptor('fillColor'),
  74494. /**
  74495. * Gets or sets the Property specifying the outline {@link Color}.
  74496. * @memberof LabelGraphics.prototype
  74497. * @type {Property}
  74498. */
  74499. outlineColor : createPropertyDescriptor('outlineColor'),
  74500. /**
  74501. * Gets or sets the numeric Property specifying the outline width.
  74502. * @memberof LabelGraphics.prototype
  74503. * @type {Property}
  74504. */
  74505. outlineWidth : createPropertyDescriptor('outlineWidth'),
  74506. /**
  74507. * Gets or sets the Property specifying the {@link HorizontalOrigin}.
  74508. * @memberof LabelGraphics.prototype
  74509. * @type {Property}
  74510. */
  74511. horizontalOrigin : createPropertyDescriptor('horizontalOrigin'),
  74512. /**
  74513. * Gets or sets the Property specifying the {@link VerticalOrigin}.
  74514. * @memberof LabelGraphics.prototype
  74515. * @type {Property}
  74516. */
  74517. verticalOrigin : createPropertyDescriptor('verticalOrigin'),
  74518. /**
  74519. * Gets or sets the {@link Cartesian3} Property specifying the label's offset in eye coordinates.
  74520. * Eye coordinates is a left-handed coordinate system, where <code>x</code> points towards the viewer's
  74521. * right, <code>y</code> points up, and <code>z</code> points into the screen.
  74522. * <p>
  74523. * An eye offset is commonly used to arrange multiple labels or objects at the same position, e.g., to
  74524. * arrange a label above its corresponding 3D model.
  74525. * </p>
  74526. * Below, the label is positioned at the center of the Earth but an eye offset makes it always
  74527. * appear on top of the Earth regardless of the viewer's or Earth's orientation.
  74528. * <p>
  74529. * <div align='center'>
  74530. * <table border='0' cellpadding='5'><tr>
  74531. * <td align='center'><img src='images/Billboard.setEyeOffset.one.png' width='250' height='188' /></td>
  74532. * <td align='center'><img src='images/Billboard.setEyeOffset.two.png' width='250' height='188' /></td>
  74533. * </tr></table>
  74534. * <code>l.eyeOffset = new Cartesian3(0.0, 8000000.0, 0.0);</code><br /><br />
  74535. * </div>
  74536. * </p>
  74537. * @memberof LabelGraphics.prototype
  74538. * @type {Property}
  74539. * @default Cartesian3.ZERO
  74540. */
  74541. eyeOffset : createPropertyDescriptor('eyeOffset'),
  74542. /**
  74543. * Gets or sets the Property specifying the {@link HeightReference}.
  74544. * @memberof LabelGraphics.prototype
  74545. * @type {Property}
  74546. * @default HeightReference.NONE
  74547. */
  74548. heightReference : createPropertyDescriptor('heightReference'),
  74549. /**
  74550. * Gets or sets the {@link Cartesian2} Property specifying the label's pixel offset in screen space
  74551. * from the origin of this label. This is commonly used to align multiple labels and labels at
  74552. * the same position, e.g., an image and text. The screen space origin is the top, left corner of the
  74553. * canvas; <code>x</code> increases from left to right, and <code>y</code> increases from top to bottom.
  74554. * <p>
  74555. * <div align='center'>
  74556. * <table border='0' cellpadding='5'><tr>
  74557. * <td align='center'><code>default</code><br/><img src='images/Label.setPixelOffset.default.png' width='250' height='188' /></td>
  74558. * <td align='center'><code>l.pixeloffset = new Cartesian2(25, 75);</code><br/><img src='images/Label.setPixelOffset.x50y-25.png' width='250' height='188' /></td>
  74559. * </tr></table>
  74560. * The label's origin is indicated by the yellow point.
  74561. * </div>
  74562. * </p>
  74563. * @memberof LabelGraphics.prototype
  74564. * @type {Property}
  74565. * @default Cartesian2.ZERO
  74566. */
  74567. pixelOffset : createPropertyDescriptor('pixelOffset'),
  74568. /**
  74569. * Gets or sets the numeric Property specifying the uniform scale to apply to the image.
  74570. * A scale greater than <code>1.0</code> enlarges the label while a scale less than <code>1.0</code> shrinks it.
  74571. * <p>
  74572. * <div align='center'>
  74573. * <img src='images/Label.setScale.png' width='400' height='300' /><br/>
  74574. * From left to right in the above image, the scales are <code>0.5</code>, <code>1.0</code>,
  74575. * and <code>2.0</code>.
  74576. * </div>
  74577. * </p>
  74578. * @memberof LabelGraphics.prototype
  74579. * @type {Property}
  74580. * @default 1.0
  74581. */
  74582. scale : createPropertyDescriptor('scale'),
  74583. /**
  74584. * Gets or sets the boolean Property specifying the visibility of the label.
  74585. * @memberof LabelGraphics.prototype
  74586. * @type {Property}
  74587. */
  74588. show : createPropertyDescriptor('show'),
  74589. /**
  74590. * Gets or sets the boolean Property specifying the visibility of the background behind the label.
  74591. * @memberof LabelGraphics.prototype
  74592. * @type {Property}
  74593. * @default false
  74594. */
  74595. showBackground : createPropertyDescriptor('showBackground'),
  74596. /**
  74597. * Gets or sets the Property specifying the background {@link Color}.
  74598. * @memberof LabelGraphics.prototype
  74599. * @type {Property}
  74600. * @default new Color(0.165, 0.165, 0.165, 0.8)
  74601. */
  74602. backgroundColor : createPropertyDescriptor('backgroundColor'),
  74603. /**
  74604. * Gets or sets the {@link Cartesian2} Property specifying the label's horizontal and vertical
  74605. * background padding in pixels.
  74606. * @memberof LabelGraphics.prototype
  74607. * @type {Property}
  74608. * @default new Cartesian2(7, 5)
  74609. */
  74610. backgroundPadding : createPropertyDescriptor('backgroundPadding'),
  74611. /**
  74612. * Gets or sets {@link NearFarScalar} Property specifying the translucency of the label based on the distance from the camera.
  74613. * A label's translucency will interpolate between the {@link NearFarScalar#nearValue} and
  74614. * {@link NearFarScalar#farValue} while the camera distance falls within the upper and lower bounds
  74615. * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
  74616. * Outside of these ranges the label's translucency remains clamped to the nearest bound.
  74617. * @memberof LabelGraphics.prototype
  74618. * @type {Property}
  74619. */
  74620. translucencyByDistance : createPropertyDescriptor('translucencyByDistance'),
  74621. /**
  74622. * Gets or sets {@link NearFarScalar} Property specifying the pixel offset of the label based on the distance from the camera.
  74623. * A label's pixel offset will interpolate between the {@link NearFarScalar#nearValue} and
  74624. * {@link NearFarScalar#farValue} while the camera distance falls within the upper and lower bounds
  74625. * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
  74626. * Outside of these ranges the label's pixel offset remains clamped to the nearest bound.
  74627. * @memberof LabelGraphics.prototype
  74628. * @type {Property}
  74629. */
  74630. pixelOffsetScaleByDistance : createPropertyDescriptor('pixelOffsetScaleByDistance'),
  74631. /**
  74632. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this label will be displayed.
  74633. * @memberof LabelGraphics.prototype
  74634. * @type {Property}
  74635. */
  74636. distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition')
  74637. });
  74638. /**
  74639. * Duplicates this instance.
  74640. *
  74641. * @param {LabelGraphics} [result] The object onto which to store the result.
  74642. * @returns {LabelGraphics} The modified result parameter or a new instance if one was not provided.
  74643. */
  74644. LabelGraphics.prototype.clone = function(result) {
  74645. if (!defined(result)) {
  74646. return new LabelGraphics(this);
  74647. }
  74648. result.text = this.text;
  74649. result.font = this.font;
  74650. result.show = this.show;
  74651. result.style = this.style;
  74652. result.fillColor = this.fillColor;
  74653. result.outlineColor = this.outlineColor;
  74654. result.outlineWidth = this.outlineWidth;
  74655. result.showBackground = this.showBackground;
  74656. result.backgroundColor = this.backgroundColor;
  74657. result.backgroundPadding = this.backgroundPadding;
  74658. result.scale = this.scale;
  74659. result.horizontalOrigin = this.horizontalOrigin;
  74660. result.verticalOrigin = this.verticalOrigin;
  74661. result.eyeOffset = this.eyeOffset;
  74662. result.heightReference = this.heightReference;
  74663. result.pixelOffset = this.pixelOffset;
  74664. result.translucencyByDistance = this.translucencyByDistance;
  74665. result.pixelOffsetScaleByDistance = this.pixelOffsetScaleByDistance;
  74666. result.distanceDisplayCondition = this.distanceDisplayCondition;
  74667. return result;
  74668. };
  74669. /**
  74670. * Assigns each unassigned property on this object to the value
  74671. * of the same property on the provided source object.
  74672. *
  74673. * @param {LabelGraphics} source The object to be merged into this object.
  74674. */
  74675. LabelGraphics.prototype.merge = function(source) {
  74676. if (!defined(source)) {
  74677. throw new DeveloperError('source is required.');
  74678. }
  74679. this.text = defaultValue(this.text, source.text);
  74680. this.font = defaultValue(this.font, source.font);
  74681. this.show = defaultValue(this.show, source.show);
  74682. this.style = defaultValue(this.style, source.style);
  74683. this.fillColor = defaultValue(this.fillColor, source.fillColor);
  74684. this.outlineColor = defaultValue(this.outlineColor, source.outlineColor);
  74685. this.outlineWidth = defaultValue(this.outlineWidth, source.outlineWidth);
  74686. this.showBackground = defaultValue(this.showBackground, source.showBackground);
  74687. this.backgroundColor = defaultValue(this.backgroundColor, source.backgroundColor);
  74688. this.backgroundPadding = defaultValue(this.backgroundPadding, source.backgroundPadding);
  74689. this.scale = defaultValue(this.scale, source.scale);
  74690. this.horizontalOrigin = defaultValue(this.horizontalOrigin, source.horizontalOrigin);
  74691. this.verticalOrigin = defaultValue(this.verticalOrigin, source.verticalOrigin);
  74692. this.eyeOffset = defaultValue(this.eyeOffset, source.eyeOffset);
  74693. this.heightReference = defaultValue(this.heightReference, source.heightReference);
  74694. this.pixelOffset = defaultValue(this.pixelOffset, source.pixelOffset);
  74695. this.translucencyByDistance = defaultValue(this._translucencyByDistance, source.translucencyByDistance);
  74696. this.pixelOffsetScaleByDistance = defaultValue(this._pixelOffsetScaleByDistance, source.pixelOffsetScaleByDistance);
  74697. this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
  74698. };
  74699. return LabelGraphics;
  74700. });
  74701. /*global define*/
  74702. define('DataSources/NodeTransformationProperty',[
  74703. '../Core/defaultValue',
  74704. '../Core/defined',
  74705. '../Core/defineProperties',
  74706. '../Core/Event',
  74707. '../Core/TranslationRotationScale',
  74708. './createPropertyDescriptor',
  74709. './Property'
  74710. ], function(
  74711. defaultValue,
  74712. defined,
  74713. defineProperties,
  74714. Event,
  74715. TranslationRotationScale,
  74716. createPropertyDescriptor,
  74717. Property) {
  74718. 'use strict';
  74719. var defaultNodeTransformation = new TranslationRotationScale();
  74720. /**
  74721. * A {@link Property} that produces {@link TranslationRotationScale} data.
  74722. * @alias NodeTransformationProperty
  74723. * @constructor
  74724. *
  74725. * @param {Object} [options] Object with the following properties:
  74726. * @param {Property} [options.translation=Cartesian3.ZERO] A {@link Cartesian3} Property specifying the (x, y, z) translation to apply to the node.
  74727. * @param {Property} [options.rotation=Quaternion.IDENTITY] A {@link Quaternion} Property specifying the (x, y, z, w) rotation to apply to the node.
  74728. * @param {Property} [options.scale=new Cartesian3(1.0, 1.0, 1.0)] A {@link Cartesian3} Property specifying the (x, y, z) scaling to apply to the node.
  74729. */
  74730. var NodeTransformationProperty = function(options) {
  74731. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  74732. this._definitionChanged = new Event();
  74733. this._translation = undefined;
  74734. this._translationSubscription = undefined;
  74735. this._rotation = undefined;
  74736. this._rotationSubscription = undefined;
  74737. this._scale = undefined;
  74738. this._scaleSubscription = undefined;
  74739. this.translation = options.translation;
  74740. this.rotation = options.rotation;
  74741. this.scale = options.scale;
  74742. };
  74743. defineProperties(NodeTransformationProperty.prototype, {
  74744. /**
  74745. * Gets a value indicating if this property is constant. A property is considered
  74746. * constant if getValue always returns the same result for the current definition.
  74747. * @memberof NodeTransformationProperty.prototype
  74748. *
  74749. * @type {Boolean}
  74750. * @readonly
  74751. */
  74752. isConstant : {
  74753. get : function() {
  74754. return Property.isConstant(this._translation) &&
  74755. Property.isConstant(this._rotation) &&
  74756. Property.isConstant(this._scale);
  74757. }
  74758. },
  74759. /**
  74760. * Gets the event that is raised whenever the definition of this property changes.
  74761. * The definition is considered to have changed if a call to getValue would return
  74762. * a different result for the same time.
  74763. * @memberof NodeTransformationProperty.prototype
  74764. *
  74765. * @type {Event}
  74766. * @readonly
  74767. */
  74768. definitionChanged : {
  74769. get : function() {
  74770. return this._definitionChanged;
  74771. }
  74772. },
  74773. /**
  74774. * Gets or sets the {@link Cartesian3} Property specifying the (x, y, z) translation to apply to the node.
  74775. * @memberof NodeTransformationProperty.prototype
  74776. * @type {Property}
  74777. * @default Cartesian3.ZERO
  74778. */
  74779. translation : createPropertyDescriptor('translation'),
  74780. /**
  74781. * Gets or sets the {@link Quaternion} Property specifying the (x, y, z, w) rotation to apply to the node.
  74782. * @memberof NodeTransformationProperty.prototype
  74783. * @type {Property}
  74784. * @default Quaternion.IDENTITY
  74785. */
  74786. rotation : createPropertyDescriptor('rotation'),
  74787. /**
  74788. * Gets or sets the {@link Cartesian3} Property specifying the (x, y, z) scaling to apply to the node.
  74789. * @memberof NodeTransformationProperty.prototype
  74790. * @type {Property}
  74791. * @default new Cartesian3(1.0, 1.0, 1.0)
  74792. */
  74793. scale : createPropertyDescriptor('scale')
  74794. });
  74795. /**
  74796. * Gets the value of the property at the provided time.
  74797. *
  74798. * @param {JulianDate} time The time for which to retrieve the value.
  74799. * @param {TranslationRotationScale} [result] The object to store the value into, if omitted, a new instance is created and returned.
  74800. * @returns {TranslationRotationScale} The modified result parameter or a new instance if the result parameter was not supplied.
  74801. */
  74802. NodeTransformationProperty.prototype.getValue = function(time, result) {
  74803. if (!defined(result)) {
  74804. result = new TranslationRotationScale();
  74805. }
  74806. result.translation = Property.getValueOrClonedDefault(this._translation, time, defaultNodeTransformation.translation, result.translation);
  74807. result.rotation = Property.getValueOrClonedDefault(this._rotation, time, defaultNodeTransformation.rotation, result.rotation);
  74808. result.scale = Property.getValueOrClonedDefault(this._scale, time, defaultNodeTransformation.scale, result.scale);
  74809. return result;
  74810. };
  74811. /**
  74812. * Compares this property to the provided property and returns
  74813. * <code>true</code> if they are equal, <code>false</code> otherwise.
  74814. *
  74815. * @param {Property} [other] The other property.
  74816. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  74817. */
  74818. NodeTransformationProperty.prototype.equals = function(other) {
  74819. return this === other ||
  74820. (other instanceof NodeTransformationProperty &&
  74821. Property.equals(this._translation, other._translation) &&
  74822. Property.equals(this._rotation, other._rotation) &&
  74823. Property.equals(this._scale, other._scale));
  74824. };
  74825. return NodeTransformationProperty;
  74826. });
  74827. /*global define*/
  74828. define('DataSources/PropertyBag',[
  74829. '../Core/defaultValue',
  74830. '../Core/defined',
  74831. '../Core/defineProperties',
  74832. '../Core/DeveloperError',
  74833. '../Core/Event',
  74834. './ConstantProperty',
  74835. './createPropertyDescriptor',
  74836. './Property'
  74837. ], function(
  74838. defaultValue,
  74839. defined,
  74840. defineProperties,
  74841. DeveloperError,
  74842. Event,
  74843. ConstantProperty,
  74844. createPropertyDescriptor,
  74845. Property) {
  74846. 'use strict';
  74847. /**
  74848. * A {@link Property} whose value is a key-value mapping of property names to the computed value of other properties.
  74849. *
  74850. * @alias PropertyBag
  74851. * @constructor
  74852. *
  74853. * @param {Object} [value] An object, containing key-value mapping of property names to properties.
  74854. * @param {Function} [createPropertyCallback] A function that will be called when the value of any of the properties in value are not a Property.
  74855. */
  74856. var PropertyBag = function(value, createPropertyCallback) {
  74857. this._propertyNames = [];
  74858. this._definitionChanged = new Event();
  74859. if (defined(value)) {
  74860. this.merge(value, createPropertyCallback);
  74861. }
  74862. };
  74863. defineProperties(PropertyBag.prototype, {
  74864. /**
  74865. * Gets the names of all properties registered on this instance.
  74866. * @memberof PropertyBag.prototype
  74867. * @type {Array}
  74868. */
  74869. propertyNames : {
  74870. get : function() {
  74871. return this._propertyNames;
  74872. }
  74873. },
  74874. /**
  74875. * Gets a value indicating if this property is constant. This property
  74876. * is considered constant if all property items in this object are constant.
  74877. * @memberof PropertyBag.prototype
  74878. *
  74879. * @type {Boolean}
  74880. * @readonly
  74881. */
  74882. isConstant : {
  74883. get : function() {
  74884. var propertyNames = this._propertyNames;
  74885. for (var i = 0, len = propertyNames.length; i < len; i++) {
  74886. if (!Property.isConstant(this[propertyNames[i]])) {
  74887. return false;
  74888. }
  74889. }
  74890. return true;
  74891. }
  74892. },
  74893. /**
  74894. * Gets the event that is raised whenever the set of properties contained in this
  74895. * object changes, or one of the properties itself changes.
  74896. *
  74897. * @memberof PropertyBag.prototype
  74898. *
  74899. * @type {Event}
  74900. * @readonly
  74901. */
  74902. definitionChanged : {
  74903. get : function() {
  74904. return this._definitionChanged;
  74905. }
  74906. }
  74907. });
  74908. /**
  74909. * Determines if this object has defined a property with the given name.
  74910. *
  74911. * @param {String} propertyName The name of the property to check for.
  74912. *
  74913. * @returns {Boolean} True if this object has defined a property with the given name, false otherwise.
  74914. */
  74915. PropertyBag.prototype.hasProperty = function(propertyName) {
  74916. return this._propertyNames.indexOf(propertyName) !== -1;
  74917. };
  74918. function createConstantProperty(value) {
  74919. return new ConstantProperty(value);
  74920. }
  74921. /**
  74922. * Adds a property to this object.
  74923. *
  74924. * @param {String} propertyName The name of the property to add.
  74925. * @param {Any} [value] The value of the new property, if provided.
  74926. * @param {Function} [createPropertyCallback] A function that will be called when the value of this new property is set to a value that is not a Property.
  74927. *
  74928. * @exception {DeveloperError} "propertyName" is already a registered property.
  74929. */
  74930. PropertyBag.prototype.addProperty = function(propertyName, value, createPropertyCallback) {
  74931. var propertyNames = this._propertyNames;
  74932. if (!defined(propertyName)) {
  74933. throw new DeveloperError('propertyName is required.');
  74934. }
  74935. if (propertyNames.indexOf(propertyName) !== -1) {
  74936. throw new DeveloperError(propertyName + ' is already a registered property.');
  74937. }
  74938. propertyNames.push(propertyName);
  74939. Object.defineProperty(this, propertyName, createPropertyDescriptor(propertyName, true, defaultValue(createPropertyCallback, createConstantProperty)));
  74940. if (defined(value)) {
  74941. this[propertyName] = value;
  74942. }
  74943. this._definitionChanged.raiseEvent(this);
  74944. };
  74945. /**
  74946. * Removed a property previously added with addProperty.
  74947. *
  74948. * @param {String} propertyName The name of the property to remove.
  74949. *
  74950. * @exception {DeveloperError} "propertyName" is not a registered property.
  74951. */
  74952. PropertyBag.prototype.removeProperty = function(propertyName) {
  74953. var propertyNames = this._propertyNames;
  74954. var index = propertyNames.indexOf(propertyName);
  74955. if (!defined(propertyName)) {
  74956. throw new DeveloperError('propertyName is required.');
  74957. }
  74958. if (index === -1) {
  74959. throw new DeveloperError(propertyName + ' is not a registered property.');
  74960. }
  74961. this._propertyNames.splice(index, 1);
  74962. delete this[propertyName];
  74963. this._definitionChanged.raiseEvent(this);
  74964. };
  74965. /**
  74966. * Gets the value of this property. Each contained property will be evaluated at the given time, and the overall
  74967. * result will be an object, mapping property names to those values.
  74968. *
  74969. * @param {JulianDate} time The time for which to retrieve the value.
  74970. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  74971. * Note that any properties in result which are not part of this PropertyBag will be left as-is.
  74972. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  74973. */
  74974. PropertyBag.prototype.getValue = function(time, result) {
  74975. if (!defined(time)) {
  74976. throw new DeveloperError('time is required.');
  74977. }
  74978. if (!defined(result)) {
  74979. result = {};
  74980. }
  74981. var propertyNames = this._propertyNames;
  74982. for (var i = 0, len = propertyNames.length; i < len; i++) {
  74983. var propertyName = propertyNames[i];
  74984. result[propertyName] = Property.getValueOrUndefined(this[propertyName], time, result[propertyName]);
  74985. }
  74986. return result;
  74987. };
  74988. /**
  74989. * Assigns each unassigned property on this object to the value
  74990. * of the same property on the provided source object.
  74991. *
  74992. * @param {Object} source The object to be merged into this object.
  74993. * @param {Function} [createPropertyCallback] A function that will be called when the value of any of the properties in value are not a Property.
  74994. */
  74995. PropertyBag.prototype.merge = function(source, createPropertyCallback) {
  74996. if (!defined(source)) {
  74997. throw new DeveloperError('source is required.');
  74998. }
  74999. var propertyNames = this._propertyNames;
  75000. var sourcePropertyNames = defined(source._propertyNames) ? source._propertyNames : Object.keys(source);
  75001. for (var i = 0, len = sourcePropertyNames.length; i < len; i++) {
  75002. var name = sourcePropertyNames[i];
  75003. var targetProperty = this[name];
  75004. var sourceProperty = source[name];
  75005. //Custom properties that are registered on the source must also be added to this.
  75006. if (!defined(targetProperty) && propertyNames.indexOf(name) === -1) {
  75007. this.addProperty(name, undefined, createPropertyCallback);
  75008. }
  75009. if (defined(sourceProperty)) {
  75010. if (defined(targetProperty)) {
  75011. if (defined(targetProperty.merge)) {
  75012. targetProperty.merge(sourceProperty);
  75013. }
  75014. } else if (defined(sourceProperty.merge) && defined(sourceProperty.clone)) {
  75015. this[name] = sourceProperty.clone();
  75016. } else {
  75017. this[name] = sourceProperty;
  75018. }
  75019. }
  75020. }
  75021. };
  75022. function propertiesEqual(a, b) {
  75023. var aPropertyNames = a._propertyNames;
  75024. var bPropertyNames = b._propertyNames;
  75025. var len = aPropertyNames.length;
  75026. if (len !== bPropertyNames.length) {
  75027. return false;
  75028. }
  75029. for (var aIndex = 0; aIndex < len; ++aIndex) {
  75030. var name = aPropertyNames[aIndex];
  75031. var bIndex = bPropertyNames.indexOf(name);
  75032. if (bIndex === -1) {
  75033. return false;
  75034. }
  75035. if (!Property.equals(a[name], b[name])) {
  75036. return false;
  75037. }
  75038. }
  75039. return true;
  75040. }
  75041. /**
  75042. * Compares this property to the provided property and returns
  75043. * <code>true</code> if they are equal, <code>false</code> otherwise.
  75044. *
  75045. * @param {Property} [other] The other property.
  75046. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  75047. */
  75048. PropertyBag.prototype.equals = function(other) {
  75049. return this === other || //
  75050. (other instanceof PropertyBag && //
  75051. propertiesEqual(this, other));
  75052. };
  75053. return PropertyBag;
  75054. });
  75055. /*global define*/
  75056. define('DataSources/ModelGraphics',[
  75057. '../Core/defaultValue',
  75058. '../Core/defined',
  75059. '../Core/defineProperties',
  75060. '../Core/DeveloperError',
  75061. '../Core/Event',
  75062. './createPropertyDescriptor',
  75063. './NodeTransformationProperty',
  75064. './PropertyBag'
  75065. ], function(
  75066. defaultValue,
  75067. defined,
  75068. defineProperties,
  75069. DeveloperError,
  75070. Event,
  75071. createPropertyDescriptor,
  75072. NodeTransformationProperty,
  75073. PropertyBag) {
  75074. 'use strict';
  75075. function createNodeTransformationProperty(value) {
  75076. return new NodeTransformationProperty(value);
  75077. }
  75078. function createNodeTransformationPropertyBag(value) {
  75079. return new PropertyBag(value, createNodeTransformationProperty);
  75080. }
  75081. /**
  75082. * A 3D model based on {@link https://github.com/KhronosGroup/glTF|glTF}, the runtime asset format for WebGL, OpenGL ES, and OpenGL.
  75083. * The position and orientation of the model is determined by the containing {@link Entity}.
  75084. * <p>
  75085. * Cesium includes support for glTF geometry, materials, animations, and skinning.
  75086. * Cameras and lights are not currently supported.
  75087. * </p>
  75088. *
  75089. * @alias ModelGraphics
  75090. * @constructor
  75091. *
  75092. * @param {Object} [options] Object with the following properties:
  75093. * @param {Property} [options.uri] A string Property specifying the URI of the glTF asset.
  75094. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the model.
  75095. * @param {Property} [options.scale=1.0] A numeric Property specifying a uniform linear scale.
  75096. * @param {Property} [options.minimumPixelSize=0.0] A numeric Property specifying the approximate minimum pixel size of the model regardless of zoom.
  75097. * @param {Property} [options.maximumScale] The maximum scale size of a model. An upper limit for minimumPixelSize.
  75098. * @param {Property} [options.incrementallyLoadTextures=true] Determine if textures may continue to stream in after the model is loaded.
  75099. * @param {Property} [options.runAnimations=true] A boolean Property specifying if glTF animations specified in the model should be started.
  75100. * @param {Property} [options.nodeTransformations] An object, where keys are names of nodes, and values are {@link TranslationRotationScale} Properties describing the transformation to apply to that node.
  75101. * @param {Property} [options.shadows=ShadowMode.ENABLED] An enum Property specifying whether the model casts or receives shadows from each light source.
  75102. * @param {Property} [options.heightReference=HeightReference.NONE] A Property specifying what the height is relative to.
  75103. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this model will be displayed.
  75104. * @param {Property} [options.silhouetteColor=Color.RED] A Property specifying the {@link Color} of the silhouette.
  75105. * @param {Property} [options.silhouetteSize=0.0] A numeric Property specifying the size of the silhouette in pixels.
  75106. * @param {Property} [options.color=Color.WHITE] A Property specifying the {@link Color} that blends with the model's rendered color.
  75107. * @param {Property} [options.colorBlendMode=ColorBlendMode.HIGHLIGHT] An enum Property specifying how the color blends with the model.
  75108. * @param {Property} [options.colorBlendAmount=0.5] A numeric Property specifying the color strength when the <code>colorBlendMode</code> is <code>MIX</code>. A value of 0.0 results in the model's rendered color while a value of 1.0 results in a solid color, with any value in-between resulting in a mix of the two.
  75109. *
  75110. * @see {@link http://cesiumjs.org/2014/03/03/Cesium-3D-Models-Tutorial/|3D Models Tutorial}
  75111. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=3D%20Models.html|Cesium Sandcastle 3D Models Demo}
  75112. */
  75113. function ModelGraphics(options) {
  75114. this._show = undefined;
  75115. this._showSubscription = undefined;
  75116. this._scale = undefined;
  75117. this._scaleSubscription = undefined;
  75118. this._minimumPixelSize = undefined;
  75119. this._minimumPixelSizeSubscription = undefined;
  75120. this._maximumScale = undefined;
  75121. this._maximumScaleSubscription = undefined;
  75122. this._incrementallyLoadTextures = undefined;
  75123. this._incrementallyLoadTexturesSubscription = undefined;
  75124. this._shadows = undefined;
  75125. this._shadowsSubscription = undefined;
  75126. this._uri = undefined;
  75127. this._uriSubscription = undefined;
  75128. this._runAnimations = undefined;
  75129. this._runAnimationsSubscription = undefined;
  75130. this._nodeTransformations = undefined;
  75131. this._nodeTransformationsSubscription = undefined;
  75132. this._heightReference = undefined;
  75133. this._heightReferenceSubscription = undefined;
  75134. this._distanceDisplayCondition = undefined;
  75135. this._distanceDisplayConditionSubscription = undefined;
  75136. this._silhouetteColor = undefined;
  75137. this._silhouetteColorSubscription = undefined;
  75138. this._silhouetteSize = undefined;
  75139. this._silhouetteSizeSubscription = undefined;
  75140. this._color = undefined;
  75141. this._colorSubscription = undefined;
  75142. this._colorBlendMode = undefined;
  75143. this._colorBlendModeSubscription = undefined;
  75144. this._colorBlendAmount = undefined;
  75145. this._colorBlendAmountSubscription = undefined;
  75146. this._definitionChanged = new Event();
  75147. this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
  75148. }
  75149. defineProperties(ModelGraphics.prototype, {
  75150. /**
  75151. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  75152. * @memberof ModelGraphics.prototype
  75153. * @type {Event}
  75154. * @readonly
  75155. */
  75156. definitionChanged : {
  75157. get : function() {
  75158. return this._definitionChanged;
  75159. }
  75160. },
  75161. /**
  75162. * Gets or sets the boolean Property specifying the visibility of the model.
  75163. * @memberof ModelGraphics.prototype
  75164. * @type {Property}
  75165. * @default true
  75166. */
  75167. show : createPropertyDescriptor('show'),
  75168. /**
  75169. * Gets or sets the numeric Property specifying a uniform linear scale
  75170. * for this model. Values greater than 1.0 increase the size of the model while
  75171. * values less than 1.0 decrease it.
  75172. * @memberof ModelGraphics.prototype
  75173. * @type {Property}
  75174. * @default 1.0
  75175. */
  75176. scale : createPropertyDescriptor('scale'),
  75177. /**
  75178. * Gets or sets the numeric Property specifying the approximate minimum
  75179. * pixel size of the model regardless of zoom. This can be used to ensure that
  75180. * a model is visible even when the viewer zooms out. When <code>0.0</code>,
  75181. * no minimum size is enforced.
  75182. * @memberof ModelGraphics.prototype
  75183. * @type {Property}
  75184. * @default 0.0
  75185. */
  75186. minimumPixelSize : createPropertyDescriptor('minimumPixelSize'),
  75187. /**
  75188. * Gets or sets the numeric Property specifying the maximum scale
  75189. * size of a model. This property is used as an upper limit for
  75190. * {@link ModelGraphics#minimumPixelSize}.
  75191. * @memberof ModelGraphics.prototype
  75192. * @type {Property}
  75193. */
  75194. maximumScale : createPropertyDescriptor('maximumScale'),
  75195. /**
  75196. * Get or sets the boolean Property specifying whether textures
  75197. * may continue to stream in after the model is loaded.
  75198. * @memberof ModelGraphics.prototype
  75199. * @type {Property}
  75200. */
  75201. incrementallyLoadTextures : createPropertyDescriptor('incrementallyLoadTextures'),
  75202. /**
  75203. * Get or sets the enum Property specifying whether the model
  75204. * casts or receives shadows from each light source.
  75205. * @memberof ModelGraphics.prototype
  75206. * @type {Property}
  75207. * @default ShadowMode.ENABLED
  75208. */
  75209. shadows : createPropertyDescriptor('shadows'),
  75210. /**
  75211. * Gets or sets the string Property specifying the URI of the glTF asset.
  75212. * @memberof ModelGraphics.prototype
  75213. * @type {Property}
  75214. */
  75215. uri : createPropertyDescriptor('uri'),
  75216. /**
  75217. * Gets or sets the boolean Property specifying if glTF animations should be run.
  75218. * @memberof ModelGraphics.prototype
  75219. * @type {Property}
  75220. * @default true
  75221. */
  75222. runAnimations : createPropertyDescriptor('runAnimations'),
  75223. /**
  75224. * Gets or sets the set of node transformations to apply to this model. This is represented as an {@link PropertyBag}, where keys are
  75225. * names of nodes, and values are {@link TranslationRotationScale} Properties describing the transformation to apply to that node.
  75226. * @memberof ModelGraphics.prototype
  75227. * @type {PropertyBag}
  75228. */
  75229. nodeTransformations : createPropertyDescriptor('nodeTransformations', undefined, createNodeTransformationPropertyBag),
  75230. /**
  75231. * Gets or sets the Property specifying the {@link HeightReference}.
  75232. * @memberof ModelGraphics.prototype
  75233. * @type {Property}
  75234. * @default HeightReference.NONE
  75235. */
  75236. heightReference : createPropertyDescriptor('heightReference'),
  75237. /**
  75238. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this model will be displayed.
  75239. * @memberof ModelGraphics.prototype
  75240. * @type {Property}
  75241. */
  75242. distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition'),
  75243. /**
  75244. * Gets or sets the Property specifying the {@link Color} of the silhouette.
  75245. * @memberof ModelGraphics.prototype
  75246. * @type {Property}
  75247. * @default Color.RED
  75248. */
  75249. silhouetteColor: createPropertyDescriptor('silhouetteColor'),
  75250. /**
  75251. * Gets or sets the numeric Property specifying the size of the silhouette in pixels.
  75252. * @memberof ModelGraphics.prototype
  75253. * @type {Property}
  75254. * @default 0.0
  75255. */
  75256. silhouetteSize : createPropertyDescriptor('silhouetteSize'),
  75257. /**
  75258. * Gets or sets the Property specifying the {@link Color} that blends with the model's rendered color.
  75259. * @memberof ModelGraphics.prototype
  75260. * @type {Property}
  75261. * @default Color.WHITE
  75262. */
  75263. color : createPropertyDescriptor('color'),
  75264. /**
  75265. * Gets or sets the enum Property specifying how the color blends with the model.
  75266. * @memberof ModelGraphics.prototype
  75267. * @type {Property}
  75268. * @default ColorBlendMode.HIGHLIGHT
  75269. */
  75270. colorBlendMode : createPropertyDescriptor('colorBlendMode'),
  75271. /**
  75272. * A numeric Property specifying the color strength when the <code>colorBlendMode</code> is MIX.
  75273. * A value of 0.0 results in the model's rendered color while a value of 1.0 results in a solid color, with
  75274. * any value in-between resulting in a mix of the two.
  75275. * @memberof ModelGraphics.prototype
  75276. * @type {Property}
  75277. * @default 0.5
  75278. */
  75279. colorBlendAmount : createPropertyDescriptor('colorBlendAmount')
  75280. });
  75281. /**
  75282. * Duplicates this instance.
  75283. *
  75284. * @param {ModelGraphics} [result] The object onto which to store the result.
  75285. * @returns {ModelGraphics} The modified result parameter or a new instance if one was not provided.
  75286. */
  75287. ModelGraphics.prototype.clone = function(result) {
  75288. if (!defined(result)) {
  75289. return new ModelGraphics(this);
  75290. }
  75291. result.show = this.show;
  75292. result.scale = this.scale;
  75293. result.minimumPixelSize = this.minimumPixelSize;
  75294. result.maximumScale = this.maximumScale;
  75295. result.incrementallyLoadTextures = this.incrementallyLoadTextures;
  75296. result.shadows = this.shadows;
  75297. result.uri = this.uri;
  75298. result.runAnimations = this.runAnimations;
  75299. result.nodeTransformations = this.nodeTransformations;
  75300. result.heightReference = this._heightReference;
  75301. result.distanceDisplayCondition = this.distanceDisplayCondition;
  75302. result.silhouetteColor = this.silhouetteColor;
  75303. result.silhouetteSize = this.silhouetteSize;
  75304. result.color = this.color;
  75305. result.colorBlendMode = this.colorBlendMode;
  75306. result.colorBlendAmount = this.colorBlendAmount;
  75307. return result;
  75308. };
  75309. /**
  75310. * Assigns each unassigned property on this object to the value
  75311. * of the same property on the provided source object.
  75312. *
  75313. * @param {ModelGraphics} source The object to be merged into this object.
  75314. */
  75315. ModelGraphics.prototype.merge = function(source) {
  75316. if (!defined(source)) {
  75317. throw new DeveloperError('source is required.');
  75318. }
  75319. this.show = defaultValue(this.show, source.show);
  75320. this.scale = defaultValue(this.scale, source.scale);
  75321. this.minimumPixelSize = defaultValue(this.minimumPixelSize, source.minimumPixelSize);
  75322. this.maximumScale = defaultValue(this.maximumScale, source.maximumScale);
  75323. this.incrementallyLoadTextures = defaultValue(this.incrementallyLoadTextures, source.incrementallyLoadTextures);
  75324. this.shadows = defaultValue(this.shadows, source.shadows);
  75325. this.uri = defaultValue(this.uri, source.uri);
  75326. this.runAnimations = defaultValue(this.runAnimations, source.runAnimations);
  75327. this.heightReference = defaultValue(this.heightReference, source.heightReference);
  75328. this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
  75329. this.silhouetteColor = defaultValue(this.silhouetteColor, source.silhouetteColor);
  75330. this.silhouetteSize = defaultValue(this.silhouetteSize, source.silhouetteSize);
  75331. this.color = defaultValue(this.color, source.color);
  75332. this.colorBlendMode = defaultValue(this.colorBlendMode, source.colorBlendMode);
  75333. this.colorBlendAmount = defaultValue(this.colorBlendAmount, source.colorBlendAmount);
  75334. var sourceNodeTransformations = source.nodeTransformations;
  75335. if (defined(sourceNodeTransformations)) {
  75336. var targetNodeTransformations = this.nodeTransformations;
  75337. if (defined(targetNodeTransformations)) {
  75338. targetNodeTransformations.merge(sourceNodeTransformations);
  75339. } else {
  75340. this.nodeTransformations = new PropertyBag(sourceNodeTransformations, createNodeTransformationProperty);
  75341. }
  75342. }
  75343. };
  75344. return ModelGraphics;
  75345. });
  75346. /*global define*/
  75347. define('DataSources/PathGraphics',[
  75348. '../Core/defaultValue',
  75349. '../Core/defined',
  75350. '../Core/defineProperties',
  75351. '../Core/DeveloperError',
  75352. '../Core/Event',
  75353. './createMaterialPropertyDescriptor',
  75354. './createPropertyDescriptor'
  75355. ], function(
  75356. defaultValue,
  75357. defined,
  75358. defineProperties,
  75359. DeveloperError,
  75360. Event,
  75361. createMaterialPropertyDescriptor,
  75362. createPropertyDescriptor) {
  75363. 'use strict';
  75364. /**
  75365. * Describes a polyline defined as the path made by an {@link Entity} as it moves over time.
  75366. *
  75367. * @alias PathGraphics
  75368. * @constructor
  75369. *
  75370. * @param {Object} [options] Object with the following properties:
  75371. * @param {Property} [options.leadTime] A Property specifying the number of seconds behind the object to show.
  75372. * @param {Property} [options.trailTime] A Property specifying the number of seconds in front of the object to show.
  75373. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the path.
  75374. * @param {Property} [options.width=1.0] A numeric Property specifying the width in pixels.
  75375. * @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to draw the path.
  75376. * @param {Property} [options.resolution=60] A numeric Property specifying the maximum number of seconds to step when sampling the position.
  75377. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this path will be displayed.
  75378. */
  75379. function PathGraphics(options) {
  75380. this._material = undefined;
  75381. this._materialSubscription = undefined;
  75382. this._show = undefined;
  75383. this._showSubscription = undefined;
  75384. this._width = undefined;
  75385. this._widthSubscription = undefined;
  75386. this._resolution = undefined;
  75387. this._resolutionSubscription = undefined;
  75388. this._leadTime = undefined;
  75389. this._leadTimeSubscription = undefined;
  75390. this._trailTime = undefined;
  75391. this._trailTimeSubscription = undefined;
  75392. this._distanceDisplayCondition = undefined;
  75393. this._distanceDisplayConditionSubscription = undefined;
  75394. this._definitionChanged = new Event();
  75395. this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
  75396. }
  75397. defineProperties(PathGraphics.prototype, {
  75398. /**
  75399. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  75400. * @memberof PathGraphics.prototype
  75401. * @type {Event}
  75402. * @readonly
  75403. */
  75404. definitionChanged : {
  75405. get : function() {
  75406. return this._definitionChanged;
  75407. }
  75408. },
  75409. /**
  75410. * Gets or sets the boolean Property specifying the visibility of the path.
  75411. * @memberof PathGraphics.prototype
  75412. * @type {Property}
  75413. * @default true
  75414. */
  75415. show : createPropertyDescriptor('show'),
  75416. /**
  75417. * Gets or sets the Property specifying the material used to draw the path.
  75418. * @memberof PathGraphics.prototype
  75419. * @type {MaterialProperty}
  75420. * @default Color.WHITE
  75421. */
  75422. material : createMaterialPropertyDescriptor('material'),
  75423. /**
  75424. * Gets or sets the numeric Property specifying the width in pixels.
  75425. * @memberof PathGraphics.prototype
  75426. * @type {Property}
  75427. * @default 1.0
  75428. */
  75429. width : createPropertyDescriptor('width'),
  75430. /**
  75431. * Gets or sets the Property specifying the maximum number of seconds to step when sampling the position.
  75432. * @memberof PathGraphics.prototype
  75433. * @type {Property}
  75434. * @default 60
  75435. */
  75436. resolution : createPropertyDescriptor('resolution'),
  75437. /**
  75438. * Gets or sets the Property specifying the number of seconds in front of the object to show.
  75439. * @memberof PathGraphics.prototype
  75440. * @type {Property}
  75441. */
  75442. leadTime : createPropertyDescriptor('leadTime'),
  75443. /**
  75444. * Gets or sets the Property specifying the number of seconds behind the object to show.
  75445. * @memberof PathGraphics.prototype
  75446. * @type {Property}
  75447. */
  75448. trailTime : createPropertyDescriptor('trailTime'),
  75449. /**
  75450. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this path will be displayed.
  75451. * @memberof PathGraphics.prototype
  75452. * @type {Property}
  75453. */
  75454. distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition')
  75455. });
  75456. /**
  75457. * Duplicates this instance.
  75458. *
  75459. * @param {PathGraphics} [result] The object onto which to store the result.
  75460. * @returns {PathGraphics} The modified result parameter or a new instance if one was not provided.
  75461. */
  75462. PathGraphics.prototype.clone = function(result) {
  75463. if (!defined(result)) {
  75464. return new PathGraphics(this);
  75465. }
  75466. result.material = this.material;
  75467. result.width = this.width;
  75468. result.resolution = this.resolution;
  75469. result.show = this.show;
  75470. result.leadTime = this.leadTime;
  75471. result.trailTime = this.trailTime;
  75472. result.distanceDisplayCondition = this.distanceDisplayCondition;
  75473. return result;
  75474. };
  75475. /**
  75476. * Assigns each unassigned property on this object to the value
  75477. * of the same property on the provided source object.
  75478. *
  75479. * @param {PathGraphics} source The object to be merged into this object.
  75480. */
  75481. PathGraphics.prototype.merge = function(source) {
  75482. if (!defined(source)) {
  75483. throw new DeveloperError('source is required.');
  75484. }
  75485. this.material = defaultValue(this.material, source.material);
  75486. this.width = defaultValue(this.width, source.width);
  75487. this.resolution = defaultValue(this.resolution, source.resolution);
  75488. this.show = defaultValue(this.show, source.show);
  75489. this.leadTime = defaultValue(this.leadTime, source.leadTime);
  75490. this.trailTime = defaultValue(this.trailTime, source.trailTime);
  75491. this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
  75492. };
  75493. return PathGraphics;
  75494. });
  75495. /*global define*/
  75496. define('DataSources/PointGraphics',[
  75497. '../Core/defaultValue',
  75498. '../Core/defined',
  75499. '../Core/defineProperties',
  75500. '../Core/DeveloperError',
  75501. '../Core/Event',
  75502. './createPropertyDescriptor'
  75503. ], function(
  75504. defaultValue,
  75505. defined,
  75506. defineProperties,
  75507. DeveloperError,
  75508. Event,
  75509. createPropertyDescriptor) {
  75510. 'use strict';
  75511. /**
  75512. * Describes a graphical point located at the position of the containing {@link Entity}.
  75513. *
  75514. * @alias PointGraphics
  75515. * @constructor
  75516. *
  75517. * @param {Object} [options] Object with the following properties:
  75518. * @param {Property} [options.color=Color.WHITE] A Property specifying the {@link Color} of the point.
  75519. * @param {Property} [options.pixelSize=1] A numeric Property specifying the size in pixels.
  75520. * @param {Property} [options.outlineColor=Color.BLACK] A Property specifying the {@link Color} of the outline.
  75521. * @param {Property} [options.outlineWidth=0] A numeric Property specifying the the outline width in pixels.
  75522. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the point.
  75523. * @param {Property} [options.scaleByDistance] A {@link NearFarScalar} Property used to scale the point based on distance.
  75524. * @param {Property} [options.translucencyByDistance] A {@link NearFarScalar} Property used to set translucency based on distance from the camera.
  75525. * @param {Property} [options.heightReference=HeightReference.NONE] A Property specifying what the height is relative to.
  75526. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this point will be displayed.
  75527. */
  75528. function PointGraphics(options) {
  75529. this._color = undefined;
  75530. this._colorSubscription = undefined;
  75531. this._pixelSize = undefined;
  75532. this._pixelSizeSubscription = undefined;
  75533. this._outlineColor = undefined;
  75534. this._outlineColorSubscription = undefined;
  75535. this._outlineWidth = undefined;
  75536. this._outlineWidthSubscription = undefined;
  75537. this._show = undefined;
  75538. this._showSubscription = undefined;
  75539. this._scaleByDistance = undefined;
  75540. this._scaleByDistanceSubscription = undefined;
  75541. this._translucencyByDistance = undefined;
  75542. this._translucencyByDistanceSubscription = undefined;
  75543. this._heightReference = undefined;
  75544. this._heightReferenceSubscription = undefined;
  75545. this._distanceDisplayCondition = undefined;
  75546. this._distanceDisplayConditionSubscription = undefined;
  75547. this._definitionChanged = new Event();
  75548. this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
  75549. }
  75550. defineProperties(PointGraphics.prototype, {
  75551. /**
  75552. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  75553. * @memberof PointGraphics.prototype
  75554. *
  75555. * @type {Event}
  75556. * @readonly
  75557. */
  75558. definitionChanged : {
  75559. get : function() {
  75560. return this._definitionChanged;
  75561. }
  75562. },
  75563. /**
  75564. * Gets or sets the Property specifying the {@link Color} of the point.
  75565. * @memberof PointGraphics.prototype
  75566. * @type {Property}
  75567. * @default Color.WHITE
  75568. */
  75569. color : createPropertyDescriptor('color'),
  75570. /**
  75571. * Gets or sets the numeric Property specifying the size in pixels.
  75572. * @memberof PointGraphics.prototype
  75573. * @type {Property}
  75574. * @default 1
  75575. */
  75576. pixelSize : createPropertyDescriptor('pixelSize'),
  75577. /**
  75578. * Gets or sets the Property specifying the {@link Color} of the outline.
  75579. * @memberof PointGraphics.prototype
  75580. * @type {Property}
  75581. * @default Color.BLACK
  75582. */
  75583. outlineColor : createPropertyDescriptor('outlineColor'),
  75584. /**
  75585. * Gets or sets the numeric Property specifying the the outline width in pixels.
  75586. * @memberof PointGraphics.prototype
  75587. * @type {Property}
  75588. * @default 0
  75589. */
  75590. outlineWidth : createPropertyDescriptor('outlineWidth'),
  75591. /**
  75592. * Gets or sets the boolean Property specifying the visibility of the point.
  75593. * @memberof PointGraphics.prototype
  75594. * @type {Property}
  75595. * @default true
  75596. */
  75597. show : createPropertyDescriptor('show'),
  75598. /**
  75599. * Gets or sets the {@link NearFarScalar} Property used to scale the point based on distance.
  75600. * If undefined, a constant size is used.
  75601. * @memberof PointGraphics.prototype
  75602. * @type {Property}
  75603. */
  75604. scaleByDistance : createPropertyDescriptor('scaleByDistance'),
  75605. /**
  75606. * Gets or sets {@link NearFarScalar} Property specifying the translucency of the point based on the distance from the camera.
  75607. * A point's translucency will interpolate between the {@link NearFarScalar#nearValue} and
  75608. * {@link NearFarScalar#farValue} while the camera distance falls within the upper and lower bounds
  75609. * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
  75610. * Outside of these ranges the points's translucency remains clamped to the nearest bound.
  75611. * @memberof PointGraphics.prototype
  75612. * @type {Property}
  75613. */
  75614. translucencyByDistance : createPropertyDescriptor('translucencyByDistance'),
  75615. /**
  75616. * Gets or sets the Property specifying the {@link HeightReference}.
  75617. * @memberof PointGraphics.prototype
  75618. * @type {Property}
  75619. * @default HeightReference.NONE
  75620. */
  75621. heightReference : createPropertyDescriptor('heightReference'),
  75622. /**
  75623. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this point will be displayed.
  75624. * @memberof PointGraphics.prototype
  75625. * @type {Property}
  75626. */
  75627. distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition')
  75628. });
  75629. /**
  75630. * Duplicates this instance.
  75631. *
  75632. * @param {PointGraphics} [result] The object onto which to store the result.
  75633. * @returns {PointGraphics} The modified result parameter or a new instance if one was not provided.
  75634. */
  75635. PointGraphics.prototype.clone = function(result) {
  75636. if (!defined(result)) {
  75637. return new PointGraphics(this);
  75638. }
  75639. result.color = this.color;
  75640. result.pixelSize = this.pixelSize;
  75641. result.outlineColor = this.outlineColor;
  75642. result.outlineWidth = this.outlineWidth;
  75643. result.show = this.show;
  75644. result.scaleByDistance = this.scaleByDistance;
  75645. result.translucencyByDistance = this._translucencyByDistance;
  75646. result.heightReference = this.heightReference;
  75647. result.distanceDisplayCondition = this.distanceDisplayCondition;
  75648. return result;
  75649. };
  75650. /**
  75651. * Assigns each unassigned property on this object to the value
  75652. * of the same property on the provided source object.
  75653. *
  75654. * @param {PointGraphics} source The object to be merged into this object.
  75655. */
  75656. PointGraphics.prototype.merge = function(source) {
  75657. if (!defined(source)) {
  75658. throw new DeveloperError('source is required.');
  75659. }
  75660. this.color = defaultValue(this.color, source.color);
  75661. this.pixelSize = defaultValue(this.pixelSize, source.pixelSize);
  75662. this.outlineColor = defaultValue(this.outlineColor, source.outlineColor);
  75663. this.outlineWidth = defaultValue(this.outlineWidth, source.outlineWidth);
  75664. this.show = defaultValue(this.show, source.show);
  75665. this.scaleByDistance = defaultValue(this.scaleByDistance, source.scaleByDistance);
  75666. this.translucencyByDistance = defaultValue(this._translucencyByDistance, source.translucencyByDistance);
  75667. this.heightReference = defaultValue(this.heightReference, source.heightReference);
  75668. this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
  75669. };
  75670. return PointGraphics;
  75671. });
  75672. /*global define*/
  75673. define('DataSources/PolygonGraphics',[
  75674. '../Core/defaultValue',
  75675. '../Core/defined',
  75676. '../Core/defineProperties',
  75677. '../Core/DeveloperError',
  75678. '../Core/Event',
  75679. './createMaterialPropertyDescriptor',
  75680. './createPropertyDescriptor'
  75681. ], function(
  75682. defaultValue,
  75683. defined,
  75684. defineProperties,
  75685. DeveloperError,
  75686. Event,
  75687. createMaterialPropertyDescriptor,
  75688. createPropertyDescriptor) {
  75689. 'use strict';
  75690. /**
  75691. * Describes a polygon defined by an hierarchy of linear rings which make up the outer shape and any nested holes.
  75692. * The polygon conforms to the curvature of the globe and can be placed on the surface or
  75693. * at altitude and can optionally be extruded into a volume.
  75694. *
  75695. * @alias PolygonGraphics
  75696. * @constructor
  75697. *
  75698. * @param {Object} [options] Object with the following properties:
  75699. * @param {Property} [options.hierarchy] A Property specifying the {@link PolygonHierarchy}.
  75700. * @param {Property} [options.height=0] A numeric Property specifying the altitude of the polygon relative to the ellipsoid surface.
  75701. * @param {Property} [options.extrudedHeight] A numeric Property specifying the altitude of the polygon's extruded face relative to the ellipsoid surface.
  75702. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the polygon.
  75703. * @param {Property} [options.fill=true] A boolean Property specifying whether the polygon is filled with the provided material.
  75704. * @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to fill the polygon.
  75705. * @param {Property} [options.outline=false] A boolean Property specifying whether the polygon is outlined.
  75706. * @param {Property} [options.outlineColor=Color.BLACK] A Property specifying the {@link Color} of the outline.
  75707. * @param {Property} [options.outlineWidth=1.0] A numeric Property specifying the width of the outline.
  75708. * @param {Property} [options.stRotation=0.0] A numeric property specifying the rotation of the polygon texture counter-clockwise from north.
  75709. * @param {Property} [options.granularity=Cesium.Math.RADIANS_PER_DEGREE] A numeric Property specifying the angular distance between each latitude and longitude point.
  75710. * @param {Property} [options.perPositionHeight=false] A boolean specifying whether or not the the height of each position is used.
  75711. * @param {Boolean} [options.closeTop=true] When false, leaves off the top of an extruded polygon open.
  75712. * @param {Boolean} [options.closeBottom=true] When false, leaves off the bottom of an extruded polygon open.
  75713. * @param {Property} [options.shadows=ShadowMode.DISABLED] An enum Property specifying whether the polygon casts or receives shadows from each light source.
  75714. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this polygon will be displayed.
  75715. *
  75716. * @see Entity
  75717. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Polygon.html|Cesium Sandcastle Polygon Demo}
  75718. */
  75719. function PolygonGraphics(options) {
  75720. this._show = undefined;
  75721. this._showSubscription = undefined;
  75722. this._material = undefined;
  75723. this._materialSubscription = undefined;
  75724. this._hierarchy = undefined;
  75725. this._hierarchySubscription = undefined;
  75726. this._height = undefined;
  75727. this._heightSubscription = undefined;
  75728. this._extrudedHeight = undefined;
  75729. this._extrudedHeightSubscription = undefined;
  75730. this._granularity = undefined;
  75731. this._granularitySubscription = undefined;
  75732. this._stRotation = undefined;
  75733. this._stRotationSubscription = undefined;
  75734. this._perPositionHeight = undefined;
  75735. this._perPositionHeightSubscription = undefined;
  75736. this._outline = undefined;
  75737. this._outlineSubscription = undefined;
  75738. this._outlineColor = undefined;
  75739. this._outlineColorSubscription = undefined;
  75740. this._outlineWidth = undefined;
  75741. this._outlineWidthSubscription = undefined;
  75742. this._fill = undefined;
  75743. this._fillSubscription = undefined;
  75744. this._definitionChanged = new Event();
  75745. this._closeTop = undefined;
  75746. this._closeTopSubscription = undefined;
  75747. this._closeBottom = undefined;
  75748. this._closeBottomSubscription = undefined;
  75749. this._shadows = undefined;
  75750. this._shadowsSubscription = undefined;
  75751. this._distanceDisplayCondition = undefined;
  75752. this._distanceDisplayConditionSubscription = undefined;
  75753. this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
  75754. }
  75755. defineProperties(PolygonGraphics.prototype, {
  75756. /**
  75757. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  75758. * @memberof PolygonGraphics.prototype
  75759. *
  75760. * @type {Event}
  75761. * @readonly
  75762. */
  75763. definitionChanged : {
  75764. get : function() {
  75765. return this._definitionChanged;
  75766. }
  75767. },
  75768. /**
  75769. * Gets or sets the boolean Property specifying the visibility of the polygon.
  75770. * @memberof PolygonGraphics.prototype
  75771. * @type {Property}
  75772. * @default true
  75773. */
  75774. show : createPropertyDescriptor('show'),
  75775. /**
  75776. * Gets or sets the Property specifying the material used to fill the polygon.
  75777. * @memberof PolygonGraphics.prototype
  75778. * @type {MaterialProperty}
  75779. * @default Color.WHITE
  75780. */
  75781. material : createMaterialPropertyDescriptor('material'),
  75782. /**
  75783. * Gets or sets the Property specifying the {@link PolygonHierarchy}.
  75784. * @memberof PolygonGraphics.prototype
  75785. * @type {Property}
  75786. */
  75787. hierarchy : createPropertyDescriptor('hierarchy'),
  75788. /**
  75789. * Gets or sets the numeric Property specifying the constant altitude of the polygon.
  75790. * @memberof PolygonGraphics.prototype
  75791. * @type {Property}
  75792. * @default 0.0
  75793. */
  75794. height : createPropertyDescriptor('height'),
  75795. /**
  75796. * Gets or sets the numeric Property specifying the altitude of the polygon extrusion.
  75797. * If {@link PolygonGraphics#perPositionHeight} is false, the volume starts at {@link PolygonGraphics#height} and ends at this altitude.
  75798. * If {@link PolygonGraphics#perPositionHeight} is true, the volume starts at the height of each {@link PolygonGraphics#hierarchy} position and ends at this altitude.
  75799. * @memberof PolygonGraphics.prototype
  75800. * @type {Property}
  75801. */
  75802. extrudedHeight : createPropertyDescriptor('extrudedHeight'),
  75803. /**
  75804. * Gets or sets the numeric Property specifying the angular distance between points on the polygon.
  75805. * @memberof PolygonGraphics.prototype
  75806. * @type {Property}
  75807. * @default {CesiumMath.RADIANS_PER_DEGREE}
  75808. */
  75809. granularity : createPropertyDescriptor('granularity'),
  75810. /**
  75811. * Gets or sets the numeric property specifying the rotation of the polygon texture counter-clockwise from north.
  75812. * @memberof PolygonGraphics.prototype
  75813. * @type {Property}
  75814. * @default 0
  75815. */
  75816. stRotation : createPropertyDescriptor('stRotation'),
  75817. /**
  75818. * Gets or sets the boolean Property specifying whether the polygon is filled with the provided material.
  75819. * @memberof PolygonGraphics.prototype
  75820. * @type {Property}
  75821. * @default true
  75822. */
  75823. fill : createPropertyDescriptor('fill'),
  75824. /**
  75825. * Gets or sets the Property specifying whether the polygon is outlined.
  75826. * @memberof PolygonGraphics.prototype
  75827. * @type {Property}
  75828. * @default false
  75829. */
  75830. outline : createPropertyDescriptor('outline'),
  75831. /**
  75832. * Gets or sets the Property specifying the {@link Color} of the outline.
  75833. * @memberof PolygonGraphics.prototype
  75834. * @type {Property}
  75835. * @default Color.BLACK
  75836. */
  75837. outlineColor : createPropertyDescriptor('outlineColor'),
  75838. /**
  75839. * Gets or sets the numeric Property specifying the width of the outline.
  75840. * @memberof PolygonGraphics.prototype
  75841. * @type {Property}
  75842. * @default 1.0
  75843. */
  75844. outlineWidth : createPropertyDescriptor('outlineWidth'),
  75845. /**
  75846. * Gets or sets the boolean specifying whether or not the the height of each position is used.
  75847. * If true, the shape will have non-uniform altitude defined by the height of each {@link PolygonGraphics#hierarchy} position.
  75848. * If false, the shape will have a constant altitude as specified by {@link PolygonGraphics#height}.
  75849. * @memberof PolygonGraphics.prototype
  75850. * @type {Property}
  75851. */
  75852. perPositionHeight : createPropertyDescriptor('perPositionHeight'),
  75853. /**
  75854. * Gets or sets a boolean specifying whether or not the top of an extruded polygon is included.
  75855. * @memberof PolygonGraphics.prototype
  75856. * @type {Property}
  75857. */
  75858. closeTop : createPropertyDescriptor('closeTop'),
  75859. /**
  75860. * Gets or sets a boolean specifying whether or not the bottom of an extruded polygon is included.
  75861. * @memberof PolygonGraphics.prototype
  75862. * @type {Property}
  75863. */
  75864. closeBottom : createPropertyDescriptor('closeBottom'),
  75865. /**
  75866. * Get or sets the enum Property specifying whether the polygon
  75867. * casts or receives shadows from each light source.
  75868. * @memberof PolygonGraphics.prototype
  75869. * @type {Property}
  75870. * @default ShadowMode.DISABLED
  75871. */
  75872. shadows : createPropertyDescriptor('shadows'),
  75873. /**
  75874. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this polygon will be displayed.
  75875. * @memberof BillboardGraphics.prototype
  75876. * @type {Property}
  75877. */
  75878. distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition')
  75879. });
  75880. /**
  75881. * Duplicates this instance.
  75882. *
  75883. * @param {PolygonGraphics} [result] The object onto which to store the result.
  75884. * @returns {PolygonGraphics} The modified result parameter or a new instance if one was not provided.
  75885. */
  75886. PolygonGraphics.prototype.clone = function(result) {
  75887. if (!defined(result)) {
  75888. return new PolygonGraphics(this);
  75889. }
  75890. result.show = this.show;
  75891. result.material = this.material;
  75892. result.hierarchy = this.hierarchy;
  75893. result.height = this.height;
  75894. result.extrudedHeight = this.extrudedHeight;
  75895. result.granularity = this.granularity;
  75896. result.stRotation = this.stRotation;
  75897. result.fill = this.fill;
  75898. result.outline = this.outline;
  75899. result.outlineColor = this.outlineColor;
  75900. result.outlineWidth = this.outlineWidth;
  75901. result.perPositionHeight = this.perPositionHeight;
  75902. result.closeTop = this.closeTop;
  75903. result.closeBottom = this.closeBottom;
  75904. result.shadows = this.shadows;
  75905. result.distanceDisplayCondition = this.distanceDisplayCondition;
  75906. return result;
  75907. };
  75908. /**
  75909. * Assigns each unassigned property on this object to the value
  75910. * of the same property on the provided source object.
  75911. *
  75912. * @param {PolygonGraphics} source The object to be merged into this object.
  75913. */
  75914. PolygonGraphics.prototype.merge = function(source) {
  75915. if (!defined(source)) {
  75916. throw new DeveloperError('source is required.');
  75917. }
  75918. this.show = defaultValue(this.show, source.show);
  75919. this.material = defaultValue(this.material, source.material);
  75920. this.hierarchy = defaultValue(this.hierarchy, source.hierarchy);
  75921. this.height = defaultValue(this.height, source.height);
  75922. this.extrudedHeight = defaultValue(this.extrudedHeight, source.extrudedHeight);
  75923. this.granularity = defaultValue(this.granularity, source.granularity);
  75924. this.stRotation = defaultValue(this.stRotation, source.stRotation);
  75925. this.fill = defaultValue(this.fill, source.fill);
  75926. this.outline = defaultValue(this.outline, source.outline);
  75927. this.outlineColor = defaultValue(this.outlineColor, source.outlineColor);
  75928. this.outlineWidth = defaultValue(this.outlineWidth, source.outlineWidth);
  75929. this.perPositionHeight = defaultValue(this.perPositionHeight, source.perPositionHeight);
  75930. this.closeTop = defaultValue(this.closeTop, source.closeTop);
  75931. this.closeBottom = defaultValue(this.closeBottom, source.closeBottom);
  75932. this.shadows = defaultValue(this.shadows, source.shadows);
  75933. this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
  75934. };
  75935. return PolygonGraphics;
  75936. });
  75937. /*global define*/
  75938. define('DataSources/PolylineGraphics',[
  75939. '../Core/defaultValue',
  75940. '../Core/defined',
  75941. '../Core/defineProperties',
  75942. '../Core/DeveloperError',
  75943. '../Core/Event',
  75944. './createMaterialPropertyDescriptor',
  75945. './createPropertyDescriptor'
  75946. ], function(
  75947. defaultValue,
  75948. defined,
  75949. defineProperties,
  75950. DeveloperError,
  75951. Event,
  75952. createMaterialPropertyDescriptor,
  75953. createPropertyDescriptor) {
  75954. 'use strict';
  75955. /**
  75956. * Describes a polyline defined as a line strip. The first two positions define a line segment,
  75957. * and each additional position defines a line segment from the previous position. The segments
  75958. * can be linear connected points or great arcs.
  75959. *
  75960. * @alias PolylineGraphics
  75961. * @constructor
  75962. *
  75963. * @param {Object} [options] Object with the following properties:
  75964. * @param {Property} [options.positions] A Property specifying the array of {@link Cartesian3} positions that define the line strip.
  75965. * @param {Property} [options.followSurface=true] A boolean Property specifying whether the line segments should be great arcs or linearly connected.
  75966. * @param {Property} [options.width=1.0] A numeric Property specifying the width in pixels.
  75967. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the polyline.
  75968. * @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to draw the polyline.
  75969. * @param {Property} [options.granularity=Cesium.Math.RADIANS_PER_DEGREE] A numeric Property specifying the angular distance between each latitude and longitude if followSurface is true.
  75970. * @param {Property} [options.shadows=ShadowMode.DISABLED] An enum Property specifying whether the polyline casts or receives shadows from each light source.
  75971. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this polyline will be displayed.
  75972. *
  75973. * @see Entity
  75974. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Polyline.html|Cesium Sandcastle Polyline Demo}
  75975. */
  75976. function PolylineGraphics(options) {
  75977. this._show = undefined;
  75978. this._showSubscription = undefined;
  75979. this._material = undefined;
  75980. this._materialSubscription = undefined;
  75981. this._positions = undefined;
  75982. this._positionsSubscription = undefined;
  75983. this._followSurface = undefined;
  75984. this._followSurfaceSubscription = undefined;
  75985. this._granularity = undefined;
  75986. this._granularitySubscription = undefined;
  75987. this._widthSubscription = undefined;
  75988. this._width = undefined;
  75989. this._widthSubscription = undefined;
  75990. this._shadows = undefined;
  75991. this._shadowsSubscription = undefined;
  75992. this._distanceDisplayCondition = undefined;
  75993. this._distanceDisplayConditionSubscription = undefined;
  75994. this._definitionChanged = new Event();
  75995. this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
  75996. }
  75997. defineProperties(PolylineGraphics.prototype, {
  75998. /**
  75999. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  76000. * @memberof PolylineGraphics.prototype
  76001. *
  76002. * @type {Event}
  76003. * @readonly
  76004. */
  76005. definitionChanged : {
  76006. get : function() {
  76007. return this._definitionChanged;
  76008. }
  76009. },
  76010. /**
  76011. * Gets or sets the boolean Property specifying the visibility of the polyline.
  76012. * @memberof PolylineGraphics.prototype
  76013. * @type {Property}
  76014. * @default true
  76015. */
  76016. show : createPropertyDescriptor('show'),
  76017. /**
  76018. * Gets or sets the Property specifying the material used to draw the polyline.
  76019. * @memberof PolylineGraphics.prototype
  76020. * @type {MaterialProperty}
  76021. * @default Color.WHITE
  76022. */
  76023. material : createMaterialPropertyDescriptor('material'),
  76024. /**
  76025. * Gets or sets the Property specifying the array of {@link Cartesian3}
  76026. * positions that define the line strip.
  76027. * @memberof PolylineGraphics.prototype
  76028. * @type {Property}
  76029. */
  76030. positions : createPropertyDescriptor('positions'),
  76031. /**
  76032. * Gets or sets the numeric Property specifying the width in pixels.
  76033. * @memberof PolylineGraphics.prototype
  76034. * @type {Property}
  76035. * @default 1.0
  76036. */
  76037. width : createPropertyDescriptor('width'),
  76038. /**
  76039. * Gets or sets the boolean Property specifying whether the line segments
  76040. * should be great arcs or linearly connected.
  76041. * @memberof PolylineGraphics.prototype
  76042. * @type {Property}
  76043. * @default true
  76044. */
  76045. followSurface : createPropertyDescriptor('followSurface'),
  76046. /**
  76047. * Gets or sets the numeric Property specifying the angular distance between each latitude and longitude if followSurface is true.
  76048. * @memberof PolylineGraphics.prototype
  76049. * @type {Property}
  76050. * @default Cesium.Math.RADIANS_PER_DEGREE
  76051. */
  76052. granularity : createPropertyDescriptor('granularity'),
  76053. /**
  76054. * Get or sets the enum Property specifying whether the polyline
  76055. * casts or receives shadows from each light source.
  76056. * @memberof PolylineGraphics.prototype
  76057. * @type {Property}
  76058. * @default ShadowMode.DISABLED
  76059. */
  76060. shadows : createPropertyDescriptor('shadows'),
  76061. /**
  76062. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this polyline will be displayed.
  76063. * @memberof PolylineGraphics.prototype
  76064. * @type {Property}
  76065. */
  76066. distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition')
  76067. });
  76068. /**
  76069. * Duplicates this instance.
  76070. *
  76071. * @param {PolylineGraphics} [result] The object onto which to store the result.
  76072. * @returns {PolylineGraphics} The modified result parameter or a new instance if one was not provided.
  76073. */
  76074. PolylineGraphics.prototype.clone = function(result) {
  76075. if (!defined(result)) {
  76076. return new PolylineGraphics(this);
  76077. }
  76078. result.show = this.show;
  76079. result.material = this.material;
  76080. result.positions = this.positions;
  76081. result.width = this.width;
  76082. result.followSurface = this.followSurface;
  76083. result.granularity = this.granularity;
  76084. result.shadows = this.shadows;
  76085. result.distanceDisplayCondition = this.distanceDisplayCondition;
  76086. return result;
  76087. };
  76088. /**
  76089. * Assigns each unassigned property on this object to the value
  76090. * of the same property on the provided source object.
  76091. *
  76092. * @param {PolylineGraphics} source The object to be merged into this object.
  76093. */
  76094. PolylineGraphics.prototype.merge = function(source) {
  76095. if (!defined(source)) {
  76096. throw new DeveloperError('source is required.');
  76097. }
  76098. this.show = defaultValue(this.show, source.show);
  76099. this.material = defaultValue(this.material, source.material);
  76100. this.positions = defaultValue(this.positions, source.positions);
  76101. this.width = defaultValue(this.width, source.width);
  76102. this.followSurface = defaultValue(this.followSurface, source.followSurface);
  76103. this.granularity = defaultValue(this.granularity, source.granularity);
  76104. this.shadows = defaultValue(this.shadows, source.shadows);
  76105. this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
  76106. };
  76107. return PolylineGraphics;
  76108. });
  76109. /*global define*/
  76110. define('DataSources/PolylineVolumeGraphics',[
  76111. '../Core/defaultValue',
  76112. '../Core/defined',
  76113. '../Core/defineProperties',
  76114. '../Core/DeveloperError',
  76115. '../Core/Event',
  76116. './createMaterialPropertyDescriptor',
  76117. './createPropertyDescriptor'
  76118. ], function(
  76119. defaultValue,
  76120. defined,
  76121. defineProperties,
  76122. DeveloperError,
  76123. Event,
  76124. createMaterialPropertyDescriptor,
  76125. createPropertyDescriptor) {
  76126. 'use strict';
  76127. /**
  76128. * Describes a polyline volume defined as a line strip and corresponding two dimensional shape which is extruded along it.
  76129. * The resulting volume conforms to the curvature of the globe.
  76130. *
  76131. * @alias PolylineVolumeGraphics
  76132. * @constructor
  76133. *
  76134. * @param {Object} [options] Object with the following properties:
  76135. * @param {Property} [options.positions] A Property specifying the array of {@link Cartesian3} positions which define the line strip.
  76136. * @param {Property} [options.shape] A Property specifying the array of {@link Cartesian2} positions which define the shape to be extruded.
  76137. * @param {Property} [options.cornerType=CornerType.ROUNDED] A {@link CornerType} Property specifying the style of the corners.
  76138. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the volume.
  76139. * @param {Property} [options.fill=true] A boolean Property specifying whether the volume is filled with the provided material.
  76140. * @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to fill the volume.
  76141. * @param {Property} [options.outline=false] A boolean Property specifying whether the volume is outlined.
  76142. * @param {Property} [options.outlineColor=Color.BLACK] A Property specifying the {@link Color} of the outline.
  76143. * @param {Property} [options.outlineWidth=1.0] A numeric Property specifying the width of the outline.
  76144. * @param {Property} [options.granularity=Cesium.Math.RADIANS_PER_DEGREE] A numeric Property specifying the angular distance between each latitude and longitude point.
  76145. * @param {Property} [options.shadows=ShadowMode.DISABLED] An enum Property specifying whether the volume casts or receives shadows from each light source.
  76146. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this volume will be displayed.
  76147. *
  76148. * @see Entity
  76149. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Polyline%20Volume.html|Cesium Sandcastle Polyline Volume Demo}
  76150. */
  76151. function PolylineVolumeGraphics(options) {
  76152. this._show = undefined;
  76153. this._showSubscription = undefined;
  76154. this._material = undefined;
  76155. this._materialSubscription = undefined;
  76156. this._positions = undefined;
  76157. this._positionsSubscription = undefined;
  76158. this._shape = undefined;
  76159. this._shapeSubscription = undefined;
  76160. this._granularity = undefined;
  76161. this._granularitySubscription = undefined;
  76162. this._cornerType = undefined;
  76163. this._cornerTypeSubscription = undefined;
  76164. this._fill = undefined;
  76165. this._fillSubscription = undefined;
  76166. this._outline = undefined;
  76167. this._outlineSubscription = undefined;
  76168. this._outlineColor = undefined;
  76169. this._outlineColorSubscription = undefined;
  76170. this._outlineWidth = undefined;
  76171. this._outlineWidthSubscription = undefined;
  76172. this._shadows = undefined;
  76173. this._shadowsSubscription = undefined;
  76174. this._distanceDisplayCondition = undefined;
  76175. this._distanceDisplayConditionSubsription = undefined;
  76176. this._definitionChanged = new Event();
  76177. this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
  76178. }
  76179. defineProperties(PolylineVolumeGraphics.prototype, {
  76180. /**
  76181. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  76182. * @memberof PolylineVolumeGraphics.prototype
  76183. *
  76184. * @type {Event}
  76185. * @readonly
  76186. */
  76187. definitionChanged : {
  76188. get : function() {
  76189. return this._definitionChanged;
  76190. }
  76191. },
  76192. /**
  76193. * Gets or sets the boolean Property specifying the visibility of the volume.
  76194. * @memberof PolylineVolumeGraphics.prototype
  76195. * @type {Property}
  76196. * @default true
  76197. */
  76198. show : createPropertyDescriptor('show'),
  76199. /**
  76200. * Gets or sets the Property specifying the material used to fill the volume.
  76201. * @memberof PolylineVolumeGraphics.prototype
  76202. * @type {MaterialProperty}
  76203. * @default Color.WHITE
  76204. */
  76205. material : createMaterialPropertyDescriptor('material'),
  76206. /**
  76207. * Gets or sets the Property specifying the array of {@link Cartesian3} positions which define the line strip.
  76208. * @memberof PolylineVolumeGraphics.prototype
  76209. * @type {Property}
  76210. */
  76211. positions : createPropertyDescriptor('positions'),
  76212. /**
  76213. * Gets or sets the Property specifying the array of {@link Cartesian2} positions which define the shape to be extruded.
  76214. * @memberof PolylineVolumeGraphics.prototype
  76215. * @type {Property}
  76216. */
  76217. shape : createPropertyDescriptor('shape'),
  76218. /**
  76219. * Gets or sets the numeric Property specifying the angular distance between points on the volume.
  76220. * @memberof PolylineVolumeGraphics.prototype
  76221. * @type {Property}
  76222. * @default {CesiumMath.RADIANS_PER_DEGREE}
  76223. */
  76224. granularity : createPropertyDescriptor('granularity'),
  76225. /**
  76226. * Gets or sets the boolean Property specifying whether the volume is filled with the provided material.
  76227. * @memberof PolylineVolumeGraphics.prototype
  76228. * @type {Property}
  76229. * @default true
  76230. */
  76231. fill : createPropertyDescriptor('fill'),
  76232. /**
  76233. * Gets or sets the Property specifying whether the volume is outlined.
  76234. * @memberof PolylineVolumeGraphics.prototype
  76235. * @type {Property}
  76236. * @default false
  76237. */
  76238. outline : createPropertyDescriptor('outline'),
  76239. /**
  76240. * Gets or sets the Property specifying the {@link Color} of the outline.
  76241. * @memberof PolylineVolumeGraphics.prototype
  76242. * @type {Property}
  76243. * @default Color.BLACK
  76244. */
  76245. outlineColor : createPropertyDescriptor('outlineColor'),
  76246. /**
  76247. * Gets or sets the numeric Property specifying the width of the outline.
  76248. * @memberof PolylineVolumeGraphics.prototype
  76249. * @type {Property}
  76250. * @default 1.0
  76251. */
  76252. outlineWidth : createPropertyDescriptor('outlineWidth'),
  76253. /**
  76254. * Gets or sets the {@link CornerType} Property specifying the style of the corners.
  76255. * @memberof PolylineVolumeGraphics.prototype
  76256. * @type {Property}
  76257. * @default CornerType.ROUNDED
  76258. */
  76259. cornerType : createPropertyDescriptor('cornerType'),
  76260. /**
  76261. * Get or sets the enum Property specifying whether the volume
  76262. * casts or receives shadows from each light source.
  76263. * @memberof PolylineVolumeGraphics.prototype
  76264. * @type {Property}
  76265. * @default ShadowMode.DISABLED
  76266. */
  76267. shadows : createPropertyDescriptor('shadows'),
  76268. /**
  76269. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this volume will be displayed.
  76270. * @memberof PolylineVolumeGraphics.prototype
  76271. * @type {Property}
  76272. */
  76273. distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition')
  76274. });
  76275. /**
  76276. * Duplicates this instance.
  76277. *
  76278. * @param {PolylineVolumeGraphics} [result] The object onto which to store the result.
  76279. * @returns {PolylineVolumeGraphics} The modified result parameter or a new instance if one was not provided.
  76280. */
  76281. PolylineVolumeGraphics.prototype.clone = function(result) {
  76282. if (!defined(result)) {
  76283. return new PolylineVolumeGraphics(this);
  76284. }
  76285. result.show = this.show;
  76286. result.material = this.material;
  76287. result.positions = this.positions;
  76288. result.shape = this.shape;
  76289. result.granularity = this.granularity;
  76290. result.fill = this.fill;
  76291. result.outline = this.outline;
  76292. result.outlineColor = this.outlineColor;
  76293. result.outlineWidth = this.outlineWidth;
  76294. result.cornerType = this.cornerType;
  76295. result.shadows = this.shadows;
  76296. result.distanceDisplayCondition = this.distanceDisplayCondition;
  76297. return result;
  76298. };
  76299. /**
  76300. * Assigns each unassigned property on this object to the value
  76301. * of the same property on the provided source object.
  76302. *
  76303. * @param {PolylineVolumeGraphics} source The object to be merged into this object.
  76304. */
  76305. PolylineVolumeGraphics.prototype.merge = function(source) {
  76306. if (!defined(source)) {
  76307. throw new DeveloperError('source is required.');
  76308. }
  76309. this.show = defaultValue(this.show, source.show);
  76310. this.material = defaultValue(this.material, source.material);
  76311. this.positions = defaultValue(this.positions, source.positions);
  76312. this.shape = defaultValue(this.shape, source.shape);
  76313. this.granularity = defaultValue(this.granularity, source.granularity);
  76314. this.fill = defaultValue(this.fill, source.fill);
  76315. this.outline = defaultValue(this.outline, source.outline);
  76316. this.outlineColor = defaultValue(this.outlineColor, source.outlineColor);
  76317. this.outlineWidth = defaultValue(this.outlineWidth, source.outlineWidth);
  76318. this.cornerType = defaultValue(this.cornerType, source.cornerType);
  76319. this.shadows = defaultValue(this.shadows, source.shadows);
  76320. this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
  76321. };
  76322. return PolylineVolumeGraphics;
  76323. });
  76324. /*global define*/
  76325. define('DataSources/RectangleGraphics',[
  76326. '../Core/defaultValue',
  76327. '../Core/defined',
  76328. '../Core/defineProperties',
  76329. '../Core/DeveloperError',
  76330. '../Core/Event',
  76331. './createMaterialPropertyDescriptor',
  76332. './createPropertyDescriptor'
  76333. ], function(
  76334. defaultValue,
  76335. defined,
  76336. defineProperties,
  76337. DeveloperError,
  76338. Event,
  76339. createMaterialPropertyDescriptor,
  76340. createPropertyDescriptor) {
  76341. 'use strict';
  76342. /**
  76343. * Describes graphics for a {@link Rectangle}.
  76344. * The rectangle conforms to the curvature of the globe and can be placed on the surface or
  76345. * at altitude and can optionally be extruded into a volume.
  76346. *
  76347. * @alias RectangleGraphics
  76348. * @constructor
  76349. *
  76350. * @param {Object} [options] Object with the following properties:
  76351. * @param {Property} [options.coordinates] The Property specifying the {@link Rectangle}.
  76352. * @param {Property} [options.height=0] A numeric Property specifying the altitude of the rectangle relative to the ellipsoid surface.
  76353. * @param {Property} [options.extrudedHeight] A numeric Property specifying the altitude of the rectangle's extruded face relative to the ellipsoid surface.
  76354. * @param {Property} [options.closeTop=true] A boolean Property specifying whether the rectangle has a top cover when extruded
  76355. * @param {Property} [options.closeBottom=true] A boolean Property specifying whether the rectangle has a bottom cover when extruded.
  76356. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the rectangle.
  76357. * @param {Property} [options.fill=true] A boolean Property specifying whether the rectangle is filled with the provided material.
  76358. * @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to fill the rectangle.
  76359. * @param {Property} [options.outline=false] A boolean Property specifying whether the rectangle is outlined.
  76360. * @param {Property} [options.outlineColor=Color.BLACK] A Property specifying the {@link Color} of the outline.
  76361. * @param {Property} [options.outlineWidth=1.0] A numeric Property specifying the width of the outline.
  76362. * @param {Property} [options.rotation=0.0] A numeric property specifying the rotation of the rectangle clockwise from north.
  76363. * @param {Property} [options.stRotation=0.0] A numeric property specifying the rotation of the rectangle texture counter-clockwise from north.
  76364. * @param {Property} [options.granularity=Cesium.Math.RADIANS_PER_DEGREE] A numeric Property specifying the angular distance between points on the rectangle.
  76365. * @param {Property} [options.shadows=ShadowMode.DISABLED] An enum Property specifying whether the rectangle casts or receives shadows from each light source.
  76366. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this rectangle will be displayed.
  76367. *
  76368. * @see Entity
  76369. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Rectangle.html|Cesium Sandcastle Rectangle Demo}
  76370. */
  76371. function RectangleGraphics(options) {
  76372. this._show = undefined;
  76373. this._showSubscription = undefined;
  76374. this._material = undefined;
  76375. this._materialSubscription = undefined;
  76376. this._coordinates = undefined;
  76377. this._coordinatesSubscription = undefined;
  76378. this._height = undefined;
  76379. this._heightSubscription = undefined;
  76380. this._extrudedHeight = undefined;
  76381. this._extrudedHeightSubscription = undefined;
  76382. this._granularity = undefined;
  76383. this._granularitySubscription = undefined;
  76384. this._stRotation = undefined;
  76385. this._stRotationSubscription = undefined;
  76386. this._rotation = undefined;
  76387. this._rotationSubscription = undefined;
  76388. this._closeTop = undefined;
  76389. this._closeTopSubscription = undefined;
  76390. this._closeBottom = undefined;
  76391. this._closeBottomSubscription = undefined;
  76392. this._fill = undefined;
  76393. this._fillSubscription = undefined;
  76394. this._outline = undefined;
  76395. this._outlineSubscription = undefined;
  76396. this._outlineColor = undefined;
  76397. this._outlineColorSubscription = undefined;
  76398. this._outlineWidth = undefined;
  76399. this._outlineWidthSubscription = undefined;
  76400. this._shadows = undefined;
  76401. this._shadowsSubscription = undefined;
  76402. this._distanceDisplayCondition = undefined;
  76403. this._distancedisplayConditionSubscription = undefined;
  76404. this._definitionChanged = new Event();
  76405. this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
  76406. }
  76407. defineProperties(RectangleGraphics.prototype, {
  76408. /**
  76409. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  76410. * @memberof RectangleGraphics.prototype
  76411. *
  76412. * @type {Event}
  76413. * @readonly
  76414. */
  76415. definitionChanged : {
  76416. get : function() {
  76417. return this._definitionChanged;
  76418. }
  76419. },
  76420. /**
  76421. * Gets or sets the boolean Property specifying the visibility of the rectangle.
  76422. * @memberof RectangleGraphics.prototype
  76423. * @type {Property}
  76424. * @default true
  76425. */
  76426. show : createPropertyDescriptor('show'),
  76427. /**
  76428. * Gets or sets the Property specifying the {@link Rectangle}.
  76429. * @memberof RectangleGraphics.prototype
  76430. * @type {Property}
  76431. */
  76432. coordinates : createPropertyDescriptor('coordinates'),
  76433. /**
  76434. * Gets or sets the Property specifying the material used to fill the rectangle.
  76435. * @memberof RectangleGraphics.prototype
  76436. * @type {MaterialProperty}
  76437. * @default Color.WHITE
  76438. */
  76439. material : createMaterialPropertyDescriptor('material'),
  76440. /**
  76441. * Gets or sets the numeric Property specifying the altitude of the rectangle.
  76442. * @memberof RectangleGraphics.prototype
  76443. * @type {Property}
  76444. * @default 0.0
  76445. */
  76446. height : createPropertyDescriptor('height'),
  76447. /**
  76448. * Gets or sets the numeric Property specifying the altitude of the rectangle extrusion.
  76449. * Setting this property creates volume starting at height and ending at this altitude.
  76450. * @memberof RectangleGraphics.prototype
  76451. * @type {Property}
  76452. */
  76453. extrudedHeight : createPropertyDescriptor('extrudedHeight'),
  76454. /**
  76455. * Gets or sets the numeric Property specifying the angular distance between points on the rectangle.
  76456. * @memberof RectangleGraphics.prototype
  76457. * @type {Property}
  76458. * @default {CesiumMath.RADIANS_PER_DEGREE}
  76459. */
  76460. granularity : createPropertyDescriptor('granularity'),
  76461. /**
  76462. * Gets or sets the numeric property specifying the rotation of the rectangle texture counter-clockwise from north.
  76463. * @memberof RectangleGraphics.prototype
  76464. * @type {Property}
  76465. * @default 0
  76466. */
  76467. stRotation : createPropertyDescriptor('stRotation'),
  76468. /**
  76469. * Gets or sets the numeric property specifying the rotation of the rectangle clockwise from north.
  76470. * @memberof RectangleGraphics.prototype
  76471. * @type {Property}
  76472. * @default 0
  76473. */
  76474. rotation : createPropertyDescriptor('rotation'),
  76475. /**
  76476. * Gets or sets the boolean Property specifying whether the rectangle is filled with the provided material.
  76477. * @memberof RectangleGraphics.prototype
  76478. * @type {Property}
  76479. * @default true
  76480. */
  76481. fill : createPropertyDescriptor('fill'),
  76482. /**
  76483. * Gets or sets the Property specifying whether the rectangle is outlined.
  76484. * @memberof RectangleGraphics.prototype
  76485. * @type {Property}
  76486. * @default false
  76487. */
  76488. outline : createPropertyDescriptor('outline'),
  76489. /**
  76490. * Gets or sets the Property specifying the {@link Color} of the outline.
  76491. * @memberof RectangleGraphics.prototype
  76492. * @type {Property}
  76493. * @default Color.BLACK
  76494. */
  76495. outlineColor : createPropertyDescriptor('outlineColor'),
  76496. /**
  76497. * Gets or sets the numeric Property specifying the width of the outline.
  76498. * @memberof RectangleGraphics.prototype
  76499. * @type {Property}
  76500. * @default 1.0
  76501. */
  76502. outlineWidth : createPropertyDescriptor('outlineWidth'),
  76503. /**
  76504. * Gets or sets the boolean Property specifying whether the rectangle has a top cover when extruded.
  76505. * @memberof RectangleGraphics.prototype
  76506. * @type {Property}
  76507. * @default true
  76508. */
  76509. closeTop : createPropertyDescriptor('closeTop'),
  76510. /**
  76511. * Gets or sets the boolean Property specifying whether the rectangle has a bottom cover when extruded.
  76512. * @memberof RectangleGraphics.prototype
  76513. * @type {Property}
  76514. * @default true
  76515. */
  76516. closeBottom : createPropertyDescriptor('closeBottom'),
  76517. /**
  76518. * Get or sets the enum Property specifying whether the rectangle
  76519. * casts or receives shadows from each light source.
  76520. * @memberof RectangleGraphics.prototype
  76521. * @type {Property}
  76522. * @default ShadowMode.DISABLED
  76523. */
  76524. shadows : createPropertyDescriptor('shadows'),
  76525. /**
  76526. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this rectangle will be displayed.
  76527. * @memberof RectangleGraphics.prototype
  76528. * @type {Property}
  76529. */
  76530. distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition')
  76531. });
  76532. /**
  76533. * Duplicates this instance.
  76534. *
  76535. * @param {RectangleGraphics} [result] The object onto which to store the result.
  76536. * @returns {RectangleGraphics} The modified result parameter or a new instance if one was not provided.
  76537. */
  76538. RectangleGraphics.prototype.clone = function(result) {
  76539. if (!defined(result)) {
  76540. return new RectangleGraphics(this);
  76541. }
  76542. result.show = this.show;
  76543. result.coordinates = this.coordinates;
  76544. result.material = this.material;
  76545. result.height = this.height;
  76546. result.extrudedHeight = this.extrudedHeight;
  76547. result.granularity = this.granularity;
  76548. result.stRotation = this.stRotation;
  76549. result.rotation = this.rotation;
  76550. result.fill = this.fill;
  76551. result.outline = this.outline;
  76552. result.outlineColor = this.outlineColor;
  76553. result.outlineWidth = this.outlineWidth;
  76554. result.closeTop = this.closeTop;
  76555. result.closeBottom = this.closeBottom;
  76556. result.shadows = this.shadows;
  76557. result.distanceDisplayCondition = this.distanceDisplayCondition;
  76558. return result;
  76559. };
  76560. /**
  76561. * Assigns each unassigned property on this object to the value
  76562. * of the same property on the provided source object.
  76563. *
  76564. * @param {RectangleGraphics} source The object to be merged into this object.
  76565. */
  76566. RectangleGraphics.prototype.merge = function(source) {
  76567. if (!defined(source)) {
  76568. throw new DeveloperError('source is required.');
  76569. }
  76570. this.show = defaultValue(this.show, source.show);
  76571. this.coordinates = defaultValue(this.coordinates, source.coordinates);
  76572. this.material = defaultValue(this.material, source.material);
  76573. this.height = defaultValue(this.height, source.height);
  76574. this.extrudedHeight = defaultValue(this.extrudedHeight, source.extrudedHeight);
  76575. this.granularity = defaultValue(this.granularity, source.granularity);
  76576. this.stRotation = defaultValue(this.stRotation, source.stRotation);
  76577. this.rotation = defaultValue(this.rotation, source.rotation);
  76578. this.fill = defaultValue(this.fill, source.fill);
  76579. this.outline = defaultValue(this.outline, source.outline);
  76580. this.outlineColor = defaultValue(this.outlineColor, source.outlineColor);
  76581. this.outlineWidth = defaultValue(this.outlineWidth, source.outlineWidth);
  76582. this.closeTop = defaultValue(this.closeTop, source.closeTop);
  76583. this.closeBottom = defaultValue(this.closeBottom, source.closeBottom);
  76584. this.shadows = defaultValue(this.shadows, source.shadows);
  76585. this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
  76586. };
  76587. return RectangleGraphics;
  76588. });
  76589. /*global define*/
  76590. define('DataSources/WallGraphics',[
  76591. '../Core/defaultValue',
  76592. '../Core/defined',
  76593. '../Core/defineProperties',
  76594. '../Core/DeveloperError',
  76595. '../Core/Event',
  76596. './createMaterialPropertyDescriptor',
  76597. './createPropertyDescriptor'
  76598. ], function(
  76599. defaultValue,
  76600. defined,
  76601. defineProperties,
  76602. DeveloperError,
  76603. Event,
  76604. createMaterialPropertyDescriptor,
  76605. createPropertyDescriptor) {
  76606. 'use strict';
  76607. /**
  76608. * Describes a two dimensional wall defined as a line strip and optional maximum and minimum heights.
  76609. * The wall conforms to the curvature of the globe and can be placed along the surface or at altitude.
  76610. *
  76611. * @alias WallGraphics
  76612. * @constructor
  76613. *
  76614. * @param {Object} [options] Object with the following properties:
  76615. * @param {Property} [options.positions] A Property specifying the array of {@link Cartesian3} positions which define the top of the wall.
  76616. * @param {Property} [options.maximumHeights] A Property specifying an array of heights to be used for the top of the wall instead of the height of each position.
  76617. * @param {Property} [options.minimumHeights] A Property specifying an array of heights to be used for the bottom of the wall instead of the globe surface.
  76618. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the wall.
  76619. * @param {Property} [options.fill=true] A boolean Property specifying whether the wall is filled with the provided material.
  76620. * @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to fill the wall.
  76621. * @param {Property} [options.outline=false] A boolean Property specifying whether the wall is outlined.
  76622. * @param {Property} [options.outlineColor=Color.BLACK] A Property specifying the {@link Color} of the outline.
  76623. * @param {Property} [options.outlineWidth=1.0] A numeric Property specifying the width of the outline.
  76624. * @param {Property} [options.granularity=Cesium.Math.RADIANS_PER_DEGREE] A numeric Property specifying the angular distance between each latitude and longitude point.
  76625. * @param {Property} [options.shadows=ShadowMode.DISABLED] An enum Property specifying whether the wall casts or receives shadows from each light source.
  76626. * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this wall will be displayed.
  76627. *
  76628. * @see Entity
  76629. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Wall.html|Cesium Sandcastle Wall Demo}
  76630. */
  76631. function WallGraphics(options) {
  76632. this._show = undefined;
  76633. this._showSubscription = undefined;
  76634. this._material = undefined;
  76635. this._materialSubscription = undefined;
  76636. this._positions = undefined;
  76637. this._positionsSubscription = undefined;
  76638. this._minimumHeights = undefined;
  76639. this._minimumHeightsSubscription = undefined;
  76640. this._maximumHeights = undefined;
  76641. this._maximumHeightsSubscription = undefined;
  76642. this._granularity = undefined;
  76643. this._granularitySubscription = undefined;
  76644. this._fill = undefined;
  76645. this._fillSubscription = undefined;
  76646. this._outline = undefined;
  76647. this._outlineSubscription = undefined;
  76648. this._outlineColor = undefined;
  76649. this._outlineColorSubscription = undefined;
  76650. this._outlineWidth = undefined;
  76651. this._outlineWidthSubscription = undefined;
  76652. this._shadows = undefined;
  76653. this._shadowsSubscription = undefined;
  76654. this._distanceDisplayCondition = undefined;
  76655. this._distanceDisplayConditionSubscription = undefined;
  76656. this._definitionChanged = new Event();
  76657. this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
  76658. }
  76659. defineProperties(WallGraphics.prototype, {
  76660. /**
  76661. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  76662. * @memberof WallGraphics.prototype
  76663. *
  76664. * @type {Event}
  76665. * @readonly
  76666. */
  76667. definitionChanged : {
  76668. get : function() {
  76669. return this._definitionChanged;
  76670. }
  76671. },
  76672. /**
  76673. * Gets or sets the boolean Property specifying the visibility of the wall.
  76674. * @memberof WallGraphics.prototype
  76675. * @type {Property}
  76676. * @default true
  76677. */
  76678. show : createPropertyDescriptor('show'),
  76679. /**
  76680. * Gets or sets the Property specifying the material used to fill the wall.
  76681. * @memberof WallGraphics.prototype
  76682. * @type {MaterialProperty}
  76683. * @default Color.WHITE
  76684. */
  76685. material : createMaterialPropertyDescriptor('material'),
  76686. /**
  76687. * Gets or sets the Property specifying the array of {@link Cartesian3} positions which define the top of the wall.
  76688. * @memberof WallGraphics.prototype
  76689. * @type {Property}
  76690. */
  76691. positions : createPropertyDescriptor('positions'),
  76692. /**
  76693. * Gets or sets the Property specifying an array of heights to be used for the bottom of the wall instead of the surface of the globe.
  76694. * If defined, the array must be the same length as {@link Wall#positions}.
  76695. * @memberof WallGraphics.prototype
  76696. * @type {Property}
  76697. */
  76698. minimumHeights : createPropertyDescriptor('minimumHeights'),
  76699. /**
  76700. * Gets or sets the Property specifying an array of heights to be used for the top of the wall instead of the height of each position.
  76701. * If defined, the array must be the same length as {@link Wall#positions}.
  76702. * @memberof WallGraphics.prototype
  76703. * @type {Property}
  76704. */
  76705. maximumHeights : createPropertyDescriptor('maximumHeights'),
  76706. /**
  76707. * Gets or sets the numeric Property specifying the angular distance between points on the wall.
  76708. * @memberof WallGraphics.prototype
  76709. * @type {Property}
  76710. * @default {CesiumMath.RADIANS_PER_DEGREE}
  76711. */
  76712. granularity : createPropertyDescriptor('granularity'),
  76713. /**
  76714. * Gets or sets the boolean Property specifying whether the wall is filled with the provided material.
  76715. * @memberof WallGraphics.prototype
  76716. * @type {Property}
  76717. * @default true
  76718. */
  76719. fill : createPropertyDescriptor('fill'),
  76720. /**
  76721. * Gets or sets the Property specifying whether the wall is outlined.
  76722. * @memberof WallGraphics.prototype
  76723. * @type {Property}
  76724. * @default false
  76725. */
  76726. outline : createPropertyDescriptor('outline'),
  76727. /**
  76728. * Gets or sets the Property specifying the {@link Color} of the outline.
  76729. * @memberof WallGraphics.prototype
  76730. * @type {Property}
  76731. * @default Color.BLACK
  76732. */
  76733. outlineColor : createPropertyDescriptor('outlineColor'),
  76734. /**
  76735. * Gets or sets the numeric Property specifying the width of the outline.
  76736. * @memberof WallGraphics.prototype
  76737. * @type {Property}
  76738. * @default 1.0
  76739. */
  76740. outlineWidth : createPropertyDescriptor('outlineWidth'),
  76741. /**
  76742. * Get or sets the enum Property specifying whether the wall
  76743. * casts or receives shadows from each light source.
  76744. * @memberof WallGraphics.prototype
  76745. * @type {Property}
  76746. * @default ShadowMode.DISABLED
  76747. */
  76748. shadows : createPropertyDescriptor('shadows'),
  76749. /**
  76750. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this wall will be displayed.
  76751. * @memberof WallGraphics.prototype
  76752. * @type {Property}
  76753. */
  76754. distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition')
  76755. });
  76756. /**
  76757. * Duplicates this instance.
  76758. *
  76759. * @param {WallGraphics} [result] The object onto which to store the result.
  76760. * @returns {WallGraphics} The modified result parameter or a new instance if one was not provided.
  76761. */
  76762. WallGraphics.prototype.clone = function(result) {
  76763. if (!defined(result)) {
  76764. return new WallGraphics(this);
  76765. }
  76766. result.show = this.show;
  76767. result.material = this.material;
  76768. result.positions = this.positions;
  76769. result.minimumHeights = this.minimumHeights;
  76770. result.maximumHeights = this.maximumHeights;
  76771. result.granularity = this.granularity;
  76772. result.fill = this.fill;
  76773. result.outline = this.outline;
  76774. result.outlineColor = this.outlineColor;
  76775. result.outlineWidth = this.outlineWidth;
  76776. result.shadows = this.shadows;
  76777. result.distanceDisplayCondition = this.distanceDisplayCondition;
  76778. return result;
  76779. };
  76780. /**
  76781. * Assigns each unassigned property on this object to the value
  76782. * of the same property on the provided source object.
  76783. *
  76784. * @param {WallGraphics} source The object to be merged into this object.
  76785. */
  76786. WallGraphics.prototype.merge = function(source) {
  76787. if (!defined(source)) {
  76788. throw new DeveloperError('source is required.');
  76789. }
  76790. this.show = defaultValue(this.show, source.show);
  76791. this.material = defaultValue(this.material, source.material);
  76792. this.positions = defaultValue(this.positions, source.positions);
  76793. this.minimumHeights = defaultValue(this.minimumHeights, source.minimumHeights);
  76794. this.maximumHeights = defaultValue(this.maximumHeights, source.maximumHeights);
  76795. this.granularity = defaultValue(this.granularity, source.granularity);
  76796. this.fill = defaultValue(this.fill, source.fill);
  76797. this.outline = defaultValue(this.outline, source.outline);
  76798. this.outlineColor = defaultValue(this.outlineColor, source.outlineColor);
  76799. this.outlineWidth = defaultValue(this.outlineWidth, source.outlineWidth);
  76800. this.shadows = defaultValue(this.shadows, source.shadows);
  76801. this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
  76802. };
  76803. return WallGraphics;
  76804. });
  76805. /*global define*/
  76806. define('DataSources/Entity',[
  76807. '../Core/Cartesian3',
  76808. '../Core/createGuid',
  76809. '../Core/defaultValue',
  76810. '../Core/defined',
  76811. '../Core/defineProperties',
  76812. '../Core/DeveloperError',
  76813. '../Core/Event',
  76814. '../Core/Matrix3',
  76815. '../Core/Matrix4',
  76816. '../Core/Quaternion',
  76817. '../Core/Transforms',
  76818. './BillboardGraphics',
  76819. './BoxGraphics',
  76820. './ConstantPositionProperty',
  76821. './CorridorGraphics',
  76822. './createPropertyDescriptor',
  76823. './createRawPropertyDescriptor',
  76824. './CylinderGraphics',
  76825. './EllipseGraphics',
  76826. './EllipsoidGraphics',
  76827. './LabelGraphics',
  76828. './ModelGraphics',
  76829. './PathGraphics',
  76830. './PointGraphics',
  76831. './PolygonGraphics',
  76832. './PolylineGraphics',
  76833. './PolylineVolumeGraphics',
  76834. './Property',
  76835. './RectangleGraphics',
  76836. './WallGraphics'
  76837. ], function(
  76838. Cartesian3,
  76839. createGuid,
  76840. defaultValue,
  76841. defined,
  76842. defineProperties,
  76843. DeveloperError,
  76844. Event,
  76845. Matrix3,
  76846. Matrix4,
  76847. Quaternion,
  76848. Transforms,
  76849. BillboardGraphics,
  76850. BoxGraphics,
  76851. ConstantPositionProperty,
  76852. CorridorGraphics,
  76853. createPropertyDescriptor,
  76854. createRawPropertyDescriptor,
  76855. CylinderGraphics,
  76856. EllipseGraphics,
  76857. EllipsoidGraphics,
  76858. LabelGraphics,
  76859. ModelGraphics,
  76860. PathGraphics,
  76861. PointGraphics,
  76862. PolygonGraphics,
  76863. PolylineGraphics,
  76864. PolylineVolumeGraphics,
  76865. Property,
  76866. RectangleGraphics,
  76867. WallGraphics) {
  76868. 'use strict';
  76869. function createConstantPositionProperty(value) {
  76870. return new ConstantPositionProperty(value);
  76871. }
  76872. function createPositionPropertyDescriptor(name) {
  76873. return createPropertyDescriptor(name, undefined, createConstantPositionProperty);
  76874. }
  76875. function createPropertyTypeDescriptor(name, Type) {
  76876. return createPropertyDescriptor(name, undefined, function(value) {
  76877. if (value instanceof Type) {
  76878. return value;
  76879. }
  76880. return new Type(value);
  76881. });
  76882. }
  76883. /**
  76884. * Entity instances aggregate multiple forms of visualization into a single high-level object.
  76885. * They can be created manually and added to {@link Viewer#entities} or be produced by
  76886. * data sources, such as {@link CzmlDataSource} and {@link GeoJsonDataSource}.
  76887. * @alias Entity
  76888. * @constructor
  76889. *
  76890. * @param {Object} [options] Object with the following properties:
  76891. * @param {String} [options.id] A unique identifier for this object. If none is provided, a GUID is generated.
  76892. * @param {String} [options.name] A human readable name to display to users. It does not have to be unique.
  76893. * @param {TimeIntervalCollection} [options.availability] The availability, if any, associated with this object.
  76894. * @param {Boolean} [options.show] A boolean value indicating if the entity and its children are displayed.
  76895. * @param {Property} [options.description] A string Property specifying an HTML description for this entity.
  76896. * @param {PositionProperty} [options.position] A Property specifying the entity position.
  76897. * @param {Property} [options.orientation] A Property specifying the entity orientation.
  76898. * @param {Property} [options.viewFrom] A suggested initial offset for viewing this object.
  76899. * @param {Entity} [options.parent] A parent entity to associate with this entity.
  76900. * @param {BillboardGraphics} [options.billboard] A billboard to associate with this entity.
  76901. * @param {BoxGraphics} [options.box] A box to associate with this entity.
  76902. * @param {CorridorGraphics} [options.corridor] A corridor to associate with this entity.
  76903. * @param {CylinderGraphics} [options.cylinder] A cylinder to associate with this entity.
  76904. * @param {EllipseGraphics} [options.ellipse] A ellipse to associate with this entity.
  76905. * @param {EllipsoidGraphics} [options.ellipsoid] A ellipsoid to associate with this entity.
  76906. * @param {LabelGraphics} [options.label] A options.label to associate with this entity.
  76907. * @param {ModelGraphics} [options.model] A model to associate with this entity.
  76908. * @param {PathGraphics} [options.path] A path to associate with this entity.
  76909. * @param {PointGraphics} [options.point] A point to associate with this entity.
  76910. * @param {PolygonGraphics} [options.polygon] A polygon to associate with this entity.
  76911. * @param {PolylineGraphics} [options.polyline] A polyline to associate with this entity.
  76912. * @param {PolylineVolumeGraphics} [options.polylineVolume] A polylineVolume to associate with this entity.
  76913. * @param {RectangleGraphics} [options.rectangle] A rectangle to associate with this entity.
  76914. * @param {WallGraphics} [options.wall] A wall to associate with this entity.
  76915. *
  76916. * @see {@link http://cesiumjs.org/2015/02/02/Visualizing-Spatial-Data/|Visualizing Spatial Data}
  76917. */
  76918. function Entity(options) {
  76919. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  76920. var id = options.id;
  76921. if (!defined(id)) {
  76922. id = createGuid();
  76923. }
  76924. this._availability = undefined;
  76925. this._id = id;
  76926. this._definitionChanged = new Event();
  76927. this._name = options.name;
  76928. this._show = defaultValue(options.show, true);
  76929. this._parent = undefined;
  76930. this._propertyNames = ['billboard', 'box', 'corridor', 'cylinder', 'description', 'ellipse', //
  76931. 'ellipsoid', 'label', 'model', 'orientation', 'path', 'point', 'polygon', //
  76932. 'polyline', 'polylineVolume', 'position', 'rectangle', 'viewFrom', 'wall'];
  76933. this._billboard = undefined;
  76934. this._billboardSubscription = undefined;
  76935. this._box = undefined;
  76936. this._boxSubscription = undefined;
  76937. this._corridor = undefined;
  76938. this._corridorSubscription = undefined;
  76939. this._cylinder = undefined;
  76940. this._cylinderSubscription = undefined;
  76941. this._description = undefined;
  76942. this._descriptionSubscription = undefined;
  76943. this._ellipse = undefined;
  76944. this._ellipseSubscription = undefined;
  76945. this._ellipsoid = undefined;
  76946. this._ellipsoidSubscription = undefined;
  76947. this._label = undefined;
  76948. this._labelSubscription = undefined;
  76949. this._model = undefined;
  76950. this._modelSubscription = undefined;
  76951. this._orientation = undefined;
  76952. this._orientationSubscription = undefined;
  76953. this._path = undefined;
  76954. this._pathSubscription = undefined;
  76955. this._point = undefined;
  76956. this._pointSubscription = undefined;
  76957. this._polygon = undefined;
  76958. this._polygonSubscription = undefined;
  76959. this._polyline = undefined;
  76960. this._polylineSubscription = undefined;
  76961. this._polylineVolume = undefined;
  76962. this._polylineVolumeSubscription = undefined;
  76963. this._position = undefined;
  76964. this._positionSubscription = undefined;
  76965. this._rectangle = undefined;
  76966. this._rectangleSubscription = undefined;
  76967. this._viewFrom = undefined;
  76968. this._viewFromSubscription = undefined;
  76969. this._wall = undefined;
  76970. this._wallSubscription = undefined;
  76971. this._children = [];
  76972. /**
  76973. * Gets or sets the entity collection that this entity belongs to.
  76974. * @type {EntityCollection}
  76975. */
  76976. this.entityCollection = undefined;
  76977. this.parent = options.parent;
  76978. this.merge(options);
  76979. }
  76980. function updateShow(entity, children, isShowing) {
  76981. var length = children.length;
  76982. for (var i = 0; i < length; i++) {
  76983. var child = children[i];
  76984. var childShow = child._show;
  76985. var oldValue = !isShowing && childShow;
  76986. var newValue = isShowing && childShow;
  76987. if (oldValue !== newValue) {
  76988. updateShow(child, child._children, isShowing);
  76989. }
  76990. }
  76991. entity._definitionChanged.raiseEvent(entity, 'isShowing', isShowing, !isShowing);
  76992. }
  76993. defineProperties(Entity.prototype, {
  76994. /**
  76995. * The availability, if any, associated with this object.
  76996. * If availability is undefined, it is assumed that this object's
  76997. * other properties will return valid data for any provided time.
  76998. * If availability exists, the objects other properties will only
  76999. * provide valid data if queried within the given interval.
  77000. * @memberof Entity.prototype
  77001. * @type {TimeIntervalCollection}
  77002. */
  77003. availability : createRawPropertyDescriptor('availability'),
  77004. /**
  77005. * Gets the unique ID associated with this object.
  77006. * @memberof Entity.prototype
  77007. * @type {String}
  77008. */
  77009. id : {
  77010. get : function() {
  77011. return this._id;
  77012. }
  77013. },
  77014. /**
  77015. * Gets the event that is raised whenever a property or sub-property is changed or modified.
  77016. * @memberof Entity.prototype
  77017. *
  77018. * @type {Event}
  77019. * @readonly
  77020. */
  77021. definitionChanged : {
  77022. get : function() {
  77023. return this._definitionChanged;
  77024. }
  77025. },
  77026. /**
  77027. * Gets or sets the name of the object. The name is intended for end-user
  77028. * consumption and does not need to be unique.
  77029. * @memberof Entity.prototype
  77030. * @type {String}
  77031. */
  77032. name : createRawPropertyDescriptor('name'),
  77033. /**
  77034. * Gets or sets whether this entity should be displayed. When set to true,
  77035. * the entity is only displayed if the parent entity's show property is also true.
  77036. * @memberof Entity.prototype
  77037. * @type {Boolean}
  77038. */
  77039. show : {
  77040. get : function() {
  77041. return this._show;
  77042. },
  77043. set : function(value) {
  77044. if (!defined(value)) {
  77045. throw new DeveloperError('value is required.');
  77046. }
  77047. if (value === this._show) {
  77048. return;
  77049. }
  77050. var wasShowing = this.isShowing;
  77051. this._show = value;
  77052. var isShowing = this.isShowing;
  77053. if (wasShowing !== isShowing) {
  77054. updateShow(this, this._children, isShowing);
  77055. }
  77056. this._definitionChanged.raiseEvent(this, 'show', value, !value);
  77057. }
  77058. },
  77059. /**
  77060. * Gets whether this entity is being displayed, taking into account
  77061. * the visibility of any ancestor entities.
  77062. * @memberof Entity.prototype
  77063. * @type {Boolean}
  77064. */
  77065. isShowing : {
  77066. get : function() {
  77067. return this._show && (!defined(this.entityCollection) || this.entityCollection.show) && (!defined(this._parent) || this._parent.isShowing);
  77068. }
  77069. },
  77070. /**
  77071. * Gets or sets the parent object.
  77072. * @memberof Entity.prototype
  77073. * @type {Entity}
  77074. */
  77075. parent : {
  77076. get : function() {
  77077. return this._parent;
  77078. },
  77079. set : function(value) {
  77080. var oldValue = this._parent;
  77081. if (oldValue === value) {
  77082. return;
  77083. }
  77084. var wasShowing = this.isShowing;
  77085. if (defined(oldValue)) {
  77086. var index = oldValue._children.indexOf(this);
  77087. oldValue._children.splice(index, 1);
  77088. }
  77089. this._parent = value;
  77090. if (defined(value)) {
  77091. value._children.push(this);
  77092. }
  77093. var isShowing = this.isShowing;
  77094. if (wasShowing !== isShowing) {
  77095. updateShow(this, this._children, isShowing);
  77096. }
  77097. this._definitionChanged.raiseEvent(this, 'parent', value, oldValue);
  77098. }
  77099. },
  77100. /**
  77101. * Gets the names of all properties registered on this instance.
  77102. * @memberof Entity.prototype
  77103. * @type {Array}
  77104. */
  77105. propertyNames : {
  77106. get : function() {
  77107. return this._propertyNames;
  77108. }
  77109. },
  77110. /**
  77111. * Gets or sets the billboard.
  77112. * @memberof Entity.prototype
  77113. * @type {BillboardGraphics}
  77114. */
  77115. billboard : createPropertyTypeDescriptor('billboard', BillboardGraphics),
  77116. /**
  77117. * Gets or sets the box.
  77118. * @memberof Entity.prototype
  77119. * @type {BoxGraphics}
  77120. */
  77121. box : createPropertyTypeDescriptor('box', BoxGraphics),
  77122. /**
  77123. * Gets or sets the corridor.
  77124. * @memberof Entity.prototype
  77125. * @type {CorridorGraphics}
  77126. */
  77127. corridor : createPropertyTypeDescriptor('corridor', CorridorGraphics),
  77128. /**
  77129. * Gets or sets the cylinder.
  77130. * @memberof Entity.prototype
  77131. * @type {CylinderGraphics}
  77132. */
  77133. cylinder : createPropertyTypeDescriptor('cylinder', CylinderGraphics),
  77134. /**
  77135. * Gets or sets the description.
  77136. * @memberof Entity.prototype
  77137. * @type {Property}
  77138. */
  77139. description : createPropertyDescriptor('description'),
  77140. /**
  77141. * Gets or sets the ellipse.
  77142. * @memberof Entity.prototype
  77143. * @type {EllipseGraphics}
  77144. */
  77145. ellipse : createPropertyTypeDescriptor('ellipse', EllipseGraphics),
  77146. /**
  77147. * Gets or sets the ellipsoid.
  77148. * @memberof Entity.prototype
  77149. * @type {EllipsoidGraphics}
  77150. */
  77151. ellipsoid : createPropertyTypeDescriptor('ellipsoid', EllipsoidGraphics),
  77152. /**
  77153. * Gets or sets the label.
  77154. * @memberof Entity.prototype
  77155. * @type {LabelGraphics}
  77156. */
  77157. label : createPropertyTypeDescriptor('label', LabelGraphics),
  77158. /**
  77159. * Gets or sets the model.
  77160. * @memberof Entity.prototype
  77161. * @type {ModelGraphics}
  77162. */
  77163. model : createPropertyTypeDescriptor('model', ModelGraphics),
  77164. /**
  77165. * Gets or sets the orientation.
  77166. * @memberof Entity.prototype
  77167. * @type {Property}
  77168. */
  77169. orientation : createPropertyDescriptor('orientation'),
  77170. /**
  77171. * Gets or sets the path.
  77172. * @memberof Entity.prototype
  77173. * @type {PathGraphics}
  77174. */
  77175. path : createPropertyTypeDescriptor('path', PathGraphics),
  77176. /**
  77177. * Gets or sets the point graphic.
  77178. * @memberof Entity.prototype
  77179. * @type {PointGraphics}
  77180. */
  77181. point : createPropertyTypeDescriptor('point', PointGraphics),
  77182. /**
  77183. * Gets or sets the polygon.
  77184. * @memberof Entity.prototype
  77185. * @type {PolygonGraphics}
  77186. */
  77187. polygon : createPropertyTypeDescriptor('polygon', PolygonGraphics),
  77188. /**
  77189. * Gets or sets the polyline.
  77190. * @memberof Entity.prototype
  77191. * @type {PolylineGraphics}
  77192. */
  77193. polyline : createPropertyTypeDescriptor('polyline', PolylineGraphics),
  77194. /**
  77195. * Gets or sets the polyline volume.
  77196. * @memberof Entity.prototype
  77197. * @type {PolylineVolumeGraphics}
  77198. */
  77199. polylineVolume : createPropertyTypeDescriptor('polylineVolume', PolylineVolumeGraphics),
  77200. /**
  77201. * Gets or sets the position.
  77202. * @memberof Entity.prototype
  77203. * @type {PositionProperty}
  77204. */
  77205. position : createPositionPropertyDescriptor('position'),
  77206. /**
  77207. * Gets or sets the rectangle.
  77208. * @memberof Entity.prototype
  77209. * @type {RectangleGraphics}
  77210. */
  77211. rectangle : createPropertyTypeDescriptor('rectangle', RectangleGraphics),
  77212. /**
  77213. * Gets or sets the suggested initial offset for viewing this object
  77214. * with the camera. The offset is defined in the east-north-up reference frame.
  77215. * @memberof Entity.prototype
  77216. * @type {Property}
  77217. */
  77218. viewFrom : createPropertyDescriptor('viewFrom'),
  77219. /**
  77220. * Gets or sets the wall.
  77221. * @memberof Entity.prototype
  77222. * @type {WallGraphics}
  77223. */
  77224. wall : createPropertyTypeDescriptor('wall', WallGraphics)
  77225. });
  77226. /**
  77227. * Given a time, returns true if this object should have data during that time.
  77228. *
  77229. * @param {JulianDate} time The time to check availability for.
  77230. * @returns {Boolean} true if the object should have data during the provided time, false otherwise.
  77231. */
  77232. Entity.prototype.isAvailable = function(time) {
  77233. if (!defined(time)) {
  77234. throw new DeveloperError('time is required.');
  77235. }
  77236. var availability = this._availability;
  77237. return !defined(availability) || availability.contains(time);
  77238. };
  77239. /**
  77240. * Adds a property to this object. Once a property is added, it can be
  77241. * observed with {@link Entity#definitionChanged} and composited
  77242. * with {@link CompositeEntityCollection}
  77243. *
  77244. * @param {String} propertyName The name of the property to add.
  77245. *
  77246. * @exception {DeveloperError} "propertyName" is a reserved property name.
  77247. * @exception {DeveloperError} "propertyName" is already a registered property.
  77248. */
  77249. Entity.prototype.addProperty = function(propertyName) {
  77250. var propertyNames = this._propertyNames;
  77251. if (!defined(propertyName)) {
  77252. throw new DeveloperError('propertyName is required.');
  77253. }
  77254. if (propertyNames.indexOf(propertyName) !== -1) {
  77255. throw new DeveloperError(propertyName + ' is already a registered property.');
  77256. }
  77257. if (propertyName in this) {
  77258. throw new DeveloperError(propertyName + ' is a reserved property name.');
  77259. }
  77260. propertyNames.push(propertyName);
  77261. Object.defineProperty(this, propertyName, createRawPropertyDescriptor(propertyName, true));
  77262. };
  77263. /**
  77264. * Removed a property previously added with addProperty.
  77265. *
  77266. * @param {String} propertyName The name of the property to remove.
  77267. *
  77268. * @exception {DeveloperError} "propertyName" is a reserved property name.
  77269. * @exception {DeveloperError} "propertyName" is not a registered property.
  77270. */
  77271. Entity.prototype.removeProperty = function(propertyName) {
  77272. var propertyNames = this._propertyNames;
  77273. var index = propertyNames.indexOf(propertyName);
  77274. if (!defined(propertyName)) {
  77275. throw new DeveloperError('propertyName is required.');
  77276. }
  77277. if (index === -1) {
  77278. throw new DeveloperError(propertyName + ' is not a registered property.');
  77279. }
  77280. this._propertyNames.splice(index, 1);
  77281. delete this[propertyName];
  77282. };
  77283. /**
  77284. * Assigns each unassigned property on this object to the value
  77285. * of the same property on the provided source object.
  77286. *
  77287. * @param {Entity} source The object to be merged into this object.
  77288. */
  77289. Entity.prototype.merge = function(source) {
  77290. if (!defined(source)) {
  77291. throw new DeveloperError('source is required.');
  77292. }
  77293. //Name, show, and availability are not Property objects and are currently handled differently.
  77294. //source.show is intentionally ignored because this.show always has a value.
  77295. this.name = defaultValue(this.name, source.name);
  77296. this.availability = defaultValue(source.availability, this.availability);
  77297. var propertyNames = this._propertyNames;
  77298. var sourcePropertyNames = defined(source._propertyNames) ? source._propertyNames : Object.keys(source);
  77299. var propertyNamesLength = sourcePropertyNames.length;
  77300. for (var i = 0; i < propertyNamesLength; i++) {
  77301. var name = sourcePropertyNames[i];
  77302. //Ignore parent when merging, this only happens at construction time.
  77303. if (name === 'parent') {
  77304. continue;
  77305. }
  77306. var targetProperty = this[name];
  77307. var sourceProperty = source[name];
  77308. //Custom properties that are registered on the source entity must also
  77309. //get registered on this entity.
  77310. if (!defined(targetProperty) && propertyNames.indexOf(name) === -1) {
  77311. this.addProperty(name);
  77312. }
  77313. if (defined(sourceProperty)) {
  77314. if (defined(targetProperty)) {
  77315. if (defined(targetProperty.merge)) {
  77316. targetProperty.merge(sourceProperty);
  77317. }
  77318. } else if (defined(sourceProperty.merge) && defined(sourceProperty.clone)) {
  77319. this[name] = sourceProperty.clone();
  77320. } else {
  77321. this[name] = sourceProperty;
  77322. }
  77323. }
  77324. }
  77325. };
  77326. var matrix3Scratch = new Matrix3();
  77327. var positionScratch = new Cartesian3();
  77328. var orientationScratch = new Quaternion();
  77329. /**
  77330. * @private
  77331. */
  77332. Entity.prototype._getModelMatrix = function(time, result) {
  77333. var position = Property.getValueOrUndefined(this._position, time, positionScratch);
  77334. if (!defined(position)) {
  77335. return undefined;
  77336. }
  77337. var orientation = Property.getValueOrUndefined(this._orientation, time, orientationScratch);
  77338. if (!defined(orientation)) {
  77339. result = Transforms.eastNorthUpToFixedFrame(position, undefined, result);
  77340. } else {
  77341. result = Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(orientation, matrix3Scratch), position, result);
  77342. }
  77343. return result;
  77344. };
  77345. return Entity;
  77346. });
  77347. /*global define*/
  77348. define('DataSources/EntityCollection',[
  77349. '../Core/AssociativeArray',
  77350. '../Core/createGuid',
  77351. '../Core/defined',
  77352. '../Core/defineProperties',
  77353. '../Core/DeveloperError',
  77354. '../Core/Event',
  77355. '../Core/Iso8601',
  77356. '../Core/JulianDate',
  77357. '../Core/RuntimeError',
  77358. '../Core/TimeInterval',
  77359. './Entity'
  77360. ], function(
  77361. AssociativeArray,
  77362. createGuid,
  77363. defined,
  77364. defineProperties,
  77365. DeveloperError,
  77366. Event,
  77367. Iso8601,
  77368. JulianDate,
  77369. RuntimeError,
  77370. TimeInterval,
  77371. Entity) {
  77372. 'use strict';
  77373. var entityOptionsScratch = {
  77374. id : undefined
  77375. };
  77376. function fireChangedEvent(collection) {
  77377. if (collection._firing) {
  77378. collection._refire = true;
  77379. return;
  77380. }
  77381. if (collection._suspendCount === 0) {
  77382. var added = collection._addedEntities;
  77383. var removed = collection._removedEntities;
  77384. var changed = collection._changedEntities;
  77385. if (changed.length !== 0 || added.length !== 0 || removed.length !== 0) {
  77386. collection._firing = true;
  77387. do {
  77388. collection._refire = false;
  77389. var addedArray = added.values.slice(0);
  77390. var removedArray = removed.values.slice(0);
  77391. var changedArray = changed.values.slice(0);
  77392. added.removeAll();
  77393. removed.removeAll();
  77394. changed.removeAll();
  77395. collection._collectionChanged.raiseEvent(collection, addedArray, removedArray, changedArray);
  77396. } while (collection._refire);
  77397. collection._firing = false;
  77398. }
  77399. }
  77400. }
  77401. /**
  77402. * An observable collection of {@link Entity} instances where each entity has a unique id.
  77403. * @alias EntityCollection
  77404. * @constructor
  77405. *
  77406. * @param {DataSource|CompositeEntityCollection} [owner] The data source (or composite entity collection) which created this collection.
  77407. */
  77408. function EntityCollection(owner) {
  77409. this._owner = owner;
  77410. this._entities = new AssociativeArray();
  77411. this._addedEntities = new AssociativeArray();
  77412. this._removedEntities = new AssociativeArray();
  77413. this._changedEntities = new AssociativeArray();
  77414. this._suspendCount = 0;
  77415. this._collectionChanged = new Event();
  77416. this._id = createGuid();
  77417. this._show = true;
  77418. this._firing = false;
  77419. this._refire = false;
  77420. }
  77421. /**
  77422. * Prevents {@link EntityCollection#collectionChanged} events from being raised
  77423. * until a corresponding call is made to {@link EntityCollection#resumeEvents}, at which
  77424. * point a single event will be raised that covers all suspended operations.
  77425. * This allows for many items to be added and removed efficiently.
  77426. * This function can be safely called multiple times as long as there
  77427. * are corresponding calls to {@link EntityCollection#resumeEvents}.
  77428. */
  77429. EntityCollection.prototype.suspendEvents = function() {
  77430. this._suspendCount++;
  77431. };
  77432. /**
  77433. * Resumes raising {@link EntityCollection#collectionChanged} events immediately
  77434. * when an item is added or removed. Any modifications made while while events were suspended
  77435. * will be triggered as a single event when this function is called.
  77436. * This function is reference counted and can safely be called multiple times as long as there
  77437. * are corresponding calls to {@link EntityCollection#resumeEvents}.
  77438. *
  77439. * @exception {DeveloperError} resumeEvents can not be called before suspendEvents.
  77440. */
  77441. EntityCollection.prototype.resumeEvents = function() {
  77442. if (this._suspendCount === 0) {
  77443. throw new DeveloperError('resumeEvents can not be called before suspendEvents.');
  77444. }
  77445. this._suspendCount--;
  77446. fireChangedEvent(this);
  77447. };
  77448. /**
  77449. * The signature of the event generated by {@link EntityCollection#collectionChanged}.
  77450. * @function
  77451. *
  77452. * @param {EntityCollection} collection The collection that triggered the event.
  77453. * @param {Entity[]} added The array of {@link Entity} instances that have been added to the collection.
  77454. * @param {Entity[]} removed The array of {@link Entity} instances that have been removed from the collection.
  77455. * @param {Entity[]} changed The array of {@link Entity} instances that have been modified.
  77456. */
  77457. EntityCollection.collectionChangedEventCallback = undefined;
  77458. defineProperties(EntityCollection.prototype, {
  77459. /**
  77460. * Gets the event that is fired when entities are added or removed from the collection.
  77461. * The generated event is a {@link EntityCollection.collectionChangedEventCallback}.
  77462. * @memberof EntityCollection.prototype
  77463. * @readonly
  77464. * @type {Event}
  77465. */
  77466. collectionChanged : {
  77467. get : function() {
  77468. return this._collectionChanged;
  77469. }
  77470. },
  77471. /**
  77472. * Gets a globally unique identifier for this collection.
  77473. * @memberof EntityCollection.prototype
  77474. * @readonly
  77475. * @type {String}
  77476. */
  77477. id : {
  77478. get : function() {
  77479. return this._id;
  77480. }
  77481. },
  77482. /**
  77483. * Gets the array of Entity instances in the collection.
  77484. * This array should not be modified directly.
  77485. * @memberof EntityCollection.prototype
  77486. * @readonly
  77487. * @type {Entity[]}
  77488. */
  77489. values : {
  77490. get : function() {
  77491. return this._entities.values;
  77492. }
  77493. },
  77494. /**
  77495. * Gets whether or not this entity collection should be
  77496. * displayed. When true, each entity is only displayed if
  77497. * its own show property is also true.
  77498. * @memberof EntityCollection.prototype
  77499. * @type {Boolean}
  77500. */
  77501. show : {
  77502. get : function() {
  77503. return this._show;
  77504. },
  77505. set : function(value) {
  77506. if (!defined(value)) {
  77507. throw new DeveloperError('value is required.');
  77508. }
  77509. if (value === this._show) {
  77510. return;
  77511. }
  77512. //Since entity.isShowing includes the EntityCollection.show state
  77513. //in its calculation, we need to loop over the entities array
  77514. //twice, once to get the old showing value and a second time
  77515. //to raise the changed event.
  77516. this.suspendEvents();
  77517. var i;
  77518. var oldShows = [];
  77519. var entities = this._entities.values;
  77520. var entitiesLength = entities.length;
  77521. for (i = 0; i < entitiesLength; i++) {
  77522. oldShows.push(entities[i].isShowing);
  77523. }
  77524. this._show = value;
  77525. for (i = 0; i < entitiesLength; i++) {
  77526. var oldShow = oldShows[i];
  77527. var entity = entities[i];
  77528. if (oldShow !== entity.isShowing) {
  77529. entity.definitionChanged.raiseEvent(entity, 'isShowing', entity.isShowing, oldShow);
  77530. }
  77531. }
  77532. this.resumeEvents();
  77533. }
  77534. },
  77535. /**
  77536. * Gets the owner of this entity collection, ie. the data source or composite entity collection which created it.
  77537. * @memberof EntityCollection.prototype
  77538. * @readonly
  77539. * @type {DataSource|CompositeEntityCollection}
  77540. */
  77541. owner : {
  77542. get : function() {
  77543. return this._owner;
  77544. }
  77545. }
  77546. });
  77547. /**
  77548. * Computes the maximum availability of the entities in the collection.
  77549. * If the collection contains a mix of infinitely available data and non-infinite data,
  77550. * it will return the interval pertaining to the non-infinite data only. If all
  77551. * data is infinite, an infinite interval will be returned.
  77552. *
  77553. * @returns {TimeInterval} The availability of entities in the collection.
  77554. */
  77555. EntityCollection.prototype.computeAvailability = function() {
  77556. var startTime = Iso8601.MAXIMUM_VALUE;
  77557. var stopTime = Iso8601.MINIMUM_VALUE;
  77558. var entities = this._entities.values;
  77559. for (var i = 0, len = entities.length; i < len; i++) {
  77560. var entity = entities[i];
  77561. var availability = entity.availability;
  77562. if (defined(availability)) {
  77563. var start = availability.start;
  77564. var stop = availability.stop;
  77565. if (JulianDate.lessThan(start, startTime) && !start.equals(Iso8601.MINIMUM_VALUE)) {
  77566. startTime = start;
  77567. }
  77568. if (JulianDate.greaterThan(stop, stopTime) && !stop.equals(Iso8601.MAXIMUM_VALUE)) {
  77569. stopTime = stop;
  77570. }
  77571. }
  77572. }
  77573. if (Iso8601.MAXIMUM_VALUE.equals(startTime)) {
  77574. startTime = Iso8601.MINIMUM_VALUE;
  77575. }
  77576. if (Iso8601.MINIMUM_VALUE.equals(stopTime)) {
  77577. stopTime = Iso8601.MAXIMUM_VALUE;
  77578. }
  77579. return new TimeInterval({
  77580. start : startTime,
  77581. stop : stopTime
  77582. });
  77583. };
  77584. /**
  77585. * Add an entity to the collection.
  77586. *
  77587. * @param {Entity} entity The entity to be added.
  77588. * @returns {Entity} The entity that was added.
  77589. * @exception {DeveloperError} An entity with <entity.id> already exists in this collection.
  77590. */
  77591. EntityCollection.prototype.add = function(entity) {
  77592. if (!defined(entity)) {
  77593. throw new DeveloperError('entity is required.');
  77594. }
  77595. if (!(entity instanceof Entity)) {
  77596. entity = new Entity(entity);
  77597. }
  77598. var id = entity.id;
  77599. var entities = this._entities;
  77600. if (entities.contains(id)) {
  77601. throw new RuntimeError('An entity with id ' + id + ' already exists in this collection.');
  77602. }
  77603. entity.entityCollection = this;
  77604. entities.set(id, entity);
  77605. if (!this._removedEntities.remove(id)) {
  77606. this._addedEntities.set(id, entity);
  77607. }
  77608. entity.definitionChanged.addEventListener(EntityCollection.prototype._onEntityDefinitionChanged, this);
  77609. fireChangedEvent(this);
  77610. return entity;
  77611. };
  77612. /**
  77613. * Removes an entity from the collection.
  77614. *
  77615. * @param {Entity} entity The entity to be removed.
  77616. * @returns {Boolean} true if the item was removed, false if it did not exist in the collection.
  77617. */
  77618. EntityCollection.prototype.remove = function(entity) {
  77619. if (!defined(entity)) {
  77620. return false;
  77621. }
  77622. return this.removeById(entity.id);
  77623. };
  77624. /**
  77625. * Returns true if the provided entity is in this collection, false otherwise.
  77626. *
  77627. * @param {Entity} entity The entity.
  77628. * @returns {Boolean} true if the provided entity is in this collection, false otherwise.
  77629. */
  77630. EntityCollection.prototype.contains = function(entity) {
  77631. if (!defined(entity)) {
  77632. throw new DeveloperError('entity is required');
  77633. }
  77634. return this._entities.get(entity.id) === entity;
  77635. };
  77636. /**
  77637. * Removes an entity with the provided id from the collection.
  77638. *
  77639. * @param {Object} id The id of the entity to remove.
  77640. * @returns {Boolean} true if the item was removed, false if no item with the provided id existed in the collection.
  77641. */
  77642. EntityCollection.prototype.removeById = function(id) {
  77643. if (!defined(id)) {
  77644. return false;
  77645. }
  77646. var entities = this._entities;
  77647. var entity = entities.get(id);
  77648. if (!this._entities.remove(id)) {
  77649. return false;
  77650. }
  77651. if (!this._addedEntities.remove(id)) {
  77652. this._removedEntities.set(id, entity);
  77653. this._changedEntities.remove(id);
  77654. }
  77655. this._entities.remove(id);
  77656. entity.definitionChanged.removeEventListener(EntityCollection.prototype._onEntityDefinitionChanged, this);
  77657. fireChangedEvent(this);
  77658. return true;
  77659. };
  77660. /**
  77661. * Removes all Entities from the collection.
  77662. */
  77663. EntityCollection.prototype.removeAll = function() {
  77664. //The event should only contain items added before events were suspended
  77665. //and the contents of the collection.
  77666. var entities = this._entities;
  77667. var entitiesLength = entities.length;
  77668. var array = entities.values;
  77669. var addedEntities = this._addedEntities;
  77670. var removed = this._removedEntities;
  77671. for (var i = 0; i < entitiesLength; i++) {
  77672. var existingItem = array[i];
  77673. var existingItemId = existingItem.id;
  77674. var addedItem = addedEntities.get(existingItemId);
  77675. if (!defined(addedItem)) {
  77676. existingItem.definitionChanged.removeEventListener(EntityCollection.prototype._onEntityDefinitionChanged, this);
  77677. removed.set(existingItemId, existingItem);
  77678. }
  77679. }
  77680. entities.removeAll();
  77681. addedEntities.removeAll();
  77682. this._changedEntities.removeAll();
  77683. fireChangedEvent(this);
  77684. };
  77685. /**
  77686. * Gets an entity with the specified id.
  77687. *
  77688. * @param {Object} id The id of the entity to retrieve.
  77689. * @returns {Entity} The entity with the provided id or undefined if the id did not exist in the collection.
  77690. */
  77691. EntityCollection.prototype.getById = function(id) {
  77692. if (!defined(id)) {
  77693. throw new DeveloperError('id is required.');
  77694. }
  77695. return this._entities.get(id);
  77696. };
  77697. /**
  77698. * Gets an entity with the specified id or creates it and adds it to the collection if it does not exist.
  77699. *
  77700. * @param {Object} id The id of the entity to retrieve or create.
  77701. * @returns {Entity} The new or existing object.
  77702. */
  77703. EntityCollection.prototype.getOrCreateEntity = function(id) {
  77704. if (!defined(id)) {
  77705. throw new DeveloperError('id is required.');
  77706. }
  77707. var entity = this._entities.get(id);
  77708. if (!defined(entity)) {
  77709. entityOptionsScratch.id = id;
  77710. entity = new Entity(entityOptionsScratch);
  77711. this.add(entity);
  77712. }
  77713. return entity;
  77714. };
  77715. EntityCollection.prototype._onEntityDefinitionChanged = function(entity) {
  77716. var id = entity.id;
  77717. if (!this._addedEntities.contains(id)) {
  77718. this._changedEntities.set(id, entity);
  77719. }
  77720. fireChangedEvent(this);
  77721. };
  77722. return EntityCollection;
  77723. });
  77724. /*global define*/
  77725. define('DataSources/CompositeEntityCollection',[
  77726. '../Core/createGuid',
  77727. '../Core/defined',
  77728. '../Core/defineProperties',
  77729. '../Core/DeveloperError',
  77730. '../Core/Math',
  77731. './Entity',
  77732. './EntityCollection'
  77733. ], function(
  77734. createGuid,
  77735. defined,
  77736. defineProperties,
  77737. DeveloperError,
  77738. CesiumMath,
  77739. Entity,
  77740. EntityCollection) {
  77741. 'use strict';
  77742. var entityOptionsScratch = {
  77743. id : undefined
  77744. };
  77745. var entityIdScratch = new Array(2);
  77746. function clean(entity) {
  77747. var propertyNames = entity.propertyNames;
  77748. var propertyNamesLength = propertyNames.length;
  77749. for (var i = 0; i < propertyNamesLength; i++) {
  77750. entity[propertyNames[i]] = undefined;
  77751. }
  77752. }
  77753. function subscribeToEntity(that, eventHash, collectionId, entity) {
  77754. entityIdScratch[0] = collectionId;
  77755. entityIdScratch[1] = entity.id;
  77756. eventHash[JSON.stringify(entityIdScratch)] = entity.definitionChanged.addEventListener(CompositeEntityCollection.prototype._onDefinitionChanged, that);
  77757. }
  77758. function unsubscribeFromEntity(that, eventHash, collectionId, entity) {
  77759. entityIdScratch[0] = collectionId;
  77760. entityIdScratch[1] = entity.id;
  77761. var id = JSON.stringify(entityIdScratch);
  77762. eventHash[id]();
  77763. eventHash[id] = undefined;
  77764. }
  77765. function recomposite(that) {
  77766. that._shouldRecomposite = true;
  77767. if (that._suspendCount !== 0) {
  77768. return;
  77769. }
  77770. var collections = that._collections;
  77771. var collectionsLength = collections.length;
  77772. var collectionsCopy = that._collectionsCopy;
  77773. var collectionsCopyLength = collectionsCopy.length;
  77774. var i;
  77775. var entity;
  77776. var entities;
  77777. var iEntities;
  77778. var collection;
  77779. var composite = that._composite;
  77780. var newEntities = new EntityCollection(that);
  77781. var eventHash = that._eventHash;
  77782. var collectionId;
  77783. for (i = 0; i < collectionsCopyLength; i++) {
  77784. collection = collectionsCopy[i];
  77785. collection.collectionChanged.removeEventListener(CompositeEntityCollection.prototype._onCollectionChanged, that);
  77786. entities = collection.values;
  77787. collectionId = collection.id;
  77788. for (iEntities = entities.length - 1; iEntities > -1; iEntities--) {
  77789. entity = entities[iEntities];
  77790. unsubscribeFromEntity(that, eventHash, collectionId, entity);
  77791. }
  77792. }
  77793. for (i = collectionsLength - 1; i >= 0; i--) {
  77794. collection = collections[i];
  77795. collection.collectionChanged.addEventListener(CompositeEntityCollection.prototype._onCollectionChanged, that);
  77796. //Merge all of the existing entities.
  77797. entities = collection.values;
  77798. collectionId = collection.id;
  77799. for (iEntities = entities.length - 1; iEntities > -1; iEntities--) {
  77800. entity = entities[iEntities];
  77801. subscribeToEntity(that, eventHash, collectionId, entity);
  77802. var compositeEntity = newEntities.getById(entity.id);
  77803. if (!defined(compositeEntity)) {
  77804. compositeEntity = composite.getById(entity.id);
  77805. if (!defined(compositeEntity)) {
  77806. entityOptionsScratch.id = entity.id;
  77807. compositeEntity = new Entity(entityOptionsScratch);
  77808. } else {
  77809. clean(compositeEntity);
  77810. }
  77811. newEntities.add(compositeEntity);
  77812. }
  77813. compositeEntity.merge(entity);
  77814. }
  77815. }
  77816. that._collectionsCopy = collections.slice(0);
  77817. composite.suspendEvents();
  77818. composite.removeAll();
  77819. var newEntitiesArray = newEntities.values;
  77820. for (i = 0; i < newEntitiesArray.length; i++) {
  77821. composite.add(newEntitiesArray[i]);
  77822. }
  77823. composite.resumeEvents();
  77824. }
  77825. /**
  77826. * Non-destructively composites multiple {@link EntityCollection} instances into a single collection.
  77827. * If a Entity with the same ID exists in multiple collections, it is non-destructively
  77828. * merged into a single new entity instance. If an entity has the same property in multiple
  77829. * collections, the property of the Entity in the last collection of the list it
  77830. * belongs to is used. CompositeEntityCollection can be used almost anywhere that a
  77831. * EntityCollection is used.
  77832. *
  77833. * @alias CompositeEntityCollection
  77834. * @constructor
  77835. *
  77836. * @param {EntityCollection[]} [collections] The initial list of EntityCollection instances to merge.
  77837. * @param {DataSource|CompositeEntityCollection} [owner] The data source (or composite entity collection) which created this collection.
  77838. */
  77839. function CompositeEntityCollection(collections, owner) {
  77840. this._owner = owner;
  77841. this._composite = new EntityCollection(this);
  77842. this._suspendCount = 0;
  77843. this._collections = defined(collections) ? collections.slice() : [];
  77844. this._collectionsCopy = [];
  77845. this._id = createGuid();
  77846. this._eventHash = {};
  77847. recomposite(this);
  77848. this._shouldRecomposite = false;
  77849. }
  77850. defineProperties(CompositeEntityCollection.prototype, {
  77851. /**
  77852. * Gets the event that is fired when entities are added or removed from the collection.
  77853. * The generated event is a {@link EntityCollection.collectionChangedEventCallback}.
  77854. * @memberof CompositeEntityCollection.prototype
  77855. * @readonly
  77856. * @type {Event}
  77857. */
  77858. collectionChanged : {
  77859. get : function() {
  77860. return this._composite._collectionChanged;
  77861. }
  77862. },
  77863. /**
  77864. * Gets a globally unique identifier for this collection.
  77865. * @memberof CompositeEntityCollection.prototype
  77866. * @readonly
  77867. * @type {String}
  77868. */
  77869. id : {
  77870. get : function() {
  77871. return this._id;
  77872. }
  77873. },
  77874. /**
  77875. * Gets the array of Entity instances in the collection.
  77876. * This array should not be modified directly.
  77877. * @memberof CompositeEntityCollection.prototype
  77878. * @readonly
  77879. * @type {Entity[]}
  77880. */
  77881. values : {
  77882. get : function() {
  77883. return this._composite.values;
  77884. }
  77885. },
  77886. /**
  77887. * Gets the owner of this composite entity collection, ie. the data source or composite entity collection which created it.
  77888. * @memberof CompositeEntityCollection.prototype
  77889. * @readonly
  77890. * @type {DataSource|CompositeEntityCollection}
  77891. */
  77892. owner : {
  77893. get : function() {
  77894. return this._owner;
  77895. }
  77896. }
  77897. });
  77898. /**
  77899. * Adds a collection to the composite.
  77900. *
  77901. * @param {EntityCollection} collection the collection to add.
  77902. * @param {Number} [index] the index to add the collection at. If omitted, the collection will
  77903. * added on top of all existing collections.
  77904. *
  77905. * @exception {DeveloperError} index, if supplied, must be greater than or equal to zero and less than or equal to the number of collections.
  77906. */
  77907. CompositeEntityCollection.prototype.addCollection = function(collection, index) {
  77908. var hasIndex = defined(index);
  77909. if (!defined(collection)) {
  77910. throw new DeveloperError('collection is required.');
  77911. }
  77912. if (hasIndex) {
  77913. if (index < 0) {
  77914. throw new DeveloperError('index must be greater than or equal to zero.');
  77915. } else if (index > this._collections.length) {
  77916. throw new DeveloperError('index must be less than or equal to the number of collections.');
  77917. }
  77918. }
  77919. if (!hasIndex) {
  77920. index = this._collections.length;
  77921. this._collections.push(collection);
  77922. } else {
  77923. this._collections.splice(index, 0, collection);
  77924. }
  77925. recomposite(this);
  77926. };
  77927. /**
  77928. * Removes a collection from this composite, if present.
  77929. *
  77930. * @param {EntityCollection} collection The collection to remove.
  77931. * @returns {Boolean} true if the collection was in the composite and was removed,
  77932. * false if the collection was not in the composite.
  77933. */
  77934. CompositeEntityCollection.prototype.removeCollection = function(collection) {
  77935. var index = this._collections.indexOf(collection);
  77936. if (index !== -1) {
  77937. this._collections.splice(index, 1);
  77938. recomposite(this);
  77939. return true;
  77940. }
  77941. return false;
  77942. };
  77943. /**
  77944. * Removes all collections from this composite.
  77945. */
  77946. CompositeEntityCollection.prototype.removeAllCollections = function() {
  77947. this._collections.length = 0;
  77948. recomposite(this);
  77949. };
  77950. /**
  77951. * Checks to see if the composite contains a given collection.
  77952. *
  77953. * @param {EntityCollection} collection the collection to check for.
  77954. * @returns {Boolean} true if the composite contains the collection, false otherwise.
  77955. */
  77956. CompositeEntityCollection.prototype.containsCollection = function(collection) {
  77957. return this._collections.indexOf(collection) !== -1;
  77958. };
  77959. /**
  77960. * Returns true if the provided entity is in this collection, false otherwise.
  77961. *
  77962. * @param {Entity} entity The entity.
  77963. * @returns {Boolean} true if the provided entity is in this collection, false otherwise.
  77964. */
  77965. CompositeEntityCollection.prototype.contains = function(entity) {
  77966. return this._composite.contains(entity);
  77967. };
  77968. /**
  77969. * Determines the index of a given collection in the composite.
  77970. *
  77971. * @param {EntityCollection} collection The collection to find the index of.
  77972. * @returns {Number} The index of the collection in the composite, or -1 if the collection does not exist in the composite.
  77973. */
  77974. CompositeEntityCollection.prototype.indexOfCollection = function(collection) {
  77975. return this._collections.indexOf(collection);
  77976. };
  77977. /**
  77978. * Gets a collection by index from the composite.
  77979. *
  77980. * @param {Number} index the index to retrieve.
  77981. */
  77982. CompositeEntityCollection.prototype.getCollection = function(index) {
  77983. if (!defined(index)) {
  77984. throw new DeveloperError('index is required.', 'index');
  77985. }
  77986. return this._collections[index];
  77987. };
  77988. /**
  77989. * Gets the number of collections in this composite.
  77990. */
  77991. CompositeEntityCollection.prototype.getCollectionsLength = function() {
  77992. return this._collections.length;
  77993. };
  77994. function getCollectionIndex(collections, collection) {
  77995. if (!defined(collection)) {
  77996. throw new DeveloperError('collection is required.');
  77997. }
  77998. var index = collections.indexOf(collection);
  77999. if (index === -1) {
  78000. throw new DeveloperError('collection is not in this composite.');
  78001. }
  78002. return index;
  78003. }
  78004. function swapCollections(composite, i, j) {
  78005. var arr = composite._collections;
  78006. i = CesiumMath.clamp(i, 0, arr.length - 1);
  78007. j = CesiumMath.clamp(j, 0, arr.length - 1);
  78008. if (i === j) {
  78009. return;
  78010. }
  78011. var temp = arr[i];
  78012. arr[i] = arr[j];
  78013. arr[j] = temp;
  78014. recomposite(composite);
  78015. }
  78016. /**
  78017. * Raises a collection up one position in the composite.
  78018. *
  78019. * @param {EntityCollection} collection the collection to move.
  78020. *
  78021. * @exception {DeveloperError} collection is not in this composite.
  78022. */
  78023. CompositeEntityCollection.prototype.raiseCollection = function(collection) {
  78024. var index = getCollectionIndex(this._collections, collection);
  78025. swapCollections(this, index, index + 1);
  78026. };
  78027. /**
  78028. * Lowers a collection down one position in the composite.
  78029. *
  78030. * @param {EntityCollection} collection the collection to move.
  78031. *
  78032. * @exception {DeveloperError} collection is not in this composite.
  78033. */
  78034. CompositeEntityCollection.prototype.lowerCollection = function(collection) {
  78035. var index = getCollectionIndex(this._collections, collection);
  78036. swapCollections(this, index, index - 1);
  78037. };
  78038. /**
  78039. * Raises a collection to the top of the composite.
  78040. *
  78041. * @param {EntityCollection} collection the collection to move.
  78042. *
  78043. * @exception {DeveloperError} collection is not in this composite.
  78044. */
  78045. CompositeEntityCollection.prototype.raiseCollectionToTop = function(collection) {
  78046. var index = getCollectionIndex(this._collections, collection);
  78047. if (index === this._collections.length - 1) {
  78048. return;
  78049. }
  78050. this._collections.splice(index, 1);
  78051. this._collections.push(collection);
  78052. recomposite(this);
  78053. };
  78054. /**
  78055. * Lowers a collection to the bottom of the composite.
  78056. *
  78057. * @param {EntityCollection} collection the collection to move.
  78058. *
  78059. * @exception {DeveloperError} collection is not in this composite.
  78060. */
  78061. CompositeEntityCollection.prototype.lowerCollectionToBottom = function(collection) {
  78062. var index = getCollectionIndex(this._collections, collection);
  78063. if (index === 0) {
  78064. return;
  78065. }
  78066. this._collections.splice(index, 1);
  78067. this._collections.splice(0, 0, collection);
  78068. recomposite(this);
  78069. };
  78070. /**
  78071. * Prevents {@link EntityCollection#collectionChanged} events from being raised
  78072. * until a corresponding call is made to {@link EntityCollection#resumeEvents}, at which
  78073. * point a single event will be raised that covers all suspended operations.
  78074. * This allows for many items to be added and removed efficiently.
  78075. * While events are suspended, recompositing of the collections will
  78076. * also be suspended, as this can be a costly operation.
  78077. * This function can be safely called multiple times as long as there
  78078. * are corresponding calls to {@link EntityCollection#resumeEvents}.
  78079. */
  78080. CompositeEntityCollection.prototype.suspendEvents = function() {
  78081. this._suspendCount++;
  78082. this._composite.suspendEvents();
  78083. };
  78084. /**
  78085. * Resumes raising {@link EntityCollection#collectionChanged} events immediately
  78086. * when an item is added or removed. Any modifications made while while events were suspended
  78087. * will be triggered as a single event when this function is called. This function also ensures
  78088. * the collection is recomposited if events are also resumed.
  78089. * This function is reference counted and can safely be called multiple times as long as there
  78090. * are corresponding calls to {@link EntityCollection#resumeEvents}.
  78091. *
  78092. * @exception {DeveloperError} resumeEvents can not be called before suspendEvents.
  78093. */
  78094. CompositeEntityCollection.prototype.resumeEvents = function() {
  78095. if (this._suspendCount === 0) {
  78096. throw new DeveloperError('resumeEvents can not be called before suspendEvents.');
  78097. }
  78098. this._suspendCount--;
  78099. // recomposite before triggering events (but only if required for performance) that might depend on a composited collection
  78100. if (this._shouldRecomposite && this._suspendCount === 0) {
  78101. recomposite(this);
  78102. this._shouldRecomposite = false;
  78103. }
  78104. this._composite.resumeEvents();
  78105. };
  78106. /**
  78107. * Computes the maximum availability of the entities in the collection.
  78108. * If the collection contains a mix of infinitely available data and non-infinite data,
  78109. * It will return the interval pertaining to the non-infinite data only. If all
  78110. * data is infinite, an infinite interval will be returned.
  78111. *
  78112. * @returns {TimeInterval} The availability of entities in the collection.
  78113. */
  78114. CompositeEntityCollection.prototype.computeAvailability = function() {
  78115. return this._composite.computeAvailability();
  78116. };
  78117. /**
  78118. * Gets an entity with the specified id.
  78119. *
  78120. * @param {Object} id The id of the entity to retrieve.
  78121. * @returns {Entity} The entity with the provided id or undefined if the id did not exist in the collection.
  78122. */
  78123. CompositeEntityCollection.prototype.getById = function(id) {
  78124. return this._composite.getById(id);
  78125. };
  78126. CompositeEntityCollection.prototype._onCollectionChanged = function(collection, added, removed) {
  78127. var collections = this._collectionsCopy;
  78128. var collectionsLength = collections.length;
  78129. var composite = this._composite;
  78130. composite.suspendEvents();
  78131. var i;
  78132. var q;
  78133. var entity;
  78134. var compositeEntity;
  78135. var removedLength = removed.length;
  78136. var eventHash = this._eventHash;
  78137. var collectionId = collection.id;
  78138. for (i = 0; i < removedLength; i++) {
  78139. var removedEntity = removed[i];
  78140. unsubscribeFromEntity(this, eventHash, collectionId, removedEntity);
  78141. var removedId = removedEntity.id;
  78142. //Check if the removed entity exists in any of the remaining collections
  78143. //If so, we clean and remerge it.
  78144. for (q = collectionsLength - 1; q >= 0; q--) {
  78145. entity = collections[q].getById(removedId);
  78146. if (defined(entity)) {
  78147. if (!defined(compositeEntity)) {
  78148. compositeEntity = composite.getById(removedId);
  78149. clean(compositeEntity);
  78150. }
  78151. compositeEntity.merge(entity);
  78152. }
  78153. }
  78154. //We never retrieved the compositeEntity, which means it no longer
  78155. //exists in any of the collections, remove it from the composite.
  78156. if (!defined(compositeEntity)) {
  78157. composite.removeById(removedId);
  78158. }
  78159. compositeEntity = undefined;
  78160. }
  78161. var addedLength = added.length;
  78162. for (i = 0; i < addedLength; i++) {
  78163. var addedEntity = added[i];
  78164. subscribeToEntity(this, eventHash, collectionId, addedEntity);
  78165. var addedId = addedEntity.id;
  78166. //We know the added entity exists in at least one collection,
  78167. //but we need to check all collections and re-merge in order
  78168. //to maintain the priority of properties.
  78169. for (q = collectionsLength - 1; q >= 0; q--) {
  78170. entity = collections[q].getById(addedId);
  78171. if (defined(entity)) {
  78172. if (!defined(compositeEntity)) {
  78173. compositeEntity = composite.getById(addedId);
  78174. if (!defined(compositeEntity)) {
  78175. entityOptionsScratch.id = addedId;
  78176. compositeEntity = new Entity(entityOptionsScratch);
  78177. composite.add(compositeEntity);
  78178. } else {
  78179. clean(compositeEntity);
  78180. }
  78181. }
  78182. compositeEntity.merge(entity);
  78183. }
  78184. }
  78185. compositeEntity = undefined;
  78186. }
  78187. composite.resumeEvents();
  78188. };
  78189. CompositeEntityCollection.prototype._onDefinitionChanged = function(entity, propertyName, newValue, oldValue) {
  78190. var collections = this._collections;
  78191. var composite = this._composite;
  78192. var collectionsLength = collections.length;
  78193. var id = entity.id;
  78194. var compositeEntity = composite.getById(id);
  78195. var compositeProperty = compositeEntity[propertyName];
  78196. var newProperty = !defined(compositeProperty);
  78197. var firstTime = true;
  78198. for (var q = collectionsLength - 1; q >= 0; q--) {
  78199. var innerEntity = collections[q].getById(entity.id);
  78200. if (defined(innerEntity)) {
  78201. var property = innerEntity[propertyName];
  78202. if (defined(property)) {
  78203. if (firstTime) {
  78204. firstTime = false;
  78205. //We only want to clone if the property is also mergeable.
  78206. //This ensures that leaf properties are referenced and not copied,
  78207. //which is the entire point of compositing.
  78208. if (defined(property.merge) && defined(property.clone)) {
  78209. compositeProperty = property.clone(compositeProperty);
  78210. } else {
  78211. compositeProperty = property;
  78212. break;
  78213. }
  78214. }
  78215. compositeProperty.merge(property);
  78216. }
  78217. }
  78218. }
  78219. if (newProperty && compositeEntity.propertyNames.indexOf(propertyName) === -1) {
  78220. compositeEntity.addProperty(propertyName);
  78221. }
  78222. compositeEntity[propertyName] = compositeProperty;
  78223. };
  78224. return CompositeEntityCollection;
  78225. });
  78226. /*global define*/
  78227. define('DataSources/CompositeProperty',[
  78228. '../Core/defined',
  78229. '../Core/defineProperties',
  78230. '../Core/DeveloperError',
  78231. '../Core/Event',
  78232. '../Core/EventHelper',
  78233. '../Core/TimeIntervalCollection',
  78234. './Property'
  78235. ], function(
  78236. defined,
  78237. defineProperties,
  78238. DeveloperError,
  78239. Event,
  78240. EventHelper,
  78241. TimeIntervalCollection,
  78242. Property) {
  78243. 'use strict';
  78244. function subscribeAll(property, eventHelper, definitionChanged, intervals) {
  78245. function callback() {
  78246. definitionChanged.raiseEvent(property);
  78247. }
  78248. var items = [];
  78249. eventHelper.removeAll();
  78250. var length = intervals.length;
  78251. for (var i = 0; i < length; i++) {
  78252. var interval = intervals.get(i);
  78253. if (defined(interval.data) && items.indexOf(interval.data) === -1) {
  78254. eventHelper.add(interval.data.definitionChanged, callback);
  78255. }
  78256. }
  78257. }
  78258. /**
  78259. * A {@link Property} which is defined by a {@link TimeIntervalCollection}, where the
  78260. * data property of each {@link TimeInterval} is another Property instance which is
  78261. * evaluated at the provided time.
  78262. *
  78263. * @alias CompositeProperty
  78264. * @constructor
  78265. *
  78266. *
  78267. * @example
  78268. * var constantProperty = ...;
  78269. * var sampledProperty = ...;
  78270. *
  78271. * //Create a composite property from two previously defined properties
  78272. * //where the property is valid on August 1st, 2012 and uses a constant
  78273. * //property for the first half of the day and a sampled property for the
  78274. * //remaining half.
  78275. * var composite = new Cesium.CompositeProperty();
  78276. * composite.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
  78277. * iso8601 : '2012-08-01T00:00:00.00Z/2012-08-01T12:00:00.00Z',
  78278. * data : constantProperty
  78279. * }));
  78280. * composite.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
  78281. * iso8601 : '2012-08-01T12:00:00.00Z/2012-08-02T00:00:00.00Z',
  78282. * isStartIncluded : false,
  78283. * isStopIncluded : false,
  78284. * data : sampledProperty
  78285. * }));
  78286. *
  78287. * @see CompositeMaterialProperty
  78288. * @see CompositePositionProperty
  78289. */
  78290. function CompositeProperty() {
  78291. this._eventHelper = new EventHelper();
  78292. this._definitionChanged = new Event();
  78293. this._intervals = new TimeIntervalCollection();
  78294. this._intervals.changedEvent.addEventListener(CompositeProperty.prototype._intervalsChanged, this);
  78295. }
  78296. defineProperties(CompositeProperty.prototype, {
  78297. /**
  78298. * Gets a value indicating if this property is constant. A property is considered
  78299. * constant if getValue always returns the same result for the current definition.
  78300. * @memberof CompositeProperty.prototype
  78301. *
  78302. * @type {Boolean}
  78303. * @readonly
  78304. */
  78305. isConstant : {
  78306. get : function() {
  78307. return this._intervals.isEmpty;
  78308. }
  78309. },
  78310. /**
  78311. * Gets the event that is raised whenever the definition of this property changes.
  78312. * The definition is changed whenever setValue is called with data different
  78313. * than the current value.
  78314. * @memberof CompositeProperty.prototype
  78315. *
  78316. * @type {Event}
  78317. * @readonly
  78318. */
  78319. definitionChanged : {
  78320. get : function() {
  78321. return this._definitionChanged;
  78322. }
  78323. },
  78324. /**
  78325. * Gets the interval collection.
  78326. * @memberof CompositeProperty.prototype
  78327. *
  78328. * @type {TimeIntervalCollection}
  78329. */
  78330. intervals : {
  78331. get : function() {
  78332. return this._intervals;
  78333. }
  78334. }
  78335. });
  78336. /**
  78337. * Gets the value of the property at the provided time.
  78338. *
  78339. * @param {JulianDate} time The time for which to retrieve the value.
  78340. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  78341. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  78342. */
  78343. CompositeProperty.prototype.getValue = function(time, result) {
  78344. if (!defined(time)) {
  78345. throw new DeveloperError('time is required');
  78346. }
  78347. var innerProperty = this._intervals.findDataForIntervalContainingDate(time);
  78348. if (defined(innerProperty)) {
  78349. return innerProperty.getValue(time, result);
  78350. }
  78351. return undefined;
  78352. };
  78353. /**
  78354. * Compares this property to the provided property and returns
  78355. * <code>true</code> if they are equal, <code>false</code> otherwise.
  78356. *
  78357. * @param {Property} [other] The other property.
  78358. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  78359. */
  78360. CompositeProperty.prototype.equals = function(other) {
  78361. return this === other || //
  78362. (other instanceof CompositeProperty && //
  78363. this._intervals.equals(other._intervals, Property.equals));
  78364. };
  78365. /**
  78366. * @private
  78367. */
  78368. CompositeProperty.prototype._intervalsChanged = function() {
  78369. subscribeAll(this, this._eventHelper, this._definitionChanged, this._intervals);
  78370. this._definitionChanged.raiseEvent(this);
  78371. };
  78372. return CompositeProperty;
  78373. });
  78374. /*global define*/
  78375. define('DataSources/CompositeMaterialProperty',[
  78376. '../Core/defined',
  78377. '../Core/defineProperties',
  78378. '../Core/DeveloperError',
  78379. '../Core/Event',
  78380. './CompositeProperty',
  78381. './Property'
  78382. ], function(
  78383. defined,
  78384. defineProperties,
  78385. DeveloperError,
  78386. Event,
  78387. CompositeProperty,
  78388. Property) {
  78389. 'use strict';
  78390. /**
  78391. * A {@link CompositeProperty} which is also a {@link MaterialProperty}.
  78392. *
  78393. * @alias CompositeMaterialProperty
  78394. * @constructor
  78395. */
  78396. function CompositeMaterialProperty() {
  78397. this._definitionChanged = new Event();
  78398. this._composite = new CompositeProperty();
  78399. this._composite.definitionChanged.addEventListener(CompositeMaterialProperty.prototype._raiseDefinitionChanged, this);
  78400. }
  78401. defineProperties(CompositeMaterialProperty.prototype, {
  78402. /**
  78403. * Gets a value indicating if this property is constant. A property is considered
  78404. * constant if getValue always returns the same result for the current definition.
  78405. * @memberof CompositeMaterialProperty.prototype
  78406. *
  78407. * @type {Boolean}
  78408. * @readonly
  78409. */
  78410. isConstant : {
  78411. get : function() {
  78412. return this._composite.isConstant;
  78413. }
  78414. },
  78415. /**
  78416. * Gets the event that is raised whenever the definition of this property changes.
  78417. * The definition is changed whenever setValue is called with data different
  78418. * than the current value.
  78419. * @memberof CompositeMaterialProperty.prototype
  78420. *
  78421. * @type {Event}
  78422. * @readonly
  78423. */
  78424. definitionChanged : {
  78425. get : function() {
  78426. return this._definitionChanged;
  78427. }
  78428. },
  78429. /**
  78430. * Gets the interval collection.
  78431. * @memberof CompositeMaterialProperty.prototype
  78432. *
  78433. * @type {TimeIntervalCollection}
  78434. */
  78435. intervals : {
  78436. get : function() {
  78437. return this._composite._intervals;
  78438. }
  78439. }
  78440. });
  78441. /**
  78442. * Gets the {@link Material} type at the provided time.
  78443. *
  78444. * @param {JulianDate} time The time for which to retrieve the type.
  78445. * @returns {String} The type of material.
  78446. */
  78447. CompositeMaterialProperty.prototype.getType = function(time) {
  78448. if (!defined(time)) {
  78449. throw new DeveloperError('time is required');
  78450. }
  78451. var innerProperty = this._composite._intervals.findDataForIntervalContainingDate(time);
  78452. if (defined(innerProperty)) {
  78453. return innerProperty.getType(time);
  78454. }
  78455. return undefined;
  78456. };
  78457. /**
  78458. * Gets the value of the property at the provided time.
  78459. *
  78460. * @param {JulianDate} time The time for which to retrieve the value.
  78461. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  78462. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  78463. */
  78464. CompositeMaterialProperty.prototype.getValue = function(time, result) {
  78465. if (!defined(time)) {
  78466. throw new DeveloperError('time is required');
  78467. }
  78468. var innerProperty = this._composite._intervals.findDataForIntervalContainingDate(time);
  78469. if (defined(innerProperty)) {
  78470. return innerProperty.getValue(time, result);
  78471. }
  78472. return undefined;
  78473. };
  78474. /**
  78475. * Compares this property to the provided property and returns
  78476. * <code>true</code> if they are equal, <code>false</code> otherwise.
  78477. *
  78478. * @param {Property} [other] The other property.
  78479. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  78480. */
  78481. CompositeMaterialProperty.prototype.equals = function(other) {
  78482. return this === other || //
  78483. (other instanceof CompositeMaterialProperty && //
  78484. this._composite.equals(other._composite, Property.equals));
  78485. };
  78486. /**
  78487. * @private
  78488. */
  78489. CompositeMaterialProperty.prototype._raiseDefinitionChanged = function() {
  78490. this._definitionChanged.raiseEvent(this);
  78491. };
  78492. return CompositeMaterialProperty;
  78493. });
  78494. /*global define*/
  78495. define('DataSources/CompositePositionProperty',[
  78496. '../Core/defaultValue',
  78497. '../Core/defined',
  78498. '../Core/defineProperties',
  78499. '../Core/DeveloperError',
  78500. '../Core/Event',
  78501. '../Core/ReferenceFrame',
  78502. './CompositeProperty',
  78503. './Property'
  78504. ], function(
  78505. defaultValue,
  78506. defined,
  78507. defineProperties,
  78508. DeveloperError,
  78509. Event,
  78510. ReferenceFrame,
  78511. CompositeProperty,
  78512. Property) {
  78513. 'use strict';
  78514. /**
  78515. * A {@link CompositeProperty} which is also a {@link PositionProperty}.
  78516. *
  78517. * @alias CompositePositionProperty
  78518. * @constructor
  78519. *
  78520. * @param {ReferenceFrame} [referenceFrame=ReferenceFrame.FIXED] The reference frame in which the position is defined.
  78521. */
  78522. function CompositePositionProperty(referenceFrame) {
  78523. this._referenceFrame = defaultValue(referenceFrame, ReferenceFrame.FIXED);
  78524. this._definitionChanged = new Event();
  78525. this._composite = new CompositeProperty();
  78526. this._composite.definitionChanged.addEventListener(CompositePositionProperty.prototype._raiseDefinitionChanged, this);
  78527. }
  78528. defineProperties(CompositePositionProperty.prototype, {
  78529. /**
  78530. * Gets a value indicating if this property is constant. A property is considered
  78531. * constant if getValue always returns the same result for the current definition.
  78532. * @memberof CompositePositionProperty.prototype
  78533. *
  78534. * @type {Boolean}
  78535. * @readonly
  78536. */
  78537. isConstant : {
  78538. get : function() {
  78539. return this._composite.isConstant;
  78540. }
  78541. },
  78542. /**
  78543. * Gets the event that is raised whenever the definition of this property changes.
  78544. * The definition is changed whenever setValue is called with data different
  78545. * than the current value.
  78546. * @memberof CompositePositionProperty.prototype
  78547. *
  78548. * @type {Event}
  78549. * @readonly
  78550. */
  78551. definitionChanged : {
  78552. get : function() {
  78553. return this._definitionChanged;
  78554. }
  78555. },
  78556. /**
  78557. * Gets the interval collection.
  78558. * @memberof CompositePositionProperty.prototype
  78559. *
  78560. * @type {TimeIntervalCollection}
  78561. */
  78562. intervals : {
  78563. get : function() {
  78564. return this._composite.intervals;
  78565. }
  78566. },
  78567. /**
  78568. * Gets or sets the reference frame which this position presents itself as.
  78569. * Each PositionProperty making up this object has it's own reference frame,
  78570. * so this property merely exposes a "preferred" reference frame for clients
  78571. * to use.
  78572. * @memberof CompositePositionProperty.prototype
  78573. *
  78574. * @type {ReferenceFrame}
  78575. */
  78576. referenceFrame : {
  78577. get : function() {
  78578. return this._referenceFrame;
  78579. },
  78580. set : function(value) {
  78581. this._referenceFrame = value;
  78582. }
  78583. }
  78584. });
  78585. /**
  78586. * Gets the value of the property at the provided time in the fixed frame.
  78587. *
  78588. * @param {JulianDate} time The time for which to retrieve the value.
  78589. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  78590. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  78591. */
  78592. CompositePositionProperty.prototype.getValue = function(time, result) {
  78593. return this.getValueInReferenceFrame(time, ReferenceFrame.FIXED, result);
  78594. };
  78595. /**
  78596. * Gets the value of the property at the provided time and in the provided reference frame.
  78597. *
  78598. * @param {JulianDate} time The time for which to retrieve the value.
  78599. * @param {ReferenceFrame} referenceFrame The desired referenceFrame of the result.
  78600. * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
  78601. * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
  78602. */
  78603. CompositePositionProperty.prototype.getValueInReferenceFrame = function(time, referenceFrame, result) {
  78604. if (!defined(time)) {
  78605. throw new DeveloperError('time is required.');
  78606. }
  78607. if (!defined(referenceFrame)) {
  78608. throw new DeveloperError('referenceFrame is required.');
  78609. }
  78610. var innerProperty = this._composite._intervals.findDataForIntervalContainingDate(time);
  78611. if (defined(innerProperty)) {
  78612. return innerProperty.getValueInReferenceFrame(time, referenceFrame, result);
  78613. }
  78614. return undefined;
  78615. };
  78616. /**
  78617. * Compares this property to the provided property and returns
  78618. * <code>true</code> if they are equal, <code>false</code> otherwise.
  78619. *
  78620. * @param {Property} [other] The other property.
  78621. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  78622. */
  78623. CompositePositionProperty.prototype.equals = function(other) {
  78624. return this === other || //
  78625. (other instanceof CompositePositionProperty && //
  78626. this._referenceFrame === other._referenceFrame && //
  78627. this._composite.equals(other._composite, Property.equals));
  78628. };
  78629. /**
  78630. * @private
  78631. */
  78632. CompositePositionProperty.prototype._raiseDefinitionChanged = function() {
  78633. this._definitionChanged.raiseEvent(this);
  78634. };
  78635. return CompositePositionProperty;
  78636. });
  78637. //This file is automatically rebuilt by the Cesium build process.
  78638. /*global define*/
  78639. define('Shaders/ShadowVolumeFS',[],function() {
  78640. 'use strict';
  78641. return "#extension GL_EXT_frag_depth : enable\n\
  78642. varying float v_WindowZ;\n\
  78643. varying vec4 v_color;\n\
  78644. void writeDepthClampedToFarPlane()\n\
  78645. {\n\
  78646. gl_FragDepthEXT = min(v_WindowZ * gl_FragCoord.w, 1.0);\n\
  78647. }\n\
  78648. void main(void)\n\
  78649. {\n\
  78650. gl_FragColor = v_color;\n\
  78651. writeDepthClampedToFarPlane();\n\
  78652. }\n\
  78653. ";
  78654. });
  78655. //This file is automatically rebuilt by the Cesium build process.
  78656. /*global define*/
  78657. define('Shaders/ShadowVolumeVS',[],function() {
  78658. 'use strict';
  78659. return "attribute vec3 position3DHigh;\n\
  78660. attribute vec3 position3DLow;\n\
  78661. attribute vec4 color;\n\
  78662. attribute float batchId;\n\
  78663. varying float v_WindowZ;\n\
  78664. varying vec4 v_color;\n\
  78665. vec4 depthClampFarPlane(vec4 vertexInClipCoordinates)\n\
  78666. {\n\
  78667. v_WindowZ = (0.5 * (vertexInClipCoordinates.z / vertexInClipCoordinates.w) + 0.5) * vertexInClipCoordinates.w;\n\
  78668. vertexInClipCoordinates.z = min(vertexInClipCoordinates.z, vertexInClipCoordinates.w);\n\
  78669. return vertexInClipCoordinates;\n\
  78670. }\n\
  78671. void main()\n\
  78672. {\n\
  78673. v_color = color;\n\
  78674. vec4 position = czm_computePosition();\n\
  78675. gl_Position = depthClampFarPlane(czm_modelViewProjectionRelativeToEye * position);\n\
  78676. }\n\
  78677. ";
  78678. });
  78679. /*global define*/
  78680. define('Scene/DepthFunction',[
  78681. '../Core/freezeObject',
  78682. '../Core/WebGLConstants'
  78683. ], function(
  78684. freezeObject,
  78685. WebGLConstants) {
  78686. 'use strict';
  78687. /**
  78688. * Determines the function used to compare two depths for the depth test.
  78689. *
  78690. * @exports DepthFunction
  78691. */
  78692. var DepthFunction = {
  78693. /**
  78694. * The depth test never passes.
  78695. *
  78696. * @type {Number}
  78697. * @constant
  78698. */
  78699. NEVER : WebGLConstants.NEVER,
  78700. /**
  78701. * The depth test passes if the incoming depth is less than the stored depth.
  78702. *
  78703. * @type {Number}
  78704. * @constant
  78705. */
  78706. LESS : WebGLConstants.LESS,
  78707. /**
  78708. * The depth test passes if the incoming depth is equal to the stored depth.
  78709. *
  78710. * @type {Number}
  78711. * @constant
  78712. */
  78713. EQUAL : WebGLConstants.EQUAL,
  78714. /**
  78715. * The depth test passes if the incoming depth is less than or equal to the stored depth.
  78716. *
  78717. * @type {Number}
  78718. * @constant
  78719. */
  78720. LESS_OR_EQUAL : WebGLConstants.LEQUAL,
  78721. /**
  78722. * The depth test passes if the incoming depth is greater than the stored depth.
  78723. *
  78724. * @type {Number}
  78725. * @constant
  78726. */
  78727. GREATER : WebGLConstants.GREATER,
  78728. /**
  78729. * The depth test passes if the incoming depth is not equal to the stored depth.
  78730. *
  78731. * @type {Number}
  78732. * @constant
  78733. */
  78734. NOT_EQUAL : WebGLConstants.NOTEQUAL,
  78735. /**
  78736. * The depth test passes if the incoming depth is greater than or equal to the stored depth.
  78737. *
  78738. * @type {Number}
  78739. * @constant
  78740. */
  78741. GREATER_OR_EQUAL : WebGLConstants.GEQUAL,
  78742. /**
  78743. * The depth test always passes.
  78744. *
  78745. * @type {Number}
  78746. * @constant
  78747. */
  78748. ALWAYS : WebGLConstants.ALWAYS
  78749. };
  78750. return freezeObject(DepthFunction);
  78751. });
  78752. /*global define*/
  78753. define('Scene/StencilFunction',[
  78754. '../Core/freezeObject',
  78755. '../Core/WebGLConstants'
  78756. ], function(
  78757. freezeObject,
  78758. WebGLConstants) {
  78759. 'use strict';
  78760. /**
  78761. * Determines the function used to compare stencil values for the stencil test.
  78762. *
  78763. * @exports StencilFunction
  78764. */
  78765. var StencilFunction = {
  78766. /**
  78767. * The stencil test never passes.
  78768. *
  78769. * @type {Number}
  78770. * @constant
  78771. */
  78772. NEVER : WebGLConstants.NEVER,
  78773. /**
  78774. * The stencil test passes when the masked reference value is less than the masked stencil value.
  78775. *
  78776. * @type {Number}
  78777. * @constant
  78778. */
  78779. LESS : WebGLConstants.LESS,
  78780. /**
  78781. * The stencil test passes when the masked reference value is equal to the masked stencil value.
  78782. *
  78783. * @type {Number}
  78784. * @constant
  78785. */
  78786. EQUAL : WebGLConstants.EQUAL,
  78787. /**
  78788. * The stencil test passes when the masked reference value is less than or equal to the masked stencil value.
  78789. *
  78790. * @type {Number}
  78791. * @constant
  78792. */
  78793. LESS_OR_EQUAL : WebGLConstants.LEQUAL,
  78794. /**
  78795. * The stencil test passes when the masked reference value is greater than the masked stencil value.
  78796. *
  78797. * @type {Number}
  78798. * @constant
  78799. */
  78800. GREATER : WebGLConstants.GREATER,
  78801. /**
  78802. * The stencil test passes when the masked reference value is not equal to the masked stencil value.
  78803. *
  78804. * @type {Number}
  78805. * @constant
  78806. */
  78807. NOT_EQUAL : WebGLConstants.NOTEQUAL,
  78808. /**
  78809. * The stencil test passes when the masked reference value is greater than or equal to the masked stencil value.
  78810. *
  78811. * @type {Number}
  78812. * @constant
  78813. */
  78814. GREATER_OR_EQUAL : WebGLConstants.GEQUAL,
  78815. /**
  78816. * The stencil test always passes.
  78817. *
  78818. * @type {Number}
  78819. * @constant
  78820. */
  78821. ALWAYS : WebGLConstants.ALWAYS
  78822. };
  78823. return freezeObject(StencilFunction);
  78824. });
  78825. /*global define*/
  78826. define('Scene/StencilOperation',[
  78827. '../Core/freezeObject',
  78828. '../Core/WebGLConstants'
  78829. ], function(
  78830. freezeObject,
  78831. WebGLConstants) {
  78832. 'use strict';
  78833. /**
  78834. * Determines the action taken based on the result of the stencil test.
  78835. *
  78836. * @exports StencilOperation
  78837. */
  78838. var StencilOperation = {
  78839. /**
  78840. * Sets the stencil buffer value to zero.
  78841. *
  78842. * @type {Number}
  78843. * @constant
  78844. */
  78845. ZERO : WebGLConstants.ZERO,
  78846. /**
  78847. * Does not change the stencil buffer.
  78848. *
  78849. * @type {Number}
  78850. * @constant
  78851. */
  78852. KEEP : WebGLConstants.KEEP,
  78853. /**
  78854. * Replaces the stencil buffer value with the reference value.
  78855. *
  78856. * @type {Number}
  78857. * @constant
  78858. */
  78859. REPLACE : WebGLConstants.REPLACE,
  78860. /**
  78861. * Increments the stencil buffer value, clamping to unsigned byte.
  78862. *
  78863. * @type {Number}
  78864. * @constant
  78865. */
  78866. INCREMENT : WebGLConstants.INCR,
  78867. /**
  78868. * Decrements the stencil buffer value, clamping to zero.
  78869. *
  78870. * @type {Number}
  78871. * @constant
  78872. */
  78873. DECREMENT : WebGLConstants.DECR,
  78874. /**
  78875. * Bitwise inverts the existing stencil buffer value.
  78876. *
  78877. * @type {Number}
  78878. * @constant
  78879. */
  78880. INVERT : WebGLConstants.INVERT,
  78881. /**
  78882. * Increments the stencil buffer value, wrapping to zero when exceeding the unsigned byte range.
  78883. *
  78884. * @type {Number}
  78885. * @constant
  78886. */
  78887. INCREMENT_WRAP : WebGLConstants.INCR_WRAP,
  78888. /**
  78889. * Decrements the stencil buffer value, wrapping to the maximum unsigned byte instead of going below zero.
  78890. *
  78891. * @type {Number}
  78892. * @constant
  78893. */
  78894. DECREMENT_WRAP : WebGLConstants.DECR_WRAP
  78895. };
  78896. return freezeObject(StencilOperation);
  78897. });
  78898. /*global define*/
  78899. define('Scene/GroundPrimitive',[
  78900. '../Core/BoundingSphere',
  78901. '../Core/buildModuleUrl',
  78902. '../Core/Cartesian2',
  78903. '../Core/Cartesian3',
  78904. '../Core/Cartographic',
  78905. '../Core/Color',
  78906. '../Core/ColorGeometryInstanceAttribute',
  78907. '../Core/defaultValue',
  78908. '../Core/defined',
  78909. '../Core/defineProperties',
  78910. '../Core/destroyObject',
  78911. '../Core/DeveloperError',
  78912. '../Core/GeographicTilingScheme',
  78913. '../Core/GeometryInstance',
  78914. '../Core/isArray',
  78915. '../Core/loadJson',
  78916. '../Core/Math',
  78917. '../Core/OrientedBoundingBox',
  78918. '../Core/Rectangle',
  78919. '../Renderer/DrawCommand',
  78920. '../Renderer/Pass',
  78921. '../Renderer/RenderState',
  78922. '../Renderer/ShaderProgram',
  78923. '../Renderer/ShaderSource',
  78924. '../Shaders/ShadowVolumeFS',
  78925. '../Shaders/ShadowVolumeVS',
  78926. '../ThirdParty/when',
  78927. './BlendingState',
  78928. './DepthFunction',
  78929. './PerInstanceColorAppearance',
  78930. './Primitive',
  78931. './SceneMode',
  78932. './StencilFunction',
  78933. './StencilOperation'
  78934. ], function(
  78935. BoundingSphere,
  78936. buildModuleUrl,
  78937. Cartesian2,
  78938. Cartesian3,
  78939. Cartographic,
  78940. Color,
  78941. ColorGeometryInstanceAttribute,
  78942. defaultValue,
  78943. defined,
  78944. defineProperties,
  78945. destroyObject,
  78946. DeveloperError,
  78947. GeographicTilingScheme,
  78948. GeometryInstance,
  78949. isArray,
  78950. loadJson,
  78951. CesiumMath,
  78952. OrientedBoundingBox,
  78953. Rectangle,
  78954. DrawCommand,
  78955. Pass,
  78956. RenderState,
  78957. ShaderProgram,
  78958. ShaderSource,
  78959. ShadowVolumeFS,
  78960. ShadowVolumeVS,
  78961. when,
  78962. BlendingState,
  78963. DepthFunction,
  78964. PerInstanceColorAppearance,
  78965. Primitive,
  78966. SceneMode,
  78967. StencilFunction,
  78968. StencilOperation) {
  78969. 'use strict';
  78970. /**
  78971. * A ground primitive represents geometry draped over the terrain in the {@link Scene}. The geometry must be from a single {@link GeometryInstance}.
  78972. * Batching multiple geometries is not yet supported.
  78973. * <p>
  78974. * A primitive combines the geometry instance with an {@link Appearance} that describes the full shading, including
  78975. * {@link Material} and {@link RenderState}. Roughly, the geometry instance defines the structure and placement,
  78976. * and the appearance defines the visual characteristics. Decoupling geometry and appearance allows us to mix
  78977. * and match most of them and add a new geometry or appearance independently of each other. Only the {@link PerInstanceColorAppearance}
  78978. * is supported at this time.
  78979. * </p>
  78980. * <p>
  78981. * Because of the cutting edge nature of this feature in WebGL, it requires the EXT_frag_depth extension, which is currently only supported in Chrome,
  78982. * Firefox, and Edge. Apple support is expected in iOS 9 and MacOS Safari 9. Android support varies by hardware and IE11 will most likely never support
  78983. * it. You can use webglreport.com to verify support for your hardware.
  78984. * </p>
  78985. * <p>
  78986. * Valid geometries are {@link CircleGeometry}, {@link CorridorGeometry}, {@link EllipseGeometry}, {@link PolygonGeometry}, and {@link RectangleGeometry}.
  78987. * </p>
  78988. *
  78989. * @alias GroundPrimitive
  78990. * @constructor
  78991. *
  78992. * @param {Object} [options] Object with the following properties:
  78993. * @param {Array|GeometryInstance} [options.geometryInstances] The geometry instances to render.
  78994. * @param {Boolean} [options.show=true] Determines if this primitive will be shown.
  78995. * @param {Boolean} [options.vertexCacheOptimize=false] When <code>true</code>, geometry vertices are optimized for the pre and post-vertex-shader caches.
  78996. * @param {Boolean} [options.interleave=false] When <code>true</code>, geometry vertex attributes are interleaved, which can slightly improve rendering performance but increases load time.
  78997. * @param {Boolean} [options.compressVertices=true] When <code>true</code>, the geometry vertices are compressed, which will save memory.
  78998. * @param {Boolean} [options.releaseGeometryInstances=true] When <code>true</code>, the primitive does not keep a reference to the input <code>geometryInstances</code> to save memory.
  78999. * @param {Boolean} [options.allowPicking=true] When <code>true</code>, each geometry instance will only be pickable with {@link Scene#pick}. When <code>false</code>, GPU memory is saved.
  79000. * @param {Boolean} [options.asynchronous=true] Determines if the primitive will be created asynchronously or block until ready. If false initializeTerrainHeights() must be called first.
  79001. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
  79002. * @param {Boolean} [options.debugShowShadowVolume=false] For debugging only. Determines if the shadow volume for each geometry in the primitive is drawn. Must be <code>true</code> on
  79003. * creation for the volumes to be created before the geometry is released or options.releaseGeometryInstance must be <code>false</code>.
  79004. *
  79005. * @example
  79006. * // Example 1: Create primitive with a single instance
  79007. * var rectangleInstance = new Cesium.GeometryInstance({
  79008. * geometry : new Cesium.RectangleGeometry({
  79009. * rectangle : Cesium.Rectangle.fromDegrees(-140.0, 30.0, -100.0, 40.0)
  79010. * }),
  79011. * id : 'rectangle',
  79012. * attributes : {
  79013. * color : new Cesium.ColorGeometryInstanceAttribute(0.0, 1.0, 1.0, 0.5)
  79014. * }
  79015. * });
  79016. * scene.primitives.add(new Cesium.GroundPrimitive({
  79017. * geometryInstances : rectangleInstance
  79018. * }));
  79019. *
  79020. * // Example 2: Batch instances
  79021. * var color = new Cesium.ColorGeometryInstanceAttribute(0.0, 1.0, 1.0, 0.5); // Both instances must have the same color.
  79022. * var rectangleInstance = new Cesium.GeometryInstance({
  79023. * geometry : new Cesium.RectangleGeometry({
  79024. * rectangle : Cesium.Rectangle.fromDegrees(-140.0, 30.0, -100.0, 40.0)
  79025. * }),
  79026. * id : 'rectangle',
  79027. * attributes : {
  79028. * color : color
  79029. * }
  79030. * });
  79031. * var ellipseInstance = new Cesium.GeometryInstance({
  79032. * geometry : new Cesium.EllipseGeometry({
  79033. * center : Cesium.Cartesian3.fromDegrees(-105.0, 40.0),
  79034. * semiMinorAxis : 300000.0,
  79035. * semiMajorAxis : 400000.0
  79036. * }),
  79037. * id : 'ellipse',
  79038. * attributes : {
  79039. * color : color
  79040. * }
  79041. * });
  79042. * scene.primitives.add(new Cesium.GroundPrimitive({
  79043. * geometryInstances : [rectangleInstance, ellipseInstance]
  79044. * }));
  79045. *
  79046. * @see Primitive
  79047. * @see GeometryInstance
  79048. * @see Appearance
  79049. */
  79050. function GroundPrimitive(options) {
  79051. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  79052. /**
  79053. * The geometry instance rendered with this primitive. This may
  79054. * be <code>undefined</code> if <code>options.releaseGeometryInstances</code>
  79055. * is <code>true</code> when the primitive is constructed.
  79056. * <p>
  79057. * Changing this property after the primitive is rendered has no effect.
  79058. * </p>
  79059. * <p>
  79060. * Because of the rendering technique used, all geometry instances must be the same color.
  79061. * If there is an instance with a differing color, a <code>DeveloperError</code> will be thrown
  79062. * on the first attempt to render.
  79063. * </p>
  79064. *
  79065. * @type {Array|GeometryInstance}
  79066. *
  79067. * @default undefined
  79068. */
  79069. this.geometryInstances = options.geometryInstances;
  79070. /**
  79071. * Determines if the primitive will be shown. This affects all geometry
  79072. * instances in the primitive.
  79073. *
  79074. * @type {Boolean}
  79075. *
  79076. * @default true
  79077. */
  79078. this.show = defaultValue(options.show, true);
  79079. /**
  79080. * This property is for debugging only; it is not for production use nor is it optimized.
  79081. * <p>
  79082. * Draws the bounding sphere for each draw command in the primitive.
  79083. * </p>
  79084. *
  79085. * @type {Boolean}
  79086. *
  79087. * @default false
  79088. */
  79089. this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false);
  79090. /**
  79091. * This property is for debugging only; it is not for production use nor is it optimized.
  79092. * <p>
  79093. * Draws the shadow volume for each geometry in the primitive. Must be <code>true</code> on
  79094. * creation for the volumes to be created before the geometry is released or releaseGeometryInstances
  79095. * must be <code>false</code>
  79096. * </p>
  79097. *
  79098. * @type {Boolean}
  79099. *
  79100. * @default false
  79101. */
  79102. this.debugShowShadowVolume = defaultValue(options.debugShowShadowVolume, false);
  79103. this._sp = undefined;
  79104. this._spPick = undefined;
  79105. this._rsStencilPreloadPass = undefined;
  79106. this._rsStencilDepthPass = undefined;
  79107. this._rsColorPass = undefined;
  79108. this._rsPickPass = undefined;
  79109. this._uniformMap = {};
  79110. this._boundingVolumes = [];
  79111. this._boundingVolumes2D = [];
  79112. this._ready = false;
  79113. this._readyPromise = when.defer();
  79114. this._primitive = undefined;
  79115. this._debugPrimitive = undefined;
  79116. this._maxHeight = undefined;
  79117. this._minHeight = undefined;
  79118. this._maxTerrainHeight = GroundPrimitive._defaultMaxTerrainHeight;
  79119. this._minTerrainHeight = GroundPrimitive._defaultMinTerrainHeight;
  79120. this._boundingSpheresKeys = [];
  79121. this._boundingSpheres = [];
  79122. var appearance = new PerInstanceColorAppearance({
  79123. flat : true
  79124. });
  79125. var readOnlyAttributes;
  79126. if (defined(this.geometryInstances) && isArray(this.geometryInstances) && this.geometryInstances.length > 1) {
  79127. readOnlyAttributes = readOnlyInstanceAttributesScratch;
  79128. }
  79129. this._primitiveOptions = {
  79130. geometryInstances : undefined,
  79131. appearance : appearance,
  79132. vertexCacheOptimize : defaultValue(options.vertexCacheOptimize, false),
  79133. interleave : defaultValue(options.interleave, false),
  79134. releaseGeometryInstances : defaultValue(options.releaseGeometryInstances, true),
  79135. allowPicking : defaultValue(options.allowPicking, true),
  79136. asynchronous : defaultValue(options.asynchronous, true),
  79137. compressVertices : defaultValue(options.compressVertices, true),
  79138. _readOnlyInstanceAttributes : readOnlyAttributes,
  79139. _createRenderStatesFunction : undefined,
  79140. _createShaderProgramFunction : undefined,
  79141. _createCommandsFunction : undefined,
  79142. _createPickOffsets : true
  79143. };
  79144. }
  79145. var readOnlyInstanceAttributesScratch = ['color'];
  79146. defineProperties(GroundPrimitive.prototype, {
  79147. /**
  79148. * When <code>true</code>, geometry vertices are optimized for the pre and post-vertex-shader caches.
  79149. *
  79150. * @memberof GroundPrimitive.prototype
  79151. *
  79152. * @type {Boolean}
  79153. * @readonly
  79154. *
  79155. * @default true
  79156. */
  79157. vertexCacheOptimize : {
  79158. get : function() {
  79159. return this._primitiveOptions.vertexCacheOptimize;
  79160. }
  79161. },
  79162. /**
  79163. * Determines if geometry vertex attributes are interleaved, which can slightly improve rendering performance.
  79164. *
  79165. * @memberof GroundPrimitive.prototype
  79166. *
  79167. * @type {Boolean}
  79168. * @readonly
  79169. *
  79170. * @default false
  79171. */
  79172. interleave : {
  79173. get : function() {
  79174. return this._primitiveOptions.interleave;
  79175. }
  79176. },
  79177. /**
  79178. * When <code>true</code>, the primitive does not keep a reference to the input <code>geometryInstances</code> to save memory.
  79179. *
  79180. * @memberof GroundPrimitive.prototype
  79181. *
  79182. * @type {Boolean}
  79183. * @readonly
  79184. *
  79185. * @default true
  79186. */
  79187. releaseGeometryInstances : {
  79188. get : function() {
  79189. return this._primitiveOptions.releaseGeometryInstances;
  79190. }
  79191. },
  79192. /**
  79193. * When <code>true</code>, each geometry instance will only be pickable with {@link Scene#pick}. When <code>false</code>, GPU memory is saved.
  79194. *
  79195. * @memberof GroundPrimitive.prototype
  79196. *
  79197. * @type {Boolean}
  79198. * @readonly
  79199. *
  79200. * @default true
  79201. */
  79202. allowPicking : {
  79203. get : function() {
  79204. return this._primitiveOptions.allowPicking;
  79205. }
  79206. },
  79207. /**
  79208. * Determines if the geometry instances will be created and batched on a web worker.
  79209. *
  79210. * @memberof GroundPrimitive.prototype
  79211. *
  79212. * @type {Boolean}
  79213. * @readonly
  79214. *
  79215. * @default true
  79216. */
  79217. asynchronous : {
  79218. get : function() {
  79219. return this._primitiveOptions.asynchronous;
  79220. }
  79221. },
  79222. /**
  79223. * When <code>true</code>, geometry vertices are compressed, which will save memory.
  79224. *
  79225. * @memberof GroundPrimitive.prototype
  79226. *
  79227. * @type {Boolean}
  79228. * @readonly
  79229. *
  79230. * @default true
  79231. */
  79232. compressVertices : {
  79233. get : function() {
  79234. return this._primitiveOptions.compressVertices;
  79235. }
  79236. },
  79237. /**
  79238. * Determines if the primitive is complete and ready to render. If this property is
  79239. * true, the primitive will be rendered the next time that {@link GroundPrimitive#update}
  79240. * is called.
  79241. *
  79242. * @memberof GroundPrimitive.prototype
  79243. *
  79244. * @type {Boolean}
  79245. * @readonly
  79246. */
  79247. ready : {
  79248. get : function() {
  79249. return this._ready;
  79250. }
  79251. },
  79252. /**
  79253. * Gets a promise that resolves when the primitive is ready to render.
  79254. * @memberof GroundPrimitive.prototype
  79255. * @type {Promise.<GroundPrimitive>}
  79256. * @readonly
  79257. */
  79258. readyPromise : {
  79259. get : function() {
  79260. return this._readyPromise.promise;
  79261. }
  79262. }
  79263. });
  79264. /**
  79265. * Determines if GroundPrimitive rendering is supported.
  79266. *
  79267. * @param {Scene} scene The scene.
  79268. * @returns {Boolean} <code>true</code> if GroundPrimitives are supported; otherwise, returns <code>false</code>
  79269. */
  79270. GroundPrimitive.isSupported = function(scene) {
  79271. return scene.context.fragmentDepth && scene.context.stencilBuffer;
  79272. };
  79273. GroundPrimitive._defaultMaxTerrainHeight = 9000.0;
  79274. GroundPrimitive._defaultMinTerrainHeight = -100000.0;
  79275. GroundPrimitive._terrainHeights = undefined;
  79276. GroundPrimitive._terrainHeightsMaxLevel = 6;
  79277. function getComputeMaximumHeightFunction(primitive) {
  79278. return function(granularity, ellipsoid) {
  79279. var r = ellipsoid.maximumRadius;
  79280. var delta = (r / Math.cos(granularity * 0.5)) - r;
  79281. return primitive._maxHeight + delta;
  79282. };
  79283. }
  79284. function getComputeMinimumHeightFunction(primitive) {
  79285. return function(granularity, ellipsoid) {
  79286. return primitive._minHeight;
  79287. };
  79288. }
  79289. var stencilPreloadRenderState = {
  79290. colorMask : {
  79291. red : false,
  79292. green : false,
  79293. blue : false,
  79294. alpha : false
  79295. },
  79296. stencilTest : {
  79297. enabled : true,
  79298. frontFunction : StencilFunction.ALWAYS,
  79299. frontOperation : {
  79300. fail : StencilOperation.KEEP,
  79301. zFail : StencilOperation.DECREMENT_WRAP,
  79302. zPass : StencilOperation.DECREMENT_WRAP
  79303. },
  79304. backFunction : StencilFunction.ALWAYS,
  79305. backOperation : {
  79306. fail : StencilOperation.KEEP,
  79307. zFail : StencilOperation.INCREMENT_WRAP,
  79308. zPass : StencilOperation.INCREMENT_WRAP
  79309. },
  79310. reference : 0,
  79311. mask : ~0
  79312. },
  79313. depthTest : {
  79314. enabled : false
  79315. },
  79316. depthMask : false
  79317. };
  79318. var stencilDepthRenderState = {
  79319. colorMask : {
  79320. red : false,
  79321. green : false,
  79322. blue : false,
  79323. alpha : false
  79324. },
  79325. stencilTest : {
  79326. enabled : true,
  79327. frontFunction : StencilFunction.ALWAYS,
  79328. frontOperation : {
  79329. fail : StencilOperation.KEEP,
  79330. zFail : StencilOperation.KEEP,
  79331. zPass : StencilOperation.INCREMENT_WRAP
  79332. },
  79333. backFunction : StencilFunction.ALWAYS,
  79334. backOperation : {
  79335. fail : StencilOperation.KEEP,
  79336. zFail : StencilOperation.KEEP,
  79337. zPass : StencilOperation.DECREMENT_WRAP
  79338. },
  79339. reference : 0,
  79340. mask : ~0
  79341. },
  79342. depthTest : {
  79343. enabled : true,
  79344. func : DepthFunction.LESS_OR_EQUAL
  79345. },
  79346. depthMask : false
  79347. };
  79348. var colorRenderState = {
  79349. stencilTest : {
  79350. enabled : true,
  79351. frontFunction : StencilFunction.NOT_EQUAL,
  79352. frontOperation : {
  79353. fail : StencilOperation.KEEP,
  79354. zFail : StencilOperation.KEEP,
  79355. zPass : StencilOperation.DECREMENT_WRAP
  79356. },
  79357. backFunction : StencilFunction.NOT_EQUAL,
  79358. backOperation : {
  79359. fail : StencilOperation.KEEP,
  79360. zFail : StencilOperation.KEEP,
  79361. zPass : StencilOperation.DECREMENT_WRAP
  79362. },
  79363. reference : 0,
  79364. mask : ~0
  79365. },
  79366. depthTest : {
  79367. enabled : false
  79368. },
  79369. depthMask : false,
  79370. blending : BlendingState.ALPHA_BLEND
  79371. };
  79372. var pickRenderState = {
  79373. stencilTest : {
  79374. enabled : true,
  79375. frontFunction : StencilFunction.NOT_EQUAL,
  79376. frontOperation : {
  79377. fail : StencilOperation.KEEP,
  79378. zFail : StencilOperation.KEEP,
  79379. zPass : StencilOperation.DECREMENT_WRAP
  79380. },
  79381. backFunction : StencilFunction.NOT_EQUAL,
  79382. backOperation : {
  79383. fail : StencilOperation.KEEP,
  79384. zFail : StencilOperation.KEEP,
  79385. zPass : StencilOperation.DECREMENT_WRAP
  79386. },
  79387. reference : 0,
  79388. mask : ~0
  79389. },
  79390. depthTest : {
  79391. enabled : false
  79392. },
  79393. depthMask : false
  79394. };
  79395. var scratchBVCartesianHigh = new Cartesian3();
  79396. var scratchBVCartesianLow = new Cartesian3();
  79397. var scratchBVCartesian = new Cartesian3();
  79398. var scratchBVCartographic = new Cartographic();
  79399. var scratchBVRectangle = new Rectangle();
  79400. var tilingScheme = new GeographicTilingScheme();
  79401. var scratchCorners = [new Cartographic(), new Cartographic(), new Cartographic(), new Cartographic()];
  79402. var scratchTileXY = new Cartesian2();
  79403. function getRectangle(frameState, geometry) {
  79404. var ellipsoid = frameState.mapProjection.ellipsoid;
  79405. if (!defined(geometry.attributes) || !defined(geometry.attributes.position3DHigh)) {
  79406. if (defined(geometry.rectangle)) {
  79407. return geometry.rectangle;
  79408. }
  79409. return undefined;
  79410. }
  79411. var highPositions = geometry.attributes.position3DHigh.values;
  79412. var lowPositions = geometry.attributes.position3DLow.values;
  79413. var length = highPositions.length;
  79414. var minLat = Number.POSITIVE_INFINITY;
  79415. var minLon = Number.POSITIVE_INFINITY;
  79416. var maxLat = Number.NEGATIVE_INFINITY;
  79417. var maxLon = Number.NEGATIVE_INFINITY;
  79418. for (var i = 0; i < length; i +=3) {
  79419. var highPosition = Cartesian3.unpack(highPositions, i, scratchBVCartesianHigh);
  79420. var lowPosition = Cartesian3.unpack(lowPositions, i, scratchBVCartesianLow);
  79421. var position = Cartesian3.add(highPosition, lowPosition, scratchBVCartesian);
  79422. var cartographic = ellipsoid.cartesianToCartographic(position, scratchBVCartographic);
  79423. var latitude = cartographic.latitude;
  79424. var longitude = cartographic.longitude;
  79425. minLat = Math.min(minLat, latitude);
  79426. minLon = Math.min(minLon, longitude);
  79427. maxLat = Math.max(maxLat, latitude);
  79428. maxLon = Math.max(maxLon, longitude);
  79429. }
  79430. var rectangle = scratchBVRectangle;
  79431. rectangle.north = maxLat;
  79432. rectangle.south = minLat;
  79433. rectangle.east = maxLon;
  79434. rectangle.west = minLon;
  79435. return rectangle;
  79436. }
  79437. var scratchDiagonalCartesianNE = new Cartesian3();
  79438. var scratchDiagonalCartesianSW = new Cartesian3();
  79439. var scratchDiagonalCartographic = new Cartographic();
  79440. var scratchCenterCartesian = new Cartesian3();
  79441. var scratchSurfaceCartesian = new Cartesian3();
  79442. function getTileXYLevel(rectangle) {
  79443. Cartographic.fromRadians(rectangle.east, rectangle.north, 0.0, scratchCorners[0]);
  79444. Cartographic.fromRadians(rectangle.west, rectangle.north, 0.0, scratchCorners[1]);
  79445. Cartographic.fromRadians(rectangle.east, rectangle.south, 0.0, scratchCorners[2]);
  79446. Cartographic.fromRadians(rectangle.west, rectangle.south, 0.0, scratchCorners[3]);
  79447. // Determine which tile the bounding rectangle is in
  79448. var lastLevelX = 0, lastLevelY = 0;
  79449. var currentX = 0, currentY = 0;
  79450. var maxLevel = GroundPrimitive._terrainHeightsMaxLevel;
  79451. for(var i = 0; i <= maxLevel; ++i) {
  79452. var failed = false;
  79453. for(var j = 0; j < 4; ++j) {
  79454. var corner = scratchCorners[j];
  79455. tilingScheme.positionToTileXY(corner, i, scratchTileXY);
  79456. if (j === 0) {
  79457. currentX = scratchTileXY.x;
  79458. currentY = scratchTileXY.y;
  79459. } else if(currentX !== scratchTileXY.x || currentY !== scratchTileXY.y) {
  79460. failed = true;
  79461. break;
  79462. }
  79463. }
  79464. if (failed) {
  79465. break;
  79466. }
  79467. lastLevelX = currentX;
  79468. lastLevelY = currentY;
  79469. }
  79470. if (i === 0) {
  79471. return undefined;
  79472. }
  79473. return {
  79474. x : lastLevelX,
  79475. y : lastLevelY,
  79476. level : (i > maxLevel) ? maxLevel : (i - 1)
  79477. };
  79478. }
  79479. function setMinMaxTerrainHeights(primitive, rectangle, ellipsoid) {
  79480. var xyLevel = getTileXYLevel(rectangle);
  79481. // Get the terrain min/max for that tile
  79482. var minTerrainHeight = GroundPrimitive._defaultMinTerrainHeight;
  79483. var maxTerrainHeight = GroundPrimitive._defaultMaxTerrainHeight;
  79484. if (defined(xyLevel)) {
  79485. var key = xyLevel.level + '-' + xyLevel.x + '-' + xyLevel.y;
  79486. var heights = GroundPrimitive._terrainHeights[key];
  79487. if (defined(heights)) {
  79488. minTerrainHeight = heights[0];
  79489. maxTerrainHeight = heights[1];
  79490. }
  79491. // Compute min by taking the center of the NE->SW diagonal and finding distance to the surface
  79492. ellipsoid.cartographicToCartesian(Rectangle.northeast(rectangle, scratchDiagonalCartographic),
  79493. scratchDiagonalCartesianNE);
  79494. ellipsoid.cartographicToCartesian(Rectangle.southwest(rectangle, scratchDiagonalCartographic),
  79495. scratchDiagonalCartesianSW);
  79496. Cartesian3.subtract(scratchDiagonalCartesianSW, scratchDiagonalCartesianNE, scratchCenterCartesian);
  79497. Cartesian3.add(scratchDiagonalCartesianNE,
  79498. Cartesian3.multiplyByScalar(scratchCenterCartesian, 0.5, scratchCenterCartesian), scratchCenterCartesian);
  79499. var surfacePosition = ellipsoid.scaleToGeodeticSurface(scratchCenterCartesian, scratchSurfaceCartesian);
  79500. if (defined(surfacePosition)) {
  79501. var distance = Cartesian3.distance(scratchCenterCartesian, surfacePosition);
  79502. minTerrainHeight = Math.min(minTerrainHeight, -distance);
  79503. } else {
  79504. minTerrainHeight = GroundPrimitive._defaultMinTerrainHeight;
  79505. }
  79506. }
  79507. primitive._minTerrainHeight = Math.max(GroundPrimitive._defaultMinTerrainHeight, minTerrainHeight);
  79508. primitive._maxTerrainHeight = maxTerrainHeight;
  79509. }
  79510. var scratchBoundingSphere = new BoundingSphere();
  79511. function getInstanceBoundingSphere(rectangle, ellipsoid) {
  79512. var xyLevel = getTileXYLevel(rectangle);
  79513. // Get the terrain max for that tile
  79514. var maxTerrainHeight = GroundPrimitive._defaultMaxTerrainHeight;
  79515. if (defined(xyLevel)) {
  79516. var key = xyLevel.level + '-' + xyLevel.x + '-' + xyLevel.y;
  79517. var heights = GroundPrimitive._terrainHeights[key];
  79518. if (defined(heights)) {
  79519. maxTerrainHeight = heights[1];
  79520. }
  79521. }
  79522. var result = BoundingSphere.fromRectangle3D(rectangle, ellipsoid, 0.0);
  79523. BoundingSphere.fromRectangle3D(rectangle, ellipsoid, maxTerrainHeight, scratchBoundingSphere);
  79524. return BoundingSphere.union(result, scratchBoundingSphere, result);
  79525. }
  79526. function createBoundingVolume(primitive, frameState, geometry) {
  79527. var ellipsoid = frameState.mapProjection.ellipsoid;
  79528. var rectangle = getRectangle(frameState, geometry);
  79529. // Use an oriented bounding box by default, but switch to a bounding sphere if bounding box creation would fail.
  79530. if (rectangle.width < CesiumMath.PI) {
  79531. var obb = OrientedBoundingBox.fromRectangle(rectangle, primitive._maxHeight, primitive._minHeight, ellipsoid);
  79532. primitive._boundingVolumes.push(obb);
  79533. } else {
  79534. var highPositions = geometry.attributes.position3DHigh.values;
  79535. var lowPositions = geometry.attributes.position3DLow.values;
  79536. primitive._boundingVolumes.push(BoundingSphere.fromEncodedCartesianVertices(highPositions, lowPositions));
  79537. }
  79538. if (!frameState.scene3DOnly) {
  79539. var projection = frameState.mapProjection;
  79540. var boundingVolume = BoundingSphere.fromRectangleWithHeights2D(rectangle, projection, primitive._maxHeight, primitive._minHeight);
  79541. Cartesian3.fromElements(boundingVolume.center.z, boundingVolume.center.x, boundingVolume.center.y, boundingVolume.center);
  79542. primitive._boundingVolumes2D.push(boundingVolume);
  79543. }
  79544. }
  79545. function createRenderStates(primitive, context, appearance, twoPasses) {
  79546. if (defined(primitive._rsStencilPreloadPass)) {
  79547. return;
  79548. }
  79549. primitive._rsStencilPreloadPass = RenderState.fromCache(stencilPreloadRenderState);
  79550. primitive._rsStencilDepthPass = RenderState.fromCache(stencilDepthRenderState);
  79551. primitive._rsColorPass = RenderState.fromCache(colorRenderState);
  79552. primitive._rsPickPass = RenderState.fromCache(pickRenderState);
  79553. }
  79554. function createShaderProgram(primitive, frameState, appearance) {
  79555. if (defined(primitive._sp)) {
  79556. return;
  79557. }
  79558. var context = frameState.context;
  79559. var vs = ShadowVolumeVS;
  79560. vs = primitive._primitive._batchTable.getVertexShaderCallback()(vs);
  79561. vs = Primitive._appendShowToShader(primitive._primitive, vs);
  79562. vs = Primitive._appendDistanceDisplayConditionToShader(primitive._primitive, vs);
  79563. vs = Primitive._modifyShaderPosition(primitive, vs, frameState.scene3DOnly);
  79564. vs = Primitive._updateColorAttribute(primitive._primitive, vs);
  79565. var fs = ShadowVolumeFS;
  79566. var attributeLocations = primitive._primitive._attributeLocations;
  79567. primitive._sp = ShaderProgram.replaceCache({
  79568. context : context,
  79569. shaderProgram : primitive._sp,
  79570. vertexShaderSource : vs,
  79571. fragmentShaderSource : fs,
  79572. attributeLocations : attributeLocations
  79573. });
  79574. if (primitive._primitive.allowPicking) {
  79575. var vsPick = ShaderSource.createPickVertexShaderSource(vs);
  79576. vsPick = Primitive._updatePickColorAttribute(vsPick);
  79577. var pickFS = new ShaderSource({
  79578. sources : [fs],
  79579. pickColorQualifier : 'varying'
  79580. });
  79581. primitive._spPick = ShaderProgram.replaceCache({
  79582. context : context,
  79583. shaderProgram : primitive._spPick,
  79584. vertexShaderSource : vsPick,
  79585. fragmentShaderSource : pickFS,
  79586. attributeLocations : attributeLocations
  79587. });
  79588. } else {
  79589. primitive._spPick = ShaderProgram.fromCache({
  79590. context : context,
  79591. vertexShaderSource : vs,
  79592. fragmentShaderSource : fs,
  79593. attributeLocations : attributeLocations
  79594. });
  79595. }
  79596. }
  79597. function createColorCommands(groundPrimitive, colorCommands) {
  79598. var primitive = groundPrimitive._primitive;
  79599. var length = primitive._va.length * 3;
  79600. colorCommands.length = length;
  79601. var vaIndex = 0;
  79602. var uniformMap = primitive._batchTable.getUniformMapCallback()(groundPrimitive._uniformMap);
  79603. for (var i = 0; i < length; i += 3) {
  79604. var vertexArray = primitive._va[vaIndex++];
  79605. // stencil preload command
  79606. var command = colorCommands[i];
  79607. if (!defined(command)) {
  79608. command = colorCommands[i] = new DrawCommand({
  79609. owner : groundPrimitive,
  79610. primitiveType : primitive._primitiveType
  79611. });
  79612. }
  79613. command.vertexArray = vertexArray;
  79614. command.renderState = groundPrimitive._rsStencilPreloadPass;
  79615. command.shaderProgram = groundPrimitive._sp;
  79616. command.uniformMap = uniformMap;
  79617. command.pass = Pass.GROUND;
  79618. // stencil depth command
  79619. command = colorCommands[i + 1];
  79620. if (!defined(command)) {
  79621. command = colorCommands[i + 1] = new DrawCommand({
  79622. owner : groundPrimitive,
  79623. primitiveType : primitive._primitiveType
  79624. });
  79625. }
  79626. command.vertexArray = vertexArray;
  79627. command.renderState = groundPrimitive._rsStencilDepthPass;
  79628. command.shaderProgram = groundPrimitive._sp;
  79629. command.uniformMap = uniformMap;
  79630. command.pass = Pass.GROUND;
  79631. // color command
  79632. command = colorCommands[i + 2];
  79633. if (!defined(command)) {
  79634. command = colorCommands[i + 2] = new DrawCommand({
  79635. owner : groundPrimitive,
  79636. primitiveType : primitive._primitiveType
  79637. });
  79638. }
  79639. command.vertexArray = vertexArray;
  79640. command.renderState = groundPrimitive._rsColorPass;
  79641. command.shaderProgram = groundPrimitive._sp;
  79642. command.uniformMap = uniformMap;
  79643. command.pass = Pass.GROUND;
  79644. }
  79645. }
  79646. function createPickCommands(groundPrimitive, pickCommands) {
  79647. var primitive = groundPrimitive._primitive;
  79648. var pickOffsets = primitive._pickOffsets;
  79649. var length = pickOffsets.length * 3;
  79650. pickCommands.length = length;
  79651. var pickIndex = 0;
  79652. var uniformMap = primitive._batchTable.getUniformMapCallback()(groundPrimitive._uniformMap);
  79653. for (var j = 0; j < length; j += 3) {
  79654. var pickOffset = pickOffsets[pickIndex++];
  79655. var offset = pickOffset.offset;
  79656. var count = pickOffset.count;
  79657. var vertexArray = primitive._va[pickOffset.index];
  79658. // stencil preload command
  79659. var command = pickCommands[j];
  79660. if (!defined(command)) {
  79661. command = pickCommands[j] = new DrawCommand({
  79662. owner : groundPrimitive,
  79663. primitiveType : primitive._primitiveType
  79664. });
  79665. }
  79666. command.vertexArray = vertexArray;
  79667. command.offset = offset;
  79668. command.count = count;
  79669. command.renderState = groundPrimitive._rsStencilPreloadPass;
  79670. command.shaderProgram = groundPrimitive._sp;
  79671. command.uniformMap = uniformMap;
  79672. command.pass = Pass.GROUND;
  79673. // stencil depth command
  79674. command = pickCommands[j + 1];
  79675. if (!defined(command)) {
  79676. command = pickCommands[j + 1] = new DrawCommand({
  79677. owner : groundPrimitive,
  79678. primitiveType : primitive._primitiveType
  79679. });
  79680. }
  79681. command.vertexArray = vertexArray;
  79682. command.offset = offset;
  79683. command.count = count;
  79684. command.renderState = groundPrimitive._rsStencilDepthPass;
  79685. command.shaderProgram = groundPrimitive._sp;
  79686. command.uniformMap = uniformMap;
  79687. command.pass = Pass.GROUND;
  79688. // color command
  79689. command = pickCommands[j + 2];
  79690. if (!defined(command)) {
  79691. command = pickCommands[j + 2] = new DrawCommand({
  79692. owner : groundPrimitive,
  79693. primitiveType : primitive._primitiveType
  79694. });
  79695. }
  79696. command.vertexArray = vertexArray;
  79697. command.offset = offset;
  79698. command.count = count;
  79699. command.renderState = groundPrimitive._rsPickPass;
  79700. command.shaderProgram = groundPrimitive._spPick;
  79701. command.uniformMap = uniformMap;
  79702. command.pass = Pass.GROUND;
  79703. }
  79704. }
  79705. function createCommands(groundPrimitive, appearance, material, translucent, twoPasses, colorCommands, pickCommands) {
  79706. createColorCommands(groundPrimitive, colorCommands);
  79707. createPickCommands(groundPrimitive, pickCommands);
  79708. }
  79709. function updateAndQueueCommands(groundPrimitive, frameState, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume, twoPasses) {
  79710. var boundingVolumes;
  79711. if (frameState.mode === SceneMode.SCENE3D) {
  79712. boundingVolumes = groundPrimitive._boundingVolumes;
  79713. } else if (frameState.mode !== SceneMode.SCENE3D && defined(groundPrimitive._boundingVolumes2D)) {
  79714. boundingVolumes = groundPrimitive._boundingVolumes2D;
  79715. }
  79716. var commandList = frameState.commandList;
  79717. var passes = frameState.passes;
  79718. if (passes.render) {
  79719. var colorLength = colorCommands.length;
  79720. for (var j = 0; j < colorLength; ++j) {
  79721. colorCommands[j].modelMatrix = modelMatrix;
  79722. colorCommands[j].boundingVolume = boundingVolumes[Math.floor(j / 3)];
  79723. colorCommands[j].cull = cull;
  79724. colorCommands[j].debugShowBoundingVolume = debugShowBoundingVolume;
  79725. commandList.push(colorCommands[j]);
  79726. }
  79727. }
  79728. if (passes.pick) {
  79729. var primitive = groundPrimitive._primitive;
  79730. var pickOffsets = primitive._pickOffsets;
  79731. var length = pickOffsets.length * 3;
  79732. pickCommands.length = length;
  79733. var pickIndex = 0;
  79734. for (var k = 0; k < length; k += 3) {
  79735. var pickOffset = pickOffsets[pickIndex++];
  79736. var bv = boundingVolumes[pickOffset.index];
  79737. pickCommands[k].modelMatrix = modelMatrix;
  79738. pickCommands[k].boundingVolume = bv;
  79739. pickCommands[k].cull = cull;
  79740. pickCommands[k + 1].modelMatrix = modelMatrix;
  79741. pickCommands[k + 1].boundingVolume = bv;
  79742. pickCommands[k + 1].cull = cull;
  79743. pickCommands[k + 2].modelMatrix = modelMatrix;
  79744. pickCommands[k + 2].boundingVolume = bv;
  79745. pickCommands[k + 2].cull = cull;
  79746. commandList.push(pickCommands[k], pickCommands[k + 1], pickCommands[k + 2]);
  79747. }
  79748. }
  79749. }
  79750. GroundPrimitive._initialized = false;
  79751. GroundPrimitive._initPromise = undefined;
  79752. /**
  79753. * Initializes the minimum and maximum terrain heights. This only needs to be called if you are creating the
  79754. * GroundPrimitive asynchronously.
  79755. *
  79756. * @returns {Promise} A promise that will resolve once the terrain heights have been loaded.
  79757. *
  79758. */
  79759. GroundPrimitive.initializeTerrainHeights = function() {
  79760. var initPromise = GroundPrimitive._initPromise;
  79761. if (defined(initPromise)) {
  79762. return initPromise;
  79763. }
  79764. GroundPrimitive._initPromise = loadJson(buildModuleUrl('Assets/approximateTerrainHeights.json')).then(function(json) {
  79765. GroundPrimitive._initialized = true;
  79766. GroundPrimitive._terrainHeights = json;
  79767. });
  79768. return GroundPrimitive._initPromise;
  79769. };
  79770. /**
  79771. * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
  79772. * get the draw commands needed to render this primitive.
  79773. * <p>
  79774. * Do not call this function directly. This is documented just to
  79775. * list the exceptions that may be propagated when the scene is rendered:
  79776. * </p>
  79777. *
  79778. * @exception {DeveloperError} All instance geometries must have the same primitiveType.
  79779. * @exception {DeveloperError} Appearance and material have a uniform with the same name.
  79780. * @exception {DeveloperError} Not all of the geometry instances have the same color attribute.
  79781. */
  79782. GroundPrimitive.prototype.update = function(frameState) {
  79783. var context = frameState.context;
  79784. if (!context.fragmentDepth || !this.show || (!defined(this._primitive) && !defined(this.geometryInstances))) {
  79785. return;
  79786. }
  79787. if (!GroundPrimitive._initialized) {
  79788. if (!this.asynchronous) {
  79789. throw new DeveloperError('For synchronous GroundPrimitives, you must call GroundPrimitive.initializeTerrainHeights() and wait for the returned promise to resolve.');
  79790. }
  79791. GroundPrimitive.initializeTerrainHeights();
  79792. return;
  79793. }
  79794. if (!defined(this._primitive)) {
  79795. var primitiveOptions = this._primitiveOptions;
  79796. var ellipsoid = frameState.mapProjection.ellipsoid;
  79797. var instance;
  79798. var geometry;
  79799. var instanceType;
  79800. var instances = isArray(this.geometryInstances) ? this.geometryInstances : [this.geometryInstances];
  79801. var length = instances.length;
  79802. var groundInstances = new Array(length);
  79803. var i;
  79804. var color;
  79805. var rectangle;
  79806. for (i = 0; i < length; ++i) {
  79807. instance = instances[i];
  79808. geometry = instance.geometry;
  79809. var instanceRectangle = getRectangle(frameState, geometry);
  79810. if (!defined(rectangle)) {
  79811. rectangle = instanceRectangle;
  79812. } else {
  79813. if (defined(instanceRectangle)) {
  79814. Rectangle.union(rectangle, instanceRectangle, rectangle);
  79815. }
  79816. }
  79817. var id = instance.id;
  79818. if (defined(id) && defined(instanceRectangle)) {
  79819. var boundingSphere = getInstanceBoundingSphere(instanceRectangle, ellipsoid);
  79820. this._boundingSpheresKeys.push(id);
  79821. this._boundingSpheres.push(boundingSphere);
  79822. }
  79823. instanceType = geometry.constructor;
  79824. if (defined(instanceType) && defined(instanceType.createShadowVolume)) {
  79825. var attributes = instance.attributes;
  79826. if (!defined(attributes) || !defined(attributes.color)) {
  79827. throw new DeveloperError('Not all of the geometry instances have the same color attribute.');
  79828. } else if (defined(color) && !ColorGeometryInstanceAttribute.equals(color, attributes.color)) {
  79829. throw new DeveloperError('Not all of the geometry instances have the same color attribute.');
  79830. } else if (!defined(color)) {
  79831. color = attributes.color;
  79832. }
  79833. } else {
  79834. throw new DeveloperError('Not all of the geometry instances have GroundPrimitive support.');
  79835. }
  79836. }
  79837. // Now compute the min/max heights for the primitive
  79838. setMinMaxTerrainHeights(this, rectangle, frameState.mapProjection.ellipsoid);
  79839. var exaggeration = frameState.terrainExaggeration;
  79840. this._minHeight = this._minTerrainHeight * exaggeration;
  79841. this._maxHeight = this._maxTerrainHeight * exaggeration;
  79842. for (i = 0; i < length; ++i) {
  79843. instance = instances[i];
  79844. geometry = instance.geometry;
  79845. instanceType = geometry.constructor;
  79846. groundInstances[i] = new GeometryInstance({
  79847. geometry : instanceType.createShadowVolume(geometry, getComputeMinimumHeightFunction(this),
  79848. getComputeMaximumHeightFunction(this)),
  79849. attributes : instance.attributes,
  79850. id : instance.id,
  79851. pickPrimitive : this
  79852. });
  79853. }
  79854. primitiveOptions.geometryInstances = groundInstances;
  79855. var that = this;
  79856. primitiveOptions._createBoundingVolumeFunction = function(frameState, geometry) {
  79857. createBoundingVolume(that, frameState, geometry);
  79858. };
  79859. primitiveOptions._createRenderStatesFunction = function(primitive, context, appearance, twoPasses) {
  79860. createRenderStates(that, context);
  79861. };
  79862. primitiveOptions._createShaderProgramFunction = function(primitive, frameState, appearance) {
  79863. createShaderProgram(that, frameState);
  79864. };
  79865. primitiveOptions._createCommandsFunction = function(primitive, appearance, material, translucent, twoPasses, colorCommands, pickCommands) {
  79866. createCommands(that, undefined, undefined, true, false, colorCommands, pickCommands);
  79867. };
  79868. primitiveOptions._updateAndQueueCommandsFunction = function(primitive, frameState, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume, twoPasses) {
  79869. updateAndQueueCommands(that, frameState, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume, twoPasses);
  79870. };
  79871. this._primitive = new Primitive(primitiveOptions);
  79872. this._primitive.readyPromise.then(function(primitive) {
  79873. that._ready = true;
  79874. if (that.releaseGeometryInstances) {
  79875. that.geometryInstances = undefined;
  79876. }
  79877. var error = primitive._error;
  79878. if (!defined(error)) {
  79879. that._readyPromise.resolve(that);
  79880. } else {
  79881. that._readyPromise.reject(error);
  79882. }
  79883. });
  79884. }
  79885. this._primitive.debugShowBoundingVolume = this.debugShowBoundingVolume;
  79886. this._primitive.update(frameState);
  79887. if (this.debugShowShadowVolume && !defined(this._debugPrimitive) && defined(this.geometryInstances)) {
  79888. var debugInstances = isArray(this.geometryInstances) ? this.geometryInstances : [this.geometryInstances];
  79889. var debugLength = debugInstances.length;
  79890. var debugVolumeInstances = new Array(debugLength);
  79891. for (var j = 0 ; j < debugLength; ++j) {
  79892. var debugInstance = debugInstances[j];
  79893. var debugGeometry = debugInstance.geometry;
  79894. var debugInstanceType = debugGeometry.constructor;
  79895. if (defined(debugInstanceType) && defined(debugInstanceType.createShadowVolume)) {
  79896. var debugColorArray = debugInstance.attributes.color.value;
  79897. var debugColor = Color.fromBytes(debugColorArray[0], debugColorArray[1], debugColorArray[2], debugColorArray[3]);
  79898. Color.subtract(new Color(1.0, 1.0, 1.0, 0.0), debugColor, debugColor);
  79899. debugVolumeInstances[j] = new GeometryInstance({
  79900. geometry : debugInstanceType.createShadowVolume(debugGeometry, getComputeMinimumHeightFunction(this), getComputeMaximumHeightFunction(this)),
  79901. attributes : {
  79902. color : ColorGeometryInstanceAttribute.fromColor(debugColor)
  79903. },
  79904. id : debugInstance.id,
  79905. pickPrimitive : this
  79906. });
  79907. }
  79908. }
  79909. this._debugPrimitive = new Primitive({
  79910. geometryInstances : debugVolumeInstances,
  79911. releaseGeometryInstances : true,
  79912. allowPicking : false,
  79913. asynchronous : false,
  79914. appearance : new PerInstanceColorAppearance({
  79915. flat : true
  79916. })
  79917. });
  79918. }
  79919. if (defined(this._debugPrimitive)) {
  79920. if (this.debugShowShadowVolume) {
  79921. this._debugPrimitive.update(frameState);
  79922. } else {
  79923. this._debugPrimitive.destroy();
  79924. this._debugPrimitive = undefined;
  79925. }
  79926. }
  79927. };
  79928. /**
  79929. * @private
  79930. */
  79931. GroundPrimitive.prototype.getBoundingSphere = function(id) {
  79932. var index = this._boundingSpheresKeys.indexOf(id);
  79933. if (index !== -1) {
  79934. return this._boundingSpheres[index];
  79935. }
  79936. return undefined;
  79937. };
  79938. /**
  79939. * Returns the modifiable per-instance attributes for a {@link GeometryInstance}.
  79940. *
  79941. * @param {Object} id The id of the {@link GeometryInstance}.
  79942. * @returns {Object} The typed array in the attribute's format or undefined if the is no instance with id.
  79943. *
  79944. * @exception {DeveloperError} must call update before calling getGeometryInstanceAttributes.
  79945. *
  79946. * @example
  79947. * var attributes = primitive.getGeometryInstanceAttributes('an id');
  79948. * attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.AQUA);
  79949. * attributes.show = Cesium.ShowGeometryInstanceAttribute.toValue(true);
  79950. */
  79951. GroundPrimitive.prototype.getGeometryInstanceAttributes = function(id) {
  79952. if (!defined(this._primitive)) {
  79953. throw new DeveloperError('must call update before calling getGeometryInstanceAttributes');
  79954. }
  79955. return this._primitive.getGeometryInstanceAttributes(id);
  79956. };
  79957. /**
  79958. * Returns true if this object was destroyed; otherwise, false.
  79959. * <p>
  79960. * If this object was destroyed, it should not be used; calling any function other than
  79961. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  79962. * </p>
  79963. *
  79964. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  79965. *
  79966. * @see GroundPrimitive#destroy
  79967. */
  79968. GroundPrimitive.prototype.isDestroyed = function() {
  79969. return false;
  79970. };
  79971. /**
  79972. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  79973. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  79974. * <p>
  79975. * Once an object is destroyed, it should not be used; calling any function other than
  79976. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  79977. * assign the return value (<code>undefined</code>) to the object as done in the example.
  79978. * </p>
  79979. *
  79980. * @returns {undefined}
  79981. *
  79982. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  79983. *
  79984. * @example
  79985. * e = e && e.destroy();
  79986. *
  79987. * @see GroundPrimitive#isDestroyed
  79988. */
  79989. GroundPrimitive.prototype.destroy = function() {
  79990. this._primitive = this._primitive && this._primitive.destroy();
  79991. this._debugPrimitive = this._debugPrimitive && this._debugPrimitive.destroy();
  79992. this._sp = this._sp && this._sp.destroy();
  79993. this._spPick = this._spPick && this._spPick.destroy();
  79994. return destroyObject(this);
  79995. };
  79996. return GroundPrimitive;
  79997. });
  79998. /*global define*/
  79999. define('DataSources/CorridorGeometryUpdater',[
  80000. '../Core/Color',
  80001. '../Core/ColorGeometryInstanceAttribute',
  80002. '../Core/CorridorGeometry',
  80003. '../Core/CorridorOutlineGeometry',
  80004. '../Core/defaultValue',
  80005. '../Core/defined',
  80006. '../Core/defineProperties',
  80007. '../Core/destroyObject',
  80008. '../Core/DeveloperError',
  80009. '../Core/DistanceDisplayCondition',
  80010. '../Core/DistanceDisplayConditionGeometryInstanceAttribute',
  80011. '../Core/Event',
  80012. '../Core/GeometryInstance',
  80013. '../Core/Iso8601',
  80014. '../Core/oneTimeWarning',
  80015. '../Core/ShowGeometryInstanceAttribute',
  80016. '../Scene/GroundPrimitive',
  80017. '../Scene/MaterialAppearance',
  80018. '../Scene/PerInstanceColorAppearance',
  80019. '../Scene/Primitive',
  80020. '../Scene/ShadowMode',
  80021. './ColorMaterialProperty',
  80022. './ConstantProperty',
  80023. './dynamicGeometryGetBoundingSphere',
  80024. './MaterialProperty',
  80025. './Property'
  80026. ], function(
  80027. Color,
  80028. ColorGeometryInstanceAttribute,
  80029. CorridorGeometry,
  80030. CorridorOutlineGeometry,
  80031. defaultValue,
  80032. defined,
  80033. defineProperties,
  80034. destroyObject,
  80035. DeveloperError,
  80036. DistanceDisplayCondition,
  80037. DistanceDisplayConditionGeometryInstanceAttribute,
  80038. Event,
  80039. GeometryInstance,
  80040. Iso8601,
  80041. oneTimeWarning,
  80042. ShowGeometryInstanceAttribute,
  80043. GroundPrimitive,
  80044. MaterialAppearance,
  80045. PerInstanceColorAppearance,
  80046. Primitive,
  80047. ShadowMode,
  80048. ColorMaterialProperty,
  80049. ConstantProperty,
  80050. dynamicGeometryGetBoundingSphere,
  80051. MaterialProperty,
  80052. Property) {
  80053. 'use strict';
  80054. var defaultMaterial = new ColorMaterialProperty(Color.WHITE);
  80055. var defaultShow = new ConstantProperty(true);
  80056. var defaultFill = new ConstantProperty(true);
  80057. var defaultOutline = new ConstantProperty(false);
  80058. var defaultOutlineColor = new ConstantProperty(Color.BLACK);
  80059. var defaultShadows = new ConstantProperty(ShadowMode.DISABLED);
  80060. var defaultDistanceDisplayCondition = new ConstantProperty(new DistanceDisplayCondition());
  80061. var scratchColor = new Color();
  80062. function GeometryOptions(entity) {
  80063. this.id = entity;
  80064. this.vertexFormat = undefined;
  80065. this.positions = undefined;
  80066. this.width = undefined;
  80067. this.cornerType = undefined;
  80068. this.height = undefined;
  80069. this.extrudedHeight = undefined;
  80070. this.granularity = undefined;
  80071. }
  80072. /**
  80073. * A {@link GeometryUpdater} for corridors.
  80074. * Clients do not normally create this class directly, but instead rely on {@link DataSourceDisplay}.
  80075. * @alias CorridorGeometryUpdater
  80076. * @constructor
  80077. *
  80078. * @param {Entity} entity The entity containing the geometry to be visualized.
  80079. * @param {Scene} scene The scene where visualization is taking place.
  80080. */
  80081. function CorridorGeometryUpdater(entity, scene) {
  80082. if (!defined(entity)) {
  80083. throw new DeveloperError('entity is required');
  80084. }
  80085. if (!defined(scene)) {
  80086. throw new DeveloperError('scene is required');
  80087. }
  80088. this._entity = entity;
  80089. this._scene = scene;
  80090. this._entitySubscription = entity.definitionChanged.addEventListener(CorridorGeometryUpdater.prototype._onEntityPropertyChanged, this);
  80091. this._fillEnabled = false;
  80092. this._isClosed = false;
  80093. this._dynamic = false;
  80094. this._outlineEnabled = false;
  80095. this._geometryChanged = new Event();
  80096. this._showProperty = undefined;
  80097. this._materialProperty = undefined;
  80098. this._hasConstantOutline = true;
  80099. this._showOutlineProperty = undefined;
  80100. this._outlineColorProperty = undefined;
  80101. this._outlineWidth = 1.0;
  80102. this._shadowsProperty = undefined;
  80103. this._distanceDisplayConditionProperty = undefined;
  80104. this._onTerrain = false;
  80105. this._options = new GeometryOptions(entity);
  80106. this._onEntityPropertyChanged(entity, 'corridor', entity.corridor, undefined);
  80107. }
  80108. defineProperties(CorridorGeometryUpdater, {
  80109. /**
  80110. * Gets the type of Appearance to use for simple color-based geometry.
  80111. * @memberof CorridorGeometryUpdater
  80112. * @type {Appearance}
  80113. */
  80114. perInstanceColorAppearanceType : {
  80115. value : PerInstanceColorAppearance
  80116. },
  80117. /**
  80118. * Gets the type of Appearance to use for material-based geometry.
  80119. * @memberof CorridorGeometryUpdater
  80120. * @type {Appearance}
  80121. */
  80122. materialAppearanceType : {
  80123. value : MaterialAppearance
  80124. }
  80125. });
  80126. defineProperties(CorridorGeometryUpdater.prototype, {
  80127. /**
  80128. * Gets the entity associated with this geometry.
  80129. * @memberof CorridorGeometryUpdater.prototype
  80130. *
  80131. * @type {Entity}
  80132. * @readonly
  80133. */
  80134. entity : {
  80135. get : function() {
  80136. return this._entity;
  80137. }
  80138. },
  80139. /**
  80140. * Gets a value indicating if the geometry has a fill component.
  80141. * @memberof CorridorGeometryUpdater.prototype
  80142. *
  80143. * @type {Boolean}
  80144. * @readonly
  80145. */
  80146. fillEnabled : {
  80147. get : function() {
  80148. return this._fillEnabled;
  80149. }
  80150. },
  80151. /**
  80152. * Gets a value indicating if fill visibility varies with simulation time.
  80153. * @memberof CorridorGeometryUpdater.prototype
  80154. *
  80155. * @type {Boolean}
  80156. * @readonly
  80157. */
  80158. hasConstantFill : {
  80159. get : function() {
  80160. return !this._fillEnabled ||
  80161. (!defined(this._entity.availability) &&
  80162. Property.isConstant(this._showProperty) &&
  80163. Property.isConstant(this._fillProperty));
  80164. }
  80165. },
  80166. /**
  80167. * Gets the material property used to fill the geometry.
  80168. * @memberof CorridorGeometryUpdater.prototype
  80169. *
  80170. * @type {MaterialProperty}
  80171. * @readonly
  80172. */
  80173. fillMaterialProperty : {
  80174. get : function() {
  80175. return this._materialProperty;
  80176. }
  80177. },
  80178. /**
  80179. * Gets a value indicating if the geometry has an outline component.
  80180. * @memberof CorridorGeometryUpdater.prototype
  80181. *
  80182. * @type {Boolean}
  80183. * @readonly
  80184. */
  80185. outlineEnabled : {
  80186. get : function() {
  80187. return this._outlineEnabled;
  80188. }
  80189. },
  80190. /**
  80191. * Gets a value indicating if the geometry has an outline component.
  80192. * @memberof CorridorGeometryUpdater.prototype
  80193. *
  80194. * @type {Boolean}
  80195. * @readonly
  80196. */
  80197. hasConstantOutline : {
  80198. get : function() {
  80199. return !this._outlineEnabled ||
  80200. (!defined(this._entity.availability) &&
  80201. Property.isConstant(this._showProperty) &&
  80202. Property.isConstant(this._showOutlineProperty));
  80203. }
  80204. },
  80205. /**
  80206. * Gets the {@link Color} property for the geometry outline.
  80207. * @memberof CorridorGeometryUpdater.prototype
  80208. *
  80209. * @type {Property}
  80210. * @readonly
  80211. */
  80212. outlineColorProperty : {
  80213. get : function() {
  80214. return this._outlineColorProperty;
  80215. }
  80216. },
  80217. /**
  80218. * Gets the constant with of the geometry outline, in pixels.
  80219. * This value is only valid if isDynamic is false.
  80220. * @memberof CorridorGeometryUpdater.prototype
  80221. *
  80222. * @type {Number}
  80223. * @readonly
  80224. */
  80225. outlineWidth : {
  80226. get : function() {
  80227. return this._outlineWidth;
  80228. }
  80229. },
  80230. /**
  80231. * Gets the property specifying whether the geometry
  80232. * casts or receives shadows from each light source.
  80233. * @memberof CorridorGeometryUpdater.prototype
  80234. *
  80235. * @type {Property}
  80236. * @readonly
  80237. */
  80238. shadowsProperty : {
  80239. get : function() {
  80240. return this._shadowsProperty;
  80241. }
  80242. },
  80243. /**
  80244. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this geometry will be displayed.
  80245. * @memberof CorridorGeometryUpdater.prototype
  80246. *
  80247. * @type {Property}
  80248. * @readonly
  80249. */
  80250. distanceDisplayConditionProperty : {
  80251. get : function() {
  80252. return this._distanceDisplayCondition;
  80253. }
  80254. },
  80255. /**
  80256. * Gets a value indicating if the geometry is time-varying.
  80257. * If true, all visualization is delegated to the {@link DynamicGeometryUpdater}
  80258. * returned by GeometryUpdater#createDynamicUpdater.
  80259. * @memberof CorridorGeometryUpdater.prototype
  80260. *
  80261. * @type {Boolean}
  80262. * @readonly
  80263. */
  80264. isDynamic : {
  80265. get : function() {
  80266. return this._dynamic;
  80267. }
  80268. },
  80269. /**
  80270. * Gets a value indicating if the geometry is closed.
  80271. * This property is only valid for static geometry.
  80272. * @memberof CorridorGeometryUpdater.prototype
  80273. *
  80274. * @type {Boolean}
  80275. * @readonly
  80276. */
  80277. isClosed : {
  80278. get : function() {
  80279. return this._isClosed;
  80280. }
  80281. },
  80282. /**
  80283. * Gets a value indicating if the geometry should be drawn on terrain.
  80284. * @memberof CorridorGeometryUpdater.prototype
  80285. *
  80286. * @type {Boolean}
  80287. * @readonly
  80288. */
  80289. onTerrain : {
  80290. get : function() {
  80291. return this._onTerrain;
  80292. }
  80293. },
  80294. /**
  80295. * Gets an event that is raised whenever the public properties
  80296. * of this updater change.
  80297. * @memberof CorridorGeometryUpdater.prototype
  80298. *
  80299. * @type {Boolean}
  80300. * @readonly
  80301. */
  80302. geometryChanged : {
  80303. get : function() {
  80304. return this._geometryChanged;
  80305. }
  80306. }
  80307. });
  80308. /**
  80309. * Checks if the geometry is outlined at the provided time.
  80310. *
  80311. * @param {JulianDate} time The time for which to retrieve visibility.
  80312. * @returns {Boolean} true if geometry is outlined at the provided time, false otherwise.
  80313. */
  80314. CorridorGeometryUpdater.prototype.isOutlineVisible = function(time) {
  80315. var entity = this._entity;
  80316. return this._outlineEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time);
  80317. };
  80318. /**
  80319. * Checks if the geometry is filled at the provided time.
  80320. *
  80321. * @param {JulianDate} time The time for which to retrieve visibility.
  80322. * @returns {Boolean} true if geometry is filled at the provided time, false otherwise.
  80323. */
  80324. CorridorGeometryUpdater.prototype.isFilled = function(time) {
  80325. var entity = this._entity;
  80326. return this._fillEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._fillProperty.getValue(time);
  80327. };
  80328. /**
  80329. * Creates the geometry instance which represents the fill of the geometry.
  80330. *
  80331. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  80332. * @returns {GeometryInstance} The geometry instance representing the filled portion of the geometry.
  80333. *
  80334. * @exception {DeveloperError} This instance does not represent a filled geometry.
  80335. */
  80336. CorridorGeometryUpdater.prototype.createFillGeometryInstance = function(time) {
  80337. if (!defined(time)) {
  80338. throw new DeveloperError('time is required.');
  80339. }
  80340. if (!this._fillEnabled) {
  80341. throw new DeveloperError('This instance does not represent a filled geometry.');
  80342. }
  80343. var entity = this._entity;
  80344. var isAvailable = entity.isAvailable(time);
  80345. var attributes;
  80346. var color;
  80347. var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time));
  80348. var distanceDisplayCondition = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(this._distanceDisplayCondition.getValue(time));
  80349. if (this._materialProperty instanceof ColorMaterialProperty) {
  80350. var currentColor = Color.WHITE;
  80351. if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) {
  80352. currentColor = this._materialProperty.color.getValue(time);
  80353. }
  80354. color = ColorGeometryInstanceAttribute.fromColor(currentColor);
  80355. attributes = {
  80356. show : show,
  80357. distanceDisplayCondition : distanceDisplayCondition,
  80358. color : color
  80359. };
  80360. } else {
  80361. attributes = {
  80362. show : show,
  80363. distanceDisplayCondition : distanceDisplayCondition
  80364. };
  80365. }
  80366. return new GeometryInstance({
  80367. id : entity,
  80368. geometry : new CorridorGeometry(this._options),
  80369. attributes : attributes
  80370. });
  80371. };
  80372. /**
  80373. * Creates the geometry instance which represents the outline of the geometry.
  80374. *
  80375. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  80376. * @returns {GeometryInstance} The geometry instance representing the outline portion of the geometry.
  80377. *
  80378. * @exception {DeveloperError} This instance does not represent an outlined geometry.
  80379. */
  80380. CorridorGeometryUpdater.prototype.createOutlineGeometryInstance = function(time) {
  80381. if (!defined(time)) {
  80382. throw new DeveloperError('time is required.');
  80383. }
  80384. if (!this._outlineEnabled) {
  80385. throw new DeveloperError('This instance does not represent an outlined geometry.');
  80386. }
  80387. var entity = this._entity;
  80388. var isAvailable = entity.isAvailable(time);
  80389. var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK);
  80390. return new GeometryInstance({
  80391. id : entity,
  80392. geometry : new CorridorOutlineGeometry(this._options),
  80393. attributes : {
  80394. show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
  80395. color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
  80396. distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(this._distanceDisplayCondition.getValue(time))
  80397. }
  80398. });
  80399. };
  80400. /**
  80401. * Returns true if this object was destroyed; otherwise, false.
  80402. *
  80403. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  80404. */
  80405. CorridorGeometryUpdater.prototype.isDestroyed = function() {
  80406. return false;
  80407. };
  80408. /**
  80409. * Destroys and resources used by the object. Once an object is destroyed, it should not be used.
  80410. *
  80411. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  80412. */
  80413. CorridorGeometryUpdater.prototype.destroy = function() {
  80414. this._entitySubscription();
  80415. destroyObject(this);
  80416. };
  80417. CorridorGeometryUpdater.prototype._onEntityPropertyChanged = function(entity, propertyName, newValue, oldValue) {
  80418. if (!(propertyName === 'availability' || propertyName === 'corridor')) {
  80419. return;
  80420. }
  80421. var corridor = this._entity.corridor;
  80422. if (!defined(corridor)) {
  80423. if (this._fillEnabled || this._outlineEnabled) {
  80424. this._fillEnabled = false;
  80425. this._outlineEnabled = false;
  80426. this._geometryChanged.raiseEvent(this);
  80427. }
  80428. return;
  80429. }
  80430. var fillProperty = corridor.fill;
  80431. var fillEnabled = defined(fillProperty) && fillProperty.isConstant ? fillProperty.getValue(Iso8601.MINIMUM_VALUE) : true;
  80432. var outlineProperty = corridor.outline;
  80433. var outlineEnabled = defined(outlineProperty);
  80434. if (outlineEnabled && outlineProperty.isConstant) {
  80435. outlineEnabled = outlineProperty.getValue(Iso8601.MINIMUM_VALUE);
  80436. }
  80437. if (!fillEnabled && !outlineEnabled) {
  80438. if (this._fillEnabled || this._outlineEnabled) {
  80439. this._fillEnabled = false;
  80440. this._outlineEnabled = false;
  80441. this._geometryChanged.raiseEvent(this);
  80442. }
  80443. return;
  80444. }
  80445. var positions = corridor.positions;
  80446. var show = corridor.show;
  80447. if ((defined(show) && show.isConstant && !show.getValue(Iso8601.MINIMUM_VALUE)) || //
  80448. (!defined(positions))) {
  80449. if (this._fillEnabled || this._outlineEnabled) {
  80450. this._fillEnabled = false;
  80451. this._outlineEnabled = false;
  80452. this._geometryChanged.raiseEvent(this);
  80453. }
  80454. return;
  80455. }
  80456. var material = defaultValue(corridor.material, defaultMaterial);
  80457. var isColorMaterial = material instanceof ColorMaterialProperty;
  80458. this._materialProperty = material;
  80459. this._fillProperty = defaultValue(fillProperty, defaultFill);
  80460. this._showProperty = defaultValue(show, defaultShow);
  80461. this._showOutlineProperty = defaultValue(corridor.outline, defaultOutline);
  80462. this._outlineColorProperty = outlineEnabled ? defaultValue(corridor.outlineColor, defaultOutlineColor) : undefined;
  80463. this._shadowsProperty = defaultValue(corridor.shadows, defaultShadows);
  80464. this._distanceDisplayCondition = defaultValue(corridor.distanceDisplayCondition, defaultDistanceDisplayCondition);
  80465. var height = corridor.height;
  80466. var extrudedHeight = corridor.extrudedHeight;
  80467. var granularity = corridor.granularity;
  80468. var width = corridor.width;
  80469. var outlineWidth = corridor.outlineWidth;
  80470. var cornerType = corridor.cornerType;
  80471. var onTerrain = fillEnabled && !defined(height) && !defined(extrudedHeight) &&
  80472. isColorMaterial && GroundPrimitive.isSupported(this._scene);
  80473. if (outlineEnabled && onTerrain) {
  80474. oneTimeWarning(oneTimeWarning.geometryOutlines);
  80475. outlineEnabled = false;
  80476. }
  80477. this._fillEnabled = fillEnabled;
  80478. this._onTerrain = onTerrain;
  80479. this._isClosed = defined(extrudedHeight) || onTerrain;
  80480. this._outlineEnabled = outlineEnabled;
  80481. if (!positions.isConstant || //
  80482. !Property.isConstant(height) || //
  80483. !Property.isConstant(extrudedHeight) || //
  80484. !Property.isConstant(granularity) || //
  80485. !Property.isConstant(width) || //
  80486. !Property.isConstant(outlineWidth) || //
  80487. !Property.isConstant(cornerType) || //
  80488. (onTerrain && !Property.isConstant(material))) {
  80489. if (!this._dynamic) {
  80490. this._dynamic = true;
  80491. this._geometryChanged.raiseEvent(this);
  80492. }
  80493. } else {
  80494. var options = this._options;
  80495. options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat;
  80496. options.positions = positions.getValue(Iso8601.MINIMUM_VALUE, options.positions);
  80497. options.height = defined(height) ? height.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  80498. options.extrudedHeight = defined(extrudedHeight) ? extrudedHeight.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  80499. options.granularity = defined(granularity) ? granularity.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  80500. options.width = defined(width) ? width.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  80501. options.cornerType = defined(cornerType) ? cornerType.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  80502. this._outlineWidth = defined(outlineWidth) ? outlineWidth.getValue(Iso8601.MINIMUM_VALUE) : 1.0;
  80503. this._dynamic = false;
  80504. this._geometryChanged.raiseEvent(this);
  80505. }
  80506. };
  80507. /**
  80508. * Creates the dynamic updater to be used when GeometryUpdater#isDynamic is true.
  80509. *
  80510. * @param {PrimitiveCollection} primitives The primitive collection to use.
  80511. * @returns {DynamicGeometryUpdater} The dynamic updater used to update the geometry each frame.
  80512. *
  80513. * @exception {DeveloperError} This instance does not represent dynamic geometry.
  80514. */
  80515. CorridorGeometryUpdater.prototype.createDynamicUpdater = function(primitives, groundPrimitives) {
  80516. if (!this._dynamic) {
  80517. throw new DeveloperError('This instance does not represent dynamic geometry.');
  80518. }
  80519. if (!defined(primitives)) {
  80520. throw new DeveloperError('primitives is required.');
  80521. }
  80522. return new DynamicGeometryUpdater(primitives, groundPrimitives, this);
  80523. };
  80524. /**
  80525. * @private
  80526. */
  80527. function DynamicGeometryUpdater(primitives, groundPrimitives, geometryUpdater) {
  80528. this._primitives = primitives;
  80529. this._groundPrimitives = groundPrimitives;
  80530. this._primitive = undefined;
  80531. this._outlinePrimitive = undefined;
  80532. this._geometryUpdater = geometryUpdater;
  80533. this._options = new GeometryOptions(geometryUpdater._entity);
  80534. }
  80535. DynamicGeometryUpdater.prototype.update = function(time) {
  80536. if (!defined(time)) {
  80537. throw new DeveloperError('time is required.');
  80538. }
  80539. var geometryUpdater = this._geometryUpdater;
  80540. var onTerrain = geometryUpdater._onTerrain;
  80541. var primitives = this._primitives;
  80542. var groundPrimitives = this._groundPrimitives;
  80543. if (onTerrain) {
  80544. groundPrimitives.removeAndDestroy(this._primitive);
  80545. } else {
  80546. primitives.removeAndDestroy(this._primitive);
  80547. primitives.removeAndDestroy(this._outlinePrimitive);
  80548. this._outlinePrimitive = undefined;
  80549. }
  80550. this._primitive = undefined;
  80551. var entity = geometryUpdater._entity;
  80552. var corridor = entity.corridor;
  80553. if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(corridor.show, time, true)) {
  80554. return;
  80555. }
  80556. var options = this._options;
  80557. var positions = Property.getValueOrUndefined(corridor.positions, time, options.positions);
  80558. var width = Property.getValueOrUndefined(corridor.width, time);
  80559. if (!defined(positions) || !defined(width)) {
  80560. return;
  80561. }
  80562. options.positions = positions;
  80563. options.width = width;
  80564. options.height = Property.getValueOrUndefined(corridor.height, time);
  80565. options.extrudedHeight = Property.getValueOrUndefined(corridor.extrudedHeight, time);
  80566. options.granularity = Property.getValueOrUndefined(corridor.granularity, time);
  80567. options.cornerType = Property.getValueOrUndefined(corridor.cornerType, time);
  80568. var shadows = this._geometryUpdater.shadowsProperty.getValue(time);
  80569. var distanceDisplayCondition = this._geometryUpdater.distanceDisplayConditionProperty.getValue(time);
  80570. var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
  80571. if (!defined(corridor.fill) || corridor.fill.getValue(time)) {
  80572. var fillMaterialProperty = geometryUpdater.fillMaterialProperty;
  80573. var material = MaterialProperty.getValue(time, fillMaterialProperty, this._material);
  80574. this._material = material;
  80575. if (onTerrain) {
  80576. var currentColor = Color.WHITE;
  80577. if (defined(fillMaterialProperty.color)) {
  80578. currentColor = fillMaterialProperty.color.getValue(time);
  80579. }
  80580. this._primitive = groundPrimitives.add(new GroundPrimitive({
  80581. geometryInstances : new GeometryInstance({
  80582. id : entity,
  80583. geometry : new CorridorGeometry(options),
  80584. attributes: {
  80585. color: ColorGeometryInstanceAttribute.fromColor(currentColor),
  80586. distanceDisplayCondition : distanceDisplayConditionAttribute
  80587. }
  80588. }),
  80589. asynchronous : false,
  80590. shadows : shadows
  80591. }));
  80592. } else {
  80593. var appearance = new MaterialAppearance({
  80594. material : material,
  80595. translucent : material.isTranslucent(),
  80596. closed : defined(options.extrudedHeight)
  80597. });
  80598. options.vertexFormat = appearance.vertexFormat;
  80599. this._primitive = primitives.add(new Primitive({
  80600. geometryInstances : new GeometryInstance({
  80601. id : entity,
  80602. geometry : new CorridorGeometry(options),
  80603. attributes : {
  80604. distanceDisplayCondition : distanceDisplayConditionAttribute
  80605. }
  80606. }),
  80607. appearance : appearance,
  80608. asynchronous : false,
  80609. shadows : shadows
  80610. }));
  80611. }
  80612. }
  80613. if (!onTerrain && defined(corridor.outline) && corridor.outline.getValue(time)) {
  80614. options.vertexFormat = PerInstanceColorAppearance.VERTEX_FORMAT;
  80615. var outlineColor = Property.getValueOrClonedDefault(corridor.outlineColor, time, Color.BLACK, scratchColor);
  80616. var outlineWidth = Property.getValueOrDefault(corridor.outlineWidth, time, 1.0);
  80617. var translucent = outlineColor.alpha !== 1.0;
  80618. this._outlinePrimitive = primitives.add(new Primitive({
  80619. geometryInstances : new GeometryInstance({
  80620. id : entity,
  80621. geometry : new CorridorOutlineGeometry(options),
  80622. attributes : {
  80623. color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
  80624. distanceDisplayCondition : distanceDisplayConditionAttribute
  80625. }
  80626. }),
  80627. appearance : new PerInstanceColorAppearance({
  80628. flat : true,
  80629. translucent : translucent,
  80630. renderState : {
  80631. lineWidth : geometryUpdater._scene.clampLineWidth(outlineWidth)
  80632. }
  80633. }),
  80634. asynchronous : false,
  80635. shadows : shadows
  80636. }));
  80637. }
  80638. };
  80639. DynamicGeometryUpdater.prototype.getBoundingSphere = function(entity, result) {
  80640. return dynamicGeometryGetBoundingSphere(entity, this._primitive, this._outlinePrimitive, result);
  80641. };
  80642. DynamicGeometryUpdater.prototype.isDestroyed = function() {
  80643. return false;
  80644. };
  80645. DynamicGeometryUpdater.prototype.destroy = function() {
  80646. var primitives = this._primitives;
  80647. var groundPrimitives = this._groundPrimitives;
  80648. if (this._geometryUpdater._onTerrain) {
  80649. groundPrimitives.removeAndDestroy(this._primitive);
  80650. } else {
  80651. primitives.removeAndDestroy(this._primitive);
  80652. }
  80653. primitives.removeAndDestroy(this._outlinePrimitive);
  80654. destroyObject(this);
  80655. };
  80656. return CorridorGeometryUpdater;
  80657. });
  80658. /*global define*/
  80659. define('DataSources/DataSource',[
  80660. '../Core/defineProperties',
  80661. '../Core/DeveloperError'
  80662. ], function(
  80663. defineProperties,
  80664. DeveloperError) {
  80665. 'use strict';
  80666. /**
  80667. * Defines the interface for data sources, which turn arbitrary data into a
  80668. * {@link EntityCollection} for generic consumption. This object is an interface
  80669. * for documentation purposes and is not intended to be instantiated directly.
  80670. * @alias DataSource
  80671. * @constructor
  80672. *
  80673. * @see Entity
  80674. * @see DataSourceDisplay
  80675. */
  80676. function DataSource() {
  80677. DeveloperError.throwInstantiationError();
  80678. }
  80679. defineProperties(DataSource.prototype, {
  80680. /**
  80681. * Gets a human-readable name for this instance.
  80682. * @memberof DataSource.prototype
  80683. * @type {String}
  80684. */
  80685. name : {
  80686. get : DeveloperError.throwInstantiationError
  80687. },
  80688. /**
  80689. * Gets the preferred clock settings for this data source.
  80690. * @memberof DataSource.prototype
  80691. * @type {DataSourceClock}
  80692. */
  80693. clock : {
  80694. get : DeveloperError.throwInstantiationError
  80695. },
  80696. /**
  80697. * Gets the collection of {@link Entity} instances.
  80698. * @memberof DataSource.prototype
  80699. * @type {EntityCollection}
  80700. */
  80701. entities : {
  80702. get : DeveloperError.throwInstantiationError
  80703. },
  80704. /**
  80705. * Gets a value indicating if the data source is currently loading data.
  80706. * @memberof DataSource.prototype
  80707. * @type {Boolean}
  80708. */
  80709. isLoading : {
  80710. get : DeveloperError.throwInstantiationError
  80711. },
  80712. /**
  80713. * Gets an event that will be raised when the underlying data changes.
  80714. * @memberof DataSource.prototype
  80715. * @type {Event}
  80716. */
  80717. changedEvent : {
  80718. get : DeveloperError.throwInstantiationError
  80719. },
  80720. /**
  80721. * Gets an event that will be raised if an error is encountered during processing.
  80722. * @memberof DataSource.prototype
  80723. * @type {Event}
  80724. */
  80725. errorEvent : {
  80726. get : DeveloperError.throwInstantiationError
  80727. },
  80728. /**
  80729. * Gets an event that will be raised when the value of isLoading changes.
  80730. * @memberof DataSource.prototype
  80731. * @type {Event}
  80732. */
  80733. loadingEvent : {
  80734. get : DeveloperError.throwInstantiationError
  80735. },
  80736. /**
  80737. * Gets whether or not this data source should be displayed.
  80738. * @memberof DataSource.prototype
  80739. * @type {Boolean}
  80740. */
  80741. show : {
  80742. get : DeveloperError.throwInstantiationError
  80743. },
  80744. /**
  80745. * Gets or sets the clustering options for this data source. This object can be shared between multiple data sources.
  80746. *
  80747. * @memberof DataSource.prototype
  80748. * @type {EntityCluster}
  80749. */
  80750. clustering : {
  80751. get : DeveloperError.throwInstantiationError
  80752. }
  80753. });
  80754. /**
  80755. * Updates the data source to the provided time. This function is optional and
  80756. * is not required to be implemented. It is provided for data sources which
  80757. * retrieve data based on the current animation time or scene state.
  80758. * If implemented, update will be called by {@link DataSourceDisplay} once a frame.
  80759. * @function
  80760. *
  80761. * @param {JulianDate} time The simulation time.
  80762. * @returns {Boolean} True if this data source is ready to be displayed at the provided time, false otherwise.
  80763. */
  80764. DataSource.prototype.update = DeveloperError.throwInstantiationError;
  80765. /**
  80766. * @private
  80767. */
  80768. DataSource.setLoading = function(dataSource, isLoading) {
  80769. if (dataSource._isLoading !== isLoading) {
  80770. if (isLoading) {
  80771. dataSource._entityCollection.suspendEvents();
  80772. } else {
  80773. dataSource._entityCollection.resumeEvents();
  80774. }
  80775. dataSource._isLoading = isLoading;
  80776. dataSource._loading.raiseEvent(dataSource, isLoading);
  80777. }
  80778. };
  80779. return DataSource;
  80780. });
  80781. /*global define*/
  80782. define('Scene/SceneTransforms',[
  80783. '../Core/BoundingRectangle',
  80784. '../Core/Cartesian2',
  80785. '../Core/Cartesian3',
  80786. '../Core/Cartesian4',
  80787. '../Core/Cartographic',
  80788. '../Core/defined',
  80789. '../Core/DeveloperError',
  80790. '../Core/Math',
  80791. '../Core/Matrix4',
  80792. '../Core/Transforms',
  80793. './SceneMode'
  80794. ], function(
  80795. BoundingRectangle,
  80796. Cartesian2,
  80797. Cartesian3,
  80798. Cartesian4,
  80799. Cartographic,
  80800. defined,
  80801. DeveloperError,
  80802. CesiumMath,
  80803. Matrix4,
  80804. Transforms,
  80805. SceneMode) {
  80806. 'use strict';
  80807. /**
  80808. * Functions that do scene-dependent transforms between rendering-related coordinate systems.
  80809. *
  80810. * @exports SceneTransforms
  80811. */
  80812. var SceneTransforms = {};
  80813. var actualPositionScratch = new Cartesian4(0, 0, 0, 1);
  80814. var positionCC = new Cartesian4();
  80815. var scratchViewport = new BoundingRectangle();
  80816. var scratchWindowCoord0 = new Cartesian2();
  80817. var scratchWindowCoord1 = new Cartesian2();
  80818. /**
  80819. * Transforms a position in WGS84 coordinates to window coordinates. This is commonly used to place an
  80820. * HTML element at the same screen position as an object in the scene.
  80821. *
  80822. * @param {Scene} scene The scene.
  80823. * @param {Cartesian3} position The position in WGS84 (world) coordinates.
  80824. * @param {Cartesian2} [result] An optional object to return the input position transformed to window coordinates.
  80825. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided. This may be <code>undefined</code> if the input position is near the center of the ellipsoid.
  80826. *
  80827. * @example
  80828. * // Output the window position of longitude/latitude (0, 0) every time the mouse moves.
  80829. * var scene = widget.scene;
  80830. * var ellipsoid = scene.globe.ellipsoid;
  80831. * var position = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  80832. * var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
  80833. * handler.setInputAction(function(movement) {
  80834. * console.log(Cesium.SceneTransforms.wgs84ToWindowCoordinates(scene, position));
  80835. * }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  80836. */
  80837. SceneTransforms.wgs84ToWindowCoordinates = function(scene, position, result) {
  80838. return SceneTransforms.wgs84WithEyeOffsetToWindowCoordinates(scene, position, Cartesian3.ZERO, result);
  80839. };
  80840. var scratchCartesian4 = new Cartesian4();
  80841. var scratchEyeOffset = new Cartesian3();
  80842. function worldToClip(position, eyeOffset, camera, result) {
  80843. var viewMatrix = camera.viewMatrix;
  80844. var positionEC = Matrix4.multiplyByVector(viewMatrix, Cartesian4.fromElements(position.x, position.y, position.z, 1, scratchCartesian4), scratchCartesian4);
  80845. var zEyeOffset = Cartesian3.multiplyComponents(eyeOffset, Cartesian3.normalize(positionEC, scratchEyeOffset), scratchEyeOffset);
  80846. positionEC.x += eyeOffset.x + zEyeOffset.x;
  80847. positionEC.y += eyeOffset.y + zEyeOffset.y;
  80848. positionEC.z += zEyeOffset.z;
  80849. return Matrix4.multiplyByVector(camera.frustum.projectionMatrix, positionEC, result);
  80850. }
  80851. var scratchMaxCartographic = new Cartographic(Math.PI, CesiumMath.PI_OVER_TWO);
  80852. var scratchProjectedCartesian = new Cartesian3();
  80853. var scratchCameraPosition = new Cartesian3();
  80854. /**
  80855. * @private
  80856. */
  80857. SceneTransforms.wgs84WithEyeOffsetToWindowCoordinates = function(scene, position, eyeOffset, result) {
  80858. if (!defined(scene)) {
  80859. throw new DeveloperError('scene is required.');
  80860. }
  80861. if (!defined(position)) {
  80862. throw new DeveloperError('position is required.');
  80863. }
  80864. // Transform for 3D, 2D, or Columbus view
  80865. var frameState = scene.frameState;
  80866. var actualPosition = SceneTransforms.computeActualWgs84Position(frameState, position, actualPositionScratch);
  80867. if (!defined(actualPosition)) {
  80868. return undefined;
  80869. }
  80870. // Assuming viewport takes up the entire canvas...
  80871. var canvas = scene.canvas;
  80872. var viewport = scratchViewport;
  80873. viewport.x = 0;
  80874. viewport.y = 0;
  80875. viewport.width = canvas.clientWidth;
  80876. viewport.height = canvas.clientHeight;
  80877. var camera = scene.camera;
  80878. var cameraCentered = false;
  80879. if (frameState.mode === SceneMode.SCENE2D) {
  80880. var projection = scene.mapProjection;
  80881. var maxCartographic = scratchMaxCartographic;
  80882. var maxCoord = projection.project(maxCartographic, scratchProjectedCartesian);
  80883. var cameraPosition = Cartesian3.clone(camera.position, scratchCameraPosition);
  80884. var frustum = camera.frustum.clone();
  80885. var viewportTransformation = Matrix4.computeViewportTransformation(viewport, 0.0, 1.0, new Matrix4());
  80886. var projectionMatrix = camera.frustum.projectionMatrix;
  80887. var x = camera.positionWC.y;
  80888. var eyePoint = Cartesian3.fromElements(CesiumMath.sign(x) * maxCoord.x - x, 0.0, -camera.positionWC.x);
  80889. var windowCoordinates = Transforms.pointToGLWindowCoordinates(projectionMatrix, viewportTransformation, eyePoint);
  80890. if (x === 0.0 || windowCoordinates.x <= 0.0 || windowCoordinates.x >= canvas.clientWidth) {
  80891. cameraCentered = true;
  80892. } else {
  80893. if (windowCoordinates.x > canvas.clientWidth * 0.5) {
  80894. viewport.width = windowCoordinates.x;
  80895. camera.frustum.right = maxCoord.x - x;
  80896. positionCC = worldToClip(actualPosition, eyeOffset, camera, positionCC);
  80897. SceneTransforms.clipToGLWindowCoordinates(viewport, positionCC, scratchWindowCoord0);
  80898. viewport.x += windowCoordinates.x;
  80899. camera.position.x = -camera.position.x;
  80900. var right = camera.frustum.right;
  80901. camera.frustum.right = -camera.frustum.left;
  80902. camera.frustum.left = -right;
  80903. positionCC = worldToClip(actualPosition, eyeOffset, camera, positionCC);
  80904. SceneTransforms.clipToGLWindowCoordinates(viewport, positionCC, scratchWindowCoord1);
  80905. } else {
  80906. viewport.x += windowCoordinates.x;
  80907. viewport.width -= windowCoordinates.x;
  80908. camera.frustum.left = -maxCoord.x - x;
  80909. positionCC = worldToClip(actualPosition, eyeOffset, camera, positionCC);
  80910. SceneTransforms.clipToGLWindowCoordinates(viewport, positionCC, scratchWindowCoord0);
  80911. viewport.x = viewport.x - viewport.width;
  80912. camera.position.x = -camera.position.x;
  80913. var left = camera.frustum.left;
  80914. camera.frustum.left = -camera.frustum.right;
  80915. camera.frustum.right = -left;
  80916. positionCC = worldToClip(actualPosition, eyeOffset, camera, positionCC);
  80917. SceneTransforms.clipToGLWindowCoordinates(viewport, positionCC, scratchWindowCoord1);
  80918. }
  80919. Cartesian3.clone(cameraPosition, camera.position);
  80920. camera.frustum = frustum.clone();
  80921. result = Cartesian2.clone(scratchWindowCoord0, result);
  80922. if (result.x < 0.0 || result.x > canvas.clientWidth) {
  80923. result.x = scratchWindowCoord1.x;
  80924. }
  80925. }
  80926. }
  80927. if (frameState.mode !== SceneMode.SCENE2D || cameraCentered) {
  80928. // View-projection matrix to transform from world coordinates to clip coordinates
  80929. positionCC = worldToClip(actualPosition, eyeOffset, camera, positionCC);
  80930. if (positionCC.z < 0 && frameState.mode !== SceneMode.SCENE2D) {
  80931. return undefined;
  80932. }
  80933. result = SceneTransforms.clipToGLWindowCoordinates(viewport, positionCC, result);
  80934. }
  80935. result.y = canvas.clientHeight - result.y;
  80936. return result;
  80937. };
  80938. /**
  80939. * Transforms a position in WGS84 coordinates to drawing buffer coordinates. This may produce different
  80940. * results from SceneTransforms.wgs84ToWindowCoordinates when the browser zoom is not 100%, or on high-DPI displays.
  80941. *
  80942. * @param {Scene} scene The scene.
  80943. * @param {Cartesian3} position The position in WGS84 (world) coordinates.
  80944. * @param {Cartesian2} [result] An optional object to return the input position transformed to window coordinates.
  80945. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided. This may be <code>undefined</code> if the input position is near the center of the ellipsoid.
  80946. *
  80947. * @example
  80948. * // Output the window position of longitude/latitude (0, 0) every time the mouse moves.
  80949. * var scene = widget.scene;
  80950. * var ellipsoid = scene.globe.ellipsoid;
  80951. * var position = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  80952. * var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
  80953. * handler.setInputAction(function(movement) {
  80954. * console.log(Cesium.SceneTransforms.wgs84ToWindowCoordinates(scene, position));
  80955. * }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  80956. */
  80957. SceneTransforms.wgs84ToDrawingBufferCoordinates = function(scene, position, result) {
  80958. result = SceneTransforms.wgs84ToWindowCoordinates(scene, position, result);
  80959. if (!defined(result)) {
  80960. return undefined;
  80961. }
  80962. return SceneTransforms.transformWindowToDrawingBuffer(scene, result, result);
  80963. };
  80964. var projectedPosition = new Cartesian3();
  80965. var positionInCartographic = new Cartographic();
  80966. /**
  80967. * @private
  80968. */
  80969. SceneTransforms.computeActualWgs84Position = function(frameState, position, result) {
  80970. var mode = frameState.mode;
  80971. if (mode === SceneMode.SCENE3D) {
  80972. return Cartesian3.clone(position, result);
  80973. }
  80974. var projection = frameState.mapProjection;
  80975. var cartographic = projection.ellipsoid.cartesianToCartographic(position, positionInCartographic);
  80976. if (!defined(cartographic)) {
  80977. return undefined;
  80978. }
  80979. projection.project(cartographic, projectedPosition);
  80980. if (mode === SceneMode.COLUMBUS_VIEW) {
  80981. return Cartesian3.fromElements(projectedPosition.z, projectedPosition.x, projectedPosition.y, result);
  80982. }
  80983. if (mode === SceneMode.SCENE2D) {
  80984. return Cartesian3.fromElements(0.0, projectedPosition.x, projectedPosition.y, result);
  80985. }
  80986. // mode === SceneMode.MORPHING
  80987. var morphTime = frameState.morphTime;
  80988. return Cartesian3.fromElements(
  80989. CesiumMath.lerp(projectedPosition.z, position.x, morphTime),
  80990. CesiumMath.lerp(projectedPosition.x, position.y, morphTime),
  80991. CesiumMath.lerp(projectedPosition.y, position.z, morphTime),
  80992. result);
  80993. };
  80994. var positionNDC = new Cartesian3();
  80995. var positionWC = new Cartesian3();
  80996. var viewportTransform = new Matrix4();
  80997. /**
  80998. * @private
  80999. */
  81000. SceneTransforms.clipToGLWindowCoordinates = function(viewport, position, result) {
  81001. // Perspective divide to transform from clip coordinates to normalized device coordinates
  81002. Cartesian3.divideByScalar(position, position.w, positionNDC);
  81003. // Viewport transform to transform from clip coordinates to window coordinates
  81004. Matrix4.computeViewportTransformation(viewport, 0.0, 1.0, viewportTransform);
  81005. Matrix4.multiplyByPoint(viewportTransform, positionNDC, positionWC);
  81006. return Cartesian2.fromCartesian3(positionWC, result);
  81007. };
  81008. /**
  81009. * @private
  81010. */
  81011. SceneTransforms.clipToDrawingBufferCoordinates = function(viewport, position, result) {
  81012. // Perspective divide to transform from clip coordinates to normalized device coordinates
  81013. Cartesian3.divideByScalar(position, position.w, positionNDC);
  81014. // Viewport transform to transform from clip coordinates to drawing buffer coordinates
  81015. Matrix4.computeViewportTransformation(viewport, 0.0, 1.0, viewportTransform);
  81016. Matrix4.multiplyByPoint(viewportTransform, positionNDC, positionWC);
  81017. return Cartesian2.fromCartesian3(positionWC, result);
  81018. };
  81019. /**
  81020. * @private
  81021. */
  81022. SceneTransforms.transformWindowToDrawingBuffer = function(scene, windowPosition, result) {
  81023. var canvas = scene.canvas;
  81024. var xScale = scene.drawingBufferWidth / canvas.clientWidth;
  81025. var yScale = scene.drawingBufferHeight / canvas.clientHeight;
  81026. return Cartesian2.fromElements(windowPosition.x * xScale, windowPosition.y * yScale, result);
  81027. };
  81028. var scratchNDC = new Cartesian4();
  81029. var scratchWorldCoords = new Cartesian4();
  81030. /**
  81031. * @private
  81032. */
  81033. SceneTransforms.drawingBufferToWgs84Coordinates = function(scene, drawingBufferPosition, depth, result) {
  81034. var context = scene.context;
  81035. var uniformState = context.uniformState;
  81036. var viewport = scene._passState.viewport;
  81037. var ndc = Cartesian4.clone(Cartesian4.UNIT_W, scratchNDC);
  81038. ndc.x = (drawingBufferPosition.x - viewport.x) / viewport.width * 2.0 - 1.0;
  81039. ndc.y = (drawingBufferPosition.y - viewport.y) / viewport.height * 2.0 - 1.0;
  81040. ndc.z = (depth * 2.0) - 1.0;
  81041. ndc.w = 1.0;
  81042. var worldCoords = Matrix4.multiplyByVector(uniformState.inverseViewProjection, ndc, scratchWorldCoords);
  81043. // Reverse perspective divide
  81044. var w = 1.0 / worldCoords.w;
  81045. Cartesian3.multiplyByScalar(worldCoords, w, worldCoords);
  81046. return Cartesian3.fromCartesian4(worldCoords, result);
  81047. };
  81048. return SceneTransforms;
  81049. });
  81050. /*global define*/
  81051. define('Scene/Billboard',[
  81052. '../Core/BoundingRectangle',
  81053. '../Core/Cartesian2',
  81054. '../Core/Cartesian3',
  81055. '../Core/Cartesian4',
  81056. '../Core/Cartographic',
  81057. '../Core/Color',
  81058. '../Core/createGuid',
  81059. '../Core/defaultValue',
  81060. '../Core/defined',
  81061. '../Core/defineProperties',
  81062. '../Core/DeveloperError',
  81063. '../Core/DistanceDisplayCondition',
  81064. '../Core/Matrix4',
  81065. '../Core/NearFarScalar',
  81066. './HeightReference',
  81067. './HorizontalOrigin',
  81068. './SceneMode',
  81069. './SceneTransforms',
  81070. './VerticalOrigin'
  81071. ], function(
  81072. BoundingRectangle,
  81073. Cartesian2,
  81074. Cartesian3,
  81075. Cartesian4,
  81076. Cartographic,
  81077. Color,
  81078. createGuid,
  81079. defaultValue,
  81080. defined,
  81081. defineProperties,
  81082. DeveloperError,
  81083. DistanceDisplayCondition,
  81084. Matrix4,
  81085. NearFarScalar,
  81086. HeightReference,
  81087. HorizontalOrigin,
  81088. SceneMode,
  81089. SceneTransforms,
  81090. VerticalOrigin) {
  81091. 'use strict';
  81092. /**
  81093. * A viewport-aligned image positioned in the 3D scene, that is created
  81094. * and rendered using a {@link BillboardCollection}. A billboard is created and its initial
  81095. * properties are set by calling {@link BillboardCollection#add}.
  81096. * <br /><br />
  81097. * <div align='center'>
  81098. * <img src='images/Billboard.png' width='400' height='300' /><br />
  81099. * Example billboards
  81100. * </div>
  81101. *
  81102. * @alias Billboard
  81103. *
  81104. * @performance Reading a property, e.g., {@link Billboard#show}, is constant time.
  81105. * Assigning to a property is constant time but results in
  81106. * CPU to GPU traffic when {@link BillboardCollection#update} is called. The per-billboard traffic is
  81107. * the same regardless of how many properties were updated. If most billboards in a collection need to be
  81108. * updated, it may be more efficient to clear the collection with {@link BillboardCollection#removeAll}
  81109. * and add new billboards instead of modifying each one.
  81110. *
  81111. * @exception {DeveloperError} scaleByDistance.far must be greater than scaleByDistance.near
  81112. * @exception {DeveloperError} translucencyByDistance.far must be greater than translucencyByDistance.near
  81113. * @exception {DeveloperError} pixelOffsetScaleByDistance.far must be greater than pixelOffsetScaleByDistance.near
  81114. * @exception {DeveloperError} distanceDisplayCondition.far must be greater than distanceDisplayCondition.near
  81115. *
  81116. * @see BillboardCollection
  81117. * @see BillboardCollection#add
  81118. * @see Label
  81119. *
  81120. * @internalConstructor
  81121. *
  81122. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Billboards.html|Cesium Sandcastle Billboard Demo}
  81123. */
  81124. function Billboard(options, billboardCollection) {
  81125. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  81126. if (defined(options.scaleByDistance) && options.scaleByDistance.far <= options.scaleByDistance.near) {
  81127. throw new DeveloperError('scaleByDistance.far must be greater than scaleByDistance.near.');
  81128. }
  81129. if (defined(options.translucencyByDistance) && options.translucencyByDistance.far <= options.translucencyByDistance.near) {
  81130. throw new DeveloperError('translucencyByDistance.far must be greater than translucencyByDistance.near.');
  81131. }
  81132. if (defined(options.pixelOffsetScaleByDistance) && options.pixelOffsetScaleByDistance.far <= options.pixelOffsetScaleByDistance.near) {
  81133. throw new DeveloperError('pixelOffsetScaleByDistance.far must be greater than pixelOffsetScaleByDistance.near.');
  81134. }
  81135. if (defined(options.distanceDisplayCondition) && options.distanceDisplayCondition.far <= options.distanceDisplayCondition.near) {
  81136. throw new DeveloperError('distanceDisplayCondition.far must be greater than distanceDisplayCondition.near');
  81137. }
  81138. this._show = defaultValue(options.show, true);
  81139. this._position = Cartesian3.clone(defaultValue(options.position, Cartesian3.ZERO));
  81140. this._actualPosition = Cartesian3.clone(this._position); // For columbus view and 2D
  81141. this._pixelOffset = Cartesian2.clone(defaultValue(options.pixelOffset, Cartesian2.ZERO));
  81142. this._translate = new Cartesian2(0.0, 0.0); // used by labels for glyph vertex translation
  81143. this._eyeOffset = Cartesian3.clone(defaultValue(options.eyeOffset, Cartesian3.ZERO));
  81144. this._heightReference = defaultValue(options.heightReference, HeightReference.NONE);
  81145. this._verticalOrigin = defaultValue(options.verticalOrigin, VerticalOrigin.CENTER);
  81146. this._horizontalOrigin = defaultValue(options.horizontalOrigin, HorizontalOrigin.CENTER);
  81147. this._scale = defaultValue(options.scale, 1.0);
  81148. this._color = Color.clone(defaultValue(options.color, Color.WHITE));
  81149. this._rotation = defaultValue(options.rotation, 0.0);
  81150. this._alignedAxis = Cartesian3.clone(defaultValue(options.alignedAxis, Cartesian3.ZERO));
  81151. this._width = options.width;
  81152. this._height = options.height;
  81153. this._scaleByDistance = options.scaleByDistance;
  81154. this._translucencyByDistance = options.translucencyByDistance;
  81155. this._pixelOffsetScaleByDistance = options.pixelOffsetScaleByDistance;
  81156. this._sizeInMeters = defaultValue(options.sizeInMeters, false);
  81157. this._distanceDisplayCondition = options.distanceDisplayCondition;
  81158. this._id = options.id;
  81159. this._collection = defaultValue(options.collection, billboardCollection);
  81160. this._pickId = undefined;
  81161. this._pickPrimitive = defaultValue(options._pickPrimitive, this);
  81162. this._billboardCollection = billboardCollection;
  81163. this._dirty = false;
  81164. this._index = -1; //Used only by BillboardCollection
  81165. this._imageIndex = -1;
  81166. this._imageIndexPromise = undefined;
  81167. this._imageId = undefined;
  81168. this._image = undefined;
  81169. this._imageSubRegion = undefined;
  81170. this._imageWidth = undefined;
  81171. this._imageHeight = undefined;
  81172. var image = options.image;
  81173. var imageId = options.imageId;
  81174. if (defined(image)) {
  81175. if (!defined(imageId)) {
  81176. if (typeof image === 'string') {
  81177. imageId = image;
  81178. } else if (defined(image.src)) {
  81179. imageId = image.src;
  81180. } else {
  81181. imageId = createGuid();
  81182. }
  81183. }
  81184. this._imageId = imageId;
  81185. this._image = image;
  81186. }
  81187. if (defined(options.imageSubRegion)) {
  81188. this._imageId = imageId;
  81189. this._imageSubRegion = options.imageSubRegion;
  81190. }
  81191. if (defined(this._billboardCollection._textureAtlas)) {
  81192. this._loadImage();
  81193. }
  81194. this._actualClampedPosition = undefined;
  81195. this._removeCallbackFunc = undefined;
  81196. this._mode = SceneMode.SCENE3D;
  81197. this._clusterShow = true;
  81198. this._updateClamping();
  81199. }
  81200. var SHOW_INDEX = Billboard.SHOW_INDEX = 0;
  81201. var POSITION_INDEX = Billboard.POSITION_INDEX = 1;
  81202. var PIXEL_OFFSET_INDEX = Billboard.PIXEL_OFFSET_INDEX = 2;
  81203. var EYE_OFFSET_INDEX = Billboard.EYE_OFFSET_INDEX = 3;
  81204. var HORIZONTAL_ORIGIN_INDEX = Billboard.HORIZONTAL_ORIGIN_INDEX = 4;
  81205. var VERTICAL_ORIGIN_INDEX = Billboard.VERTICAL_ORIGIN_INDEX = 5;
  81206. var SCALE_INDEX = Billboard.SCALE_INDEX = 6;
  81207. var IMAGE_INDEX_INDEX = Billboard.IMAGE_INDEX_INDEX = 7;
  81208. var COLOR_INDEX = Billboard.COLOR_INDEX = 8;
  81209. var ROTATION_INDEX = Billboard.ROTATION_INDEX = 9;
  81210. var ALIGNED_AXIS_INDEX = Billboard.ALIGNED_AXIS_INDEX = 10;
  81211. var SCALE_BY_DISTANCE_INDEX = Billboard.SCALE_BY_DISTANCE_INDEX = 11;
  81212. var TRANSLUCENCY_BY_DISTANCE_INDEX = Billboard.TRANSLUCENCY_BY_DISTANCE_INDEX = 12;
  81213. var PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX = Billboard.PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX = 13;
  81214. var DISTANCE_DISPLAY_CONDITION = Billboard.DISTANCE_DISPLAY_CONDITION = 14;
  81215. Billboard.NUMBER_OF_PROPERTIES = 15;
  81216. function makeDirty(billboard, propertyChanged) {
  81217. var billboardCollection = billboard._billboardCollection;
  81218. if (defined(billboardCollection)) {
  81219. billboardCollection._updateBillboard(billboard, propertyChanged);
  81220. billboard._dirty = true;
  81221. }
  81222. }
  81223. defineProperties(Billboard.prototype, {
  81224. /**
  81225. * Determines if this billboard will be shown. Use this to hide or show a billboard, instead
  81226. * of removing it and re-adding it to the collection.
  81227. * @memberof Billboard.prototype
  81228. * @type {Boolean}
  81229. * @default true
  81230. */
  81231. show : {
  81232. get : function() {
  81233. return this._show;
  81234. },
  81235. set : function(value) {
  81236. if (!defined(value)) {
  81237. throw new DeveloperError('value is required.');
  81238. }
  81239. if (this._show !== value) {
  81240. this._show = value;
  81241. makeDirty(this, SHOW_INDEX);
  81242. }
  81243. }
  81244. },
  81245. /**
  81246. * Gets or sets the Cartesian position of this billboard.
  81247. * @memberof Billboard.prototype
  81248. * @type {Cartesian3}
  81249. */
  81250. position : {
  81251. get : function() {
  81252. return this._position;
  81253. },
  81254. set : function(value) {
  81255. if (!defined(value)) {
  81256. throw new DeveloperError('value is required.');
  81257. }
  81258. var position = this._position;
  81259. if (!Cartesian3.equals(position, value)) {
  81260. Cartesian3.clone(value, position);
  81261. Cartesian3.clone(value, this._actualPosition);
  81262. this._updateClamping();
  81263. makeDirty(this, POSITION_INDEX);
  81264. }
  81265. }
  81266. },
  81267. /**
  81268. * Gets or sets the height reference of this billboard.
  81269. * @memberof Billboard.prototype
  81270. * @type {HeightReference}
  81271. * @default HeightReference.NONE
  81272. */
  81273. heightReference : {
  81274. get : function() {
  81275. return this._heightReference;
  81276. },
  81277. set : function(value) {
  81278. if (!defined(value)) {
  81279. throw new DeveloperError('value is required.');
  81280. }
  81281. var heightReference = this._heightReference;
  81282. if (value !== heightReference) {
  81283. this._heightReference = value;
  81284. this._updateClamping();
  81285. makeDirty(this, POSITION_INDEX);
  81286. }
  81287. }
  81288. },
  81289. /**
  81290. * Gets or sets the pixel offset in screen space from the origin of this billboard. This is commonly used
  81291. * to align multiple billboards and labels at the same position, e.g., an image and text. The
  81292. * screen space origin is the top, left corner of the canvas; <code>x</code> increases from
  81293. * left to right, and <code>y</code> increases from top to bottom.
  81294. * <br /><br />
  81295. * <div align='center'>
  81296. * <table border='0' cellpadding='5'><tr>
  81297. * <td align='center'><code>default</code><br/><img src='images/Billboard.setPixelOffset.default.png' width='250' height='188' /></td>
  81298. * <td align='center'><code>b.pixeloffset = new Cartesian2(50, 25);</code><br/><img src='images/Billboard.setPixelOffset.x50y-25.png' width='250' height='188' /></td>
  81299. * </tr></table>
  81300. * The billboard's origin is indicated by the yellow point.
  81301. * </div>
  81302. * @memberof Billboard.prototype
  81303. * @type {Cartesian2}
  81304. */
  81305. pixelOffset : {
  81306. get : function() {
  81307. return this._pixelOffset;
  81308. },
  81309. set : function(value) {
  81310. if (!defined(value)) {
  81311. throw new DeveloperError('value is required.');
  81312. }
  81313. var pixelOffset = this._pixelOffset;
  81314. if (!Cartesian2.equals(pixelOffset, value)) {
  81315. Cartesian2.clone(value, pixelOffset);
  81316. makeDirty(this, PIXEL_OFFSET_INDEX);
  81317. }
  81318. }
  81319. },
  81320. /**
  81321. * Gets or sets near and far scaling properties of a Billboard based on the billboard's distance from the camera.
  81322. * A billboard's scale will interpolate between the {@link NearFarScalar#nearValue} and
  81323. * {@link NearFarScalar#farValue} while the camera distance falls within the upper and lower bounds
  81324. * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
  81325. * Outside of these ranges the billboard's scale remains clamped to the nearest bound. If undefined,
  81326. * scaleByDistance will be disabled.
  81327. * @memberof Billboard.prototype
  81328. * @type {NearFarScalar}
  81329. *
  81330. * @example
  81331. * // Example 1.
  81332. * // Set a billboard's scaleByDistance to scale by 1.5 when the
  81333. * // camera is 1500 meters from the billboard and disappear as
  81334. * // the camera distance approaches 8.0e6 meters.
  81335. * b.scaleByDistance = new Cesium.NearFarScalar(1.5e2, 1.5, 8.0e6, 0.0);
  81336. *
  81337. * @example
  81338. * // Example 2.
  81339. * // disable scaling by distance
  81340. * b.scaleByDistance = undefined;
  81341. */
  81342. scaleByDistance : {
  81343. get : function() {
  81344. return this._scaleByDistance;
  81345. },
  81346. set : function(value) {
  81347. if (defined(value) && value.far <= value.near) {
  81348. throw new DeveloperError('far distance must be greater than near distance.');
  81349. }
  81350. var scaleByDistance = this._scaleByDistance;
  81351. if (!NearFarScalar.equals(scaleByDistance, value)) {
  81352. this._scaleByDistance = NearFarScalar.clone(value, scaleByDistance);
  81353. makeDirty(this, SCALE_BY_DISTANCE_INDEX);
  81354. }
  81355. }
  81356. },
  81357. /**
  81358. * Gets or sets near and far translucency properties of a Billboard based on the billboard's distance from the camera.
  81359. * A billboard's translucency will interpolate between the {@link NearFarScalar#nearValue} and
  81360. * {@link NearFarScalar#farValue} while the camera distance falls within the upper and lower bounds
  81361. * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
  81362. * Outside of these ranges the billboard's translucency remains clamped to the nearest bound. If undefined,
  81363. * translucencyByDistance will be disabled.
  81364. * @memberof Billboard.prototype
  81365. * @type {NearFarScalar}
  81366. *
  81367. * @example
  81368. * // Example 1.
  81369. * // Set a billboard's translucency to 1.0 when the
  81370. * // camera is 1500 meters from the billboard and disappear as
  81371. * // the camera distance approaches 8.0e6 meters.
  81372. * b.translucencyByDistance = new Cesium.NearFarScalar(1.5e2, 1.0, 8.0e6, 0.0);
  81373. *
  81374. * @example
  81375. * // Example 2.
  81376. * // disable translucency by distance
  81377. * b.translucencyByDistance = undefined;
  81378. */
  81379. translucencyByDistance : {
  81380. get : function() {
  81381. return this._translucencyByDistance;
  81382. },
  81383. set : function(value) {
  81384. if (defined(value) && value.far <= value.near) {
  81385. throw new DeveloperError('far distance must be greater than near distance.');
  81386. }
  81387. var translucencyByDistance = this._translucencyByDistance;
  81388. if (!NearFarScalar.equals(translucencyByDistance, value)) {
  81389. this._translucencyByDistance = NearFarScalar.clone(value, translucencyByDistance);
  81390. makeDirty(this, TRANSLUCENCY_BY_DISTANCE_INDEX);
  81391. }
  81392. }
  81393. },
  81394. /**
  81395. * Gets or sets near and far pixel offset scaling properties of a Billboard based on the billboard's distance from the camera.
  81396. * A billboard's pixel offset will be scaled between the {@link NearFarScalar#nearValue} and
  81397. * {@link NearFarScalar#farValue} while the camera distance falls within the upper and lower bounds
  81398. * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
  81399. * Outside of these ranges the billboard's pixel offset scale remains clamped to the nearest bound. If undefined,
  81400. * pixelOffsetScaleByDistance will be disabled.
  81401. * @memberof Billboard.prototype
  81402. * @type {NearFarScalar}
  81403. *
  81404. * @example
  81405. * // Example 1.
  81406. * // Set a billboard's pixel offset scale to 0.0 when the
  81407. * // camera is 1500 meters from the billboard and scale pixel offset to 10.0 pixels
  81408. * // in the y direction the camera distance approaches 8.0e6 meters.
  81409. * b.pixelOffset = new Cesium.Cartesian2(0.0, 1.0);
  81410. * b.pixelOffsetScaleByDistance = new Cesium.NearFarScalar(1.5e2, 0.0, 8.0e6, 10.0);
  81411. *
  81412. * @example
  81413. * // Example 2.
  81414. * // disable pixel offset by distance
  81415. * b.pixelOffsetScaleByDistance = undefined;
  81416. */
  81417. pixelOffsetScaleByDistance : {
  81418. get : function() {
  81419. return this._pixelOffsetScaleByDistance;
  81420. },
  81421. set : function(value) {
  81422. if (defined(value) && value.far <= value.near) {
  81423. throw new DeveloperError('far distance must be greater than near distance.');
  81424. }
  81425. var pixelOffsetScaleByDistance = this._pixelOffsetScaleByDistance;
  81426. if (!NearFarScalar.equals(pixelOffsetScaleByDistance, value)) {
  81427. this._pixelOffsetScaleByDistance = NearFarScalar.clone(value, pixelOffsetScaleByDistance);
  81428. makeDirty(this, PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX);
  81429. }
  81430. }
  81431. },
  81432. /**
  81433. * Gets or sets the 3D Cartesian offset applied to this billboard in eye coordinates. Eye coordinates is a left-handed
  81434. * coordinate system, where <code>x</code> points towards the viewer's right, <code>y</code> points up, and
  81435. * <code>z</code> points into the screen. Eye coordinates use the same scale as world and model coordinates,
  81436. * which is typically meters.
  81437. * <br /><br />
  81438. * An eye offset is commonly used to arrange multiple billboards or objects at the same position, e.g., to
  81439. * arrange a billboard above its corresponding 3D model.
  81440. * <br /><br />
  81441. * Below, the billboard is positioned at the center of the Earth but an eye offset makes it always
  81442. * appear on top of the Earth regardless of the viewer's or Earth's orientation.
  81443. * <br /><br />
  81444. * <div align='center'>
  81445. * <table border='0' cellpadding='5'><tr>
  81446. * <td align='center'><img src='images/Billboard.setEyeOffset.one.png' width='250' height='188' /></td>
  81447. * <td align='center'><img src='images/Billboard.setEyeOffset.two.png' width='250' height='188' /></td>
  81448. * </tr></table>
  81449. * <code>b.eyeOffset = new Cartesian3(0.0, 8000000.0, 0.0);</code><br /><br />
  81450. * </div>
  81451. * @memberof Billboard.prototype
  81452. * @type {Cartesian3}
  81453. */
  81454. eyeOffset : {
  81455. get : function() {
  81456. return this._eyeOffset;
  81457. },
  81458. set : function(value) {
  81459. if (!defined(value)) {
  81460. throw new DeveloperError('value is required.');
  81461. }
  81462. var eyeOffset = this._eyeOffset;
  81463. if (!Cartesian3.equals(eyeOffset, value)) {
  81464. Cartesian3.clone(value, eyeOffset);
  81465. makeDirty(this, EYE_OFFSET_INDEX);
  81466. }
  81467. }
  81468. },
  81469. /**
  81470. * Gets or sets the horizontal origin of this billboard, which determines if the billboard is
  81471. * to the left, center, or right of its anchor position.
  81472. * <br /><br />
  81473. * <div align='center'>
  81474. * <img src='images/Billboard.setHorizontalOrigin.png' width='648' height='196' /><br />
  81475. * </div>
  81476. * @memberof Billboard.prototype
  81477. * @type {HorizontalOrigin}
  81478. * @example
  81479. * // Use a bottom, left origin
  81480. * b.horizontalOrigin = Cesium.HorizontalOrigin.LEFT;
  81481. * b.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
  81482. */
  81483. horizontalOrigin : {
  81484. get : function() {
  81485. return this._horizontalOrigin;
  81486. },
  81487. set : function(value) {
  81488. if (!defined(value)) {
  81489. throw new DeveloperError('value is required.');
  81490. }
  81491. if (this._horizontalOrigin !== value) {
  81492. this._horizontalOrigin = value;
  81493. makeDirty(this, HORIZONTAL_ORIGIN_INDEX);
  81494. }
  81495. }
  81496. },
  81497. /**
  81498. * Gets or sets the vertical origin of this billboard, which determines if the billboard is
  81499. * to the above, below, or at the center of its anchor position.
  81500. * <br /><br />
  81501. * <div align='center'>
  81502. * <img src='images/Billboard.setVerticalOrigin.png' width='695' height='175' /><br />
  81503. * </div>
  81504. * @memberof Billboard.prototype
  81505. * @type {VerticalOrigin}
  81506. * @example
  81507. * // Use a bottom, left origin
  81508. * b.horizontalOrigin = Cesium.HorizontalOrigin.LEFT;
  81509. * b.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
  81510. */
  81511. verticalOrigin : {
  81512. get : function() {
  81513. return this._verticalOrigin;
  81514. },
  81515. set : function(value) {
  81516. if (!defined(value)) {
  81517. throw new DeveloperError('value is required.');
  81518. }
  81519. if (this._verticalOrigin !== value) {
  81520. this._verticalOrigin = value;
  81521. makeDirty(this, VERTICAL_ORIGIN_INDEX);
  81522. }
  81523. }
  81524. },
  81525. /**
  81526. * Gets or sets the uniform scale that is multiplied with the billboard's image size in pixels.
  81527. * A scale of <code>1.0</code> does not change the size of the billboard; a scale greater than
  81528. * <code>1.0</code> enlarges the billboard; a positive scale less than <code>1.0</code> shrinks
  81529. * the billboard.
  81530. * <br /><br />
  81531. * <div align='center'>
  81532. * <img src='images/Billboard.setScale.png' width='400' height='300' /><br/>
  81533. * From left to right in the above image, the scales are <code>0.5</code>, <code>1.0</code>,
  81534. * and <code>2.0</code>.
  81535. * </div>
  81536. * @memberof Billboard.prototype
  81537. * @type {Number}
  81538. */
  81539. scale : {
  81540. get : function() {
  81541. return this._scale;
  81542. },
  81543. set : function(value) {
  81544. if (!defined(value)) {
  81545. throw new DeveloperError('value is required.');
  81546. }
  81547. if (this._scale !== value) {
  81548. this._scale = value;
  81549. makeDirty(this, SCALE_INDEX);
  81550. }
  81551. }
  81552. },
  81553. /**
  81554. * Gets or sets the color that is multiplied with the billboard's texture. This has two common use cases. First,
  81555. * the same white texture may be used by many different billboards, each with a different color, to create
  81556. * colored billboards. Second, the color's alpha component can be used to make the billboard translucent as shown below.
  81557. * An alpha of <code>0.0</code> makes the billboard transparent, and <code>1.0</code> makes the billboard opaque.
  81558. * <br /><br />
  81559. * <div align='center'>
  81560. * <table border='0' cellpadding='5'><tr>
  81561. * <td align='center'><code>default</code><br/><img src='images/Billboard.setColor.Alpha255.png' width='250' height='188' /></td>
  81562. * <td align='center'><code>alpha : 0.5</code><br/><img src='images/Billboard.setColor.Alpha127.png' width='250' height='188' /></td>
  81563. * </tr></table>
  81564. * </div>
  81565. * <br />
  81566. * The red, green, blue, and alpha values are indicated by <code>value</code>'s <code>red</code>, <code>green</code>,
  81567. * <code>blue</code>, and <code>alpha</code> properties as shown in Example 1. These components range from <code>0.0</code>
  81568. * (no intensity) to <code>1.0</code> (full intensity).
  81569. * @memberof Billboard.prototype
  81570. * @type {Color}
  81571. *
  81572. * @example
  81573. * // Example 1. Assign yellow.
  81574. * b.color = Cesium.Color.YELLOW;
  81575. *
  81576. * @example
  81577. * // Example 2. Make a billboard 50% translucent.
  81578. * b.color = new Cesium.Color(1.0, 1.0, 1.0, 0.5);
  81579. */
  81580. color : {
  81581. get : function() {
  81582. return this._color;
  81583. },
  81584. set : function(value) {
  81585. if (!defined(value)) {
  81586. throw new DeveloperError('value is required.');
  81587. }
  81588. var color = this._color;
  81589. if (!Color.equals(color, value)) {
  81590. Color.clone(value, color);
  81591. makeDirty(this, COLOR_INDEX);
  81592. }
  81593. }
  81594. },
  81595. /**
  81596. * Gets or sets the rotation angle in radians.
  81597. * @memberof Billboard.prototype
  81598. * @type {Number}
  81599. */
  81600. rotation : {
  81601. get : function() {
  81602. return this._rotation;
  81603. },
  81604. set : function(value) {
  81605. if (!defined(value)) {
  81606. throw new DeveloperError('value is required.');
  81607. }
  81608. if (this._rotation !== value) {
  81609. this._rotation = value;
  81610. makeDirty(this, ROTATION_INDEX);
  81611. }
  81612. }
  81613. },
  81614. /**
  81615. * Gets or sets the aligned axis in world space. The aligned axis is the unit vector that the billboard up vector points towards.
  81616. * The default is the zero vector, which means the billboard is aligned to the screen up vector.
  81617. * @memberof Billboard.prototype
  81618. * @type {Cartesian3}
  81619. * @example
  81620. * // Example 1.
  81621. * // Have the billboard up vector point north
  81622. * billboard.alignedAxis = Cesium.Cartesian3.UNIT_Z;
  81623. *
  81624. * @example
  81625. * // Example 2.
  81626. * // Have the billboard point east.
  81627. * billboard.alignedAxis = Cesium.Cartesian3.UNIT_Z;
  81628. * billboard.rotation = -Cesium.Math.PI_OVER_TWO;
  81629. *
  81630. * @example
  81631. * // Example 3.
  81632. * // Reset the aligned axis
  81633. * billboard.alignedAxis = Cesium.Cartesian3.ZERO;
  81634. */
  81635. alignedAxis : {
  81636. get : function() {
  81637. return this._alignedAxis;
  81638. },
  81639. set : function(value) {
  81640. if (!defined(value)) {
  81641. throw new DeveloperError('value is required.');
  81642. }
  81643. var alignedAxis = this._alignedAxis;
  81644. if (!Cartesian3.equals(alignedAxis, value)) {
  81645. Cartesian3.clone(value, alignedAxis);
  81646. makeDirty(this, ALIGNED_AXIS_INDEX);
  81647. }
  81648. }
  81649. },
  81650. /**
  81651. * Gets or sets a width for the billboard. If undefined, the image width will be used.
  81652. * @memberof Billboard.prototype
  81653. * @type {Number}
  81654. */
  81655. width : {
  81656. get : function() {
  81657. return defaultValue(this._width, this._imageWidth);
  81658. },
  81659. set : function(value) {
  81660. if (this._width !== value) {
  81661. this._width = value;
  81662. makeDirty(this, IMAGE_INDEX_INDEX);
  81663. }
  81664. }
  81665. },
  81666. /**
  81667. * Gets or sets a height for the billboard. If undefined, the image height will be used.
  81668. * @memberof Billboard.prototype
  81669. * @type {Number}
  81670. */
  81671. height : {
  81672. get : function() {
  81673. return defaultValue(this._height, this._imageHeight);
  81674. },
  81675. set : function(value) {
  81676. if (this._height !== value) {
  81677. this._height = value;
  81678. makeDirty(this, IMAGE_INDEX_INDEX);
  81679. }
  81680. }
  81681. },
  81682. /**
  81683. * Gets or sets if the billboard size is in meters or pixels. <code>true</code> to size the billboard in meters;
  81684. * otherwise, the size is in pixels.
  81685. * @memberof Billboard.prototype
  81686. * @type {Boolean}
  81687. * @default false
  81688. */
  81689. sizeInMeters : {
  81690. get : function() {
  81691. return this._sizeInMeters;
  81692. },
  81693. set : function(value) {
  81694. if (this._sizeInMeters !== value) {
  81695. this._sizeInMeters = value;
  81696. makeDirty(this, COLOR_INDEX);
  81697. }
  81698. }
  81699. },
  81700. /**
  81701. * Gets or sets the condition specifying at what distance from the camera that this billboard will be displayed.
  81702. * @memberof Billboard.prototype
  81703. * @type {DistanceDisplayCondition}
  81704. * @default undefined
  81705. */
  81706. distanceDisplayCondition : {
  81707. get : function() {
  81708. return this._distanceDisplayCondition;
  81709. },
  81710. set : function(value) {
  81711. if (!DistanceDisplayCondition.equals(value, this._distanceDisplayCondition)) {
  81712. if (defined(value) && value.far <= value.near) {
  81713. throw new DeveloperError('far distance must be greater than near distance.');
  81714. }
  81715. this._distanceDisplayCondition = DistanceDisplayCondition.clone(value, this._distanceDisplayCondition);
  81716. makeDirty(this, DISTANCE_DISPLAY_CONDITION);
  81717. }
  81718. }
  81719. },
  81720. /**
  81721. * Gets or sets the user-defined object returned when the billboard is picked.
  81722. * @memberof Billboard.prototype
  81723. * @type {Object}
  81724. */
  81725. id : {
  81726. get : function() {
  81727. return this._id;
  81728. },
  81729. set : function(value) {
  81730. this._id = value;
  81731. if (defined(this._pickId)) {
  81732. this._pickId.object.id = value;
  81733. }
  81734. }
  81735. },
  81736. /**
  81737. * The primitive to return when picking this billboard.
  81738. * @memberof Billboard.prototype
  81739. * @private
  81740. */
  81741. pickPrimitive : {
  81742. get : function() {
  81743. return this._pickPrimitive;
  81744. },
  81745. set : function(value) {
  81746. this._pickPrimitive = value;
  81747. if (defined(this._pickId)) {
  81748. this._pickId.object.primitive = value;
  81749. }
  81750. }
  81751. },
  81752. /**
  81753. * <p>
  81754. * Gets or sets the image to be used for this billboard. If a texture has already been created for the
  81755. * given image, the existing texture is used.
  81756. * </p>
  81757. * <p>
  81758. * This property can be set to a loaded Image, a URL which will be loaded as an Image automatically,
  81759. * a canvas, or another billboard's image property (from the same billboard collection).
  81760. * </p>
  81761. *
  81762. * @memberof Billboard.prototype
  81763. * @type {String}
  81764. * @example
  81765. * // load an image from a URL
  81766. * b.image = 'some/image/url.png';
  81767. *
  81768. * // assuming b1 and b2 are billboards in the same billboard collection,
  81769. * // use the same image for both billboards.
  81770. * b2.image = b1.image;
  81771. */
  81772. image : {
  81773. get : function() {
  81774. return this._imageId;
  81775. },
  81776. set : function(value) {
  81777. if (!defined(value)) {
  81778. this._imageIndex = -1;
  81779. this._imageSubRegion = undefined;
  81780. this._imageId = undefined;
  81781. this._image = undefined;
  81782. this._imageIndexPromise = undefined;
  81783. makeDirty(this, IMAGE_INDEX_INDEX);
  81784. } else if (typeof value === 'string') {
  81785. this.setImage(value, value);
  81786. } else if (defined(value.src)) {
  81787. this.setImage(value.src, value);
  81788. } else {
  81789. this.setImage(createGuid(), value);
  81790. }
  81791. }
  81792. },
  81793. /**
  81794. * When <code>true</code>, this billboard is ready to render, i.e., the image
  81795. * has been downloaded and the WebGL resources are created.
  81796. *
  81797. * @memberof Billboard.prototype
  81798. *
  81799. * @type {Boolean}
  81800. * @readonly
  81801. *
  81802. * @default false
  81803. */
  81804. ready : {
  81805. get : function() {
  81806. return this._imageIndex !== -1;
  81807. }
  81808. },
  81809. /**
  81810. * Keeps track of the position of the billboard based on the height reference.
  81811. * @memberof Billboard.prototype
  81812. * @type {Cartesian3}
  81813. * @private
  81814. */
  81815. _clampedPosition : {
  81816. get : function() {
  81817. return this._actualClampedPosition;
  81818. },
  81819. set : function(value) {
  81820. this._actualClampedPosition = Cartesian3.clone(value, this._actualClampedPosition);
  81821. makeDirty(this, POSITION_INDEX);
  81822. }
  81823. },
  81824. /**
  81825. * Determines whether or not this billboard will be shown or hidden because it was clustered.
  81826. * @memberof Billboard.prototype
  81827. * @type {Boolean}
  81828. * @private
  81829. */
  81830. clusterShow : {
  81831. get : function() {
  81832. return this._clusterShow;
  81833. },
  81834. set : function(value) {
  81835. if (this._clusterShow !== value) {
  81836. this._clusterShow = value;
  81837. makeDirty(this, SHOW_INDEX);
  81838. }
  81839. }
  81840. }
  81841. });
  81842. Billboard.prototype.getPickId = function(context) {
  81843. if (!defined(this._pickId)) {
  81844. this._pickId = context.createPickId({
  81845. primitive : this._pickPrimitive,
  81846. collection : this._collection,
  81847. id : this._id
  81848. });
  81849. }
  81850. return this._pickId;
  81851. };
  81852. Billboard.prototype._updateClamping = function() {
  81853. Billboard._updateClamping(this._billboardCollection, this);
  81854. };
  81855. var scratchCartographic = new Cartographic();
  81856. var scratchPosition = new Cartesian3();
  81857. Billboard._updateClamping = function(collection, owner) {
  81858. var scene = collection._scene;
  81859. if (!defined(scene)) {
  81860. if (owner._heightReference !== HeightReference.NONE) {
  81861. throw new DeveloperError('Height reference is not supported without a scene.');
  81862. }
  81863. return;
  81864. }
  81865. var globe = scene.globe;
  81866. var ellipsoid = globe.ellipsoid;
  81867. var surface = globe._surface;
  81868. var mode = scene.frameState.mode;
  81869. var modeChanged = mode !== owner._mode;
  81870. owner._mode = mode;
  81871. if ((owner._heightReference === HeightReference.NONE || modeChanged) && defined(owner._removeCallbackFunc)) {
  81872. owner._removeCallbackFunc();
  81873. owner._removeCallbackFunc = undefined;
  81874. owner._clampedPosition = undefined;
  81875. }
  81876. if (owner._heightReference === HeightReference.NONE || !defined(owner._position)) {
  81877. return;
  81878. }
  81879. var position = ellipsoid.cartesianToCartographic(owner._position);
  81880. if (!defined(position)) {
  81881. return;
  81882. }
  81883. if (defined(owner._removeCallbackFunc)) {
  81884. owner._removeCallbackFunc();
  81885. }
  81886. function updateFunction(clampedPosition) {
  81887. if (owner._heightReference === HeightReference.RELATIVE_TO_GROUND) {
  81888. if (owner._mode === SceneMode.SCENE3D) {
  81889. var clampedCart = ellipsoid.cartesianToCartographic(clampedPosition, scratchCartographic);
  81890. clampedCart.height += position.height;
  81891. ellipsoid.cartographicToCartesian(clampedCart, clampedPosition);
  81892. } else {
  81893. clampedPosition.x += position.height;
  81894. }
  81895. }
  81896. owner._clampedPosition = Cartesian3.clone(clampedPosition, owner._clampedPosition);
  81897. }
  81898. owner._removeCallbackFunc = surface.updateHeight(position, updateFunction);
  81899. Cartographic.clone(position, scratchCartographic);
  81900. var height = globe.getHeight(position);
  81901. if (defined(height)) {
  81902. scratchCartographic.height = height;
  81903. }
  81904. ellipsoid.cartographicToCartesian(scratchCartographic, scratchPosition);
  81905. updateFunction(scratchPosition);
  81906. };
  81907. Billboard.prototype._loadImage = function() {
  81908. var atlas = this._billboardCollection._textureAtlas;
  81909. var imageId = this._imageId;
  81910. var image = this._image;
  81911. var imageSubRegion = this._imageSubRegion;
  81912. var imageIndexPromise;
  81913. if (defined(image)) {
  81914. imageIndexPromise = atlas.addImage(imageId, image);
  81915. }
  81916. if (defined(imageSubRegion)) {
  81917. imageIndexPromise = atlas.addSubRegion(imageId, imageSubRegion);
  81918. }
  81919. this._imageIndexPromise = imageIndexPromise;
  81920. if (!defined(imageIndexPromise)) {
  81921. return;
  81922. }
  81923. var that = this;
  81924. imageIndexPromise.then(function(index) {
  81925. if (that._imageId !== imageId || that._image !== image || !BoundingRectangle.equals(that._imageSubRegion, imageSubRegion)) {
  81926. // another load occurred before this one finished, ignore the index
  81927. return;
  81928. }
  81929. // fill in imageWidth and imageHeight
  81930. var textureCoordinates = atlas.textureCoordinates[index];
  81931. that._imageWidth = atlas.texture.width * textureCoordinates.width;
  81932. that._imageHeight = atlas.texture.height * textureCoordinates.height;
  81933. that._imageIndex = index;
  81934. that._ready = true;
  81935. that._image = undefined;
  81936. that._imageIndexPromise = undefined;
  81937. makeDirty(that, IMAGE_INDEX_INDEX);
  81938. }).otherwise(function(error) {
  81939. console.error('Error loading image for billboard: ' + error);
  81940. that._imageIndexPromise = undefined;
  81941. });
  81942. };
  81943. /**
  81944. * <p>
  81945. * Sets the image to be used for this billboard. If a texture has already been created for the
  81946. * given id, the existing texture is used.
  81947. * </p>
  81948. * <p>
  81949. * This function is useful for dynamically creating textures that are shared across many billboards.
  81950. * Only the first billboard will actually call the function and create the texture, while subsequent
  81951. * billboards created with the same id will simply re-use the existing texture.
  81952. * </p>
  81953. * <p>
  81954. * To load an image from a URL, setting the {@link Billboard#image} property is more convenient.
  81955. * </p>
  81956. *
  81957. * @param {String} id The id of the image. This can be any string that uniquely identifies the image.
  81958. * @param {Image|Canvas|String|Billboard~CreateImageCallback} image The image to load. This parameter
  81959. * can either be a loaded Image or Canvas, a URL which will be loaded as an Image automatically,
  81960. * or a function which will be called to create the image if it hasn't been loaded already.
  81961. * @example
  81962. * // create a billboard image dynamically
  81963. * function drawImage(id) {
  81964. * // create and draw an image using a canvas
  81965. * var canvas = document.createElement('canvas');
  81966. * var context2D = canvas.getContext('2d');
  81967. * // ... draw image
  81968. * return canvas;
  81969. * }
  81970. * // drawImage will be called to create the texture
  81971. * b.setImage('myImage', drawImage);
  81972. *
  81973. * // subsequent billboards created in the same collection using the same id will use the existing
  81974. * // texture, without the need to create the canvas or draw the image
  81975. * b2.setImage('myImage', drawImage);
  81976. */
  81977. Billboard.prototype.setImage = function(id, image) {
  81978. if (!defined(id)) {
  81979. throw new DeveloperError('id is required.');
  81980. }
  81981. if (!defined(image)) {
  81982. throw new DeveloperError('image is required.');
  81983. }
  81984. if (this._imageId === id) {
  81985. return;
  81986. }
  81987. this._imageIndex = -1;
  81988. this._imageSubRegion = undefined;
  81989. this._imageId = id;
  81990. this._image = image;
  81991. if (defined(this._billboardCollection._textureAtlas)) {
  81992. this._loadImage();
  81993. }
  81994. };
  81995. /**
  81996. * Uses a sub-region of the image with the given id as the image for this billboard,
  81997. * measured in pixels from the bottom-left.
  81998. *
  81999. * @param {String} id The id of the image to use.
  82000. * @param {BoundingRectangle} subRegion The sub-region of the image.
  82001. *
  82002. * @exception {RuntimeError} image with id must be in the atlas
  82003. */
  82004. Billboard.prototype.setImageSubRegion = function(id, subRegion) {
  82005. if (!defined(id)) {
  82006. throw new DeveloperError('id is required.');
  82007. }
  82008. if (!defined(subRegion)) {
  82009. throw new DeveloperError('subRegion is required.');
  82010. }
  82011. if (this._imageId === id && BoundingRectangle.equals(this._imageSubRegion, subRegion)) {
  82012. return;
  82013. }
  82014. this._imageIndex = -1;
  82015. this._imageId = id;
  82016. this._imageSubRegion = BoundingRectangle.clone(subRegion);
  82017. if (defined(this._billboardCollection._textureAtlas)) {
  82018. this._loadImage();
  82019. }
  82020. };
  82021. Billboard.prototype._setTranslate = function(value) {
  82022. if (!defined(value)) {
  82023. throw new DeveloperError('value is required.');
  82024. }
  82025. var translate = this._translate;
  82026. if (!Cartesian2.equals(translate, value)) {
  82027. Cartesian2.clone(value, translate);
  82028. makeDirty(this, PIXEL_OFFSET_INDEX);
  82029. }
  82030. };
  82031. Billboard.prototype._getActualPosition = function() {
  82032. return defined(this._clampedPosition) ? this._clampedPosition : this._actualPosition;
  82033. };
  82034. Billboard.prototype._setActualPosition = function(value) {
  82035. if (!(defined(this._clampedPosition))) {
  82036. Cartesian3.clone(value, this._actualPosition);
  82037. }
  82038. makeDirty(this, POSITION_INDEX);
  82039. };
  82040. var tempCartesian3 = new Cartesian4();
  82041. Billboard._computeActualPosition = function(billboard, position, frameState, modelMatrix) {
  82042. if (defined(billboard._clampedPosition)) {
  82043. if (frameState.mode !== billboard._mode) {
  82044. billboard._updateClamping();
  82045. }
  82046. return billboard._clampedPosition;
  82047. } else if (frameState.mode === SceneMode.SCENE3D) {
  82048. return position;
  82049. }
  82050. Matrix4.multiplyByPoint(modelMatrix, position, tempCartesian3);
  82051. return SceneTransforms.computeActualWgs84Position(frameState, tempCartesian3);
  82052. };
  82053. var scratchCartesian3 = new Cartesian3();
  82054. // This function is basically a stripped-down JavaScript version of BillboardCollectionVS.glsl
  82055. Billboard._computeScreenSpacePosition = function(modelMatrix, position, eyeOffset, pixelOffset, scene, result) {
  82056. // Model to world coordinates
  82057. var positionWorld = Matrix4.multiplyByPoint(modelMatrix, position, scratchCartesian3);
  82058. // World to window coordinates
  82059. var positionWC = SceneTransforms.wgs84WithEyeOffsetToWindowCoordinates(scene, positionWorld, eyeOffset, result);
  82060. if (!defined(positionWC)) {
  82061. return undefined;
  82062. }
  82063. // Apply pixel offset
  82064. Cartesian2.add(positionWC, pixelOffset, positionWC);
  82065. return positionWC;
  82066. };
  82067. var scratchPixelOffset = new Cartesian2(0.0, 0.0);
  82068. /**
  82069. * Computes the screen-space position of the billboard's origin, taking into account eye and pixel offsets.
  82070. * The screen space origin is the top, left corner of the canvas; <code>x</code> increases from
  82071. * left to right, and <code>y</code> increases from top to bottom.
  82072. *
  82073. * @param {Scene} scene The scene.
  82074. * @param {Cartesian2} [result] The object onto which to store the result.
  82075. * @returns {Cartesian2} The screen-space position of the billboard.
  82076. *
  82077. * @exception {DeveloperError} Billboard must be in a collection.
  82078. *
  82079. * @example
  82080. * console.log(b.computeScreenSpacePosition(scene).toString());
  82081. *
  82082. * @see Billboard#eyeOffset
  82083. * @see Billboard#pixelOffset
  82084. */
  82085. Billboard.prototype.computeScreenSpacePosition = function(scene, result) {
  82086. var billboardCollection = this._billboardCollection;
  82087. if (!defined(result)) {
  82088. result = new Cartesian2();
  82089. }
  82090. if (!defined(billboardCollection)) {
  82091. throw new DeveloperError('Billboard must be in a collection. Was it removed?');
  82092. }
  82093. if (!defined(scene)) {
  82094. throw new DeveloperError('scene is required.');
  82095. }
  82096. // pixel offset for screenspace computation is the pixelOffset + screenspace translate
  82097. Cartesian2.clone(this._pixelOffset, scratchPixelOffset);
  82098. Cartesian2.add(scratchPixelOffset, this._translate, scratchPixelOffset);
  82099. var modelMatrix = billboardCollection.modelMatrix;
  82100. var actualPosition = this._getActualPosition();
  82101. var windowCoordinates = Billboard._computeScreenSpacePosition(modelMatrix, actualPosition,
  82102. this._eyeOffset, scratchPixelOffset, scene, result);
  82103. return windowCoordinates;
  82104. };
  82105. /**
  82106. * Gets a billboard's screen space bounding box centered around screenSpacePosition.
  82107. * @param {Billboard} billboard The billboard to get the screen space bounding box for.
  82108. * @param {Cartesian2} screenSpacePosition The screen space center of the label.
  82109. * @param {BoundingRectangle} [result] The object onto which to store the result.
  82110. * @returns {BoundingRectangle} The screen space bounding box.
  82111. *
  82112. * @private
  82113. */
  82114. Billboard.getScreenSpaceBoundingBox = function(billboard, screenSpacePosition, result) {
  82115. var width = billboard.width;
  82116. var height = billboard.height;
  82117. var scale = billboard.scale;
  82118. width *= scale;
  82119. height *= scale;
  82120. var x = screenSpacePosition.x;
  82121. if (billboard.horizontalOrigin === HorizontalOrigin.RIGHT) {
  82122. x -= width;
  82123. } else if (billboard.horizontalOrigin === HorizontalOrigin.CENTER) {
  82124. x -= width * 0.5;
  82125. }
  82126. var y = screenSpacePosition.y;
  82127. if (billboard.verticalOrigin === VerticalOrigin.BOTTOM || billboard.verticalOrigin === VerticalOrigin.BASELINE) {
  82128. y -= height;
  82129. } else if (billboard.verticalOrigin === VerticalOrigin.CENTER) {
  82130. y -= height * 0.5;
  82131. }
  82132. if (!defined(result)) {
  82133. result = new BoundingRectangle();
  82134. }
  82135. result.x = x;
  82136. result.y = y;
  82137. result.width = width;
  82138. result.height = height;
  82139. return result;
  82140. };
  82141. /**
  82142. * Determines if this billboard equals another billboard. Billboards are equal if all their properties
  82143. * are equal. Billboards in different collections can be equal.
  82144. *
  82145. * @param {Billboard} other The billboard to compare for equality.
  82146. * @returns {Boolean} <code>true</code> if the billboards are equal; otherwise, <code>false</code>.
  82147. */
  82148. Billboard.prototype.equals = function(other) {
  82149. return this === other ||
  82150. defined(other) &&
  82151. this._id === other._id &&
  82152. Cartesian3.equals(this._position, other._position) &&
  82153. this._imageId === other._imageId &&
  82154. this._show === other._show &&
  82155. this._scale === other._scale &&
  82156. this._verticalOrigin === other._verticalOrigin &&
  82157. this._horizontalOrigin === other._horizontalOrigin &&
  82158. this._heightReference === other._heightReference &&
  82159. BoundingRectangle.equals(this._imageSubRegion, other._imageSubRegion) &&
  82160. Color.equals(this._color, other._color) &&
  82161. Cartesian2.equals(this._pixelOffset, other._pixelOffset) &&
  82162. Cartesian2.equals(this._translate, other._translate) &&
  82163. Cartesian3.equals(this._eyeOffset, other._eyeOffset) &&
  82164. NearFarScalar.equals(this._scaleByDistance, other._scaleByDistance) &&
  82165. NearFarScalar.equals(this._translucencyByDistance, other._translucencyByDistance) &&
  82166. NearFarScalar.equals(this._pixelOffsetScaleByDistance, other._pixelOffsetScaleByDistance) &&
  82167. DistanceDisplayCondition.equals(this._distanceDisplayCondition, other._distanceDisplayCondition);
  82168. };
  82169. Billboard.prototype._destroy = function() {
  82170. if (defined(this._customData)) {
  82171. this._billboardCollection._scene.globe._surface.removeTileCustomData(this._customData);
  82172. this._customData = undefined;
  82173. }
  82174. if (defined(this._removeCallbackFunc)) {
  82175. this._removeCallbackFunc();
  82176. this._removeCallbackFunc = undefined;
  82177. }
  82178. this.image = undefined;
  82179. this._pickId = this._pickId && this._pickId.destroy();
  82180. this._billboardCollection = undefined;
  82181. };
  82182. /**
  82183. * A function that creates an image.
  82184. * @callback Billboard~CreateImageCallback
  82185. * @param {String} id The identifier of the image to load.
  82186. * @returns {Image|Canvas|Promise<Image|Canvas>} The image, or a promise that will resolve to an image.
  82187. */
  82188. return Billboard;
  82189. });
  82190. /*global define*/
  82191. define('Renderer/VertexArrayFacade',[
  82192. '../Core/ComponentDatatype',
  82193. '../Core/defaultValue',
  82194. '../Core/defined',
  82195. '../Core/destroyObject',
  82196. '../Core/DeveloperError',
  82197. '../Core/Math',
  82198. './Buffer',
  82199. './BufferUsage',
  82200. './VertexArray'
  82201. ], function(
  82202. ComponentDatatype,
  82203. defaultValue,
  82204. defined,
  82205. destroyObject,
  82206. DeveloperError,
  82207. CesiumMath,
  82208. Buffer,
  82209. BufferUsage,
  82210. VertexArray) {
  82211. 'use strict';
  82212. /**
  82213. * @private
  82214. */
  82215. function VertexArrayFacade(context, attributes, sizeInVertices, instanced) {
  82216. if (!context) {
  82217. throw new DeveloperError('context is required.');
  82218. }
  82219. if (!attributes || (attributes.length === 0)) {
  82220. throw new DeveloperError('At least one attribute is required.');
  82221. }
  82222. var attrs = VertexArrayFacade._verifyAttributes(attributes);
  82223. sizeInVertices = defaultValue(sizeInVertices, 0);
  82224. var precreatedAttributes = [];
  82225. var attributesByUsage = {};
  82226. var attributesForUsage;
  82227. var usage;
  82228. // Bucket the attributes by usage.
  82229. var length = attrs.length;
  82230. for (var i = 0; i < length; ++i) {
  82231. var attribute = attrs[i];
  82232. // If the attribute already has a vertex buffer, we do not need
  82233. // to manage a vertex buffer or typed array for it.
  82234. if (attribute.vertexBuffer) {
  82235. precreatedAttributes.push(attribute);
  82236. continue;
  82237. }
  82238. usage = attribute.usage;
  82239. attributesForUsage = attributesByUsage[usage];
  82240. if (!defined(attributesForUsage)) {
  82241. attributesForUsage = attributesByUsage[usage] = [];
  82242. }
  82243. attributesForUsage.push(attribute);
  82244. }
  82245. // A function to sort attributes by the size of their components. From left to right, a vertex
  82246. // stores floats, shorts, and then bytes.
  82247. function compare(left, right) {
  82248. return ComponentDatatype.getSizeInBytes(right.componentDatatype) - ComponentDatatype.getSizeInBytes(left.componentDatatype);
  82249. }
  82250. this._allBuffers = [];
  82251. for (usage in attributesByUsage) {
  82252. if (attributesByUsage.hasOwnProperty(usage)) {
  82253. attributesForUsage = attributesByUsage[usage];
  82254. attributesForUsage.sort(compare);
  82255. var vertexSizeInBytes = VertexArrayFacade._vertexSizeInBytes(attributesForUsage);
  82256. var bufferUsage = attributesForUsage[0].usage;
  82257. var buffer = {
  82258. vertexSizeInBytes : vertexSizeInBytes,
  82259. vertexBuffer : undefined,
  82260. usage : bufferUsage,
  82261. needsCommit : false,
  82262. arrayBuffer : undefined,
  82263. arrayViews : VertexArrayFacade._createArrayViews(attributesForUsage, vertexSizeInBytes)
  82264. };
  82265. this._allBuffers.push(buffer);
  82266. }
  82267. }
  82268. this._size = 0;
  82269. this._instanced = defaultValue(instanced, false);
  82270. this._precreated = precreatedAttributes;
  82271. this._context = context;
  82272. this.writers = undefined;
  82273. this.va = undefined;
  82274. this.resize(sizeInVertices);
  82275. }
  82276. VertexArrayFacade._verifyAttributes = function(attributes) {
  82277. var attrs = [];
  82278. for ( var i = 0; i < attributes.length; ++i) {
  82279. var attribute = attributes[i];
  82280. var attr = {
  82281. index : defaultValue(attribute.index, i),
  82282. enabled : defaultValue(attribute.enabled, true),
  82283. componentsPerAttribute : attribute.componentsPerAttribute,
  82284. componentDatatype : defaultValue(attribute.componentDatatype, ComponentDatatype.FLOAT),
  82285. normalize : defaultValue(attribute.normalize, false),
  82286. // There will be either a vertexBuffer or an [optional] usage.
  82287. vertexBuffer : attribute.vertexBuffer,
  82288. usage : defaultValue(attribute.usage, BufferUsage.STATIC_DRAW)
  82289. };
  82290. attrs.push(attr);
  82291. if ((attr.componentsPerAttribute !== 1) && (attr.componentsPerAttribute !== 2) && (attr.componentsPerAttribute !== 3) && (attr.componentsPerAttribute !== 4)) {
  82292. throw new DeveloperError('attribute.componentsPerAttribute must be in the range [1, 4].');
  82293. }
  82294. var datatype = attr.componentDatatype;
  82295. if (!ComponentDatatype.validate(datatype)) {
  82296. throw new DeveloperError('Attribute must have a valid componentDatatype or not specify it.');
  82297. }
  82298. if (!BufferUsage.validate(attr.usage)) {
  82299. throw new DeveloperError('Attribute must have a valid usage or not specify it.');
  82300. }
  82301. }
  82302. // Verify all attribute names are unique.
  82303. var uniqueIndices = new Array(attrs.length);
  82304. for ( var j = 0; j < attrs.length; ++j) {
  82305. var currentAttr = attrs[j];
  82306. var index = currentAttr.index;
  82307. if (uniqueIndices[index]) {
  82308. throw new DeveloperError('Index ' + index + ' is used by more than one attribute.');
  82309. }
  82310. uniqueIndices[index] = true;
  82311. }
  82312. return attrs;
  82313. };
  82314. VertexArrayFacade._vertexSizeInBytes = function(attributes) {
  82315. var sizeInBytes = 0;
  82316. var length = attributes.length;
  82317. for ( var i = 0; i < length; ++i) {
  82318. var attribute = attributes[i];
  82319. sizeInBytes += (attribute.componentsPerAttribute * ComponentDatatype.getSizeInBytes(attribute.componentDatatype));
  82320. }
  82321. var maxComponentSizeInBytes = (length > 0) ? ComponentDatatype.getSizeInBytes(attributes[0].componentDatatype) : 0; // Sorted by size
  82322. var remainder = (maxComponentSizeInBytes > 0) ? (sizeInBytes % maxComponentSizeInBytes) : 0;
  82323. var padding = (remainder === 0) ? 0 : (maxComponentSizeInBytes - remainder);
  82324. sizeInBytes += padding;
  82325. return sizeInBytes;
  82326. };
  82327. VertexArrayFacade._createArrayViews = function(attributes, vertexSizeInBytes) {
  82328. var views = [];
  82329. var offsetInBytes = 0;
  82330. var length = attributes.length;
  82331. for ( var i = 0; i < length; ++i) {
  82332. var attribute = attributes[i];
  82333. var componentDatatype = attribute.componentDatatype;
  82334. views.push({
  82335. index : attribute.index,
  82336. enabled : attribute.enabled,
  82337. componentsPerAttribute : attribute.componentsPerAttribute,
  82338. componentDatatype : componentDatatype,
  82339. normalize : attribute.normalize,
  82340. offsetInBytes : offsetInBytes,
  82341. vertexSizeInComponentType : vertexSizeInBytes / ComponentDatatype.getSizeInBytes(componentDatatype),
  82342. view : undefined
  82343. });
  82344. offsetInBytes += (attribute.componentsPerAttribute * ComponentDatatype.getSizeInBytes(componentDatatype));
  82345. }
  82346. return views;
  82347. };
  82348. /**
  82349. * Invalidates writers. Can't render again until commit is called.
  82350. */
  82351. VertexArrayFacade.prototype.resize = function(sizeInVertices) {
  82352. this._size = sizeInVertices;
  82353. var allBuffers = this._allBuffers;
  82354. this.writers = [];
  82355. for (var i = 0, len = allBuffers.length; i < len; ++i) {
  82356. var buffer = allBuffers[i];
  82357. VertexArrayFacade._resize(buffer, this._size);
  82358. // Reserving invalidates the writers, so if client's cache them, they need to invalidate their cache.
  82359. VertexArrayFacade._appendWriters(this.writers, buffer);
  82360. }
  82361. // VAs are recreated next time commit is called.
  82362. destroyVA(this);
  82363. };
  82364. VertexArrayFacade._resize = function(buffer, size) {
  82365. if (buffer.vertexSizeInBytes > 0) {
  82366. // Create larger array buffer
  82367. var arrayBuffer = new ArrayBuffer(size * buffer.vertexSizeInBytes);
  82368. // Copy contents from previous array buffer
  82369. if (defined(buffer.arrayBuffer)) {
  82370. var destView = new Uint8Array(arrayBuffer);
  82371. var sourceView = new Uint8Array(buffer.arrayBuffer);
  82372. var sourceLength = sourceView.length;
  82373. for ( var j = 0; j < sourceLength; ++j) {
  82374. destView[j] = sourceView[j];
  82375. }
  82376. }
  82377. // Create typed views into the new array buffer
  82378. var views = buffer.arrayViews;
  82379. var length = views.length;
  82380. for ( var i = 0; i < length; ++i) {
  82381. var view = views[i];
  82382. view.view = ComponentDatatype.createArrayBufferView(view.componentDatatype, arrayBuffer, view.offsetInBytes);
  82383. }
  82384. buffer.arrayBuffer = arrayBuffer;
  82385. }
  82386. };
  82387. var createWriters = [
  82388. // 1 component per attribute
  82389. function(buffer, view, vertexSizeInComponentType) {
  82390. return function(index, attribute) {
  82391. view[index * vertexSizeInComponentType] = attribute;
  82392. buffer.needsCommit = true;
  82393. };
  82394. },
  82395. // 2 component per attribute
  82396. function(buffer, view, vertexSizeInComponentType) {
  82397. return function(index, component0, component1) {
  82398. var i = index * vertexSizeInComponentType;
  82399. view[i] = component0;
  82400. view[i + 1] = component1;
  82401. buffer.needsCommit = true;
  82402. };
  82403. },
  82404. // 3 component per attribute
  82405. function(buffer, view, vertexSizeInComponentType) {
  82406. return function(index, component0, component1, component2) {
  82407. var i = index * vertexSizeInComponentType;
  82408. view[i] = component0;
  82409. view[i + 1] = component1;
  82410. view[i + 2] = component2;
  82411. buffer.needsCommit = true;
  82412. };
  82413. },
  82414. // 4 component per attribute
  82415. function(buffer, view, vertexSizeInComponentType) {
  82416. return function(index, component0, component1, component2, component3) {
  82417. var i = index * vertexSizeInComponentType;
  82418. view[i] = component0;
  82419. view[i + 1] = component1;
  82420. view[i + 2] = component2;
  82421. view[i + 3] = component3;
  82422. buffer.needsCommit = true;
  82423. };
  82424. }];
  82425. VertexArrayFacade._appendWriters = function(writers, buffer) {
  82426. var arrayViews = buffer.arrayViews;
  82427. var length = arrayViews.length;
  82428. for ( var i = 0; i < length; ++i) {
  82429. var arrayView = arrayViews[i];
  82430. writers[arrayView.index] = createWriters[arrayView.componentsPerAttribute - 1](buffer, arrayView.view, arrayView.vertexSizeInComponentType);
  82431. }
  82432. };
  82433. VertexArrayFacade.prototype.commit = function(indexBuffer) {
  82434. var recreateVA = false;
  82435. var allBuffers = this._allBuffers;
  82436. var buffer;
  82437. var i;
  82438. var length;
  82439. for (i = 0, length = allBuffers.length; i < length; ++i) {
  82440. buffer = allBuffers[i];
  82441. recreateVA = commit(this, buffer) || recreateVA;
  82442. }
  82443. ///////////////////////////////////////////////////////////////////////
  82444. if (recreateVA || !defined(this.va)) {
  82445. destroyVA(this);
  82446. var va = this.va = [];
  82447. var numberOfVertexArrays = defined(indexBuffer) ? Math.ceil(this._size / (CesiumMath.SIXTY_FOUR_KILOBYTES - 1)) : 1;
  82448. for ( var k = 0; k < numberOfVertexArrays; ++k) {
  82449. var attributes = [];
  82450. for (i = 0, length = allBuffers.length; i < length; ++i) {
  82451. buffer = allBuffers[i];
  82452. var offset = k * (buffer.vertexSizeInBytes * (CesiumMath.SIXTY_FOUR_KILOBYTES - 1));
  82453. VertexArrayFacade._appendAttributes(attributes, buffer, offset, this._instanced);
  82454. }
  82455. attributes = attributes.concat(this._precreated);
  82456. va.push({
  82457. va : new VertexArray({
  82458. context : this._context,
  82459. attributes : attributes,
  82460. indexBuffer : indexBuffer
  82461. }),
  82462. indicesCount : 1.5 * ((k !== (numberOfVertexArrays - 1)) ? (CesiumMath.SIXTY_FOUR_KILOBYTES - 1) : (this._size % (CesiumMath.SIXTY_FOUR_KILOBYTES - 1)))
  82463. // TODO: not hardcode 1.5, this assumes 6 indices per 4 vertices (as for Billboard quads).
  82464. });
  82465. }
  82466. }
  82467. };
  82468. function commit(vertexArrayFacade, buffer) {
  82469. if (buffer.needsCommit && (buffer.vertexSizeInBytes > 0)) {
  82470. buffer.needsCommit = false;
  82471. var vertexBuffer = buffer.vertexBuffer;
  82472. var vertexBufferSizeInBytes = vertexArrayFacade._size * buffer.vertexSizeInBytes;
  82473. var vertexBufferDefined = defined(vertexBuffer);
  82474. if (!vertexBufferDefined || (vertexBuffer.sizeInBytes < vertexBufferSizeInBytes)) {
  82475. if (vertexBufferDefined) {
  82476. vertexBuffer.destroy();
  82477. }
  82478. buffer.vertexBuffer = Buffer.createVertexBuffer({
  82479. context : vertexArrayFacade._context,
  82480. typedArray : buffer.arrayBuffer,
  82481. usage : buffer.usage
  82482. });
  82483. buffer.vertexBuffer.vertexArrayDestroyable = false;
  82484. return true; // Created new vertex buffer
  82485. }
  82486. buffer.vertexBuffer.copyFromArrayView(buffer.arrayBuffer);
  82487. }
  82488. return false; // Did not create new vertex buffer
  82489. }
  82490. VertexArrayFacade._appendAttributes = function(attributes, buffer, vertexBufferOffset, instanced) {
  82491. var arrayViews = buffer.arrayViews;
  82492. var length = arrayViews.length;
  82493. for ( var i = 0; i < length; ++i) {
  82494. var view = arrayViews[i];
  82495. attributes.push({
  82496. index : view.index,
  82497. enabled : view.enabled,
  82498. componentsPerAttribute : view.componentsPerAttribute,
  82499. componentDatatype : view.componentDatatype,
  82500. normalize : view.normalize,
  82501. vertexBuffer : buffer.vertexBuffer,
  82502. offsetInBytes : vertexBufferOffset + view.offsetInBytes,
  82503. strideInBytes : buffer.vertexSizeInBytes,
  82504. instanceDivisor : instanced ? 1 : 0
  82505. });
  82506. }
  82507. };
  82508. VertexArrayFacade.prototype.subCommit = function(offsetInVertices, lengthInVertices) {
  82509. if (offsetInVertices < 0 || offsetInVertices >= this._size) {
  82510. throw new DeveloperError('offsetInVertices must be greater than or equal to zero and less than the vertex array size.');
  82511. }
  82512. if (offsetInVertices + lengthInVertices > this._size) {
  82513. throw new DeveloperError('offsetInVertices + lengthInVertices cannot exceed the vertex array size.');
  82514. }
  82515. var allBuffers = this._allBuffers;
  82516. for (var i = 0, len = allBuffers.length; i < len; ++i) {
  82517. subCommit(allBuffers[i], offsetInVertices, lengthInVertices);
  82518. }
  82519. };
  82520. function subCommit(buffer, offsetInVertices, lengthInVertices) {
  82521. if (buffer.needsCommit && (buffer.vertexSizeInBytes > 0)) {
  82522. var byteOffset = buffer.vertexSizeInBytes * offsetInVertices;
  82523. var byteLength = buffer.vertexSizeInBytes * lengthInVertices;
  82524. // PERFORMANCE_IDEA: If we want to get really crazy, we could consider updating
  82525. // individual attributes instead of the entire (sub-)vertex.
  82526. //
  82527. // PERFORMANCE_IDEA: Does creating the typed view add too much GC overhead?
  82528. buffer.vertexBuffer.copyFromArrayView(new Uint8Array(buffer.arrayBuffer, byteOffset, byteLength), byteOffset);
  82529. }
  82530. }
  82531. VertexArrayFacade.prototype.endSubCommits = function() {
  82532. var allBuffers = this._allBuffers;
  82533. for (var i = 0, len = allBuffers.length; i < len; ++i) {
  82534. allBuffers[i].needsCommit = false;
  82535. }
  82536. };
  82537. function destroyVA(vertexArrayFacade) {
  82538. var va = vertexArrayFacade.va;
  82539. if (!defined(va)) {
  82540. return;
  82541. }
  82542. var length = va.length;
  82543. for (var i = 0; i < length; ++i) {
  82544. va[i].va.destroy();
  82545. }
  82546. vertexArrayFacade.va = undefined;
  82547. }
  82548. VertexArrayFacade.prototype.isDestroyed = function() {
  82549. return false;
  82550. };
  82551. VertexArrayFacade.prototype.destroy = function() {
  82552. var allBuffers = this._allBuffers;
  82553. for (var i = 0, len = allBuffers.length; i < len; ++i) {
  82554. var buffer = allBuffers[i];
  82555. buffer.vertexBuffer = buffer.vertexBuffer && buffer.vertexBuffer.destroy();
  82556. }
  82557. destroyVA(this);
  82558. return destroyObject(this);
  82559. };
  82560. return VertexArrayFacade;
  82561. });
  82562. //This file is automatically rebuilt by the Cesium build process.
  82563. /*global define*/
  82564. define('Shaders/BillboardCollectionFS',[],function() {
  82565. 'use strict';
  82566. return "uniform sampler2D u_atlas;\n\
  82567. varying vec2 v_textureCoordinates;\n\
  82568. #ifdef RENDER_FOR_PICK\n\
  82569. varying vec4 v_pickColor;\n\
  82570. #else\n\
  82571. varying vec4 v_color;\n\
  82572. #endif\n\
  82573. void main()\n\
  82574. {\n\
  82575. #ifdef RENDER_FOR_PICK\n\
  82576. vec4 vertexColor = vec4(1.0, 1.0, 1.0, 1.0);\n\
  82577. #else\n\
  82578. vec4 vertexColor = v_color;\n\
  82579. #endif\n\
  82580. vec4 color = texture2D(u_atlas, v_textureCoordinates) * vertexColor;\n\
  82581. if (color.a == 0.0)\n\
  82582. {\n\
  82583. discard;\n\
  82584. }\n\
  82585. #ifdef RENDER_FOR_PICK\n\
  82586. gl_FragColor = v_pickColor;\n\
  82587. #else\n\
  82588. gl_FragColor = color;\n\
  82589. #endif\n\
  82590. }\n\
  82591. ";
  82592. });
  82593. //This file is automatically rebuilt by the Cesium build process.
  82594. /*global define*/
  82595. define('Shaders/BillboardCollectionVS',[],function() {
  82596. 'use strict';
  82597. return "#ifdef INSTANCED\n\
  82598. attribute vec2 direction;\n\
  82599. #endif\n\
  82600. attribute vec4 positionHighAndScale;\n\
  82601. attribute vec4 positionLowAndRotation;\n\
  82602. attribute vec4 compressedAttribute0;\n\
  82603. attribute vec4 compressedAttribute1;\n\
  82604. attribute vec4 compressedAttribute2;\n\
  82605. attribute vec4 eyeOffset;\n\
  82606. attribute vec4 scaleByDistance;\n\
  82607. attribute vec4 pixelOffsetScaleByDistance;\n\
  82608. attribute vec2 distanceDisplayCondition;\n\
  82609. varying vec2 v_textureCoordinates;\n\
  82610. #ifdef RENDER_FOR_PICK\n\
  82611. varying vec4 v_pickColor;\n\
  82612. #else\n\
  82613. varying vec4 v_color;\n\
  82614. #endif\n\
  82615. const float UPPER_BOUND = 32768.0;\n\
  82616. const float SHIFT_LEFT16 = 65536.0;\n\
  82617. const float SHIFT_LEFT8 = 256.0;\n\
  82618. const float SHIFT_LEFT7 = 128.0;\n\
  82619. const float SHIFT_LEFT5 = 32.0;\n\
  82620. const float SHIFT_LEFT3 = 8.0;\n\
  82621. const float SHIFT_LEFT2 = 4.0;\n\
  82622. const float SHIFT_LEFT1 = 2.0;\n\
  82623. const float SHIFT_RIGHT8 = 1.0 / 256.0;\n\
  82624. const float SHIFT_RIGHT7 = 1.0 / 128.0;\n\
  82625. const float SHIFT_RIGHT5 = 1.0 / 32.0;\n\
  82626. const float SHIFT_RIGHT3 = 1.0 / 8.0;\n\
  82627. const float SHIFT_RIGHT2 = 1.0 / 4.0;\n\
  82628. const float SHIFT_RIGHT1 = 1.0 / 2.0;\n\
  82629. vec4 computePositionWindowCoordinates(vec4 positionEC, vec2 imageSize, float scale, vec2 direction, vec2 origin, vec2 translate, vec2 pixelOffset, vec3 alignedAxis, bool validAlignedAxis, float rotation, bool sizeInMeters)\n\
  82630. {\n\
  82631. vec2 halfSize = imageSize * scale * czm_resolutionScale * 0.5;\n\
  82632. halfSize *= ((direction * 2.0) - 1.0);\n\
  82633. vec2 originTranslate = origin * abs(halfSize);\n\
  82634. #if defined(ROTATION) || defined(ALIGNED_AXIS)\n\
  82635. if (validAlignedAxis || rotation != 0.0)\n\
  82636. {\n\
  82637. float angle = rotation;\n\
  82638. if (validAlignedAxis)\n\
  82639. {\n\
  82640. vec3 pos = positionEC.xyz + czm_encodedCameraPositionMCHigh + czm_encodedCameraPositionMCLow;\n\
  82641. vec3 normal = normalize(cross(alignedAxis, pos));\n\
  82642. vec4 tangent = vec4(normalize(cross(pos, normal)), 0.0);\n\
  82643. tangent = czm_modelViewProjection * tangent;\n\
  82644. angle += sign(-tangent.x) * acos(tangent.y / length(tangent.xy));\n\
  82645. }\n\
  82646. float cosTheta = cos(angle);\n\
  82647. float sinTheta = sin(angle);\n\
  82648. mat2 rotationMatrix = mat2(cosTheta, sinTheta, -sinTheta, cosTheta);\n\
  82649. halfSize = rotationMatrix * halfSize;\n\
  82650. }\n\
  82651. #endif\n\
  82652. if (sizeInMeters)\n\
  82653. {\n\
  82654. positionEC.xy += halfSize;\n\
  82655. }\n\
  82656. vec4 positionWC = czm_eyeToWindowCoordinates(positionEC);\n\
  82657. if (sizeInMeters)\n\
  82658. {\n\
  82659. originTranslate += originTranslate / czm_metersPerPixel(positionEC);\n\
  82660. }\n\
  82661. positionWC.xy += originTranslate;\n\
  82662. if (!sizeInMeters)\n\
  82663. {\n\
  82664. positionWC.xy += halfSize;\n\
  82665. }\n\
  82666. positionWC.xy += translate;\n\
  82667. positionWC.xy += (pixelOffset * czm_resolutionScale);\n\
  82668. return positionWC;\n\
  82669. }\n\
  82670. void main()\n\
  82671. {\n\
  82672. vec3 positionHigh = positionHighAndScale.xyz;\n\
  82673. vec3 positionLow = positionLowAndRotation.xyz;\n\
  82674. float scale = positionHighAndScale.w;\n\
  82675. #if defined(ROTATION) || defined(ALIGNED_AXIS)\n\
  82676. float rotation = positionLowAndRotation.w;\n\
  82677. #else\n\
  82678. float rotation = 0.0;\n\
  82679. #endif\n\
  82680. float compressed = compressedAttribute0.x;\n\
  82681. vec2 pixelOffset;\n\
  82682. pixelOffset.x = floor(compressed * SHIFT_RIGHT7);\n\
  82683. compressed -= pixelOffset.x * SHIFT_LEFT7;\n\
  82684. pixelOffset.x -= UPPER_BOUND;\n\
  82685. vec2 origin;\n\
  82686. origin.x = floor(compressed * SHIFT_RIGHT5);\n\
  82687. compressed -= origin.x * SHIFT_LEFT5;\n\
  82688. origin.y = floor(compressed * SHIFT_RIGHT3);\n\
  82689. compressed -= origin.y * SHIFT_LEFT3;\n\
  82690. origin -= vec2(1.0);\n\
  82691. float show = floor(compressed * SHIFT_RIGHT2);\n\
  82692. compressed -= show * SHIFT_LEFT2;\n\
  82693. #ifdef INSTANCED\n\
  82694. vec2 textureCoordinatesBottomLeft = czm_decompressTextureCoordinates(compressedAttribute0.w);\n\
  82695. vec2 textureCoordinatesRange = czm_decompressTextureCoordinates(eyeOffset.w);\n\
  82696. vec2 textureCoordinates = textureCoordinatesBottomLeft + direction * textureCoordinatesRange;\n\
  82697. #else\n\
  82698. vec2 direction;\n\
  82699. direction.x = floor(compressed * SHIFT_RIGHT1);\n\
  82700. direction.y = compressed - direction.x * SHIFT_LEFT1;\n\
  82701. vec2 textureCoordinates = czm_decompressTextureCoordinates(compressedAttribute0.w);\n\
  82702. #endif\n\
  82703. float temp = compressedAttribute0.y * SHIFT_RIGHT8;\n\
  82704. pixelOffset.y = -(floor(temp) - UPPER_BOUND);\n\
  82705. vec2 translate;\n\
  82706. translate.y = (temp - floor(temp)) * SHIFT_LEFT16;\n\
  82707. temp = compressedAttribute0.z * SHIFT_RIGHT8;\n\
  82708. translate.x = floor(temp) - UPPER_BOUND;\n\
  82709. translate.y += (temp - floor(temp)) * SHIFT_LEFT8;\n\
  82710. translate.y -= UPPER_BOUND;\n\
  82711. temp = compressedAttribute1.x * SHIFT_RIGHT8;\n\
  82712. vec2 imageSize = vec2(floor(temp), compressedAttribute2.w);\n\
  82713. #ifdef EYE_DISTANCE_TRANSLUCENCY\n\
  82714. vec4 translucencyByDistance;\n\
  82715. translucencyByDistance.x = compressedAttribute1.z;\n\
  82716. translucencyByDistance.z = compressedAttribute1.w;\n\
  82717. translucencyByDistance.y = ((temp - floor(temp)) * SHIFT_LEFT8) / 255.0;\n\
  82718. temp = compressedAttribute1.y * SHIFT_RIGHT8;\n\
  82719. translucencyByDistance.w = ((temp - floor(temp)) * SHIFT_LEFT8) / 255.0;\n\
  82720. #endif\n\
  82721. #ifdef ALIGNED_AXIS\n\
  82722. vec3 alignedAxis = czm_octDecode(floor(compressedAttribute1.y * SHIFT_RIGHT8));\n\
  82723. temp = compressedAttribute2.z * SHIFT_RIGHT5;\n\
  82724. bool validAlignedAxis = (temp - floor(temp)) * SHIFT_LEFT1 > 0.0;\n\
  82725. #else\n\
  82726. vec3 alignedAxis = vec3(0.0);\n\
  82727. bool validAlignedAxis = false;\n\
  82728. #endif\n\
  82729. #ifdef RENDER_FOR_PICK\n\
  82730. temp = compressedAttribute2.y;\n\
  82731. #else\n\
  82732. temp = compressedAttribute2.x;\n\
  82733. #endif\n\
  82734. vec4 color;\n\
  82735. temp = temp * SHIFT_RIGHT8;\n\
  82736. color.b = (temp - floor(temp)) * SHIFT_LEFT8;\n\
  82737. temp = floor(temp) * SHIFT_RIGHT8;\n\
  82738. color.g = (temp - floor(temp)) * SHIFT_LEFT8;\n\
  82739. color.r = floor(temp);\n\
  82740. temp = compressedAttribute2.z * SHIFT_RIGHT8;\n\
  82741. bool sizeInMeters = floor((temp - floor(temp)) * SHIFT_LEFT7) > 0.0;\n\
  82742. temp = floor(temp) * SHIFT_RIGHT8;\n\
  82743. #ifdef RENDER_FOR_PICK\n\
  82744. color.a = (temp - floor(temp)) * SHIFT_LEFT8;\n\
  82745. vec4 pickColor = color / 255.0;\n\
  82746. #else\n\
  82747. color.a = floor(temp);\n\
  82748. color /= 255.0;\n\
  82749. #endif\n\
  82750. vec4 p = czm_translateRelativeToEye(positionHigh, positionLow);\n\
  82751. vec4 positionEC = czm_modelViewRelativeToEye * p;\n\
  82752. positionEC = czm_eyeOffset(positionEC, eyeOffset.xyz);\n\
  82753. positionEC.xyz *= show;\n\
  82754. #if defined(EYE_DISTANCE_SCALING) || defined(EYE_DISTANCE_TRANSLUCENCY) || defined(EYE_DISTANCE_PIXEL_OFFSET) || defined(DISTANCE_DISPLAY_CONDITION)\n\
  82755. float lengthSq;\n\
  82756. if (czm_sceneMode == czm_sceneMode2D)\n\
  82757. {\n\
  82758. lengthSq = czm_eyeHeight2D.y;\n\
  82759. }\n\
  82760. else\n\
  82761. {\n\
  82762. lengthSq = dot(positionEC.xyz, positionEC.xyz);\n\
  82763. }\n\
  82764. #endif\n\
  82765. #ifdef EYE_DISTANCE_SCALING\n\
  82766. scale *= czm_nearFarScalar(scaleByDistance, lengthSq);\n\
  82767. if (scale == 0.0)\n\
  82768. {\n\
  82769. positionEC.xyz = vec3(0.0);\n\
  82770. }\n\
  82771. #endif\n\
  82772. float translucency = 1.0;\n\
  82773. #ifdef EYE_DISTANCE_TRANSLUCENCY\n\
  82774. translucency = czm_nearFarScalar(translucencyByDistance, lengthSq);\n\
  82775. if (translucency == 0.0)\n\
  82776. {\n\
  82777. positionEC.xyz = vec3(0.0);\n\
  82778. }\n\
  82779. #endif\n\
  82780. #ifdef EYE_DISTANCE_PIXEL_OFFSET\n\
  82781. float pixelOffsetScale = czm_nearFarScalar(pixelOffsetScaleByDistance, lengthSq);\n\
  82782. pixelOffset *= pixelOffsetScale;\n\
  82783. #endif\n\
  82784. #ifdef DISTANCE_DISPLAY_CONDITION\n\
  82785. float nearSq = distanceDisplayCondition.x * distanceDisplayCondition.x;\n\
  82786. float farSq = distanceDisplayCondition.y * distanceDisplayCondition.y;\n\
  82787. if (lengthSq < nearSq || lengthSq > farSq)\n\
  82788. {\n\
  82789. positionEC.xyz = vec3(0.0);\n\
  82790. }\n\
  82791. #endif\n\
  82792. vec4 positionWC = computePositionWindowCoordinates(positionEC, imageSize, scale, direction, origin, translate, pixelOffset, alignedAxis, validAlignedAxis, rotation, sizeInMeters);\n\
  82793. gl_Position = czm_viewportOrthographic * vec4(positionWC.xy, -positionWC.z, 1.0);\n\
  82794. v_textureCoordinates = textureCoordinates;\n\
  82795. #ifdef RENDER_FOR_PICK\n\
  82796. v_pickColor = pickColor;\n\
  82797. #else\n\
  82798. v_color = color;\n\
  82799. v_color.a *= translucency;\n\
  82800. #endif\n\
  82801. }\n\
  82802. ";
  82803. });
  82804. /*global define*/
  82805. define('Renderer/Framebuffer',[
  82806. '../Core/defaultValue',
  82807. '../Core/defined',
  82808. '../Core/defineProperties',
  82809. '../Core/destroyObject',
  82810. '../Core/DeveloperError',
  82811. '../Core/PixelFormat',
  82812. './ContextLimits'
  82813. ], function(
  82814. defaultValue,
  82815. defined,
  82816. defineProperties,
  82817. destroyObject,
  82818. DeveloperError,
  82819. PixelFormat,
  82820. ContextLimits) {
  82821. 'use strict';
  82822. function attachTexture(framebuffer, attachment, texture) {
  82823. var gl = framebuffer._gl;
  82824. gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, texture._target, texture._texture, 0);
  82825. }
  82826. function attachRenderbuffer(framebuffer, attachment, renderbuffer) {
  82827. var gl = framebuffer._gl;
  82828. gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, renderbuffer._getRenderbuffer());
  82829. }
  82830. /**
  82831. * Creates a framebuffer with optional initial color, depth, and stencil attachments.
  82832. * Framebuffers are used for render-to-texture effects; they allow us to render to
  82833. * textures in one pass, and read from it in a later pass.
  82834. *
  82835. * @param {Object} options The initial framebuffer attachments as shown in the example below. <code>context</code> is required. The possible properties are <code>colorTextures</code>, <code>colorRenderbuffers</code>, <code>depthTexture</code>, <code>depthRenderbuffer</code>, <code>stencilRenderbuffer</code>, <code>depthStencilTexture</code>, and <code>depthStencilRenderbuffer</code>.
  82836. *
  82837. * @exception {DeveloperError} Cannot have both color texture and color renderbuffer attachments.
  82838. * @exception {DeveloperError} Cannot have both a depth texture and depth renderbuffer attachment.
  82839. * @exception {DeveloperError} Cannot have both a depth-stencil texture and depth-stencil renderbuffer attachment.
  82840. * @exception {DeveloperError} Cannot have both a depth and depth-stencil renderbuffer.
  82841. * @exception {DeveloperError} Cannot have both a stencil and depth-stencil renderbuffer.
  82842. * @exception {DeveloperError} Cannot have both a depth and stencil renderbuffer.
  82843. * @exception {DeveloperError} The color-texture pixel-format must be a color format.
  82844. * @exception {DeveloperError} The depth-texture pixel-format must be DEPTH_COMPONENT.
  82845. * @exception {DeveloperError} The depth-stencil-texture pixel-format must be DEPTH_STENCIL.
  82846. * @exception {DeveloperError} The number of color attachments exceeds the number supported.
  82847. *
  82848. * @example
  82849. * // Create a framebuffer with color and depth texture attachments.
  82850. * var width = context.canvas.clientWidth;
  82851. * var height = context.canvas.clientHeight;
  82852. * var framebuffer = new Framebuffer({
  82853. * context : context,
  82854. * colorTextures : [new Texture({
  82855. * context : context,
  82856. * width : width,
  82857. * height : height,
  82858. * pixelFormat : PixelFormat.RGBA
  82859. * })],
  82860. * depthTexture : new Texture({
  82861. * context : context,
  82862. * width : width,
  82863. * height : height,
  82864. * pixelFormat : PixelFormat.DEPTH_COMPONENT,
  82865. * pixelDatatype : PixelDatatype.UNSIGNED_SHORT
  82866. * })
  82867. * });
  82868. *
  82869. * @private
  82870. */
  82871. function Framebuffer(options) {
  82872. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  82873. if (!defined(options.context)) {
  82874. throw new DeveloperError('options.context is required.');
  82875. }
  82876. var gl = options.context._gl;
  82877. var maximumColorAttachments = ContextLimits.maximumColorAttachments;
  82878. this._gl = gl;
  82879. this._framebuffer = gl.createFramebuffer();
  82880. this._colorTextures = [];
  82881. this._colorRenderbuffers = [];
  82882. this._activeColorAttachments = [];
  82883. this._depthTexture = undefined;
  82884. this._depthRenderbuffer = undefined;
  82885. this._stencilRenderbuffer = undefined;
  82886. this._depthStencilTexture = undefined;
  82887. this._depthStencilRenderbuffer = undefined;
  82888. /**
  82889. * When true, the framebuffer owns its attachments so they will be destroyed when
  82890. * {@link Framebuffer#destroy} is called or when a new attachment is assigned
  82891. * to an attachment point.
  82892. *
  82893. * @type {Boolean}
  82894. * @default true
  82895. *
  82896. * @see Framebuffer#destroy
  82897. */
  82898. this.destroyAttachments = defaultValue(options.destroyAttachments, true);
  82899. // Throw if a texture and renderbuffer are attached to the same point. This won't
  82900. // cause a WebGL error (because only one will be attached), but is likely a developer error.
  82901. if (defined(options.colorTextures) && defined(options.colorRenderbuffers)) {
  82902. throw new DeveloperError('Cannot have both color texture and color renderbuffer attachments.');
  82903. }
  82904. if (defined(options.depthTexture) && defined(options.depthRenderbuffer)) {
  82905. throw new DeveloperError('Cannot have both a depth texture and depth renderbuffer attachment.');
  82906. }
  82907. if (defined(options.depthStencilTexture) && defined(options.depthStencilRenderbuffer)) {
  82908. throw new DeveloperError('Cannot have both a depth-stencil texture and depth-stencil renderbuffer attachment.');
  82909. }
  82910. // Avoid errors defined in Section 6.5 of the WebGL spec
  82911. var depthAttachment = (defined(options.depthTexture) || defined(options.depthRenderbuffer));
  82912. var depthStencilAttachment = (defined(options.depthStencilTexture) || defined(options.depthStencilRenderbuffer));
  82913. if (depthAttachment && depthStencilAttachment) {
  82914. throw new DeveloperError('Cannot have both a depth and depth-stencil attachment.');
  82915. }
  82916. if (defined(options.stencilRenderbuffer) && depthStencilAttachment) {
  82917. throw new DeveloperError('Cannot have both a stencil and depth-stencil attachment.');
  82918. }
  82919. if (depthAttachment && defined(options.stencilRenderbuffer)) {
  82920. throw new DeveloperError('Cannot have both a depth and stencil attachment.');
  82921. }
  82922. ///////////////////////////////////////////////////////////////////
  82923. this._bind();
  82924. var texture;
  82925. var renderbuffer;
  82926. var i;
  82927. var length;
  82928. var attachmentEnum;
  82929. if (defined(options.colorTextures)) {
  82930. var textures = options.colorTextures;
  82931. length = this._colorTextures.length = this._activeColorAttachments.length = textures.length;
  82932. if (length > maximumColorAttachments) {
  82933. throw new DeveloperError('The number of color attachments exceeds the number supported.');
  82934. }
  82935. for (i = 0; i < length; ++i) {
  82936. texture = textures[i];
  82937. if (!PixelFormat.isColorFormat(texture.pixelFormat)) {
  82938. throw new DeveloperError('The color-texture pixel-format must be a color format.');
  82939. }
  82940. attachmentEnum = this._gl.COLOR_ATTACHMENT0 + i;
  82941. attachTexture(this, attachmentEnum, texture);
  82942. this._activeColorAttachments[i] = attachmentEnum;
  82943. this._colorTextures[i] = texture;
  82944. }
  82945. }
  82946. if (defined(options.colorRenderbuffers)) {
  82947. var renderbuffers = options.colorRenderbuffers;
  82948. length = this._colorRenderbuffers.length = this._activeColorAttachments.length = renderbuffers.length;
  82949. if (length > maximumColorAttachments) {
  82950. throw new DeveloperError('The number of color attachments exceeds the number supported.');
  82951. }
  82952. for (i = 0; i < length; ++i) {
  82953. renderbuffer = renderbuffers[i];
  82954. attachmentEnum = this._gl.COLOR_ATTACHMENT0 + i;
  82955. attachRenderbuffer(this, attachmentEnum, renderbuffer);
  82956. this._activeColorAttachments[i] = attachmentEnum;
  82957. this._colorRenderbuffers[i] = renderbuffer;
  82958. }
  82959. }
  82960. if (defined(options.depthTexture)) {
  82961. texture = options.depthTexture;
  82962. if (texture.pixelFormat !== PixelFormat.DEPTH_COMPONENT) {
  82963. throw new DeveloperError('The depth-texture pixel-format must be DEPTH_COMPONENT.');
  82964. }
  82965. attachTexture(this, this._gl.DEPTH_ATTACHMENT, texture);
  82966. this._depthTexture = texture;
  82967. }
  82968. if (defined(options.depthRenderbuffer)) {
  82969. renderbuffer = options.depthRenderbuffer;
  82970. attachRenderbuffer(this, this._gl.DEPTH_ATTACHMENT, renderbuffer);
  82971. this._depthRenderbuffer = renderbuffer;
  82972. }
  82973. if (defined(options.stencilRenderbuffer)) {
  82974. renderbuffer = options.stencilRenderbuffer;
  82975. attachRenderbuffer(this, this._gl.STENCIL_ATTACHMENT, renderbuffer);
  82976. this._stencilRenderbuffer = renderbuffer;
  82977. }
  82978. if (defined(options.depthStencilTexture)) {
  82979. texture = options.depthStencilTexture;
  82980. if (texture.pixelFormat !== PixelFormat.DEPTH_STENCIL) {
  82981. throw new DeveloperError('The depth-stencil pixel-format must be DEPTH_STENCIL.');
  82982. }
  82983. attachTexture(this, this._gl.DEPTH_STENCIL_ATTACHMENT, texture);
  82984. this._depthStencilTexture = texture;
  82985. }
  82986. if (defined(options.depthStencilRenderbuffer)) {
  82987. renderbuffer = options.depthStencilRenderbuffer;
  82988. attachRenderbuffer(this, this._gl.DEPTH_STENCIL_ATTACHMENT, renderbuffer);
  82989. this._depthStencilRenderbuffer = renderbuffer;
  82990. }
  82991. this._unBind();
  82992. }
  82993. defineProperties(Framebuffer.prototype, {
  82994. /**
  82995. * The status of the framebuffer. If the status is not WebGLConstants.FRAMEBUFFER_COMPLETE,
  82996. * a {@link DeveloperError} will be thrown when attempting to render to the framebuffer.
  82997. * @memberof Framebuffer.prototype
  82998. * @type {Number}
  82999. */
  83000. status : {
  83001. get : function() {
  83002. this._bind();
  83003. var status = this._gl.checkFramebufferStatus(this._gl.FRAMEBUFFER);
  83004. this._unBind();
  83005. return status;
  83006. }
  83007. },
  83008. numberOfColorAttachments : {
  83009. get : function() {
  83010. return this._activeColorAttachments.length;
  83011. }
  83012. },
  83013. depthTexture: {
  83014. get : function() {
  83015. return this._depthTexture;
  83016. }
  83017. },
  83018. depthRenderbuffer: {
  83019. get : function() {
  83020. return this._depthRenderbuffer;
  83021. }
  83022. },
  83023. stencilRenderbuffer : {
  83024. get : function() {
  83025. return this._stencilRenderbuffer;
  83026. }
  83027. },
  83028. depthStencilTexture : {
  83029. get : function() {
  83030. return this._depthStencilTexture;
  83031. }
  83032. },
  83033. depthStencilRenderbuffer : {
  83034. get : function() {
  83035. return this._depthStencilRenderbuffer;
  83036. }
  83037. },
  83038. /**
  83039. * True if the framebuffer has a depth attachment. Depth attachments include
  83040. * depth and depth-stencil textures, and depth and depth-stencil renderbuffers. When
  83041. * rendering to a framebuffer, a depth attachment is required for the depth test to have effect.
  83042. * @memberof Framebuffer.prototype
  83043. * @type {Boolean}
  83044. */
  83045. hasDepthAttachment : {
  83046. get : function() {
  83047. return !!(this.depthTexture || this.depthRenderbuffer || this.depthStencilTexture || this.depthStencilRenderbuffer);
  83048. }
  83049. }
  83050. });
  83051. Framebuffer.prototype._bind = function() {
  83052. var gl = this._gl;
  83053. gl.bindFramebuffer(gl.FRAMEBUFFER, this._framebuffer);
  83054. };
  83055. Framebuffer.prototype._unBind = function() {
  83056. var gl = this._gl;
  83057. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  83058. };
  83059. Framebuffer.prototype._getActiveColorAttachments = function() {
  83060. return this._activeColorAttachments;
  83061. };
  83062. Framebuffer.prototype.getColorTexture = function(index) {
  83063. if (!defined(index) || index < 0 || index >= this._colorTextures.length) {
  83064. throw new DeveloperError('index is required, must be greater than or equal to zero and must be less than the number of color attachments.');
  83065. }
  83066. return this._colorTextures[index];
  83067. };
  83068. Framebuffer.prototype.getColorRenderbuffer = function(index) {
  83069. if (!defined(index) || index < 0 || index >= this._colorRenderbuffers.length) {
  83070. throw new DeveloperError('index is required, must be greater than or equal to zero and must be less than the number of color attachments.');
  83071. }
  83072. return this._colorRenderbuffers[index];
  83073. };
  83074. Framebuffer.prototype.isDestroyed = function() {
  83075. return false;
  83076. };
  83077. Framebuffer.prototype.destroy = function() {
  83078. if (this.destroyAttachments) {
  83079. // If the color texture is a cube map face, it is owned by the cube map, and will not be destroyed.
  83080. var i = 0;
  83081. var textures = this._colorTextures;
  83082. var length = textures.length;
  83083. for (; i < length; ++i) {
  83084. var texture = textures[i];
  83085. if (defined(texture)) {
  83086. texture.destroy();
  83087. }
  83088. }
  83089. var renderbuffers = this._colorRenderbuffers;
  83090. length = renderbuffers.length;
  83091. for (i = 0; i < length; ++i) {
  83092. var renderbuffer = renderbuffers[i];
  83093. if (defined(renderbuffer)) {
  83094. renderbuffer.destroy();
  83095. }
  83096. }
  83097. this._depthTexture = this._depthTexture && this._depthTexture.destroy();
  83098. this._depthRenderbuffer = this._depthRenderbuffer && this._depthRenderbuffer.destroy();
  83099. this._stencilRenderbuffer = this._stencilRenderbuffer && this._stencilRenderbuffer.destroy();
  83100. this._depthStencilTexture = this._depthStencilTexture && this._depthStencilTexture.destroy();
  83101. this._depthStencilRenderbuffer = this._depthStencilRenderbuffer && this._depthStencilRenderbuffer.destroy();
  83102. }
  83103. this._gl.deleteFramebuffer(this._framebuffer);
  83104. return destroyObject(this);
  83105. };
  83106. return Framebuffer;
  83107. });
  83108. /*global define*/
  83109. define('Scene/TextureAtlas',[
  83110. '../Core/BoundingRectangle',
  83111. '../Core/Cartesian2',
  83112. '../Core/createGuid',
  83113. '../Core/defaultValue',
  83114. '../Core/defined',
  83115. '../Core/defineProperties',
  83116. '../Core/destroyObject',
  83117. '../Core/DeveloperError',
  83118. '../Core/loadImage',
  83119. '../Core/PixelFormat',
  83120. '../Core/RuntimeError',
  83121. '../Renderer/Framebuffer',
  83122. '../Renderer/Texture',
  83123. '../ThirdParty/when'
  83124. ], function(
  83125. BoundingRectangle,
  83126. Cartesian2,
  83127. createGuid,
  83128. defaultValue,
  83129. defined,
  83130. defineProperties,
  83131. destroyObject,
  83132. DeveloperError,
  83133. loadImage,
  83134. PixelFormat,
  83135. RuntimeError,
  83136. Framebuffer,
  83137. Texture,
  83138. when) {
  83139. 'use strict';
  83140. // The atlas is made up of regions of space called nodes that contain images or child nodes.
  83141. function TextureAtlasNode(bottomLeft, topRight, childNode1, childNode2, imageIndex) {
  83142. this.bottomLeft = defaultValue(bottomLeft, Cartesian2.ZERO);
  83143. this.topRight = defaultValue(topRight, Cartesian2.ZERO);
  83144. this.childNode1 = childNode1;
  83145. this.childNode2 = childNode2;
  83146. this.imageIndex = imageIndex;
  83147. }
  83148. var defaultInitialSize = new Cartesian2(16.0, 16.0);
  83149. /**
  83150. * A TextureAtlas stores multiple images in one square texture and keeps
  83151. * track of the texture coordinates for each image. TextureAtlas is dynamic,
  83152. * meaning new images can be added at any point in time.
  83153. * Texture coordinates are subject to change if the texture atlas resizes, so it is
  83154. * important to check {@link TextureAtlas#getGUID} before using old values.
  83155. *
  83156. * @alias TextureAtlas
  83157. * @constructor
  83158. *
  83159. * @param {Object} options Object with the following properties:
  83160. * @param {Scene} options.context The context in which the texture gets created.
  83161. * @param {PixelFormat} [options.pixelFormat=PixelFormat.RGBA] The pixel format of the texture.
  83162. * @param {Number} [options.borderWidthInPixels=1] The amount of spacing between adjacent images in pixels.
  83163. * @param {Cartesian2} [options.initialSize=new Cartesian2(16.0, 16.0)] The initial side lengths of the texture.
  83164. *
  83165. * @exception {DeveloperError} borderWidthInPixels must be greater than or equal to zero.
  83166. * @exception {DeveloperError} initialSize must be greater than zero.
  83167. *
  83168. * @private
  83169. */
  83170. function TextureAtlas(options) {
  83171. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  83172. var borderWidthInPixels = defaultValue(options.borderWidthInPixels, 1.0);
  83173. var initialSize = defaultValue(options.initialSize, defaultInitialSize);
  83174. if (!defined(options.context)) {
  83175. throw new DeveloperError('context is required.');
  83176. }
  83177. if (borderWidthInPixels < 0) {
  83178. throw new DeveloperError('borderWidthInPixels must be greater than or equal to zero.');
  83179. }
  83180. if (initialSize.x < 1 || initialSize.y < 1) {
  83181. throw new DeveloperError('initialSize must be greater than zero.');
  83182. }
  83183. this._context = options.context;
  83184. this._pixelFormat = defaultValue(options.pixelFormat, PixelFormat.RGBA);
  83185. this._borderWidthInPixels = borderWidthInPixels;
  83186. this._textureCoordinates = [];
  83187. this._guid = createGuid();
  83188. this._idHash = {};
  83189. this._initialSize = initialSize;
  83190. this._root = undefined;
  83191. }
  83192. defineProperties(TextureAtlas.prototype, {
  83193. /**
  83194. * The amount of spacing between adjacent images in pixels.
  83195. * @memberof TextureAtlas.prototype
  83196. * @type {Number}
  83197. */
  83198. borderWidthInPixels : {
  83199. get : function() {
  83200. return this._borderWidthInPixels;
  83201. }
  83202. },
  83203. /**
  83204. * An array of {@link BoundingRectangle} texture coordinate regions for all the images in the texture atlas.
  83205. * The x and y values of the rectangle correspond to the bottom-left corner of the texture coordinate.
  83206. * The coordinates are in the order that the corresponding images were added to the atlas.
  83207. * @memberof TextureAtlas.prototype
  83208. * @type {BoundingRectangle[]}
  83209. */
  83210. textureCoordinates : {
  83211. get : function() {
  83212. return this._textureCoordinates;
  83213. }
  83214. },
  83215. /**
  83216. * The texture that all of the images are being written to.
  83217. * @memberof TextureAtlas.prototype
  83218. * @type {Texture}
  83219. */
  83220. texture : {
  83221. get : function() {
  83222. if(!defined(this._texture)) {
  83223. this._texture = new Texture({
  83224. context : this._context,
  83225. width : this._initialSize.x,
  83226. height : this._initialSize.y,
  83227. pixelFormat : this._pixelFormat
  83228. });
  83229. }
  83230. return this._texture;
  83231. }
  83232. },
  83233. /**
  83234. * The number of images in the texture atlas. This value increases
  83235. * every time addImage or addImages is called.
  83236. * Texture coordinates are subject to change if the texture atlas resizes, so it is
  83237. * important to check {@link TextureAtlas#getGUID} before using old values.
  83238. * @memberof TextureAtlas.prototype
  83239. * @type {Number}
  83240. */
  83241. numberOfImages : {
  83242. get : function() {
  83243. return this._textureCoordinates.length;
  83244. }
  83245. },
  83246. /**
  83247. * The atlas' globally unique identifier (GUID).
  83248. * The GUID changes whenever the texture atlas is modified.
  83249. * Classes that use a texture atlas should check if the GUID
  83250. * has changed before processing the atlas data.
  83251. * @memberof TextureAtlas.prototype
  83252. * @type {String}
  83253. */
  83254. guid : {
  83255. get : function() {
  83256. return this._guid;
  83257. }
  83258. }
  83259. });
  83260. // Builds a larger texture and copies the old texture into the new one.
  83261. function resizeAtlas(textureAtlas, image) {
  83262. var context = textureAtlas._context;
  83263. var numImages = textureAtlas.numberOfImages;
  83264. var scalingFactor = 2.0;
  83265. var borderWidthInPixels = textureAtlas._borderWidthInPixels;
  83266. if (numImages > 0) {
  83267. var oldAtlasWidth = textureAtlas._texture.width;
  83268. var oldAtlasHeight = textureAtlas._texture.height;
  83269. var atlasWidth = scalingFactor * (oldAtlasWidth + image.width + borderWidthInPixels);
  83270. var atlasHeight = scalingFactor * (oldAtlasHeight + image.height + borderWidthInPixels);
  83271. var widthRatio = oldAtlasWidth / atlasWidth;
  83272. var heightRatio = oldAtlasHeight / atlasHeight;
  83273. // Create new node structure, putting the old root node in the bottom left.
  83274. var nodeBottomRight = new TextureAtlasNode(new Cartesian2(oldAtlasWidth + borderWidthInPixels, borderWidthInPixels), new Cartesian2(atlasWidth, oldAtlasHeight));
  83275. var nodeBottomHalf = new TextureAtlasNode(new Cartesian2(), new Cartesian2(atlasWidth, oldAtlasHeight), textureAtlas._root, nodeBottomRight);
  83276. var nodeTopHalf = new TextureAtlasNode(new Cartesian2(borderWidthInPixels, oldAtlasHeight + borderWidthInPixels), new Cartesian2(atlasWidth, atlasHeight));
  83277. var nodeMain = new TextureAtlasNode(new Cartesian2(), new Cartesian2(atlasWidth, atlasHeight), nodeBottomHalf, nodeTopHalf);
  83278. // Resize texture coordinates.
  83279. for (var i = 0; i < textureAtlas._textureCoordinates.length; i++) {
  83280. var texCoord = textureAtlas._textureCoordinates[i];
  83281. if (defined(texCoord)) {
  83282. texCoord.x *= widthRatio;
  83283. texCoord.y *= heightRatio;
  83284. texCoord.width *= widthRatio;
  83285. texCoord.height *= heightRatio;
  83286. }
  83287. }
  83288. // Copy larger texture.
  83289. var newTexture = new Texture({
  83290. context : textureAtlas._context,
  83291. width : atlasWidth,
  83292. height : atlasHeight,
  83293. pixelFormat : textureAtlas._pixelFormat
  83294. });
  83295. var framebuffer = new Framebuffer({
  83296. context : context,
  83297. colorTextures : [textureAtlas._texture],
  83298. destroyAttachments : false
  83299. });
  83300. framebuffer._bind();
  83301. newTexture.copyFromFramebuffer(0, 0, 0, 0, atlasWidth, atlasHeight);
  83302. framebuffer._unBind();
  83303. framebuffer.destroy();
  83304. textureAtlas._texture = textureAtlas._texture && textureAtlas._texture.destroy();
  83305. textureAtlas._texture = newTexture;
  83306. textureAtlas._root = nodeMain;
  83307. } else {
  83308. // First image exceeds initialSize
  83309. var initialWidth = scalingFactor * (image.width + 2 * borderWidthInPixels);
  83310. var initialHeight = scalingFactor * (image.height + 2 * borderWidthInPixels);
  83311. if(initialWidth < textureAtlas._initialSize.x) {
  83312. initialWidth = textureAtlas._initialSize.x;
  83313. }
  83314. if(initialHeight < textureAtlas._initialSize.y) {
  83315. initialHeight = textureAtlas._initialSize.y;
  83316. }
  83317. textureAtlas._texture = textureAtlas._texture && textureAtlas._texture.destroy();
  83318. textureAtlas._texture = new Texture({
  83319. context : textureAtlas._context,
  83320. width : initialWidth,
  83321. height : initialHeight,
  83322. pixelFormat : textureAtlas._pixelFormat
  83323. });
  83324. textureAtlas._root = new TextureAtlasNode(new Cartesian2(borderWidthInPixels, borderWidthInPixels),
  83325. new Cartesian2(initialWidth, initialHeight));
  83326. }
  83327. }
  83328. // A recursive function that finds the best place to insert
  83329. // a new image based on existing image 'nodes'.
  83330. // Inspired by: http://blackpawn.com/texts/lightmaps/default.html
  83331. function findNode(textureAtlas, node, image) {
  83332. if (!defined(node)) {
  83333. return undefined;
  83334. }
  83335. // If a leaf node
  83336. if (!defined(node.childNode1) &&
  83337. !defined(node.childNode2)) {
  83338. // Node already contains an image, don't add to it.
  83339. if (defined(node.imageIndex)) {
  83340. return undefined;
  83341. }
  83342. var nodeWidth = node.topRight.x - node.bottomLeft.x;
  83343. var nodeHeight = node.topRight.y - node.bottomLeft.y;
  83344. var widthDifference = nodeWidth - image.width;
  83345. var heightDifference = nodeHeight - image.height;
  83346. // Node is smaller than the image.
  83347. if (widthDifference < 0 || heightDifference < 0) {
  83348. return undefined;
  83349. }
  83350. // If the node is the same size as the image, return the node
  83351. if (widthDifference === 0 && heightDifference === 0) {
  83352. return node;
  83353. }
  83354. // Vertical split (childNode1 = left half, childNode2 = right half).
  83355. if (widthDifference > heightDifference) {
  83356. node.childNode1 = new TextureAtlasNode(new Cartesian2(node.bottomLeft.x, node.bottomLeft.y), new Cartesian2(node.bottomLeft.x + image.width, node.topRight.y));
  83357. // Only make a second child if the border gives enough space.
  83358. var childNode2BottomLeftX = node.bottomLeft.x + image.width + textureAtlas._borderWidthInPixels;
  83359. if (childNode2BottomLeftX < node.topRight.x) {
  83360. node.childNode2 = new TextureAtlasNode(new Cartesian2(childNode2BottomLeftX, node.bottomLeft.y), new Cartesian2(node.topRight.x, node.topRight.y));
  83361. }
  83362. }
  83363. // Horizontal split (childNode1 = bottom half, childNode2 = top half).
  83364. else {
  83365. node.childNode1 = new TextureAtlasNode(new Cartesian2(node.bottomLeft.x, node.bottomLeft.y), new Cartesian2(node.topRight.x, node.bottomLeft.y + image.height));
  83366. // Only make a second child if the border gives enough space.
  83367. var childNode2BottomLeftY = node.bottomLeft.y + image.height + textureAtlas._borderWidthInPixels;
  83368. if (childNode2BottomLeftY < node.topRight.y) {
  83369. node.childNode2 = new TextureAtlasNode(new Cartesian2(node.bottomLeft.x, childNode2BottomLeftY), new Cartesian2(node.topRight.x, node.topRight.y));
  83370. }
  83371. }
  83372. return findNode(textureAtlas, node.childNode1, image);
  83373. }
  83374. // If not a leaf node
  83375. return findNode(textureAtlas, node.childNode1, image) ||
  83376. findNode(textureAtlas, node.childNode2, image);
  83377. }
  83378. // Adds image of given index to the texture atlas. Called from addImage and addImages.
  83379. function addImage(textureAtlas, image, index) {
  83380. var node = findNode(textureAtlas, textureAtlas._root, image);
  83381. if (defined(node)) {
  83382. // Found a node that can hold the image.
  83383. node.imageIndex = index;
  83384. // Add texture coordinate and write to texture
  83385. var atlasWidth = textureAtlas._texture.width;
  83386. var atlasHeight = textureAtlas._texture.height;
  83387. var nodeWidth = node.topRight.x - node.bottomLeft.x;
  83388. var nodeHeight = node.topRight.y - node.bottomLeft.y;
  83389. var x = node.bottomLeft.x / atlasWidth;
  83390. var y = node.bottomLeft.y / atlasHeight;
  83391. var w = nodeWidth / atlasWidth;
  83392. var h = nodeHeight / atlasHeight;
  83393. textureAtlas._textureCoordinates[index] = new BoundingRectangle(x, y, w, h);
  83394. textureAtlas._texture.copyFrom(image, node.bottomLeft.x, node.bottomLeft.y);
  83395. } else {
  83396. // No node found, must resize the texture atlas.
  83397. resizeAtlas(textureAtlas, image);
  83398. addImage(textureAtlas, image, index);
  83399. }
  83400. textureAtlas._guid = createGuid();
  83401. }
  83402. /**
  83403. * Adds an image to the atlas. If the image is already in the atlas, the atlas is unchanged and
  83404. * the existing index is used.
  83405. *
  83406. * @param {String} id An identifier to detect whether the image already exists in the atlas.
  83407. * @param {Image|Canvas|String|Promise|TextureAtlas~CreateImageCallback} image An image or canvas to add to the texture atlas,
  83408. * or a URL to an Image, or a Promise for an image, or a function that creates an image.
  83409. * @returns {Promise.<Number>} A Promise for the image index.
  83410. */
  83411. TextureAtlas.prototype.addImage = function(id, image) {
  83412. if (!defined(id)) {
  83413. throw new DeveloperError('id is required.');
  83414. }
  83415. if (!defined(image)) {
  83416. throw new DeveloperError('image is required.');
  83417. }
  83418. var indexPromise = this._idHash[id];
  83419. if (defined(indexPromise)) {
  83420. // we're already aware of this source
  83421. return indexPromise;
  83422. }
  83423. // not in atlas, create the promise for the index
  83424. if (typeof image === 'function') {
  83425. // if image is a function, call it
  83426. image = image(id);
  83427. if (!defined(image)) {
  83428. throw new DeveloperError('image is required.');
  83429. }
  83430. } else if (typeof image === 'string') {
  83431. // if image is a string, load it as an image
  83432. image = loadImage(image);
  83433. }
  83434. var that = this;
  83435. indexPromise = when(image, function(image) {
  83436. if (that.isDestroyed()) {
  83437. return -1;
  83438. }
  83439. var index = that.numberOfImages;
  83440. addImage(that, image, index);
  83441. return index;
  83442. });
  83443. // store the promise
  83444. this._idHash[id] = indexPromise;
  83445. return indexPromise;
  83446. };
  83447. /**
  83448. * Add a sub-region of an existing atlas image as additional image indices.
  83449. *
  83450. * @param {String} id The identifier of the existing image.
  83451. * @param {BoundingRectangle} subRegion An {@link BoundingRectangle} sub-region measured in pixels from the bottom-left.
  83452. *
  83453. * @returns {Promise.<Number>} A Promise for the image index.
  83454. */
  83455. TextureAtlas.prototype.addSubRegion = function(id, subRegion) {
  83456. if (!defined(id)) {
  83457. throw new DeveloperError('id is required.');
  83458. }
  83459. if (!defined(subRegion)) {
  83460. throw new DeveloperError('subRegion is required.');
  83461. }
  83462. var indexPromise = this._idHash[id];
  83463. if (!defined(indexPromise)) {
  83464. throw new RuntimeError('image with id "' + id + '" not found in the atlas.');
  83465. }
  83466. var that = this;
  83467. return when(indexPromise, function(index) {
  83468. if (index === -1) {
  83469. // the atlas is destroyed
  83470. return -1;
  83471. }
  83472. var atlasWidth = that._texture.width;
  83473. var atlasHeight = that._texture.height;
  83474. var numImages = that.numberOfImages;
  83475. var baseRegion = that._textureCoordinates[index];
  83476. var x = baseRegion.x + (subRegion.x / atlasWidth);
  83477. var y = baseRegion.y + (subRegion.y / atlasHeight);
  83478. var w = subRegion.width / atlasWidth;
  83479. var h = subRegion.height / atlasHeight;
  83480. that._textureCoordinates.push(new BoundingRectangle(x, y, w, h));
  83481. that._guid = createGuid();
  83482. return numImages;
  83483. });
  83484. };
  83485. /**
  83486. * Returns true if this object was destroyed; otherwise, false.
  83487. * <br /><br />
  83488. * If this object was destroyed, it should not be used; calling any function other than
  83489. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  83490. *
  83491. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  83492. *
  83493. * @see TextureAtlas#destroy
  83494. */
  83495. TextureAtlas.prototype.isDestroyed = function() {
  83496. return false;
  83497. };
  83498. /**
  83499. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  83500. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  83501. * <br /><br />
  83502. * Once an object is destroyed, it should not be used; calling any function other than
  83503. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  83504. * assign the return value (<code>undefined</code>) to the object as done in the example.
  83505. *
  83506. * @returns {undefined}
  83507. *
  83508. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  83509. *
  83510. *
  83511. * @example
  83512. * atlas = atlas && atlas.destroy();
  83513. *
  83514. * @see TextureAtlas#isDestroyed
  83515. */
  83516. TextureAtlas.prototype.destroy = function() {
  83517. this._texture = this._texture && this._texture.destroy();
  83518. return destroyObject(this);
  83519. };
  83520. /**
  83521. * A function that creates an image.
  83522. * @callback TextureAtlas~CreateImageCallback
  83523. * @param {String} id The identifier of the image to load.
  83524. * @returns {Image|Promise} The image, or a promise that will resolve to an image.
  83525. */
  83526. return TextureAtlas;
  83527. });
  83528. /*global define*/
  83529. define('Scene/BillboardCollection',[
  83530. '../Core/AttributeCompression',
  83531. '../Core/BoundingSphere',
  83532. '../Core/Cartesian2',
  83533. '../Core/Cartesian3',
  83534. '../Core/Color',
  83535. '../Core/ComponentDatatype',
  83536. '../Core/defaultValue',
  83537. '../Core/defined',
  83538. '../Core/defineProperties',
  83539. '../Core/destroyObject',
  83540. '../Core/DeveloperError',
  83541. '../Core/EncodedCartesian3',
  83542. '../Core/IndexDatatype',
  83543. '../Core/Math',
  83544. '../Core/Matrix4',
  83545. '../Core/WebGLConstants',
  83546. '../Renderer/Buffer',
  83547. '../Renderer/BufferUsage',
  83548. '../Renderer/DrawCommand',
  83549. '../Renderer/Pass',
  83550. '../Renderer/RenderState',
  83551. '../Renderer/ShaderProgram',
  83552. '../Renderer/ShaderSource',
  83553. '../Renderer/VertexArrayFacade',
  83554. '../Shaders/BillboardCollectionFS',
  83555. '../Shaders/BillboardCollectionVS',
  83556. './Billboard',
  83557. './BlendingState',
  83558. './HeightReference',
  83559. './HorizontalOrigin',
  83560. './SceneMode',
  83561. './TextureAtlas',
  83562. './VerticalOrigin'
  83563. ], function(
  83564. AttributeCompression,
  83565. BoundingSphere,
  83566. Cartesian2,
  83567. Cartesian3,
  83568. Color,
  83569. ComponentDatatype,
  83570. defaultValue,
  83571. defined,
  83572. defineProperties,
  83573. destroyObject,
  83574. DeveloperError,
  83575. EncodedCartesian3,
  83576. IndexDatatype,
  83577. CesiumMath,
  83578. Matrix4,
  83579. WebGLConstants,
  83580. Buffer,
  83581. BufferUsage,
  83582. DrawCommand,
  83583. Pass,
  83584. RenderState,
  83585. ShaderProgram,
  83586. ShaderSource,
  83587. VertexArrayFacade,
  83588. BillboardCollectionFS,
  83589. BillboardCollectionVS,
  83590. Billboard,
  83591. BlendingState,
  83592. HeightReference,
  83593. HorizontalOrigin,
  83594. SceneMode,
  83595. TextureAtlas,
  83596. VerticalOrigin) {
  83597. 'use strict';
  83598. var SHOW_INDEX = Billboard.SHOW_INDEX;
  83599. var POSITION_INDEX = Billboard.POSITION_INDEX;
  83600. var PIXEL_OFFSET_INDEX = Billboard.PIXEL_OFFSET_INDEX;
  83601. var EYE_OFFSET_INDEX = Billboard.EYE_OFFSET_INDEX;
  83602. var HORIZONTAL_ORIGIN_INDEX = Billboard.HORIZONTAL_ORIGIN_INDEX;
  83603. var VERTICAL_ORIGIN_INDEX = Billboard.VERTICAL_ORIGIN_INDEX;
  83604. var SCALE_INDEX = Billboard.SCALE_INDEX;
  83605. var IMAGE_INDEX_INDEX = Billboard.IMAGE_INDEX_INDEX;
  83606. var COLOR_INDEX = Billboard.COLOR_INDEX;
  83607. var ROTATION_INDEX = Billboard.ROTATION_INDEX;
  83608. var ALIGNED_AXIS_INDEX = Billboard.ALIGNED_AXIS_INDEX;
  83609. var SCALE_BY_DISTANCE_INDEX = Billboard.SCALE_BY_DISTANCE_INDEX;
  83610. var TRANSLUCENCY_BY_DISTANCE_INDEX = Billboard.TRANSLUCENCY_BY_DISTANCE_INDEX;
  83611. var PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX = Billboard.PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX;
  83612. var DISTANCE_DISPLAY_CONDITION_INDEX = Billboard.DISTANCE_DISPLAY_CONDITION_INDEX;
  83613. var NUMBER_OF_PROPERTIES = Billboard.NUMBER_OF_PROPERTIES;
  83614. var attributeLocations;
  83615. var attributeLocationsBatched = {
  83616. positionHighAndScale : 0,
  83617. positionLowAndRotation : 1,
  83618. compressedAttribute0 : 2, // pixel offset, translate, horizontal origin, vertical origin, show, direction, texture coordinates
  83619. compressedAttribute1 : 3, // aligned axis, translucency by distance, image width
  83620. compressedAttribute2 : 4, // image height, color, pick color, size in meters, valid aligned axis, 13 bits free
  83621. eyeOffset : 5, // 4 bytes free
  83622. scaleByDistance : 6,
  83623. pixelOffsetScaleByDistance : 7,
  83624. distanceDisplayCondition : 8
  83625. };
  83626. var attributeLocationsInstanced = {
  83627. direction : 0,
  83628. positionHighAndScale : 1,
  83629. positionLowAndRotation : 2, // texture offset in w
  83630. compressedAttribute0 : 3,
  83631. compressedAttribute1 : 4,
  83632. compressedAttribute2 : 5,
  83633. eyeOffset : 6, // texture range in w
  83634. scaleByDistance : 7,
  83635. pixelOffsetScaleByDistance : 8,
  83636. distanceDisplayCondition : 9
  83637. };
  83638. /**
  83639. * A renderable collection of billboards. Billboards are viewport-aligned
  83640. * images positioned in the 3D scene.
  83641. * <br /><br />
  83642. * <div align='center'>
  83643. * <img src='images/Billboard.png' width='400' height='300' /><br />
  83644. * Example billboards
  83645. * </div>
  83646. * <br /><br />
  83647. * Billboards are added and removed from the collection using {@link BillboardCollection#add}
  83648. * and {@link BillboardCollection#remove}. Billboards in a collection automatically share textures
  83649. * for images with the same identifier.
  83650. *
  83651. * @alias BillboardCollection
  83652. * @constructor
  83653. *
  83654. * @param {Object} [options] Object with the following properties:
  83655. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms each billboard from model to world coordinates.
  83656. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
  83657. * @param {Scene} [options.scene] Must be passed in for billboards that use the height reference property or will be depth tested against the globe.
  83658. *
  83659. * @performance For best performance, prefer a few collections, each with many billboards, to
  83660. * many collections with only a few billboards each. Organize collections so that billboards
  83661. * with the same update frequency are in the same collection, i.e., billboards that do not
  83662. * change should be in one collection; billboards that change every frame should be in another
  83663. * collection; and so on.
  83664. *
  83665. * @see BillboardCollection#add
  83666. * @see BillboardCollection#remove
  83667. * @see Billboard
  83668. * @see LabelCollection
  83669. *
  83670. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Billboards.html|Cesium Sandcastle Billboard Demo}
  83671. *
  83672. * @example
  83673. * // Create a billboard collection with two billboards
  83674. * var billboards = scene.primitives.add(new Cesium.BillboardCollection());
  83675. * billboards.add({
  83676. * position : new Cesium.Cartesian3(1.0, 2.0, 3.0),
  83677. * image : 'url/to/image'
  83678. * });
  83679. * billboards.add({
  83680. * position : new Cesium.Cartesian3(4.0, 5.0, 6.0),
  83681. * image : 'url/to/another/image'
  83682. * });
  83683. */
  83684. function BillboardCollection(options) {
  83685. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  83686. this._scene = options.scene;
  83687. this._textureAtlas = undefined;
  83688. this._textureAtlasGUID = undefined;
  83689. this._destroyTextureAtlas = true;
  83690. this._sp = undefined;
  83691. this._rs = undefined;
  83692. this._vaf = undefined;
  83693. this._spPick = undefined;
  83694. this._billboards = [];
  83695. this._billboardsToUpdate = [];
  83696. this._billboardsToUpdateIndex = 0;
  83697. this._billboardsRemoved = false;
  83698. this._createVertexArray = false;
  83699. this._shaderRotation = false;
  83700. this._compiledShaderRotation = false;
  83701. this._compiledShaderRotationPick = false;
  83702. this._shaderAlignedAxis = false;
  83703. this._compiledShaderAlignedAxis = false;
  83704. this._compiledShaderAlignedAxisPick = false;
  83705. this._shaderScaleByDistance = false;
  83706. this._compiledShaderScaleByDistance = false;
  83707. this._compiledShaderScaleByDistancePick = false;
  83708. this._shaderTranslucencyByDistance = false;
  83709. this._compiledShaderTranslucencyByDistance = false;
  83710. this._compiledShaderTranslucencyByDistancePick = false;
  83711. this._shaderPixelOffsetScaleByDistance = false;
  83712. this._compiledShaderPixelOffsetScaleByDistance = false;
  83713. this._compiledShaderPixelOffsetScaleByDistancePick = false;
  83714. this._shaderDistanceDisplayCondition = false;
  83715. this._compiledShaderDistanceDisplayCondition = false;
  83716. this._compiledShaderDistanceDisplayConditionPick = false;
  83717. this._propertiesChanged = new Uint32Array(NUMBER_OF_PROPERTIES);
  83718. this._maxSize = 0.0;
  83719. this._maxEyeOffset = 0.0;
  83720. this._maxScale = 1.0;
  83721. this._maxPixelOffset = 0.0;
  83722. this._allHorizontalCenter = true;
  83723. this._allVerticalCenter = true;
  83724. this._allSizedInMeters = true;
  83725. this._baseVolume = new BoundingSphere();
  83726. this._baseVolumeWC = new BoundingSphere();
  83727. this._baseVolume2D = new BoundingSphere();
  83728. this._boundingVolume = new BoundingSphere();
  83729. this._boundingVolumeDirty = false;
  83730. this._colorCommands = [];
  83731. this._pickCommands = [];
  83732. /**
  83733. * The 4x4 transformation matrix that transforms each billboard in this collection from model to world coordinates.
  83734. * When this is the identity matrix, the billboards are drawn in world coordinates, i.e., Earth's WGS84 coordinates.
  83735. * Local reference frames can be used by providing a different transformation matrix, like that returned
  83736. * by {@link Transforms.eastNorthUpToFixedFrame}.
  83737. *
  83738. * @type {Matrix4}
  83739. * @default {@link Matrix4.IDENTITY}
  83740. *
  83741. *
  83742. * @example
  83743. * var center = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883);
  83744. * billboards.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
  83745. * billboards.add({
  83746. * image : 'url/to/image',
  83747. * position : new Cesium.Cartesian3(0.0, 0.0, 0.0) // center
  83748. * });
  83749. * billboards.add({
  83750. * image : 'url/to/image',
  83751. * position : new Cesium.Cartesian3(1000000.0, 0.0, 0.0) // east
  83752. * });
  83753. * billboards.add({
  83754. * image : 'url/to/image',
  83755. * position : new Cesium.Cartesian3(0.0, 1000000.0, 0.0) // north
  83756. * });
  83757. * billboards.add({
  83758. * image : 'url/to/image',
  83759. * position : new Cesium.Cartesian3(0.0, 0.0, 1000000.0) // up
  83760. * });
  83761. *
  83762. * @see Transforms.eastNorthUpToFixedFrame
  83763. */
  83764. this.modelMatrix = Matrix4.clone(defaultValue(options.modelMatrix, Matrix4.IDENTITY));
  83765. this._modelMatrix = Matrix4.clone(Matrix4.IDENTITY);
  83766. /**
  83767. * This property is for debugging only; it is not for production use nor is it optimized.
  83768. * <p>
  83769. * Draws the bounding sphere for each draw command in the primitive.
  83770. * </p>
  83771. *
  83772. * @type {Boolean}
  83773. *
  83774. * @default false
  83775. */
  83776. this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false);
  83777. this._mode = SceneMode.SCENE3D;
  83778. // The buffer usage for each attribute is determined based on the usage of the attribute over time.
  83779. this._buffersUsage = [
  83780. BufferUsage.STATIC_DRAW, // SHOW_INDEX
  83781. BufferUsage.STATIC_DRAW, // POSITION_INDEX
  83782. BufferUsage.STATIC_DRAW, // PIXEL_OFFSET_INDEX
  83783. BufferUsage.STATIC_DRAW, // EYE_OFFSET_INDEX
  83784. BufferUsage.STATIC_DRAW, // HORIZONTAL_ORIGIN_INDEX
  83785. BufferUsage.STATIC_DRAW, // VERTICAL_ORIGIN_INDEX
  83786. BufferUsage.STATIC_DRAW, // SCALE_INDEX
  83787. BufferUsage.STATIC_DRAW, // IMAGE_INDEX_INDEX
  83788. BufferUsage.STATIC_DRAW, // COLOR_INDEX
  83789. BufferUsage.STATIC_DRAW, // ROTATION_INDEX
  83790. BufferUsage.STATIC_DRAW, // ALIGNED_AXIS_INDEX
  83791. BufferUsage.STATIC_DRAW, // SCALE_BY_DISTANCE_INDEX
  83792. BufferUsage.STATIC_DRAW, // TRANSLUCENCY_BY_DISTANCE_INDEX
  83793. BufferUsage.STATIC_DRAW, // PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX
  83794. BufferUsage.STATIC_DRAW // DISTANCE_DISPLAY_CONDITION_INDEX
  83795. ];
  83796. var that = this;
  83797. this._uniforms = {
  83798. u_atlas : function() {
  83799. return that._textureAtlas.texture;
  83800. }
  83801. };
  83802. var scene = this._scene;
  83803. if (defined(scene)) {
  83804. this._removeCallbackFunc = scene.terrainProviderChanged.addEventListener(function() {
  83805. var billboards = this._billboards;
  83806. var length = billboards.length;
  83807. for (var i=0;i<length;++i) {
  83808. billboards[i]._updateClamping();
  83809. }
  83810. }, this);
  83811. }
  83812. }
  83813. defineProperties(BillboardCollection.prototype, {
  83814. /**
  83815. * Returns the number of billboards in this collection. This is commonly used with
  83816. * {@link BillboardCollection#get} to iterate over all the billboards
  83817. * in the collection.
  83818. * @memberof BillboardCollection.prototype
  83819. * @type {Number}
  83820. */
  83821. length : {
  83822. get : function() {
  83823. removeBillboards(this);
  83824. return this._billboards.length;
  83825. }
  83826. },
  83827. /**
  83828. * Gets or sets the textureAtlas.
  83829. * @memberof BillboardCollection.prototype
  83830. * @type {TextureAtlas}
  83831. * @private
  83832. */
  83833. textureAtlas : {
  83834. get : function() {
  83835. return this._textureAtlas;
  83836. },
  83837. set : function(value) {
  83838. if (this._textureAtlas !== value) {
  83839. this._textureAtlas = this._destroyTextureAtlas && this._textureAtlas && this._textureAtlas.destroy();
  83840. this._textureAtlas = value;
  83841. this._createVertexArray = true; // New per-billboard texture coordinates
  83842. }
  83843. }
  83844. },
  83845. /**
  83846. * Gets or sets a value which determines if the texture atlas is
  83847. * destroyed when the collection is destroyed.
  83848. *
  83849. * If the texture atlas is used by more than one collection, set this to <code>false</code>,
  83850. * and explicitly destroy the atlas to avoid attempting to destroy it multiple times.
  83851. *
  83852. * @memberof BillboardCollection.prototype
  83853. * @type {Boolean}
  83854. * @private
  83855. *
  83856. * @example
  83857. * // Set destroyTextureAtlas
  83858. * // Destroy a billboard collection but not its texture atlas.
  83859. *
  83860. * var atlas = new TextureAtlas({
  83861. * scene : scene,
  83862. * images : images
  83863. * });
  83864. * billboards.textureAtlas = atlas;
  83865. * billboards.destroyTextureAtlas = false;
  83866. * billboards = billboards.destroy();
  83867. * console.log(atlas.isDestroyed()); // False
  83868. */
  83869. destroyTextureAtlas : {
  83870. get : function() {
  83871. return this._destroyTextureAtlas;
  83872. },
  83873. set : function(value) {
  83874. this._destroyTextureAtlas = value;
  83875. }
  83876. }
  83877. });
  83878. function destroyBillboards(billboards) {
  83879. var length = billboards.length;
  83880. for (var i = 0; i < length; ++i) {
  83881. if (billboards[i]) {
  83882. billboards[i]._destroy();
  83883. }
  83884. }
  83885. }
  83886. /**
  83887. * Creates and adds a billboard with the specified initial properties to the collection.
  83888. * The added billboard is returned so it can be modified or removed from the collection later.
  83889. *
  83890. * @param {Object}[billboard] A template describing the billboard's properties as shown in Example 1.
  83891. * @returns {Billboard} The billboard that was added to the collection.
  83892. *
  83893. * @performance Calling <code>add</code> is expected constant time. However, the collection's vertex buffer
  83894. * is rewritten - an <code>O(n)</code> operation that also incurs CPU to GPU overhead. For
  83895. * best performance, add as many billboards as possible before calling <code>update</code>.
  83896. *
  83897. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  83898. *
  83899. *
  83900. * @example
  83901. * // Example 1: Add a billboard, specifying all the default values.
  83902. * var b = billboards.add({
  83903. * show : true,
  83904. * position : Cesium.Cartesian3.ZERO,
  83905. * pixelOffset : Cesium.Cartesian2.ZERO,
  83906. * eyeOffset : Cesium.Cartesian3.ZERO,
  83907. * heightReference : Cesium.HeightReference.NONE,
  83908. * horizontalOrigin : Cesium.HorizontalOrigin.CENTER,
  83909. * verticalOrigin : Cesium.VerticalOrigin.CENTER,
  83910. * scale : 1.0,
  83911. * image : 'url/to/image',
  83912. * imageSubRegion : undefined,
  83913. * color : Cesium.Color.WHITE,
  83914. * id : undefined,
  83915. * rotation : 0.0,
  83916. * alignedAxis : Cesium.Cartesian3.ZERO,
  83917. * width : undefined,
  83918. * height : undefined,
  83919. * scaleByDistance : undefined,
  83920. * translucencyByDistance : undefined,
  83921. * pixelOffsetScaleByDistance : undefined,
  83922. * sizeInMeters : false,
  83923. * distanceDisplayCondition : undefined
  83924. * });
  83925. *
  83926. * @example
  83927. * // Example 2: Specify only the billboard's cartographic position.
  83928. * var b = billboards.add({
  83929. * position : Cesium.Cartesian3.fromDegrees(longitude, latitude, height)
  83930. * });
  83931. *
  83932. * @see BillboardCollection#remove
  83933. * @see BillboardCollection#removeAll
  83934. */
  83935. BillboardCollection.prototype.add = function(billboard) {
  83936. var b = new Billboard(billboard, this);
  83937. b._index = this._billboards.length;
  83938. this._billboards.push(b);
  83939. this._createVertexArray = true;
  83940. return b;
  83941. };
  83942. /**
  83943. * Removes a billboard from the collection.
  83944. *
  83945. * @param {Billboard} billboard The billboard to remove.
  83946. * @returns {Boolean} <code>true</code> if the billboard was removed; <code>false</code> if the billboard was not found in the collection.
  83947. *
  83948. * @performance Calling <code>remove</code> is expected constant time. However, the collection's vertex buffer
  83949. * is rewritten - an <code>O(n)</code> operation that also incurs CPU to GPU overhead. For
  83950. * best performance, remove as many billboards as possible before calling <code>update</code>.
  83951. * If you intend to temporarily hide a billboard, it is usually more efficient to call
  83952. * {@link Billboard#show} instead of removing and re-adding the billboard.
  83953. *
  83954. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  83955. *
  83956. *
  83957. * @example
  83958. * var b = billboards.add(...);
  83959. * billboards.remove(b); // Returns true
  83960. *
  83961. * @see BillboardCollection#add
  83962. * @see BillboardCollection#removeAll
  83963. * @see Billboard#show
  83964. */
  83965. BillboardCollection.prototype.remove = function(billboard) {
  83966. if (this.contains(billboard)) {
  83967. this._billboards[billboard._index] = null; // Removed later
  83968. this._billboardsRemoved = true;
  83969. this._createVertexArray = true;
  83970. billboard._destroy();
  83971. return true;
  83972. }
  83973. return false;
  83974. };
  83975. /**
  83976. * Removes all billboards from the collection.
  83977. *
  83978. * @performance <code>O(n)</code>. It is more efficient to remove all the billboards
  83979. * from a collection and then add new ones than to create a new collection entirely.
  83980. *
  83981. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  83982. *
  83983. *
  83984. * @example
  83985. * billboards.add(...);
  83986. * billboards.add(...);
  83987. * billboards.removeAll();
  83988. *
  83989. * @see BillboardCollection#add
  83990. * @see BillboardCollection#remove
  83991. */
  83992. BillboardCollection.prototype.removeAll = function() {
  83993. destroyBillboards(this._billboards);
  83994. this._billboards = [];
  83995. this._billboardsToUpdate = [];
  83996. this._billboardsToUpdateIndex = 0;
  83997. this._billboardsRemoved = false;
  83998. this._createVertexArray = true;
  83999. };
  84000. function removeBillboards(billboardCollection) {
  84001. if (billboardCollection._billboardsRemoved) {
  84002. billboardCollection._billboardsRemoved = false;
  84003. var newBillboards = [];
  84004. var billboards = billboardCollection._billboards;
  84005. var length = billboards.length;
  84006. for (var i = 0, j = 0; i < length; ++i) {
  84007. var billboard = billboards[i];
  84008. if (billboard) {
  84009. billboard._index = j++;
  84010. newBillboards.push(billboard);
  84011. }
  84012. }
  84013. billboardCollection._billboards = newBillboards;
  84014. }
  84015. }
  84016. BillboardCollection.prototype._updateBillboard = function(billboard, propertyChanged) {
  84017. if (!billboard._dirty) {
  84018. this._billboardsToUpdate[this._billboardsToUpdateIndex++] = billboard;
  84019. }
  84020. ++this._propertiesChanged[propertyChanged];
  84021. };
  84022. /**
  84023. * Check whether this collection contains a given billboard.
  84024. *
  84025. * @param {Billboard} [billboard] The billboard to check for.
  84026. * @returns {Boolean} true if this collection contains the billboard, false otherwise.
  84027. *
  84028. * @see BillboardCollection#get
  84029. */
  84030. BillboardCollection.prototype.contains = function(billboard) {
  84031. return defined(billboard) && billboard._billboardCollection === this;
  84032. };
  84033. /**
  84034. * Returns the billboard in the collection at the specified index. Indices are zero-based
  84035. * and increase as billboards are added. Removing a billboard shifts all billboards after
  84036. * it to the left, changing their indices. This function is commonly used with
  84037. * {@link BillboardCollection#length} to iterate over all the billboards
  84038. * in the collection.
  84039. *
  84040. * @param {Number} index The zero-based index of the billboard.
  84041. * @returns {Billboard} The billboard at the specified index.
  84042. *
  84043. * @performance Expected constant time. If billboards were removed from the collection and
  84044. * {@link BillboardCollection#update} was not called, an implicit <code>O(n)</code>
  84045. * operation is performed.
  84046. *
  84047. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  84048. *
  84049. *
  84050. * @example
  84051. * // Toggle the show property of every billboard in the collection
  84052. * var len = billboards.length;
  84053. * for (var i = 0; i < len; ++i) {
  84054. * var b = billboards.get(i);
  84055. * b.show = !b.show;
  84056. * }
  84057. *
  84058. * @see BillboardCollection#length
  84059. */
  84060. BillboardCollection.prototype.get = function(index) {
  84061. if (!defined(index)) {
  84062. throw new DeveloperError('index is required.');
  84063. }
  84064. removeBillboards(this);
  84065. return this._billboards[index];
  84066. };
  84067. var getIndexBuffer;
  84068. function getIndexBufferBatched(context) {
  84069. var sixteenK = 16 * 1024;
  84070. var indexBuffer = context.cache.billboardCollection_indexBufferBatched;
  84071. if (defined(indexBuffer)) {
  84072. return indexBuffer;
  84073. }
  84074. // Subtract 6 because the last index is reserverd for primitive restart.
  84075. // https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.18
  84076. var length = sixteenK * 6 - 6;
  84077. var indices = new Uint16Array(length);
  84078. for (var i = 0, j = 0; i < length; i += 6, j += 4) {
  84079. indices[i] = j;
  84080. indices[i + 1] = j + 1;
  84081. indices[i + 2] = j + 2;
  84082. indices[i + 3] = j + 0;
  84083. indices[i + 4] = j + 2;
  84084. indices[i + 5] = j + 3;
  84085. }
  84086. // PERFORMANCE_IDEA: Should we reference count billboard collections, and eventually delete this?
  84087. // Is this too much memory to allocate up front? Should we dynamically grow it?
  84088. indexBuffer = Buffer.createIndexBuffer({
  84089. context : context,
  84090. typedArray : indices,
  84091. usage : BufferUsage.STATIC_DRAW,
  84092. indexDatatype : IndexDatatype.UNSIGNED_SHORT
  84093. });
  84094. indexBuffer.vertexArrayDestroyable = false;
  84095. context.cache.billboardCollection_indexBufferBatched = indexBuffer;
  84096. return indexBuffer;
  84097. }
  84098. function getIndexBufferInstanced(context) {
  84099. var indexBuffer = context.cache.billboardCollection_indexBufferInstanced;
  84100. if (defined(indexBuffer)) {
  84101. return indexBuffer;
  84102. }
  84103. indexBuffer = Buffer.createIndexBuffer({
  84104. context : context,
  84105. typedArray : new Uint16Array([0, 1, 2, 0, 2, 3]),
  84106. usage : BufferUsage.STATIC_DRAW,
  84107. indexDatatype : IndexDatatype.UNSIGNED_SHORT
  84108. });
  84109. indexBuffer.vertexArrayDestroyable = false;
  84110. context.cache.billboardCollection_indexBufferInstanced = indexBuffer;
  84111. return indexBuffer;
  84112. }
  84113. function getVertexBufferInstanced(context) {
  84114. var vertexBuffer = context.cache.billboardCollection_vertexBufferInstanced;
  84115. if (defined(vertexBuffer)) {
  84116. return vertexBuffer;
  84117. }
  84118. vertexBuffer = Buffer.createVertexBuffer({
  84119. context : context,
  84120. typedArray : new Float32Array([0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0]),
  84121. usage : BufferUsage.STATIC_DRAW
  84122. });
  84123. vertexBuffer.vertexArrayDestroyable = false;
  84124. context.cache.billboardCollection_vertexBufferInstanced = vertexBuffer;
  84125. return vertexBuffer;
  84126. }
  84127. BillboardCollection.prototype.computeNewBuffersUsage = function() {
  84128. var buffersUsage = this._buffersUsage;
  84129. var usageChanged = false;
  84130. var properties = this._propertiesChanged;
  84131. for ( var k = 0; k < NUMBER_OF_PROPERTIES; ++k) {
  84132. var newUsage = (properties[k] === 0) ? BufferUsage.STATIC_DRAW : BufferUsage.STREAM_DRAW;
  84133. usageChanged = usageChanged || (buffersUsage[k] !== newUsage);
  84134. buffersUsage[k] = newUsage;
  84135. }
  84136. return usageChanged;
  84137. };
  84138. function createVAF(context, numberOfBillboards, buffersUsage, instanced) {
  84139. var attributes = [{
  84140. index : attributeLocations.positionHighAndScale,
  84141. componentsPerAttribute : 4,
  84142. componentDatatype : ComponentDatatype.FLOAT,
  84143. usage : buffersUsage[POSITION_INDEX]
  84144. }, {
  84145. index : attributeLocations.positionLowAndRotation,
  84146. componentsPerAttribute : 4,
  84147. componentDatatype : ComponentDatatype.FLOAT,
  84148. usage : buffersUsage[POSITION_INDEX]
  84149. }, {
  84150. index : attributeLocations.compressedAttribute0,
  84151. componentsPerAttribute : 4,
  84152. componentDatatype : ComponentDatatype.FLOAT,
  84153. usage : buffersUsage[PIXEL_OFFSET_INDEX]
  84154. }, {
  84155. index : attributeLocations.compressedAttribute1,
  84156. componentsPerAttribute : 4,
  84157. componentDatatype : ComponentDatatype.FLOAT,
  84158. usage : buffersUsage[TRANSLUCENCY_BY_DISTANCE_INDEX]
  84159. }, {
  84160. index : attributeLocations.compressedAttribute2,
  84161. componentsPerAttribute : 4,
  84162. componentDatatype : ComponentDatatype.FLOAT,
  84163. usage : buffersUsage[COLOR_INDEX]
  84164. }, {
  84165. index : attributeLocations.eyeOffset,
  84166. componentsPerAttribute : 4,
  84167. componentDatatype : ComponentDatatype.FLOAT,
  84168. usage : buffersUsage[EYE_OFFSET_INDEX]
  84169. }, {
  84170. index : attributeLocations.scaleByDistance,
  84171. componentsPerAttribute : 4,
  84172. componentDatatype : ComponentDatatype.FLOAT,
  84173. usage : buffersUsage[SCALE_BY_DISTANCE_INDEX]
  84174. }, {
  84175. index : attributeLocations.pixelOffsetScaleByDistance,
  84176. componentsPerAttribute : 4,
  84177. componentDatatype : ComponentDatatype.FLOAT,
  84178. usage : buffersUsage[PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX]
  84179. }, {
  84180. index : attributeLocations.distanceDisplayCondition,
  84181. componentsPerAttribute : 2,
  84182. componentDatatype : ComponentDatatype.FLOAT,
  84183. usage : buffersUsage[DISTANCE_DISPLAY_CONDITION_INDEX]
  84184. }];
  84185. // Instancing requires one non-instanced attribute.
  84186. if (instanced) {
  84187. attributes.push({
  84188. index : attributeLocations.direction,
  84189. componentsPerAttribute : 2,
  84190. componentDatatype : ComponentDatatype.FLOAT,
  84191. vertexBuffer : getVertexBufferInstanced(context)
  84192. });
  84193. }
  84194. // When instancing is enabled, only one vertex is needed for each billboard.
  84195. var sizeInVertices = instanced ? numberOfBillboards : 4 * numberOfBillboards;
  84196. return new VertexArrayFacade(context, attributes, sizeInVertices, instanced);
  84197. }
  84198. ///////////////////////////////////////////////////////////////////////////
  84199. // Four vertices per billboard. Each has the same position, etc., but a different screen-space direction vector.
  84200. // PERFORMANCE_IDEA: Save memory if a property is the same for all billboards, use a latched attribute state,
  84201. // instead of storing it in a vertex buffer.
  84202. var writePositionScratch = new EncodedCartesian3();
  84203. function writePositionScaleAndRotation(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) {
  84204. var i;
  84205. var positionHighWriter = vafWriters[attributeLocations.positionHighAndScale];
  84206. var positionLowWriter = vafWriters[attributeLocations.positionLowAndRotation];
  84207. var position = billboard._getActualPosition();
  84208. if (billboardCollection._mode === SceneMode.SCENE3D) {
  84209. BoundingSphere.expand(billboardCollection._baseVolume, position, billboardCollection._baseVolume);
  84210. billboardCollection._boundingVolumeDirty = true;
  84211. }
  84212. EncodedCartesian3.fromCartesian(position, writePositionScratch);
  84213. var scale = billboard.scale;
  84214. var rotation = billboard.rotation;
  84215. if (rotation !== 0.0) {
  84216. billboardCollection._shaderRotation = true;
  84217. }
  84218. billboardCollection._maxScale = Math.max(billboardCollection._maxScale, scale);
  84219. var high = writePositionScratch.high;
  84220. var low = writePositionScratch.low;
  84221. if (billboardCollection._instanced) {
  84222. i = billboard._index;
  84223. positionHighWriter(i, high.x, high.y, high.z, scale);
  84224. positionLowWriter(i, low.x, low.y, low.z, rotation);
  84225. } else {
  84226. i = billboard._index * 4;
  84227. positionHighWriter(i + 0, high.x, high.y, high.z, scale);
  84228. positionHighWriter(i + 1, high.x, high.y, high.z, scale);
  84229. positionHighWriter(i + 2, high.x, high.y, high.z, scale);
  84230. positionHighWriter(i + 3, high.x, high.y, high.z, scale);
  84231. positionLowWriter(i + 0, low.x, low.y, low.z, rotation);
  84232. positionLowWriter(i + 1, low.x, low.y, low.z, rotation);
  84233. positionLowWriter(i + 2, low.x, low.y, low.z, rotation);
  84234. positionLowWriter(i + 3, low.x, low.y, low.z, rotation);
  84235. }
  84236. }
  84237. var scratchCartesian2 = new Cartesian2();
  84238. var UPPER_BOUND = 32768.0; // 2^15
  84239. var LEFT_SHIFT16 = 65536.0; // 2^16
  84240. var LEFT_SHIFT8 = 256.0; // 2^8
  84241. var LEFT_SHIFT7 = 128.0;
  84242. var LEFT_SHIFT5 = 32.0;
  84243. var LEFT_SHIFT3 = 8.0;
  84244. var LEFT_SHIFT2 = 4.0;
  84245. var RIGHT_SHIFT8 = 1.0 / 256.0;
  84246. var LOWER_LEFT = 0.0;
  84247. var LOWER_RIGHT = 2.0;
  84248. var UPPER_RIGHT = 3.0;
  84249. var UPPER_LEFT = 1.0;
  84250. function writeCompressedAttrib0(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) {
  84251. var i;
  84252. var writer = vafWriters[attributeLocations.compressedAttribute0];
  84253. var pixelOffset = billboard.pixelOffset;
  84254. var pixelOffsetX = pixelOffset.x;
  84255. var pixelOffsetY = pixelOffset.y;
  84256. var translate = billboard._translate;
  84257. var translateX = translate.x;
  84258. var translateY = translate.y;
  84259. billboardCollection._maxPixelOffset = Math.max(billboardCollection._maxPixelOffset, Math.abs(pixelOffsetX + translateX), Math.abs(-pixelOffsetY + translateY));
  84260. var horizontalOrigin = billboard.horizontalOrigin;
  84261. var verticalOrigin = billboard._verticalOrigin;
  84262. var show = billboard.show && billboard.clusterShow;
  84263. // If the color alpha is zero, do not show this billboard. This lets us avoid providing
  84264. // color during the pick pass and also eliminates a discard in the fragment shader.
  84265. if (billboard.color.alpha === 0.0) {
  84266. show = false;
  84267. }
  84268. // Raw billboards don't distinguish between BASELINE and BOTTOM, only LabelCollection does that.
  84269. if (verticalOrigin === VerticalOrigin.BASELINE) {
  84270. verticalOrigin = VerticalOrigin.BOTTOM;
  84271. }
  84272. billboardCollection._allHorizontalCenter = billboardCollection._allHorizontalCenter && horizontalOrigin === HorizontalOrigin.CENTER;
  84273. billboardCollection._allVerticalCenter = billboardCollection._allVerticalCenter && verticalOrigin === VerticalOrigin.CENTER;
  84274. var bottomLeftX = 0;
  84275. var bottomLeftY = 0;
  84276. var width = 0;
  84277. var height = 0;
  84278. var index = billboard._imageIndex;
  84279. if (index !== -1) {
  84280. var imageRectangle = textureAtlasCoordinates[index];
  84281. if (!defined(imageRectangle)) {
  84282. throw new DeveloperError('Invalid billboard image index: ' + index);
  84283. }
  84284. bottomLeftX = imageRectangle.x;
  84285. bottomLeftY = imageRectangle.y;
  84286. width = imageRectangle.width;
  84287. height = imageRectangle.height;
  84288. }
  84289. var topRightX = bottomLeftX + width;
  84290. var topRightY = bottomLeftY + height;
  84291. var compressed0 = Math.floor(CesiumMath.clamp(pixelOffsetX, -UPPER_BOUND, UPPER_BOUND) + UPPER_BOUND) * LEFT_SHIFT7;
  84292. compressed0 += (horizontalOrigin + 1.0) * LEFT_SHIFT5;
  84293. compressed0 += (verticalOrigin + 1.0) * LEFT_SHIFT3;
  84294. compressed0 += (show ? 1.0 : 0.0) * LEFT_SHIFT2;
  84295. var compressed1 = Math.floor(CesiumMath.clamp(pixelOffsetY, -UPPER_BOUND, UPPER_BOUND) + UPPER_BOUND) * LEFT_SHIFT8;
  84296. var compressed2 = Math.floor(CesiumMath.clamp(translateX, -UPPER_BOUND, UPPER_BOUND) + UPPER_BOUND) * LEFT_SHIFT8;
  84297. var tempTanslateY = (CesiumMath.clamp(translateY, -UPPER_BOUND, UPPER_BOUND) + UPPER_BOUND) * RIGHT_SHIFT8;
  84298. var upperTranslateY = Math.floor(tempTanslateY);
  84299. var lowerTranslateY = Math.floor((tempTanslateY - upperTranslateY) * LEFT_SHIFT8);
  84300. compressed1 += upperTranslateY;
  84301. compressed2 += lowerTranslateY;
  84302. scratchCartesian2.x = bottomLeftX;
  84303. scratchCartesian2.y = bottomLeftY;
  84304. var compressedTexCoordsLL = AttributeCompression.compressTextureCoordinates(scratchCartesian2);
  84305. scratchCartesian2.x = topRightX;
  84306. var compressedTexCoordsLR = AttributeCompression.compressTextureCoordinates(scratchCartesian2);
  84307. scratchCartesian2.y = topRightY;
  84308. var compressedTexCoordsUR = AttributeCompression.compressTextureCoordinates(scratchCartesian2);
  84309. scratchCartesian2.x = bottomLeftX;
  84310. var compressedTexCoordsUL = AttributeCompression.compressTextureCoordinates(scratchCartesian2);
  84311. if (billboardCollection._instanced) {
  84312. i = billboard._index;
  84313. writer(i, compressed0, compressed1, compressed2, compressedTexCoordsLL);
  84314. } else {
  84315. i = billboard._index * 4;
  84316. writer(i + 0, compressed0 + LOWER_LEFT, compressed1, compressed2, compressedTexCoordsLL);
  84317. writer(i + 1, compressed0 + LOWER_RIGHT, compressed1, compressed2, compressedTexCoordsLR);
  84318. writer(i + 2, compressed0 + UPPER_RIGHT, compressed1, compressed2, compressedTexCoordsUR);
  84319. writer(i + 3, compressed0 + UPPER_LEFT, compressed1, compressed2, compressedTexCoordsUL);
  84320. }
  84321. }
  84322. function writeCompressedAttrib1(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) {
  84323. var i;
  84324. var writer = vafWriters[attributeLocations.compressedAttribute1];
  84325. var alignedAxis = billboard.alignedAxis;
  84326. if (!Cartesian3.equals(alignedAxis, Cartesian3.ZERO)) {
  84327. billboardCollection._shaderAlignedAxis = true;
  84328. }
  84329. var near = 0.0;
  84330. var nearValue = 1.0;
  84331. var far = 1.0;
  84332. var farValue = 1.0;
  84333. var translucency = billboard.translucencyByDistance;
  84334. if (defined(translucency)) {
  84335. near = translucency.near;
  84336. nearValue = translucency.nearValue;
  84337. far = translucency.far;
  84338. farValue = translucency.farValue;
  84339. if (nearValue !== 1.0 || farValue !== 1.0) {
  84340. // translucency by distance calculation in shader need not be enabled
  84341. // until a billboard with near and far !== 1.0 is found
  84342. billboardCollection._shaderTranslucencyByDistance = true;
  84343. }
  84344. }
  84345. var width = 0;
  84346. var index = billboard._imageIndex;
  84347. if (index !== -1) {
  84348. var imageRectangle = textureAtlasCoordinates[index];
  84349. if (!defined(imageRectangle)) {
  84350. throw new DeveloperError('Invalid billboard image index: ' + index);
  84351. }
  84352. width = imageRectangle.width;
  84353. }
  84354. var textureWidth = billboardCollection._textureAtlas.texture.width;
  84355. var imageWidth = Math.round(defaultValue(billboard.width, textureWidth * width));
  84356. billboardCollection._maxSize = Math.max(billboardCollection._maxSize, imageWidth);
  84357. var compressed0 = CesiumMath.clamp(imageWidth, 0.0, LEFT_SHIFT16);
  84358. var compressed1 = 0.0;
  84359. if (Math.abs(Cartesian3.magnitudeSquared(alignedAxis) - 1.0) < CesiumMath.EPSILON6) {
  84360. compressed1 = AttributeCompression.octEncodeFloat(alignedAxis);
  84361. }
  84362. nearValue = CesiumMath.clamp(nearValue, 0.0, 1.0);
  84363. nearValue = nearValue === 1.0 ? 255.0 : (nearValue * 255.0) | 0;
  84364. compressed0 = compressed0 * LEFT_SHIFT8 + nearValue;
  84365. farValue = CesiumMath.clamp(farValue, 0.0, 1.0);
  84366. farValue = farValue === 1.0 ? 255.0 : (farValue * 255.0) | 0;
  84367. compressed1 = compressed1 * LEFT_SHIFT8 + farValue;
  84368. if (billboardCollection._instanced) {
  84369. i = billboard._index;
  84370. writer(i, compressed0, compressed1, near, far);
  84371. } else {
  84372. i = billboard._index * 4;
  84373. writer(i + 0, compressed0, compressed1, near, far);
  84374. writer(i + 1, compressed0, compressed1, near, far);
  84375. writer(i + 2, compressed0, compressed1, near, far);
  84376. writer(i + 3, compressed0, compressed1, near, far);
  84377. }
  84378. }
  84379. function writeCompressedAttrib2(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) {
  84380. var i;
  84381. var writer = vafWriters[attributeLocations.compressedAttribute2];
  84382. var color = billboard.color;
  84383. var pickColor = billboard.getPickId(context).color;
  84384. var sizeInMeters = billboard.sizeInMeters ? 1.0 : 0.0;
  84385. var validAlignedAxis = Math.abs(Cartesian3.magnitudeSquared(billboard.alignedAxis) - 1.0) < CesiumMath.EPSILON6 ? 1.0 : 0.0;
  84386. billboardCollection._allSizedInMeters = billboardCollection._allSizedInMeters && sizeInMeters === 1.0;
  84387. var height = 0;
  84388. var index = billboard._imageIndex;
  84389. if (index !== -1) {
  84390. var imageRectangle = textureAtlasCoordinates[index];
  84391. if (!defined(imageRectangle)) {
  84392. throw new DeveloperError('Invalid billboard image index: ' + index);
  84393. }
  84394. height = imageRectangle.height;
  84395. }
  84396. var dimensions = billboardCollection._textureAtlas.texture.dimensions;
  84397. var imageHeight = Math.round(defaultValue(billboard.height, dimensions.y * height));
  84398. billboardCollection._maxSize = Math.max(billboardCollection._maxSize, imageHeight);
  84399. var red = Color.floatToByte(color.red);
  84400. var green = Color.floatToByte(color.green);
  84401. var blue = Color.floatToByte(color.blue);
  84402. var compressed0 = red * LEFT_SHIFT16 + green * LEFT_SHIFT8 + blue;
  84403. red = Color.floatToByte(pickColor.red);
  84404. green = Color.floatToByte(pickColor.green);
  84405. blue = Color.floatToByte(pickColor.blue);
  84406. var compressed1 = red * LEFT_SHIFT16 + green * LEFT_SHIFT8 + blue;
  84407. var compressed2 = Color.floatToByte(color.alpha) * LEFT_SHIFT16 + Color.floatToByte(pickColor.alpha) * LEFT_SHIFT8;
  84408. compressed2 += sizeInMeters * 2.0 + validAlignedAxis;
  84409. if (billboardCollection._instanced) {
  84410. i = billboard._index;
  84411. writer(i, compressed0, compressed1, compressed2, imageHeight);
  84412. } else {
  84413. i = billboard._index * 4;
  84414. writer(i + 0, compressed0, compressed1, compressed2, imageHeight);
  84415. writer(i + 1, compressed0, compressed1, compressed2, imageHeight);
  84416. writer(i + 2, compressed0, compressed1, compressed2, imageHeight);
  84417. writer(i + 3, compressed0, compressed1, compressed2, imageHeight);
  84418. }
  84419. }
  84420. function writeEyeOffset(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) {
  84421. var i;
  84422. var writer = vafWriters[attributeLocations.eyeOffset];
  84423. var eyeOffset = billboard.eyeOffset;
  84424. // For billboards that are clamped to ground, move it slightly closer to the camera
  84425. var eyeOffsetZ = eyeOffset.z;
  84426. if (billboard._heightReference !== HeightReference.NONE) {
  84427. eyeOffsetZ *= 1.005;
  84428. }
  84429. billboardCollection._maxEyeOffset = Math.max(billboardCollection._maxEyeOffset, Math.abs(eyeOffset.x), Math.abs(eyeOffset.y), Math.abs(eyeOffsetZ));
  84430. if (billboardCollection._instanced) {
  84431. var width = 0;
  84432. var height = 0;
  84433. var index = billboard._imageIndex;
  84434. if (index !== -1) {
  84435. var imageRectangle = textureAtlasCoordinates[index];
  84436. if (!defined(imageRectangle)) {
  84437. throw new DeveloperError('Invalid billboard image index: ' + index);
  84438. }
  84439. width = imageRectangle.width;
  84440. height = imageRectangle.height;
  84441. }
  84442. scratchCartesian2.x = width;
  84443. scratchCartesian2.y = height;
  84444. var compressedTexCoordsRange = AttributeCompression.compressTextureCoordinates(scratchCartesian2);
  84445. i = billboard._index;
  84446. writer(i, eyeOffset.x, eyeOffset.y, eyeOffsetZ, compressedTexCoordsRange);
  84447. } else {
  84448. i = billboard._index * 4;
  84449. writer(i + 0, eyeOffset.x, eyeOffset.y, eyeOffsetZ, 0.0);
  84450. writer(i + 1, eyeOffset.x, eyeOffset.y, eyeOffsetZ, 0.0);
  84451. writer(i + 2, eyeOffset.x, eyeOffset.y, eyeOffsetZ, 0.0);
  84452. writer(i + 3, eyeOffset.x, eyeOffset.y, eyeOffsetZ, 0.0);
  84453. }
  84454. }
  84455. function writeScaleByDistance(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) {
  84456. var i;
  84457. var writer = vafWriters[attributeLocations.scaleByDistance];
  84458. var near = 0.0;
  84459. var nearValue = 1.0;
  84460. var far = 1.0;
  84461. var farValue = 1.0;
  84462. var scale = billboard.scaleByDistance;
  84463. if (defined(scale)) {
  84464. near = scale.near;
  84465. nearValue = scale.nearValue;
  84466. far = scale.far;
  84467. farValue = scale.farValue;
  84468. if (nearValue !== 1.0 || farValue !== 1.0) {
  84469. // scale by distance calculation in shader need not be enabled
  84470. // until a billboard with near and far !== 1.0 is found
  84471. billboardCollection._shaderScaleByDistance = true;
  84472. }
  84473. }
  84474. if (billboardCollection._instanced) {
  84475. i = billboard._index;
  84476. writer(i, near, nearValue, far, farValue);
  84477. } else {
  84478. i = billboard._index * 4;
  84479. writer(i + 0, near, nearValue, far, farValue);
  84480. writer(i + 1, near, nearValue, far, farValue);
  84481. writer(i + 2, near, nearValue, far, farValue);
  84482. writer(i + 3, near, nearValue, far, farValue);
  84483. }
  84484. }
  84485. function writePixelOffsetScaleByDistance(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) {
  84486. var i;
  84487. var writer = vafWriters[attributeLocations.pixelOffsetScaleByDistance];
  84488. var near = 0.0;
  84489. var nearValue = 1.0;
  84490. var far = 1.0;
  84491. var farValue = 1.0;
  84492. var pixelOffsetScale = billboard.pixelOffsetScaleByDistance;
  84493. if (defined(pixelOffsetScale)) {
  84494. near = pixelOffsetScale.near;
  84495. nearValue = pixelOffsetScale.nearValue;
  84496. far = pixelOffsetScale.far;
  84497. farValue = pixelOffsetScale.farValue;
  84498. if (nearValue !== 1.0 || farValue !== 1.0) {
  84499. // pixelOffsetScale by distance calculation in shader need not be enabled
  84500. // until a billboard with near and far !== 1.0 is found
  84501. billboardCollection._shaderPixelOffsetScaleByDistance = true;
  84502. }
  84503. }
  84504. if (billboardCollection._instanced) {
  84505. i = billboard._index;
  84506. writer(i, near, nearValue, far, farValue);
  84507. } else {
  84508. i = billboard._index * 4;
  84509. writer(i + 0, near, nearValue, far, farValue);
  84510. writer(i + 1, near, nearValue, far, farValue);
  84511. writer(i + 2, near, nearValue, far, farValue);
  84512. writer(i + 3, near, nearValue, far, farValue);
  84513. }
  84514. }
  84515. function writeDistanceDisplayCondition(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) {
  84516. var i;
  84517. var writer = vafWriters[attributeLocations.distanceDisplayCondition];
  84518. var near = 0.0;
  84519. var far = Number.MAX_VALUE;
  84520. var distanceDisplayCondition = billboard.distanceDisplayCondition;
  84521. if (defined(distanceDisplayCondition)) {
  84522. near = distanceDisplayCondition.near;
  84523. far = distanceDisplayCondition.far;
  84524. billboardCollection._shaderDistanceDisplayCondition = true;
  84525. }
  84526. if (billboardCollection._instanced) {
  84527. i = billboard._index;
  84528. writer(i, near, far);
  84529. } else {
  84530. i = billboard._index * 4;
  84531. writer(i + 0, near, far);
  84532. writer(i + 1, near, far);
  84533. writer(i + 2, near, far);
  84534. writer(i + 3, near, far);
  84535. }
  84536. }
  84537. function writeBillboard(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) {
  84538. writePositionScaleAndRotation(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard);
  84539. writeCompressedAttrib0(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard);
  84540. writeCompressedAttrib1(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard);
  84541. writeCompressedAttrib2(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard);
  84542. writeEyeOffset(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard);
  84543. writeScaleByDistance(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard);
  84544. writePixelOffsetScaleByDistance(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard);
  84545. writeDistanceDisplayCondition(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard);
  84546. }
  84547. function recomputeActualPositions(billboardCollection, billboards, length, frameState, modelMatrix, recomputeBoundingVolume) {
  84548. var boundingVolume;
  84549. if (frameState.mode === SceneMode.SCENE3D) {
  84550. boundingVolume = billboardCollection._baseVolume;
  84551. billboardCollection._boundingVolumeDirty = true;
  84552. } else {
  84553. boundingVolume = billboardCollection._baseVolume2D;
  84554. }
  84555. var positions = [];
  84556. for ( var i = 0; i < length; ++i) {
  84557. var billboard = billboards[i];
  84558. var position = billboard.position;
  84559. var actualPosition = Billboard._computeActualPosition(billboard, position, frameState, modelMatrix);
  84560. if (defined(actualPosition)) {
  84561. billboard._setActualPosition(actualPosition);
  84562. if (recomputeBoundingVolume) {
  84563. positions.push(actualPosition);
  84564. } else {
  84565. BoundingSphere.expand(boundingVolume, actualPosition, boundingVolume);
  84566. }
  84567. }
  84568. }
  84569. if (recomputeBoundingVolume) {
  84570. BoundingSphere.fromPoints(positions, boundingVolume);
  84571. }
  84572. }
  84573. function updateMode(billboardCollection, frameState) {
  84574. var mode = frameState.mode;
  84575. var billboards = billboardCollection._billboards;
  84576. var billboardsToUpdate = billboardCollection._billboardsToUpdate;
  84577. var modelMatrix = billboardCollection._modelMatrix;
  84578. if (billboardCollection._createVertexArray ||
  84579. billboardCollection._mode !== mode ||
  84580. mode !== SceneMode.SCENE3D &&
  84581. !Matrix4.equals(modelMatrix, billboardCollection.modelMatrix)) {
  84582. billboardCollection._mode = mode;
  84583. Matrix4.clone(billboardCollection.modelMatrix, modelMatrix);
  84584. billboardCollection._createVertexArray = true;
  84585. if (mode === SceneMode.SCENE3D || mode === SceneMode.SCENE2D || mode === SceneMode.COLUMBUS_VIEW) {
  84586. recomputeActualPositions(billboardCollection, billboards, billboards.length, frameState, modelMatrix, true);
  84587. }
  84588. } else if (mode === SceneMode.MORPHING) {
  84589. recomputeActualPositions(billboardCollection, billboards, billboards.length, frameState, modelMatrix, true);
  84590. } else if (mode === SceneMode.SCENE2D || mode === SceneMode.COLUMBUS_VIEW) {
  84591. recomputeActualPositions(billboardCollection, billboardsToUpdate, billboardCollection._billboardsToUpdateIndex, frameState, modelMatrix, false);
  84592. }
  84593. }
  84594. function updateBoundingVolume(collection, frameState, boundingVolume) {
  84595. var pixelScale = 1.0;
  84596. if (!collection._allSizedInMeters || collection._maxPixelOffset !== 0.0) {
  84597. pixelScale = frameState.camera.getPixelSize(boundingVolume, frameState.context.drawingBufferWidth, frameState.context.drawingBufferHeight);
  84598. }
  84599. var size = pixelScale * collection._maxScale * collection._maxSize * 2.0;
  84600. if (collection._allHorizontalCenter && collection._allVerticalCenter ) {
  84601. size *= 0.5;
  84602. }
  84603. var offset = pixelScale * collection._maxPixelOffset + collection._maxEyeOffset;
  84604. boundingVolume.radius += size + offset;
  84605. }
  84606. var scratchWriterArray = [];
  84607. /**
  84608. * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
  84609. * get the draw commands needed to render this primitive.
  84610. * <p>
  84611. * Do not call this function directly. This is documented just to
  84612. * list the exceptions that may be propagated when the scene is rendered:
  84613. * </p>
  84614. *
  84615. * @exception {RuntimeError} image with id must be in the atlas.
  84616. */
  84617. BillboardCollection.prototype.update = function(frameState) {
  84618. removeBillboards(this);
  84619. var billboards = this._billboards;
  84620. var billboardsLength = billboards.length;
  84621. var context = frameState.context;
  84622. this._instanced = context.instancedArrays;
  84623. attributeLocations = this._instanced ? attributeLocationsInstanced : attributeLocationsBatched;
  84624. getIndexBuffer = this._instanced ? getIndexBufferInstanced : getIndexBufferBatched;
  84625. var textureAtlas = this._textureAtlas;
  84626. if (!defined(textureAtlas)) {
  84627. textureAtlas = this._textureAtlas = new TextureAtlas({
  84628. context : context
  84629. });
  84630. for (var ii = 0; ii < billboardsLength; ++ii) {
  84631. billboards[ii]._loadImage();
  84632. }
  84633. }
  84634. var textureAtlasCoordinates = textureAtlas.textureCoordinates;
  84635. if (textureAtlasCoordinates.length === 0) {
  84636. // Can't write billboard vertices until we have texture coordinates
  84637. // provided by a texture atlas
  84638. return;
  84639. }
  84640. updateMode(this, frameState);
  84641. billboards = this._billboards;
  84642. billboardsLength = billboards.length;
  84643. var billboardsToUpdate = this._billboardsToUpdate;
  84644. var billboardsToUpdateLength = this._billboardsToUpdateIndex;
  84645. var properties = this._propertiesChanged;
  84646. var textureAtlasGUID = textureAtlas.guid;
  84647. var createVertexArray = this._createVertexArray || this._textureAtlasGUID !== textureAtlasGUID;
  84648. this._textureAtlasGUID = textureAtlasGUID;
  84649. var vafWriters;
  84650. var pass = frameState.passes;
  84651. var picking = pass.pick;
  84652. // PERFORMANCE_IDEA: Round robin multiple buffers.
  84653. if (createVertexArray || (!picking && this.computeNewBuffersUsage())) {
  84654. this._createVertexArray = false;
  84655. for (var k = 0; k < NUMBER_OF_PROPERTIES; ++k) {
  84656. properties[k] = 0;
  84657. }
  84658. this._vaf = this._vaf && this._vaf.destroy();
  84659. if (billboardsLength > 0) {
  84660. // PERFORMANCE_IDEA: Instead of creating a new one, resize like std::vector.
  84661. this._vaf = createVAF(context, billboardsLength, this._buffersUsage, this._instanced);
  84662. vafWriters = this._vaf.writers;
  84663. // Rewrite entire buffer if billboards were added or removed.
  84664. for (var i = 0; i < billboardsLength; ++i) {
  84665. var billboard = this._billboards[i];
  84666. billboard._dirty = false; // In case it needed an update.
  84667. writeBillboard(this, context, textureAtlasCoordinates, vafWriters, billboard);
  84668. }
  84669. // Different billboard collections share the same index buffer.
  84670. this._vaf.commit(getIndexBuffer(context));
  84671. }
  84672. this._billboardsToUpdateIndex = 0;
  84673. } else {
  84674. // Billboards were modified, but none were added or removed.
  84675. if (billboardsToUpdateLength > 0) {
  84676. var writers = scratchWriterArray;
  84677. writers.length = 0;
  84678. if (properties[POSITION_INDEX] || properties[ROTATION_INDEX] || properties[SCALE_INDEX]) {
  84679. writers.push(writePositionScaleAndRotation);
  84680. }
  84681. if (properties[IMAGE_INDEX_INDEX] || properties[PIXEL_OFFSET_INDEX] || properties[HORIZONTAL_ORIGIN_INDEX] || properties[VERTICAL_ORIGIN_INDEX] || properties[SHOW_INDEX]) {
  84682. writers.push(writeCompressedAttrib0);
  84683. if (this._instanced) {
  84684. writers.push(writeEyeOffset);
  84685. }
  84686. }
  84687. if (properties[IMAGE_INDEX_INDEX] || properties[ALIGNED_AXIS_INDEX] || properties[TRANSLUCENCY_BY_DISTANCE_INDEX]) {
  84688. writers.push(writeCompressedAttrib1);
  84689. writers.push(writeCompressedAttrib2);
  84690. }
  84691. if (properties[IMAGE_INDEX_INDEX] || properties[COLOR_INDEX]) {
  84692. writers.push(writeCompressedAttrib2);
  84693. }
  84694. if (properties[EYE_OFFSET_INDEX]) {
  84695. writers.push(writeEyeOffset);
  84696. }
  84697. if (properties[SCALE_BY_DISTANCE_INDEX]) {
  84698. writers.push(writeScaleByDistance);
  84699. }
  84700. if (properties[PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX]) {
  84701. writers.push(writePixelOffsetScaleByDistance);
  84702. }
  84703. if (properties[DISTANCE_DISPLAY_CONDITION_INDEX]) {
  84704. writers.push(writeDistanceDisplayCondition);
  84705. }
  84706. var numWriters = writers.length;
  84707. vafWriters = this._vaf.writers;
  84708. if ((billboardsToUpdateLength / billboardsLength) > 0.1) {
  84709. // If more than 10% of billboard change, rewrite the entire buffer.
  84710. // PERFORMANCE_IDEA: I totally made up 10% :).
  84711. for (var m = 0; m < billboardsToUpdateLength; ++m) {
  84712. var b = billboardsToUpdate[m];
  84713. b._dirty = false;
  84714. for ( var n = 0; n < numWriters; ++n) {
  84715. writers[n](this, context, textureAtlasCoordinates, vafWriters, b);
  84716. }
  84717. }
  84718. this._vaf.commit(getIndexBuffer(context));
  84719. } else {
  84720. for (var h = 0; h < billboardsToUpdateLength; ++h) {
  84721. var bb = billboardsToUpdate[h];
  84722. bb._dirty = false;
  84723. for ( var o = 0; o < numWriters; ++o) {
  84724. writers[o](this, context, textureAtlasCoordinates, vafWriters, bb);
  84725. }
  84726. if (this._instanced) {
  84727. this._vaf.subCommit(bb._index, 1);
  84728. } else {
  84729. this._vaf.subCommit(bb._index * 4, 4);
  84730. }
  84731. }
  84732. this._vaf.endSubCommits();
  84733. }
  84734. this._billboardsToUpdateIndex = 0;
  84735. }
  84736. }
  84737. // If the number of total billboards ever shrinks considerably
  84738. // Truncate billboardsToUpdate so that we free memory that we're
  84739. // not going to be using.
  84740. if (billboardsToUpdateLength > billboardsLength * 1.5) {
  84741. billboardsToUpdate.length = billboardsLength;
  84742. }
  84743. if (!defined(this._vaf) || !defined(this._vaf.va)) {
  84744. return;
  84745. }
  84746. if (this._boundingVolumeDirty) {
  84747. this._boundingVolumeDirty = false;
  84748. BoundingSphere.transform(this._baseVolume, this.modelMatrix, this._baseVolumeWC);
  84749. }
  84750. var boundingVolume;
  84751. var modelMatrix = Matrix4.IDENTITY;
  84752. if (frameState.mode === SceneMode.SCENE3D) {
  84753. modelMatrix = this.modelMatrix;
  84754. boundingVolume = BoundingSphere.clone(this._baseVolumeWC, this._boundingVolume);
  84755. } else {
  84756. boundingVolume = BoundingSphere.clone(this._baseVolume2D, this._boundingVolume);
  84757. }
  84758. updateBoundingVolume(this, frameState, boundingVolume);
  84759. var va;
  84760. var vaLength;
  84761. var command;
  84762. var vs;
  84763. var fs;
  84764. var j;
  84765. var commandList = frameState.commandList;
  84766. if (pass.render) {
  84767. var colorList = this._colorCommands;
  84768. if (!defined(this._rs)) {
  84769. this._rs = RenderState.fromCache({
  84770. depthTest : {
  84771. enabled : true,
  84772. func : WebGLConstants.LEQUAL // Allows label glyphs and billboards to overlap.
  84773. },
  84774. blending : BlendingState.ALPHA_BLEND
  84775. });
  84776. }
  84777. if (!defined(this._sp) ||
  84778. (this._shaderRotation !== this._compiledShaderRotation) ||
  84779. (this._shaderAlignedAxis !== this._compiledShaderAlignedAxis) ||
  84780. (this._shaderScaleByDistance !== this._compiledShaderScaleByDistance) ||
  84781. (this._shaderTranslucencyByDistance !== this._compiledShaderTranslucencyByDistance) ||
  84782. (this._shaderPixelOffsetScaleByDistance !== this._compiledShaderPixelOffsetScaleByDistance) ||
  84783. (this._shaderDistanceDisplayCondition !== this._compiledShaderDistanceDisplayCondition)) {
  84784. vs = new ShaderSource({
  84785. sources : [BillboardCollectionVS]
  84786. });
  84787. if (this._instanced) {
  84788. vs.defines.push('INSTANCED');
  84789. }
  84790. if (this._shaderRotation) {
  84791. vs.defines.push('ROTATION');
  84792. }
  84793. if (this._shaderAlignedAxis) {
  84794. vs.defines.push('ALIGNED_AXIS');
  84795. }
  84796. if (this._shaderScaleByDistance) {
  84797. vs.defines.push('EYE_DISTANCE_SCALING');
  84798. }
  84799. if (this._shaderTranslucencyByDistance) {
  84800. vs.defines.push('EYE_DISTANCE_TRANSLUCENCY');
  84801. }
  84802. if (this._shaderPixelOffsetScaleByDistance) {
  84803. vs.defines.push('EYE_DISTANCE_PIXEL_OFFSET');
  84804. }
  84805. if (this._shaderDistanceDisplayCondition) {
  84806. vs.defines.push('DISTANCE_DISPLAY_CONDITION');
  84807. }
  84808. this._sp = ShaderProgram.replaceCache({
  84809. context : context,
  84810. shaderProgram : this._sp,
  84811. vertexShaderSource : vs,
  84812. fragmentShaderSource : BillboardCollectionFS,
  84813. attributeLocations : attributeLocations
  84814. });
  84815. this._compiledShaderRotation = this._shaderRotation;
  84816. this._compiledShaderAlignedAxis = this._shaderAlignedAxis;
  84817. this._compiledShaderScaleByDistance = this._shaderScaleByDistance;
  84818. this._compiledShaderTranslucencyByDistance = this._shaderTranslucencyByDistance;
  84819. this._compiledShaderPixelOffsetScaleByDistance = this._shaderPixelOffsetScaleByDistance;
  84820. this._compiledShaderDistanceDisplayCondition = this._shaderDistanceDisplayCondition;
  84821. }
  84822. va = this._vaf.va;
  84823. vaLength = va.length;
  84824. colorList.length = vaLength;
  84825. for (j = 0; j < vaLength; ++j) {
  84826. command = colorList[j];
  84827. if (!defined(command)) {
  84828. command = colorList[j] = new DrawCommand({
  84829. pass : Pass.OPAQUE,
  84830. owner : this
  84831. });
  84832. }
  84833. command.boundingVolume = boundingVolume;
  84834. command.modelMatrix = modelMatrix;
  84835. command.count = va[j].indicesCount;
  84836. command.shaderProgram = this._sp;
  84837. command.uniformMap = this._uniforms;
  84838. command.vertexArray = va[j].va;
  84839. command.renderState = this._rs;
  84840. command.debugShowBoundingVolume = this.debugShowBoundingVolume;
  84841. if (this._instanced) {
  84842. command.count = 6;
  84843. command.instanceCount = billboardsLength;
  84844. }
  84845. commandList.push(command);
  84846. }
  84847. }
  84848. if (picking) {
  84849. var pickList = this._pickCommands;
  84850. if (!defined(this._spPick) ||
  84851. (this._shaderRotation !== this._compiledShaderRotationPick) ||
  84852. (this._shaderAlignedAxis !== this._compiledShaderAlignedAxisPick) ||
  84853. (this._shaderScaleByDistance !== this._compiledShaderScaleByDistancePick) ||
  84854. (this._shaderTranslucencyByDistance !== this._compiledShaderTranslucencyByDistancePick) ||
  84855. (this._shaderPixelOffsetScaleByDistance !== this._compiledShaderPixelOffsetScaleByDistancePick) ||
  84856. (this._shaderDistanceDisplayCondition !== this._compiledShaderDistanceDisplayConditionPick)) {
  84857. vs = new ShaderSource({
  84858. defines : ['RENDER_FOR_PICK'],
  84859. sources : [BillboardCollectionVS]
  84860. });
  84861. if(this._instanced) {
  84862. vs.defines.push('INSTANCED');
  84863. }
  84864. if (this._shaderRotation) {
  84865. vs.defines.push('ROTATION');
  84866. }
  84867. if (this._shaderAlignedAxis) {
  84868. vs.defines.push('ALIGNED_AXIS');
  84869. }
  84870. if (this._shaderScaleByDistance) {
  84871. vs.defines.push('EYE_DISTANCE_SCALING');
  84872. }
  84873. if (this._shaderTranslucencyByDistance) {
  84874. vs.defines.push('EYE_DISTANCE_TRANSLUCENCY');
  84875. }
  84876. if (this._shaderPixelOffsetScaleByDistance) {
  84877. vs.defines.push('EYE_DISTANCE_PIXEL_OFFSET');
  84878. }
  84879. if (this._shaderDistanceDisplayCondition) {
  84880. vs.defines.push('DISTANCE_DISPLAY_CONDITION');
  84881. }
  84882. fs = new ShaderSource({
  84883. defines : ['RENDER_FOR_PICK'],
  84884. sources : [BillboardCollectionFS]
  84885. });
  84886. this._spPick = ShaderProgram.replaceCache({
  84887. context : context,
  84888. shaderProgram : this._spPick,
  84889. vertexShaderSource : vs,
  84890. fragmentShaderSource : fs,
  84891. attributeLocations : attributeLocations
  84892. });
  84893. this._compiledShaderRotationPick = this._shaderRotation;
  84894. this._compiledShaderAlignedAxisPick = this._shaderAlignedAxis;
  84895. this._compiledShaderScaleByDistancePick = this._shaderScaleByDistance;
  84896. this._compiledShaderTranslucencyByDistancePick = this._shaderTranslucencyByDistance;
  84897. this._compiledShaderPixelOffsetScaleByDistancePick = this._shaderPixelOffsetScaleByDistance;
  84898. this._compiledShaderDistanceDisplayConditionPick = this._shaderDistanceDisplayCondition;
  84899. }
  84900. va = this._vaf.va;
  84901. vaLength = va.length;
  84902. pickList.length = vaLength;
  84903. for (j = 0; j < vaLength; ++j) {
  84904. command = pickList[j];
  84905. if (!defined(command)) {
  84906. command = pickList[j] = new DrawCommand({
  84907. pass : Pass.OPAQUE,
  84908. owner : this
  84909. });
  84910. }
  84911. command.boundingVolume = boundingVolume;
  84912. command.modelMatrix = modelMatrix;
  84913. command.count = va[j].indicesCount;
  84914. command.shaderProgram = this._spPick;
  84915. command.uniformMap = this._uniforms;
  84916. command.vertexArray = va[j].va;
  84917. command.renderState = this._rs;
  84918. if (this._instanced) {
  84919. command.count = 6;
  84920. command.instanceCount = billboardsLength;
  84921. }
  84922. commandList.push(command);
  84923. }
  84924. }
  84925. };
  84926. /**
  84927. * Returns true if this object was destroyed; otherwise, false.
  84928. * <br /><br />
  84929. * If this object was destroyed, it should not be used; calling any function other than
  84930. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  84931. *
  84932. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  84933. *
  84934. * @see BillboardCollection#destroy
  84935. */
  84936. BillboardCollection.prototype.isDestroyed = function() {
  84937. return false;
  84938. };
  84939. /**
  84940. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  84941. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  84942. * <br /><br />
  84943. * Once an object is destroyed, it should not be used; calling any function other than
  84944. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  84945. * assign the return value (<code>undefined</code>) to the object as done in the example.
  84946. *
  84947. * @returns {undefined}
  84948. *
  84949. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  84950. *
  84951. *
  84952. * @example
  84953. * billboards = billboards && billboards.destroy();
  84954. *
  84955. * @see BillboardCollection#isDestroyed
  84956. */
  84957. BillboardCollection.prototype.destroy = function() {
  84958. if (defined(this._removeCallbackFunc)) {
  84959. this._removeCallbackFunc();
  84960. this._removeCallbackFunc = undefined;
  84961. }
  84962. this._textureAtlas = this._destroyTextureAtlas && this._textureAtlas && this._textureAtlas.destroy();
  84963. this._sp = this._sp && this._sp.destroy();
  84964. this._spPick = this._spPick && this._spPick.destroy();
  84965. this._vaf = this._vaf && this._vaf.destroy();
  84966. destroyBillboards(this._billboards);
  84967. return destroyObject(this);
  84968. };
  84969. return BillboardCollection;
  84970. });
  84971. /*global define*/
  84972. define('Scene/LabelStyle',[
  84973. '../Core/freezeObject'
  84974. ], function(
  84975. freezeObject) {
  84976. 'use strict';
  84977. /**
  84978. * Describes how to draw a label.
  84979. *
  84980. * @exports LabelStyle
  84981. *
  84982. * @see Label#style
  84983. */
  84984. var LabelStyle = {
  84985. /**
  84986. * Fill the text of the label, but do not outline.
  84987. *
  84988. * @type {Number}
  84989. * @constant
  84990. */
  84991. FILL : 0,
  84992. /**
  84993. * Outline the text of the label, but do not fill.
  84994. *
  84995. * @type {Number}
  84996. * @constant
  84997. */
  84998. OUTLINE : 1,
  84999. /**
  85000. * Fill and outline the text of the label.
  85001. *
  85002. * @type {Number}
  85003. * @constant
  85004. */
  85005. FILL_AND_OUTLINE : 2
  85006. };
  85007. return freezeObject(LabelStyle);
  85008. });
  85009. /*global define*/
  85010. define('Scene/Label',[
  85011. '../Core/BoundingRectangle',
  85012. '../Core/Cartesian2',
  85013. '../Core/Cartesian3',
  85014. '../Core/Color',
  85015. '../Core/defaultValue',
  85016. '../Core/defined',
  85017. '../Core/defineProperties',
  85018. '../Core/DeveloperError',
  85019. '../Core/DistanceDisplayCondition',
  85020. '../Core/NearFarScalar',
  85021. './Billboard',
  85022. './HeightReference',
  85023. './HorizontalOrigin',
  85024. './LabelStyle',
  85025. './VerticalOrigin'
  85026. ], function(
  85027. BoundingRectangle,
  85028. Cartesian2,
  85029. Cartesian3,
  85030. Color,
  85031. defaultValue,
  85032. defined,
  85033. defineProperties,
  85034. DeveloperError,
  85035. DistanceDisplayCondition,
  85036. NearFarScalar,
  85037. Billboard,
  85038. HeightReference,
  85039. HorizontalOrigin,
  85040. LabelStyle,
  85041. VerticalOrigin) {
  85042. 'use strict';
  85043. function rebindAllGlyphs(label) {
  85044. if (!label._rebindAllGlyphs && !label._repositionAllGlyphs) {
  85045. // only push label if it's not already been marked dirty
  85046. label._labelCollection._labelsToUpdate.push(label);
  85047. }
  85048. label._rebindAllGlyphs = true;
  85049. }
  85050. function repositionAllGlyphs(label) {
  85051. if (!label._rebindAllGlyphs && !label._repositionAllGlyphs) {
  85052. // only push label if it's not already been marked dirty
  85053. label._labelCollection._labelsToUpdate.push(label);
  85054. }
  85055. label._repositionAllGlyphs = true;
  85056. }
  85057. /**
  85058. * A Label draws viewport-aligned text positioned in the 3D scene. This constructor
  85059. * should not be used directly, instead create labels by calling {@link LabelCollection#add}.
  85060. *
  85061. * @alias Label
  85062. * @internalConstructor
  85063. *
  85064. * @exception {DeveloperError} translucencyByDistance.far must be greater than translucencyByDistance.near
  85065. * @exception {DeveloperError} pixelOffsetScaleByDistance.far must be greater than pixelOffsetScaleByDistance.near
  85066. * @exception {DeveloperError} distanceDisplayCondition.far must be greater than distanceDisplayCondition.near
  85067. *
  85068. * @see LabelCollection
  85069. * @see LabelCollection#add
  85070. *
  85071. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Labels.html|Cesium Sandcastle Labels Demo}
  85072. */
  85073. function Label(options, labelCollection) {
  85074. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  85075. if (defined(options.translucencyByDistance) && options.translucencyByDistance.far <= options.translucencyByDistance.near) {
  85076. throw new DeveloperError('translucencyByDistance.far must be greater than translucencyByDistance.near.');
  85077. }
  85078. if (defined(options.pixelOffsetScaleByDistance) && options.pixelOffsetScaleByDistance.far <= options.pixelOffsetScaleByDistance.near) {
  85079. throw new DeveloperError('pixelOffsetScaleByDistance.far must be greater than pixelOffsetScaleByDistance.near.');
  85080. }
  85081. if (defined(options.distanceDisplayCondition) && options.distanceDisplayCondition.far <= options.distanceDisplayCondition.near) {
  85082. throw new DeveloperError('distanceDisplayCondition.far must be greater than distanceDisplayCondition.near');
  85083. }
  85084. this._text = defaultValue(options.text, '');
  85085. this._show = defaultValue(options.show, true);
  85086. this._font = defaultValue(options.font, '30px sans-serif');
  85087. this._fillColor = Color.clone(defaultValue(options.fillColor, Color.WHITE));
  85088. this._outlineColor = Color.clone(defaultValue(options.outlineColor, Color.BLACK));
  85089. this._outlineWidth = defaultValue(options.outlineWidth, 1.0);
  85090. this._showBackground = defaultValue(options.showBackground, false);
  85091. this._backgroundColor = defaultValue(options.backgroundColor, new Color(0.165, 0.165, 0.165, 0.8));
  85092. this._backgroundPadding = defaultValue(options.backgroundPadding, new Cartesian2(7, 5));
  85093. this._style = defaultValue(options.style, LabelStyle.FILL);
  85094. this._verticalOrigin = defaultValue(options.verticalOrigin, VerticalOrigin.BASELINE);
  85095. this._horizontalOrigin = defaultValue(options.horizontalOrigin, HorizontalOrigin.LEFT);
  85096. this._pixelOffset = Cartesian2.clone(defaultValue(options.pixelOffset, Cartesian2.ZERO));
  85097. this._eyeOffset = Cartesian3.clone(defaultValue(options.eyeOffset, Cartesian3.ZERO));
  85098. this._position = Cartesian3.clone(defaultValue(options.position, Cartesian3.ZERO));
  85099. this._scale = defaultValue(options.scale, 1.0);
  85100. this._id = options.id;
  85101. this._translucencyByDistance = options.translucencyByDistance;
  85102. this._pixelOffsetScaleByDistance = options.pixelOffsetScaleByDistance;
  85103. this._heightReference = defaultValue(options.heightReference, HeightReference.NONE);
  85104. this._distanceDisplayCondition = options.distanceDisplayCondition;
  85105. this._labelCollection = labelCollection;
  85106. this._glyphs = [];
  85107. this._backgroundBillboard = undefined;
  85108. this._rebindAllGlyphs = true;
  85109. this._repositionAllGlyphs = true;
  85110. this._actualClampedPosition = undefined;
  85111. this._removeCallbackFunc = undefined;
  85112. this._mode = undefined;
  85113. this._clusterShow = true;
  85114. this._updateClamping();
  85115. }
  85116. defineProperties(Label.prototype, {
  85117. /**
  85118. * Determines if this label will be shown. Use this to hide or show a label, instead
  85119. * of removing it and re-adding it to the collection.
  85120. * @memberof Label.prototype
  85121. * @type {Boolean}
  85122. * @default true
  85123. */
  85124. show : {
  85125. get : function() {
  85126. return this._show;
  85127. },
  85128. set : function(value) {
  85129. if (!defined(value)) {
  85130. throw new DeveloperError('value is required.');
  85131. }
  85132. if (this._show !== value) {
  85133. this._show = value;
  85134. var glyphs = this._glyphs;
  85135. for (var i = 0, len = glyphs.length; i < len; i++) {
  85136. var billboard = glyphs[i].billboard;
  85137. if (defined(billboard)) {
  85138. billboard.show = value;
  85139. }
  85140. }
  85141. var backgroundBillboard = this._backgroundBillboard;
  85142. if (defined(backgroundBillboard)) {
  85143. backgroundBillboard.show = value;
  85144. }
  85145. }
  85146. }
  85147. },
  85148. /**
  85149. * Gets or sets the Cartesian position of this label.
  85150. * @memberof Label.prototype
  85151. * @type {Cartesian3}
  85152. */
  85153. position : {
  85154. get : function() {
  85155. return this._position;
  85156. },
  85157. set : function(value) {
  85158. if (!defined(value)) {
  85159. throw new DeveloperError('value is required.');
  85160. }
  85161. var position = this._position;
  85162. if (!Cartesian3.equals(position, value)) {
  85163. Cartesian3.clone(value, position);
  85164. var glyphs = this._glyphs;
  85165. for (var i = 0, len = glyphs.length; i < len; i++) {
  85166. var billboard = glyphs[i].billboard;
  85167. if (defined(billboard)) {
  85168. billboard.position = value;
  85169. }
  85170. }
  85171. var backgroundBillboard = this._backgroundBillboard;
  85172. if (defined(backgroundBillboard)) {
  85173. backgroundBillboard.position = value;
  85174. }
  85175. if (this._heightReference !== HeightReference.NONE) {
  85176. this._updateClamping();
  85177. }
  85178. }
  85179. }
  85180. },
  85181. /**
  85182. * Gets or sets the height reference of this billboard.
  85183. * @memberof Label.prototype
  85184. * @type {HeightReference}
  85185. * @default HeightReference.NONE
  85186. */
  85187. heightReference : {
  85188. get : function() {
  85189. return this._heightReference;
  85190. },
  85191. set : function(value) {
  85192. if (!defined(value)) {
  85193. throw new DeveloperError('value is required.');
  85194. }
  85195. if (value !== this._heightReference) {
  85196. this._heightReference = value;
  85197. var glyphs = this._glyphs;
  85198. for (var i = 0, len = glyphs.length; i < len; i++) {
  85199. var billboard = glyphs[i].billboard;
  85200. if (defined(billboard)) {
  85201. billboard.heightReference = value;
  85202. }
  85203. }
  85204. var backgroundBillboard = this._backgroundBillboard;
  85205. if (defined(backgroundBillboard)) {
  85206. backgroundBillboard.heightReference = value;
  85207. }
  85208. repositionAllGlyphs(this);
  85209. this._updateClamping();
  85210. }
  85211. }
  85212. },
  85213. /**
  85214. * Gets or sets the text of this label.
  85215. * @memberof Label.prototype
  85216. * @type {String}
  85217. */
  85218. text : {
  85219. get : function() {
  85220. return this._text;
  85221. },
  85222. set : function(value) {
  85223. if (!defined(value)) {
  85224. throw new DeveloperError('value is required.');
  85225. }
  85226. if (this._text !== value) {
  85227. this._text = value;
  85228. rebindAllGlyphs(this);
  85229. }
  85230. }
  85231. },
  85232. /**
  85233. * Gets or sets the font used to draw this label. Fonts are specified using the same syntax as the CSS 'font' property.
  85234. * @memberof Label.prototype
  85235. * @type {String}
  85236. * @default '30px sans-serif'
  85237. * @see {@link http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#text-styles|HTML canvas 2D context text styles}
  85238. */
  85239. font : {
  85240. get : function() {
  85241. return this._font;
  85242. },
  85243. set : function(value) {
  85244. if (!defined(value)) {
  85245. throw new DeveloperError('value is required.');
  85246. }
  85247. if (this._font !== value) {
  85248. this._font = value;
  85249. rebindAllGlyphs(this);
  85250. }
  85251. }
  85252. },
  85253. /**
  85254. * Gets or sets the fill color of this label.
  85255. * @memberof Label.prototype
  85256. * @type {Color}
  85257. * @default Color.WHITE
  85258. * @see {@link http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#fill-and-stroke-styles|HTML canvas 2D context fill and stroke styles}
  85259. */
  85260. fillColor : {
  85261. get : function() {
  85262. return this._fillColor;
  85263. },
  85264. set : function(value) {
  85265. if (!defined(value)) {
  85266. throw new DeveloperError('value is required.');
  85267. }
  85268. var fillColor = this._fillColor;
  85269. if (!Color.equals(fillColor, value)) {
  85270. Color.clone(value, fillColor);
  85271. rebindAllGlyphs(this);
  85272. }
  85273. }
  85274. },
  85275. /**
  85276. * Gets or sets the outline color of this label.
  85277. * @memberof Label.prototype
  85278. * @type {Color}
  85279. * @default Color.BLACK
  85280. * @see {@link http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#fill-and-stroke-styles|HTML canvas 2D context fill and stroke styles}
  85281. */
  85282. outlineColor : {
  85283. get : function() {
  85284. return this._outlineColor;
  85285. },
  85286. set : function(value) {
  85287. if (!defined(value)) {
  85288. throw new DeveloperError('value is required.');
  85289. }
  85290. var outlineColor = this._outlineColor;
  85291. if (!Color.equals(outlineColor, value)) {
  85292. Color.clone(value, outlineColor);
  85293. rebindAllGlyphs(this);
  85294. }
  85295. }
  85296. },
  85297. /**
  85298. * Gets or sets the outline width of this label.
  85299. * @memberof Label.prototype
  85300. * @type {Number}
  85301. * @default 1.0
  85302. * @see {@link http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#fill-and-stroke-styles|HTML canvas 2D context fill and stroke styles}
  85303. */
  85304. outlineWidth : {
  85305. get : function() {
  85306. return this._outlineWidth;
  85307. },
  85308. set : function(value) {
  85309. if (!defined(value)) {
  85310. throw new DeveloperError('value is required.');
  85311. }
  85312. if (this._outlineWidth !== value) {
  85313. this._outlineWidth = value;
  85314. rebindAllGlyphs(this);
  85315. }
  85316. }
  85317. },
  85318. /**
  85319. * Determines if a background behind this label will be shown.
  85320. * @memberof Label.prototype
  85321. * @default false
  85322. * @type {Boolean}
  85323. */
  85324. showBackground : {
  85325. get : function() {
  85326. return this._showBackground;
  85327. },
  85328. set : function(value) {
  85329. if (!defined(value)) {
  85330. throw new DeveloperError('value is required.');
  85331. }
  85332. if (this._showBackground !== value) {
  85333. this._showBackground = value;
  85334. rebindAllGlyphs(this);
  85335. }
  85336. }
  85337. },
  85338. /**
  85339. * Gets or sets the background color of this label.
  85340. * @memberof Label.prototype
  85341. * @type {Color}
  85342. * @default new Color(0.165, 0.165, 0.165, 0.8)
  85343. */
  85344. backgroundColor : {
  85345. get : function() {
  85346. return this._backgroundColor;
  85347. },
  85348. set : function(value) {
  85349. if (!defined(value)) {
  85350. throw new DeveloperError('value is required.');
  85351. }
  85352. var backgroundColor = this._backgroundColor;
  85353. if (!Color.equals(backgroundColor, value)) {
  85354. Color.clone(value, backgroundColor);
  85355. var backgroundBillboard = this._backgroundBillboard;
  85356. if (defined(backgroundBillboard)) {
  85357. backgroundBillboard.color = backgroundColor;
  85358. }
  85359. }
  85360. }
  85361. },
  85362. /**
  85363. * Gets or sets the background padding, in pixels, of this label. The <code>x</code> value
  85364. * controls horizontal padding, and the <code>y</code> value controls vertical padding.
  85365. * @memberof Label.prototype
  85366. * @type {Cartesian2}
  85367. * @default new Cartesian2(7, 5)
  85368. */
  85369. backgroundPadding : {
  85370. get : function() {
  85371. return this._backgroundPadding;
  85372. },
  85373. set : function(value) {
  85374. if (!defined(value)) {
  85375. throw new DeveloperError('value is required.');
  85376. }
  85377. var backgroundPadding = this._backgroundPadding;
  85378. if (!Cartesian2.equals(backgroundPadding, value)) {
  85379. Cartesian2.clone(value, backgroundPadding);
  85380. repositionAllGlyphs(this);
  85381. }
  85382. }
  85383. },
  85384. /**
  85385. * Gets or sets the style of this label.
  85386. * @memberof Label.prototype
  85387. * @type {LabelStyle}
  85388. * @default LabelStyle.FILL
  85389. */
  85390. style : {
  85391. get : function() {
  85392. return this._style;
  85393. },
  85394. set : function(value) {
  85395. if (!defined(value)) {
  85396. throw new DeveloperError('value is required.');
  85397. }
  85398. if (this._style !== value) {
  85399. this._style = value;
  85400. rebindAllGlyphs(this);
  85401. }
  85402. }
  85403. },
  85404. /**
  85405. * Gets or sets the pixel offset in screen space from the origin of this label. This is commonly used
  85406. * to align multiple labels and billboards at the same position, e.g., an image and text. The
  85407. * screen space origin is the top, left corner of the canvas; <code>x</code> increases from
  85408. * left to right, and <code>y</code> increases from top to bottom.
  85409. * <br /><br />
  85410. * <div align='center'>
  85411. * <table border='0' cellpadding='5'><tr>
  85412. * <td align='center'><code>default</code><br/><img src='images/Label.setPixelOffset.default.png' width='250' height='188' /></td>
  85413. * <td align='center'><code>l.pixeloffset = new Cartesian2(25, 75);</code><br/><img src='images/Label.setPixelOffset.x50y-25.png' width='250' height='188' /></td>
  85414. * </tr></table>
  85415. * The label's origin is indicated by the yellow point.
  85416. * </div>
  85417. * @memberof Label.prototype
  85418. * @type {Cartesian2}
  85419. * @default Cartesian2.ZERO
  85420. */
  85421. pixelOffset : {
  85422. get : function() {
  85423. return this._pixelOffset;
  85424. },
  85425. set : function(value) {
  85426. if (!defined(value)) {
  85427. throw new DeveloperError('value is required.');
  85428. }
  85429. var pixelOffset = this._pixelOffset;
  85430. if (!Cartesian2.equals(pixelOffset, value)) {
  85431. Cartesian2.clone(value, pixelOffset);
  85432. var glyphs = this._glyphs;
  85433. for (var i = 0, len = glyphs.length; i < len; i++) {
  85434. var glyph = glyphs[i];
  85435. if (defined(glyph.billboard)) {
  85436. glyph.billboard.pixelOffset = value;
  85437. }
  85438. }
  85439. var backgroundBillboard = this._backgroundBillboard;
  85440. if (defined(backgroundBillboard)) {
  85441. backgroundBillboard.pixelOffset = value;
  85442. }
  85443. }
  85444. }
  85445. },
  85446. /**
  85447. * Gets or sets near and far translucency properties of a Label based on the Label's distance from the camera.
  85448. * A label's translucency will interpolate between the {@link NearFarScalar#nearValue} and
  85449. * {@link NearFarScalar#farValue} while the camera distance falls within the upper and lower bounds
  85450. * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
  85451. * Outside of these ranges the label's translucency remains clamped to the nearest bound. If undefined,
  85452. * translucencyByDistance will be disabled.
  85453. * @memberof Label.prototype
  85454. * @type {NearFarScalar}
  85455. *
  85456. * @example
  85457. * // Example 1.
  85458. * // Set a label's translucencyByDistance to 1.0 when the
  85459. * // camera is 1500 meters from the label and disappear as
  85460. * // the camera distance approaches 8.0e6 meters.
  85461. * text.translucencyByDistance = new Cesium.NearFarScalar(1.5e2, 1.0, 8.0e6, 0.0);
  85462. *
  85463. * @example
  85464. * // Example 2.
  85465. * // disable translucency by distance
  85466. * text.translucencyByDistance = undefined;
  85467. */
  85468. translucencyByDistance : {
  85469. get : function() {
  85470. return this._translucencyByDistance;
  85471. },
  85472. set : function(value) {
  85473. if (defined(value) && value.far <= value.near) {
  85474. throw new DeveloperError('far distance must be greater than near distance.');
  85475. }
  85476. var translucencyByDistance = this._translucencyByDistance;
  85477. if (!NearFarScalar.equals(translucencyByDistance, value)) {
  85478. this._translucencyByDistance = NearFarScalar.clone(value, translucencyByDistance);
  85479. var glyphs = this._glyphs;
  85480. for (var i = 0, len = glyphs.length; i < len; i++) {
  85481. var glyph = glyphs[i];
  85482. if (defined(glyph.billboard)) {
  85483. glyph.billboard.translucencyByDistance = value;
  85484. }
  85485. }
  85486. var backgroundBillboard = this._backgroundBillboard;
  85487. if (defined(backgroundBillboard)) {
  85488. backgroundBillboard.translucencyByDistance = value;
  85489. }
  85490. }
  85491. }
  85492. },
  85493. /**
  85494. * Gets or sets near and far pixel offset scaling properties of a Label based on the Label's distance from the camera.
  85495. * A label's pixel offset will be scaled between the {@link NearFarScalar#nearValue} and
  85496. * {@link NearFarScalar#farValue} while the camera distance falls within the upper and lower bounds
  85497. * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
  85498. * Outside of these ranges the label's pixel offset scaling remains clamped to the nearest bound. If undefined,
  85499. * pixelOffsetScaleByDistance will be disabled.
  85500. * @memberof Label.prototype
  85501. * @type {NearFarScalar}
  85502. *
  85503. * @example
  85504. * // Example 1.
  85505. * // Set a label's pixel offset scale to 0.0 when the
  85506. * // camera is 1500 meters from the label and scale pixel offset to 10.0 pixels
  85507. * // in the y direction the camera distance approaches 8.0e6 meters.
  85508. * text.pixelOffset = new Cesium.Cartesian2(0.0, 1.0);
  85509. * text.pixelOffsetScaleByDistance = new Cesium.NearFarScalar(1.5e2, 0.0, 8.0e6, 10.0);
  85510. *
  85511. * @example
  85512. * // Example 2.
  85513. * // disable pixel offset by distance
  85514. * text.pixelOffsetScaleByDistance = undefined;
  85515. */
  85516. pixelOffsetScaleByDistance : {
  85517. get : function() {
  85518. return this._pixelOffsetScaleByDistance;
  85519. },
  85520. set : function(value) {
  85521. if (defined(value) && value.far <= value.near) {
  85522. throw new DeveloperError('far distance must be greater than near distance.');
  85523. }
  85524. var pixelOffsetScaleByDistance = this._pixelOffsetScaleByDistance;
  85525. if (!NearFarScalar.equals(pixelOffsetScaleByDistance, value)) {
  85526. this._pixelOffsetScaleByDistance = NearFarScalar.clone(value, pixelOffsetScaleByDistance);
  85527. var glyphs = this._glyphs;
  85528. for (var i = 0, len = glyphs.length; i < len; i++) {
  85529. var glyph = glyphs[i];
  85530. if (defined(glyph.billboard)) {
  85531. glyph.billboard.pixelOffsetScaleByDistance = value;
  85532. }
  85533. }
  85534. var backgroundBillboard = this._backgroundBillboard;
  85535. if (defined(backgroundBillboard)) {
  85536. backgroundBillboard.pixelOffsetScaleByDistance = value;
  85537. }
  85538. }
  85539. }
  85540. },
  85541. /**
  85542. * Gets and sets the 3D Cartesian offset applied to this label in eye coordinates. Eye coordinates is a left-handed
  85543. * coordinate system, where <code>x</code> points towards the viewer's right, <code>y</code> points up, and
  85544. * <code>z</code> points into the screen. Eye coordinates use the same scale as world and model coordinates,
  85545. * which is typically meters.
  85546. * <br /><br />
  85547. * An eye offset is commonly used to arrange multiple label or objects at the same position, e.g., to
  85548. * arrange a label above its corresponding 3D model.
  85549. * <br /><br />
  85550. * Below, the label is positioned at the center of the Earth but an eye offset makes it always
  85551. * appear on top of the Earth regardless of the viewer's or Earth's orientation.
  85552. * <br /><br />
  85553. * <div align='center'>
  85554. * <table border='0' cellpadding='5'><tr>
  85555. * <td align='center'><img src='images/Billboard.setEyeOffset.one.png' width='250' height='188' /></td>
  85556. * <td align='center'><img src='images/Billboard.setEyeOffset.two.png' width='250' height='188' /></td>
  85557. * </tr></table>
  85558. * <code>l.eyeOffset = new Cartesian3(0.0, 8000000.0, 0.0);</code><br /><br />
  85559. * </div>
  85560. * @memberof Label.prototype
  85561. * @type {Cartesian3}
  85562. * @default Cartesian3.ZERO
  85563. */
  85564. eyeOffset : {
  85565. get : function() {
  85566. return this._eyeOffset;
  85567. },
  85568. set : function(value) {
  85569. if (!defined(value)) {
  85570. throw new DeveloperError('value is required.');
  85571. }
  85572. var eyeOffset = this._eyeOffset;
  85573. if (!Cartesian3.equals(eyeOffset, value)) {
  85574. Cartesian3.clone(value, eyeOffset);
  85575. var glyphs = this._glyphs;
  85576. for (var i = 0, len = glyphs.length; i < len; i++) {
  85577. var glyph = glyphs[i];
  85578. if (defined(glyph.billboard)) {
  85579. glyph.billboard.eyeOffset = value;
  85580. }
  85581. }
  85582. var backgroundBillboard = this._backgroundBillboard;
  85583. if (defined(backgroundBillboard)) {
  85584. backgroundBillboard.eyeOffset = value;
  85585. }
  85586. }
  85587. }
  85588. },
  85589. /**
  85590. * Gets or sets the horizontal origin of this label, which determines if the label is drawn
  85591. * to the left, center, or right of its anchor position.
  85592. * <br /><br />
  85593. * <div align='center'>
  85594. * <img src='images/Billboard.setHorizontalOrigin.png' width='648' height='196' /><br />
  85595. * </div>
  85596. * @memberof Label.prototype
  85597. * @type {HorizontalOrigin}
  85598. * @default HorizontalOrigin.LEFT
  85599. * @example
  85600. * // Use a top, right origin
  85601. * l.horizontalOrigin = Cesium.HorizontalOrigin.RIGHT;
  85602. * l.verticalOrigin = Cesium.VerticalOrigin.TOP;
  85603. */
  85604. horizontalOrigin : {
  85605. get : function() {
  85606. return this._horizontalOrigin;
  85607. },
  85608. set : function(value) {
  85609. if (!defined(value)) {
  85610. throw new DeveloperError('value is required.');
  85611. }
  85612. if (this._horizontalOrigin !== value) {
  85613. this._horizontalOrigin = value;
  85614. repositionAllGlyphs(this);
  85615. }
  85616. }
  85617. },
  85618. /**
  85619. * Gets or sets the vertical origin of this label, which determines if the label is
  85620. * to the above, below, or at the center of its anchor position.
  85621. * <br /><br />
  85622. * <div align='center'>
  85623. * <img src='images/Billboard.setVerticalOrigin.png' width='695' height='175' /><br />
  85624. * </div>
  85625. * @memberof Label.prototype
  85626. * @type {VerticalOrigin}
  85627. * @default VerticalOrigin.BASELINE
  85628. * @example
  85629. * // Use a top, right origin
  85630. * l.horizontalOrigin = Cesium.HorizontalOrigin.RIGHT;
  85631. * l.verticalOrigin = Cesium.VerticalOrigin.TOP;
  85632. */
  85633. verticalOrigin : {
  85634. get : function() {
  85635. return this._verticalOrigin;
  85636. },
  85637. set : function(value) {
  85638. if (!defined(value)) {
  85639. throw new DeveloperError('value is required.');
  85640. }
  85641. if (this._verticalOrigin !== value) {
  85642. this._verticalOrigin = value;
  85643. var glyphs = this._glyphs;
  85644. for (var i = 0, len = glyphs.length; i < len; i++) {
  85645. var glyph = glyphs[i];
  85646. if (defined(glyph.billboard)) {
  85647. glyph.billboard.verticalOrigin = value;
  85648. }
  85649. }
  85650. var backgroundBillboard = this._backgroundBillboard;
  85651. if (defined(backgroundBillboard)) {
  85652. backgroundBillboard.verticalOrigin = value;
  85653. }
  85654. repositionAllGlyphs(this);
  85655. }
  85656. }
  85657. },
  85658. /**
  85659. * Gets or sets the uniform scale that is multiplied with the label's size in pixels.
  85660. * A scale of <code>1.0</code> does not change the size of the label; a scale greater than
  85661. * <code>1.0</code> enlarges the label; a positive scale less than <code>1.0</code> shrinks
  85662. * the label.
  85663. * <br /><br />
  85664. * Applying a large scale value may pixelate the label. To make text larger without pixelation,
  85665. * use a larger font size when calling {@link Label#font} instead.
  85666. * <br /><br />
  85667. * <div align='center'>
  85668. * <img src='images/Label.setScale.png' width='400' height='300' /><br/>
  85669. * From left to right in the above image, the scales are <code>0.5</code>, <code>1.0</code>,
  85670. * and <code>2.0</code>.
  85671. * </div>
  85672. * @memberof Label.prototype
  85673. * @type {Number}
  85674. * @default 1.0
  85675. */
  85676. scale : {
  85677. get : function() {
  85678. return this._scale;
  85679. },
  85680. set : function(value) {
  85681. if (!defined(value)) {
  85682. throw new DeveloperError('value is required.');
  85683. }
  85684. if (this._scale !== value) {
  85685. this._scale = value;
  85686. var glyphs = this._glyphs;
  85687. for (var i = 0, len = glyphs.length; i < len; i++) {
  85688. var glyph = glyphs[i];
  85689. if (defined(glyph.billboard)) {
  85690. glyph.billboard.scale = value;
  85691. }
  85692. }
  85693. var backgroundBillboard = this._backgroundBillboard;
  85694. if (defined(backgroundBillboard)) {
  85695. backgroundBillboard.scale = value;
  85696. }
  85697. repositionAllGlyphs(this);
  85698. }
  85699. }
  85700. },
  85701. /**
  85702. * Gets or sets the condition specifying at what distance from the camera that this label will be displayed.
  85703. * @memberof Label.prototype
  85704. * @type {DistanceDisplayCondition}
  85705. * @default undefined
  85706. */
  85707. distanceDisplayCondition : {
  85708. get : function() {
  85709. return this._distanceDisplayCondition;
  85710. },
  85711. set : function(value) {
  85712. if (defined(value) && value.far <= value.near) {
  85713. throw new DeveloperError('far must be greater than near');
  85714. }
  85715. if (!DistanceDisplayCondition.equals(value, this._distanceDisplayCondition)) {
  85716. this._distanceDisplayCondition = DistanceDisplayCondition.clone(value, this._distanceDisplayCondition);
  85717. var glyphs = this._glyphs;
  85718. for (var i = 0, len = glyphs.length; i < len; i++) {
  85719. var glyph = glyphs[i];
  85720. if (defined(glyph.billboard)) {
  85721. glyph.billboard.distanceDisplayCondition = value;
  85722. }
  85723. }
  85724. var backgroundBillboard = this._backgroundBillboard;
  85725. if (defined(backgroundBillboard)) {
  85726. backgroundBillboard.distanceDisplayCondition = value;
  85727. }
  85728. }
  85729. }
  85730. },
  85731. /**
  85732. * Gets or sets the user-defined object returned when the label is picked.
  85733. * @memberof Label.prototype
  85734. * @type {Object}
  85735. */
  85736. id : {
  85737. get : function() {
  85738. return this._id;
  85739. },
  85740. set : function(value) {
  85741. if (this._id !== value) {
  85742. this._id = value;
  85743. var glyphs = this._glyphs;
  85744. for (var i = 0, len = glyphs.length; i < len; i++) {
  85745. var glyph = glyphs[i];
  85746. if (defined(glyph.billboard)) {
  85747. glyph.billboard.id = value;
  85748. }
  85749. }
  85750. var backgroundBillboard = this._backgroundBillboard;
  85751. if (defined(backgroundBillboard)) {
  85752. backgroundBillboard.id = value;
  85753. }
  85754. }
  85755. }
  85756. },
  85757. /**
  85758. * Keeps track of the position of the label based on the height reference.
  85759. * @memberof Label.prototype
  85760. * @type {Cartesian3}
  85761. * @private
  85762. */
  85763. _clampedPosition : {
  85764. get : function() {
  85765. return this._actualClampedPosition;
  85766. },
  85767. set : function(value) {
  85768. this._actualClampedPosition = Cartesian3.clone(value, this._actualClampedPosition);
  85769. var glyphs = this._glyphs;
  85770. value = defaultValue(value, this._position);
  85771. for (var i = 0, len = glyphs.length; i < len; i++) {
  85772. var glyph = glyphs[i];
  85773. if (defined(glyph.billboard)) {
  85774. // Set all the private values here, because we already clamped to ground
  85775. // so we don't want to do it again for every glyph
  85776. glyph.billboard._clampedPosition = value;
  85777. Cartesian3.clone(value, glyph.billboard._position);
  85778. Cartesian3.clone(value, glyph.billboard._actualPosition);
  85779. }
  85780. }
  85781. var backgroundBillboard = this._backgroundBillboard;
  85782. if (defined(backgroundBillboard)) {
  85783. backgroundBillboard._clampedPosition = value;
  85784. Cartesian3.clone(value, backgroundBillboard._position);
  85785. Cartesian3.clone(value, backgroundBillboard._actualPosition);
  85786. }
  85787. }
  85788. },
  85789. /**
  85790. * Determines whether or not this label will be shown or hidden because it was clustered.
  85791. * @memberof Label.prototype
  85792. * @type {Boolean}
  85793. * @default true
  85794. * @private
  85795. */
  85796. clusterShow : {
  85797. get : function() {
  85798. return this._clusterShow;
  85799. },
  85800. set : function(value) {
  85801. if (this._clusterShow !== value) {
  85802. this._clusterShow = value;
  85803. var glyphs = this._glyphs;
  85804. for (var i = 0, len = glyphs.length; i < len; i++) {
  85805. var glyph = glyphs[i];
  85806. if (defined(glyph.billboard)) {
  85807. glyph.billboard.clusterShow = value;
  85808. }
  85809. }
  85810. var backgroundBillboard = this._backgroundBillboard;
  85811. if (defined(backgroundBillboard)) {
  85812. backgroundBillboard.clusterShow = value;
  85813. }
  85814. }
  85815. }
  85816. }
  85817. });
  85818. Label.prototype._updateClamping = function() {
  85819. Billboard._updateClamping(this._labelCollection, this);
  85820. };
  85821. /**
  85822. * Computes the screen-space position of the label's origin, taking into account eye and pixel offsets.
  85823. * The screen space origin is the top, left corner of the canvas; <code>x</code> increases from
  85824. * left to right, and <code>y</code> increases from top to bottom.
  85825. *
  85826. * @param {Scene} scene The scene the label is in.
  85827. * @param {Cartesian2} [result] The object onto which to store the result.
  85828. * @returns {Cartesian2} The screen-space position of the label.
  85829. *
  85830. *
  85831. * @example
  85832. * console.log(l.computeScreenSpacePosition(scene).toString());
  85833. *
  85834. * @see Label#eyeOffset
  85835. * @see Label#pixelOffset
  85836. */
  85837. Label.prototype.computeScreenSpacePosition = function(scene, result) {
  85838. if (!defined(scene)) {
  85839. throw new DeveloperError('scene is required.');
  85840. }
  85841. if (!defined(result)) {
  85842. result = new Cartesian2();
  85843. }
  85844. var labelCollection = this._labelCollection;
  85845. var modelMatrix = labelCollection.modelMatrix;
  85846. var actualPosition = defined(this._actualClampedPosition) ? this._actualClampedPosition : this._position;
  85847. var windowCoordinates = Billboard._computeScreenSpacePosition(modelMatrix, actualPosition,
  85848. this._eyeOffset, this._pixelOffset, scene, result);
  85849. return windowCoordinates;
  85850. };
  85851. /**
  85852. * Gets a label's screen space bounding box centered around screenSpacePosition.
  85853. * @param {Label} label The label to get the screen space bounding box for.
  85854. * @param {Cartesian2} screenSpacePosition The screen space center of the label.
  85855. * @param {BoundingRectangle} [result] The object onto which to store the result.
  85856. * @returns {BoundingRectangle} The screen space bounding box.
  85857. *
  85858. * @private
  85859. */
  85860. Label.getScreenSpaceBoundingBox = function(label, screenSpacePosition, result) {
  85861. var x = 0;
  85862. var y = 0;
  85863. var width = 0;
  85864. var height = 0;
  85865. var scale = label.scale;
  85866. var resolutionScale = label._labelCollection._resolutionScale;
  85867. var backgroundBillboard = label._backgroundBillboard;
  85868. if (defined(backgroundBillboard)) {
  85869. x = screenSpacePosition.x + (backgroundBillboard._translate.x / resolutionScale);
  85870. y = screenSpacePosition.y - (backgroundBillboard._translate.y / resolutionScale);
  85871. width = backgroundBillboard.width * scale;
  85872. height = backgroundBillboard.height * scale;
  85873. if (label.verticalOrigin === VerticalOrigin.BOTTOM || label.verticalOrigin === VerticalOrigin.BASELINE) {
  85874. y -= height;
  85875. } else if (label.verticalOrigin === VerticalOrigin.CENTER) {
  85876. y -= height * 0.5;
  85877. }
  85878. } else {
  85879. x = Number.POSITIVE_INFINITY;
  85880. y = Number.POSITIVE_INFINITY;
  85881. var maxX = 0;
  85882. var maxY = 0;
  85883. var glyphs = label._glyphs;
  85884. var length = glyphs.length;
  85885. for (var i = 0; i < length; ++i) {
  85886. var glyph = glyphs[i];
  85887. var billboard = glyph.billboard;
  85888. if (!defined(billboard)) {
  85889. continue;
  85890. }
  85891. var glyphX = screenSpacePosition.x + (billboard._translate.x / resolutionScale);
  85892. var glyphY = screenSpacePosition.y - (billboard._translate.y / resolutionScale);
  85893. var glyphWidth = billboard.width * scale;
  85894. var glyphHeight = billboard.height * scale;
  85895. if (label.verticalOrigin === VerticalOrigin.BOTTOM || label.verticalOrigin === VerticalOrigin.BASELINE) {
  85896. glyphY -= glyphHeight;
  85897. } else if (label.verticalOrigin === VerticalOrigin.CENTER) {
  85898. glyphY -= glyphHeight * 0.5;
  85899. }
  85900. x = Math.min(x, glyphX);
  85901. y = Math.min(y, glyphY);
  85902. maxX = Math.max(maxX, glyphX + glyphWidth);
  85903. maxY = Math.max(maxY, glyphY + glyphHeight);
  85904. }
  85905. width = maxX - x;
  85906. height = maxY - y;
  85907. }
  85908. if (!defined(result)) {
  85909. result = new BoundingRectangle();
  85910. }
  85911. result.x = x;
  85912. result.y = y;
  85913. result.width = width;
  85914. result.height = height;
  85915. return result;
  85916. };
  85917. /**
  85918. * Determines if this label equals another label. Labels are equal if all their properties
  85919. * are equal. Labels in different collections can be equal.
  85920. *
  85921. * @param {Label} other The label to compare for equality.
  85922. * @returns {Boolean} <code>true</code> if the labels are equal; otherwise, <code>false</code>.
  85923. */
  85924. Label.prototype.equals = function(other) {
  85925. return this === other ||
  85926. defined(other) &&
  85927. this._show === other._show &&
  85928. this._scale === other._scale &&
  85929. this._outlineWidth === other._outlineWidth &&
  85930. this._showBackground === other._showBackground &&
  85931. this._style === other._style &&
  85932. this._verticalOrigin === other._verticalOrigin &&
  85933. this._horizontalOrigin === other._horizontalOrigin &&
  85934. this._heightReference === other._heightReference &&
  85935. this._text === other._text &&
  85936. this._font === other._font &&
  85937. Cartesian3.equals(this._position, other._position) &&
  85938. Color.equals(this._fillColor, other._fillColor) &&
  85939. Color.equals(this._outlineColor, other._outlineColor) &&
  85940. Color.equals(this._backgroundColor, other._backgroundColor) &&
  85941. Cartesian2.equals(this._backgroundPadding, other._backgroundPadding) &&
  85942. Cartesian2.equals(this._pixelOffset, other._pixelOffset) &&
  85943. Cartesian3.equals(this._eyeOffset, other._eyeOffset) &&
  85944. NearFarScalar.equals(this._translucencyByDistance, other._translucencyByDistance) &&
  85945. NearFarScalar.equals(this._pixelOffsetScaleByDistance, other._pixelOffsetScaleByDistance) &&
  85946. DistanceDisplayCondition.equals(this._distanceDisplayCondition, other._distanceDisplayCondition) &&
  85947. this._id === other._id;
  85948. };
  85949. /**
  85950. * Returns true if this object was destroyed; otherwise, false.
  85951. * <br /><br />
  85952. * If this object was destroyed, it should not be used; calling any function other than
  85953. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  85954. *
  85955. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  85956. */
  85957. Label.prototype.isDestroyed = function() {
  85958. return false;
  85959. };
  85960. return Label;
  85961. });
  85962. /*global define*/
  85963. define('Scene/LabelCollection',[
  85964. '../Core/BoundingRectangle',
  85965. '../Core/Cartesian2',
  85966. '../Core/Color',
  85967. '../Core/defaultValue',
  85968. '../Core/defined',
  85969. '../Core/defineProperties',
  85970. '../Core/destroyObject',
  85971. '../Core/DeveloperError',
  85972. '../Core/Matrix4',
  85973. '../Core/writeTextToCanvas',
  85974. './BillboardCollection',
  85975. './HorizontalOrigin',
  85976. './Label',
  85977. './LabelStyle',
  85978. './TextureAtlas',
  85979. './VerticalOrigin'
  85980. ], function(
  85981. BoundingRectangle,
  85982. Cartesian2,
  85983. Color,
  85984. defaultValue,
  85985. defined,
  85986. defineProperties,
  85987. destroyObject,
  85988. DeveloperError,
  85989. Matrix4,
  85990. writeTextToCanvas,
  85991. BillboardCollection,
  85992. HorizontalOrigin,
  85993. Label,
  85994. LabelStyle,
  85995. TextureAtlas,
  85996. VerticalOrigin) {
  85997. 'use strict';
  85998. // A glyph represents a single character in a particular label. It may or may
  85999. // not have a billboard, depending on whether the texture info has an index into
  86000. // the the label collection's texture atlas. Invisible characters have no texture, and
  86001. // no billboard. However, it always has a valid dimensions object.
  86002. function Glyph() {
  86003. this.textureInfo = undefined;
  86004. this.dimensions = undefined;
  86005. this.billboard = undefined;
  86006. }
  86007. // GlyphTextureInfo represents a single character, drawn in a particular style,
  86008. // shared and reference counted across all labels. It may or may not have an
  86009. // index into the label collection's texture atlas, depending on whether the character
  86010. // has both width and height, but it always has a valid dimensions object.
  86011. function GlyphTextureInfo(labelCollection, index, dimensions) {
  86012. this.labelCollection = labelCollection;
  86013. this.index = index;
  86014. this.dimensions = dimensions;
  86015. }
  86016. // Traditionally, leading is %20 of the font size.
  86017. var defaultLineSpacingPercent = 1.2;
  86018. var whitePixelCanvasId = 'ID_WHITE_PIXEL';
  86019. var whitePixelSize = new Cartesian2(4, 4);
  86020. var whitePixelBoundingRegion = new BoundingRectangle(1, 1, 1, 1);
  86021. function addWhitePixelCanvas(textureAtlas, labelCollection) {
  86022. var canvas = document.createElement('canvas');
  86023. canvas.width = whitePixelSize.x;
  86024. canvas.height = whitePixelSize.y;
  86025. var context2D = canvas.getContext('2d');
  86026. context2D.fillStyle = '#fff';
  86027. context2D.fillRect(0, 0, canvas.width, canvas.height);
  86028. textureAtlas.addImage(whitePixelCanvasId, canvas).then(function(index) {
  86029. labelCollection._whitePixelIndex = index;
  86030. });
  86031. }
  86032. // reusable object for calling writeTextToCanvas
  86033. var writeTextToCanvasParameters = {};
  86034. function createGlyphCanvas(character, font, fillColor, outlineColor, outlineWidth, style, verticalOrigin) {
  86035. writeTextToCanvasParameters.font = font;
  86036. writeTextToCanvasParameters.fillColor = fillColor;
  86037. writeTextToCanvasParameters.strokeColor = outlineColor;
  86038. writeTextToCanvasParameters.strokeWidth = outlineWidth;
  86039. if (verticalOrigin === VerticalOrigin.CENTER) {
  86040. writeTextToCanvasParameters.textBaseline = 'middle';
  86041. } else if (verticalOrigin === VerticalOrigin.TOP) {
  86042. writeTextToCanvasParameters.textBaseline = 'top';
  86043. } else {
  86044. // VerticalOrigin.BOTTOM and VerticalOrigin.BASELINE
  86045. writeTextToCanvasParameters.textBaseline = 'bottom';
  86046. }
  86047. writeTextToCanvasParameters.fill = style === LabelStyle.FILL || style === LabelStyle.FILL_AND_OUTLINE;
  86048. writeTextToCanvasParameters.stroke = style === LabelStyle.OUTLINE || style === LabelStyle.FILL_AND_OUTLINE;
  86049. return writeTextToCanvas(character, writeTextToCanvasParameters);
  86050. }
  86051. function unbindGlyph(labelCollection, glyph) {
  86052. glyph.textureInfo = undefined;
  86053. glyph.dimensions = undefined;
  86054. var billboard = glyph.billboard;
  86055. if (defined(billboard)) {
  86056. billboard.show = false;
  86057. billboard.image = undefined;
  86058. labelCollection._spareBillboards.push(billboard);
  86059. glyph.billboard = undefined;
  86060. }
  86061. }
  86062. function addGlyphToTextureAtlas(textureAtlas, id, canvas, glyphTextureInfo) {
  86063. textureAtlas.addImage(id, canvas).then(function(index, id) {
  86064. glyphTextureInfo.index = index;
  86065. });
  86066. }
  86067. function rebindAllGlyphs(labelCollection, label) {
  86068. var text = label._text;
  86069. var textLength = text.length;
  86070. var glyphs = label._glyphs;
  86071. var glyphsLength = glyphs.length;
  86072. var glyph;
  86073. var glyphIndex;
  86074. var textIndex;
  86075. // if we have more glyphs than needed, unbind the extras.
  86076. if (textLength < glyphsLength) {
  86077. for (glyphIndex = textLength; glyphIndex < glyphsLength; ++glyphIndex) {
  86078. unbindGlyph(labelCollection, glyphs[glyphIndex]);
  86079. }
  86080. }
  86081. // presize glyphs to match the new text length
  86082. glyphs.length = textLength;
  86083. var showBackground = label._showBackground && (text.split('\n').join('').length > 0);
  86084. var backgroundBillboard = label._backgroundBillboard;
  86085. var backgroundBillboardCollection = labelCollection._backgroundBillboardCollection;
  86086. if (!showBackground) {
  86087. if (defined(backgroundBillboard)) {
  86088. backgroundBillboardCollection.remove(backgroundBillboard);
  86089. label._backgroundBillboard = backgroundBillboard = undefined;
  86090. }
  86091. } else {
  86092. if (!defined(backgroundBillboard)) {
  86093. backgroundBillboard = backgroundBillboardCollection.add({
  86094. collection : labelCollection,
  86095. image : whitePixelCanvasId,
  86096. imageSubRegion : whitePixelBoundingRegion
  86097. });
  86098. label._backgroundBillboard = backgroundBillboard;
  86099. }
  86100. backgroundBillboard.color = label._backgroundColor;
  86101. backgroundBillboard.show = label._show;
  86102. backgroundBillboard.position = label._position;
  86103. backgroundBillboard.eyeOffset = label._eyeOffset;
  86104. backgroundBillboard.pixelOffset = label._pixelOffset;
  86105. backgroundBillboard.horizontalOrigin = HorizontalOrigin.LEFT;
  86106. backgroundBillboard.verticalOrigin = label._verticalOrigin;
  86107. backgroundBillboard.heightReference = label._heightReference;
  86108. backgroundBillboard.scale = label._scale;
  86109. backgroundBillboard.pickPrimitive = label;
  86110. backgroundBillboard.id = label._id;
  86111. backgroundBillboard.translucencyByDistance = label._translucencyByDistance;
  86112. backgroundBillboard.pixelOffsetScaleByDistance = label._pixelOffsetScaleByDistance;
  86113. backgroundBillboard.distanceDisplayCondition = label._distanceDisplayCondition;
  86114. }
  86115. var glyphTextureCache = labelCollection._glyphTextureCache;
  86116. // walk the text looking for new characters (creating new glyphs for each)
  86117. // or changed characters (rebinding existing glyphs)
  86118. for (textIndex = 0; textIndex < textLength; ++textIndex) {
  86119. var character = text.charAt(textIndex);
  86120. var font = label._font;
  86121. var fillColor = label._fillColor;
  86122. var outlineColor = label._outlineColor;
  86123. var outlineWidth = label._outlineWidth;
  86124. var style = label._style;
  86125. var verticalOrigin = label._verticalOrigin;
  86126. // retrieve glyph dimensions and texture index (if the canvas has area)
  86127. // from the glyph texture cache, or create and add if not present.
  86128. var id = JSON.stringify([
  86129. character,
  86130. font,
  86131. fillColor.toRgba(),
  86132. outlineColor.toRgba(),
  86133. outlineWidth,
  86134. +style,
  86135. +verticalOrigin
  86136. ]);
  86137. var glyphTextureInfo = glyphTextureCache[id];
  86138. if (!defined(glyphTextureInfo)) {
  86139. var canvas = createGlyphCanvas(character, font, fillColor, outlineColor, outlineWidth, style, verticalOrigin);
  86140. glyphTextureInfo = new GlyphTextureInfo(labelCollection, -1, canvas.dimensions);
  86141. glyphTextureCache[id] = glyphTextureInfo;
  86142. if (canvas.width > 0 && canvas.height > 0) {
  86143. addGlyphToTextureAtlas(labelCollection._textureAtlas, id, canvas, glyphTextureInfo);
  86144. }
  86145. }
  86146. glyph = glyphs[textIndex];
  86147. if (defined(glyph)) {
  86148. // clean up leftover information from the previous glyph
  86149. if (glyphTextureInfo.index === -1) {
  86150. // no texture, and therefore no billboard, for this glyph.
  86151. // so, completely unbind glyph.
  86152. unbindGlyph(labelCollection, glyph);
  86153. } else {
  86154. // we have a texture and billboard. If we had one before, release
  86155. // our reference to that texture info, but reuse the billboard.
  86156. if (defined(glyph.textureInfo)) {
  86157. glyph.textureInfo = undefined;
  86158. }
  86159. }
  86160. } else {
  86161. // create a glyph object
  86162. glyph = new Glyph();
  86163. glyphs[textIndex] = glyph;
  86164. }
  86165. glyph.textureInfo = glyphTextureInfo;
  86166. glyph.dimensions = glyphTextureInfo.dimensions;
  86167. // if we have a texture, configure the existing billboard, or obtain one
  86168. if (glyphTextureInfo.index !== -1) {
  86169. var billboard = glyph.billboard;
  86170. var spareBillboards = labelCollection._spareBillboards;
  86171. if (!defined(billboard)) {
  86172. if (spareBillboards.length > 0) {
  86173. billboard = spareBillboards.pop();
  86174. } else {
  86175. billboard = labelCollection._billboardCollection.add({
  86176. collection : labelCollection
  86177. });
  86178. }
  86179. glyph.billboard = billboard;
  86180. }
  86181. billboard.show = label._show;
  86182. billboard.position = label._position;
  86183. billboard.eyeOffset = label._eyeOffset;
  86184. billboard.pixelOffset = label._pixelOffset;
  86185. billboard.horizontalOrigin = HorizontalOrigin.LEFT;
  86186. billboard.verticalOrigin = label._verticalOrigin;
  86187. billboard.heightReference = label._heightReference;
  86188. billboard.scale = label._scale;
  86189. billboard.pickPrimitive = label;
  86190. billboard.id = label._id;
  86191. billboard.image = id;
  86192. billboard.translucencyByDistance = label._translucencyByDistance;
  86193. billboard.pixelOffsetScaleByDistance = label._pixelOffsetScaleByDistance;
  86194. billboard.distanceDisplayCondition = label._distanceDisplayCondition;
  86195. }
  86196. }
  86197. // changing glyphs will cause the position of the
  86198. // glyphs to change, since different characters have different widths
  86199. label._repositionAllGlyphs = true;
  86200. }
  86201. function calculateWidthOffset(lineWidth, horizontalOrigin, backgroundPadding) {
  86202. if (horizontalOrigin === HorizontalOrigin.CENTER) {
  86203. return -lineWidth / 2;
  86204. } else if (horizontalOrigin === HorizontalOrigin.RIGHT) {
  86205. return -(lineWidth + backgroundPadding.x);
  86206. }
  86207. return backgroundPadding.x;
  86208. }
  86209. // reusable Cartesian2 instances
  86210. var glyphPixelOffset = new Cartesian2();
  86211. var scratchBackgroundPadding = new Cartesian2();
  86212. function repositionAllGlyphs(label, resolutionScale) {
  86213. var glyphs = label._glyphs;
  86214. var text = label._text;
  86215. var glyph;
  86216. var dimensions;
  86217. var lastLineWidth = 0;
  86218. var maxLineWidth = 0;
  86219. var lineWidths = [];
  86220. var maxGlyphDescent = Number.NEGATIVE_INFINITY;
  86221. var maxGlyphY = 0;
  86222. var numberOfLines = 1;
  86223. var glyphIndex = 0;
  86224. var glyphLength = glyphs.length;
  86225. var backgroundBillboard = label._backgroundBillboard;
  86226. var backgroundPadding = scratchBackgroundPadding;
  86227. Cartesian2.clone(
  86228. (defined(backgroundBillboard) ? label._backgroundPadding : Cartesian2.ZERO),
  86229. backgroundPadding);
  86230. for (glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) {
  86231. if (text.charAt(glyphIndex) === '\n') {
  86232. lineWidths.push(lastLineWidth);
  86233. ++numberOfLines;
  86234. lastLineWidth = 0;
  86235. } else {
  86236. glyph = glyphs[glyphIndex];
  86237. dimensions = glyph.dimensions;
  86238. maxGlyphY = Math.max(maxGlyphY, dimensions.height - dimensions.descent);
  86239. maxGlyphDescent = Math.max(maxGlyphDescent, dimensions.descent);
  86240. //Computing the line width must also account for the kerning that occurs between letters.
  86241. lastLineWidth += dimensions.width - dimensions.bounds.minx;
  86242. if (glyphIndex < glyphLength - 1) {
  86243. lastLineWidth += glyphs[glyphIndex + 1].dimensions.bounds.minx;
  86244. }
  86245. maxLineWidth = Math.max(maxLineWidth, lastLineWidth);
  86246. }
  86247. }
  86248. lineWidths.push(lastLineWidth);
  86249. var maxLineHeight = maxGlyphY + maxGlyphDescent;
  86250. var scale = label._scale;
  86251. var horizontalOrigin = label._horizontalOrigin;
  86252. var verticalOrigin = label._verticalOrigin;
  86253. var lineIndex = 0;
  86254. var lineWidth = lineWidths[lineIndex];
  86255. var widthOffset = calculateWidthOffset(lineWidth, horizontalOrigin, backgroundPadding);
  86256. var lineSpacing = defaultLineSpacingPercent * maxLineHeight;
  86257. var otherLinesHeight = lineSpacing * (numberOfLines - 1);
  86258. glyphPixelOffset.x = widthOffset * scale * resolutionScale;
  86259. glyphPixelOffset.y = 0;
  86260. var lineOffsetY = 0;
  86261. for (glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) {
  86262. if (text.charAt(glyphIndex) === '\n') {
  86263. ++lineIndex;
  86264. lineOffsetY += lineSpacing;
  86265. lineWidth = lineWidths[lineIndex];
  86266. widthOffset = calculateWidthOffset(lineWidth, horizontalOrigin, backgroundPadding);
  86267. glyphPixelOffset.x = widthOffset * scale * resolutionScale;
  86268. } else {
  86269. glyph = glyphs[glyphIndex];
  86270. dimensions = glyph.dimensions;
  86271. if (verticalOrigin === VerticalOrigin.TOP) {
  86272. glyphPixelOffset.y = dimensions.height - maxGlyphY - backgroundPadding.y;
  86273. } else if (verticalOrigin === VerticalOrigin.CENTER) {
  86274. glyphPixelOffset.y = (otherLinesHeight + dimensions.height - maxGlyphY) / 2;
  86275. } else if (verticalOrigin === VerticalOrigin.BASELINE) {
  86276. glyphPixelOffset.y = otherLinesHeight;
  86277. } else {
  86278. // VerticalOrigin.BOTTOM
  86279. glyphPixelOffset.y = otherLinesHeight + maxGlyphDescent + backgroundPadding.y;
  86280. }
  86281. glyphPixelOffset.y = (glyphPixelOffset.y - dimensions.descent - lineOffsetY) * scale * resolutionScale;
  86282. if (defined(glyph.billboard)) {
  86283. glyph.billboard._setTranslate(glyphPixelOffset);
  86284. }
  86285. //Compute the next x offset taking into acocunt the kerning performed
  86286. //on both the current letter as well as the next letter to be drawn
  86287. //as well as any applied scale.
  86288. if (glyphIndex < glyphLength - 1) {
  86289. var nextGlyph = glyphs[glyphIndex + 1];
  86290. glyphPixelOffset.x += ((dimensions.width - dimensions.bounds.minx) + nextGlyph.dimensions.bounds.minx) * scale * resolutionScale;
  86291. }
  86292. }
  86293. }
  86294. if (defined(backgroundBillboard) && (text.split('\n').join('').length > 0)) {
  86295. if (horizontalOrigin === HorizontalOrigin.CENTER) {
  86296. widthOffset = -maxLineWidth / 2 - backgroundPadding.x;
  86297. } else if (horizontalOrigin === HorizontalOrigin.RIGHT) {
  86298. widthOffset = -(maxLineWidth + backgroundPadding.x * 2);
  86299. } else {
  86300. widthOffset = 0;
  86301. }
  86302. glyphPixelOffset.x = widthOffset * scale * resolutionScale;
  86303. if (verticalOrigin === VerticalOrigin.TOP) {
  86304. glyphPixelOffset.y = maxLineHeight - maxGlyphY - maxGlyphDescent;
  86305. } else if (verticalOrigin === VerticalOrigin.CENTER) {
  86306. glyphPixelOffset.y = (maxLineHeight - maxGlyphY) / 2 - maxGlyphDescent;
  86307. } else if (verticalOrigin === VerticalOrigin.BASELINE) {
  86308. glyphPixelOffset.y = -backgroundPadding.y - maxGlyphDescent;
  86309. } else {
  86310. // VerticalOrigin.BOTTOM
  86311. glyphPixelOffset.y = 0;
  86312. }
  86313. glyphPixelOffset.y = glyphPixelOffset.y * scale * resolutionScale;
  86314. backgroundBillboard.width = maxLineWidth + (backgroundPadding.x * 2);
  86315. backgroundBillboard.height = maxLineHeight + otherLinesHeight + (backgroundPadding.y * 2);
  86316. backgroundBillboard._setTranslate(glyphPixelOffset);
  86317. }
  86318. }
  86319. function destroyLabel(labelCollection, label) {
  86320. var glyphs = label._glyphs;
  86321. for (var i = 0, len = glyphs.length; i < len; ++i) {
  86322. unbindGlyph(labelCollection, glyphs[i]);
  86323. }
  86324. if (defined(label._backgroundBillboard)) {
  86325. labelCollection._backgroundBillboardCollection.remove(label._backgroundBillboard);
  86326. label._backgroundBillboard = undefined;
  86327. }
  86328. label._labelCollection = undefined;
  86329. if (defined(label._removeCallbackFunc)) {
  86330. label._removeCallbackFunc();
  86331. }
  86332. destroyObject(label);
  86333. }
  86334. /**
  86335. * A renderable collection of labels. Labels are viewport-aligned text positioned in the 3D scene.
  86336. * Each label can have a different font, color, scale, etc.
  86337. * <br /><br />
  86338. * <div align='center'>
  86339. * <img src='images/Label.png' width='400' height='300' /><br />
  86340. * Example labels
  86341. * </div>
  86342. * <br /><br />
  86343. * Labels are added and removed from the collection using {@link LabelCollection#add}
  86344. * and {@link LabelCollection#remove}.
  86345. *
  86346. * @alias LabelCollection
  86347. * @constructor
  86348. *
  86349. * @param {Object} [options] Object with the following properties:
  86350. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms each label from model to world coordinates.
  86351. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
  86352. * @param {Scene} [options.scene] Must be passed in for labels that use the height reference property or will be depth tested against the globe.
  86353. *
  86354. * @performance For best performance, prefer a few collections, each with many labels, to
  86355. * many collections with only a few labels each. Avoid having collections where some
  86356. * labels change every frame and others do not; instead, create one or more collections
  86357. * for static labels, and one or more collections for dynamic labels.
  86358. *
  86359. * @see LabelCollection#add
  86360. * @see LabelCollection#remove
  86361. * @see Label
  86362. * @see BillboardCollection
  86363. *
  86364. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Labels.html|Cesium Sandcastle Labels Demo}
  86365. *
  86366. * @example
  86367. * // Create a label collection with two labels
  86368. * var labels = scene.primitives.add(new Cesium.LabelCollection());
  86369. * labels.add({
  86370. * position : new Cesium.Cartesian3(1.0, 2.0, 3.0),
  86371. * text : 'A label'
  86372. * });
  86373. * labels.add({
  86374. * position : new Cesium.Cartesian3(4.0, 5.0, 6.0),
  86375. * text : 'Another label'
  86376. * });
  86377. */
  86378. function LabelCollection(options) {
  86379. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  86380. this._scene = options.scene;
  86381. this._textureAtlas = undefined;
  86382. this._backgroundTextureAtlas = undefined;
  86383. this._whitePixelIndex = undefined;
  86384. this._backgroundBillboardCollection = new BillboardCollection({
  86385. scene : this._scene
  86386. });
  86387. this._backgroundBillboardCollection.destroyTextureAtlas = false;
  86388. this._billboardCollection = new BillboardCollection({
  86389. scene : this._scene
  86390. });
  86391. this._billboardCollection.destroyTextureAtlas = false;
  86392. this._spareBillboards = [];
  86393. this._glyphTextureCache = {};
  86394. this._labels = [];
  86395. this._labelsToUpdate = [];
  86396. this._totalGlyphCount = 0;
  86397. this._resolutionScale = undefined;
  86398. /**
  86399. * The 4x4 transformation matrix that transforms each label in this collection from model to world coordinates.
  86400. * When this is the identity matrix, the labels are drawn in world coordinates, i.e., Earth's WGS84 coordinates.
  86401. * Local reference frames can be used by providing a different transformation matrix, like that returned
  86402. * by {@link Transforms.eastNorthUpToFixedFrame}.
  86403. *
  86404. * @type Matrix4
  86405. * @default {@link Matrix4.IDENTITY}
  86406. *
  86407. * @example
  86408. * var center = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883);
  86409. * labels.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
  86410. * labels.add({
  86411. * position : new Cesium.Cartesian3(0.0, 0.0, 0.0),
  86412. * text : 'Center'
  86413. * });
  86414. * labels.add({
  86415. * position : new Cesium.Cartesian3(1000000.0, 0.0, 0.0),
  86416. * text : 'East'
  86417. * });
  86418. * labels.add({
  86419. * position : new Cesium.Cartesian3(0.0, 1000000.0, 0.0),
  86420. * text : 'North'
  86421. * });
  86422. * labels.add({
  86423. * position : new Cesium.Cartesian3(0.0, 0.0, 1000000.0),
  86424. * text : 'Up'
  86425. * });
  86426. */
  86427. this.modelMatrix = Matrix4.clone(defaultValue(options.modelMatrix, Matrix4.IDENTITY));
  86428. /**
  86429. * This property is for debugging only; it is not for production use nor is it optimized.
  86430. * <p>
  86431. * Draws the bounding sphere for each draw command in the primitive.
  86432. * </p>
  86433. *
  86434. * @type {Boolean}
  86435. *
  86436. * @default false
  86437. */
  86438. this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false);
  86439. }
  86440. defineProperties(LabelCollection.prototype, {
  86441. /**
  86442. * Returns the number of labels in this collection. This is commonly used with
  86443. * {@link LabelCollection#get} to iterate over all the labels
  86444. * in the collection.
  86445. * @memberof LabelCollection.prototype
  86446. * @type {Number}
  86447. */
  86448. length : {
  86449. get : function() {
  86450. return this._labels.length;
  86451. }
  86452. }
  86453. });
  86454. /**
  86455. * Creates and adds a label with the specified initial properties to the collection.
  86456. * The added label is returned so it can be modified or removed from the collection later.
  86457. *
  86458. * @param {Object}[options] A template describing the label's properties as shown in Example 1.
  86459. * @returns {Label} The label that was added to the collection.
  86460. *
  86461. * @performance Calling <code>add</code> is expected constant time. However, the collection's vertex buffer
  86462. * is rewritten; this operations is <code>O(n)</code> and also incurs
  86463. * CPU to GPU overhead. For best performance, add as many billboards as possible before
  86464. * calling <code>update</code>.
  86465. *
  86466. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  86467. *
  86468. *
  86469. * @example
  86470. * // Example 1: Add a label, specifying all the default values.
  86471. * var l = labels.add({
  86472. * show : true,
  86473. * position : Cesium.Cartesian3.ZERO,
  86474. * text : '',
  86475. * font : '30px sans-serif',
  86476. * fillColor : Cesium.Color.WHITE,
  86477. * outlineColor : Cesium.Color.BLACK,
  86478. * outlineWidth : 1.0,
  86479. * showBackground : false,
  86480. * backgroundColor : new Cesium.Color(0.165, 0.165, 0.165, 0.8),
  86481. * backgroundPadding : new Cesium.Cartesian2(7, 5),
  86482. * style : Cesium.LabelStyle.FILL,
  86483. * pixelOffset : Cesium.Cartesian2.ZERO,
  86484. * eyeOffset : Cesium.Cartesian3.ZERO,
  86485. * horizontalOrigin : Cesium.HorizontalOrigin.LEFT,
  86486. * verticalOrigin : Cesium.VerticalOrigin.BASELINE,
  86487. * scale : 1.0,
  86488. * translucencyByDistance : undefined,
  86489. * pixelOffsetScaleByDistance : undefined,
  86490. * heightReference : HeightReference.NONE,
  86491. * distanceDisplayCondition : undefined
  86492. * });
  86493. *
  86494. * @example
  86495. * // Example 2: Specify only the label's cartographic position,
  86496. * // text, and font.
  86497. * var l = labels.add({
  86498. * position : Cesium.Cartesian3.fromRadians(longitude, latitude, height),
  86499. * text : 'Hello World',
  86500. * font : '24px Helvetica',
  86501. * });
  86502. *
  86503. * @see LabelCollection#remove
  86504. * @see LabelCollection#removeAll
  86505. */
  86506. LabelCollection.prototype.add = function(options) {
  86507. var label = new Label(options, this);
  86508. this._labels.push(label);
  86509. this._labelsToUpdate.push(label);
  86510. return label;
  86511. };
  86512. /**
  86513. * Removes a label from the collection. Once removed, a label is no longer usable.
  86514. *
  86515. * @param {Label} label The label to remove.
  86516. * @returns {Boolean} <code>true</code> if the label was removed; <code>false</code> if the label was not found in the collection.
  86517. *
  86518. * @performance Calling <code>remove</code> is expected constant time. However, the collection's vertex buffer
  86519. * is rewritten - an <code>O(n)</code> operation that also incurs CPU to GPU overhead. For
  86520. * best performance, remove as many labels as possible before calling <code>update</code>.
  86521. * If you intend to temporarily hide a label, it is usually more efficient to call
  86522. * {@link Label#show} instead of removing and re-adding the label.
  86523. *
  86524. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  86525. *
  86526. *
  86527. * @example
  86528. * var l = labels.add(...);
  86529. * labels.remove(l); // Returns true
  86530. *
  86531. * @see LabelCollection#add
  86532. * @see LabelCollection#removeAll
  86533. * @see Label#show
  86534. */
  86535. LabelCollection.prototype.remove = function(label) {
  86536. if (defined(label) && label._labelCollection === this) {
  86537. var index = this._labels.indexOf(label);
  86538. if (index !== -1) {
  86539. this._labels.splice(index, 1);
  86540. destroyLabel(this, label);
  86541. return true;
  86542. }
  86543. }
  86544. return false;
  86545. };
  86546. /**
  86547. * Removes all labels from the collection.
  86548. *
  86549. * @performance <code>O(n)</code>. It is more efficient to remove all the labels
  86550. * from a collection and then add new ones than to create a new collection entirely.
  86551. *
  86552. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  86553. *
  86554. *
  86555. * @example
  86556. * labels.add(...);
  86557. * labels.add(...);
  86558. * labels.removeAll();
  86559. *
  86560. * @see LabelCollection#add
  86561. * @see LabelCollection#remove
  86562. */
  86563. LabelCollection.prototype.removeAll = function() {
  86564. var labels = this._labels;
  86565. for (var i = 0, len = labels.length; i < len; ++i) {
  86566. destroyLabel(this, labels[i]);
  86567. }
  86568. labels.length = 0;
  86569. };
  86570. /**
  86571. * Check whether this collection contains a given label.
  86572. *
  86573. * @param {Label} label The label to check for.
  86574. * @returns {Boolean} true if this collection contains the label, false otherwise.
  86575. *
  86576. * @see LabelCollection#get
  86577. */
  86578. LabelCollection.prototype.contains = function(label) {
  86579. return defined(label) && label._labelCollection === this;
  86580. };
  86581. /**
  86582. * Returns the label in the collection at the specified index. Indices are zero-based
  86583. * and increase as labels are added. Removing a label shifts all labels after
  86584. * it to the left, changing their indices. This function is commonly used with
  86585. * {@link LabelCollection#length} to iterate over all the labels
  86586. * in the collection.
  86587. *
  86588. * @param {Number} index The zero-based index of the billboard.
  86589. *
  86590. * @returns {Label} The label at the specified index.
  86591. *
  86592. * @performance Expected constant time. If labels were removed from the collection and
  86593. * {@link Scene#render} was not called, an implicit <code>O(n)</code>
  86594. * operation is performed.
  86595. *
  86596. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  86597. *
  86598. *
  86599. * @example
  86600. * // Toggle the show property of every label in the collection
  86601. * var len = labels.length;
  86602. * for (var i = 0; i < len; ++i) {
  86603. * var l = billboards.get(i);
  86604. * l.show = !l.show;
  86605. * }
  86606. *
  86607. * @see LabelCollection#length
  86608. */
  86609. LabelCollection.prototype.get = function(index) {
  86610. if (!defined(index)) {
  86611. throw new DeveloperError('index is required.');
  86612. }
  86613. return this._labels[index];
  86614. };
  86615. /**
  86616. * @private
  86617. */
  86618. LabelCollection.prototype.update = function(frameState) {
  86619. var billboardCollection = this._billboardCollection;
  86620. var backgroundBillboardCollection = this._backgroundBillboardCollection;
  86621. billboardCollection.modelMatrix = this.modelMatrix;
  86622. billboardCollection.debugShowBoundingVolume = this.debugShowBoundingVolume;
  86623. backgroundBillboardCollection.modelMatrix = this.modelMatrix;
  86624. backgroundBillboardCollection.debugShowBoundingVolume = this.debugShowBoundingVolume;
  86625. var context = frameState.context;
  86626. if (!defined(this._textureAtlas)) {
  86627. this._textureAtlas = new TextureAtlas({
  86628. context : context
  86629. });
  86630. billboardCollection.textureAtlas = this._textureAtlas;
  86631. }
  86632. if (!defined(this._backgroundTextureAtlas)) {
  86633. this._backgroundTextureAtlas = new TextureAtlas({
  86634. context : context,
  86635. initialSize : whitePixelSize
  86636. });
  86637. backgroundBillboardCollection.textureAtlas = this._backgroundTextureAtlas;
  86638. addWhitePixelCanvas(this._backgroundTextureAtlas, this);
  86639. }
  86640. var uniformState = context.uniformState;
  86641. var resolutionScale = uniformState.resolutionScale;
  86642. var resolutionChanged = this._resolutionScale !== resolutionScale;
  86643. this._resolutionScale = resolutionScale;
  86644. var labelsToUpdate;
  86645. if (resolutionChanged) {
  86646. labelsToUpdate = this._labels;
  86647. } else {
  86648. labelsToUpdate = this._labelsToUpdate;
  86649. }
  86650. var len = labelsToUpdate.length;
  86651. for (var i = 0; i < len; ++i) {
  86652. var label = labelsToUpdate[i];
  86653. if (label.isDestroyed()) {
  86654. continue;
  86655. }
  86656. var preUpdateGlyphCount = label._glyphs.length;
  86657. if (label._rebindAllGlyphs) {
  86658. rebindAllGlyphs(this, label);
  86659. label._rebindAllGlyphs = false;
  86660. }
  86661. if (resolutionChanged || label._repositionAllGlyphs) {
  86662. repositionAllGlyphs(label, resolutionScale);
  86663. label._repositionAllGlyphs = false;
  86664. }
  86665. var glyphCountDifference = label._glyphs.length - preUpdateGlyphCount;
  86666. this._totalGlyphCount += glyphCountDifference;
  86667. }
  86668. this._labelsToUpdate.length = 0;
  86669. backgroundBillboardCollection.update(frameState);
  86670. billboardCollection.update(frameState);
  86671. };
  86672. /**
  86673. * Returns true if this object was destroyed; otherwise, false.
  86674. * <br /><br />
  86675. * If this object was destroyed, it should not be used; calling any function other than
  86676. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  86677. *
  86678. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  86679. *
  86680. * @see LabelCollection#destroy
  86681. */
  86682. LabelCollection.prototype.isDestroyed = function() {
  86683. return false;
  86684. };
  86685. /**
  86686. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  86687. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  86688. * <br /><br />
  86689. * Once an object is destroyed, it should not be used; calling any function other than
  86690. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  86691. * assign the return value (<code>undefined</code>) to the object as done in the example.
  86692. *
  86693. * @returns {undefined}
  86694. *
  86695. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  86696. *
  86697. *
  86698. * @example
  86699. * labels = labels && labels.destroy();
  86700. *
  86701. * @see LabelCollection#isDestroyed
  86702. */
  86703. LabelCollection.prototype.destroy = function() {
  86704. this.removeAll();
  86705. this._billboardCollection = this._billboardCollection.destroy();
  86706. this._textureAtlas = this._textureAtlas && this._textureAtlas.destroy();
  86707. this._backgroundBillboardCollection = this._backgroundBillboardCollection.destroy();
  86708. this._backgroundTextureAtlas = this._backgroundTextureAtlas && this._backgroundTextureAtlas.destroy();
  86709. return destroyObject(this);
  86710. };
  86711. return LabelCollection;
  86712. });
  86713. /*global define*/
  86714. define('Scene/PointPrimitive',[
  86715. '../Core/BoundingRectangle',
  86716. '../Core/Cartesian2',
  86717. '../Core/Cartesian3',
  86718. '../Core/Cartesian4',
  86719. '../Core/Color',
  86720. '../Core/defaultValue',
  86721. '../Core/defined',
  86722. '../Core/defineProperties',
  86723. '../Core/DeveloperError',
  86724. '../Core/DistanceDisplayCondition',
  86725. '../Core/Matrix4',
  86726. '../Core/NearFarScalar',
  86727. './SceneMode',
  86728. './SceneTransforms'
  86729. ], function(
  86730. BoundingRectangle,
  86731. Cartesian2,
  86732. Cartesian3,
  86733. Cartesian4,
  86734. Color,
  86735. defaultValue,
  86736. defined,
  86737. defineProperties,
  86738. DeveloperError,
  86739. DistanceDisplayCondition,
  86740. Matrix4,
  86741. NearFarScalar,
  86742. SceneMode,
  86743. SceneTransforms) {
  86744. 'use strict';
  86745. /**
  86746. * A graphical point positioned in the 3D scene, that is created
  86747. * and rendered using a {@link PointPrimitiveCollection}. A point is created and its initial
  86748. * properties are set by calling {@link PointPrimitiveCollection#add}.
  86749. *
  86750. * @alias PointPrimitive
  86751. *
  86752. * @performance Reading a property, e.g., {@link PointPrimitive#show}, is constant time.
  86753. * Assigning to a property is constant time but results in
  86754. * CPU to GPU traffic when {@link PointPrimitiveCollection#update} is called. The per-pointPrimitive traffic is
  86755. * the same regardless of how many properties were updated. If most pointPrimitives in a collection need to be
  86756. * updated, it may be more efficient to clear the collection with {@link PointPrimitiveCollection#removeAll}
  86757. * and add new pointPrimitives instead of modifying each one.
  86758. *
  86759. * @exception {DeveloperError} scaleByDistance.far must be greater than scaleByDistance.near
  86760. * @exception {DeveloperError} translucencyByDistance.far must be greater than translucencyByDistance.near
  86761. * @exception {DeveloperError} distanceDisplayCondition.far must be greater than distanceDisplayCondition.near
  86762. *
  86763. * @see PointPrimitiveCollection
  86764. * @see PointPrimitiveCollection#add
  86765. *
  86766. * @internalConstructor
  86767. *
  86768. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Points.html|Cesium Sandcastle Points Demo}
  86769. */
  86770. function PointPrimitive(options, pointPrimitiveCollection) {
  86771. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  86772. if (defined(options.scaleByDistance) && options.scaleByDistance.far <= options.scaleByDistance.near) {
  86773. throw new DeveloperError('scaleByDistance.far must be greater than scaleByDistance.near.');
  86774. }
  86775. if (defined(options.translucencyByDistance) && options.translucencyByDistance.far <= options.translucencyByDistance.near) {
  86776. throw new DeveloperError('translucencyByDistance.far must be greater than translucencyByDistance.near.');
  86777. }
  86778. if (defined(options.distanceDisplayCondition) && options.distanceDisplayCondition.far <= options.distanceDisplayCondition.near) {
  86779. throw new DeveloperError('distanceDisplayCondition.far must be greater than distanceDisplayCondition.near');
  86780. }
  86781. this._show = defaultValue(options.show, true);
  86782. this._position = Cartesian3.clone(defaultValue(options.position, Cartesian3.ZERO));
  86783. this._actualPosition = Cartesian3.clone(this._position); // For columbus view and 2D
  86784. this._color = Color.clone(defaultValue(options.color, Color.WHITE));
  86785. this._outlineColor = Color.clone(defaultValue(options.outlineColor, Color.TRANSPARENT));
  86786. this._outlineWidth = defaultValue(options.outlineWidth, 0.0);
  86787. this._pixelSize = defaultValue(options.pixelSize, 10.0);
  86788. this._scaleByDistance = options.scaleByDistance;
  86789. this._translucencyByDistance = options.translucencyByDistance;
  86790. this._distanceDisplayCondition = options.distanceDisplayCondition;
  86791. this._id = options.id;
  86792. this._collection = defaultValue(options.collection, pointPrimitiveCollection);
  86793. this._clusterShow = true;
  86794. this._pickId = undefined;
  86795. this._pointPrimitiveCollection = pointPrimitiveCollection;
  86796. this._dirty = false;
  86797. this._index = -1; //Used only by PointPrimitiveCollection
  86798. }
  86799. var SHOW_INDEX = PointPrimitive.SHOW_INDEX = 0;
  86800. var POSITION_INDEX = PointPrimitive.POSITION_INDEX = 1;
  86801. var COLOR_INDEX = PointPrimitive.COLOR_INDEX = 2;
  86802. var OUTLINE_COLOR_INDEX = PointPrimitive.OUTLINE_COLOR_INDEX = 3;
  86803. var OUTLINE_WIDTH_INDEX = PointPrimitive.OUTLINE_WIDTH_INDEX = 4;
  86804. var PIXEL_SIZE_INDEX = PointPrimitive.PIXEL_SIZE_INDEX = 5;
  86805. var SCALE_BY_DISTANCE_INDEX = PointPrimitive.SCALE_BY_DISTANCE_INDEX = 6;
  86806. var TRANSLUCENCY_BY_DISTANCE_INDEX = PointPrimitive.TRANSLUCENCY_BY_DISTANCE_INDEX = 7;
  86807. var DISTANCE_DISPLAY_CONDITION_INDEX = PointPrimitive.DISTANCE_DISPLAY_CONDITION = 8;
  86808. PointPrimitive.NUMBER_OF_PROPERTIES = 9;
  86809. function makeDirty(pointPrimitive, propertyChanged) {
  86810. var pointPrimitiveCollection = pointPrimitive._pointPrimitiveCollection;
  86811. if (defined(pointPrimitiveCollection)) {
  86812. pointPrimitiveCollection._updatePointPrimitive(pointPrimitive, propertyChanged);
  86813. pointPrimitive._dirty = true;
  86814. }
  86815. }
  86816. defineProperties(PointPrimitive.prototype, {
  86817. /**
  86818. * Determines if this point will be shown. Use this to hide or show a point, instead
  86819. * of removing it and re-adding it to the collection.
  86820. * @memberof PointPrimitive.prototype
  86821. * @type {Boolean}
  86822. */
  86823. show : {
  86824. get : function() {
  86825. return this._show;
  86826. },
  86827. set : function(value) {
  86828. if (!defined(value)) {
  86829. throw new DeveloperError('value is required.');
  86830. }
  86831. if (this._show !== value) {
  86832. this._show = value;
  86833. makeDirty(this, SHOW_INDEX);
  86834. }
  86835. }
  86836. },
  86837. /**
  86838. * Gets or sets the Cartesian position of this point.
  86839. * @memberof PointPrimitive.prototype
  86840. * @type {Cartesian3}
  86841. */
  86842. position : {
  86843. get : function() {
  86844. return this._position;
  86845. },
  86846. set : function(value) {
  86847. if (!defined(value)) {
  86848. throw new DeveloperError('value is required.');
  86849. }
  86850. var position = this._position;
  86851. if (!Cartesian3.equals(position, value)) {
  86852. Cartesian3.clone(value, position);
  86853. Cartesian3.clone(value, this._actualPosition);
  86854. makeDirty(this, POSITION_INDEX);
  86855. }
  86856. }
  86857. },
  86858. /**
  86859. * Gets or sets near and far scaling properties of a point based on the point's distance from the camera.
  86860. * A point's scale will interpolate between the {@link NearFarScalar#nearValue} and
  86861. * {@link NearFarScalar#farValue} while the camera distance falls within the upper and lower bounds
  86862. * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
  86863. * Outside of these ranges the point's scale remains clamped to the nearest bound. This scale
  86864. * multiplies the pixelSize and outlineWidth to affect the total size of the point. If undefined,
  86865. * scaleByDistance will be disabled.
  86866. * @memberof PointPrimitive.prototype
  86867. * @type {NearFarScalar}
  86868. *
  86869. * @example
  86870. * // Example 1.
  86871. * // Set a pointPrimitive's scaleByDistance to scale to 15 when the
  86872. * // camera is 1500 meters from the pointPrimitive and disappear as
  86873. * // the camera distance approaches 8.0e6 meters.
  86874. * p.scaleByDistance = new Cesium.NearFarScalar(1.5e2, 15, 8.0e6, 0.0);
  86875. *
  86876. * @example
  86877. * // Example 2.
  86878. * // disable scaling by distance
  86879. * p.scaleByDistance = undefined;
  86880. */
  86881. scaleByDistance : {
  86882. get : function() {
  86883. return this._scaleByDistance;
  86884. },
  86885. set : function(value) {
  86886. if (defined(value) && value.far <= value.near) {
  86887. throw new DeveloperError('far distance must be greater than near distance.');
  86888. }
  86889. var scaleByDistance = this._scaleByDistance;
  86890. if (!NearFarScalar.equals(scaleByDistance, value)) {
  86891. this._scaleByDistance = NearFarScalar.clone(value, scaleByDistance);
  86892. makeDirty(this, SCALE_BY_DISTANCE_INDEX);
  86893. }
  86894. }
  86895. },
  86896. /**
  86897. * Gets or sets near and far translucency properties of a point based on the point's distance from the camera.
  86898. * A point's translucency will interpolate between the {@link NearFarScalar#nearValue} and
  86899. * {@link NearFarScalar#farValue} while the camera distance falls within the upper and lower bounds
  86900. * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
  86901. * Outside of these ranges the point's translucency remains clamped to the nearest bound. If undefined,
  86902. * translucencyByDistance will be disabled.
  86903. * @memberof PointPrimitive.prototype
  86904. * @type {NearFarScalar}
  86905. *
  86906. * @example
  86907. * // Example 1.
  86908. * // Set a point's translucency to 1.0 when the
  86909. * // camera is 1500 meters from the point and disappear as
  86910. * // the camera distance approaches 8.0e6 meters.
  86911. * p.translucencyByDistance = new Cesium.NearFarScalar(1.5e2, 1.0, 8.0e6, 0.0);
  86912. *
  86913. * @example
  86914. * // Example 2.
  86915. * // disable translucency by distance
  86916. * p.translucencyByDistance = undefined;
  86917. */
  86918. translucencyByDistance : {
  86919. get : function() {
  86920. return this._translucencyByDistance;
  86921. },
  86922. set : function(value) {
  86923. if (defined(value) && value.far <= value.near) {
  86924. throw new DeveloperError('far distance must be greater than near distance.');
  86925. }
  86926. var translucencyByDistance = this._translucencyByDistance;
  86927. if (!NearFarScalar.equals(translucencyByDistance, value)) {
  86928. this._translucencyByDistance = NearFarScalar.clone(value, translucencyByDistance);
  86929. makeDirty(this, TRANSLUCENCY_BY_DISTANCE_INDEX);
  86930. }
  86931. }
  86932. },
  86933. /**
  86934. * Gets or sets the inner size of the point in pixels.
  86935. * @memberof PointPrimitive.prototype
  86936. * @type {Number}
  86937. */
  86938. pixelSize : {
  86939. get : function() {
  86940. return this._pixelSize;
  86941. },
  86942. set : function(value) {
  86943. if (!defined(value)) {
  86944. throw new DeveloperError('value is required.');
  86945. }
  86946. if (this._pixelSize !== value) {
  86947. this._pixelSize = value;
  86948. makeDirty(this, PIXEL_SIZE_INDEX);
  86949. }
  86950. }
  86951. },
  86952. /**
  86953. * Gets or sets the inner color of the point.
  86954. * The red, green, blue, and alpha values are indicated by <code>value</code>'s <code>red</code>, <code>green</code>,
  86955. * <code>blue</code>, and <code>alpha</code> properties as shown in Example 1. These components range from <code>0.0</code>
  86956. * (no intensity) to <code>1.0</code> (full intensity).
  86957. * @memberof PointPrimitive.prototype
  86958. * @type {Color}
  86959. *
  86960. * @example
  86961. * // Example 1. Assign yellow.
  86962. * p.color = Cesium.Color.YELLOW;
  86963. *
  86964. * @example
  86965. * // Example 2. Make a pointPrimitive 50% translucent.
  86966. * p.color = new Cesium.Color(1.0, 1.0, 1.0, 0.5);
  86967. */
  86968. color : {
  86969. get : function() {
  86970. return this._color;
  86971. },
  86972. set : function(value) {
  86973. if (!defined(value)) {
  86974. throw new DeveloperError('value is required.');
  86975. }
  86976. var color = this._color;
  86977. if (!Color.equals(color, value)) {
  86978. Color.clone(value, color);
  86979. makeDirty(this, COLOR_INDEX);
  86980. }
  86981. }
  86982. },
  86983. /**
  86984. * Gets or sets the outline color of the point.
  86985. * @memberof PointPrimitive.prototype
  86986. * @type {Color}
  86987. */
  86988. outlineColor : {
  86989. get : function() {
  86990. return this._outlineColor;
  86991. },
  86992. set : function(value) {
  86993. if (!defined(value)) {
  86994. throw new DeveloperError('value is required.');
  86995. }
  86996. var outlineColor = this._outlineColor;
  86997. if (!Color.equals(outlineColor, value)) {
  86998. Color.clone(value, outlineColor);
  86999. makeDirty(this, OUTLINE_COLOR_INDEX);
  87000. }
  87001. }
  87002. },
  87003. /**
  87004. * Gets or sets the outline width in pixels. This width adds to pixelSize,
  87005. * increasing the total size of the point.
  87006. * @memberof PointPrimitive.prototype
  87007. * @type {Number}
  87008. */
  87009. outlineWidth : {
  87010. get : function() {
  87011. return this._outlineWidth;
  87012. },
  87013. set : function(value) {
  87014. if (!defined(value)) {
  87015. throw new DeveloperError('value is required.');
  87016. }
  87017. if (this._outlineWidth !== value) {
  87018. this._outlineWidth = value;
  87019. makeDirty(this, OUTLINE_WIDTH_INDEX);
  87020. }
  87021. }
  87022. },
  87023. /**
  87024. * Gets or sets the condition specifying at what distance from the camera that this point will be displayed.
  87025. * @memberof PointPrimitive.prototype
  87026. * @type {DistanceDisplayCondition}
  87027. * @default undefined
  87028. */
  87029. distanceDisplayCondition : {
  87030. get : function() {
  87031. return this._distanceDisplayCondition;
  87032. },
  87033. set : function(value) {
  87034. if (defined(value) && value.far <= value.near) {
  87035. throw new DeveloperError('far must be greater than near');
  87036. }
  87037. if (!DistanceDisplayCondition.equals(this._distanceDisplayCondition, value)) {
  87038. this._distanceDisplayCondition = DistanceDisplayCondition.clone(value, this._distanceDisplayCondition);
  87039. makeDirty(this, DISTANCE_DISPLAY_CONDITION_INDEX);
  87040. }
  87041. }
  87042. },
  87043. /**
  87044. * Gets or sets the user-defined object returned when the point is picked.
  87045. * @memberof PointPrimitive.prototype
  87046. * @type {Object}
  87047. */
  87048. id : {
  87049. get : function() {
  87050. return this._id;
  87051. },
  87052. set : function(value) {
  87053. this._id = value;
  87054. if (defined(this._pickId)) {
  87055. this._pickId.object.id = value;
  87056. }
  87057. }
  87058. },
  87059. /**
  87060. * Determines whether or not this point will be shown or hidden because it was clustered.
  87061. * @memberof PointPrimitive.prototype
  87062. * @type {Boolean}
  87063. * @private
  87064. */
  87065. clusterShow : {
  87066. get : function() {
  87067. return this._clusterShow;
  87068. },
  87069. set : function(value) {
  87070. if (this._clusterShow !== value) {
  87071. this._clusterShow = value;
  87072. makeDirty(this, SHOW_INDEX);
  87073. }
  87074. }
  87075. }
  87076. });
  87077. PointPrimitive.prototype.getPickId = function(context) {
  87078. if (!defined(this._pickId)) {
  87079. this._pickId = context.createPickId({
  87080. primitive : this,
  87081. collection : this._collection,
  87082. id : this._id
  87083. });
  87084. }
  87085. return this._pickId;
  87086. };
  87087. PointPrimitive.prototype._getActualPosition = function() {
  87088. return this._actualPosition;
  87089. };
  87090. PointPrimitive.prototype._setActualPosition = function(value) {
  87091. Cartesian3.clone(value, this._actualPosition);
  87092. makeDirty(this, POSITION_INDEX);
  87093. };
  87094. var tempCartesian3 = new Cartesian4();
  87095. PointPrimitive._computeActualPosition = function(position, frameState, modelMatrix) {
  87096. if (frameState.mode === SceneMode.SCENE3D) {
  87097. return position;
  87098. }
  87099. Matrix4.multiplyByPoint(modelMatrix, position, tempCartesian3);
  87100. return SceneTransforms.computeActualWgs84Position(frameState, tempCartesian3);
  87101. };
  87102. var scratchCartesian4 = new Cartesian4();
  87103. // This function is basically a stripped-down JavaScript version of PointPrimitiveCollectionVS.glsl
  87104. PointPrimitive._computeScreenSpacePosition = function(modelMatrix, position, scene, result) {
  87105. // Model to world coordinates
  87106. var positionWorld = Matrix4.multiplyByVector(modelMatrix, Cartesian4.fromElements(position.x, position.y, position.z, 1, scratchCartesian4), scratchCartesian4);
  87107. var positionWC = SceneTransforms.wgs84ToWindowCoordinates(scene, positionWorld, result);
  87108. return positionWC;
  87109. };
  87110. /**
  87111. * Computes the screen-space position of the point's origin.
  87112. * The screen space origin is the top, left corner of the canvas; <code>x</code> increases from
  87113. * left to right, and <code>y</code> increases from top to bottom.
  87114. *
  87115. * @param {Scene} scene The scene.
  87116. * @param {Cartesian2} [result] The object onto which to store the result.
  87117. * @returns {Cartesian2} The screen-space position of the point.
  87118. *
  87119. * @exception {DeveloperError} PointPrimitive must be in a collection.
  87120. *
  87121. * @example
  87122. * console.log(p.computeScreenSpacePosition(scene).toString());
  87123. */
  87124. PointPrimitive.prototype.computeScreenSpacePosition = function(scene, result) {
  87125. var pointPrimitiveCollection = this._pointPrimitiveCollection;
  87126. if (!defined(result)) {
  87127. result = new Cartesian2();
  87128. }
  87129. if (!defined(pointPrimitiveCollection)) {
  87130. throw new DeveloperError('PointPrimitive must be in a collection.');
  87131. }
  87132. if (!defined(scene)) {
  87133. throw new DeveloperError('scene is required.');
  87134. }
  87135. var modelMatrix = pointPrimitiveCollection.modelMatrix;
  87136. var windowCoordinates = PointPrimitive._computeScreenSpacePosition(modelMatrix, this._actualPosition, scene, result);
  87137. if (!defined(windowCoordinates)) {
  87138. return undefined;
  87139. }
  87140. windowCoordinates.y = scene.canvas.clientHeight - windowCoordinates.y;
  87141. return windowCoordinates;
  87142. };
  87143. /**
  87144. * Gets a point's screen space bounding box centered around screenSpacePosition.
  87145. * @param {PointPrimitive} point The point to get the screen space bounding box for.
  87146. * @param {Cartesian2} screenSpacePosition The screen space center of the label.
  87147. * @param {BoundingRectangle} [result] The object onto which to store the result.
  87148. * @returns {BoundingRectangle} The screen space bounding box.
  87149. *
  87150. * @private
  87151. */
  87152. PointPrimitive.getScreenSpaceBoundingBox = function(point, screenSpacePosition, result) {
  87153. var size = point.pixelSize;
  87154. var halfSize = size * 0.5;
  87155. var x = screenSpacePosition.x - halfSize;
  87156. var y = screenSpacePosition.y - halfSize;
  87157. var width = size;
  87158. var height = size;
  87159. if (!defined(result)) {
  87160. result = new BoundingRectangle();
  87161. }
  87162. result.x = x;
  87163. result.y = y;
  87164. result.width = width;
  87165. result.height = height;
  87166. return result;
  87167. };
  87168. /**
  87169. * Determines if this point equals another point. Points are equal if all their properties
  87170. * are equal. Points in different collections can be equal.
  87171. *
  87172. * @param {PointPrimitive} other The point to compare for equality.
  87173. * @returns {Boolean} <code>true</code> if the points are equal; otherwise, <code>false</code>.
  87174. */
  87175. PointPrimitive.prototype.equals = function(other) {
  87176. return this === other ||
  87177. defined(other) &&
  87178. this._id === other._id &&
  87179. Cartesian3.equals(this._position, other._position) &&
  87180. Color.equals(this._color, other._color) &&
  87181. this._pixelSize === other._pixelSize &&
  87182. this._outlineWidth === other._outlineWidth &&
  87183. this._show === other._show &&
  87184. Color.equals(this._outlineColor, other._outlineColor) &&
  87185. NearFarScalar.equals(this._scaleByDistance, other._scaleByDistance) &&
  87186. NearFarScalar.equals(this._translucencyByDistance, other._translucencyByDistance) &&
  87187. DistanceDisplayCondition.equals(this._distanceDisplayCondition, other._distanceDisplayCondition);
  87188. };
  87189. PointPrimitive.prototype._destroy = function() {
  87190. this._pickId = this._pickId && this._pickId.destroy();
  87191. this._pointPrimitiveCollection = undefined;
  87192. };
  87193. return PointPrimitive;
  87194. });
  87195. //This file is automatically rebuilt by the Cesium build process.
  87196. /*global define*/
  87197. define('Shaders/PointPrimitiveCollectionFS',[],function() {
  87198. 'use strict';
  87199. return "varying vec4 v_color;\n\
  87200. varying vec4 v_outlineColor;\n\
  87201. varying float v_innerPercent;\n\
  87202. varying float v_pixelDistance;\n\
  87203. #ifdef RENDER_FOR_PICK\n\
  87204. varying vec4 v_pickColor;\n\
  87205. #endif\n\
  87206. void main()\n\
  87207. {\n\
  87208. float distanceToCenter = length(gl_PointCoord - vec2(0.5));\n\
  87209. float maxDistance = max(0.0, 0.5 - v_pixelDistance);\n\
  87210. float wholeAlpha = 1.0 - smoothstep(maxDistance, 0.5, distanceToCenter);\n\
  87211. float innerAlpha = 1.0 - smoothstep(maxDistance * v_innerPercent, 0.5 * v_innerPercent, distanceToCenter);\n\
  87212. vec4 color = mix(v_outlineColor, v_color, innerAlpha);\n\
  87213. color.a *= wholeAlpha;\n\
  87214. if (color.a < 0.005)\n\
  87215. {\n\
  87216. discard;\n\
  87217. }\n\
  87218. #ifdef RENDER_FOR_PICK\n\
  87219. gl_FragColor = v_pickColor;\n\
  87220. #else\n\
  87221. gl_FragColor = color;\n\
  87222. #endif\n\
  87223. }\n\
  87224. ";
  87225. });
  87226. //This file is automatically rebuilt by the Cesium build process.
  87227. /*global define*/
  87228. define('Shaders/PointPrimitiveCollectionVS',[],function() {
  87229. 'use strict';
  87230. return "uniform float u_maxTotalPointSize;\n\
  87231. attribute vec4 positionHighAndSize;\n\
  87232. attribute vec4 positionLowAndOutline;\n\
  87233. attribute vec4 compressedAttribute0;\n\
  87234. attribute vec4 compressedAttribute1;\n\
  87235. attribute vec4 scaleByDistance;\n\
  87236. attribute vec2 distanceDisplayCondition;\n\
  87237. varying vec4 v_color;\n\
  87238. varying vec4 v_outlineColor;\n\
  87239. varying float v_innerPercent;\n\
  87240. varying float v_pixelDistance;\n\
  87241. #ifdef RENDER_FOR_PICK\n\
  87242. varying vec4 v_pickColor;\n\
  87243. #endif\n\
  87244. const float SHIFT_LEFT8 = 256.0;\n\
  87245. const float SHIFT_RIGHT8 = 1.0 / 256.0;\n\
  87246. void main()\n\
  87247. {\n\
  87248. vec3 positionHigh = positionHighAndSize.xyz;\n\
  87249. vec3 positionLow = positionLowAndOutline.xyz;\n\
  87250. float outlineWidthBothSides = 2.0 * positionLowAndOutline.w;\n\
  87251. float totalSize = positionHighAndSize.w + outlineWidthBothSides;\n\
  87252. float outlinePercent = outlineWidthBothSides / totalSize;\n\
  87253. totalSize *= czm_resolutionScale;\n\
  87254. totalSize += 3.0;\n\
  87255. float temp = compressedAttribute1.x * SHIFT_RIGHT8;\n\
  87256. float show = floor(temp);\n\
  87257. #ifdef EYE_DISTANCE_TRANSLUCENCY\n\
  87258. vec4 translucencyByDistance;\n\
  87259. translucencyByDistance.x = compressedAttribute1.z;\n\
  87260. translucencyByDistance.z = compressedAttribute1.w;\n\
  87261. translucencyByDistance.y = ((temp - floor(temp)) * SHIFT_LEFT8) / 255.0;\n\
  87262. temp = compressedAttribute1.y * SHIFT_RIGHT8;\n\
  87263. translucencyByDistance.w = ((temp - floor(temp)) * SHIFT_LEFT8) / 255.0;\n\
  87264. #endif\n\
  87265. vec4 color;\n\
  87266. vec4 outlineColor;\n\
  87267. #ifdef RENDER_FOR_PICK\n\
  87268. color = vec4(0.0);\n\
  87269. outlineColor = vec4(0.0);\n\
  87270. vec4 pickColor;\n\
  87271. temp = compressedAttribute0.z * SHIFT_RIGHT8;\n\
  87272. pickColor.b = (temp - floor(temp)) * SHIFT_LEFT8;\n\
  87273. temp = floor(temp) * SHIFT_RIGHT8;\n\
  87274. pickColor.g = (temp - floor(temp)) * SHIFT_LEFT8;\n\
  87275. pickColor.r = floor(temp);\n\
  87276. #else\n\
  87277. temp = compressedAttribute0.x * SHIFT_RIGHT8;\n\
  87278. color.b = (temp - floor(temp)) * SHIFT_LEFT8;\n\
  87279. temp = floor(temp) * SHIFT_RIGHT8;\n\
  87280. color.g = (temp - floor(temp)) * SHIFT_LEFT8;\n\
  87281. color.r = floor(temp);\n\
  87282. temp = compressedAttribute0.y * SHIFT_RIGHT8;\n\
  87283. outlineColor.b = (temp - floor(temp)) * SHIFT_LEFT8;\n\
  87284. temp = floor(temp) * SHIFT_RIGHT8;\n\
  87285. outlineColor.g = (temp - floor(temp)) * SHIFT_LEFT8;\n\
  87286. outlineColor.r = floor(temp);\n\
  87287. #endif\n\
  87288. temp = compressedAttribute0.w * SHIFT_RIGHT8;\n\
  87289. #ifdef RENDER_FOR_PICK\n\
  87290. pickColor.a = (temp - floor(temp)) * SHIFT_LEFT8;\n\
  87291. pickColor = pickColor / 255.0;\n\
  87292. #endif\n\
  87293. temp = floor(temp) * SHIFT_RIGHT8;\n\
  87294. outlineColor.a = (temp - floor(temp)) * SHIFT_LEFT8;\n\
  87295. outlineColor /= 255.0;\n\
  87296. color.a = floor(temp);\n\
  87297. color /= 255.0;\n\
  87298. vec4 p = czm_translateRelativeToEye(positionHigh, positionLow);\n\
  87299. vec4 positionEC = czm_modelViewRelativeToEye * p;\n\
  87300. positionEC.xyz *= show;\n\
  87301. #if defined(EYE_DISTANCE_SCALING) || defined(EYE_DISTANCE_TRANSLUCENCY) || defined(DISTANCE_DISPLAY_CONDITION)\n\
  87302. float lengthSq;\n\
  87303. if (czm_sceneMode == czm_sceneMode2D)\n\
  87304. {\n\
  87305. lengthSq = czm_eyeHeight2D.y;\n\
  87306. }\n\
  87307. else\n\
  87308. {\n\
  87309. lengthSq = dot(positionEC.xyz, positionEC.xyz);\n\
  87310. }\n\
  87311. #endif\n\
  87312. #ifdef EYE_DISTANCE_SCALING\n\
  87313. totalSize *= czm_nearFarScalar(scaleByDistance, lengthSq);\n\
  87314. #endif\n\
  87315. totalSize = min(totalSize, u_maxTotalPointSize);\n\
  87316. if (totalSize < 1.0)\n\
  87317. {\n\
  87318. positionEC.xyz = vec3(0.0);\n\
  87319. totalSize = 1.0;\n\
  87320. }\n\
  87321. float translucency = 1.0;\n\
  87322. #ifdef EYE_DISTANCE_TRANSLUCENCY\n\
  87323. translucency = czm_nearFarScalar(translucencyByDistance, lengthSq);\n\
  87324. if (translucency < 0.004)\n\
  87325. {\n\
  87326. positionEC.xyz = vec3(0.0);\n\
  87327. }\n\
  87328. #endif\n\
  87329. #ifdef DISTANCE_DISPLAY_CONDITION\n\
  87330. float nearSq = distanceDisplayCondition.x * distanceDisplayCondition.x;\n\
  87331. float farSq = distanceDisplayCondition.y * distanceDisplayCondition.y;\n\
  87332. if (lengthSq < nearSq || lengthSq > farSq) {\n\
  87333. positionEC.xyz = vec3(0.0);\n\
  87334. }\n\
  87335. #endif\n\
  87336. vec4 positionWC = czm_eyeToWindowCoordinates(positionEC);\n\
  87337. gl_Position = czm_viewportOrthographic * vec4(positionWC.xy, -positionWC.z, 1.0);\n\
  87338. v_color = color;\n\
  87339. v_color.a *= translucency;\n\
  87340. v_outlineColor = outlineColor;\n\
  87341. v_outlineColor.a *= translucency;\n\
  87342. v_innerPercent = 1.0 - outlinePercent;\n\
  87343. v_pixelDistance = 2.0 / totalSize;\n\
  87344. gl_PointSize = totalSize;\n\
  87345. #ifdef RENDER_FOR_PICK\n\
  87346. v_pickColor = pickColor;\n\
  87347. #endif\n\
  87348. }\n\
  87349. ";
  87350. });
  87351. /*global define*/
  87352. define('Scene/PointPrimitiveCollection',[
  87353. '../Core/BoundingSphere',
  87354. '../Core/Color',
  87355. '../Core/ComponentDatatype',
  87356. '../Core/defaultValue',
  87357. '../Core/defined',
  87358. '../Core/defineProperties',
  87359. '../Core/destroyObject',
  87360. '../Core/DeveloperError',
  87361. '../Core/EncodedCartesian3',
  87362. '../Core/Math',
  87363. '../Core/Matrix4',
  87364. '../Core/PrimitiveType',
  87365. '../Core/WebGLConstants',
  87366. '../Renderer/BufferUsage',
  87367. '../Renderer/ContextLimits',
  87368. '../Renderer/DrawCommand',
  87369. '../Renderer/Pass',
  87370. '../Renderer/RenderState',
  87371. '../Renderer/ShaderProgram',
  87372. '../Renderer/ShaderSource',
  87373. '../Renderer/VertexArrayFacade',
  87374. '../Shaders/PointPrimitiveCollectionFS',
  87375. '../Shaders/PointPrimitiveCollectionVS',
  87376. './BlendingState',
  87377. './PointPrimitive',
  87378. './SceneMode'
  87379. ], function(
  87380. BoundingSphere,
  87381. Color,
  87382. ComponentDatatype,
  87383. defaultValue,
  87384. defined,
  87385. defineProperties,
  87386. destroyObject,
  87387. DeveloperError,
  87388. EncodedCartesian3,
  87389. CesiumMath,
  87390. Matrix4,
  87391. PrimitiveType,
  87392. WebGLConstants,
  87393. BufferUsage,
  87394. ContextLimits,
  87395. DrawCommand,
  87396. Pass,
  87397. RenderState,
  87398. ShaderProgram,
  87399. ShaderSource,
  87400. VertexArrayFacade,
  87401. PointPrimitiveCollectionFS,
  87402. PointPrimitiveCollectionVS,
  87403. BlendingState,
  87404. PointPrimitive,
  87405. SceneMode) {
  87406. 'use strict';
  87407. var SHOW_INDEX = PointPrimitive.SHOW_INDEX;
  87408. var POSITION_INDEX = PointPrimitive.POSITION_INDEX;
  87409. var COLOR_INDEX = PointPrimitive.COLOR_INDEX;
  87410. var OUTLINE_COLOR_INDEX = PointPrimitive.OUTLINE_COLOR_INDEX;
  87411. var OUTLINE_WIDTH_INDEX = PointPrimitive.OUTLINE_WIDTH_INDEX;
  87412. var PIXEL_SIZE_INDEX = PointPrimitive.PIXEL_SIZE_INDEX;
  87413. var SCALE_BY_DISTANCE_INDEX = PointPrimitive.SCALE_BY_DISTANCE_INDEX;
  87414. var TRANSLUCENCY_BY_DISTANCE_INDEX = PointPrimitive.TRANSLUCENCY_BY_DISTANCE_INDEX;
  87415. var DISTANCE_DISPLAY_CONDITION_INDEX = PointPrimitive.DISTANCE_DISPLAY_CONDITION_INDEX;
  87416. var NUMBER_OF_PROPERTIES = PointPrimitive.NUMBER_OF_PROPERTIES;
  87417. var attributeLocations = {
  87418. positionHighAndSize : 0,
  87419. positionLowAndOutline : 1,
  87420. compressedAttribute0 : 2, // color, outlineColor, pick color
  87421. compressedAttribute1 : 3, // show, translucency by distance, some free space
  87422. scaleByDistance : 4,
  87423. distanceDisplayCondition : 5
  87424. };
  87425. /**
  87426. * A renderable collection of points.
  87427. * <br /><br />
  87428. * Points are added and removed from the collection using {@link PointPrimitiveCollection#add}
  87429. * and {@link PointPrimitiveCollection#remove}.
  87430. *
  87431. * @alias PointPrimitiveCollection
  87432. * @constructor
  87433. *
  87434. * @param {Object} [options] Object with the following properties:
  87435. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms each point from model to world coordinates.
  87436. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
  87437. *
  87438. * @performance For best performance, prefer a few collections, each with many points, to
  87439. * many collections with only a few points each. Organize collections so that points
  87440. * with the same update frequency are in the same collection, i.e., points that do not
  87441. * change should be in one collection; points that change every frame should be in another
  87442. * collection; and so on.
  87443. *
  87444. *
  87445. * @example
  87446. * // Create a pointPrimitive collection with two points
  87447. * var points = scene.primitives.add(new Cesium.PointPrimitiveCollection());
  87448. * points.add({
  87449. * position : new Cesium.Cartesian3(1.0, 2.0, 3.0),
  87450. * color : Cesium.Color.YELLOW
  87451. * });
  87452. * points.add({
  87453. * position : new Cesium.Cartesian3(4.0, 5.0, 6.0),
  87454. * color : Cesium.Color.CYAN
  87455. * });
  87456. *
  87457. * @see PointPrimitiveCollection#add
  87458. * @see PointPrimitiveCollection#remove
  87459. * @see PointPrimitive
  87460. */
  87461. function PointPrimitiveCollection(options) {
  87462. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  87463. this._sp = undefined;
  87464. this._rs = undefined;
  87465. this._vaf = undefined;
  87466. this._spPick = undefined;
  87467. this._pointPrimitives = [];
  87468. this._pointPrimitivesToUpdate = [];
  87469. this._pointPrimitivesToUpdateIndex = 0;
  87470. this._pointPrimitivesRemoved = false;
  87471. this._createVertexArray = false;
  87472. this._shaderScaleByDistance = false;
  87473. this._compiledShaderScaleByDistance = false;
  87474. this._compiledShaderScaleByDistancePick = false;
  87475. this._shaderTranslucencyByDistance = false;
  87476. this._compiledShaderTranslucencyByDistance = false;
  87477. this._compiledShaderTranslucencyByDistancePick = false;
  87478. this._shaderDistanceDisplayCondition = false;
  87479. this._compiledShaderDistanceDisplayCondition = false;
  87480. this._compiledShaderDistanceDisplayConditionPick = false;
  87481. this._propertiesChanged = new Uint32Array(NUMBER_OF_PROPERTIES);
  87482. this._maxPixelSize = 1.0;
  87483. this._baseVolume = new BoundingSphere();
  87484. this._baseVolumeWC = new BoundingSphere();
  87485. this._baseVolume2D = new BoundingSphere();
  87486. this._boundingVolume = new BoundingSphere();
  87487. this._boundingVolumeDirty = false;
  87488. this._colorCommands = [];
  87489. this._pickCommands = [];
  87490. /**
  87491. * The 4x4 transformation matrix that transforms each point in this collection from model to world coordinates.
  87492. * When this is the identity matrix, the pointPrimitives are drawn in world coordinates, i.e., Earth's WGS84 coordinates.
  87493. * Local reference frames can be used by providing a different transformation matrix, like that returned
  87494. * by {@link Transforms.eastNorthUpToFixedFrame}.
  87495. *
  87496. * @type {Matrix4}
  87497. * @default {@link Matrix4.IDENTITY}
  87498. *
  87499. *
  87500. * @example
  87501. * var center = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883);
  87502. * pointPrimitives.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
  87503. * pointPrimitives.add({
  87504. * color : Cesium.Color.ORANGE,
  87505. * position : new Cesium.Cartesian3(0.0, 0.0, 0.0) // center
  87506. * });
  87507. * pointPrimitives.add({
  87508. * color : Cesium.Color.YELLOW,
  87509. * position : new Cesium.Cartesian3(1000000.0, 0.0, 0.0) // east
  87510. * });
  87511. * pointPrimitives.add({
  87512. * color : Cesium.Color.GREEN,
  87513. * position : new Cesium.Cartesian3(0.0, 1000000.0, 0.0) // north
  87514. * });
  87515. * pointPrimitives.add({
  87516. * color : Cesium.Color.CYAN,
  87517. * position : new Cesium.Cartesian3(0.0, 0.0, 1000000.0) // up
  87518. * });
  87519. *
  87520. * @see Transforms.eastNorthUpToFixedFrame
  87521. */
  87522. this.modelMatrix = Matrix4.clone(defaultValue(options.modelMatrix, Matrix4.IDENTITY));
  87523. this._modelMatrix = Matrix4.clone(Matrix4.IDENTITY);
  87524. /**
  87525. * This property is for debugging only; it is not for production use nor is it optimized.
  87526. * <p>
  87527. * Draws the bounding sphere for each draw command in the primitive.
  87528. * </p>
  87529. *
  87530. * @type {Boolean}
  87531. *
  87532. * @default false
  87533. */
  87534. this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false);
  87535. this._mode = SceneMode.SCENE3D;
  87536. this._maxTotalPointSize = 1;
  87537. // The buffer usage for each attribute is determined based on the usage of the attribute over time.
  87538. this._buffersUsage = [
  87539. BufferUsage.STATIC_DRAW, // SHOW_INDEX
  87540. BufferUsage.STATIC_DRAW, // POSITION_INDEX
  87541. BufferUsage.STATIC_DRAW, // COLOR_INDEX
  87542. BufferUsage.STATIC_DRAW, // OUTLINE_COLOR_INDEX
  87543. BufferUsage.STATIC_DRAW, // OUTLINE_WIDTH_INDEX
  87544. BufferUsage.STATIC_DRAW, // PIXEL_SIZE_INDEX
  87545. BufferUsage.STATIC_DRAW, // SCALE_BY_DISTANCE_INDEX
  87546. BufferUsage.STATIC_DRAW, // TRANSLUCENCY_BY_DISTANCE_INDEX
  87547. BufferUsage.STATIC_DRAW // DISTANCE_DISPLAY_CONDITION_INDEX
  87548. ];
  87549. var that = this;
  87550. this._uniforms = {
  87551. u_maxTotalPointSize : function() {
  87552. return that._maxTotalPointSize;
  87553. }
  87554. };
  87555. }
  87556. defineProperties(PointPrimitiveCollection.prototype, {
  87557. /**
  87558. * Returns the number of points in this collection. This is commonly used with
  87559. * {@link PointPrimitiveCollection#get} to iterate over all the points
  87560. * in the collection.
  87561. * @memberof PointPrimitiveCollection.prototype
  87562. * @type {Number}
  87563. */
  87564. length : {
  87565. get : function() {
  87566. removePointPrimitives(this);
  87567. return this._pointPrimitives.length;
  87568. }
  87569. }
  87570. });
  87571. function destroyPointPrimitives(pointPrimitives) {
  87572. var length = pointPrimitives.length;
  87573. for (var i = 0; i < length; ++i) {
  87574. if (pointPrimitives[i]) {
  87575. pointPrimitives[i]._destroy();
  87576. }
  87577. }
  87578. }
  87579. /**
  87580. * Creates and adds a point with the specified initial properties to the collection.
  87581. * The added point is returned so it can be modified or removed from the collection later.
  87582. *
  87583. * @param {Object}[pointPrimitive] A template describing the point's properties as shown in Example 1.
  87584. * @returns {PointPrimitive} The point that was added to the collection.
  87585. *
  87586. * @performance Calling <code>add</code> is expected constant time. However, the collection's vertex buffer
  87587. * is rewritten - an <code>O(n)</code> operation that also incurs CPU to GPU overhead. For
  87588. * best performance, add as many pointPrimitives as possible before calling <code>update</code>.
  87589. *
  87590. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  87591. *
  87592. *
  87593. * @example
  87594. * // Example 1: Add a point, specifying all the default values.
  87595. * var p = pointPrimitives.add({
  87596. * show : true,
  87597. * position : Cesium.Cartesian3.ZERO,
  87598. * pixelSize : 10.0,
  87599. * color : Cesium.Color.WHITE,
  87600. * outlineColor : Cesium.Color.TRANSPARENT,
  87601. * outlineWidth : 0.0,
  87602. * id : undefined
  87603. * });
  87604. *
  87605. * @example
  87606. * // Example 2: Specify only the point's cartographic position.
  87607. * var p = pointPrimitives.add({
  87608. * position : Cesium.Cartesian3.fromDegrees(longitude, latitude, height)
  87609. * });
  87610. *
  87611. * @see PointPrimitiveCollection#remove
  87612. * @see PointPrimitiveCollection#removeAll
  87613. */
  87614. PointPrimitiveCollection.prototype.add = function(pointPrimitive) {
  87615. var p = new PointPrimitive(pointPrimitive, this);
  87616. p._index = this._pointPrimitives.length;
  87617. this._pointPrimitives.push(p);
  87618. this._createVertexArray = true;
  87619. return p;
  87620. };
  87621. /**
  87622. * Removes a point from the collection.
  87623. *
  87624. * @param {PointPrimitive} pointPrimitive The point to remove.
  87625. * @returns {Boolean} <code>true</code> if the point was removed; <code>false</code> if the point was not found in the collection.
  87626. *
  87627. * @performance Calling <code>remove</code> is expected constant time. However, the collection's vertex buffer
  87628. * is rewritten - an <code>O(n)</code> operation that also incurs CPU to GPU overhead. For
  87629. * best performance, remove as many points as possible before calling <code>update</code>.
  87630. * If you intend to temporarily hide a point, it is usually more efficient to call
  87631. * {@link PointPrimitive#show} instead of removing and re-adding the point.
  87632. *
  87633. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  87634. *
  87635. *
  87636. * @example
  87637. * var p = pointPrimitives.add(...);
  87638. * pointPrimitives.remove(p); // Returns true
  87639. *
  87640. * @see PointPrimitiveCollection#add
  87641. * @see PointPrimitiveCollection#removeAll
  87642. * @see PointPrimitive#show
  87643. */
  87644. PointPrimitiveCollection.prototype.remove = function(pointPrimitive) {
  87645. if (this.contains(pointPrimitive)) {
  87646. this._pointPrimitives[pointPrimitive._index] = null; // Removed later
  87647. this._pointPrimitivesRemoved = true;
  87648. this._createVertexArray = true;
  87649. pointPrimitive._destroy();
  87650. return true;
  87651. }
  87652. return false;
  87653. };
  87654. /**
  87655. * Removes all points from the collection.
  87656. *
  87657. * @performance <code>O(n)</code>. It is more efficient to remove all the points
  87658. * from a collection and then add new ones than to create a new collection entirely.
  87659. *
  87660. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  87661. *
  87662. *
  87663. * @example
  87664. * pointPrimitives.add(...);
  87665. * pointPrimitives.add(...);
  87666. * pointPrimitives.removeAll();
  87667. *
  87668. * @see PointPrimitiveCollection#add
  87669. * @see PointPrimitiveCollection#remove
  87670. */
  87671. PointPrimitiveCollection.prototype.removeAll = function() {
  87672. destroyPointPrimitives(this._pointPrimitives);
  87673. this._pointPrimitives = [];
  87674. this._pointPrimitivesToUpdate = [];
  87675. this._pointPrimitivesToUpdateIndex = 0;
  87676. this._pointPrimitivesRemoved = false;
  87677. this._createVertexArray = true;
  87678. };
  87679. function removePointPrimitives(pointPrimitiveCollection) {
  87680. if (pointPrimitiveCollection._pointPrimitivesRemoved) {
  87681. pointPrimitiveCollection._pointPrimitivesRemoved = false;
  87682. var newPointPrimitives = [];
  87683. var pointPrimitives = pointPrimitiveCollection._pointPrimitives;
  87684. var length = pointPrimitives.length;
  87685. for (var i = 0, j = 0; i < length; ++i) {
  87686. var pointPrimitive = pointPrimitives[i];
  87687. if (pointPrimitive) {
  87688. pointPrimitive._index = j++;
  87689. newPointPrimitives.push(pointPrimitive);
  87690. }
  87691. }
  87692. pointPrimitiveCollection._pointPrimitives = newPointPrimitives;
  87693. }
  87694. }
  87695. PointPrimitiveCollection.prototype._updatePointPrimitive = function(pointPrimitive, propertyChanged) {
  87696. if (!pointPrimitive._dirty) {
  87697. this._pointPrimitivesToUpdate[this._pointPrimitivesToUpdateIndex++] = pointPrimitive;
  87698. }
  87699. ++this._propertiesChanged[propertyChanged];
  87700. };
  87701. /**
  87702. * Check whether this collection contains a given point.
  87703. *
  87704. * @param {PointPrimitive} [pointPrimitive] The point to check for.
  87705. * @returns {Boolean} true if this collection contains the point, false otherwise.
  87706. *
  87707. * @see PointPrimitiveCollection#get
  87708. */
  87709. PointPrimitiveCollection.prototype.contains = function(pointPrimitive) {
  87710. return defined(pointPrimitive) && pointPrimitive._pointPrimitiveCollection === this;
  87711. };
  87712. /**
  87713. * Returns the point in the collection at the specified index. Indices are zero-based
  87714. * and increase as points are added. Removing a point shifts all points after
  87715. * it to the left, changing their indices. This function is commonly used with
  87716. * {@link PointPrimitiveCollection#length} to iterate over all the points
  87717. * in the collection.
  87718. *
  87719. * @param {Number} index The zero-based index of the point.
  87720. * @returns {PointPrimitive} The point at the specified index.
  87721. *
  87722. * @performance Expected constant time. If points were removed from the collection and
  87723. * {@link PointPrimitiveCollection#update} was not called, an implicit <code>O(n)</code>
  87724. * operation is performed.
  87725. *
  87726. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  87727. *
  87728. *
  87729. * @example
  87730. * // Toggle the show property of every point in the collection
  87731. * var len = pointPrimitives.length;
  87732. * for (var i = 0; i < len; ++i) {
  87733. * var p = pointPrimitives.get(i);
  87734. * p.show = !p.show;
  87735. * }
  87736. *
  87737. * @see PointPrimitiveCollection#length
  87738. */
  87739. PointPrimitiveCollection.prototype.get = function(index) {
  87740. if (!defined(index)) {
  87741. throw new DeveloperError('index is required.');
  87742. }
  87743. removePointPrimitives(this);
  87744. return this._pointPrimitives[index];
  87745. };
  87746. PointPrimitiveCollection.prototype.computeNewBuffersUsage = function() {
  87747. var buffersUsage = this._buffersUsage;
  87748. var usageChanged = false;
  87749. var properties = this._propertiesChanged;
  87750. for ( var k = 0; k < NUMBER_OF_PROPERTIES; ++k) {
  87751. var newUsage = (properties[k] === 0) ? BufferUsage.STATIC_DRAW : BufferUsage.STREAM_DRAW;
  87752. usageChanged = usageChanged || (buffersUsage[k] !== newUsage);
  87753. buffersUsage[k] = newUsage;
  87754. }
  87755. return usageChanged;
  87756. };
  87757. function createVAF(context, numberOfPointPrimitives, buffersUsage) {
  87758. return new VertexArrayFacade(context, [{
  87759. index : attributeLocations.positionHighAndSize,
  87760. componentsPerAttribute : 4,
  87761. componentDatatype : ComponentDatatype.FLOAT,
  87762. usage : buffersUsage[POSITION_INDEX]
  87763. }, {
  87764. index : attributeLocations.positionLowAndShow,
  87765. componentsPerAttribute : 4,
  87766. componentDatatype : ComponentDatatype.FLOAT,
  87767. usage : buffersUsage[POSITION_INDEX]
  87768. }, {
  87769. index : attributeLocations.compressedAttribute0,
  87770. componentsPerAttribute : 4,
  87771. componentDatatype : ComponentDatatype.FLOAT,
  87772. usage : buffersUsage[COLOR_INDEX]
  87773. }, {
  87774. index : attributeLocations.compressedAttribute1,
  87775. componentsPerAttribute : 4,
  87776. componentDatatype : ComponentDatatype.FLOAT,
  87777. usage : buffersUsage[TRANSLUCENCY_BY_DISTANCE_INDEX]
  87778. }, {
  87779. index : attributeLocations.scaleByDistance,
  87780. componentsPerAttribute : 4,
  87781. componentDatatype : ComponentDatatype.FLOAT,
  87782. usage : buffersUsage[SCALE_BY_DISTANCE_INDEX]
  87783. }, {
  87784. index : attributeLocations.distanceDisplayCondition,
  87785. componentsPerAttribute : 2,
  87786. componentDatatype : ComponentDatatype.FLOAT,
  87787. usage : buffersUsage[DISTANCE_DISPLAY_CONDITION_INDEX]
  87788. }], numberOfPointPrimitives); // 1 vertex per pointPrimitive
  87789. }
  87790. ///////////////////////////////////////////////////////////////////////////
  87791. // PERFORMANCE_IDEA: Save memory if a property is the same for all pointPrimitives, use a latched attribute state,
  87792. // instead of storing it in a vertex buffer.
  87793. var writePositionScratch = new EncodedCartesian3();
  87794. function writePositionSizeAndOutline(pointPrimitiveCollection, context, vafWriters, pointPrimitive) {
  87795. var i = pointPrimitive._index;
  87796. var position = pointPrimitive._getActualPosition();
  87797. if (pointPrimitiveCollection._mode === SceneMode.SCENE3D) {
  87798. BoundingSphere.expand(pointPrimitiveCollection._baseVolume, position, pointPrimitiveCollection._baseVolume);
  87799. pointPrimitiveCollection._boundingVolumeDirty = true;
  87800. }
  87801. EncodedCartesian3.fromCartesian(position, writePositionScratch);
  87802. var pixelSize = pointPrimitive.pixelSize;
  87803. var outlineWidth = pointPrimitive.outlineWidth;
  87804. pointPrimitiveCollection._maxPixelSize = Math.max(pointPrimitiveCollection._maxPixelSize, pixelSize + outlineWidth);
  87805. var positionHighWriter = vafWriters[attributeLocations.positionHighAndSize];
  87806. var high = writePositionScratch.high;
  87807. positionHighWriter(i, high.x, high.y, high.z, pixelSize);
  87808. var positionLowWriter = vafWriters[attributeLocations.positionLowAndOutline];
  87809. var low = writePositionScratch.low;
  87810. positionLowWriter(i, low.x, low.y, low.z, outlineWidth);
  87811. }
  87812. var LEFT_SHIFT16 = 65536.0; // 2^16
  87813. var LEFT_SHIFT8 = 256.0; // 2^8
  87814. function writeCompressedAttrib0(pointPrimitiveCollection, context, vafWriters, pointPrimitive) {
  87815. var i = pointPrimitive._index;
  87816. var color = pointPrimitive.color;
  87817. var pickColor = pointPrimitive.getPickId(context).color;
  87818. var outlineColor = pointPrimitive.outlineColor;
  87819. var red = Color.floatToByte(color.red);
  87820. var green = Color.floatToByte(color.green);
  87821. var blue = Color.floatToByte(color.blue);
  87822. var compressed0 = red * LEFT_SHIFT16 + green * LEFT_SHIFT8 + blue;
  87823. red = Color.floatToByte(outlineColor.red);
  87824. green = Color.floatToByte(outlineColor.green);
  87825. blue = Color.floatToByte(outlineColor.blue);
  87826. var compressed1 = red * LEFT_SHIFT16 + green * LEFT_SHIFT8 + blue;
  87827. red = Color.floatToByte(pickColor.red);
  87828. green = Color.floatToByte(pickColor.green);
  87829. blue = Color.floatToByte(pickColor.blue);
  87830. var compressed2 = red * LEFT_SHIFT16 + green * LEFT_SHIFT8 + blue;
  87831. var compressed3 =
  87832. Color.floatToByte(color.alpha) * LEFT_SHIFT16 +
  87833. Color.floatToByte(outlineColor.alpha) * LEFT_SHIFT8 +
  87834. Color.floatToByte(pickColor.alpha);
  87835. var writer = vafWriters[attributeLocations.compressedAttribute0];
  87836. writer(i, compressed0, compressed1, compressed2, compressed3);
  87837. }
  87838. function writeCompressedAttrib1(pointPrimitiveCollection, context, vafWriters, pointPrimitive) {
  87839. var i = pointPrimitive._index;
  87840. var near = 0.0;
  87841. var nearValue = 1.0;
  87842. var far = 1.0;
  87843. var farValue = 1.0;
  87844. var translucency = pointPrimitive.translucencyByDistance;
  87845. if (defined(translucency)) {
  87846. near = translucency.near;
  87847. nearValue = translucency.nearValue;
  87848. far = translucency.far;
  87849. farValue = translucency.farValue;
  87850. if (nearValue !== 1.0 || farValue !== 1.0) {
  87851. // translucency by distance calculation in shader need not be enabled
  87852. // until a pointPrimitive with near and far !== 1.0 is found
  87853. pointPrimitiveCollection._shaderTranslucencyByDistance = true;
  87854. }
  87855. }
  87856. var show = pointPrimitive.show && pointPrimitive.clusterShow;
  87857. // If the color alphas are zero, do not show this pointPrimitive. This lets us avoid providing
  87858. // color during the pick pass and also eliminates a discard in the fragment shader.
  87859. if (pointPrimitive.color.alpha === 0.0 && pointPrimitive.outlineColor.alpha === 0.0) {
  87860. show = false;
  87861. }
  87862. nearValue = CesiumMath.clamp(nearValue, 0.0, 1.0);
  87863. nearValue = nearValue === 1.0 ? 255.0 : (nearValue * 255.0) | 0;
  87864. var compressed0 = (show ? 1.0 : 0.0) * LEFT_SHIFT8 + nearValue;
  87865. farValue = CesiumMath.clamp(farValue, 0.0, 1.0);
  87866. farValue = farValue === 1.0 ? 255.0 : (farValue * 255.0) | 0;
  87867. var compressed1 = farValue;
  87868. var writer = vafWriters[attributeLocations.compressedAttribute1];
  87869. writer(i, compressed0, compressed1, near, far);
  87870. }
  87871. function writeScaleByDistance(pointPrimitiveCollection, context, vafWriters, pointPrimitive) {
  87872. var i = pointPrimitive._index;
  87873. var writer = vafWriters[attributeLocations.scaleByDistance];
  87874. var near = 0.0;
  87875. var nearValue = 1.0;
  87876. var far = 1.0;
  87877. var farValue = 1.0;
  87878. var scale = pointPrimitive.scaleByDistance;
  87879. if (defined(scale)) {
  87880. near = scale.near;
  87881. nearValue = scale.nearValue;
  87882. far = scale.far;
  87883. farValue = scale.farValue;
  87884. if (nearValue !== 1.0 || farValue !== 1.0) {
  87885. // scale by distance calculation in shader need not be enabled
  87886. // until a pointPrimitive with near and far !== 1.0 is found
  87887. pointPrimitiveCollection._shaderScaleByDistance = true;
  87888. }
  87889. }
  87890. writer(i, near, nearValue, far, farValue);
  87891. }
  87892. function writeDistanceDisplayCondition(pointPrimitiveCollection, context, vafWriters, pointPrimitive) {
  87893. var i = pointPrimitive._index;
  87894. var writer = vafWriters[attributeLocations.distanceDisplayCondition];
  87895. var near = 0.0;
  87896. var far = Number.MAX_VALUE;
  87897. var distanceDisplayCondition = pointPrimitive.distanceDisplayCondition;
  87898. if (defined(distanceDisplayCondition)) {
  87899. near = distanceDisplayCondition.near;
  87900. far = distanceDisplayCondition.far;
  87901. pointPrimitiveCollection._shaderDistanceDisplayCondition = true;
  87902. }
  87903. writer(i, near, far);
  87904. }
  87905. function writePointPrimitive(pointPrimitiveCollection, context, vafWriters, pointPrimitive) {
  87906. writePositionSizeAndOutline(pointPrimitiveCollection, context, vafWriters, pointPrimitive);
  87907. writeCompressedAttrib0(pointPrimitiveCollection, context, vafWriters, pointPrimitive);
  87908. writeCompressedAttrib1(pointPrimitiveCollection, context, vafWriters, pointPrimitive);
  87909. writeScaleByDistance(pointPrimitiveCollection, context, vafWriters, pointPrimitive);
  87910. writeDistanceDisplayCondition(pointPrimitiveCollection, context, vafWriters, pointPrimitive);
  87911. }
  87912. function recomputeActualPositions(pointPrimitiveCollection, pointPrimitives, length, frameState, modelMatrix, recomputeBoundingVolume) {
  87913. var boundingVolume;
  87914. if (frameState.mode === SceneMode.SCENE3D) {
  87915. boundingVolume = pointPrimitiveCollection._baseVolume;
  87916. pointPrimitiveCollection._boundingVolumeDirty = true;
  87917. } else {
  87918. boundingVolume = pointPrimitiveCollection._baseVolume2D;
  87919. }
  87920. var positions = [];
  87921. for ( var i = 0; i < length; ++i) {
  87922. var pointPrimitive = pointPrimitives[i];
  87923. var position = pointPrimitive.position;
  87924. var actualPosition = PointPrimitive._computeActualPosition(position, frameState, modelMatrix);
  87925. if (defined(actualPosition)) {
  87926. pointPrimitive._setActualPosition(actualPosition);
  87927. if (recomputeBoundingVolume) {
  87928. positions.push(actualPosition);
  87929. } else {
  87930. BoundingSphere.expand(boundingVolume, actualPosition, boundingVolume);
  87931. }
  87932. }
  87933. }
  87934. if (recomputeBoundingVolume) {
  87935. BoundingSphere.fromPoints(positions, boundingVolume);
  87936. }
  87937. }
  87938. function updateMode(pointPrimitiveCollection, frameState) {
  87939. var mode = frameState.mode;
  87940. var pointPrimitives = pointPrimitiveCollection._pointPrimitives;
  87941. var pointPrimitivesToUpdate = pointPrimitiveCollection._pointPrimitivesToUpdate;
  87942. var modelMatrix = pointPrimitiveCollection._modelMatrix;
  87943. if (pointPrimitiveCollection._createVertexArray ||
  87944. pointPrimitiveCollection._mode !== mode ||
  87945. mode !== SceneMode.SCENE3D &&
  87946. !Matrix4.equals(modelMatrix, pointPrimitiveCollection.modelMatrix)) {
  87947. pointPrimitiveCollection._mode = mode;
  87948. Matrix4.clone(pointPrimitiveCollection.modelMatrix, modelMatrix);
  87949. pointPrimitiveCollection._createVertexArray = true;
  87950. if (mode === SceneMode.SCENE3D || mode === SceneMode.SCENE2D || mode === SceneMode.COLUMBUS_VIEW) {
  87951. recomputeActualPositions(pointPrimitiveCollection, pointPrimitives, pointPrimitives.length, frameState, modelMatrix, true);
  87952. }
  87953. } else if (mode === SceneMode.MORPHING) {
  87954. recomputeActualPositions(pointPrimitiveCollection, pointPrimitives, pointPrimitives.length, frameState, modelMatrix, true);
  87955. } else if (mode === SceneMode.SCENE2D || mode === SceneMode.COLUMBUS_VIEW) {
  87956. recomputeActualPositions(pointPrimitiveCollection, pointPrimitivesToUpdate, pointPrimitiveCollection._pointPrimitivesToUpdateIndex, frameState, modelMatrix, false);
  87957. }
  87958. }
  87959. function updateBoundingVolume(collection, frameState, boundingVolume) {
  87960. var pixelSize = frameState.camera.getPixelSize(boundingVolume, frameState.context.drawingBufferWidth, frameState.context.drawingBufferHeight);
  87961. var size = pixelSize * collection._maxPixelSize;
  87962. boundingVolume.radius += size;
  87963. }
  87964. var scratchWriterArray = [];
  87965. /**
  87966. * @private
  87967. */
  87968. PointPrimitiveCollection.prototype.update = function(frameState) {
  87969. removePointPrimitives(this);
  87970. this._maxTotalPointSize = ContextLimits.maximumAliasedPointSize;
  87971. updateMode(this, frameState);
  87972. var pointPrimitives = this._pointPrimitives;
  87973. var pointPrimitivesLength = pointPrimitives.length;
  87974. var pointPrimitivesToUpdate = this._pointPrimitivesToUpdate;
  87975. var pointPrimitivesToUpdateLength = this._pointPrimitivesToUpdateIndex;
  87976. var properties = this._propertiesChanged;
  87977. var createVertexArray = this._createVertexArray;
  87978. var vafWriters;
  87979. var context = frameState.context;
  87980. var pass = frameState.passes;
  87981. var picking = pass.pick;
  87982. // PERFORMANCE_IDEA: Round robin multiple buffers.
  87983. if (createVertexArray || (!picking && this.computeNewBuffersUsage())) {
  87984. this._createVertexArray = false;
  87985. for (var k = 0; k < NUMBER_OF_PROPERTIES; ++k) {
  87986. properties[k] = 0;
  87987. }
  87988. this._vaf = this._vaf && this._vaf.destroy();
  87989. if (pointPrimitivesLength > 0) {
  87990. // PERFORMANCE_IDEA: Instead of creating a new one, resize like std::vector.
  87991. this._vaf = createVAF(context, pointPrimitivesLength, this._buffersUsage);
  87992. vafWriters = this._vaf.writers;
  87993. // Rewrite entire buffer if pointPrimitives were added or removed.
  87994. for (var i = 0; i < pointPrimitivesLength; ++i) {
  87995. var pointPrimitive = this._pointPrimitives[i];
  87996. pointPrimitive._dirty = false; // In case it needed an update.
  87997. writePointPrimitive(this, context, vafWriters, pointPrimitive);
  87998. }
  87999. this._vaf.commit();
  88000. }
  88001. this._pointPrimitivesToUpdateIndex = 0;
  88002. } else {
  88003. // PointPrimitives were modified, but none were added or removed.
  88004. if (pointPrimitivesToUpdateLength > 0) {
  88005. var writers = scratchWriterArray;
  88006. writers.length = 0;
  88007. if (properties[POSITION_INDEX] || properties[OUTLINE_WIDTH_INDEX] || properties[PIXEL_SIZE_INDEX]) {
  88008. writers.push(writePositionSizeAndOutline);
  88009. }
  88010. if (properties[COLOR_INDEX] || properties[OUTLINE_COLOR_INDEX]) {
  88011. writers.push(writeCompressedAttrib0);
  88012. }
  88013. if (properties[SHOW_INDEX] || properties[TRANSLUCENCY_BY_DISTANCE_INDEX]) {
  88014. writers.push(writeCompressedAttrib1);
  88015. }
  88016. if (properties[SCALE_BY_DISTANCE_INDEX]) {
  88017. writers.push(writeScaleByDistance);
  88018. }
  88019. if (properties[DISTANCE_DISPLAY_CONDITION_INDEX]) {
  88020. writers.push(writeDistanceDisplayCondition);
  88021. }
  88022. var numWriters = writers.length;
  88023. vafWriters = this._vaf.writers;
  88024. if ((pointPrimitivesToUpdateLength / pointPrimitivesLength) > 0.1) {
  88025. // If more than 10% of pointPrimitive change, rewrite the entire buffer.
  88026. // PERFORMANCE_IDEA: I totally made up 10% :).
  88027. for (var m = 0; m < pointPrimitivesToUpdateLength; ++m) {
  88028. var b = pointPrimitivesToUpdate[m];
  88029. b._dirty = false;
  88030. for ( var n = 0; n < numWriters; ++n) {
  88031. writers[n](this, context, vafWriters, b);
  88032. }
  88033. }
  88034. this._vaf.commit();
  88035. } else {
  88036. for (var h = 0; h < pointPrimitivesToUpdateLength; ++h) {
  88037. var bb = pointPrimitivesToUpdate[h];
  88038. bb._dirty = false;
  88039. for ( var o = 0; o < numWriters; ++o) {
  88040. writers[o](this, context, vafWriters, bb);
  88041. }
  88042. this._vaf.subCommit(bb._index, 1);
  88043. }
  88044. this._vaf.endSubCommits();
  88045. }
  88046. this._pointPrimitivesToUpdateIndex = 0;
  88047. }
  88048. }
  88049. // If the number of total pointPrimitives ever shrinks considerably
  88050. // Truncate pointPrimitivesToUpdate so that we free memory that we're
  88051. // not going to be using.
  88052. if (pointPrimitivesToUpdateLength > pointPrimitivesLength * 1.5) {
  88053. pointPrimitivesToUpdate.length = pointPrimitivesLength;
  88054. }
  88055. if (!defined(this._vaf) || !defined(this._vaf.va)) {
  88056. return;
  88057. }
  88058. if (this._boundingVolumeDirty) {
  88059. this._boundingVolumeDirty = false;
  88060. BoundingSphere.transform(this._baseVolume, this.modelMatrix, this._baseVolumeWC);
  88061. }
  88062. var boundingVolume;
  88063. var modelMatrix = Matrix4.IDENTITY;
  88064. if (frameState.mode === SceneMode.SCENE3D) {
  88065. modelMatrix = this.modelMatrix;
  88066. boundingVolume = BoundingSphere.clone(this._baseVolumeWC, this._boundingVolume);
  88067. } else {
  88068. boundingVolume = BoundingSphere.clone(this._baseVolume2D, this._boundingVolume);
  88069. }
  88070. updateBoundingVolume(this, frameState, boundingVolume);
  88071. var va;
  88072. var vaLength;
  88073. var command;
  88074. var j;
  88075. var vs;
  88076. var fs;
  88077. var commandList = frameState.commandList;
  88078. if (pass.render) {
  88079. var colorList = this._colorCommands;
  88080. if (!defined(this._rs)) {
  88081. this._rs = RenderState.fromCache({
  88082. depthTest : {
  88083. enabled : true,
  88084. func : WebGLConstants.LEQUAL
  88085. },
  88086. blending : BlendingState.ALPHA_BLEND
  88087. });
  88088. }
  88089. if (!defined(this._sp) ||
  88090. (this._shaderScaleByDistance && !this._compiledShaderScaleByDistance) ||
  88091. (this._shaderTranslucencyByDistance && !this._compiledShaderTranslucencyByDistance) ||
  88092. (this._shaderDistanceDisplayCondition && !this._compiledShaderDistanceDisplayCondition)) {
  88093. vs = new ShaderSource({
  88094. sources : [PointPrimitiveCollectionVS]
  88095. });
  88096. if (this._shaderScaleByDistance) {
  88097. vs.defines.push('EYE_DISTANCE_SCALING');
  88098. }
  88099. if (this._shaderTranslucencyByDistance) {
  88100. vs.defines.push('EYE_DISTANCE_TRANSLUCENCY');
  88101. }
  88102. if (this._shaderDistanceDisplayCondition) {
  88103. vs.defines.push('DISTANCE_DISPLAY_CONDITION');
  88104. }
  88105. this._sp = ShaderProgram.replaceCache({
  88106. context : context,
  88107. shaderProgram : this._sp,
  88108. vertexShaderSource : vs,
  88109. fragmentShaderSource : PointPrimitiveCollectionFS,
  88110. attributeLocations : attributeLocations
  88111. });
  88112. this._compiledShaderScaleByDistance = this._shaderScaleByDistance;
  88113. this._compiledShaderTranslucencyByDistance = this._shaderTranslucencyByDistance;
  88114. this._compiledShaderDistanceDisplayCondition = this._shaderDistanceDisplayCondition;
  88115. }
  88116. va = this._vaf.va;
  88117. vaLength = va.length;
  88118. colorList.length = vaLength;
  88119. for (j = 0; j < vaLength; ++j) {
  88120. command = colorList[j];
  88121. if (!defined(command)) {
  88122. command = colorList[j] = new DrawCommand({
  88123. primitiveType : PrimitiveType.POINTS,
  88124. pass : Pass.OPAQUE,
  88125. owner : this
  88126. });
  88127. }
  88128. command.boundingVolume = boundingVolume;
  88129. command.modelMatrix = modelMatrix;
  88130. command.shaderProgram = this._sp;
  88131. command.uniformMap = this._uniforms;
  88132. command.vertexArray = va[j].va;
  88133. command.renderState = this._rs;
  88134. command.debugShowBoundingVolume = this.debugShowBoundingVolume;
  88135. commandList.push(command);
  88136. }
  88137. }
  88138. if (picking) {
  88139. var pickList = this._pickCommands;
  88140. if (!defined(this._spPick) ||
  88141. (this._shaderScaleByDistance && !this._compiledShaderScaleByDistancePick) ||
  88142. (this._shaderTranslucencyByDistance && !this._compiledShaderTranslucencyByDistancePick) ||
  88143. (this._shaderDistanceDisplayCondition && !this._compiledShaderDistanceDisplayConditionPick)) {
  88144. vs = new ShaderSource({
  88145. defines : ['RENDER_FOR_PICK'],
  88146. sources : [PointPrimitiveCollectionVS]
  88147. });
  88148. if (this._shaderScaleByDistance) {
  88149. vs.defines.push('EYE_DISTANCE_SCALING');
  88150. }
  88151. if (this._shaderTranslucencyByDistance) {
  88152. vs.defines.push('EYE_DISTANCE_TRANSLUCENCY');
  88153. }
  88154. if (this._shaderDistanceDisplayCondition) {
  88155. vs.defines.push('DISTANCE_DISPLAY_CONDITION');
  88156. }
  88157. fs = new ShaderSource({
  88158. defines : ['RENDER_FOR_PICK'],
  88159. sources : [PointPrimitiveCollectionFS]
  88160. });
  88161. this._spPick = ShaderProgram.replaceCache({
  88162. context : context,
  88163. shaderProgram : this._spPick,
  88164. vertexShaderSource : vs,
  88165. fragmentShaderSource : fs,
  88166. attributeLocations : attributeLocations
  88167. });
  88168. this._compiledShaderScaleByDistancePick = this._shaderScaleByDistance;
  88169. this._compiledShaderTranslucencyByDistancePick = this._shaderTranslucencyByDistance;
  88170. this._compiledShaderDistanceDisplayConditionPick = this._shaderDistanceDisplayCondition;
  88171. }
  88172. va = this._vaf.va;
  88173. vaLength = va.length;
  88174. pickList.length = vaLength;
  88175. for (j = 0; j < vaLength; ++j) {
  88176. command = pickList[j];
  88177. if (!defined(command)) {
  88178. command = pickList[j] = new DrawCommand({
  88179. primitiveType : PrimitiveType.POINTS,
  88180. pass : Pass.OPAQUE,
  88181. owner : this
  88182. });
  88183. }
  88184. command.boundingVolume = boundingVolume;
  88185. command.modelMatrix = modelMatrix;
  88186. command.shaderProgram = this._spPick;
  88187. command.uniformMap = this._uniforms;
  88188. command.vertexArray = va[j].va;
  88189. command.renderState = this._rs;
  88190. commandList.push(command);
  88191. }
  88192. }
  88193. };
  88194. /**
  88195. * Returns true if this object was destroyed; otherwise, false.
  88196. * <br /><br />
  88197. * If this object was destroyed, it should not be used; calling any function other than
  88198. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  88199. *
  88200. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  88201. *
  88202. * @see PointPrimitiveCollection#destroy
  88203. */
  88204. PointPrimitiveCollection.prototype.isDestroyed = function() {
  88205. return false;
  88206. };
  88207. /**
  88208. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  88209. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  88210. * <br /><br />
  88211. * Once an object is destroyed, it should not be used; calling any function other than
  88212. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  88213. * assign the return value (<code>undefined</code>) to the object as done in the example.
  88214. *
  88215. * @returns {undefined}
  88216. *
  88217. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  88218. *
  88219. *
  88220. * @example
  88221. * pointPrimitives = pointPrimitives && pointPrimitives.destroy();
  88222. *
  88223. * @see PointPrimitiveCollection#isDestroyed
  88224. */
  88225. PointPrimitiveCollection.prototype.destroy = function() {
  88226. this._sp = this._sp && this._sp.destroy();
  88227. this._spPick = this._spPick && this._spPick.destroy();
  88228. this._vaf = this._vaf && this._vaf.destroy();
  88229. destroyPointPrimitives(this._pointPrimitives);
  88230. return destroyObject(this);
  88231. };
  88232. return PointPrimitiveCollection;
  88233. });
  88234. /*global define*/
  88235. define('ThirdParty/kdbush',[], function() {
  88236. 'use strict';
  88237. function kdbush(points, getX, getY, nodeSize, ArrayType) {
  88238. return new KDBush(points, getX, getY, nodeSize, ArrayType);
  88239. }
  88240. function KDBush(points, getX, getY, nodeSize, ArrayType) {
  88241. getX = getX || defaultGetX;
  88242. getY = getY || defaultGetY;
  88243. ArrayType = ArrayType || Array;
  88244. this.nodeSize = nodeSize || 64;
  88245. this.points = points;
  88246. this.ids = new ArrayType(points.length);
  88247. this.coords = new ArrayType(points.length * 2);
  88248. for (var i = 0; i < points.length; i++) {
  88249. this.ids[i] = i;
  88250. this.coords[2 * i] = getX(points[i]);
  88251. this.coords[2 * i + 1] = getY(points[i]);
  88252. }
  88253. sort(this.ids, this.coords, this.nodeSize, 0, this.ids.length - 1, 0);
  88254. }
  88255. KDBush.prototype = {
  88256. range: function (minX, minY, maxX, maxY) {
  88257. return range(this.ids, this.coords, minX, minY, maxX, maxY, this.nodeSize);
  88258. },
  88259. within: function (x, y, r) {
  88260. return within(this.ids, this.coords, x, y, r, this.nodeSize);
  88261. }
  88262. };
  88263. function defaultGetX(p) { return p[0]; }
  88264. function defaultGetY(p) { return p[1]; }
  88265. function range(ids, coords, minX, minY, maxX, maxY, nodeSize) {
  88266. var stack = [0, ids.length - 1, 0];
  88267. var result = [];
  88268. var x, y;
  88269. while (stack.length) {
  88270. var axis = stack.pop();
  88271. var right = stack.pop();
  88272. var left = stack.pop();
  88273. if (right - left <= nodeSize) {
  88274. for (var i = left; i <= right; i++) {
  88275. x = coords[2 * i];
  88276. y = coords[2 * i + 1];
  88277. if (x >= minX && x <= maxX && y >= minY && y <= maxY) result.push(ids[i]);
  88278. }
  88279. continue;
  88280. }
  88281. var m = Math.floor((left + right) / 2);
  88282. x = coords[2 * m];
  88283. y = coords[2 * m + 1];
  88284. if (x >= minX && x <= maxX && y >= minY && y <= maxY) result.push(ids[m]);
  88285. var nextAxis = (axis + 1) % 2;
  88286. if (axis === 0 ? minX <= x : minY <= y) {
  88287. stack.push(left);
  88288. stack.push(m - 1);
  88289. stack.push(nextAxis);
  88290. }
  88291. if (axis === 0 ? maxX >= x : maxY >= y) {
  88292. stack.push(m + 1);
  88293. stack.push(right);
  88294. stack.push(nextAxis);
  88295. }
  88296. }
  88297. return result;
  88298. }
  88299. function sort(ids, coords, nodeSize, left, right, depth) {
  88300. if (right - left <= nodeSize) return;
  88301. var m = Math.floor((left + right) / 2);
  88302. select(ids, coords, m, left, right, depth % 2);
  88303. sort(ids, coords, nodeSize, left, m - 1, depth + 1);
  88304. sort(ids, coords, nodeSize, m + 1, right, depth + 1);
  88305. }
  88306. function select(ids, coords, k, left, right, inc) {
  88307. while (right > left) {
  88308. if (right - left > 600) {
  88309. var n = right - left + 1;
  88310. var m = k - left + 1;
  88311. var z = Math.log(n);
  88312. var s = 0.5 * Math.exp(2 * z / 3);
  88313. var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
  88314. var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
  88315. var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
  88316. select(ids, coords, k, newLeft, newRight, inc);
  88317. }
  88318. var t = coords[2 * k + inc];
  88319. var i = left;
  88320. var j = right;
  88321. swapItem(ids, coords, left, k);
  88322. if (coords[2 * right + inc] > t) swapItem(ids, coords, left, right);
  88323. while (i < j) {
  88324. swapItem(ids, coords, i, j);
  88325. i++;
  88326. j--;
  88327. while (coords[2 * i + inc] < t) i++;
  88328. while (coords[2 * j + inc] > t) j--;
  88329. }
  88330. if (coords[2 * left + inc] === t) swapItem(ids, coords, left, j);
  88331. else {
  88332. j++;
  88333. swapItem(ids, coords, j, right);
  88334. }
  88335. if (j <= k) left = j + 1;
  88336. if (k <= j) right = j - 1;
  88337. }
  88338. }
  88339. function swapItem(ids, coords, i, j) {
  88340. swap(ids, i, j);
  88341. swap(coords, 2 * i, 2 * j);
  88342. swap(coords, 2 * i + 1, 2 * j + 1);
  88343. }
  88344. function swap(arr, i, j) {
  88345. var tmp = arr[i];
  88346. arr[i] = arr[j];
  88347. arr[j] = tmp;
  88348. }
  88349. function within(ids, coords, qx, qy, r, nodeSize) {
  88350. var stack = [0, ids.length - 1, 0];
  88351. var result = [];
  88352. var r2 = r * r;
  88353. while (stack.length) {
  88354. var axis = stack.pop();
  88355. var right = stack.pop();
  88356. var left = stack.pop();
  88357. if (right - left <= nodeSize) {
  88358. for (var i = left; i <= right; i++) {
  88359. if (sqDist(coords[2 * i], coords[2 * i + 1], qx, qy) <= r2) result.push(ids[i]);
  88360. }
  88361. continue;
  88362. }
  88363. var m = Math.floor((left + right) / 2);
  88364. var x = coords[2 * m];
  88365. var y = coords[2 * m + 1];
  88366. if (sqDist(x, y, qx, qy) <= r2) result.push(ids[m]);
  88367. var nextAxis = (axis + 1) % 2;
  88368. if (axis === 0 ? qx - r <= x : qy - r <= y) {
  88369. stack.push(left);
  88370. stack.push(m - 1);
  88371. stack.push(nextAxis);
  88372. }
  88373. if (axis === 0 ? qx + r >= x : qy + r >= y) {
  88374. stack.push(m + 1);
  88375. stack.push(right);
  88376. stack.push(nextAxis);
  88377. }
  88378. }
  88379. return result;
  88380. }
  88381. function sqDist(ax, ay, bx, by) {
  88382. var dx = ax - bx;
  88383. var dy = ay - by;
  88384. return dx * dx + dy * dy;
  88385. }
  88386. return kdbush;
  88387. });
  88388. /*global define*/
  88389. define('DataSources/EntityCluster',[
  88390. '../Core/BoundingRectangle',
  88391. '../Core/Cartesian2',
  88392. '../Core/Cartesian3',
  88393. '../Core/defaultValue',
  88394. '../Core/defined',
  88395. '../Core/defineProperties',
  88396. '../Core/EllipsoidalOccluder',
  88397. '../Core/Event',
  88398. '../Core/Matrix4',
  88399. '../Scene/Billboard',
  88400. '../Scene/BillboardCollection',
  88401. '../Scene/Label',
  88402. '../Scene/LabelCollection',
  88403. '../Scene/PointPrimitive',
  88404. '../Scene/PointPrimitiveCollection',
  88405. '../ThirdParty/kdbush'
  88406. ], function(
  88407. BoundingRectangle,
  88408. Cartesian2,
  88409. Cartesian3,
  88410. defaultValue,
  88411. defined,
  88412. defineProperties,
  88413. EllipsoidalOccluder,
  88414. Event,
  88415. Matrix4,
  88416. Billboard,
  88417. BillboardCollection,
  88418. Label,
  88419. LabelCollection,
  88420. PointPrimitive,
  88421. PointPrimitiveCollection,
  88422. kdbush) {
  88423. 'use strict';
  88424. /**
  88425. * Defines how screen space objects (billboards, points, labels) are clustered.
  88426. *
  88427. * @param {Object} [options] An object with the following properties:
  88428. * @param {Boolean} [options.enabled=false] Whether or not to enable clustering.
  88429. * @param {Number} [options.pixelRange=80] The pixel range to extend the screen space bounding box.
  88430. * @param {Number} [options.minimumClusterSize=2] The minimum number of screen space objects that can be clustered.
  88431. * @param {Boolean} [options.clusterBillboards=true] Whether or not to cluster the billboards of an entity.
  88432. * @param {Boolean} [options.clusterLabels=true] Whether or not to cluster the labels of an entity.
  88433. * @param {Boolean} [options.clusterPoints=true] Whether or not to cluster the points of an entity.
  88434. *
  88435. * @alias EntityCluster
  88436. * @constructor
  88437. *
  88438. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Clustering.html|Cesium Sandcastle Clustering Demo}
  88439. */
  88440. function EntityCluster(options) {
  88441. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  88442. this._enabled = defaultValue(options.enabled, false);
  88443. this._pixelRange = defaultValue(options.pixelRange, 80);
  88444. this._minimumClusterSize = defaultValue(options.minimumClusterSize, 2);
  88445. this._clusterBillboards = defaultValue(options.clusterBillboards, true);
  88446. this._clusterLabels = defaultValue(options.clusterLabels, true);
  88447. this._clusterPoints = defaultValue(options.clusterPoints, true);
  88448. this._labelCollection = undefined;
  88449. this._billboardCollection = undefined;
  88450. this._pointCollection = undefined;
  88451. this._clusterBillboardCollection = undefined;
  88452. this._clusterLabelCollection = undefined;
  88453. this._clusterPointCollection = undefined;
  88454. this._collectionIndicesByEntity = {};
  88455. this._unusedLabelIndices = [];
  88456. this._unusedBillboardIndices = [];
  88457. this._unusedPointIndices = [];
  88458. this._previousClusters = [];
  88459. this._previousHeight = undefined;
  88460. this._enabledDirty = false;
  88461. this._clusterDirty = false;
  88462. this._cluster = undefined;
  88463. this._removeEventListener = undefined;
  88464. this._clusterEvent = new Event();
  88465. }
  88466. function getX(point) {
  88467. return point.coord.x;
  88468. }
  88469. function getY(point) {
  88470. return point.coord.y;
  88471. }
  88472. function expandBoundingBox(bbox, pixelRange) {
  88473. bbox.x -= pixelRange;
  88474. bbox.y -= pixelRange;
  88475. bbox.width += pixelRange * 2.0;
  88476. bbox.height += pixelRange * 2.0;
  88477. }
  88478. var labelBoundingBoxScratch = new BoundingRectangle();
  88479. function getBoundingBox(item, coord, pixelRange, entityCluster, result) {
  88480. if (defined(item._labelCollection) && entityCluster._clusterLabels) {
  88481. result = Label.getScreenSpaceBoundingBox(item, coord, result);
  88482. } else if (defined(item._billboardCollection) && entityCluster._clusterBillboards) {
  88483. result = Billboard.getScreenSpaceBoundingBox(item, coord, result);
  88484. } else if (defined(item._pointPrimitiveCollection) && entityCluster._clusterPoints) {
  88485. result = PointPrimitive.getScreenSpaceBoundingBox(item, coord, result);
  88486. }
  88487. expandBoundingBox(result, pixelRange);
  88488. if (entityCluster._clusterLabels && !defined(item._labelCollection) && defined(item.id) && hasLabelIndex(entityCluster, item.id) && defined(item.id._label)) {
  88489. var labelIndex = entityCluster._collectionIndicesByEntity[item.id];
  88490. var label = entityCluster._labelCollection.get(labelIndex);
  88491. var labelBBox = Label.getScreenSpaceBoundingBox(label, coord, labelBoundingBoxScratch);
  88492. expandBoundingBox(labelBBox, pixelRange);
  88493. result = BoundingRectangle.union(result, labelBBox, result);
  88494. }
  88495. return result;
  88496. }
  88497. function addNonClusteredItem(item, entityCluster) {
  88498. item.clusterShow = true;
  88499. if (!defined(item._labelCollection) && defined(item.id) && hasLabelIndex(entityCluster, item.id) && defined(item.id._label)) {
  88500. var labelIndex = entityCluster._collectionIndicesByEntity[item.id];
  88501. var label = entityCluster._labelCollection.get(labelIndex);
  88502. label.clusterShow = true;
  88503. }
  88504. }
  88505. function addCluster(position, numPoints, ids, entityCluster) {
  88506. var cluster = {
  88507. billboard : entityCluster._clusterBillboardCollection.add(),
  88508. label : entityCluster._clusterLabelCollection.add(),
  88509. point : entityCluster._clusterPointCollection.add()
  88510. };
  88511. cluster.billboard.show = false;
  88512. cluster.point.show = false;
  88513. cluster.label.show = true;
  88514. cluster.label.text = numPoints.toLocaleString();
  88515. cluster.billboard.position = cluster.label.position = cluster.point.position = position;
  88516. entityCluster._clusterEvent.raiseEvent(ids, cluster);
  88517. }
  88518. function hasLabelIndex(entityCluster, entityId) {
  88519. return defined(entityCluster) && defined(entityCluster._collectionIndicesByEntity[entityId]) && defined(entityCluster._collectionIndicesByEntity[entityId].labelIndex);
  88520. }
  88521. function getScreenSpacePositions(collection, points, scene, occluder, entityCluster) {
  88522. if (!defined(collection)) {
  88523. return;
  88524. }
  88525. var length = collection.length;
  88526. for (var i = 0; i < length; ++i) {
  88527. var item = collection.get(i);
  88528. item.clusterShow = false;
  88529. if (!item.show || !occluder.isPointVisible(item.position)) {
  88530. continue;
  88531. }
  88532. var canClusterLabels = entityCluster._clusterLabels && defined(item._labelCollection);
  88533. var canClusterBillboards = entityCluster._clusterBillboards && defined(item.id._billboard);
  88534. var canClusterPoints = entityCluster._clusterPoints && defined(item.id._point);
  88535. if (canClusterLabels && (canClusterPoints || canClusterBillboards)) {
  88536. continue;
  88537. }
  88538. var coord = item.computeScreenSpacePosition(scene);
  88539. if (!defined(coord)) {
  88540. continue;
  88541. }
  88542. points.push({
  88543. index : i,
  88544. collection : collection,
  88545. clustered : false,
  88546. coord : coord
  88547. });
  88548. }
  88549. }
  88550. var pointBoundinRectangleScratch = new BoundingRectangle();
  88551. var totalBoundingRectangleScratch = new BoundingRectangle();
  88552. var neighborBoundingRectangleScratch = new BoundingRectangle();
  88553. function createDeclutterCallback(entityCluster) {
  88554. return function(amount) {
  88555. if ((defined(amount) && amount < 0.05) || !entityCluster.enabled) {
  88556. return;
  88557. }
  88558. var scene = entityCluster._scene;
  88559. var labelCollection = entityCluster._labelCollection;
  88560. var billboardCollection = entityCluster._billboardCollection;
  88561. var pointCollection = entityCluster._pointCollection;
  88562. if ((!defined(labelCollection) && !defined(billboardCollection) && !defined(pointCollection)) ||
  88563. (!entityCluster._clusterBillboards && !entityCluster._clusterLabels && !entityCluster._clusterPoints)) {
  88564. return;
  88565. }
  88566. var clusteredLabelCollection = entityCluster._clusterLabelCollection;
  88567. var clusteredBillboardCollection = entityCluster._clusterBillboardCollection;
  88568. var clusteredPointCollection = entityCluster._clusterPointCollection;
  88569. if (defined(clusteredLabelCollection)) {
  88570. clusteredLabelCollection.removeAll();
  88571. } else {
  88572. clusteredLabelCollection = entityCluster._clusterLabelCollection = new LabelCollection({
  88573. scene : scene
  88574. });
  88575. }
  88576. if (defined(clusteredBillboardCollection)) {
  88577. clusteredBillboardCollection.removeAll();
  88578. } else {
  88579. clusteredBillboardCollection = entityCluster._clusterBillboardCollection = new BillboardCollection({
  88580. scene : scene
  88581. });
  88582. }
  88583. if (defined(clusteredPointCollection)) {
  88584. clusteredPointCollection.removeAll();
  88585. } else {
  88586. clusteredPointCollection = entityCluster._clusterPointCollection = new PointPrimitiveCollection();
  88587. }
  88588. var pixelRange = entityCluster._pixelRange;
  88589. var minimumClusterSize = entityCluster._minimumClusterSize;
  88590. var clusters = entityCluster._previousClusters;
  88591. var newClusters = [];
  88592. var previousHeight = entityCluster._previousHeight;
  88593. var currentHeight = scene.camera.positionCartographic.height;
  88594. var ellipsoid = scene.mapProjection.ellipsoid;
  88595. var cameraPosition = scene.camera.positionWC;
  88596. var occluder = new EllipsoidalOccluder(ellipsoid, cameraPosition);
  88597. var points = [];
  88598. if (entityCluster._clusterLabels) {
  88599. getScreenSpacePositions(labelCollection, points, scene, occluder, entityCluster);
  88600. }
  88601. if (entityCluster._clusterBillboards) {
  88602. getScreenSpacePositions(billboardCollection, points, scene, occluder, entityCluster);
  88603. }
  88604. if (entityCluster._clusterPoints) {
  88605. getScreenSpacePositions(pointCollection, points, scene, occluder, entityCluster);
  88606. }
  88607. var i;
  88608. var j;
  88609. var length;
  88610. var bbox;
  88611. var neighbors;
  88612. var neighborLength;
  88613. var neighborIndex;
  88614. var neighborPoint;
  88615. var ids;
  88616. var numPoints;
  88617. var collection;
  88618. var collectionIndex;
  88619. var index = kdbush(points, getX, getY, 64, Int32Array);
  88620. if (currentHeight < previousHeight) {
  88621. length = clusters.length;
  88622. for (i = 0; i < length; ++i) {
  88623. var cluster = clusters[i];
  88624. if (!occluder.isPointVisible(cluster.position)) {
  88625. continue;
  88626. }
  88627. var coord = Billboard._computeScreenSpacePosition(Matrix4.IDENTITY, cluster.position, Cartesian3.ZERO, Cartesian2.ZERO, scene);
  88628. if (!defined(coord)) {
  88629. continue;
  88630. }
  88631. var factor = 1.0 - currentHeight / previousHeight;
  88632. var width = cluster.width = cluster.width * factor;
  88633. var height = cluster.height = cluster.height * factor;
  88634. width = Math.max(width, cluster.minimumWidth);
  88635. height = Math.max(height, cluster.minimumHeight);
  88636. var minX = coord.x - width * 0.5;
  88637. var minY = coord.y - height * 0.5;
  88638. var maxX = coord.x + width;
  88639. var maxY = coord.y + height;
  88640. neighbors = index.range(minX, minY, maxX, maxY);
  88641. neighborLength = neighbors.length;
  88642. numPoints = 0;
  88643. ids = [];
  88644. for (j = 0; j < neighborLength; ++j) {
  88645. neighborIndex = neighbors[j];
  88646. neighborPoint = points[neighborIndex];
  88647. if (!neighborPoint.clustered) {
  88648. ++numPoints;
  88649. collection = neighborPoint.collection;
  88650. collectionIndex = neighborPoint.index;
  88651. ids.push(collection.get(collectionIndex).id);
  88652. }
  88653. }
  88654. if (numPoints >= minimumClusterSize) {
  88655. addCluster(cluster.position, numPoints, ids, entityCluster);
  88656. newClusters.push(cluster);
  88657. for (j = 0; j < neighborLength; ++j) {
  88658. points[neighbors[j]].clustered = true;
  88659. }
  88660. }
  88661. }
  88662. }
  88663. length = points.length;
  88664. for (i = 0; i < length; ++i) {
  88665. var point = points[i];
  88666. if (point.clustered) {
  88667. continue;
  88668. }
  88669. point.clustered = true;
  88670. collection = point.collection;
  88671. collectionIndex = point.index;
  88672. var item = collection.get(collectionIndex);
  88673. bbox = getBoundingBox(item, point.coord, pixelRange, entityCluster, pointBoundinRectangleScratch);
  88674. var totalBBox = BoundingRectangle.clone(bbox, totalBoundingRectangleScratch);
  88675. neighbors = index.range(bbox.x, bbox.y, bbox.x + bbox.width, bbox.y + bbox.height);
  88676. neighborLength = neighbors.length;
  88677. var clusterPosition = Cartesian3.clone(item.position);
  88678. numPoints = 1;
  88679. ids = [item.id];
  88680. for (j = 0; j < neighborLength; ++j) {
  88681. neighborIndex = neighbors[j];
  88682. neighborPoint = points[neighborIndex];
  88683. if (!neighborPoint.clustered) {
  88684. var neighborItem = neighborPoint.collection.get(neighborPoint.index);
  88685. var neighborBBox = getBoundingBox(neighborItem, neighborPoint.coord, pixelRange, entityCluster, neighborBoundingRectangleScratch);
  88686. Cartesian3.add(neighborItem.position, clusterPosition, clusterPosition);
  88687. BoundingRectangle.union(totalBBox, neighborBBox, totalBBox);
  88688. ++numPoints;
  88689. ids.push(neighborItem.id);
  88690. }
  88691. }
  88692. if (numPoints >= minimumClusterSize) {
  88693. var position = Cartesian3.multiplyByScalar(clusterPosition, 1.0 / numPoints, clusterPosition);
  88694. addCluster(position, numPoints, ids, entityCluster);
  88695. newClusters.push({
  88696. position : position,
  88697. width : totalBBox.width,
  88698. height : totalBBox.height,
  88699. minimumWidth : bbox.width,
  88700. minimumHeight : bbox.height
  88701. });
  88702. for (j = 0; j < neighborLength; ++j) {
  88703. points[neighbors[j]].clustered = true;
  88704. }
  88705. } else {
  88706. addNonClusteredItem(item, entityCluster);
  88707. }
  88708. }
  88709. if (clusteredLabelCollection.length === 0) {
  88710. clusteredLabelCollection.destroy();
  88711. entityCluster._clusterLabelCollection = undefined;
  88712. }
  88713. if (clusteredBillboardCollection.length === 0) {
  88714. clusteredBillboardCollection.destroy();
  88715. entityCluster._clusterBillboardCollection = undefined;
  88716. }
  88717. if (clusteredPointCollection.length === 0) {
  88718. clusteredPointCollection.destroy();
  88719. entityCluster._clusterPointCollection = undefined;
  88720. }
  88721. entityCluster._previousClusters = newClusters;
  88722. entityCluster._previousHeight = currentHeight;
  88723. };
  88724. }
  88725. EntityCluster.prototype._initialize = function(scene) {
  88726. this._scene = scene;
  88727. var cluster = createDeclutterCallback(this);
  88728. this._cluster = cluster;
  88729. this._removeEventListener = scene.camera.changed.addEventListener(cluster);
  88730. };
  88731. defineProperties(EntityCluster.prototype, {
  88732. /**
  88733. * Gets or sets whether clustering is enabled.
  88734. * @memberof EntityCluster.prototype
  88735. * @type {Boolean}
  88736. */
  88737. enabled : {
  88738. get : function() {
  88739. return this._enabled;
  88740. },
  88741. set : function(value) {
  88742. this._enabledDirty = value !== this._enabled;
  88743. this._enabled = value;
  88744. }
  88745. },
  88746. /**
  88747. * Gets or sets the pixel range to extend the screen space bounding box.
  88748. * @memberof EntityCluster.prototype
  88749. * @type {Number}
  88750. */
  88751. pixelRange : {
  88752. get : function() {
  88753. return this._pixelRange;
  88754. },
  88755. set : function(value) {
  88756. this._clusterDirty = this._clusterDirty || value !== this._pixelRange;
  88757. this._pixelRange = value;
  88758. }
  88759. },
  88760. /**
  88761. * Gets or sets the minimum number of screen space objects that can be clustered.
  88762. * @memberof EntityCluster.prototype
  88763. * @type {Number}
  88764. */
  88765. minimumClusterSize : {
  88766. get : function() {
  88767. return this._minimumClusterSize;
  88768. },
  88769. set : function(value) {
  88770. this._clusterDirty = this._clusterDirty || value !== this._minimumClusterSize;
  88771. this._minimumClusterSize = value;
  88772. }
  88773. },
  88774. /**
  88775. * Gets the event that will be raised when a new cluster will be displayed. The signature of the event listener is {@link EntityCluster~newClusterCallback}.
  88776. * @memberof EntityCluster.prototype
  88777. * @type {Event}
  88778. */
  88779. clusterEvent : {
  88780. get : function() {
  88781. return this._clusterEvent;
  88782. }
  88783. },
  88784. /**
  88785. * Gets or sets whether clustering billboard entities is enabled.
  88786. * @memberof EntityCluster.prototype
  88787. * @type {Boolean}
  88788. */
  88789. clusterBillboards : {
  88790. get : function() {
  88791. return this._clusterBillboards;
  88792. },
  88793. set : function(value) {
  88794. this._clusterDirty = this._clusterDirty || value !== this._clusterBillboards;
  88795. this._clusterBillboards = value;
  88796. }
  88797. },
  88798. /**
  88799. * Gets or sets whether clustering labels entities is enabled.
  88800. * @memberof EntityCluster.prototype
  88801. * @type {Boolean}
  88802. */
  88803. clusterLabels : {
  88804. get : function() {
  88805. return this._clusterLabels;
  88806. },
  88807. set : function(value) {
  88808. this._clusterDirty = this._clusterDirty || value !== this._clusterLabels;
  88809. this._clusterLabels = value;
  88810. }
  88811. },
  88812. /**
  88813. * Gets or sets whether clustering point entities is enabled.
  88814. * @memberof EntityCluster.prototype
  88815. * @type {Boolean}
  88816. */
  88817. clusterPoints : {
  88818. get : function() {
  88819. return this._clusterPoints;
  88820. },
  88821. set : function(value) {
  88822. this._clusterDirty = this._clusterDirty || value !== this._clusterPoints;
  88823. this._clusterPoints = value;
  88824. }
  88825. }
  88826. });
  88827. function createGetEntity(collectionProperty, CollectionConstructor, unusedIndicesProperty, entityIndexProperty) {
  88828. return function(entity) {
  88829. var collection = this[collectionProperty];
  88830. if (!defined(this._collectionIndicesByEntity)) {
  88831. this._collectionIndicesByEntity = {};
  88832. }
  88833. var entityIndices = this._collectionIndicesByEntity[entity.id];
  88834. if (!defined(entityIndices)) {
  88835. entityIndices = this._collectionIndicesByEntity[entity.id] = {
  88836. billboardIndex: undefined,
  88837. labelIndex: undefined,
  88838. pointIndex: undefined
  88839. };
  88840. }
  88841. if (defined(collection) && defined(entityIndices[entityIndexProperty])) {
  88842. return collection.get(entityIndices[entityIndexProperty]);
  88843. }
  88844. if (!defined(collection)) {
  88845. collection = this[collectionProperty] = new CollectionConstructor({
  88846. scene : this._scene
  88847. });
  88848. }
  88849. var index;
  88850. var entityItem;
  88851. var unusedIndices = this[unusedIndicesProperty];
  88852. if (unusedIndices.length > 0) {
  88853. index = unusedIndices.pop();
  88854. entityItem = collection.get(index);
  88855. } else {
  88856. entityItem = collection.add();
  88857. index = collection.length - 1;
  88858. }
  88859. entityIndices[entityIndexProperty] = index;
  88860. this._clusterDirty = true;
  88861. return entityItem;
  88862. };
  88863. }
  88864. function removeEntityIndicesIfUnused(entityCluster, entityId) {
  88865. var indices = entityCluster._collectionIndicesByEntity[entityId];
  88866. if (!defined(indices.billboardIndex) && !defined(indices.labelIndex) && !defined(indices.pointIndex)) {
  88867. delete entityCluster._collectionIndicesByEntity[entityId];
  88868. }
  88869. }
  88870. /**
  88871. * Returns a new {@link Label}.
  88872. * @param {Entity} entity The entity that will use the returned {@link Label} for visualization.
  88873. * @returns {Label} The label that will be used to visualize an entity.
  88874. *
  88875. * @private
  88876. */
  88877. EntityCluster.prototype.getLabel = createGetEntity('_labelCollection', LabelCollection, '_unusedLabelIndices', 'labelIndex');
  88878. /**
  88879. * Removes the {@link Label} associated with an entity so it can be reused by another entity.
  88880. * @param {Entity} entity The entity that will uses the returned {@link Label} for visualization.
  88881. *
  88882. * @private
  88883. */
  88884. EntityCluster.prototype.removeLabel = function(entity) {
  88885. var entityIndices = this._collectionIndicesByEntity && this._collectionIndicesByEntity[entity.id];
  88886. if (!defined(this._labelCollection) || !defined(entityIndices) || !defined(entityIndices.labelIndex)) {
  88887. return;
  88888. }
  88889. var index = entityIndices.labelIndex;
  88890. entityIndices.labelIndex = undefined;
  88891. removeEntityIndicesIfUnused(this, entity.id);
  88892. var label = this._labelCollection.get(index);
  88893. label.show = false;
  88894. label.text = '';
  88895. label.id = undefined;
  88896. this._unusedLabelIndices.push(index);
  88897. this._clusterDirty = true;
  88898. };
  88899. /**
  88900. * Returns a new {@link Billboard}.
  88901. * @param {Entity} entity The entity that will use the returned {@link Billboard} for visualization.
  88902. * @returns {Billboard} The label that will be used to visualize an entity.
  88903. *
  88904. * @private
  88905. */
  88906. EntityCluster.prototype.getBillboard = createGetEntity('_billboardCollection', BillboardCollection, '_unusedBillboardIndices', 'billboardIndex');
  88907. /**
  88908. * Removes the {@link Billboard} associated with an entity so it can be reused by another entity.
  88909. * @param {Entity} entity The entity that will uses the returned {@link Billboard} for visualization.
  88910. *
  88911. * @private
  88912. */
  88913. EntityCluster.prototype.removeBillboard = function(entity) {
  88914. var entityIndices = this._collectionIndicesByEntity && this._collectionIndicesByEntity[entity.id];
  88915. if (!defined(this._billboardCollection) || !defined(entityIndices) || !defined(entityIndices.billboardIndex)) {
  88916. return;
  88917. }
  88918. var index = entityIndices.billboardIndex;
  88919. entityIndices.billboardIndex = undefined;
  88920. removeEntityIndicesIfUnused(this, entity.id);
  88921. var billboard = this._billboardCollection.get(index);
  88922. billboard.id = undefined;
  88923. billboard.show = false;
  88924. billboard.image = undefined;
  88925. this._unusedBillboardIndices.push(index);
  88926. this._clusterDirty = true;
  88927. };
  88928. /**
  88929. * Returns a new {@link Point}.
  88930. * @param {Entity} entity The entity that will use the returned {@link Point} for visualization.
  88931. * @returns {Point} The label that will be used to visualize an entity.
  88932. *
  88933. * @private
  88934. */
  88935. EntityCluster.prototype.getPoint = createGetEntity('_pointCollection', PointPrimitiveCollection, '_unusedPointIndices', 'pointIndex');
  88936. /**
  88937. * Removes the {@link Point} associated with an entity so it can be reused by another entity.
  88938. * @param {Entity} entity The entity that will uses the returned {@link Point} for visualization.
  88939. *
  88940. * @private
  88941. */
  88942. EntityCluster.prototype.removePoint = function(entity) {
  88943. var entityIndices = this._collectionIndicesByEntity && this._collectionIndicesByEntity[entity.id];
  88944. if (!defined(this._pointCollection) || !defined(entityIndices) || !defined(entityIndices.pointIndex)) {
  88945. return;
  88946. }
  88947. var index = entityIndices.pointIndex;
  88948. entityIndices.pointIndex = undefined;
  88949. removeEntityIndicesIfUnused(this, entity.id);
  88950. var point = this._pointCollection.get(index);
  88951. point.show = false;
  88952. point.id = undefined;
  88953. this._unusedPointIndices.push(index);
  88954. this._clusterDirty = true;
  88955. };
  88956. function disableCollectionClustering(collection) {
  88957. if (!defined(collection)) {
  88958. return;
  88959. }
  88960. var length = collection.length;
  88961. for (var i = 0; i < length; ++i) {
  88962. collection.get(i).clusterShow = true;
  88963. }
  88964. }
  88965. function updateEnable(entityCluster) {
  88966. if (entityCluster.enabled) {
  88967. return;
  88968. }
  88969. if (defined(entityCluster._clusterLabelCollection)) {
  88970. entityCluster._clusterLabelCollection.destroy();
  88971. }
  88972. if (defined(entityCluster._clusterBillboardCollection)) {
  88973. entityCluster._clusterBillboardCollection.destroy();
  88974. }
  88975. if (defined(entityCluster._clusterPointCollection)) {
  88976. entityCluster._clusterPointCollection.destroy();
  88977. }
  88978. entityCluster._clusterLabelCollection = undefined;
  88979. entityCluster._clusterBillboardCollection = undefined;
  88980. entityCluster._clusterPointCollection = undefined;
  88981. disableCollectionClustering(entityCluster._labelCollection);
  88982. disableCollectionClustering(entityCluster._billboardCollection);
  88983. disableCollectionClustering(entityCluster._pointCollection);
  88984. }
  88985. /**
  88986. * Gets the draw commands for the clustered billboards/points/labels if enabled, otherwise,
  88987. * queues the draw commands for billboards/points/labels created for entities.
  88988. * @private
  88989. */
  88990. EntityCluster.prototype.update = function(frameState) {
  88991. // If clustering is enabled before the label collection is updated,
  88992. // the glyphs haven't been created so the screen space bounding boxes
  88993. // are incorrect.
  88994. if (defined(this._labelCollection) && this._labelCollection.length > 0 && this._labelCollection.get(0)._glyphs.length === 0) {
  88995. var commandList = frameState.commandList;
  88996. frameState.commandList = [];
  88997. this._labelCollection.update(frameState);
  88998. frameState.commandList = commandList;
  88999. }
  89000. if (this._enabledDirty) {
  89001. this._enabledDirty = false;
  89002. updateEnable(this);
  89003. this._clusterDirty = true;
  89004. }
  89005. if (this._clusterDirty) {
  89006. this._clusterDirty = false;
  89007. this._cluster();
  89008. }
  89009. if (defined(this._clusterLabelCollection)) {
  89010. this._clusterLabelCollection.update(frameState);
  89011. }
  89012. if (defined(this._clusterBillboardCollection)) {
  89013. this._clusterBillboardCollection.update(frameState);
  89014. }
  89015. if (defined(this._clusterPointCollection)) {
  89016. this._clusterPointCollection.update(frameState);
  89017. }
  89018. if (defined(this._labelCollection)) {
  89019. this._labelCollection.update(frameState);
  89020. }
  89021. if (defined(this._billboardCollection)) {
  89022. this._billboardCollection.update(frameState);
  89023. }
  89024. if (defined(this._pointCollection)) {
  89025. this._pointCollection.update(frameState);
  89026. }
  89027. };
  89028. /**
  89029. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  89030. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  89031. * <p>
  89032. * Unlike other objects that use WebGL resources, this object can be reused. For example, if a data source is removed
  89033. * from a data source collection and added to another.
  89034. * </p>
  89035. *
  89036. * @returns {undefined}
  89037. */
  89038. EntityCluster.prototype.destroy = function() {
  89039. this._labelCollection = this._labelCollection && this._labelCollection.destroy();
  89040. this._billboardCollection = this._billboardCollection && this._billboardCollection.destroy();
  89041. this._pointCollection = this._pointCollection && this._pointCollection.destroy();
  89042. this._clusterLabelCollection = this._clusterLabelCollection && this._clusterLabelCollection.destroy();
  89043. this._clusterBillboardCollection = this._clusterBillboardCollection && this._clusterBillboardCollection.destroy();
  89044. this._clusterPointCollection = this._clusterPointCollection && this._clusterPointCollection.destroy();
  89045. if (defined(this._removeEventListener)) {
  89046. this._removeEventListener();
  89047. this._removeEventListener = undefined;
  89048. }
  89049. this._labelCollection = undefined;
  89050. this._billboardCollection = undefined;
  89051. this._pointCollection = undefined;
  89052. this._clusterBillboardCollection = undefined;
  89053. this._clusterLabelCollection = undefined;
  89054. this._clusterPointCollection = undefined;
  89055. this._collectionIndicesByEntity = undefined;
  89056. this._unusedLabelIndices = [];
  89057. this._unusedBillboardIndices = [];
  89058. this._unusedPointIndices = [];
  89059. this._previousClusters = [];
  89060. this._previousHeight = undefined;
  89061. this._enabledDirty = false;
  89062. this._pixelRangeDirty = false;
  89063. this._minimumClusterSizeDirty = false;
  89064. return undefined;
  89065. };
  89066. /**
  89067. * A event listener function used to style clusters.
  89068. * @callback EntityCluster~newClusterCallback
  89069. *
  89070. * @param {Entity[]} clusteredEntities An array of the entities contained in the cluster.
  89071. * @param {Object} cluster An object containing billboard, label, and point properties. The values are the same as
  89072. * billboard, label and point entities, but must be the values of the ConstantProperty.
  89073. *
  89074. * @example
  89075. * // The default cluster values.
  89076. * dataSource.clustering.clusterEvent.addEventListener(function(entities, cluster) {
  89077. * cluster.label.show = true;
  89078. * cluster.label.text = entities.length.toLocaleString();
  89079. * });
  89080. */
  89081. return EntityCluster;
  89082. });
  89083. /*global define*/
  89084. define('DataSources/CustomDataSource',[
  89085. '../Core/defined',
  89086. '../Core/defineProperties',
  89087. '../Core/DeveloperError',
  89088. '../Core/Event',
  89089. './DataSource',
  89090. './EntityCluster',
  89091. './EntityCollection'
  89092. ], function(
  89093. defined,
  89094. defineProperties,
  89095. DeveloperError,
  89096. Event,
  89097. DataSource,
  89098. EntityCluster,
  89099. EntityCollection) {
  89100. 'use strict';
  89101. /**
  89102. * A {@link DataSource} implementation which can be used to manually manage a group of entities.
  89103. *
  89104. * @alias CustomDataSource
  89105. * @constructor
  89106. *
  89107. * @param {String} [name] A human-readable name for this instance.
  89108. *
  89109. * @example
  89110. * var dataSource = new Cesium.CustomDataSource('myData');
  89111. *
  89112. * var entity = dataSource.entities.add({
  89113. * position : Cesium.Cartesian3.fromDegrees(1, 2, 0),
  89114. * billboard : {
  89115. * image : 'image.png'
  89116. * }
  89117. * });
  89118. *
  89119. * viewer.dataSources.add(dataSource);
  89120. */
  89121. function CustomDataSource(name) {
  89122. this._name = name;
  89123. this._clock = undefined;
  89124. this._changed = new Event();
  89125. this._error = new Event();
  89126. this._isLoading = false;
  89127. this._loading = new Event();
  89128. this._entityCollection = new EntityCollection(this);
  89129. this._entityCluster = new EntityCluster();
  89130. }
  89131. defineProperties(CustomDataSource.prototype, {
  89132. /**
  89133. * Gets or sets a human-readable name for this instance.
  89134. * @memberof CustomDataSource.prototype
  89135. * @type {String}
  89136. */
  89137. name : {
  89138. get : function() {
  89139. return this._name;
  89140. },
  89141. set : function(value) {
  89142. if (this._name !== value) {
  89143. this._name = value;
  89144. this._changed.raiseEvent(this);
  89145. }
  89146. }
  89147. },
  89148. /**
  89149. * Gets or sets the clock for this instance.
  89150. * @memberof CustomDataSource.prototype
  89151. * @type {DataSourceClock}
  89152. */
  89153. clock : {
  89154. get : function() {
  89155. return this._clock;
  89156. },
  89157. set : function(value) {
  89158. if (this._clock !== value) {
  89159. this._clock = value;
  89160. this._changed.raiseEvent(this);
  89161. }
  89162. }
  89163. },
  89164. /**
  89165. * Gets the collection of {@link Entity} instances.
  89166. * @memberof CustomDataSource.prototype
  89167. * @type {EntityCollection}
  89168. */
  89169. entities : {
  89170. get : function() {
  89171. return this._entityCollection;
  89172. }
  89173. },
  89174. /**
  89175. * Gets or sets whether the data source is currently loading data.
  89176. * @memberof CustomDataSource.prototype
  89177. * @type {Boolean}
  89178. */
  89179. isLoading : {
  89180. get : function() {
  89181. return this._isLoading;
  89182. },
  89183. set : function(value) {
  89184. DataSource.setLoading(this, value);
  89185. }
  89186. },
  89187. /**
  89188. * Gets an event that will be raised when the underlying data changes.
  89189. * @memberof CustomDataSource.prototype
  89190. * @type {Event}
  89191. */
  89192. changedEvent : {
  89193. get : function() {
  89194. return this._changed;
  89195. }
  89196. },
  89197. /**
  89198. * Gets an event that will be raised if an error is encountered during processing.
  89199. * @memberof CustomDataSource.prototype
  89200. * @type {Event}
  89201. */
  89202. errorEvent : {
  89203. get : function() {
  89204. return this._error;
  89205. }
  89206. },
  89207. /**
  89208. * Gets an event that will be raised when the data source either starts or stops loading.
  89209. * @memberof CustomDataSource.prototype
  89210. * @type {Event}
  89211. */
  89212. loadingEvent : {
  89213. get : function() {
  89214. return this._loading;
  89215. }
  89216. },
  89217. /**
  89218. * Gets whether or not this data source should be displayed.
  89219. * @memberof CustomDataSource.prototype
  89220. * @type {Boolean}
  89221. */
  89222. show : {
  89223. get : function() {
  89224. return this._entityCollection.show;
  89225. },
  89226. set : function(value) {
  89227. this._entityCollection.show = value;
  89228. }
  89229. },
  89230. /**
  89231. * Gets or sets the clustering options for this data source. This object can be shared between multiple data sources.
  89232. *
  89233. * @memberof CustomDataSource.prototype
  89234. * @type {EntityCluster}
  89235. */
  89236. clustering : {
  89237. get : function() {
  89238. return this._entityCluster;
  89239. },
  89240. set : function(value) {
  89241. if (!defined(value)) {
  89242. throw new DeveloperError('value must be defined.');
  89243. }
  89244. this._entityCluster = value;
  89245. }
  89246. }
  89247. });
  89248. return CustomDataSource;
  89249. });
  89250. /*global define*/
  89251. define('DataSources/CylinderGeometryUpdater',[
  89252. '../Core/Color',
  89253. '../Core/ColorGeometryInstanceAttribute',
  89254. '../Core/CylinderGeometry',
  89255. '../Core/CylinderOutlineGeometry',
  89256. '../Core/defaultValue',
  89257. '../Core/defined',
  89258. '../Core/defineProperties',
  89259. '../Core/destroyObject',
  89260. '../Core/DeveloperError',
  89261. '../Core/DistanceDisplayCondition',
  89262. '../Core/DistanceDisplayConditionGeometryInstanceAttribute',
  89263. '../Core/Event',
  89264. '../Core/GeometryInstance',
  89265. '../Core/Iso8601',
  89266. '../Core/ShowGeometryInstanceAttribute',
  89267. '../Scene/MaterialAppearance',
  89268. '../Scene/PerInstanceColorAppearance',
  89269. '../Scene/Primitive',
  89270. '../Scene/ShadowMode',
  89271. './ColorMaterialProperty',
  89272. './ConstantProperty',
  89273. './dynamicGeometryGetBoundingSphere',
  89274. './MaterialProperty',
  89275. './Property'
  89276. ], function(
  89277. Color,
  89278. ColorGeometryInstanceAttribute,
  89279. CylinderGeometry,
  89280. CylinderOutlineGeometry,
  89281. defaultValue,
  89282. defined,
  89283. defineProperties,
  89284. destroyObject,
  89285. DeveloperError,
  89286. DistanceDisplayCondition,
  89287. DistanceDisplayConditionGeometryInstanceAttribute,
  89288. Event,
  89289. GeometryInstance,
  89290. Iso8601,
  89291. ShowGeometryInstanceAttribute,
  89292. MaterialAppearance,
  89293. PerInstanceColorAppearance,
  89294. Primitive,
  89295. ShadowMode,
  89296. ColorMaterialProperty,
  89297. ConstantProperty,
  89298. dynamicGeometryGetBoundingSphere,
  89299. MaterialProperty,
  89300. Property) {
  89301. 'use strict';
  89302. var defaultMaterial = new ColorMaterialProperty(Color.WHITE);
  89303. var defaultShow = new ConstantProperty(true);
  89304. var defaultFill = new ConstantProperty(true);
  89305. var defaultOutline = new ConstantProperty(false);
  89306. var defaultOutlineColor = new ConstantProperty(Color.BLACK);
  89307. var defaultShadows = new ConstantProperty(ShadowMode.DISABLED);
  89308. var defaultDistanceDisplayCondition = new ConstantProperty(new DistanceDisplayCondition());
  89309. var scratchColor = new Color();
  89310. function GeometryOptions(entity) {
  89311. this.id = entity;
  89312. this.vertexFormat = undefined;
  89313. this.length = undefined;
  89314. this.topRadius = undefined;
  89315. this.bottomRadius = undefined;
  89316. this.slices = undefined;
  89317. this.numberOfVerticalLines = undefined;
  89318. }
  89319. /**
  89320. * A {@link GeometryUpdater} for cylinders.
  89321. * Clients do not normally create this class directly, but instead rely on {@link DataSourceDisplay}.
  89322. * @alias CylinderGeometryUpdater
  89323. * @constructor
  89324. *
  89325. * @param {Entity} entity The entity containing the geometry to be visualized.
  89326. * @param {Scene} scene The scene where visualization is taking place.
  89327. */
  89328. function CylinderGeometryUpdater(entity, scene) {
  89329. if (!defined(entity)) {
  89330. throw new DeveloperError('entity is required');
  89331. }
  89332. if (!defined(scene)) {
  89333. throw new DeveloperError('scene is required');
  89334. }
  89335. this._entity = entity;
  89336. this._scene = scene;
  89337. this._entitySubscription = entity.definitionChanged.addEventListener(CylinderGeometryUpdater.prototype._onEntityPropertyChanged, this);
  89338. this._fillEnabled = false;
  89339. this._dynamic = false;
  89340. this._outlineEnabled = false;
  89341. this._geometryChanged = new Event();
  89342. this._showProperty = undefined;
  89343. this._materialProperty = undefined;
  89344. this._hasConstantOutline = true;
  89345. this._showOutlineProperty = undefined;
  89346. this._outlineColorProperty = undefined;
  89347. this._outlineWidth = 1.0;
  89348. this._shadowsProperty = undefined;
  89349. this._distanceDisplayConditionProperty = undefined;
  89350. this._options = new GeometryOptions(entity);
  89351. this._onEntityPropertyChanged(entity, 'cylinder', entity.cylinder, undefined);
  89352. }
  89353. defineProperties(CylinderGeometryUpdater, {
  89354. /**
  89355. * Gets the type of Appearance to use for simple color-based geometry.
  89356. * @memberof CylinderGeometryUpdater
  89357. * @type {Appearance}
  89358. */
  89359. perInstanceColorAppearanceType : {
  89360. value : PerInstanceColorAppearance
  89361. },
  89362. /**
  89363. * Gets the type of Appearance to use for material-based geometry.
  89364. * @memberof CylinderGeometryUpdater
  89365. * @type {Appearance}
  89366. */
  89367. materialAppearanceType : {
  89368. value : MaterialAppearance
  89369. }
  89370. });
  89371. defineProperties(CylinderGeometryUpdater.prototype, {
  89372. /**
  89373. * Gets the entity associated with this geometry.
  89374. * @memberof CylinderGeometryUpdater.prototype
  89375. *
  89376. * @type {Entity}
  89377. * @readonly
  89378. */
  89379. entity : {
  89380. get : function() {
  89381. return this._entity;
  89382. }
  89383. },
  89384. /**
  89385. * Gets a value indicating if the geometry has a fill component.
  89386. * @memberof CylinderGeometryUpdater.prototype
  89387. *
  89388. * @type {Boolean}
  89389. * @readonly
  89390. */
  89391. fillEnabled : {
  89392. get : function() {
  89393. return this._fillEnabled;
  89394. }
  89395. },
  89396. /**
  89397. * Gets a value indicating if fill visibility varies with simulation time.
  89398. * @memberof CylinderGeometryUpdater.prototype
  89399. *
  89400. * @type {Boolean}
  89401. * @readonly
  89402. */
  89403. hasConstantFill : {
  89404. get : function() {
  89405. return !this._fillEnabled ||
  89406. (!defined(this._entity.availability) &&
  89407. Property.isConstant(this._showProperty) &&
  89408. Property.isConstant(this._fillProperty));
  89409. }
  89410. },
  89411. /**
  89412. * Gets the material property used to fill the geometry.
  89413. * @memberof CylinderGeometryUpdater.prototype
  89414. *
  89415. * @type {MaterialProperty}
  89416. * @readonly
  89417. */
  89418. fillMaterialProperty : {
  89419. get : function() {
  89420. return this._materialProperty;
  89421. }
  89422. },
  89423. /**
  89424. * Gets a value indicating if the geometry has an outline component.
  89425. * @memberof CylinderGeometryUpdater.prototype
  89426. *
  89427. * @type {Boolean}
  89428. * @readonly
  89429. */
  89430. outlineEnabled : {
  89431. get : function() {
  89432. return this._outlineEnabled;
  89433. }
  89434. },
  89435. /**
  89436. * Gets a value indicating if outline visibility varies with simulation time.
  89437. * @memberof CylinderGeometryUpdater.prototype
  89438. *
  89439. * @type {Boolean}
  89440. * @readonly
  89441. */
  89442. hasConstantOutline : {
  89443. get : function() {
  89444. return !this._outlineEnabled ||
  89445. (!defined(this._entity.availability) &&
  89446. Property.isConstant(this._showProperty) &&
  89447. Property.isConstant(this._showOutlineProperty));
  89448. }
  89449. },
  89450. /**
  89451. * Gets the {@link Color} property for the geometry outline.
  89452. * @memberof CylinderGeometryUpdater.prototype
  89453. *
  89454. * @type {Property}
  89455. * @readonly
  89456. */
  89457. outlineColorProperty : {
  89458. get : function() {
  89459. return this._outlineColorProperty;
  89460. }
  89461. },
  89462. /**
  89463. * Gets the constant with of the geometry outline, in pixels.
  89464. * This value is only valid if isDynamic is false.
  89465. * @memberof CylinderGeometryUpdater.prototype
  89466. *
  89467. * @type {Number}
  89468. * @readonly
  89469. */
  89470. outlineWidth : {
  89471. get : function() {
  89472. return this._outlineWidth;
  89473. }
  89474. },
  89475. /**
  89476. * Gets the property specifying whether the geometry
  89477. * casts or receives shadows from each light source.
  89478. * @memberof CylinderGeometryUpdater.prototype
  89479. *
  89480. * @type {Property}
  89481. * @readonly
  89482. */
  89483. shadowsProperty : {
  89484. get : function() {
  89485. return this._shadowsProperty;
  89486. }
  89487. },
  89488. /**
  89489. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this geometry will be displayed.
  89490. * @memberof CylinderGeometryUpdater.prototype
  89491. *
  89492. * @type {Property}
  89493. * @readonly
  89494. */
  89495. distanceDisplayConditionProperty : {
  89496. get : function() {
  89497. return this._distanceDisplayConditionProperty;
  89498. }
  89499. },
  89500. /**
  89501. * Gets a value indicating if the geometry is time-varying.
  89502. * If true, all visualization is delegated to the {@link DynamicGeometryUpdater}
  89503. * returned by GeometryUpdater#createDynamicUpdater.
  89504. * @memberof CylinderGeometryUpdater.prototype
  89505. *
  89506. * @type {Boolean}
  89507. * @readonly
  89508. */
  89509. isDynamic : {
  89510. get : function() {
  89511. return this._dynamic;
  89512. }
  89513. },
  89514. /**
  89515. * Gets a value indicating if the geometry is closed.
  89516. * This property is only valid for static geometry.
  89517. * @memberof CylinderGeometryUpdater.prototype
  89518. *
  89519. * @type {Boolean}
  89520. * @readonly
  89521. */
  89522. isClosed : {
  89523. value : true
  89524. },
  89525. /**
  89526. * Gets an event that is raised whenever the public properties
  89527. * of this updater change.
  89528. * @memberof CylinderGeometryUpdater.prototype
  89529. *
  89530. * @type {Boolean}
  89531. * @readonly
  89532. */
  89533. geometryChanged : {
  89534. get : function() {
  89535. return this._geometryChanged;
  89536. }
  89537. }
  89538. });
  89539. /**
  89540. * Checks if the geometry is outlined at the provided time.
  89541. *
  89542. * @param {JulianDate} time The time for which to retrieve visibility.
  89543. * @returns {Boolean} true if geometry is outlined at the provided time, false otherwise.
  89544. */
  89545. CylinderGeometryUpdater.prototype.isOutlineVisible = function(time) {
  89546. var entity = this._entity;
  89547. return this._outlineEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time);
  89548. };
  89549. /**
  89550. * Checks if the geometry is filled at the provided time.
  89551. *
  89552. * @param {JulianDate} time The time for which to retrieve visibility.
  89553. * @returns {Boolean} true if geometry is filled at the provided time, false otherwise.
  89554. */
  89555. CylinderGeometryUpdater.prototype.isFilled = function(time) {
  89556. var entity = this._entity;
  89557. return this._fillEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._fillProperty.getValue(time);
  89558. };
  89559. /**
  89560. * Creates the geometry instance which represents the fill of the geometry.
  89561. *
  89562. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  89563. * @returns {GeometryInstance} The geometry instance representing the filled portion of the geometry.
  89564. *
  89565. * @exception {DeveloperError} This instance does not represent a filled geometry.
  89566. */
  89567. CylinderGeometryUpdater.prototype.createFillGeometryInstance = function(time) {
  89568. if (!defined(time)) {
  89569. throw new DeveloperError('time is required.');
  89570. }
  89571. if (!this._fillEnabled) {
  89572. throw new DeveloperError('This instance does not represent a filled geometry.');
  89573. }
  89574. var entity = this._entity;
  89575. var isAvailable = entity.isAvailable(time);
  89576. var attributes;
  89577. var color;
  89578. var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time));
  89579. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  89580. var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
  89581. if (this._materialProperty instanceof ColorMaterialProperty) {
  89582. var currentColor = Color.WHITE;
  89583. if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) {
  89584. currentColor = this._materialProperty.color.getValue(time);
  89585. }
  89586. color = ColorGeometryInstanceAttribute.fromColor(currentColor);
  89587. attributes = {
  89588. show : show,
  89589. distanceDisplayCondition : distanceDisplayConditionAttribute,
  89590. color : color
  89591. };
  89592. } else {
  89593. attributes = {
  89594. show : show,
  89595. distanceDisplayCondition : distanceDisplayConditionAttribute
  89596. };
  89597. }
  89598. return new GeometryInstance({
  89599. id : entity,
  89600. geometry : new CylinderGeometry(this._options),
  89601. modelMatrix : entity._getModelMatrix(Iso8601.MINIMUM_VALUE),
  89602. attributes : attributes
  89603. });
  89604. };
  89605. /**
  89606. * Creates the geometry instance which represents the outline of the geometry.
  89607. *
  89608. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  89609. * @returns {GeometryInstance} The geometry instance representing the outline portion of the geometry.
  89610. *
  89611. * @exception {DeveloperError} This instance does not represent an outlined geometry.
  89612. */
  89613. CylinderGeometryUpdater.prototype.createOutlineGeometryInstance = function(time) {
  89614. if (!defined(time)) {
  89615. throw new DeveloperError('time is required.');
  89616. }
  89617. if (!this._outlineEnabled) {
  89618. throw new DeveloperError('This instance does not represent an outlined geometry.');
  89619. }
  89620. var entity = this._entity;
  89621. var isAvailable = entity.isAvailable(time);
  89622. var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK);
  89623. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  89624. return new GeometryInstance({
  89625. id : entity,
  89626. geometry : new CylinderOutlineGeometry(this._options),
  89627. modelMatrix : entity._getModelMatrix(Iso8601.MINIMUM_VALUE),
  89628. attributes : {
  89629. show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
  89630. color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
  89631. distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition)
  89632. }
  89633. });
  89634. };
  89635. /**
  89636. * Returns true if this object was destroyed; otherwise, false.
  89637. *
  89638. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  89639. */
  89640. CylinderGeometryUpdater.prototype.isDestroyed = function() {
  89641. return false;
  89642. };
  89643. /**
  89644. * Destroys and resources used by the object. Once an object is destroyed, it should not be used.
  89645. *
  89646. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  89647. */
  89648. CylinderGeometryUpdater.prototype.destroy = function() {
  89649. this._entitySubscription();
  89650. destroyObject(this);
  89651. };
  89652. CylinderGeometryUpdater.prototype._onEntityPropertyChanged = function(entity, propertyName, newValue, oldValue) {
  89653. if (!(propertyName === 'availability' || propertyName === 'position' || propertyName === 'orientation' || propertyName === 'cylinder')) {
  89654. return;
  89655. }
  89656. var cylinder = entity.cylinder;
  89657. if (!defined(cylinder)) {
  89658. if (this._fillEnabled || this._outlineEnabled) {
  89659. this._fillEnabled = false;
  89660. this._outlineEnabled = false;
  89661. this._geometryChanged.raiseEvent(this);
  89662. }
  89663. return;
  89664. }
  89665. var fillProperty = cylinder.fill;
  89666. var fillEnabled = defined(fillProperty) && fillProperty.isConstant ? fillProperty.getValue(Iso8601.MINIMUM_VALUE) : true;
  89667. var outlineProperty = cylinder.outline;
  89668. var outlineEnabled = defined(outlineProperty);
  89669. if (outlineEnabled && outlineProperty.isConstant) {
  89670. outlineEnabled = outlineProperty.getValue(Iso8601.MINIMUM_VALUE);
  89671. }
  89672. if (!fillEnabled && !outlineEnabled) {
  89673. if (this._fillEnabled || this._outlineEnabled) {
  89674. this._fillEnabled = false;
  89675. this._outlineEnabled = false;
  89676. this._geometryChanged.raiseEvent(this);
  89677. }
  89678. return;
  89679. }
  89680. var position = entity.position;
  89681. var length = cylinder.length;
  89682. var topRadius = cylinder.topRadius;
  89683. var bottomRadius = cylinder.bottomRadius;
  89684. var show = cylinder.show;
  89685. if ((defined(show) && show.isConstant && !show.getValue(Iso8601.MINIMUM_VALUE)) || //
  89686. (!defined(position) || !defined(length) || !defined(topRadius) || !defined(bottomRadius))) {
  89687. if (this._fillEnabled || this._outlineEnabled) {
  89688. this._fillEnabled = false;
  89689. this._outlineEnabled = false;
  89690. this._geometryChanged.raiseEvent(this);
  89691. }
  89692. return;
  89693. }
  89694. var material = defaultValue(cylinder.material, defaultMaterial);
  89695. var isColorMaterial = material instanceof ColorMaterialProperty;
  89696. this._materialProperty = material;
  89697. this._fillProperty = defaultValue(fillProperty, defaultFill);
  89698. this._showProperty = defaultValue(show, defaultShow);
  89699. this._showOutlineProperty = defaultValue(cylinder.outline, defaultOutline);
  89700. this._outlineColorProperty = outlineEnabled ? defaultValue(cylinder.outlineColor, defaultOutlineColor) : undefined;
  89701. this._shadowsProperty = defaultValue(cylinder.shadows, defaultShadows);
  89702. this._distanceDisplayConditionProperty = defaultValue(cylinder.distanceDisplayCondition, defaultDistanceDisplayCondition);
  89703. var slices = cylinder.slices;
  89704. var outlineWidth = cylinder.outlineWidth;
  89705. var numberOfVerticalLines = cylinder.numberOfVerticalLines;
  89706. this._fillEnabled = fillEnabled;
  89707. this._outlineEnabled = outlineEnabled;
  89708. if (!position.isConstant || //
  89709. !Property.isConstant(entity.orientation) || //
  89710. !length.isConstant || //
  89711. !topRadius.isConstant || //
  89712. !bottomRadius.isConstant || //
  89713. !Property.isConstant(slices) || //
  89714. !Property.isConstant(outlineWidth) || //
  89715. !Property.isConstant(numberOfVerticalLines)) {
  89716. if (!this._dynamic) {
  89717. this._dynamic = true;
  89718. this._geometryChanged.raiseEvent(this);
  89719. }
  89720. } else {
  89721. var options = this._options;
  89722. options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat;
  89723. options.length = length.getValue(Iso8601.MINIMUM_VALUE);
  89724. options.topRadius = topRadius.getValue(Iso8601.MINIMUM_VALUE);
  89725. options.bottomRadius = bottomRadius.getValue(Iso8601.MINIMUM_VALUE);
  89726. options.slices = defined(slices) ? slices.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  89727. options.numberOfVerticalLines = defined(numberOfVerticalLines) ? numberOfVerticalLines.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  89728. this._outlineWidth = defined(outlineWidth) ? outlineWidth.getValue(Iso8601.MINIMUM_VALUE) : 1.0;
  89729. this._dynamic = false;
  89730. this._geometryChanged.raiseEvent(this);
  89731. }
  89732. };
  89733. /**
  89734. * Creates the dynamic updater to be used when GeometryUpdater#isDynamic is true.
  89735. *
  89736. * @param {PrimitiveCollection} primitives The primitive collection to use.
  89737. * @returns {DynamicGeometryUpdater} The dynamic updater used to update the geometry each frame.
  89738. *
  89739. * @exception {DeveloperError} This instance does not represent dynamic geometry.
  89740. */
  89741. CylinderGeometryUpdater.prototype.createDynamicUpdater = function(primitives) {
  89742. if (!this._dynamic) {
  89743. throw new DeveloperError('This instance does not represent dynamic geometry.');
  89744. }
  89745. if (!defined(primitives)) {
  89746. throw new DeveloperError('primitives is required.');
  89747. }
  89748. return new DynamicGeometryUpdater(primitives, this);
  89749. };
  89750. /**
  89751. * @private
  89752. */
  89753. function DynamicGeometryUpdater(primitives, geometryUpdater) {
  89754. this._primitives = primitives;
  89755. this._primitive = undefined;
  89756. this._outlinePrimitive = undefined;
  89757. this._geometryUpdater = geometryUpdater;
  89758. this._options = new GeometryOptions(geometryUpdater._entity);
  89759. }
  89760. DynamicGeometryUpdater.prototype.update = function(time) {
  89761. if (!defined(time)) {
  89762. throw new DeveloperError('time is required.');
  89763. }
  89764. var primitives = this._primitives;
  89765. primitives.removeAndDestroy(this._primitive);
  89766. primitives.removeAndDestroy(this._outlinePrimitive);
  89767. this._primitive = undefined;
  89768. this._outlinePrimitive = undefined;
  89769. var geometryUpdater = this._geometryUpdater;
  89770. var entity = geometryUpdater._entity;
  89771. var cylinder = entity.cylinder;
  89772. if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(cylinder.show, time, true)) {
  89773. return;
  89774. }
  89775. var options = this._options;
  89776. var modelMatrix = entity._getModelMatrix(time);
  89777. var length = Property.getValueOrUndefined(cylinder.length, time);
  89778. var topRadius = Property.getValueOrUndefined(cylinder.topRadius, time);
  89779. var bottomRadius = Property.getValueOrUndefined(cylinder.bottomRadius, time);
  89780. if (!defined(modelMatrix) || !defined(length) || !defined(topRadius) || !defined(bottomRadius)) {
  89781. return;
  89782. }
  89783. options.length = length;
  89784. options.topRadius = topRadius;
  89785. options.bottomRadius = bottomRadius;
  89786. options.slices = Property.getValueOrUndefined(cylinder.slices, time);
  89787. options.numberOfVerticalLines = Property.getValueOrUndefined(cylinder.numberOfVerticalLines, time);
  89788. var shadows = this._geometryUpdater.shadowsProperty.getValue(time);
  89789. var distanceDisplayConditionProperty = this._geometryUpdater.distanceDisplayConditionProperty;
  89790. var distanceDisplayCondition = distanceDisplayConditionProperty.getValue(time);
  89791. var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
  89792. if (Property.getValueOrDefault(cylinder.fill, time, true)) {
  89793. var material = MaterialProperty.getValue(time, geometryUpdater.fillMaterialProperty, this._material);
  89794. this._material = material;
  89795. var appearance = new MaterialAppearance({
  89796. material : material,
  89797. translucent : material.isTranslucent(),
  89798. closed : true
  89799. });
  89800. options.vertexFormat = appearance.vertexFormat;
  89801. this._primitive = primitives.add(new Primitive({
  89802. geometryInstances : new GeometryInstance({
  89803. id : entity,
  89804. geometry : new CylinderGeometry(options),
  89805. modelMatrix : modelMatrix,
  89806. attributes : {
  89807. distanceDisplayCondition : distanceDisplayConditionAttribute
  89808. }
  89809. }),
  89810. appearance : appearance,
  89811. asynchronous : false,
  89812. shadows : shadows
  89813. }));
  89814. }
  89815. if (Property.getValueOrDefault(cylinder.outline, time, false)) {
  89816. options.vertexFormat = PerInstanceColorAppearance.VERTEX_FORMAT;
  89817. var outlineColor = Property.getValueOrClonedDefault(cylinder.outlineColor, time, Color.BLACK, scratchColor);
  89818. var outlineWidth = Property.getValueOrDefault(cylinder.outlineWidth, time, 1.0);
  89819. var translucent = outlineColor.alpha !== 1.0;
  89820. this._outlinePrimitive = primitives.add(new Primitive({
  89821. geometryInstances : new GeometryInstance({
  89822. id : entity,
  89823. geometry : new CylinderOutlineGeometry(options),
  89824. modelMatrix : modelMatrix,
  89825. attributes : {
  89826. color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
  89827. distanceDisplayCondition : distanceDisplayConditionAttribute
  89828. }
  89829. }),
  89830. appearance : new PerInstanceColorAppearance({
  89831. flat : true,
  89832. translucent : translucent,
  89833. renderState : {
  89834. lineWidth : geometryUpdater._scene.clampLineWidth(outlineWidth)
  89835. }
  89836. }),
  89837. asynchronous : false,
  89838. shadows : shadows
  89839. }));
  89840. }
  89841. };
  89842. DynamicGeometryUpdater.prototype.getBoundingSphere = function(entity, result) {
  89843. return dynamicGeometryGetBoundingSphere(entity, this._primitive, this._outlinePrimitive, result);
  89844. };
  89845. DynamicGeometryUpdater.prototype.isDestroyed = function() {
  89846. return false;
  89847. };
  89848. DynamicGeometryUpdater.prototype.destroy = function() {
  89849. var primitives = this._primitives;
  89850. primitives.removeAndDestroy(this._primitive);
  89851. primitives.removeAndDestroy(this._outlinePrimitive);
  89852. destroyObject(this);
  89853. };
  89854. return CylinderGeometryUpdater;
  89855. });
  89856. /*global define*/
  89857. define('Scene/ColorBlendMode',[
  89858. '../Core/freezeObject',
  89859. '../Core/Math'
  89860. ], function(
  89861. freezeObject,
  89862. CesiumMath) {
  89863. 'use strict';
  89864. /**
  89865. * Defines different modes for blending between a target color and a primitive's source color.
  89866. *
  89867. * HIGHLIGHT multiplies the source color by the target color
  89868. * REPLACE replaces the source color with the target color
  89869. * MIX blends the source color and target color together
  89870. *
  89871. * @exports ColorBlendMode
  89872. *
  89873. * @see Model.colorBlendMode
  89874. */
  89875. var ColorBlendMode = {
  89876. HIGHLIGHT : 0,
  89877. REPLACE : 1,
  89878. MIX : 2
  89879. };
  89880. /**
  89881. * @private
  89882. */
  89883. ColorBlendMode.getColorBlend = function(colorBlendMode, colorBlendAmount) {
  89884. if (colorBlendMode === ColorBlendMode.HIGHLIGHT) {
  89885. return 0.0;
  89886. } else if (colorBlendMode === ColorBlendMode.REPLACE) {
  89887. return 1.0;
  89888. } else if (colorBlendMode === ColorBlendMode.MIX) {
  89889. // The value 0.0 is reserved for highlight, so clamp to just above 0.0.
  89890. return CesiumMath.clamp(colorBlendAmount, CesiumMath.EPSILON4, 1.0);
  89891. }
  89892. };
  89893. return freezeObject(ColorBlendMode);
  89894. });
  89895. /*global define*/
  89896. define('DataSources/DataSourceClock',[
  89897. '../Core/Clock',
  89898. '../Core/defaultValue',
  89899. '../Core/defined',
  89900. '../Core/defineProperties',
  89901. '../Core/DeveloperError',
  89902. '../Core/Event',
  89903. '../Core/JulianDate',
  89904. './createRawPropertyDescriptor'
  89905. ], function(
  89906. Clock,
  89907. defaultValue,
  89908. defined,
  89909. defineProperties,
  89910. DeveloperError,
  89911. Event,
  89912. JulianDate,
  89913. createRawPropertyDescriptor) {
  89914. 'use strict';
  89915. /**
  89916. * Represents desired clock settings for a particular {@link DataSource}. These settings may be applied
  89917. * to the {@link Clock} when the DataSource is loaded.
  89918. *
  89919. * @alias DataSourceClock
  89920. * @constructor
  89921. */
  89922. function DataSourceClock() {
  89923. this._startTime = undefined;
  89924. this._stopTime = undefined;
  89925. this._currentTime = undefined;
  89926. this._clockRange = undefined;
  89927. this._clockStep = undefined;
  89928. this._multiplier = undefined;
  89929. this._definitionChanged = new Event();
  89930. }
  89931. defineProperties(DataSourceClock.prototype, {
  89932. /**
  89933. * Gets the event that is raised whenever a new property is assigned.
  89934. * @memberof DataSourceClock.prototype
  89935. *
  89936. * @type {Event}
  89937. * @readonly
  89938. */
  89939. definitionChanged : {
  89940. get : function() {
  89941. return this._definitionChanged;
  89942. }
  89943. },
  89944. /**
  89945. * Gets or sets the desired start time of the clock.
  89946. * See {@link Clock#startTime}.
  89947. * @memberof DataSourceClock.prototype
  89948. * @type {JulianDate}
  89949. */
  89950. startTime : createRawPropertyDescriptor('startTime'),
  89951. /**
  89952. * Gets or sets the desired stop time of the clock.
  89953. * See {@link Clock#stopTime}.
  89954. * @memberof DataSourceClock.prototype
  89955. * @type {JulianDate}
  89956. */
  89957. stopTime : createRawPropertyDescriptor('stopTime'),
  89958. /**
  89959. * Gets or sets the desired current time when this data source is loaded.
  89960. * See {@link Clock#currentTime}.
  89961. * @memberof DataSourceClock.prototype
  89962. * @type {JulianDate}
  89963. */
  89964. currentTime : createRawPropertyDescriptor('currentTime'),
  89965. /**
  89966. * Gets or sets the desired clock range setting.
  89967. * See {@link Clock#clockRange}.
  89968. * @memberof DataSourceClock.prototype
  89969. * @type {ClockRange}
  89970. */
  89971. clockRange : createRawPropertyDescriptor('clockRange'),
  89972. /**
  89973. * Gets or sets the desired clock step setting.
  89974. * See {@link Clock#clockStep}.
  89975. * @memberof DataSourceClock.prototype
  89976. * @type {ClockStep}
  89977. */
  89978. clockStep : createRawPropertyDescriptor('clockStep'),
  89979. /**
  89980. * Gets or sets the desired clock multiplier.
  89981. * See {@link Clock#multiplier}.
  89982. * @memberof DataSourceClock.prototype
  89983. * @type {Number}
  89984. */
  89985. multiplier : createRawPropertyDescriptor('multiplier')
  89986. });
  89987. /**
  89988. * Duplicates a DataSourceClock instance.
  89989. *
  89990. * @param {DataSourceClock} [result] The object onto which to store the result.
  89991. * @returns {DataSourceClock} The modified result parameter or a new instance if one was not provided.
  89992. */
  89993. DataSourceClock.prototype.clone = function(result) {
  89994. if (!defined(result)) {
  89995. result = new DataSourceClock();
  89996. }
  89997. result.startTime = this.startTime;
  89998. result.stopTime = this.stopTime;
  89999. result.currentTime = this.currentTime;
  90000. result.clockRange = this.clockRange;
  90001. result.clockStep = this.clockStep;
  90002. result.multiplier = this.multiplier;
  90003. return result;
  90004. };
  90005. /**
  90006. * Returns true if this DataSourceClock is equivalent to the other
  90007. *
  90008. * @param {DataSourceClock} other The other DataSourceClock to compare to.
  90009. * @returns {Boolean} <code>true</code> if the DataSourceClocks are equal; otherwise, <code>false</code>.
  90010. */
  90011. DataSourceClock.prototype.equals = function(other) {
  90012. return this === other ||
  90013. defined(other) &&
  90014. JulianDate.equals(this.startTime, other.startTime) &&
  90015. JulianDate.equals(this.stopTime, other.stopTime) &&
  90016. JulianDate.equals(this.currentTime, other.currentTime) &&
  90017. this.clockRange === other.clockRange &&
  90018. this.clockStep === other.clockStep &&
  90019. this.multiplier === other.multiplier;
  90020. };
  90021. /**
  90022. * Assigns each unassigned property on this object to the value
  90023. * of the same property on the provided source object.
  90024. *
  90025. * @param {DataSourceClock} source The object to be merged into this object.
  90026. */
  90027. DataSourceClock.prototype.merge = function(source) {
  90028. if (!defined(source)) {
  90029. throw new DeveloperError('source is required.');
  90030. }
  90031. this.startTime = defaultValue(this.startTime, source.startTime);
  90032. this.stopTime = defaultValue(this.stopTime, source.stopTime);
  90033. this.currentTime = defaultValue(this.currentTime, source.currentTime);
  90034. this.clockRange = defaultValue(this.clockRange, source.clockRange);
  90035. this.clockStep = defaultValue(this.clockStep, source.clockStep);
  90036. this.multiplier = defaultValue(this.multiplier, source.multiplier);
  90037. };
  90038. /**
  90039. * Gets the value of this clock instance as a {@link Clock} object.
  90040. *
  90041. * @returns {Clock} The modified result parameter or a new instance if one was not provided.
  90042. */
  90043. DataSourceClock.prototype.getValue = function(result) {
  90044. if (!defined(result)) {
  90045. result = new Clock();
  90046. }
  90047. result.startTime = defaultValue(this.startTime, result.startTime);
  90048. result.stopTime = defaultValue(this.stopTime, result.stopTime);
  90049. result.currentTime = defaultValue(this.currentTime, result.currentTime);
  90050. result.clockRange = defaultValue(this.clockRange, result.clockRange);
  90051. result.multiplier = defaultValue(this.multiplier, result.multiplier);
  90052. result.clockStep = defaultValue(this.clockStep, result.clockStep);
  90053. return result;
  90054. };
  90055. return DataSourceClock;
  90056. });
  90057. /*global define*/
  90058. define('DataSources/GridMaterialProperty',[
  90059. '../Core/Cartesian2',
  90060. '../Core/Color',
  90061. '../Core/defaultValue',
  90062. '../Core/defined',
  90063. '../Core/defineProperties',
  90064. '../Core/Event',
  90065. './createPropertyDescriptor',
  90066. './Property'
  90067. ], function(
  90068. Cartesian2,
  90069. Color,
  90070. defaultValue,
  90071. defined,
  90072. defineProperties,
  90073. Event,
  90074. createPropertyDescriptor,
  90075. Property) {
  90076. 'use strict';
  90077. var defaultColor = Color.WHITE;
  90078. var defaultCellAlpha = 0.1;
  90079. var defaultLineCount = new Cartesian2(8, 8);
  90080. var defaultLineOffset = new Cartesian2(0, 0);
  90081. var defaultLineThickness = new Cartesian2(1, 1);
  90082. /**
  90083. * A {@link MaterialProperty} that maps to grid {@link Material} uniforms.
  90084. * @alias GridMaterialProperty
  90085. *
  90086. * @param {Object} [options] Object with the following properties:
  90087. * @param {Property} [options.color=Color.WHITE] A Property specifying the grid {@link Color}.
  90088. * @param {Property} [options.cellAlpha=0.1] A numeric Property specifying cell alpha values.
  90089. * @param {Property} [options.lineCount=new Cartesian2(8, 8)] A {@link Cartesian2} Property specifying the number of grid lines along each axis.
  90090. * @param {Property} [options.lineThickness=new Cartesian2(1.0, 1.0)] A {@link Cartesian2} Property specifying the thickness of grid lines along each axis.
  90091. * @param {Property} [options.lineOffset=new Cartesian2(0.0, 0.0)] A {@link Cartesian2} Property specifying starting offset of grid lines along each axis.
  90092. *
  90093. * @constructor
  90094. */
  90095. function GridMaterialProperty(options) {
  90096. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  90097. this._definitionChanged = new Event();
  90098. this._color = undefined;
  90099. this._colorSubscription = undefined;
  90100. this._cellAlpha = undefined;
  90101. this._cellAlphaSubscription = undefined;
  90102. this._lineCount = undefined;
  90103. this._lineCountSubscription = undefined;
  90104. this._lineThickness = undefined;
  90105. this._lineThicknessSubscription = undefined;
  90106. this._lineOffset = undefined;
  90107. this._lineOffsetSubscription = undefined;
  90108. this.color = options.color;
  90109. this.cellAlpha = options.cellAlpha;
  90110. this.lineCount = options.lineCount;
  90111. this.lineThickness = options.lineThickness;
  90112. this.lineOffset = options.lineOffset;
  90113. }
  90114. defineProperties(GridMaterialProperty.prototype, {
  90115. /**
  90116. * Gets a value indicating if this property is constant. A property is considered
  90117. * constant if getValue always returns the same result for the current definition.
  90118. * @memberof GridMaterialProperty.prototype
  90119. *
  90120. * @type {Boolean}
  90121. * @readonly
  90122. */
  90123. isConstant : {
  90124. get : function() {
  90125. return Property.isConstant(this._color) &&
  90126. Property.isConstant(this._cellAlpha) &&
  90127. Property.isConstant(this._lineCount) &&
  90128. Property.isConstant(this._lineThickness) &&
  90129. Property.isConstant(this._lineOffset);
  90130. }
  90131. },
  90132. /**
  90133. * Gets the event that is raised whenever the definition of this property changes.
  90134. * The definition is considered to have changed if a call to getValue would return
  90135. * a different result for the same time.
  90136. * @memberof GridMaterialProperty.prototype
  90137. *
  90138. * @type {Event}
  90139. * @readonly
  90140. */
  90141. definitionChanged : {
  90142. get : function() {
  90143. return this._definitionChanged;
  90144. }
  90145. },
  90146. /**
  90147. * Gets or sets the Property specifying the grid {@link Color}.
  90148. * @memberof GridMaterialProperty.prototype
  90149. * @type {Property}
  90150. * @default Color.WHITE
  90151. */
  90152. color : createPropertyDescriptor('color'),
  90153. /**
  90154. * Gets or sets the numeric Property specifying cell alpha values.
  90155. * @memberof GridMaterialProperty.prototype
  90156. * @type {Property}
  90157. * @default 0.1
  90158. */
  90159. cellAlpha : createPropertyDescriptor('cellAlpha'),
  90160. /**
  90161. * Gets or sets the {@link Cartesian2} Property specifying the number of grid lines along each axis.
  90162. * @memberof GridMaterialProperty.prototype
  90163. * @type {Property}
  90164. * @default new Cartesian2(8.0, 8.0)
  90165. */
  90166. lineCount : createPropertyDescriptor('lineCount'),
  90167. /**
  90168. * Gets or sets the {@link Cartesian2} Property specifying the thickness of grid lines along each axis.
  90169. * @memberof GridMaterialProperty.prototype
  90170. * @type {Property}
  90171. * @default new Cartesian2(1.0, 1.0)
  90172. */
  90173. lineThickness : createPropertyDescriptor('lineThickness'),
  90174. /**
  90175. * Gets or sets the {@link Cartesian2} Property specifying the starting offset of grid lines along each axis.
  90176. * @memberof GridMaterialProperty.prototype
  90177. * @type {Property}
  90178. * @default new Cartesian2(0.0, 0.0)
  90179. */
  90180. lineOffset : createPropertyDescriptor('lineOffset')
  90181. });
  90182. /**
  90183. * Gets the {@link Material} type at the provided time.
  90184. *
  90185. * @param {JulianDate} time The time for which to retrieve the type.
  90186. * @returns {String} The type of material.
  90187. */
  90188. GridMaterialProperty.prototype.getType = function(time) {
  90189. return 'Grid';
  90190. };
  90191. /**
  90192. * Gets the value of the property at the provided time.
  90193. *
  90194. * @param {JulianDate} time The time for which to retrieve the value.
  90195. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  90196. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  90197. */
  90198. GridMaterialProperty.prototype.getValue = function(time, result) {
  90199. if (!defined(result)) {
  90200. result = {};
  90201. }
  90202. result.color = Property.getValueOrClonedDefault(this._color, time, defaultColor, result.color);
  90203. result.cellAlpha = Property.getValueOrDefault(this._cellAlpha, time, defaultCellAlpha);
  90204. result.lineCount = Property.getValueOrClonedDefault(this._lineCount, time, defaultLineCount, result.lineCount);
  90205. result.lineThickness = Property.getValueOrClonedDefault(this._lineThickness, time, defaultLineThickness, result.lineThickness);
  90206. result.lineOffset = Property.getValueOrClonedDefault(this._lineOffset, time, defaultLineOffset, result.lineOffset);
  90207. return result;
  90208. };
  90209. /**
  90210. * Compares this property to the provided property and returns
  90211. * <code>true</code> if they are equal, <code>false</code> otherwise.
  90212. *
  90213. * @param {Property} [other] The other property.
  90214. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  90215. */
  90216. GridMaterialProperty.prototype.equals = function(other) {
  90217. return this === other || //
  90218. (other instanceof GridMaterialProperty && //
  90219. Property.equals(this._color, other._color) && //
  90220. Property.equals(this._cellAlpha, other._cellAlpha) && //
  90221. Property.equals(this._lineCount, other._lineCount) && //
  90222. Property.equals(this._lineThickness, other._lineThickness) && //
  90223. Property.equals(this._lineOffset, other._lineOffset));
  90224. };
  90225. return GridMaterialProperty;
  90226. });
  90227. /*global define*/
  90228. define('DataSources/PolylineArrowMaterialProperty',[
  90229. '../Core/Color',
  90230. '../Core/defined',
  90231. '../Core/defineProperties',
  90232. '../Core/Event',
  90233. './createPropertyDescriptor',
  90234. './Property'
  90235. ], function(
  90236. Color,
  90237. defined,
  90238. defineProperties,
  90239. Event,
  90240. createPropertyDescriptor,
  90241. Property) {
  90242. 'use strict';
  90243. /**
  90244. * A {@link MaterialProperty} that maps to PolylineArrow {@link Material} uniforms.
  90245. *
  90246. * @param {Property} [color=Color.WHITE] The {@link Color} Property to be used.
  90247. *
  90248. * @alias PolylineArrowMaterialProperty
  90249. * @constructor
  90250. */
  90251. function PolylineArrowMaterialProperty(color) {
  90252. this._definitionChanged = new Event();
  90253. this._color = undefined;
  90254. this._colorSubscription = undefined;
  90255. this.color = color;
  90256. }
  90257. defineProperties(PolylineArrowMaterialProperty.prototype, {
  90258. /**
  90259. * Gets a value indicating if this property is constant. A property is considered
  90260. * constant if getValue always returns the same result for the current definition.
  90261. * @memberof PolylineArrowMaterialProperty.prototype
  90262. *
  90263. * @type {Boolean}
  90264. * @readonly
  90265. */
  90266. isConstant : {
  90267. get : function() {
  90268. return Property.isConstant(this._color);
  90269. }
  90270. },
  90271. /**
  90272. * Gets the event that is raised whenever the definition of this property changes.
  90273. * The definition is considered to have changed if a call to getValue would return
  90274. * a different result for the same time.
  90275. * @memberof PolylineArrowMaterialProperty.prototype
  90276. *
  90277. * @type {Event}
  90278. * @readonly
  90279. */
  90280. definitionChanged : {
  90281. get : function() {
  90282. return this._definitionChanged;
  90283. }
  90284. },
  90285. /**
  90286. * Gets or sets the {@link Color} {@link Property}.
  90287. * @memberof PolylineArrowMaterialProperty.prototype
  90288. * @type {Property}
  90289. * @default Color.WHITE
  90290. */
  90291. color : createPropertyDescriptor('color')
  90292. });
  90293. /**
  90294. * Gets the {@link Material} type at the provided time.
  90295. *
  90296. * @param {JulianDate} time The time for which to retrieve the type.
  90297. * @returns {String} The type of material.
  90298. */
  90299. PolylineArrowMaterialProperty.prototype.getType = function(time) {
  90300. return 'PolylineArrow';
  90301. };
  90302. /**
  90303. * Gets the value of the property at the provided time.
  90304. *
  90305. * @param {JulianDate} time The time for which to retrieve the value.
  90306. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  90307. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  90308. */
  90309. PolylineArrowMaterialProperty.prototype.getValue = function(time, result) {
  90310. if (!defined(result)) {
  90311. result = {};
  90312. }
  90313. result.color = Property.getValueOrClonedDefault(this._color, time, Color.WHITE, result.color);
  90314. return result;
  90315. };
  90316. /**
  90317. * Compares this property to the provided property and returns
  90318. * <code>true</code> if they are equal, <code>false</code> otherwise.
  90319. *
  90320. * @param {Property} [other] The other property.
  90321. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  90322. */
  90323. PolylineArrowMaterialProperty.prototype.equals = function(other) {
  90324. return this === other || //
  90325. (other instanceof PolylineArrowMaterialProperty && //
  90326. Property.equals(this._color, other._color));
  90327. };
  90328. return PolylineArrowMaterialProperty;
  90329. });
  90330. /*global define*/
  90331. define('DataSources/PolylineGlowMaterialProperty',[
  90332. '../Core/Color',
  90333. '../Core/defaultValue',
  90334. '../Core/defined',
  90335. '../Core/defineProperties',
  90336. '../Core/Event',
  90337. './createPropertyDescriptor',
  90338. './Property'
  90339. ], function(
  90340. Color,
  90341. defaultValue,
  90342. defined,
  90343. defineProperties,
  90344. Event,
  90345. createPropertyDescriptor,
  90346. Property) {
  90347. 'use strict';
  90348. var defaultColor = Color.WHITE;
  90349. var defaultGlowPower = 0.25;
  90350. /**
  90351. * A {@link MaterialProperty} that maps to polyline glow {@link Material} uniforms.
  90352. * @alias PolylineGlowMaterialProperty
  90353. * @constructor
  90354. *
  90355. * @param {Object} [options] Object with the following properties:
  90356. * @param {Property} [options.color=Color.WHITE] A Property specifying the {@link Color} of the line.
  90357. * @param {Property} [options.glowPower=0.25] A numeric Property specifying the strength of the glow, as a percentage of the total line width.
  90358. */
  90359. function PolylineGlowMaterialProperty(options) {
  90360. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  90361. this._definitionChanged = new Event();
  90362. this._color = undefined;
  90363. this._colorSubscription = undefined;
  90364. this._glowPower = undefined;
  90365. this._glowPowerSubscription = undefined;
  90366. this.color = options.color;
  90367. this.glowPower = options.glowPower;
  90368. }
  90369. defineProperties(PolylineGlowMaterialProperty.prototype, {
  90370. /**
  90371. * Gets a value indicating if this property is constant. A property is considered
  90372. * constant if getValue always returns the same result for the current definition.
  90373. * @memberof PolylineGlowMaterialProperty.prototype
  90374. * @type {Boolean}
  90375. * @readonly
  90376. */
  90377. isConstant : {
  90378. get : function() {
  90379. return Property.isConstant(this._color) && Property.isConstant(this._glow);
  90380. }
  90381. },
  90382. /**
  90383. * Gets the event that is raised whenever the definition of this property changes.
  90384. * The definition is considered to have changed if a call to getValue would return
  90385. * a different result for the same time.
  90386. * @memberof PolylineGlowMaterialProperty.prototype
  90387. * @type {Event}
  90388. * @readonly
  90389. */
  90390. definitionChanged : {
  90391. get : function() {
  90392. return this._definitionChanged;
  90393. }
  90394. },
  90395. /**
  90396. * Gets or sets the Property specifying the {@link Color} of the line.
  90397. * @memberof PolylineGlowMaterialProperty.prototype
  90398. * @type {Property}
  90399. */
  90400. color : createPropertyDescriptor('color'),
  90401. /**
  90402. * Gets or sets the numeric Property specifying the strength of the glow, as a percentage of the total line width (less than 1.0).
  90403. * @memberof PolylineGlowMaterialProperty.prototype
  90404. * @type {Property}
  90405. */
  90406. glowPower : createPropertyDescriptor('glowPower')
  90407. });
  90408. /**
  90409. * Gets the {@link Material} type at the provided time.
  90410. *
  90411. * @param {JulianDate} time The time for which to retrieve the type.
  90412. * @returns {String} The type of material.
  90413. */
  90414. PolylineGlowMaterialProperty.prototype.getType = function(time) {
  90415. return 'PolylineGlow';
  90416. };
  90417. /**
  90418. * Gets the value of the property at the provided time.
  90419. *
  90420. * @param {JulianDate} time The time for which to retrieve the value.
  90421. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  90422. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  90423. */
  90424. PolylineGlowMaterialProperty.prototype.getValue = function(time, result) {
  90425. if (!defined(result)) {
  90426. result = {};
  90427. }
  90428. result.color = Property.getValueOrClonedDefault(this._color, time, defaultColor, result.color);
  90429. result.glowPower = Property.getValueOrDefault(this._glowPower, time, defaultGlowPower, result.glowPower);
  90430. return result;
  90431. };
  90432. /**
  90433. * Compares this property to the provided property and returns
  90434. * <code>true</code> if they are equal, <code>false</code> otherwise.
  90435. *
  90436. * @param {Property} [other] The other property.
  90437. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  90438. */
  90439. PolylineGlowMaterialProperty.prototype.equals = function(other) {
  90440. return this === other || //
  90441. (other instanceof PolylineGlowMaterialProperty && //
  90442. Property.equals(this._color, other._color) &&
  90443. Property.equals(this._glowPower, other._glowPower));
  90444. };
  90445. return PolylineGlowMaterialProperty;
  90446. });
  90447. /*global define*/
  90448. define('DataSources/PolylineOutlineMaterialProperty',[
  90449. '../Core/Color',
  90450. '../Core/defaultValue',
  90451. '../Core/defined',
  90452. '../Core/defineProperties',
  90453. '../Core/Event',
  90454. './createPropertyDescriptor',
  90455. './Property'
  90456. ], function(
  90457. Color,
  90458. defaultValue,
  90459. defined,
  90460. defineProperties,
  90461. Event,
  90462. createPropertyDescriptor,
  90463. Property) {
  90464. 'use strict';
  90465. var defaultColor = Color.WHITE;
  90466. var defaultOutlineColor = Color.BLACK;
  90467. var defaultOutlineWidth = 1.0;
  90468. /**
  90469. * A {@link MaterialProperty} that maps to polyline outline {@link Material} uniforms.
  90470. * @alias PolylineOutlineMaterialProperty
  90471. * @constructor
  90472. *
  90473. * @param {Object} [options] Object with the following properties:
  90474. * @param {Property} [options.color=Color.WHITE] A Property specifying the {@link Color} of the line.
  90475. * @param {Property} [options.outlineColor=Color.BLACK] A Property specifying the {@link Color} of the outline.
  90476. * @param {Property} [options.outlineWidth=1.0] A numeric Property specifying the width of the outline, in pixels.
  90477. */
  90478. function PolylineOutlineMaterialProperty(options) {
  90479. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  90480. this._definitionChanged = new Event();
  90481. this._color = undefined;
  90482. this._colorSubscription = undefined;
  90483. this._outlineColor = undefined;
  90484. this._outlineColorSubscription = undefined;
  90485. this._outlineWidth = undefined;
  90486. this._outlineWidthSubscription = undefined;
  90487. this.color = options.color;
  90488. this.outlineColor = options.outlineColor;
  90489. this.outlineWidth = options.outlineWidth;
  90490. }
  90491. defineProperties(PolylineOutlineMaterialProperty.prototype, {
  90492. /**
  90493. * Gets a value indicating if this property is constant. A property is considered
  90494. * constant if getValue always returns the same result for the current definition.
  90495. * @memberof PolylineOutlineMaterialProperty.prototype
  90496. *
  90497. * @type {Boolean}
  90498. * @readonly
  90499. */
  90500. isConstant : {
  90501. get : function() {
  90502. return Property.isConstant(this._color) && Property.isConstant(this._outlineColor) && Property.isConstant(this._outlineWidth);
  90503. }
  90504. },
  90505. /**
  90506. * Gets the event that is raised whenever the definition of this property changes.
  90507. * The definition is considered to have changed if a call to getValue would return
  90508. * a different result for the same time.
  90509. * @memberof PolylineOutlineMaterialProperty.prototype
  90510. *
  90511. * @type {Event}
  90512. * @readonly
  90513. */
  90514. definitionChanged : {
  90515. get : function() {
  90516. return this._definitionChanged;
  90517. }
  90518. },
  90519. /**
  90520. * Gets or sets the Property specifying the {@link Color} of the line.
  90521. * @memberof PolylineOutlineMaterialProperty.prototype
  90522. * @type {Property}
  90523. * @default Color.WHITE
  90524. */
  90525. color : createPropertyDescriptor('color'),
  90526. /**
  90527. * Gets or sets the Property specifying the {@link Color} of the outline.
  90528. * @memberof PolylineOutlineMaterialProperty.prototype
  90529. * @type {Property}
  90530. * @default Color.BLACK
  90531. */
  90532. outlineColor : createPropertyDescriptor('outlineColor'),
  90533. /**
  90534. * Gets or sets the numeric Property specifying the width of the outline.
  90535. * @memberof PolylineOutlineMaterialProperty.prototype
  90536. * @type {Property}
  90537. * @default 1.0
  90538. */
  90539. outlineWidth : createPropertyDescriptor('outlineWidth')
  90540. });
  90541. /**
  90542. * Gets the {@link Material} type at the provided time.
  90543. *
  90544. * @param {JulianDate} time The time for which to retrieve the type.
  90545. * @returns {String} The type of material.
  90546. */
  90547. PolylineOutlineMaterialProperty.prototype.getType = function(time) {
  90548. return 'PolylineOutline';
  90549. };
  90550. /**
  90551. * Gets the value of the property at the provided time.
  90552. *
  90553. * @param {JulianDate} time The time for which to retrieve the value.
  90554. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  90555. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  90556. */
  90557. PolylineOutlineMaterialProperty.prototype.getValue = function(time, result) {
  90558. if (!defined(result)) {
  90559. result = {};
  90560. }
  90561. result.color = Property.getValueOrClonedDefault(this._color, time, defaultColor, result.color);
  90562. result.outlineColor = Property.getValueOrClonedDefault(this._outlineColor, time, defaultOutlineColor, result.outlineColor);
  90563. result.outlineWidth = Property.getValueOrDefault(this._outlineWidth, time, defaultOutlineWidth);
  90564. return result;
  90565. };
  90566. /**
  90567. * Compares this property to the provided property and returns
  90568. * <code>true</code> if they are equal, <code>false</code> otherwise.
  90569. *
  90570. * @param {Property} [other] The other property.
  90571. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  90572. */
  90573. PolylineOutlineMaterialProperty.prototype.equals = function(other) {
  90574. return this === other || //
  90575. (other instanceof PolylineOutlineMaterialProperty && //
  90576. Property.equals(this._color, other._color) && //
  90577. Property.equals(this._outlineColor, other._outlineColor) && //
  90578. Property.equals(this._outlineWidth, other._outlineWidth));
  90579. };
  90580. return PolylineOutlineMaterialProperty;
  90581. });
  90582. /*global define*/
  90583. define('DataSources/PositionPropertyArray',[
  90584. '../Core/defaultValue',
  90585. '../Core/defined',
  90586. '../Core/defineProperties',
  90587. '../Core/DeveloperError',
  90588. '../Core/Event',
  90589. '../Core/EventHelper',
  90590. '../Core/ReferenceFrame',
  90591. './Property'
  90592. ], function(
  90593. defaultValue,
  90594. defined,
  90595. defineProperties,
  90596. DeveloperError,
  90597. Event,
  90598. EventHelper,
  90599. ReferenceFrame,
  90600. Property) {
  90601. 'use strict';
  90602. /**
  90603. * A {@link PositionProperty} whose value is an array whose items are the computed value
  90604. * of other PositionProperty instances.
  90605. *
  90606. * @alias PositionPropertyArray
  90607. * @constructor
  90608. *
  90609. * @param {Property[]} [value] An array of Property instances.
  90610. * @param {ReferenceFrame} [referenceFrame=ReferenceFrame.FIXED] The reference frame in which the position is defined.
  90611. */
  90612. function PositionPropertyArray(value, referenceFrame) {
  90613. this._value = undefined;
  90614. this._definitionChanged = new Event();
  90615. this._eventHelper = new EventHelper();
  90616. this._referenceFrame = defaultValue(referenceFrame, ReferenceFrame.FIXED);
  90617. this.setValue(value);
  90618. }
  90619. defineProperties(PositionPropertyArray.prototype, {
  90620. /**
  90621. * Gets a value indicating if this property is constant. This property
  90622. * is considered constant if all property items in the array are constant.
  90623. * @memberof PositionPropertyArray.prototype
  90624. *
  90625. * @type {Boolean}
  90626. * @readonly
  90627. */
  90628. isConstant : {
  90629. get : function() {
  90630. var value = this._value;
  90631. if (!defined(value)) {
  90632. return true;
  90633. }
  90634. var length = value.length;
  90635. for (var i = 0; i < length; i++) {
  90636. if (!Property.isConstant(value[i])) {
  90637. return false;
  90638. }
  90639. }
  90640. return true;
  90641. }
  90642. },
  90643. /**
  90644. * Gets the event that is raised whenever the definition of this property changes.
  90645. * The definition is changed whenever setValue is called with data different
  90646. * than the current value or one of the properties in the array also changes.
  90647. * @memberof PositionPropertyArray.prototype
  90648. *
  90649. * @type {Event}
  90650. * @readonly
  90651. */
  90652. definitionChanged : {
  90653. get : function() {
  90654. return this._definitionChanged;
  90655. }
  90656. },
  90657. /**
  90658. * Gets the reference frame in which the position is defined.
  90659. * @memberof PositionPropertyArray.prototype
  90660. * @type {ReferenceFrame}
  90661. * @default ReferenceFrame.FIXED;
  90662. */
  90663. referenceFrame : {
  90664. get : function() {
  90665. return this._referenceFrame;
  90666. }
  90667. }
  90668. });
  90669. /**
  90670. * Gets the value of the property.
  90671. *
  90672. * @param {JulianDate} [time] The time for which to retrieve the value. This parameter is unused since the value does not change with respect to time.
  90673. * @param {Cartesian3[]} [result] The object to store the value into, if omitted, a new instance is created and returned.
  90674. * @returns {Cartesian3[]} The modified result parameter or a new instance if the result parameter was not supplied.
  90675. */
  90676. PositionPropertyArray.prototype.getValue = function(time, result) {
  90677. return this.getValueInReferenceFrame(time, ReferenceFrame.FIXED, result);
  90678. };
  90679. /**
  90680. * Gets the value of the property at the provided time and in the provided reference frame.
  90681. *
  90682. * @param {JulianDate} time The time for which to retrieve the value.
  90683. * @param {ReferenceFrame} referenceFrame The desired referenceFrame of the result.
  90684. * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
  90685. * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
  90686. */
  90687. PositionPropertyArray.prototype.getValueInReferenceFrame = function(time, referenceFrame, result) {
  90688. if (!defined(time)) {
  90689. throw new DeveloperError('time is required.');
  90690. }
  90691. if (!defined(referenceFrame)) {
  90692. throw new DeveloperError('referenceFrame is required.');
  90693. }
  90694. var value = this._value;
  90695. if (!defined(value)) {
  90696. return undefined;
  90697. }
  90698. var length = value.length;
  90699. if (!defined(result)) {
  90700. result = new Array(length);
  90701. }
  90702. var i = 0;
  90703. var x = 0;
  90704. while (i < length) {
  90705. var property = value[i];
  90706. var itemValue = property.getValueInReferenceFrame(time, referenceFrame, result[i]);
  90707. if (defined(itemValue)) {
  90708. result[x] = itemValue;
  90709. x++;
  90710. }
  90711. i++;
  90712. }
  90713. result.length = x;
  90714. return result;
  90715. };
  90716. /**
  90717. * Sets the value of the property.
  90718. *
  90719. * @param {Property[]} value An array of Property instances.
  90720. */
  90721. PositionPropertyArray.prototype.setValue = function(value) {
  90722. var eventHelper = this._eventHelper;
  90723. eventHelper.removeAll();
  90724. if (defined(value)) {
  90725. this._value = value.slice();
  90726. var length = value.length;
  90727. for (var i = 0; i < length; i++) {
  90728. var property = value[i];
  90729. if (defined(property)) {
  90730. eventHelper.add(property.definitionChanged, PositionPropertyArray.prototype._raiseDefinitionChanged, this);
  90731. }
  90732. }
  90733. } else {
  90734. this._value = undefined;
  90735. }
  90736. this._definitionChanged.raiseEvent(this);
  90737. };
  90738. /**
  90739. * Compares this property to the provided property and returns
  90740. * <code>true</code> if they are equal, <code>false</code> otherwise.
  90741. *
  90742. * @param {Property} [other] The other property.
  90743. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  90744. */
  90745. PositionPropertyArray.prototype.equals = function(other) {
  90746. return this === other || //
  90747. (other instanceof PositionPropertyArray && //
  90748. this._referenceFrame === other._referenceFrame && //
  90749. Property.arrayEquals(this._value, other._value));
  90750. };
  90751. PositionPropertyArray.prototype._raiseDefinitionChanged = function() {
  90752. this._definitionChanged.raiseEvent(this);
  90753. };
  90754. return PositionPropertyArray;
  90755. });
  90756. /*global define*/
  90757. define('DataSources/PropertyArray',[
  90758. '../Core/defined',
  90759. '../Core/defineProperties',
  90760. '../Core/DeveloperError',
  90761. '../Core/Event',
  90762. '../Core/EventHelper',
  90763. './Property'
  90764. ], function(
  90765. defined,
  90766. defineProperties,
  90767. DeveloperError,
  90768. Event,
  90769. EventHelper,
  90770. Property) {
  90771. 'use strict';
  90772. /**
  90773. * A {@link Property} whose value is an array whose items are the computed value
  90774. * of other property instances.
  90775. *
  90776. * @alias PropertyArray
  90777. * @constructor
  90778. *
  90779. * @param {Property[]} [value] An array of Property instances.
  90780. */
  90781. function PropertyArray(value) {
  90782. this._value = undefined;
  90783. this._definitionChanged = new Event();
  90784. this._eventHelper = new EventHelper();
  90785. this.setValue(value);
  90786. }
  90787. defineProperties(PropertyArray.prototype, {
  90788. /**
  90789. * Gets a value indicating if this property is constant. This property
  90790. * is considered constant if all property items in the array are constant.
  90791. * @memberof PropertyArray.prototype
  90792. *
  90793. * @type {Boolean}
  90794. * @readonly
  90795. */
  90796. isConstant : {
  90797. get : function() {
  90798. var value = this._value;
  90799. if (!defined(value)) {
  90800. return true;
  90801. }
  90802. var length = value.length;
  90803. for (var i = 0; i < length; i++) {
  90804. if (!Property.isConstant(value[i])) {
  90805. return false;
  90806. }
  90807. }
  90808. return true;
  90809. }
  90810. },
  90811. /**
  90812. * Gets the event that is raised whenever the definition of this property changes.
  90813. * The definition is changed whenever setValue is called with data different
  90814. * than the current value or one of the properties in the array also changes.
  90815. * @memberof PropertyArray.prototype
  90816. *
  90817. * @type {Event}
  90818. * @readonly
  90819. */
  90820. definitionChanged : {
  90821. get : function() {
  90822. return this._definitionChanged;
  90823. }
  90824. }
  90825. });
  90826. /**
  90827. * Gets the value of the property.
  90828. *
  90829. * @param {JulianDate} time The time for which to retrieve the value.
  90830. * @param {Object[]} [result] The object to store the value into, if omitted, a new instance is created and returned.
  90831. * @returns {Object[]} The modified result parameter, which is an array of values produced by evaluating each of the contained properties at the given time or a new instance if the result parameter was not supplied.
  90832. */
  90833. PropertyArray.prototype.getValue = function(time, result) {
  90834. if (!defined(time)) {
  90835. throw new DeveloperError('time is required.');
  90836. }
  90837. var value = this._value;
  90838. if (!defined(value)) {
  90839. return undefined;
  90840. }
  90841. var length = value.length;
  90842. if (!defined(result)) {
  90843. result = new Array(length);
  90844. }
  90845. var i = 0;
  90846. var x = 0;
  90847. while (i < length) {
  90848. var property = this._value[i];
  90849. var itemValue = property.getValue(time, result[i]);
  90850. if (defined(itemValue)) {
  90851. result[x] = itemValue;
  90852. x++;
  90853. }
  90854. i++;
  90855. }
  90856. result.length = x;
  90857. return result;
  90858. };
  90859. /**
  90860. * Sets the value of the property.
  90861. *
  90862. * @param {Property[]} value An array of Property instances.
  90863. */
  90864. PropertyArray.prototype.setValue = function(value) {
  90865. var eventHelper = this._eventHelper;
  90866. eventHelper.removeAll();
  90867. if (defined(value)) {
  90868. this._value = value.slice();
  90869. var length = value.length;
  90870. for (var i = 0; i < length; i++) {
  90871. var property = value[i];
  90872. if (defined(property)) {
  90873. eventHelper.add(property.definitionChanged, PropertyArray.prototype._raiseDefinitionChanged, this);
  90874. }
  90875. }
  90876. } else {
  90877. this._value = undefined;
  90878. }
  90879. this._definitionChanged.raiseEvent(this);
  90880. };
  90881. /**
  90882. * Compares this property to the provided property and returns
  90883. * <code>true</code> if they are equal, <code>false</code> otherwise.
  90884. *
  90885. * @param {Property} [other] The other property.
  90886. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  90887. */
  90888. PropertyArray.prototype.equals = function(other) {
  90889. return this === other || //
  90890. (other instanceof PropertyArray && //
  90891. Property.arrayEquals(this._value, other._value));
  90892. };
  90893. PropertyArray.prototype._raiseDefinitionChanged = function() {
  90894. this._definitionChanged.raiseEvent(this);
  90895. };
  90896. return PropertyArray;
  90897. });
  90898. /*global define*/
  90899. define('DataSources/ReferenceProperty',[
  90900. '../Core/defined',
  90901. '../Core/defineProperties',
  90902. '../Core/DeveloperError',
  90903. '../Core/Event',
  90904. '../Core/RuntimeError',
  90905. './Property'
  90906. ], function(
  90907. defined,
  90908. defineProperties,
  90909. DeveloperError,
  90910. Event,
  90911. RuntimeError,
  90912. Property) {
  90913. 'use strict';
  90914. function resolveEntity(that) {
  90915. var entityIsResolved = true;
  90916. if (that._resolveEntity) {
  90917. var targetEntity = that._targetCollection.getById(that._targetId);
  90918. if (defined(targetEntity)) {
  90919. targetEntity.definitionChanged.addEventListener(ReferenceProperty.prototype._onTargetEntityDefinitionChanged, that);
  90920. that._targetEntity = targetEntity;
  90921. that._resolveEntity = false;
  90922. } else {
  90923. //The property has become detached. It has a valid value but is not currently resolved to an entity in the collection
  90924. targetEntity = that._targetEntity;
  90925. entityIsResolved = false;
  90926. }
  90927. if (!defined(targetEntity)) {
  90928. throw new RuntimeError('target entity "' + that._targetId + '" could not be resolved.');
  90929. }
  90930. }
  90931. return entityIsResolved;
  90932. }
  90933. function resolve(that) {
  90934. var targetProperty = that._targetProperty;
  90935. if (that._resolveProperty) {
  90936. var entityIsResolved = resolveEntity(that);
  90937. var names = that._targetPropertyNames;
  90938. targetProperty = that._targetEntity;
  90939. var length = names.length;
  90940. for (var i = 0; i < length && defined(targetProperty); i++) {
  90941. targetProperty = targetProperty[names[i]];
  90942. }
  90943. if (defined(targetProperty)) {
  90944. that._targetProperty = targetProperty;
  90945. that._resolveProperty = !entityIsResolved;
  90946. } else if (!defined(that._targetProperty)) {
  90947. throw new RuntimeError('targetProperty "' + that._targetId + '.' + names.join('.') + '" could not be resolved.');
  90948. }
  90949. }
  90950. return targetProperty;
  90951. }
  90952. /**
  90953. * A {@link Property} which transparently links to another property on a provided object.
  90954. *
  90955. * @alias ReferenceProperty
  90956. * @constructor
  90957. *
  90958. * @param {EntityCollection} targetCollection The entity collection which will be used to resolve the reference.
  90959. * @param {String} targetId The id of the entity which is being referenced.
  90960. * @param {String[]} targetPropertyNames The names of the property on the target entity which we will use.
  90961. *
  90962. * @example
  90963. * var collection = new Cesium.EntityCollection();
  90964. *
  90965. * //Create a new entity and assign a billboard scale.
  90966. * var object1 = new Cesium.Entity({id:'object1'});
  90967. * object1.billboard = new Cesium.BillboardGraphics();
  90968. * object1.billboard.scale = new Cesium.ConstantProperty(2.0);
  90969. * collection.add(object1);
  90970. *
  90971. * //Create a second entity and reference the scale from the first one.
  90972. * var object2 = new Cesium.Entity({id:'object2'});
  90973. * object2.model = new Cesium.ModelGraphics();
  90974. * object2.model.scale = new Cesium.ReferenceProperty(collection, 'object1', ['billboard', 'scale']);
  90975. * collection.add(object2);
  90976. *
  90977. * //Create a third object, but use the fromString helper function.
  90978. * var object3 = new Cesium.Entity({id:'object3'});
  90979. * object3.billboard = new Cesium.BillboardGraphics();
  90980. * object3.billboard.scale = Cesium.ReferenceProperty.fromString(collection, 'object1#billboard.scale');
  90981. * collection.add(object3);
  90982. *
  90983. * //You can refer to an entity with a # or . in id and property names by escaping them.
  90984. * var object4 = new Cesium.Entity({id:'#object.4'});
  90985. * object4.billboard = new Cesium.BillboardGraphics();
  90986. * object4.billboard.scale = new Cesium.ConstantProperty(2.0);
  90987. * collection.add(object4);
  90988. *
  90989. * var object5 = new Cesium.Entity({id:'object5'});
  90990. * object5.billboard = new Cesium.BillboardGraphics();
  90991. * object5.billboard.scale = Cesium.ReferenceProperty.fromString(collection, '\\#object\\.4#billboard.scale');
  90992. * collection.add(object5);
  90993. */
  90994. function ReferenceProperty(targetCollection, targetId, targetPropertyNames) {
  90995. if (!defined(targetCollection)) {
  90996. throw new DeveloperError('targetCollection is required.');
  90997. }
  90998. if (!defined(targetId) || targetId === '') {
  90999. throw new DeveloperError('targetId is required.');
  91000. }
  91001. if (!defined(targetPropertyNames) || targetPropertyNames.length === 0) {
  91002. throw new DeveloperError('targetPropertyNames is required.');
  91003. }
  91004. for (var i = 0; i < targetPropertyNames.length; i++) {
  91005. var item = targetPropertyNames[i];
  91006. if (!defined(item) || item === '') {
  91007. throw new DeveloperError('reference contains invalid properties.');
  91008. }
  91009. }
  91010. this._targetCollection = targetCollection;
  91011. this._targetId = targetId;
  91012. this._targetPropertyNames = targetPropertyNames;
  91013. this._targetProperty = undefined;
  91014. this._targetEntity = undefined;
  91015. this._definitionChanged = new Event();
  91016. this._resolveEntity = true;
  91017. this._resolveProperty = true;
  91018. targetCollection.collectionChanged.addEventListener(ReferenceProperty.prototype._onCollectionChanged, this);
  91019. }
  91020. defineProperties(ReferenceProperty.prototype, {
  91021. /**
  91022. * Gets a value indicating if this property is constant.
  91023. * @memberof ReferenceProperty.prototype
  91024. * @type {Boolean}
  91025. * @readonly
  91026. */
  91027. isConstant : {
  91028. get : function() {
  91029. return Property.isConstant(resolve(this));
  91030. }
  91031. },
  91032. /**
  91033. * Gets the event that is raised whenever the definition of this property changes.
  91034. * The definition is changed whenever the referenced property's definition is changed.
  91035. * @memberof ReferenceProperty.prototype
  91036. * @type {Event}
  91037. * @readonly
  91038. */
  91039. definitionChanged : {
  91040. get : function() {
  91041. return this._definitionChanged;
  91042. }
  91043. },
  91044. /**
  91045. * Gets the reference frame that the position is defined in.
  91046. * This property is only valid if the referenced property is a {@link PositionProperty}.
  91047. * @memberof ReferenceProperty.prototype
  91048. * @type {ReferenceFrame}
  91049. * @readonly
  91050. */
  91051. referenceFrame : {
  91052. get : function() {
  91053. return resolve(this).referenceFrame;
  91054. }
  91055. },
  91056. /**
  91057. * Gets the id of the entity being referenced.
  91058. * @memberof ReferenceProperty.prototype
  91059. * @type {String}
  91060. * @readonly
  91061. */
  91062. targetId : {
  91063. get : function() {
  91064. return this._targetId;
  91065. }
  91066. },
  91067. /**
  91068. * Gets the collection containing the entity being referenced.
  91069. * @memberof ReferenceProperty.prototype
  91070. * @type {EntityCollection}
  91071. * @readonly
  91072. */
  91073. targetCollection : {
  91074. get : function() {
  91075. return this._targetCollection;
  91076. }
  91077. },
  91078. /**
  91079. * Gets the array of property names used to retrieve the referenced property.
  91080. * @memberof ReferenceProperty.prototype
  91081. * @type {String[]}
  91082. * @readonly
  91083. */
  91084. targetPropertyNames : {
  91085. get : function() {
  91086. return this._targetPropertyNames;
  91087. }
  91088. },
  91089. /**
  91090. * Gets the resolved instance of the underlying referenced property.
  91091. * @memberof ReferenceProperty.prototype
  91092. * @type {Property}
  91093. * @readonly
  91094. */
  91095. resolvedProperty : {
  91096. get : function() {
  91097. return resolve(this);
  91098. }
  91099. }
  91100. });
  91101. /**
  91102. * Creates a new instance given the entity collection that will
  91103. * be used to resolve it and a string indicating the target entity id and property.
  91104. * The format of the string is "objectId#foo.bar", where # separates the id from
  91105. * property path and . separates sub-properties. If the reference identifier or
  91106. * or any sub-properties contains a # . or \ they must be escaped.
  91107. *
  91108. * @param {EntityCollection} targetCollection
  91109. * @param {String} referenceString
  91110. * @returns {ReferenceProperty} A new instance of ReferenceProperty.
  91111. *
  91112. * @exception {DeveloperError} invalid referenceString.
  91113. */
  91114. ReferenceProperty.fromString = function(targetCollection, referenceString) {
  91115. if (!defined(targetCollection)) {
  91116. throw new DeveloperError('targetCollection is required.');
  91117. }
  91118. if (!defined(referenceString)) {
  91119. throw new DeveloperError('referenceString is required.');
  91120. }
  91121. var identifier;
  91122. var values = [];
  91123. var inIdentifier = true;
  91124. var isEscaped = false;
  91125. var token = '';
  91126. for (var i = 0; i < referenceString.length; ++i) {
  91127. var c = referenceString.charAt(i);
  91128. if (isEscaped) {
  91129. token += c;
  91130. isEscaped = false;
  91131. } else if (c === '\\') {
  91132. isEscaped = true;
  91133. } else if (inIdentifier && c === '#') {
  91134. identifier = token;
  91135. inIdentifier = false;
  91136. token = '';
  91137. } else if (!inIdentifier && c === '.') {
  91138. values.push(token);
  91139. token = '';
  91140. } else {
  91141. token += c;
  91142. }
  91143. }
  91144. values.push(token);
  91145. return new ReferenceProperty(targetCollection, identifier, values);
  91146. };
  91147. /**
  91148. * Gets the value of the property at the provided time.
  91149. *
  91150. * @param {JulianDate} time The time for which to retrieve the value.
  91151. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  91152. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  91153. */
  91154. ReferenceProperty.prototype.getValue = function(time, result) {
  91155. return resolve(this).getValue(time, result);
  91156. };
  91157. /**
  91158. * Gets the value of the property at the provided time and in the provided reference frame.
  91159. * This method is only valid if the property being referenced is a {@link PositionProperty}.
  91160. *
  91161. * @param {JulianDate} time The time for which to retrieve the value.
  91162. * @param {ReferenceFrame} referenceFrame The desired referenceFrame of the result.
  91163. * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
  91164. * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
  91165. */
  91166. ReferenceProperty.prototype.getValueInReferenceFrame = function(time, referenceFrame, result) {
  91167. return resolve(this).getValueInReferenceFrame(time, referenceFrame, result);
  91168. };
  91169. /**
  91170. * Gets the {@link Material} type at the provided time.
  91171. * This method is only valid if the property being referenced is a {@link MaterialProperty}.
  91172. *
  91173. * @param {JulianDate} time The time for which to retrieve the type.
  91174. * @returns {String} The type of material.
  91175. */
  91176. ReferenceProperty.prototype.getType = function(time) {
  91177. return resolve(this).getType(time);
  91178. };
  91179. /**
  91180. * Compares this property to the provided property and returns
  91181. * <code>true</code> if they are equal, <code>false</code> otherwise.
  91182. *
  91183. * @param {Property} [other] The other property.
  91184. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  91185. */
  91186. ReferenceProperty.prototype.equals = function(other) {
  91187. if (this === other) {
  91188. return true;
  91189. }
  91190. var names = this._targetPropertyNames;
  91191. var otherNames = other._targetPropertyNames;
  91192. if (this._targetCollection !== other._targetCollection || //
  91193. this._targetId !== other._targetId || //
  91194. names.length !== otherNames.length) {
  91195. return false;
  91196. }
  91197. var length = this._targetPropertyNames.length;
  91198. for (var i = 0; i < length; i++) {
  91199. if (names[i] !== otherNames[i]) {
  91200. return false;
  91201. }
  91202. }
  91203. return true;
  91204. };
  91205. ReferenceProperty.prototype._onTargetEntityDefinitionChanged = function(targetEntity, name, value, oldValue) {
  91206. if (this._targetPropertyNames[0] === name) {
  91207. this._resolveProperty = true;
  91208. this._definitionChanged.raiseEvent(this);
  91209. }
  91210. };
  91211. ReferenceProperty.prototype._onCollectionChanged = function(collection, added, removed) {
  91212. var targetEntity = this._targetEntity;
  91213. if (defined(targetEntity)) {
  91214. if (removed.indexOf(targetEntity) !== -1) {
  91215. targetEntity.definitionChanged.removeEventListener(ReferenceProperty.prototype._onTargetEntityDefinitionChanged, this);
  91216. this._resolveEntity = true;
  91217. this._resolveProperty = true;
  91218. } else if (this._resolveEntity) {
  91219. //If targetEntity is defined but resolveEntity is true, then the entity is detached
  91220. //and any change to the collection needs to incur an attempt to resolve in order to re-attach.
  91221. //without this if block, a reference that becomes re-attached will not signal definitionChanged
  91222. resolve(this);
  91223. if (!this._resolveEntity) {
  91224. this._definitionChanged.raiseEvent(this);
  91225. }
  91226. }
  91227. }
  91228. };
  91229. return ReferenceProperty;
  91230. });
  91231. /*global define*/
  91232. define('DataSources/Rotation',[
  91233. '../Core/defaultValue',
  91234. '../Core/defined',
  91235. '../Core/DeveloperError',
  91236. '../Core/Math'
  91237. ], function(
  91238. defaultValue,
  91239. defined,
  91240. DeveloperError,
  91241. CesiumMath) {
  91242. 'use strict';
  91243. /**
  91244. * Represents a {@link Packable} number that always interpolates values
  91245. * towards the shortest angle of rotation. This object is never used directly
  91246. * but is instead passed to the constructor of {@link SampledProperty}
  91247. * in order to represent a two-dimensional angle of rotation.
  91248. *
  91249. * @exports Rotation
  91250. *
  91251. *
  91252. * @example
  91253. * var time1 = Cesium.JulianDate.fromIso8601('2010-05-07T00:00:00');
  91254. * var time2 = Cesium.JulianDate.fromIso8601('2010-05-07T00:01:00');
  91255. * var time3 = Cesium.JulianDate.fromIso8601('2010-05-07T00:02:00');
  91256. *
  91257. * var property = new Cesium.SampledProperty(Cesium.Rotation);
  91258. * property.addSample(time1, 0);
  91259. * property.addSample(time3, Cesium.Math.toRadians(350));
  91260. *
  91261. * //Getting the value at time2 will equal 355 degrees instead
  91262. * //of 175 degrees (which is what you get if you construct
  91263. * //a SampledProperty(Number) instead. Note, the actual
  91264. * //return value is in radians, not degrees.
  91265. * property.getValue(time2);
  91266. *
  91267. * @see PackableForInterpolation
  91268. */
  91269. var Rotation = {
  91270. /**
  91271. * The number of elements used to pack the object into an array.
  91272. * @type {Number}
  91273. */
  91274. packedLength : 1,
  91275. /**
  91276. * Stores the provided instance into the provided array.
  91277. *
  91278. * @param {Rotation} value The value to pack.
  91279. * @param {Number[]} array The array to pack into.
  91280. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  91281. *
  91282. * @returns {Number[]} The array that was packed into
  91283. */
  91284. pack : function(value, array, startingIndex) {
  91285. if (!defined(value)) {
  91286. throw new DeveloperError('value is required');
  91287. }
  91288. if (!defined(array)) {
  91289. throw new DeveloperError('array is required');
  91290. }
  91291. startingIndex = defaultValue(startingIndex, 0);
  91292. array[startingIndex] = value;
  91293. return array;
  91294. },
  91295. /**
  91296. * Retrieves an instance from a packed array.
  91297. *
  91298. * @param {Number[]} array The packed array.
  91299. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  91300. * @param {Rotation} [result] The object into which to store the result.
  91301. * @returns {Rotation} The modified result parameter or a new Rotation instance if one was not provided.
  91302. */
  91303. unpack : function(array, startingIndex, result) {
  91304. if (!defined(array)) {
  91305. throw new DeveloperError('array is required');
  91306. }
  91307. startingIndex = defaultValue(startingIndex, 0);
  91308. return array[startingIndex];
  91309. },
  91310. /**
  91311. * Converts a packed array into a form suitable for interpolation.
  91312. *
  91313. * @param {Number[]} packedArray The packed array.
  91314. * @param {Number} [startingIndex=0] The index of the first element to be converted.
  91315. * @param {Number} [lastIndex=packedArray.length] The index of the last element to be converted.
  91316. * @param {Number[]} result The object into which to store the result.
  91317. */
  91318. convertPackedArrayForInterpolation : function(packedArray, startingIndex, lastIndex, result) {
  91319. if (!defined(packedArray)) {
  91320. throw new DeveloperError('packedArray is required');
  91321. }
  91322. startingIndex = defaultValue(startingIndex, 0);
  91323. lastIndex = defaultValue(lastIndex, packedArray.length);
  91324. var previousValue;
  91325. for (var i = 0, len = lastIndex - startingIndex + 1; i < len; i++) {
  91326. var value = packedArray[startingIndex + i];
  91327. if (i === 0 || Math.abs(previousValue - value) < Math.PI) {
  91328. result[i] = value;
  91329. } else {
  91330. result[i] = value - CesiumMath.TWO_PI;
  91331. }
  91332. previousValue = value;
  91333. }
  91334. },
  91335. /**
  91336. * Retrieves an instance from a packed array converted with {@link Rotation.convertPackedArrayForInterpolation}.
  91337. *
  91338. * @param {Number[]} array The array previously packed for interpolation.
  91339. * @param {Number[]} sourceArray The original packed array.
  91340. * @param {Number} [startingIndex=0] The startingIndex used to convert the array.
  91341. * @param {Number} [lastIndex=packedArray.length] The lastIndex used to convert the array.
  91342. * @param {Rotation} [result] The object into which to store the result.
  91343. * @returns {Rotation} The modified result parameter or a new Rotation instance if one was not provided.
  91344. */
  91345. unpackInterpolationResult : function(array, sourceArray, firstIndex, lastIndex, result) {
  91346. if (!defined(array)) {
  91347. throw new DeveloperError('array is required');
  91348. }
  91349. if (!defined(sourceArray)) {
  91350. throw new DeveloperError('sourceArray is required');
  91351. }
  91352. result = array[0];
  91353. if (result < 0) {
  91354. return result + CesiumMath.TWO_PI;
  91355. }
  91356. return result;
  91357. }
  91358. };
  91359. return Rotation;
  91360. });
  91361. /*global define*/
  91362. define('DataSources/SampledProperty',[
  91363. '../Core/binarySearch',
  91364. '../Core/defaultValue',
  91365. '../Core/defined',
  91366. '../Core/defineProperties',
  91367. '../Core/DeveloperError',
  91368. '../Core/Event',
  91369. '../Core/ExtrapolationType',
  91370. '../Core/JulianDate',
  91371. '../Core/LinearApproximation'
  91372. ], function(
  91373. binarySearch,
  91374. defaultValue,
  91375. defined,
  91376. defineProperties,
  91377. DeveloperError,
  91378. Event,
  91379. ExtrapolationType,
  91380. JulianDate,
  91381. LinearApproximation) {
  91382. 'use strict';
  91383. var PackableNumber = {
  91384. packedLength : 1,
  91385. pack : function(value, array, startingIndex) {
  91386. startingIndex = defaultValue(startingIndex, 0);
  91387. array[startingIndex] = value;
  91388. },
  91389. unpack : function(array, startingIndex, result) {
  91390. startingIndex = defaultValue(startingIndex, 0);
  91391. return array[startingIndex];
  91392. }
  91393. };
  91394. //We can't use splice for inserting new elements because function apply can't handle
  91395. //a huge number of arguments. See https://code.google.com/p/chromium/issues/detail?id=56588
  91396. function arrayInsert(array, startIndex, items) {
  91397. var i;
  91398. var arrayLength = array.length;
  91399. var itemsLength = items.length;
  91400. var newLength = arrayLength + itemsLength;
  91401. array.length = newLength;
  91402. if (arrayLength !== startIndex) {
  91403. var q = arrayLength - 1;
  91404. for (i = newLength - 1; i >= startIndex; i--) {
  91405. array[i] = array[q--];
  91406. }
  91407. }
  91408. for (i = 0; i < itemsLength; i++) {
  91409. array[startIndex++] = items[i];
  91410. }
  91411. }
  91412. function convertDate(date, epoch) {
  91413. if (date instanceof JulianDate) {
  91414. return date;
  91415. }
  91416. if (typeof date === 'string') {
  91417. return JulianDate.fromIso8601(date);
  91418. }
  91419. return JulianDate.addSeconds(epoch, date, new JulianDate());
  91420. }
  91421. var timesSpliceArgs = [];
  91422. var valuesSpliceArgs = [];
  91423. function mergeNewSamples(epoch, times, values, newData, packedLength) {
  91424. var newDataIndex = 0;
  91425. var i;
  91426. var prevItem;
  91427. var timesInsertionPoint;
  91428. var valuesInsertionPoint;
  91429. var currentTime;
  91430. var nextTime;
  91431. while (newDataIndex < newData.length) {
  91432. currentTime = convertDate(newData[newDataIndex], epoch);
  91433. timesInsertionPoint = binarySearch(times, currentTime, JulianDate.compare);
  91434. var timesSpliceArgsCount = 0;
  91435. var valuesSpliceArgsCount = 0;
  91436. if (timesInsertionPoint < 0) {
  91437. //Doesn't exist, insert as many additional values as we can.
  91438. timesInsertionPoint = ~timesInsertionPoint;
  91439. valuesInsertionPoint = timesInsertionPoint * packedLength;
  91440. prevItem = undefined;
  91441. nextTime = times[timesInsertionPoint];
  91442. while (newDataIndex < newData.length) {
  91443. currentTime = convertDate(newData[newDataIndex], epoch);
  91444. if ((defined(prevItem) && JulianDate.compare(prevItem, currentTime) >= 0) || (defined(nextTime) && JulianDate.compare(currentTime, nextTime) >= 0)) {
  91445. break;
  91446. }
  91447. timesSpliceArgs[timesSpliceArgsCount++] = currentTime;
  91448. newDataIndex = newDataIndex + 1;
  91449. for (i = 0; i < packedLength; i++) {
  91450. valuesSpliceArgs[valuesSpliceArgsCount++] = newData[newDataIndex];
  91451. newDataIndex = newDataIndex + 1;
  91452. }
  91453. prevItem = currentTime;
  91454. }
  91455. if (timesSpliceArgsCount > 0) {
  91456. valuesSpliceArgs.length = valuesSpliceArgsCount;
  91457. arrayInsert(values, valuesInsertionPoint, valuesSpliceArgs);
  91458. timesSpliceArgs.length = timesSpliceArgsCount;
  91459. arrayInsert(times, timesInsertionPoint, timesSpliceArgs);
  91460. }
  91461. } else {
  91462. //Found an exact match
  91463. for (i = 0; i < packedLength; i++) {
  91464. newDataIndex++;
  91465. values[(timesInsertionPoint * packedLength) + i] = newData[newDataIndex];
  91466. }
  91467. newDataIndex++;
  91468. }
  91469. }
  91470. }
  91471. /**
  91472. * A {@link Property} whose value is interpolated for a given time from the
  91473. * provided set of samples and specified interpolation algorithm and degree.
  91474. * @alias SampledProperty
  91475. * @constructor
  91476. *
  91477. * @param {Number|Packable} type The type of property.
  91478. * @param {Packable[]} [derivativeTypes] When supplied, indicates that samples will contain derivative information of the specified types.
  91479. *
  91480. *
  91481. * @example
  91482. * //Create a linearly interpolated Cartesian2
  91483. * var property = new Cesium.SampledProperty(Cesium.Cartesian2);
  91484. *
  91485. * //Populate it with data
  91486. * property.addSample(Cesium.JulianDate.fromIso8601(`2012-08-01T00:00:00.00Z`), new Cesium.Cartesian2(0, 0));
  91487. * property.addSample(Cesium.JulianDate.fromIso8601(`2012-08-02T00:00:00.00Z`), new Cesium.Cartesian2(4, 7));
  91488. *
  91489. * //Retrieve an interpolated value
  91490. * var result = property.getValue(Cesium.JulianDate.fromIso8601(`2012-08-01T12:00:00.00Z`));
  91491. *
  91492. * @example
  91493. * //Create a simple numeric SampledProperty that uses third degree Hermite Polynomial Approximation
  91494. * var property = new Cesium.SampledProperty(Number);
  91495. * property.setInterpolationOptions({
  91496. * interpolationDegree : 3,
  91497. * interpolationAlgorithm : Cesium.HermitePolynomialApproximation
  91498. * });
  91499. *
  91500. * //Populate it with data
  91501. * property.addSample(Cesium.JulianDate.fromIso8601(`2012-08-01T00:00:00.00Z`), 1.0);
  91502. * property.addSample(Cesium.JulianDate.fromIso8601(`2012-08-01T00:01:00.00Z`), 6.0);
  91503. * property.addSample(Cesium.JulianDate.fromIso8601(`2012-08-01T00:02:00.00Z`), 12.0);
  91504. * property.addSample(Cesium.JulianDate.fromIso8601(`2012-08-01T00:03:30.00Z`), 5.0);
  91505. * property.addSample(Cesium.JulianDate.fromIso8601(`2012-08-01T00:06:30.00Z`), 2.0);
  91506. *
  91507. * //Samples can be added in any order.
  91508. * property.addSample(Cesium.JulianDate.fromIso8601(`2012-08-01T00:00:30.00Z`), 6.2);
  91509. *
  91510. * //Retrieve an interpolated value
  91511. * var result = property.getValue(Cesium.JulianDate.fromIso8601(`2012-08-01T00:02:34.00Z`));
  91512. *
  91513. * @see SampledPositionProperty
  91514. */
  91515. function SampledProperty(type, derivativeTypes) {
  91516. if (!defined(type)) {
  91517. throw new DeveloperError('type is required.');
  91518. }
  91519. var innerType = type;
  91520. if (innerType === Number) {
  91521. innerType = PackableNumber;
  91522. }
  91523. var packedLength = innerType.packedLength;
  91524. var packedInterpolationLength = defaultValue(innerType.packedInterpolationLength, packedLength);
  91525. var inputOrder = 0;
  91526. var innerDerivativeTypes;
  91527. if (defined(derivativeTypes)) {
  91528. var length = derivativeTypes.length;
  91529. innerDerivativeTypes = new Array(length);
  91530. for (var i = 0; i < length; i++) {
  91531. var derivativeType = derivativeTypes[i];
  91532. if (derivativeType === Number) {
  91533. derivativeType = PackableNumber;
  91534. }
  91535. var derivativePackedLength = derivativeType.packedLength;
  91536. packedLength += derivativePackedLength;
  91537. packedInterpolationLength += defaultValue(derivativeType.packedInterpolationLength, derivativePackedLength);
  91538. innerDerivativeTypes[i] = derivativeType;
  91539. }
  91540. inputOrder = length;
  91541. }
  91542. this._type = type;
  91543. this._innerType = innerType;
  91544. this._interpolationDegree = 1;
  91545. this._interpolationAlgorithm = LinearApproximation;
  91546. this._numberOfPoints = 0;
  91547. this._times = [];
  91548. this._values = [];
  91549. this._xTable = [];
  91550. this._yTable = [];
  91551. this._packedLength = packedLength;
  91552. this._packedInterpolationLength = packedInterpolationLength;
  91553. this._updateTableLength = true;
  91554. this._interpolationResult = new Array(packedInterpolationLength);
  91555. this._definitionChanged = new Event();
  91556. this._derivativeTypes = derivativeTypes;
  91557. this._innerDerivativeTypes = innerDerivativeTypes;
  91558. this._inputOrder = inputOrder;
  91559. this._forwardExtrapolationType = ExtrapolationType.NONE;
  91560. this._forwardExtrapolationDuration = 0;
  91561. this._backwardExtrapolationType = ExtrapolationType.NONE;
  91562. this._backwardExtrapolationDuration = 0;
  91563. }
  91564. defineProperties(SampledProperty.prototype, {
  91565. /**
  91566. * Gets a value indicating if this property is constant. A property is considered
  91567. * constant if getValue always returns the same result for the current definition.
  91568. * @memberof SampledProperty.prototype
  91569. *
  91570. * @type {Boolean}
  91571. * @readonly
  91572. */
  91573. isConstant : {
  91574. get : function() {
  91575. return this._values.length === 0;
  91576. }
  91577. },
  91578. /**
  91579. * Gets the event that is raised whenever the definition of this property changes.
  91580. * The definition is considered to have changed if a call to getValue would return
  91581. * a different result for the same time.
  91582. * @memberof SampledProperty.prototype
  91583. *
  91584. * @type {Event}
  91585. * @readonly
  91586. */
  91587. definitionChanged : {
  91588. get : function() {
  91589. return this._definitionChanged;
  91590. }
  91591. },
  91592. /**
  91593. * Gets the type of property.
  91594. * @memberof SampledProperty.prototype
  91595. * @type {Object}
  91596. */
  91597. type : {
  91598. get : function() {
  91599. return this._type;
  91600. }
  91601. },
  91602. /**
  91603. * Gets the derivative types used by this property.
  91604. * @memberof SampledProperty.prototype
  91605. * @type {Packable[]}
  91606. */
  91607. derivativeTypes : {
  91608. get : function() {
  91609. return this._derivativeTypes;
  91610. }
  91611. },
  91612. /**
  91613. * Gets the degree of interpolation to perform when retrieving a value.
  91614. * @memberof SampledProperty.prototype
  91615. * @type {Number}
  91616. * @default 1
  91617. */
  91618. interpolationDegree : {
  91619. get : function() {
  91620. return this._interpolationDegree;
  91621. }
  91622. },
  91623. /**
  91624. * Gets the interpolation algorithm to use when retrieving a value.
  91625. * @memberof SampledProperty.prototype
  91626. * @type {InterpolationAlgorithm}
  91627. * @default LinearApproximation
  91628. */
  91629. interpolationAlgorithm : {
  91630. get : function() {
  91631. return this._interpolationAlgorithm;
  91632. }
  91633. },
  91634. /**
  91635. * Gets or sets the type of extrapolation to perform when a value
  91636. * is requested at a time after any available samples.
  91637. * @memberof SampledProperty.prototype
  91638. * @type {ExtrapolationType}
  91639. * @default ExtrapolationType.NONE
  91640. */
  91641. forwardExtrapolationType : {
  91642. get : function() {
  91643. return this._forwardExtrapolationType;
  91644. },
  91645. set : function(value) {
  91646. if (this._forwardExtrapolationType !== value) {
  91647. this._forwardExtrapolationType = value;
  91648. this._definitionChanged.raiseEvent(this);
  91649. }
  91650. }
  91651. },
  91652. /**
  91653. * Gets or sets the amount of time to extrapolate forward before
  91654. * the property becomes undefined. A value of 0 will extrapolate forever.
  91655. * @memberof SampledProperty.prototype
  91656. * @type {Number}
  91657. * @default 0
  91658. */
  91659. forwardExtrapolationDuration : {
  91660. get : function() {
  91661. return this._forwardExtrapolationDuration;
  91662. },
  91663. set : function(value) {
  91664. if (this._forwardExtrapolationDuration !== value) {
  91665. this._forwardExtrapolationDuration = value;
  91666. this._definitionChanged.raiseEvent(this);
  91667. }
  91668. }
  91669. },
  91670. /**
  91671. * Gets or sets the type of extrapolation to perform when a value
  91672. * is requested at a time before any available samples.
  91673. * @memberof SampledProperty.prototype
  91674. * @type {ExtrapolationType}
  91675. * @default ExtrapolationType.NONE
  91676. */
  91677. backwardExtrapolationType : {
  91678. get : function() {
  91679. return this._backwardExtrapolationType;
  91680. },
  91681. set : function(value) {
  91682. if (this._backwardExtrapolationType !== value) {
  91683. this._backwardExtrapolationType = value;
  91684. this._definitionChanged.raiseEvent(this);
  91685. }
  91686. }
  91687. },
  91688. /**
  91689. * Gets or sets the amount of time to extrapolate backward
  91690. * before the property becomes undefined. A value of 0 will extrapolate forever.
  91691. * @memberof SampledProperty.prototype
  91692. * @type {Number}
  91693. * @default 0
  91694. */
  91695. backwardExtrapolationDuration : {
  91696. get : function() {
  91697. return this._backwardExtrapolationDuration;
  91698. },
  91699. set : function(value) {
  91700. if (this._backwardExtrapolationDuration !== value) {
  91701. this._backwardExtrapolationDuration = value;
  91702. this._definitionChanged.raiseEvent(this);
  91703. }
  91704. }
  91705. }
  91706. });
  91707. /**
  91708. * Gets the value of the property at the provided time.
  91709. *
  91710. * @param {JulianDate} time The time for which to retrieve the value.
  91711. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  91712. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  91713. */
  91714. SampledProperty.prototype.getValue = function(time, result) {
  91715. if (!defined(time)) {
  91716. throw new DeveloperError('time is required.');
  91717. }
  91718. var times = this._times;
  91719. var timesLength = times.length;
  91720. if (timesLength === 0) {
  91721. return undefined;
  91722. }
  91723. var timeout;
  91724. var innerType = this._innerType;
  91725. var values = this._values;
  91726. var index = binarySearch(times, time, JulianDate.compare);
  91727. if (index < 0) {
  91728. index = ~index;
  91729. if (index === 0) {
  91730. var startTime = times[index];
  91731. timeout = this._backwardExtrapolationDuration;
  91732. if (this._backwardExtrapolationType === ExtrapolationType.NONE || (timeout !== 0 && JulianDate.secondsDifference(startTime, time) > timeout)) {
  91733. return undefined;
  91734. }
  91735. if (this._backwardExtrapolationType === ExtrapolationType.HOLD) {
  91736. return innerType.unpack(values, 0, result);
  91737. }
  91738. }
  91739. if (index >= timesLength) {
  91740. index = timesLength - 1;
  91741. var endTime = times[index];
  91742. timeout = this._forwardExtrapolationDuration;
  91743. if (this._forwardExtrapolationType === ExtrapolationType.NONE || (timeout !== 0 && JulianDate.secondsDifference(time, endTime) > timeout)) {
  91744. return undefined;
  91745. }
  91746. if (this._forwardExtrapolationType === ExtrapolationType.HOLD) {
  91747. index = timesLength - 1;
  91748. return innerType.unpack(values, index * innerType.packedLength, result);
  91749. }
  91750. }
  91751. var xTable = this._xTable;
  91752. var yTable = this._yTable;
  91753. var interpolationAlgorithm = this._interpolationAlgorithm;
  91754. var packedInterpolationLength = this._packedInterpolationLength;
  91755. var inputOrder = this._inputOrder;
  91756. if (this._updateTableLength) {
  91757. this._updateTableLength = false;
  91758. var numberOfPoints = Math.min(interpolationAlgorithm.getRequiredDataPoints(this._interpolationDegree, inputOrder), timesLength);
  91759. if (numberOfPoints !== this._numberOfPoints) {
  91760. this._numberOfPoints = numberOfPoints;
  91761. xTable.length = numberOfPoints;
  91762. yTable.length = numberOfPoints * packedInterpolationLength;
  91763. }
  91764. }
  91765. var degree = this._numberOfPoints - 1;
  91766. if (degree < 1) {
  91767. return undefined;
  91768. }
  91769. var firstIndex = 0;
  91770. var lastIndex = timesLength - 1;
  91771. var pointsInCollection = lastIndex - firstIndex + 1;
  91772. if (pointsInCollection >= degree + 1) {
  91773. var computedFirstIndex = index - ((degree / 2) | 0) - 1;
  91774. if (computedFirstIndex < firstIndex) {
  91775. computedFirstIndex = firstIndex;
  91776. }
  91777. var computedLastIndex = computedFirstIndex + degree;
  91778. if (computedLastIndex > lastIndex) {
  91779. computedLastIndex = lastIndex;
  91780. computedFirstIndex = computedLastIndex - degree;
  91781. if (computedFirstIndex < firstIndex) {
  91782. computedFirstIndex = firstIndex;
  91783. }
  91784. }
  91785. firstIndex = computedFirstIndex;
  91786. lastIndex = computedLastIndex;
  91787. }
  91788. var length = lastIndex - firstIndex + 1;
  91789. // Build the tables
  91790. for (var i = 0; i < length; ++i) {
  91791. xTable[i] = JulianDate.secondsDifference(times[firstIndex + i], times[lastIndex]);
  91792. }
  91793. if (!defined(innerType.convertPackedArrayForInterpolation)) {
  91794. var destinationIndex = 0;
  91795. var packedLength = this._packedLength;
  91796. var sourceIndex = firstIndex * packedLength;
  91797. var stop = (lastIndex + 1) * packedLength;
  91798. while (sourceIndex < stop) {
  91799. yTable[destinationIndex] = values[sourceIndex];
  91800. sourceIndex++;
  91801. destinationIndex++;
  91802. }
  91803. } else {
  91804. innerType.convertPackedArrayForInterpolation(values, firstIndex, lastIndex, yTable);
  91805. }
  91806. // Interpolate!
  91807. var x = JulianDate.secondsDifference(time, times[lastIndex]);
  91808. var interpolationResult;
  91809. if (inputOrder === 0 || !defined(interpolationAlgorithm.interpolate)) {
  91810. interpolationResult = interpolationAlgorithm.interpolateOrderZero(x, xTable, yTable, packedInterpolationLength, this._interpolationResult);
  91811. } else {
  91812. var yStride = Math.floor(packedInterpolationLength / (inputOrder + 1));
  91813. interpolationResult = interpolationAlgorithm.interpolate(x, xTable, yTable, yStride, inputOrder, inputOrder, this._interpolationResult);
  91814. }
  91815. if (!defined(innerType.unpackInterpolationResult)) {
  91816. return innerType.unpack(interpolationResult, 0, result);
  91817. }
  91818. return innerType.unpackInterpolationResult(interpolationResult, values, firstIndex, lastIndex, result);
  91819. }
  91820. return innerType.unpack(values, index * this._packedLength, result);
  91821. };
  91822. /**
  91823. * Sets the algorithm and degree to use when interpolating a value.
  91824. *
  91825. * @param {Object} [options] Object with the following properties:
  91826. * @param {InterpolationAlgorithm} [options.interpolationAlgorithm] The new interpolation algorithm. If undefined, the existing property will be unchanged.
  91827. * @param {Number} [options.interpolationDegree] The new interpolation degree. If undefined, the existing property will be unchanged.
  91828. */
  91829. SampledProperty.prototype.setInterpolationOptions = function(options) {
  91830. if (!defined(options)) {
  91831. throw new DeveloperError('options is required.');
  91832. }
  91833. var valuesChanged = false;
  91834. var interpolationAlgorithm = options.interpolationAlgorithm;
  91835. var interpolationDegree = options.interpolationDegree;
  91836. if (this._interpolationAlgorithm !== interpolationAlgorithm) {
  91837. this._interpolationAlgorithm = interpolationAlgorithm;
  91838. valuesChanged = true;
  91839. }
  91840. if (this._interpolationDegree !== interpolationDegree) {
  91841. this._interpolationDegree = interpolationDegree;
  91842. valuesChanged = true;
  91843. }
  91844. if (valuesChanged) {
  91845. this._updateTableLength = true;
  91846. this._definitionChanged.raiseEvent(this);
  91847. }
  91848. };
  91849. /**
  91850. * Adds a new sample
  91851. *
  91852. * @param {JulianDate} time The sample time.
  91853. * @param {Packable} value The value at the provided time.
  91854. * @param {Packable[]} [derivatives] The array of derivatives at the provided time.
  91855. */
  91856. SampledProperty.prototype.addSample = function(time, value, derivatives) {
  91857. var innerDerivativeTypes = this._innerDerivativeTypes;
  91858. var hasDerivatives = defined(innerDerivativeTypes);
  91859. if (!defined(time)) {
  91860. throw new DeveloperError('time is required.');
  91861. }
  91862. if (!defined(value)) {
  91863. throw new DeveloperError('value is required.');
  91864. }
  91865. if (hasDerivatives && !defined(derivatives)) {
  91866. throw new DeveloperError('derivatives is required.');
  91867. }
  91868. var innerType = this._innerType;
  91869. var data = [];
  91870. data.push(time);
  91871. innerType.pack(value, data, data.length);
  91872. if (hasDerivatives) {
  91873. var derivativesLength = innerDerivativeTypes.length;
  91874. for (var x = 0; x < derivativesLength; x++) {
  91875. innerDerivativeTypes[x].pack(derivatives[x], data, data.length);
  91876. }
  91877. }
  91878. mergeNewSamples(undefined, this._times, this._values, data, this._packedLength);
  91879. this._updateTableLength = true;
  91880. this._definitionChanged.raiseEvent(this);
  91881. };
  91882. /**
  91883. * Adds an array of samples
  91884. *
  91885. * @param {JulianDate[]} times An array of JulianDate instances where each index is a sample time.
  91886. * @param {Packable[]} values The array of values, where each value corresponds to the provided times index.
  91887. * @param {Array[]} [derivativeValues] An array where each item is the array of derivatives at the equivalent time index.
  91888. *
  91889. * @exception {DeveloperError} times and values must be the same length.
  91890. * @exception {DeveloperError} times and derivativeValues must be the same length.
  91891. */
  91892. SampledProperty.prototype.addSamples = function(times, values, derivativeValues) {
  91893. var innerDerivativeTypes = this._innerDerivativeTypes;
  91894. var hasDerivatives = defined(innerDerivativeTypes);
  91895. if (!defined(times)) {
  91896. throw new DeveloperError('times is required.');
  91897. }
  91898. if (!defined(values)) {
  91899. throw new DeveloperError('values is required.');
  91900. }
  91901. if (times.length !== values.length) {
  91902. throw new DeveloperError('times and values must be the same length.');
  91903. }
  91904. if (hasDerivatives && (!defined(derivativeValues) || derivativeValues.length !== times.length)) {
  91905. throw new DeveloperError('times and derivativeValues must be the same length.');
  91906. }
  91907. var innerType = this._innerType;
  91908. var length = times.length;
  91909. var data = [];
  91910. for (var i = 0; i < length; i++) {
  91911. data.push(times[i]);
  91912. innerType.pack(values[i], data, data.length);
  91913. if (hasDerivatives) {
  91914. var derivatives = derivativeValues[i];
  91915. var derivativesLength = innerDerivativeTypes.length;
  91916. for (var x = 0; x < derivativesLength; x++) {
  91917. innerDerivativeTypes[x].pack(derivatives[x], data, data.length);
  91918. }
  91919. }
  91920. }
  91921. mergeNewSamples(undefined, this._times, this._values, data, this._packedLength);
  91922. this._updateTableLength = true;
  91923. this._definitionChanged.raiseEvent(this);
  91924. };
  91925. /**
  91926. * Adds samples as a single packed array where each new sample is represented as a date,
  91927. * followed by the packed representation of the corresponding value and derivatives.
  91928. *
  91929. * @param {Number[]} packedSamples The array of packed samples.
  91930. * @param {JulianDate} [epoch] If any of the dates in packedSamples are numbers, they are considered an offset from this epoch, in seconds.
  91931. */
  91932. SampledProperty.prototype.addSamplesPackedArray = function(packedSamples, epoch) {
  91933. if (!defined(packedSamples)) {
  91934. throw new DeveloperError('packedSamples is required.');
  91935. }
  91936. mergeNewSamples(epoch, this._times, this._values, packedSamples, this._packedLength);
  91937. this._updateTableLength = true;
  91938. this._definitionChanged.raiseEvent(this);
  91939. };
  91940. /**
  91941. * Compares this property to the provided property and returns
  91942. * <code>true</code> if they are equal, <code>false</code> otherwise.
  91943. *
  91944. * @param {Property} [other] The other property.
  91945. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  91946. */
  91947. SampledProperty.prototype.equals = function(other) {
  91948. if (this === other) {
  91949. return true;
  91950. }
  91951. if (!defined(other)) {
  91952. return false;
  91953. }
  91954. if (this._type !== other._type || //
  91955. this._interpolationDegree !== other._interpolationDegree || //
  91956. this._interpolationAlgorithm !== other._interpolationAlgorithm) {
  91957. return false;
  91958. }
  91959. var derivativeTypes = this._derivativeTypes;
  91960. var hasDerivatives = defined(derivativeTypes);
  91961. var otherDerivativeTypes = other._derivativeTypes;
  91962. var otherHasDerivatives = defined(otherDerivativeTypes);
  91963. if (hasDerivatives !== otherHasDerivatives) {
  91964. return false;
  91965. }
  91966. var i;
  91967. var length;
  91968. if (hasDerivatives) {
  91969. length = derivativeTypes.length;
  91970. if (length !== otherDerivativeTypes.length) {
  91971. return false;
  91972. }
  91973. for (i = 0; i < length; i++) {
  91974. if (derivativeTypes[i] !== otherDerivativeTypes[i]) {
  91975. return false;
  91976. }
  91977. }
  91978. }
  91979. var times = this._times;
  91980. var otherTimes = other._times;
  91981. length = times.length;
  91982. if (length !== otherTimes.length) {
  91983. return false;
  91984. }
  91985. for (i = 0; i < length; i++) {
  91986. if (!JulianDate.equals(times[i], otherTimes[i])) {
  91987. return false;
  91988. }
  91989. }
  91990. var values = this._values;
  91991. var otherValues = other._values;
  91992. for (i = 0; i < length; i++) {
  91993. if (values[i] !== otherValues[i]) {
  91994. return false;
  91995. }
  91996. }
  91997. return true;
  91998. };
  91999. //Exposed for testing.
  92000. SampledProperty._mergeNewSamples = mergeNewSamples;
  92001. return SampledProperty;
  92002. });
  92003. /*global define*/
  92004. define('DataSources/SampledPositionProperty',[
  92005. '../Core/Cartesian3',
  92006. '../Core/defaultValue',
  92007. '../Core/defined',
  92008. '../Core/defineProperties',
  92009. '../Core/DeveloperError',
  92010. '../Core/Event',
  92011. '../Core/ReferenceFrame',
  92012. './PositionProperty',
  92013. './Property',
  92014. './SampledProperty'
  92015. ], function(
  92016. Cartesian3,
  92017. defaultValue,
  92018. defined,
  92019. defineProperties,
  92020. DeveloperError,
  92021. Event,
  92022. ReferenceFrame,
  92023. PositionProperty,
  92024. Property,
  92025. SampledProperty) {
  92026. 'use strict';
  92027. /**
  92028. * A {@link SampledProperty} which is also a {@link PositionProperty}.
  92029. *
  92030. * @alias SampledPositionProperty
  92031. * @constructor
  92032. *
  92033. * @param {ReferenceFrame} [referenceFrame=ReferenceFrame.FIXED] The reference frame in which the position is defined.
  92034. * @param {Number} [numberOfDerivatives=0] The number of derivatives that accompany each position; i.e. velocity, acceleration, etc...
  92035. */
  92036. function SampledPositionProperty(referenceFrame, numberOfDerivatives) {
  92037. numberOfDerivatives = defaultValue(numberOfDerivatives, 0);
  92038. var derivativeTypes;
  92039. if (numberOfDerivatives > 0) {
  92040. derivativeTypes = new Array(numberOfDerivatives);
  92041. for (var i = 0; i < numberOfDerivatives; i++) {
  92042. derivativeTypes[i] = Cartesian3;
  92043. }
  92044. }
  92045. this._numberOfDerivatives = numberOfDerivatives;
  92046. this._property = new SampledProperty(Cartesian3, derivativeTypes);
  92047. this._definitionChanged = new Event();
  92048. this._referenceFrame = defaultValue(referenceFrame, ReferenceFrame.FIXED);
  92049. this._property._definitionChanged.addEventListener(function() {
  92050. this._definitionChanged.raiseEvent(this);
  92051. }, this);
  92052. }
  92053. defineProperties(SampledPositionProperty.prototype, {
  92054. /**
  92055. * Gets a value indicating if this property is constant. A property is considered
  92056. * constant if getValue always returns the same result for the current definition.
  92057. * @memberof SampledPositionProperty.prototype
  92058. *
  92059. * @type {Boolean}
  92060. * @readonly
  92061. */
  92062. isConstant : {
  92063. get : function() {
  92064. return this._property.isConstant;
  92065. }
  92066. },
  92067. /**
  92068. * Gets the event that is raised whenever the definition of this property changes.
  92069. * The definition is considered to have changed if a call to getValue would return
  92070. * a different result for the same time.
  92071. * @memberof SampledPositionProperty.prototype
  92072. *
  92073. * @type {Event}
  92074. * @readonly
  92075. */
  92076. definitionChanged : {
  92077. get : function() {
  92078. return this._definitionChanged;
  92079. }
  92080. },
  92081. /**
  92082. * Gets the reference frame in which the position is defined.
  92083. * @memberof SampledPositionProperty.prototype
  92084. * @type {ReferenceFrame}
  92085. * @default ReferenceFrame.FIXED;
  92086. */
  92087. referenceFrame : {
  92088. get : function() {
  92089. return this._referenceFrame;
  92090. }
  92091. },
  92092. /**
  92093. * Gets the degree of interpolation to perform when retrieving a value.
  92094. * @memberof SampledPositionProperty.prototype
  92095. *
  92096. * @type {Number}
  92097. * @default 1
  92098. */
  92099. interpolationDegree : {
  92100. get : function() {
  92101. return this._property.interpolationDegree;
  92102. }
  92103. },
  92104. /**
  92105. * Gets the interpolation algorithm to use when retrieving a value.
  92106. * @memberof SampledPositionProperty.prototype
  92107. *
  92108. * @type {InterpolationAlgorithm}
  92109. * @default LinearApproximation
  92110. */
  92111. interpolationAlgorithm : {
  92112. get : function() {
  92113. return this._property.interpolationAlgorithm;
  92114. }
  92115. },
  92116. /**
  92117. * The number of derivatives contained by this property; i.e. 0 for just position, 1 for velocity, etc.
  92118. * @memberof SampledPositionProperty.prototype
  92119. *
  92120. * @type {Boolean}
  92121. * @default false
  92122. */
  92123. numberOfDerivatives : {
  92124. get : function() {
  92125. return this._numberOfDerivatives;
  92126. }
  92127. },
  92128. /**
  92129. * Gets or sets the type of extrapolation to perform when a value
  92130. * is requested at a time after any available samples.
  92131. * @memberof SampledPositionProperty.prototype
  92132. * @type {ExtrapolationType}
  92133. * @default ExtrapolationType.NONE
  92134. */
  92135. forwardExtrapolationType : {
  92136. get : function() {
  92137. return this._property.forwardExtrapolationType;
  92138. },
  92139. set : function(value) {
  92140. this._property.forwardExtrapolationType = value;
  92141. }
  92142. },
  92143. /**
  92144. * Gets or sets the amount of time to extrapolate forward before
  92145. * the property becomes undefined. A value of 0 will extrapolate forever.
  92146. * @memberof SampledPositionProperty.prototype
  92147. * @type {Number}
  92148. * @default 0
  92149. */
  92150. forwardExtrapolationDuration : {
  92151. get : function() {
  92152. return this._property.forwardExtrapolationDuration;
  92153. },
  92154. set : function(value) {
  92155. this._property.forwardExtrapolationDuration = value;
  92156. }
  92157. },
  92158. /**
  92159. * Gets or sets the type of extrapolation to perform when a value
  92160. * is requested at a time before any available samples.
  92161. * @memberof SampledPositionProperty.prototype
  92162. * @type {ExtrapolationType}
  92163. * @default ExtrapolationType.NONE
  92164. */
  92165. backwardExtrapolationType : {
  92166. get : function() {
  92167. return this._property.backwardExtrapolationType;
  92168. },
  92169. set : function(value) {
  92170. this._property.backwardExtrapolationType = value;
  92171. }
  92172. },
  92173. /**
  92174. * Gets or sets the amount of time to extrapolate backward
  92175. * before the property becomes undefined. A value of 0 will extrapolate forever.
  92176. * @memberof SampledPositionProperty.prototype
  92177. * @type {Number}
  92178. * @default 0
  92179. */
  92180. backwardExtrapolationDuration : {
  92181. get : function() {
  92182. return this._property.backwardExtrapolationDuration;
  92183. },
  92184. set : function(value) {
  92185. this._property.backwardExtrapolationDuration = value;
  92186. }
  92187. }
  92188. });
  92189. /**
  92190. * Gets the position at the provided time.
  92191. *
  92192. * @param {JulianDate} time The time for which to retrieve the value.
  92193. * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
  92194. * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
  92195. */
  92196. SampledPositionProperty.prototype.getValue = function(time, result) {
  92197. return this.getValueInReferenceFrame(time, ReferenceFrame.FIXED, result);
  92198. };
  92199. /**
  92200. * Gets the position at the provided time and in the provided reference frame.
  92201. *
  92202. * @param {JulianDate} time The time for which to retrieve the value.
  92203. * @param {ReferenceFrame} referenceFrame The desired referenceFrame of the result.
  92204. * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
  92205. * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
  92206. */
  92207. SampledPositionProperty.prototype.getValueInReferenceFrame = function(time, referenceFrame, result) {
  92208. if (!defined(time)) {
  92209. throw new DeveloperError('time is required.');
  92210. }
  92211. if (!defined(referenceFrame)) {
  92212. throw new DeveloperError('referenceFrame is required.');
  92213. }
  92214. result = this._property.getValue(time, result);
  92215. if (defined(result)) {
  92216. return PositionProperty.convertToReferenceFrame(time, result, this._referenceFrame, referenceFrame, result);
  92217. }
  92218. return undefined;
  92219. };
  92220. /**
  92221. * Sets the algorithm and degree to use when interpolating a position.
  92222. *
  92223. * @param {Object} [options] Object with the following properties:
  92224. * @param {InterpolationAlgorithm} [options.interpolationAlgorithm] The new interpolation algorithm. If undefined, the existing property will be unchanged.
  92225. * @param {Number} [options.interpolationDegree] The new interpolation degree. If undefined, the existing property will be unchanged.
  92226. */
  92227. SampledPositionProperty.prototype.setInterpolationOptions = function(options) {
  92228. this._property.setInterpolationOptions(options);
  92229. };
  92230. /**
  92231. * Adds a new sample.
  92232. *
  92233. * @param {JulianDate} time The sample time.
  92234. * @param {Cartesian3} position The position at the provided time.
  92235. * @param {Cartesian3[]} [derivatives] The array of derivative values at the provided time.
  92236. */
  92237. SampledPositionProperty.prototype.addSample = function(time, position, derivatives) {
  92238. var numberOfDerivatives = this._numberOfDerivatives;
  92239. if (numberOfDerivatives > 0 && (!defined(derivatives) || derivatives.length !== numberOfDerivatives)) {
  92240. throw new DeveloperError('derivatives length must be equal to the number of derivatives.');
  92241. }
  92242. this._property.addSample(time, position, derivatives);
  92243. };
  92244. /**
  92245. * Adds multiple samples via parallel arrays.
  92246. *
  92247. * @param {JulianDate[]} times An array of JulianDate instances where each index is a sample time.
  92248. * @param {Cartesian3[]} positions An array of Cartesian3 position instances, where each value corresponds to the provided time index.
  92249. * @param {Array[]} [derivatives] An array where each value is another array containing derivatives for the corresponding time index.
  92250. *
  92251. * @exception {DeveloperError} All arrays must be the same length.
  92252. */
  92253. SampledPositionProperty.prototype.addSamples = function(times, positions, derivatives) {
  92254. this._property.addSamples(times, positions, derivatives);
  92255. };
  92256. /**
  92257. * Adds samples as a single packed array where each new sample is represented as a date,
  92258. * followed by the packed representation of the corresponding value and derivatives.
  92259. *
  92260. * @param {Number[]} packedSamples The array of packed samples.
  92261. * @param {JulianDate} [epoch] If any of the dates in packedSamples are numbers, they are considered an offset from this epoch, in seconds.
  92262. */
  92263. SampledPositionProperty.prototype.addSamplesPackedArray = function(data, epoch) {
  92264. this._property.addSamplesPackedArray(data, epoch);
  92265. };
  92266. /**
  92267. * Compares this property to the provided property and returns
  92268. * <code>true</code> if they are equal, <code>false</code> otherwise.
  92269. *
  92270. * @param {Property} [other] The other property.
  92271. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  92272. */
  92273. SampledPositionProperty.prototype.equals = function(other) {
  92274. return this === other || //
  92275. (other instanceof SampledPositionProperty &&
  92276. Property.equals(this._property, other._property) && //
  92277. this._referenceFrame === other._referenceFrame);
  92278. };
  92279. return SampledPositionProperty;
  92280. });
  92281. /*global define*/
  92282. define('DataSources/StripeOrientation',[
  92283. '../Core/freezeObject'
  92284. ], function(
  92285. freezeObject) {
  92286. 'use strict';
  92287. /**
  92288. * Defined the orientation of stripes in {@link StripeMaterialProperty}.
  92289. *
  92290. * @exports StripeOrientation
  92291. */
  92292. var StripeOrientation = {
  92293. /**
  92294. * Horizontal orientation.
  92295. * @type {Number}
  92296. */
  92297. HORIZONTAL : 0,
  92298. /**
  92299. * Vertical orientation.
  92300. * @type {Number}
  92301. */
  92302. VERTICAL : 1
  92303. };
  92304. return freezeObject(StripeOrientation);
  92305. });
  92306. /*global define*/
  92307. define('DataSources/StripeMaterialProperty',[
  92308. '../Core/Color',
  92309. '../Core/defaultValue',
  92310. '../Core/defined',
  92311. '../Core/defineProperties',
  92312. '../Core/Event',
  92313. './createPropertyDescriptor',
  92314. './Property',
  92315. './StripeOrientation'
  92316. ], function(
  92317. Color,
  92318. defaultValue,
  92319. defined,
  92320. defineProperties,
  92321. Event,
  92322. createPropertyDescriptor,
  92323. Property,
  92324. StripeOrientation) {
  92325. 'use strict';
  92326. var defaultOrientation = StripeOrientation.HORIZONTAL;
  92327. var defaultEvenColor = Color.WHITE;
  92328. var defaultOddColor = Color.BLACK;
  92329. var defaultOffset = 0;
  92330. var defaultRepeat = 1;
  92331. /**
  92332. * A {@link MaterialProperty} that maps to stripe {@link Material} uniforms.
  92333. * @alias StripeMaterialProperty
  92334. * @constructor
  92335. *
  92336. * @param {Object} [options] Object with the following properties:
  92337. * @param {Property} [options.evenColor=Color.WHITE] A Property specifying the first {@link Color}.
  92338. * @param {Property} [options.oddColor=Color.BLACK] A Property specifying the second {@link Color}.
  92339. * @param {Property} [options.repeat=1] A numeric Property specifying how many times the stripes repeat.
  92340. * @param {Property} [options.offset=0] A numeric Property specifying how far into the pattern to start the material.
  92341. * @param {Property} [options.orientation=StripeOrientation.HORIZONTAL] A Property specifying the {@link StripeOrientation}.
  92342. */
  92343. function StripeMaterialProperty(options) {
  92344. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  92345. this._definitionChanged = new Event();
  92346. this._orientation = undefined;
  92347. this._orientationSubscription = undefined;
  92348. this._evenColor = undefined;
  92349. this._evenColorSubscription = undefined;
  92350. this._oddColor = undefined;
  92351. this._oddColorSubscription = undefined;
  92352. this._offset = undefined;
  92353. this._offsetSubscription = undefined;
  92354. this._repeat = undefined;
  92355. this._repeatSubscription = undefined;
  92356. this.orientation = options.orientation;
  92357. this.evenColor = options.evenColor;
  92358. this.oddColor = options.oddColor;
  92359. this.offset = options.offset;
  92360. this.repeat = options.repeat;
  92361. }
  92362. defineProperties(StripeMaterialProperty.prototype, {
  92363. /**
  92364. * Gets a value indicating if this property is constant. A property is considered
  92365. * constant if getValue always returns the same result for the current definition.
  92366. * @memberof StripeMaterialProperty.prototype
  92367. *
  92368. * @type {Boolean}
  92369. * @readonly
  92370. */
  92371. isConstant : {
  92372. get : function() {
  92373. return Property.isConstant(this._orientation) && //
  92374. Property.isConstant(this._evenColor) && //
  92375. Property.isConstant(this._oddColor) && //
  92376. Property.isConstant(this._offset) && //
  92377. Property.isConstant(this._repeat);
  92378. }
  92379. },
  92380. /**
  92381. * Gets the event that is raised whenever the definition of this property changes.
  92382. * The definition is considered to have changed if a call to getValue would return
  92383. * a different result for the same time.
  92384. * @memberof StripeMaterialProperty.prototype
  92385. *
  92386. * @type {Event}
  92387. * @readonly
  92388. */
  92389. definitionChanged : {
  92390. get : function() {
  92391. return this._definitionChanged;
  92392. }
  92393. },
  92394. /**
  92395. * Gets or sets the Property specifying the {@link StripeOrientation}/
  92396. * @memberof StripeMaterialProperty.prototype
  92397. * @type {Property}
  92398. * @default StripeOrientation.HORIZONTAL
  92399. */
  92400. orientation : createPropertyDescriptor('orientation'),
  92401. /**
  92402. * Gets or sets the Property specifying the first {@link Color}.
  92403. * @memberof StripeMaterialProperty.prototype
  92404. * @type {Property}
  92405. * @default Color.WHITE
  92406. */
  92407. evenColor : createPropertyDescriptor('evenColor'),
  92408. /**
  92409. * Gets or sets the Property specifying the second {@link Color}.
  92410. * @memberof StripeMaterialProperty.prototype
  92411. * @type {Property}
  92412. * @default Color.BLACK
  92413. */
  92414. oddColor : createPropertyDescriptor('oddColor'),
  92415. /**
  92416. * Gets or sets the numeric Property specifying the point into the pattern
  92417. * to begin drawing; with 0.0 being the beginning of the even color, 1.0 the beginning
  92418. * of the odd color, 2.0 being the even color again, and any multiple or fractional values
  92419. * being in between.
  92420. * @memberof StripeMaterialProperty.prototype
  92421. * @type {Property}
  92422. * @default 0.0
  92423. */
  92424. offset : createPropertyDescriptor('offset'),
  92425. /**
  92426. * Gets or sets the numeric Property specifying how many times the stripes repeat.
  92427. * @memberof StripeMaterialProperty.prototype
  92428. * @type {Property}
  92429. * @default 1.0
  92430. */
  92431. repeat : createPropertyDescriptor('repeat')
  92432. });
  92433. /**
  92434. * Gets the {@link Material} type at the provided time.
  92435. *
  92436. * @param {JulianDate} time The time for which to retrieve the type.
  92437. * @returns {String} The type of material.
  92438. */
  92439. StripeMaterialProperty.prototype.getType = function(time) {
  92440. return 'Stripe';
  92441. };
  92442. /**
  92443. * Gets the value of the property at the provided time.
  92444. *
  92445. * @param {JulianDate} time The time for which to retrieve the value.
  92446. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  92447. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  92448. */
  92449. StripeMaterialProperty.prototype.getValue = function(time, result) {
  92450. if (!defined(result)) {
  92451. result = {};
  92452. }
  92453. result.horizontal = Property.getValueOrDefault(this._orientation, time, defaultOrientation) === StripeOrientation.HORIZONTAL;
  92454. result.evenColor = Property.getValueOrClonedDefault(this._evenColor, time, defaultEvenColor, result.evenColor);
  92455. result.oddColor = Property.getValueOrClonedDefault(this._oddColor, time, defaultOddColor, result.oddColor);
  92456. result.offset = Property.getValueOrDefault(this._offset, time, defaultOffset);
  92457. result.repeat = Property.getValueOrDefault(this._repeat, time, defaultRepeat);
  92458. return result;
  92459. };
  92460. /**
  92461. * Compares this property to the provided property and returns
  92462. * <code>true</code> if they are equal, <code>false</code> otherwise.
  92463. *
  92464. * @param {Property} [other] The other property.
  92465. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  92466. */
  92467. StripeMaterialProperty.prototype.equals = function(other) {
  92468. return this === other || //
  92469. (other instanceof StripeMaterialProperty && //
  92470. Property.equals(this._orientation, other._orientation) && //
  92471. Property.equals(this._evenColor, other._evenColor) && //
  92472. Property.equals(this._oddColor, other._oddColor) && //
  92473. Property.equals(this._offset, other._offset) && //
  92474. Property.equals(this._repeat, other._repeat));
  92475. };
  92476. return StripeMaterialProperty;
  92477. });
  92478. /*global define*/
  92479. define('DataSources/TimeIntervalCollectionPositionProperty',[
  92480. '../Core/defaultValue',
  92481. '../Core/defined',
  92482. '../Core/defineProperties',
  92483. '../Core/DeveloperError',
  92484. '../Core/Event',
  92485. '../Core/ReferenceFrame',
  92486. '../Core/TimeIntervalCollection',
  92487. './PositionProperty',
  92488. './Property'
  92489. ], function(
  92490. defaultValue,
  92491. defined,
  92492. defineProperties,
  92493. DeveloperError,
  92494. Event,
  92495. ReferenceFrame,
  92496. TimeIntervalCollection,
  92497. PositionProperty,
  92498. Property) {
  92499. 'use strict';
  92500. /**
  92501. * A {@link TimeIntervalCollectionProperty} which is also a {@link PositionProperty}.
  92502. *
  92503. * @alias TimeIntervalCollectionPositionProperty
  92504. * @constructor
  92505. *
  92506. * @param {ReferenceFrame} [referenceFrame=ReferenceFrame.FIXED] The reference frame in which the position is defined.
  92507. */
  92508. function TimeIntervalCollectionPositionProperty(referenceFrame) {
  92509. this._definitionChanged = new Event();
  92510. this._intervals = new TimeIntervalCollection();
  92511. this._intervals.changedEvent.addEventListener(TimeIntervalCollectionPositionProperty.prototype._intervalsChanged, this);
  92512. this._referenceFrame = defaultValue(referenceFrame, ReferenceFrame.FIXED);
  92513. }
  92514. defineProperties(TimeIntervalCollectionPositionProperty.prototype, {
  92515. /**
  92516. * Gets a value indicating if this property is constant. A property is considered
  92517. * constant if getValue always returns the same result for the current definition.
  92518. * @memberof TimeIntervalCollectionPositionProperty.prototype
  92519. *
  92520. * @type {Boolean}
  92521. * @readonly
  92522. */
  92523. isConstant : {
  92524. get : function() {
  92525. return this._intervals.isEmpty;
  92526. }
  92527. },
  92528. /**
  92529. * Gets the event that is raised whenever the definition of this property changes.
  92530. * The definition is considered to have changed if a call to getValue would return
  92531. * a different result for the same time.
  92532. * @memberof TimeIntervalCollectionPositionProperty.prototype
  92533. *
  92534. * @type {Event}
  92535. * @readonly
  92536. */
  92537. definitionChanged : {
  92538. get : function() {
  92539. return this._definitionChanged;
  92540. }
  92541. },
  92542. /**
  92543. * Gets the interval collection.
  92544. * @memberof TimeIntervalCollectionPositionProperty.prototype
  92545. * @type {TimeIntervalCollection}
  92546. */
  92547. intervals : {
  92548. get : function() {
  92549. return this._intervals;
  92550. }
  92551. },
  92552. /**
  92553. * Gets the reference frame in which the position is defined.
  92554. * @memberof TimeIntervalCollectionPositionProperty.prototype
  92555. * @type {ReferenceFrame}
  92556. * @default ReferenceFrame.FIXED;
  92557. */
  92558. referenceFrame : {
  92559. get : function() {
  92560. return this._referenceFrame;
  92561. }
  92562. }
  92563. });
  92564. /**
  92565. * Gets the value of the property at the provided time in the fixed frame.
  92566. *
  92567. * @param {JulianDate} time The time for which to retrieve the value.
  92568. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  92569. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  92570. */
  92571. TimeIntervalCollectionPositionProperty.prototype.getValue = function(time, result) {
  92572. return this.getValueInReferenceFrame(time, ReferenceFrame.FIXED, result);
  92573. };
  92574. /**
  92575. * Gets the value of the property at the provided time and in the provided reference frame.
  92576. *
  92577. * @param {JulianDate} time The time for which to retrieve the value.
  92578. * @param {ReferenceFrame} referenceFrame The desired referenceFrame of the result.
  92579. * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
  92580. * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
  92581. */
  92582. TimeIntervalCollectionPositionProperty.prototype.getValueInReferenceFrame = function(time, referenceFrame, result) {
  92583. if (!defined(time)) {
  92584. throw new DeveloperError('time is required.');
  92585. }
  92586. if (!defined(referenceFrame)) {
  92587. throw new DeveloperError('referenceFrame is required.');
  92588. }
  92589. var position = this._intervals.findDataForIntervalContainingDate(time);
  92590. if (defined(position)) {
  92591. return PositionProperty.convertToReferenceFrame(time, position, this._referenceFrame, referenceFrame, result);
  92592. }
  92593. return undefined;
  92594. };
  92595. /**
  92596. * Compares this property to the provided property and returns
  92597. * <code>true</code> if they are equal, <code>false</code> otherwise.
  92598. *
  92599. * @param {Property} [other] The other property.
  92600. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  92601. */
  92602. TimeIntervalCollectionPositionProperty.prototype.equals = function(other) {
  92603. return this === other || //
  92604. (other instanceof TimeIntervalCollectionPositionProperty && //
  92605. this._intervals.equals(other._intervals, Property.equals) && //
  92606. this._referenceFrame === other._referenceFrame);
  92607. };
  92608. /**
  92609. * @private
  92610. */
  92611. TimeIntervalCollectionPositionProperty.prototype._intervalsChanged = function() {
  92612. this._definitionChanged.raiseEvent(this);
  92613. };
  92614. return TimeIntervalCollectionPositionProperty;
  92615. });
  92616. /*global define*/
  92617. define('DataSources/TimeIntervalCollectionProperty',[
  92618. '../Core/defined',
  92619. '../Core/defineProperties',
  92620. '../Core/DeveloperError',
  92621. '../Core/Event',
  92622. '../Core/TimeIntervalCollection',
  92623. './Property'
  92624. ], function(
  92625. defined,
  92626. defineProperties,
  92627. DeveloperError,
  92628. Event,
  92629. TimeIntervalCollection,
  92630. Property) {
  92631. 'use strict';
  92632. /**
  92633. * A {@link Property} which is defined by a {@link TimeIntervalCollection}, where the
  92634. * data property of each {@link TimeInterval} represents the value at time.
  92635. *
  92636. * @alias TimeIntervalCollectionProperty
  92637. * @constructor
  92638. *
  92639. * @example
  92640. * //Create a Cartesian2 interval property which contains data on August 1st, 2012
  92641. * //and uses a different value every 6 hours.
  92642. * var composite = new Cesium.TimeIntervalCollectionProperty();
  92643. * composite.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
  92644. * iso8601 : '2012-08-01T00:00:00.00Z/2012-08-01T06:00:00.00Z',
  92645. * isStartIncluded : true,
  92646. * isStopIncluded : false,
  92647. * data : new Cesium.Cartesian2(2.0, 3.4)
  92648. * }));
  92649. * composite.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
  92650. * iso8601 : '2012-08-01T06:00:00.00Z/2012-08-01T12:00:00.00Z',
  92651. * isStartIncluded : true,
  92652. * isStopIncluded : false,
  92653. * data : new Cesium.Cartesian2(12.0, 2.7)
  92654. * }));
  92655. * composite.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
  92656. * iso8601 : '2012-08-01T12:00:00.00Z/2012-08-01T18:00:00.00Z',
  92657. * isStartIncluded : true,
  92658. * isStopIncluded : false,
  92659. * data : new Cesium.Cartesian2(5.0, 12.4)
  92660. * }));
  92661. * composite.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
  92662. * iso8601 : '2012-08-01T18:00:00.00Z/2012-08-02T00:00:00.00Z',
  92663. * isStartIncluded : true,
  92664. * isStopIncluded : true,
  92665. * data : new Cesium.Cartesian2(85.0, 4.1)
  92666. * }));
  92667. */
  92668. function TimeIntervalCollectionProperty() {
  92669. this._definitionChanged = new Event();
  92670. this._intervals = new TimeIntervalCollection();
  92671. this._intervals.changedEvent.addEventListener(TimeIntervalCollectionProperty.prototype._intervalsChanged, this);
  92672. }
  92673. defineProperties(TimeIntervalCollectionProperty.prototype, {
  92674. /**
  92675. * Gets a value indicating if this property is constant. A property is considered
  92676. * constant if getValue always returns the same result for the current definition.
  92677. * @memberof TimeIntervalCollectionProperty.prototype
  92678. *
  92679. * @type {Boolean}
  92680. * @readonly
  92681. */
  92682. isConstant : {
  92683. get : function() {
  92684. return this._intervals.isEmpty;
  92685. }
  92686. },
  92687. /**
  92688. * Gets the event that is raised whenever the definition of this property changes.
  92689. * The definition is changed whenever setValue is called with data different
  92690. * than the current value.
  92691. * @memberof TimeIntervalCollectionProperty.prototype
  92692. *
  92693. * @type {Event}
  92694. * @readonly
  92695. */
  92696. definitionChanged : {
  92697. get : function() {
  92698. return this._definitionChanged;
  92699. }
  92700. },
  92701. /**
  92702. * Gets the interval collection.
  92703. * @memberof TimeIntervalCollectionProperty.prototype
  92704. *
  92705. * @type {TimeIntervalCollection}
  92706. */
  92707. intervals : {
  92708. get : function() {
  92709. return this._intervals;
  92710. }
  92711. }
  92712. });
  92713. /**
  92714. * Gets the value of the property at the provided time.
  92715. *
  92716. * @param {JulianDate} time The time for which to retrieve the value.
  92717. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  92718. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  92719. */
  92720. TimeIntervalCollectionProperty.prototype.getValue = function(time, result) {
  92721. if (!defined(time)) {
  92722. throw new DeveloperError('time is required');
  92723. }
  92724. var value = this._intervals.findDataForIntervalContainingDate(time);
  92725. if (defined(value) && (typeof value.clone === 'function')) {
  92726. return value.clone(result);
  92727. }
  92728. return value;
  92729. };
  92730. /**
  92731. * Compares this property to the provided property and returns
  92732. * <code>true</code> if they are equal, <code>false</code> otherwise.
  92733. *
  92734. * @param {Property} [other] The other property.
  92735. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  92736. */
  92737. TimeIntervalCollectionProperty.prototype.equals = function(other) {
  92738. return this === other || //
  92739. (other instanceof TimeIntervalCollectionProperty && //
  92740. this._intervals.equals(other._intervals, Property.equals));
  92741. };
  92742. /**
  92743. * @private
  92744. */
  92745. TimeIntervalCollectionProperty.prototype._intervalsChanged = function() {
  92746. this._definitionChanged.raiseEvent(this);
  92747. };
  92748. return TimeIntervalCollectionProperty;
  92749. });
  92750. /*global define*/
  92751. define('DataSources/VelocityVectorProperty',[
  92752. '../Core/Cartesian3',
  92753. '../Core/defaultValue',
  92754. '../Core/defined',
  92755. '../Core/defineProperties',
  92756. '../Core/DeveloperError',
  92757. '../Core/Event',
  92758. '../Core/JulianDate',
  92759. './Property'
  92760. ], function(
  92761. Cartesian3,
  92762. defaultValue,
  92763. defined,
  92764. defineProperties,
  92765. DeveloperError,
  92766. Event,
  92767. JulianDate,
  92768. Property) {
  92769. 'use strict';
  92770. /**
  92771. * A {@link Property} which evaluates to a {@link Cartesian3} vector
  92772. * based on the velocity of the provided {@link PositionProperty}.
  92773. *
  92774. * @alias VelocityVectorProperty
  92775. * @constructor
  92776. *
  92777. * @param {Property} [position] The position property used to compute the velocity.
  92778. * @param {Boolean} [normalize=true] Whether to normalize the computed velocity vector.
  92779. *
  92780. * @example
  92781. * //Create an entity with a billboard rotated to match its velocity.
  92782. * var position = new Cesium.SampledProperty();
  92783. * position.addSamples(...);
  92784. * var entity = viewer.entities.add({
  92785. * position : position,
  92786. * billboard : {
  92787. * image : 'image.png',
  92788. * alignedAxis : new Cesium.VelocityVectorProperty(position, true) // alignedAxis must be a unit vector
  92789. * }
  92790. * }));
  92791. */
  92792. function VelocityVectorProperty(position, normalize) {
  92793. this._position = undefined;
  92794. this._subscription = undefined;
  92795. this._definitionChanged = new Event();
  92796. this._normalize = defaultValue(normalize, true);
  92797. this.position = position;
  92798. }
  92799. defineProperties(VelocityVectorProperty.prototype, {
  92800. /**
  92801. * Gets a value indicating if this property is constant.
  92802. * @memberof VelocityVectorProperty.prototype
  92803. *
  92804. * @type {Boolean}
  92805. * @readonly
  92806. */
  92807. isConstant : {
  92808. get : function() {
  92809. return Property.isConstant(this._position);
  92810. }
  92811. },
  92812. /**
  92813. * Gets the event that is raised whenever the definition of this property changes.
  92814. * @memberof VelocityVectorProperty.prototype
  92815. *
  92816. * @type {Event}
  92817. * @readonly
  92818. */
  92819. definitionChanged : {
  92820. get : function() {
  92821. return this._definitionChanged;
  92822. }
  92823. },
  92824. /**
  92825. * Gets or sets the position property used to compute the velocity vector.
  92826. * @memberof VelocityVectorProperty.prototype
  92827. *
  92828. * @type {Property}
  92829. */
  92830. position : {
  92831. get : function() {
  92832. return this._position;
  92833. },
  92834. set : function(value) {
  92835. var oldValue = this._position;
  92836. if (oldValue !== value) {
  92837. if (defined(oldValue)) {
  92838. this._subscription();
  92839. }
  92840. this._position = value;
  92841. if (defined(value)) {
  92842. this._subscription = value._definitionChanged.addEventListener(function() {
  92843. this._definitionChanged.raiseEvent(this);
  92844. }, this);
  92845. }
  92846. this._definitionChanged.raiseEvent(this);
  92847. }
  92848. }
  92849. },
  92850. /**
  92851. * Gets or sets whether the vector produced by this property
  92852. * will be normalized or not.
  92853. * @memberof VelocityVectorProperty.prototype
  92854. *
  92855. * @type {Boolean}
  92856. */
  92857. normalize : {
  92858. get : function() {
  92859. return this._normalize;
  92860. },
  92861. set : function(value) {
  92862. if (this._normalize === value) {
  92863. return;
  92864. }
  92865. this._normalize = value;
  92866. this._definitionChanged.raiseEvent(this);
  92867. }
  92868. }
  92869. });
  92870. var position1Scratch = new Cartesian3();
  92871. var position2Scratch = new Cartesian3();
  92872. var timeScratch = new JulianDate();
  92873. var step = 1.0 / 60.0;
  92874. /**
  92875. * Gets the value of the property at the provided time.
  92876. *
  92877. * @param {JulianDate} [time] The time for which to retrieve the value.
  92878. * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
  92879. * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
  92880. */
  92881. VelocityVectorProperty.prototype.getValue = function(time, result) {
  92882. return this._getValue(time, result);
  92883. };
  92884. /**
  92885. * @private
  92886. */
  92887. VelocityVectorProperty.prototype._getValue = function(time, velocityResult, positionResult) {
  92888. if (!defined(time)) {
  92889. throw new DeveloperError('time is required');
  92890. }
  92891. if (!defined(velocityResult)) {
  92892. velocityResult = new Cartesian3();
  92893. }
  92894. var property = this._position;
  92895. if (Property.isConstant(property)) {
  92896. return this._normalize ? undefined : Cartesian3.clone(Cartesian3.ZERO, velocityResult);
  92897. }
  92898. var position1 = property.getValue(time, position1Scratch);
  92899. var position2 = property.getValue(JulianDate.addSeconds(time, step, timeScratch), position2Scratch);
  92900. //If we don't have a position for now, return undefined.
  92901. if (!defined(position1)) {
  92902. return undefined;
  92903. }
  92904. //If we don't have a position for now + step, see if we have a position for now - step.
  92905. if (!defined(position2)) {
  92906. position2 = position1;
  92907. position1 = property.getValue(JulianDate.addSeconds(time, -step, timeScratch), position2Scratch);
  92908. if (!defined(position1)) {
  92909. return undefined;
  92910. }
  92911. }
  92912. if (Cartesian3.equals(position1, position2)) {
  92913. return this._normalize ? undefined : Cartesian3.clone(Cartesian3.ZERO, velocityResult);
  92914. }
  92915. if (defined(positionResult)) {
  92916. position1.clone(positionResult);
  92917. }
  92918. var velocity = Cartesian3.subtract(position2, position1, velocityResult);
  92919. if (this._normalize) {
  92920. return Cartesian3.normalize(velocity, velocityResult);
  92921. } else {
  92922. return Cartesian3.divideByScalar(velocity, step, velocityResult);
  92923. }
  92924. };
  92925. /**
  92926. * Compares this property to the provided property and returns
  92927. * <code>true</code> if they are equal, <code>false</code> otherwise.
  92928. *
  92929. * @param {Property} [other] The other property.
  92930. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  92931. */
  92932. VelocityVectorProperty.prototype.equals = function(other) {
  92933. return this === other ||//
  92934. (other instanceof VelocityVectorProperty &&
  92935. Property.equals(this._position, other._position));
  92936. };
  92937. return VelocityVectorProperty;
  92938. });
  92939. /*global define*/
  92940. define('DataSources/CzmlDataSource',[
  92941. '../Core/BoundingRectangle',
  92942. '../Core/Cartesian2',
  92943. '../Core/Cartesian3',
  92944. '../Core/Cartographic',
  92945. '../Core/ClockRange',
  92946. '../Core/ClockStep',
  92947. '../Core/Color',
  92948. '../Core/CornerType',
  92949. '../Core/createGuid',
  92950. '../Core/defaultValue',
  92951. '../Core/defined',
  92952. '../Core/defineProperties',
  92953. '../Core/DeveloperError',
  92954. '../Core/Ellipsoid',
  92955. '../Core/Event',
  92956. '../Core/ExtrapolationType',
  92957. '../Core/getAbsoluteUri',
  92958. '../Core/getFilenameFromUri',
  92959. '../Core/HermitePolynomialApproximation',
  92960. '../Core/isArray',
  92961. '../Core/Iso8601',
  92962. '../Core/JulianDate',
  92963. '../Core/LagrangePolynomialApproximation',
  92964. '../Core/LinearApproximation',
  92965. '../Core/loadJson',
  92966. '../Core/Math',
  92967. '../Core/NearFarScalar',
  92968. '../Core/Quaternion',
  92969. '../Core/Rectangle',
  92970. '../Core/ReferenceFrame',
  92971. '../Core/RuntimeError',
  92972. '../Core/Spherical',
  92973. '../Core/TimeInterval',
  92974. '../Core/TimeIntervalCollection',
  92975. '../Scene/ColorBlendMode',
  92976. '../Scene/HeightReference',
  92977. '../Scene/HorizontalOrigin',
  92978. '../Scene/LabelStyle',
  92979. '../Scene/ShadowMode',
  92980. '../Scene/VerticalOrigin',
  92981. '../ThirdParty/Uri',
  92982. '../ThirdParty/when',
  92983. './BillboardGraphics',
  92984. './BoxGraphics',
  92985. './ColorMaterialProperty',
  92986. './CompositeMaterialProperty',
  92987. './CompositePositionProperty',
  92988. './CompositeProperty',
  92989. './ConstantPositionProperty',
  92990. './ConstantProperty',
  92991. './CorridorGraphics',
  92992. './CylinderGraphics',
  92993. './DataSource',
  92994. './DataSourceClock',
  92995. './EllipseGraphics',
  92996. './EllipsoidGraphics',
  92997. './EntityCluster',
  92998. './EntityCollection',
  92999. './GridMaterialProperty',
  93000. './ImageMaterialProperty',
  93001. './LabelGraphics',
  93002. './ModelGraphics',
  93003. './NodeTransformationProperty',
  93004. './PathGraphics',
  93005. './PointGraphics',
  93006. './PolygonGraphics',
  93007. './PolylineArrowMaterialProperty',
  93008. './PolylineGlowMaterialProperty',
  93009. './PolylineGraphics',
  93010. './PolylineOutlineMaterialProperty',
  93011. './PositionPropertyArray',
  93012. './PropertyArray',
  93013. './PropertyBag',
  93014. './RectangleGraphics',
  93015. './ReferenceProperty',
  93016. './Rotation',
  93017. './SampledPositionProperty',
  93018. './SampledProperty',
  93019. './StripeMaterialProperty',
  93020. './StripeOrientation',
  93021. './TimeIntervalCollectionPositionProperty',
  93022. './TimeIntervalCollectionProperty',
  93023. './VelocityVectorProperty',
  93024. './WallGraphics'
  93025. ], function(
  93026. BoundingRectangle,
  93027. Cartesian2,
  93028. Cartesian3,
  93029. Cartographic,
  93030. ClockRange,
  93031. ClockStep,
  93032. Color,
  93033. CornerType,
  93034. createGuid,
  93035. defaultValue,
  93036. defined,
  93037. defineProperties,
  93038. DeveloperError,
  93039. Ellipsoid,
  93040. Event,
  93041. ExtrapolationType,
  93042. getAbsoluteUri,
  93043. getFilenameFromUri,
  93044. HermitePolynomialApproximation,
  93045. isArray,
  93046. Iso8601,
  93047. JulianDate,
  93048. LagrangePolynomialApproximation,
  93049. LinearApproximation,
  93050. loadJson,
  93051. CesiumMath,
  93052. NearFarScalar,
  93053. Quaternion,
  93054. Rectangle,
  93055. ReferenceFrame,
  93056. RuntimeError,
  93057. Spherical,
  93058. TimeInterval,
  93059. TimeIntervalCollection,
  93060. ColorBlendMode,
  93061. HeightReference,
  93062. HorizontalOrigin,
  93063. LabelStyle,
  93064. ShadowMode,
  93065. VerticalOrigin,
  93066. Uri,
  93067. when,
  93068. BillboardGraphics,
  93069. BoxGraphics,
  93070. ColorMaterialProperty,
  93071. CompositeMaterialProperty,
  93072. CompositePositionProperty,
  93073. CompositeProperty,
  93074. ConstantPositionProperty,
  93075. ConstantProperty,
  93076. CorridorGraphics,
  93077. CylinderGraphics,
  93078. DataSource,
  93079. DataSourceClock,
  93080. EllipseGraphics,
  93081. EllipsoidGraphics,
  93082. EntityCluster,
  93083. EntityCollection,
  93084. GridMaterialProperty,
  93085. ImageMaterialProperty,
  93086. LabelGraphics,
  93087. ModelGraphics,
  93088. NodeTransformationProperty,
  93089. PathGraphics,
  93090. PointGraphics,
  93091. PolygonGraphics,
  93092. PolylineArrowMaterialProperty,
  93093. PolylineGlowMaterialProperty,
  93094. PolylineGraphics,
  93095. PolylineOutlineMaterialProperty,
  93096. PositionPropertyArray,
  93097. PropertyArray,
  93098. PropertyBag,
  93099. RectangleGraphics,
  93100. ReferenceProperty,
  93101. Rotation,
  93102. SampledPositionProperty,
  93103. SampledProperty,
  93104. StripeMaterialProperty,
  93105. StripeOrientation,
  93106. TimeIntervalCollectionPositionProperty,
  93107. TimeIntervalCollectionProperty,
  93108. VelocityVectorProperty,
  93109. WallGraphics) {
  93110. 'use strict';
  93111. var currentId;
  93112. function makeReference(collection, referenceString) {
  93113. if (referenceString[0] === '#') {
  93114. referenceString = currentId + referenceString;
  93115. }
  93116. return ReferenceProperty.fromString(collection, referenceString);
  93117. }
  93118. var scratchCartesian = new Cartesian3();
  93119. var scratchSpherical = new Spherical();
  93120. var scratchCartographic = new Cartographic();
  93121. var scratchTimeInterval = new TimeInterval();
  93122. function unwrapColorInterval(czmlInterval) {
  93123. var rgbaf = czmlInterval.rgbaf;
  93124. if (defined(rgbaf)) {
  93125. return rgbaf;
  93126. }
  93127. var rgba = czmlInterval.rgba;
  93128. if (!defined(rgba)) {
  93129. return undefined;
  93130. }
  93131. var length = rgba.length;
  93132. if (length === Color.packedLength) {
  93133. return [Color.byteToFloat(rgba[0]), Color.byteToFloat(rgba[1]), Color.byteToFloat(rgba[2]), Color.byteToFloat(rgba[3])];
  93134. }
  93135. rgbaf = new Array(length);
  93136. for (var i = 0; i < length; i += 5) {
  93137. rgbaf[i] = rgba[i];
  93138. rgbaf[i + 1] = Color.byteToFloat(rgba[i + 1]);
  93139. rgbaf[i + 2] = Color.byteToFloat(rgba[i + 2]);
  93140. rgbaf[i + 3] = Color.byteToFloat(rgba[i + 3]);
  93141. rgbaf[i + 4] = Color.byteToFloat(rgba[i + 4]);
  93142. }
  93143. return rgbaf;
  93144. }
  93145. function unwrapUriInterval(czmlInterval, sourceUri) {
  93146. var result = defaultValue(czmlInterval.uri, czmlInterval);
  93147. if (defined(sourceUri)) {
  93148. result = getAbsoluteUri(result, getAbsoluteUri(sourceUri));
  93149. }
  93150. return result;
  93151. }
  93152. function unwrapRectangleInterval(czmlInterval) {
  93153. var wsen = czmlInterval.wsen;
  93154. if (defined(wsen)) {
  93155. return wsen;
  93156. }
  93157. var wsenDegrees = czmlInterval.wsenDegrees;
  93158. if (!defined(wsenDegrees)) {
  93159. return undefined;
  93160. }
  93161. var length = wsenDegrees.length;
  93162. if (length === Rectangle.packedLength) {
  93163. return [CesiumMath.toRadians(wsenDegrees[0]), CesiumMath.toRadians(wsenDegrees[1]), CesiumMath.toRadians(wsenDegrees[2]), CesiumMath.toRadians(wsenDegrees[3])];
  93164. }
  93165. wsen = new Array(length);
  93166. for (var i = 0; i < length; i += 5) {
  93167. wsen[i] = wsenDegrees[i];
  93168. wsen[i + 1] = CesiumMath.toRadians(wsenDegrees[i + 1]);
  93169. wsen[i + 2] = CesiumMath.toRadians(wsenDegrees[i + 2]);
  93170. wsen[i + 3] = CesiumMath.toRadians(wsenDegrees[i + 3]);
  93171. wsen[i + 4] = CesiumMath.toRadians(wsenDegrees[i + 4]);
  93172. }
  93173. return wsen;
  93174. }
  93175. function convertUnitSphericalToCartesian(unitSpherical) {
  93176. var length = unitSpherical.length;
  93177. scratchSpherical.magnitude = 1.0;
  93178. if (length === 2) {
  93179. scratchSpherical.clock = unitSpherical[0];
  93180. scratchSpherical.cone = unitSpherical[1];
  93181. Cartesian3.fromSpherical(scratchSpherical, scratchCartesian);
  93182. return [scratchCartesian.x, scratchCartesian.y, scratchCartesian.z];
  93183. } else {
  93184. var result = new Array(length / 3 * 4);
  93185. for (var i = 0, j = 0; i < length; i += 3, j += 4) {
  93186. result[j] = unitSpherical[i];
  93187. scratchSpherical.clock = unitSpherical[i + 1];
  93188. scratchSpherical.cone = unitSpherical[i + 2];
  93189. Cartesian3.fromSpherical(scratchSpherical, scratchCartesian);
  93190. result[j + 1] = scratchCartesian.x;
  93191. result[j + 2] = scratchCartesian.y;
  93192. result[j + 3] = scratchCartesian.z;
  93193. }
  93194. return result;
  93195. }
  93196. }
  93197. function convertSphericalToCartesian(spherical) {
  93198. var length = spherical.length;
  93199. if (length === 3) {
  93200. scratchSpherical.clock = spherical[0];
  93201. scratchSpherical.cone = spherical[1];
  93202. scratchSpherical.magnitude = spherical[2];
  93203. Cartesian3.fromSpherical(scratchSpherical, scratchCartesian);
  93204. return [scratchCartesian.x, scratchCartesian.y, scratchCartesian.z];
  93205. } else {
  93206. var result = new Array(length);
  93207. for (var i = 0; i < length; i += 4) {
  93208. result[i] = spherical[i];
  93209. scratchSpherical.clock = spherical[i + 1];
  93210. scratchSpherical.cone = spherical[i + 2];
  93211. scratchSpherical.magnitude = spherical[i + 3];
  93212. Cartesian3.fromSpherical(scratchSpherical, scratchCartesian);
  93213. result[i + 1] = scratchCartesian.x;
  93214. result[i + 2] = scratchCartesian.y;
  93215. result[i + 3] = scratchCartesian.z;
  93216. }
  93217. return result;
  93218. }
  93219. }
  93220. function convertCartographicRadiansToCartesian(cartographicRadians) {
  93221. var length = cartographicRadians.length;
  93222. if (length === 3) {
  93223. scratchCartographic.longitude = cartographicRadians[0];
  93224. scratchCartographic.latitude = cartographicRadians[1];
  93225. scratchCartographic.height = cartographicRadians[2];
  93226. Ellipsoid.WGS84.cartographicToCartesian(scratchCartographic, scratchCartesian);
  93227. return [scratchCartesian.x, scratchCartesian.y, scratchCartesian.z];
  93228. } else {
  93229. var result = new Array(length);
  93230. for (var i = 0; i < length; i += 4) {
  93231. result[i] = cartographicRadians[i];
  93232. scratchCartographic.longitude = cartographicRadians[i + 1];
  93233. scratchCartographic.latitude = cartographicRadians[i + 2];
  93234. scratchCartographic.height = cartographicRadians[i + 3];
  93235. Ellipsoid.WGS84.cartographicToCartesian(scratchCartographic, scratchCartesian);
  93236. result[i + 1] = scratchCartesian.x;
  93237. result[i + 2] = scratchCartesian.y;
  93238. result[i + 3] = scratchCartesian.z;
  93239. }
  93240. return result;
  93241. }
  93242. }
  93243. function convertCartographicDegreesToCartesian(cartographicDegrees) {
  93244. var length = cartographicDegrees.length;
  93245. if (length === 3) {
  93246. scratchCartographic.longitude = CesiumMath.toRadians(cartographicDegrees[0]);
  93247. scratchCartographic.latitude = CesiumMath.toRadians(cartographicDegrees[1]);
  93248. scratchCartographic.height = cartographicDegrees[2];
  93249. Ellipsoid.WGS84.cartographicToCartesian(scratchCartographic, scratchCartesian);
  93250. return [scratchCartesian.x, scratchCartesian.y, scratchCartesian.z];
  93251. } else {
  93252. var result = new Array(length);
  93253. for (var i = 0; i < length; i += 4) {
  93254. result[i] = cartographicDegrees[i];
  93255. scratchCartographic.longitude = CesiumMath.toRadians(cartographicDegrees[i + 1]);
  93256. scratchCartographic.latitude = CesiumMath.toRadians(cartographicDegrees[i + 2]);
  93257. scratchCartographic.height = cartographicDegrees[i + 3];
  93258. Ellipsoid.WGS84.cartographicToCartesian(scratchCartographic, scratchCartesian);
  93259. result[i + 1] = scratchCartesian.x;
  93260. result[i + 2] = scratchCartesian.y;
  93261. result[i + 3] = scratchCartesian.z;
  93262. }
  93263. return result;
  93264. }
  93265. }
  93266. function unwrapCartesianInterval(czmlInterval) {
  93267. var cartesian = czmlInterval.cartesian;
  93268. if (defined(cartesian)) {
  93269. return cartesian;
  93270. }
  93271. var cartesianVelocity = czmlInterval.cartesianVelocity;
  93272. if (defined(cartesianVelocity)) {
  93273. return cartesianVelocity;
  93274. }
  93275. var unitCartesian = czmlInterval.unitCartesian;
  93276. if (defined(unitCartesian)) {
  93277. return unitCartesian;
  93278. }
  93279. var unitSpherical = czmlInterval.unitSpherical;
  93280. if (defined(unitSpherical)) {
  93281. return convertUnitSphericalToCartesian(unitSpherical);
  93282. }
  93283. var spherical = czmlInterval.spherical;
  93284. if (defined(spherical)) {
  93285. return convertSphericalToCartesian(spherical);
  93286. }
  93287. var cartographicRadians = czmlInterval.cartographicRadians;
  93288. if (defined(cartographicRadians)) {
  93289. return convertCartographicRadiansToCartesian(cartographicRadians);
  93290. }
  93291. var cartographicDegrees = czmlInterval.cartographicDegrees;
  93292. if (defined(cartographicDegrees)) {
  93293. return convertCartographicDegreesToCartesian(cartographicDegrees);
  93294. }
  93295. throw new RuntimeError(JSON.stringify(czmlInterval) + ' is not a valid CZML interval.');
  93296. }
  93297. function normalizePackedQuaternionArray(array, startingIndex) {
  93298. var x = array[startingIndex];
  93299. var y = array[startingIndex + 1];
  93300. var z = array[startingIndex + 2];
  93301. var w = array[startingIndex + 3];
  93302. var inverseMagnitude = 1.0 / Math.sqrt(x * x + y * y + z * z + w * w);
  93303. array[startingIndex] = x * inverseMagnitude;
  93304. array[startingIndex + 1] = y * inverseMagnitude;
  93305. array[startingIndex + 2] = z * inverseMagnitude;
  93306. array[startingIndex + 3] = w * inverseMagnitude;
  93307. }
  93308. function unwrapQuaternionInterval(czmlInterval) {
  93309. var unitQuaternion = czmlInterval.unitQuaternion;
  93310. if (defined(unitQuaternion)) {
  93311. if (unitQuaternion.length === 4) {
  93312. normalizePackedQuaternionArray(unitQuaternion, 0);
  93313. return unitQuaternion;
  93314. }
  93315. for (var i = 1; i < unitQuaternion.length; i += 5) {
  93316. normalizePackedQuaternionArray(unitQuaternion, i);
  93317. }
  93318. }
  93319. return unitQuaternion;
  93320. }
  93321. function unwrapInterval(type, czmlInterval, sourceUri) {
  93322. /*jshint sub:true*/
  93323. switch (type) {
  93324. case Array:
  93325. return czmlInterval.array;
  93326. case Boolean:
  93327. return defaultValue(czmlInterval['boolean'], czmlInterval);
  93328. case BoundingRectangle:
  93329. return czmlInterval.boundingRectangle;
  93330. case Cartesian2:
  93331. return czmlInterval.cartesian2;
  93332. case Cartesian3:
  93333. return unwrapCartesianInterval(czmlInterval);
  93334. case Color:
  93335. return unwrapColorInterval(czmlInterval);
  93336. case ColorBlendMode:
  93337. return ColorBlendMode[defaultValue(czmlInterval.colorBlendMode, czmlInterval)];
  93338. case CornerType:
  93339. return CornerType[defaultValue(czmlInterval.cornerType, czmlInterval)];
  93340. case HeightReference:
  93341. return HeightReference[defaultValue(czmlInterval.heightReference, czmlInterval)];
  93342. case HorizontalOrigin:
  93343. return HorizontalOrigin[defaultValue(czmlInterval.horizontalOrigin, czmlInterval)];
  93344. case Image:
  93345. return unwrapUriInterval(czmlInterval, sourceUri);
  93346. case JulianDate:
  93347. return JulianDate.fromIso8601(defaultValue(czmlInterval.date, czmlInterval));
  93348. case LabelStyle:
  93349. return LabelStyle[defaultValue(czmlInterval.labelStyle, czmlInterval)];
  93350. case Number:
  93351. return defaultValue(czmlInterval.number, czmlInterval);
  93352. case NearFarScalar:
  93353. return czmlInterval.nearFarScalar;
  93354. case Quaternion:
  93355. return unwrapQuaternionInterval(czmlInterval);
  93356. case Rotation:
  93357. return defaultValue(czmlInterval.number, czmlInterval);
  93358. case ShadowMode:
  93359. return ShadowMode[defaultValue(czmlInterval.shadows, czmlInterval)];
  93360. case String:
  93361. return defaultValue(czmlInterval.string, czmlInterval);
  93362. case StripeOrientation:
  93363. return StripeOrientation[defaultValue(czmlInterval.stripeOrientation, czmlInterval)];
  93364. case Rectangle:
  93365. return unwrapRectangleInterval(czmlInterval);
  93366. case Uri:
  93367. return unwrapUriInterval(czmlInterval, sourceUri);
  93368. case VerticalOrigin:
  93369. return VerticalOrigin[defaultValue(czmlInterval.verticalOrigin, czmlInterval)];
  93370. default:
  93371. throw new RuntimeError(type);
  93372. }
  93373. }
  93374. var interpolators = {
  93375. HERMITE : HermitePolynomialApproximation,
  93376. LAGRANGE : LagrangePolynomialApproximation,
  93377. LINEAR : LinearApproximation
  93378. };
  93379. function updateInterpolationSettings(packetData, property) {
  93380. var interpolationAlgorithm = packetData.interpolationAlgorithm;
  93381. if (defined(interpolationAlgorithm) || defined(packetData.interpolationDegree)) {
  93382. property.setInterpolationOptions({
  93383. interpolationAlgorithm : interpolators[interpolationAlgorithm],
  93384. interpolationDegree : packetData.interpolationDegree
  93385. });
  93386. }
  93387. var forwardExtrapolationType = packetData.forwardExtrapolationType;
  93388. if (defined(forwardExtrapolationType)) {
  93389. property.forwardExtrapolationType = ExtrapolationType[forwardExtrapolationType];
  93390. }
  93391. var forwardExtrapolationDuration = packetData.forwardExtrapolationDuration;
  93392. if (defined(forwardExtrapolationDuration)) {
  93393. property.forwardExtrapolationDuration = forwardExtrapolationDuration;
  93394. }
  93395. var backwardExtrapolationType = packetData.backwardExtrapolationType;
  93396. if (defined(backwardExtrapolationType)) {
  93397. property.backwardExtrapolationType = ExtrapolationType[backwardExtrapolationType];
  93398. }
  93399. var backwardExtrapolationDuration = packetData.backwardExtrapolationDuration;
  93400. if (defined(backwardExtrapolationDuration)) {
  93401. property.backwardExtrapolationDuration = backwardExtrapolationDuration;
  93402. }
  93403. }
  93404. function processProperty(type, object, propertyName, packetData, constrainedInterval, sourceUri, entityCollection) {
  93405. var combinedInterval;
  93406. var packetInterval = packetData.interval;
  93407. if (defined(packetInterval)) {
  93408. iso8601Scratch.iso8601 = packetInterval;
  93409. combinedInterval = TimeInterval.fromIso8601(iso8601Scratch);
  93410. if (defined(constrainedInterval)) {
  93411. combinedInterval = TimeInterval.intersect(combinedInterval, constrainedInterval, scratchTimeInterval);
  93412. }
  93413. } else if (defined(constrainedInterval)) {
  93414. combinedInterval = constrainedInterval;
  93415. }
  93416. var packedLength;
  93417. var isSampled;
  93418. var unwrappedInterval;
  93419. var unwrappedIntervalLength;
  93420. var isReference = defined(packetData.reference);
  93421. var hasInterval = defined(combinedInterval) && !combinedInterval.equals(Iso8601.MAXIMUM_INTERVAL);
  93422. if (!isReference) {
  93423. unwrappedInterval = unwrapInterval(type, packetData, sourceUri);
  93424. packedLength = defaultValue(type.packedLength, 1);
  93425. unwrappedIntervalLength = defaultValue(unwrappedInterval.length, 1);
  93426. isSampled = !defined(packetData.array) && (typeof unwrappedInterval !== 'string') && unwrappedIntervalLength > packedLength;
  93427. }
  93428. //Rotation is a special case because it represents a native type (Number)
  93429. //and therefore does not need to be unpacked when loaded as a constant value.
  93430. var needsUnpacking = typeof type.unpack === 'function' && type !== Rotation;
  93431. //Any time a constant value is assigned, it completely blows away anything else.
  93432. if (!isSampled && !hasInterval) {
  93433. if (isReference) {
  93434. object[propertyName] = makeReference(entityCollection, packetData.reference);
  93435. } else if (needsUnpacking) {
  93436. object[propertyName] = new ConstantProperty(type.unpack(unwrappedInterval, 0));
  93437. } else {
  93438. object[propertyName] = new ConstantProperty(unwrappedInterval);
  93439. }
  93440. return;
  93441. }
  93442. var property = object[propertyName];
  93443. var epoch;
  93444. var packetEpoch = packetData.epoch;
  93445. if (defined(packetEpoch)) {
  93446. epoch = JulianDate.fromIso8601(packetEpoch);
  93447. }
  93448. //Without an interval, any sampled value is infinite, meaning it completely
  93449. //replaces any non-sampled property that may exist.
  93450. if (isSampled && !hasInterval) {
  93451. if (!(property instanceof SampledProperty)) {
  93452. property = new SampledProperty(type);
  93453. object[propertyName] = property;
  93454. }
  93455. property.addSamplesPackedArray(unwrappedInterval, epoch);
  93456. updateInterpolationSettings(packetData, property);
  93457. return;
  93458. }
  93459. var interval;
  93460. //A constant value with an interval is normally part of a TimeIntervalCollection,
  93461. //However, if the current property is not a time-interval collection, we need
  93462. //to turn it into a Composite, preserving the old data with the new interval.
  93463. if (!isSampled && hasInterval) {
  93464. //Create a new interval for the constant value.
  93465. combinedInterval = combinedInterval.clone();
  93466. if (isReference) {
  93467. combinedInterval.data = makeReference(entityCollection, packetData.reference);
  93468. } else if (needsUnpacking) {
  93469. combinedInterval.data = type.unpack(unwrappedInterval, 0);
  93470. } else {
  93471. combinedInterval.data = unwrappedInterval;
  93472. }
  93473. //If no property exists, simply use a new interval collection
  93474. if (!defined(property)) {
  93475. if (isReference) {
  93476. property = new CompositeProperty();
  93477. } else {
  93478. property = new TimeIntervalCollectionProperty();
  93479. }
  93480. object[propertyName] = property;
  93481. }
  93482. if (!isReference && property instanceof TimeIntervalCollectionProperty) {
  93483. //If we create a collection, or it already existed, use it.
  93484. property.intervals.addInterval(combinedInterval);
  93485. } else if (property instanceof CompositeProperty) {
  93486. //If the collection was already a CompositeProperty, use it.
  93487. combinedInterval.data = isReference ? combinedInterval.data : new ConstantProperty(combinedInterval.data);
  93488. property.intervals.addInterval(combinedInterval);
  93489. } else {
  93490. //Otherwise, create a CompositeProperty but preserve the existing data.
  93491. //Put the old property in an infinite interval.
  93492. interval = Iso8601.MAXIMUM_INTERVAL.clone();
  93493. interval.data = property;
  93494. //Create the composite.
  93495. property = new CompositeProperty();
  93496. object[propertyName] = property;
  93497. //add the old property interval
  93498. property.intervals.addInterval(interval);
  93499. //Change the new data to a ConstantProperty and add it.
  93500. combinedInterval.data = isReference ? combinedInterval.data : new ConstantProperty(combinedInterval.data);
  93501. property.intervals.addInterval(combinedInterval);
  93502. }
  93503. return;
  93504. }
  93505. //isSampled && hasInterval
  93506. if (!defined(property)) {
  93507. property = new CompositeProperty();
  93508. object[propertyName] = property;
  93509. }
  93510. //create a CompositeProperty but preserve the existing data.
  93511. if (!(property instanceof CompositeProperty)) {
  93512. //Put the old property in an infinite interval.
  93513. interval = Iso8601.MAXIMUM_INTERVAL.clone();
  93514. interval.data = property;
  93515. //Create the composite.
  93516. property = new CompositeProperty();
  93517. object[propertyName] = property;
  93518. //add the old property interval
  93519. property.intervals.addInterval(interval);
  93520. }
  93521. //Check if the interval already exists in the composite
  93522. var intervals = property.intervals;
  93523. interval = intervals.findInterval(combinedInterval);
  93524. if (!defined(interval) || !(interval.data instanceof SampledProperty)) {
  93525. //If not, create a SampledProperty for it.
  93526. interval = combinedInterval.clone();
  93527. interval.data = new SampledProperty(type);
  93528. intervals.addInterval(interval);
  93529. }
  93530. interval.data.addSamplesPackedArray(unwrappedInterval, epoch);
  93531. updateInterpolationSettings(packetData, interval.data);
  93532. }
  93533. function processPacketData(type, object, propertyName, packetData, interval, sourceUri, entityCollection) {
  93534. if (!defined(packetData)) {
  93535. return;
  93536. }
  93537. if (isArray(packetData)) {
  93538. for (var i = 0, len = packetData.length; i < len; i++) {
  93539. processProperty(type, object, propertyName, packetData[i], interval, sourceUri, entityCollection);
  93540. }
  93541. } else {
  93542. processProperty(type, object, propertyName, packetData, interval, sourceUri, entityCollection);
  93543. }
  93544. }
  93545. function processPositionProperty(object, propertyName, packetData, constrainedInterval, sourceUri, entityCollection) {
  93546. var combinedInterval;
  93547. var packetInterval = packetData.interval;
  93548. if (defined(packetInterval)) {
  93549. iso8601Scratch.iso8601 = packetInterval;
  93550. combinedInterval = TimeInterval.fromIso8601(iso8601Scratch);
  93551. if (defined(constrainedInterval)) {
  93552. combinedInterval = TimeInterval.intersect(combinedInterval, constrainedInterval, scratchTimeInterval);
  93553. }
  93554. } else if (defined(constrainedInterval)) {
  93555. combinedInterval = constrainedInterval;
  93556. }
  93557. var referenceFrame;
  93558. var unwrappedInterval;
  93559. var isSampled = false;
  93560. var unwrappedIntervalLength;
  93561. var numberOfDerivatives = defined(packetData.cartesianVelocity) ? 1 : 0;
  93562. var packedLength = Cartesian3.packedLength * (numberOfDerivatives + 1);
  93563. var isReference = defined(packetData.reference);
  93564. var hasInterval = defined(combinedInterval) && !combinedInterval.equals(Iso8601.MAXIMUM_INTERVAL);
  93565. if (!isReference) {
  93566. if (defined(packetData.referenceFrame)) {
  93567. referenceFrame = ReferenceFrame[packetData.referenceFrame];
  93568. }
  93569. referenceFrame = defaultValue(referenceFrame, ReferenceFrame.FIXED);
  93570. unwrappedInterval = unwrapCartesianInterval(packetData);
  93571. unwrappedIntervalLength = defaultValue(unwrappedInterval.length, 1);
  93572. isSampled = unwrappedIntervalLength > packedLength;
  93573. }
  93574. //Any time a constant value is assigned, it completely blows away anything else.
  93575. if (!isSampled && !hasInterval) {
  93576. if (isReference) {
  93577. object[propertyName] = makeReference(entityCollection, packetData.reference);
  93578. } else {
  93579. object[propertyName] = new ConstantPositionProperty(Cartesian3.unpack(unwrappedInterval), referenceFrame);
  93580. }
  93581. return;
  93582. }
  93583. var property = object[propertyName];
  93584. var epoch;
  93585. var packetEpoch = packetData.epoch;
  93586. if (defined(packetEpoch)) {
  93587. epoch = JulianDate.fromIso8601(packetEpoch);
  93588. }
  93589. //Without an interval, any sampled value is infinite, meaning it completely
  93590. //replaces any non-sampled property that may exist.
  93591. if (isSampled && !hasInterval) {
  93592. if (!(property instanceof SampledPositionProperty) || (defined(referenceFrame) && property.referenceFrame !== referenceFrame)) {
  93593. property = new SampledPositionProperty(referenceFrame, numberOfDerivatives);
  93594. object[propertyName] = property;
  93595. }
  93596. property.addSamplesPackedArray(unwrappedInterval, epoch);
  93597. updateInterpolationSettings(packetData, property);
  93598. return;
  93599. }
  93600. var interval;
  93601. //A constant value with an interval is normally part of a TimeIntervalCollection,
  93602. //However, if the current property is not a time-interval collection, we need
  93603. //to turn it into a Composite, preserving the old data with the new interval.
  93604. if (!isSampled && hasInterval) {
  93605. //Create a new interval for the constant value.
  93606. combinedInterval = combinedInterval.clone();
  93607. if (isReference) {
  93608. combinedInterval.data = makeReference(entityCollection, packetData.reference);
  93609. } else {
  93610. combinedInterval.data = Cartesian3.unpack(unwrappedInterval);
  93611. }
  93612. //If no property exists, simply use a new interval collection
  93613. if (!defined(property)) {
  93614. if (isReference) {
  93615. property = new CompositePositionProperty(referenceFrame);
  93616. } else {
  93617. property = new TimeIntervalCollectionPositionProperty(referenceFrame);
  93618. }
  93619. object[propertyName] = property;
  93620. }
  93621. if (!isReference && property instanceof TimeIntervalCollectionPositionProperty && (defined(referenceFrame) && property.referenceFrame === referenceFrame)) {
  93622. //If we create a collection, or it already existed, use it.
  93623. property.intervals.addInterval(combinedInterval);
  93624. } else if (property instanceof CompositePositionProperty) {
  93625. //If the collection was already a CompositePositionProperty, use it.
  93626. combinedInterval.data = isReference ? combinedInterval.data : new ConstantPositionProperty(combinedInterval.data, referenceFrame);
  93627. property.intervals.addInterval(combinedInterval);
  93628. } else {
  93629. //Otherwise, create a CompositePositionProperty but preserve the existing data.
  93630. //Put the old property in an infinite interval.
  93631. interval = Iso8601.MAXIMUM_INTERVAL.clone();
  93632. interval.data = property;
  93633. //Create the composite.
  93634. property = new CompositePositionProperty(property.referenceFrame);
  93635. object[propertyName] = property;
  93636. //add the old property interval
  93637. property.intervals.addInterval(interval);
  93638. //Change the new data to a ConstantPositionProperty and add it.
  93639. combinedInterval.data = isReference ? combinedInterval.data : new ConstantPositionProperty(combinedInterval.data, referenceFrame);
  93640. property.intervals.addInterval(combinedInterval);
  93641. }
  93642. return;
  93643. }
  93644. //isSampled && hasInterval
  93645. if (!defined(property)) {
  93646. property = new CompositePositionProperty(referenceFrame);
  93647. object[propertyName] = property;
  93648. } else if (!(property instanceof CompositePositionProperty)) {
  93649. //create a CompositeProperty but preserve the existing data.
  93650. //Put the old property in an infinite interval.
  93651. interval = Iso8601.MAXIMUM_INTERVAL.clone();
  93652. interval.data = property;
  93653. //Create the composite.
  93654. property = new CompositePositionProperty(property.referenceFrame);
  93655. object[propertyName] = property;
  93656. //add the old property interval
  93657. property.intervals.addInterval(interval);
  93658. }
  93659. //Check if the interval already exists in the composite
  93660. var intervals = property.intervals;
  93661. interval = intervals.findInterval(combinedInterval);
  93662. if (!defined(interval) || !(interval.data instanceof SampledPositionProperty) || (defined(referenceFrame) && interval.data.referenceFrame !== referenceFrame)) {
  93663. //If not, create a SampledPositionProperty for it.
  93664. interval = combinedInterval.clone();
  93665. interval.data = new SampledPositionProperty(referenceFrame, numberOfDerivatives);
  93666. intervals.addInterval(interval);
  93667. }
  93668. interval.data.addSamplesPackedArray(unwrappedInterval, epoch);
  93669. updateInterpolationSettings(packetData, interval.data);
  93670. }
  93671. function processPositionPacketData(object, propertyName, packetData, interval, sourceUri, entityCollection) {
  93672. if (!defined(packetData)) {
  93673. return;
  93674. }
  93675. if (isArray(packetData)) {
  93676. for (var i = 0, len = packetData.length; i < len; i++) {
  93677. processPositionProperty(object, propertyName, packetData[i], interval, sourceUri, entityCollection);
  93678. }
  93679. } else {
  93680. processPositionProperty(object, propertyName, packetData, interval, sourceUri, entityCollection);
  93681. }
  93682. }
  93683. function processMaterialProperty(object, propertyName, packetData, constrainedInterval, sourceUri, entityCollection) {
  93684. var combinedInterval;
  93685. var packetInterval = packetData.interval;
  93686. if (defined(packetInterval)) {
  93687. iso8601Scratch.iso8601 = packetInterval;
  93688. combinedInterval = TimeInterval.fromIso8601(iso8601Scratch);
  93689. if (defined(constrainedInterval)) {
  93690. combinedInterval = TimeInterval.intersect(combinedInterval, constrainedInterval, scratchTimeInterval);
  93691. }
  93692. } else if (defined(constrainedInterval)) {
  93693. combinedInterval = constrainedInterval;
  93694. }
  93695. var property = object[propertyName];
  93696. var existingMaterial;
  93697. var existingInterval;
  93698. if (defined(combinedInterval)) {
  93699. if (!(property instanceof CompositeMaterialProperty)) {
  93700. property = new CompositeMaterialProperty();
  93701. object[propertyName] = property;
  93702. }
  93703. //See if we already have data at that interval.
  93704. var thisIntervals = property.intervals;
  93705. existingInterval = thisIntervals.findInterval({
  93706. start : combinedInterval.start,
  93707. stop : combinedInterval.stop
  93708. });
  93709. if (defined(existingInterval)) {
  93710. //We have an interval, but we need to make sure the
  93711. //new data is the same type of material as the old data.
  93712. existingMaterial = existingInterval.data;
  93713. } else {
  93714. //If not, create it.
  93715. existingInterval = combinedInterval.clone();
  93716. thisIntervals.addInterval(existingInterval);
  93717. }
  93718. } else {
  93719. existingMaterial = property;
  93720. }
  93721. var materialData;
  93722. if (defined(packetData.solidColor)) {
  93723. if (!(existingMaterial instanceof ColorMaterialProperty)) {
  93724. existingMaterial = new ColorMaterialProperty();
  93725. }
  93726. materialData = packetData.solidColor;
  93727. processPacketData(Color, existingMaterial, 'color', materialData.color, undefined, undefined, entityCollection);
  93728. } else if (defined(packetData.grid)) {
  93729. if (!(existingMaterial instanceof GridMaterialProperty)) {
  93730. existingMaterial = new GridMaterialProperty();
  93731. }
  93732. materialData = packetData.grid;
  93733. processPacketData(Color, existingMaterial, 'color', materialData.color, undefined, sourceUri, entityCollection);
  93734. processPacketData(Number, existingMaterial, 'cellAlpha', materialData.cellAlpha, undefined, sourceUri, entityCollection);
  93735. processPacketData(Cartesian2, existingMaterial, 'lineCount', materialData.lineCount, undefined, sourceUri, entityCollection);
  93736. processPacketData(Cartesian2, existingMaterial, 'lineThickness', materialData.lineThickness, undefined, sourceUri, entityCollection);
  93737. processPacketData(Cartesian2, existingMaterial, 'lineOffset', materialData.lineOffset, undefined, sourceUri, entityCollection);
  93738. } else if (defined(packetData.image)) {
  93739. if (!(existingMaterial instanceof ImageMaterialProperty)) {
  93740. existingMaterial = new ImageMaterialProperty();
  93741. }
  93742. materialData = packetData.image;
  93743. processPacketData(Image, existingMaterial, 'image', materialData.image, undefined, sourceUri, entityCollection);
  93744. processPacketData(Cartesian2, existingMaterial, 'repeat', materialData.repeat, undefined, sourceUri, entityCollection);
  93745. processPacketData(Color, existingMaterial, 'color', materialData.color, undefined, sourceUri, entityCollection);
  93746. processPacketData(Boolean, existingMaterial, 'transparent', materialData.transparent, undefined, sourceUri, entityCollection);
  93747. } else if (defined(packetData.stripe)) {
  93748. if (!(existingMaterial instanceof StripeMaterialProperty)) {
  93749. existingMaterial = new StripeMaterialProperty();
  93750. }
  93751. materialData = packetData.stripe;
  93752. processPacketData(StripeOrientation, existingMaterial, 'orientation', materialData.orientation, undefined, sourceUri, entityCollection);
  93753. processPacketData(Color, existingMaterial, 'evenColor', materialData.evenColor, undefined, sourceUri, entityCollection);
  93754. processPacketData(Color, existingMaterial, 'oddColor', materialData.oddColor, undefined, sourceUri, entityCollection);
  93755. processPacketData(Number, existingMaterial, 'offset', materialData.offset, undefined, sourceUri, entityCollection);
  93756. processPacketData(Number, existingMaterial, 'repeat', materialData.repeat, undefined, sourceUri, entityCollection);
  93757. } else if (defined(packetData.polylineOutline)) {
  93758. if (!(existingMaterial instanceof PolylineOutlineMaterialProperty)) {
  93759. existingMaterial = new PolylineOutlineMaterialProperty();
  93760. }
  93761. materialData = packetData.polylineOutline;
  93762. processPacketData(Color, existingMaterial, 'color', materialData.color, undefined, sourceUri, entityCollection);
  93763. processPacketData(Color, existingMaterial, 'outlineColor', materialData.outlineColor, undefined, sourceUri, entityCollection);
  93764. processPacketData(Number, existingMaterial, 'outlineWidth', materialData.outlineWidth, undefined, sourceUri, entityCollection);
  93765. } else if (defined(packetData.polylineGlow)) {
  93766. if (!(existingMaterial instanceof PolylineGlowMaterialProperty)) {
  93767. existingMaterial = new PolylineGlowMaterialProperty();
  93768. }
  93769. materialData = packetData.polylineGlow;
  93770. processPacketData(Color, existingMaterial, 'color', materialData.color, undefined, sourceUri, entityCollection);
  93771. processPacketData(Number, existingMaterial, 'glowPower', materialData.glowPower, undefined, sourceUri, entityCollection);
  93772. } else if (defined(packetData.polylineArrow)) {
  93773. if (!(existingMaterial instanceof PolylineArrowMaterialProperty)) {
  93774. existingMaterial = new PolylineArrowMaterialProperty();
  93775. }
  93776. materialData = packetData.polylineArrow;
  93777. processPacketData(Color, existingMaterial, 'color', materialData.color, undefined, undefined, entityCollection);
  93778. }
  93779. if (defined(existingInterval)) {
  93780. existingInterval.data = existingMaterial;
  93781. } else {
  93782. object[propertyName] = existingMaterial;
  93783. }
  93784. }
  93785. function processMaterialPacketData(object, propertyName, packetData, interval, sourceUri, entityCollection) {
  93786. if (!defined(packetData)) {
  93787. return;
  93788. }
  93789. if (isArray(packetData)) {
  93790. for (var i = 0, len = packetData.length; i < len; i++) {
  93791. processMaterialProperty(object, propertyName, packetData[i], interval, sourceUri, entityCollection);
  93792. }
  93793. } else {
  93794. processMaterialProperty(object, propertyName, packetData, interval, sourceUri, entityCollection);
  93795. }
  93796. }
  93797. function processName(entity, packet, entityCollection, sourceUri) {
  93798. entity.name = defaultValue(packet.name, entity.name);
  93799. }
  93800. function processDescription(entity, packet, entityCollection, sourceUri) {
  93801. var descriptionData = packet.description;
  93802. if (defined(descriptionData)) {
  93803. processPacketData(String, entity, 'description', descriptionData, undefined, sourceUri, entityCollection);
  93804. }
  93805. }
  93806. function processPosition(entity, packet, entityCollection, sourceUri) {
  93807. var positionData = packet.position;
  93808. if (defined(positionData)) {
  93809. processPositionPacketData(entity, 'position', positionData, undefined, sourceUri, entityCollection);
  93810. }
  93811. }
  93812. function processViewFrom(entity, packet, entityCollection, sourceUri) {
  93813. var viewFromData = packet.viewFrom;
  93814. if (defined(viewFromData)) {
  93815. processPacketData(Cartesian3, entity, 'viewFrom', viewFromData, undefined, sourceUri, entityCollection);
  93816. }
  93817. }
  93818. function processOrientation(entity, packet, entityCollection, sourceUri) {
  93819. var orientationData = packet.orientation;
  93820. if (defined(orientationData)) {
  93821. processPacketData(Quaternion, entity, 'orientation', orientationData, undefined, sourceUri, entityCollection);
  93822. }
  93823. }
  93824. function processArrayPacketData(object, propertyName, packetData, entityCollection) {
  93825. var references = packetData.references;
  93826. if (defined(references)) {
  93827. var properties = references.map(function(reference) {
  93828. return makeReference(entityCollection, reference);
  93829. });
  93830. var iso8601Interval = packetData.interval;
  93831. if (defined(iso8601Interval)) {
  93832. iso8601Interval = TimeInterval.fromIso8601(iso8601Interval);
  93833. if (!(object[propertyName] instanceof CompositePositionProperty)) {
  93834. iso8601Interval.data = new PropertyArray(properties);
  93835. var property = new CompositeProperty();
  93836. property.intervals.addInterval(iso8601Interval);
  93837. object[propertyName] = property;
  93838. }
  93839. } else {
  93840. object[propertyName] = new PropertyArray(properties);
  93841. }
  93842. } else {
  93843. processPacketData(Array, object, propertyName, packetData, undefined, undefined, entityCollection);
  93844. }
  93845. }
  93846. function processArray(object, propertyName, packetData, entityCollection) {
  93847. if (!defined(packetData)) {
  93848. return;
  93849. }
  93850. if (isArray(packetData)) {
  93851. for (var i = 0, length = packetData.length; i < length; ++i) {
  93852. processArrayPacketData(object, propertyName, packetData[i], entityCollection);
  93853. }
  93854. } else {
  93855. processArrayPacketData(object, propertyName, packetData, entityCollection);
  93856. }
  93857. }
  93858. function processPositionsPacketData(object, propertyName, positionsData, entityCollection) {
  93859. if (defined(positionsData.references)) {
  93860. var properties = positionsData.references.map(function(reference) {
  93861. return makeReference(entityCollection, reference);
  93862. });
  93863. var iso8601Interval = positionsData.interval;
  93864. if (defined(iso8601Interval)) {
  93865. iso8601Interval = TimeInterval.fromIso8601(iso8601Interval);
  93866. if (!(object[propertyName] instanceof CompositePositionProperty)) {
  93867. iso8601Interval.data = new PositionPropertyArray(properties);
  93868. var property = new CompositePositionProperty();
  93869. property.intervals.addInterval(iso8601Interval);
  93870. object[propertyName] = property;
  93871. }
  93872. } else {
  93873. object[propertyName] = new PositionPropertyArray(properties);
  93874. }
  93875. } else {
  93876. if (defined(positionsData.cartesian)) {
  93877. positionsData.array = Cartesian3.unpackArray(positionsData.cartesian);
  93878. } else if (defined(positionsData.cartographicRadians)) {
  93879. positionsData.array = Cartesian3.fromRadiansArrayHeights(positionsData.cartographicRadians);
  93880. } else if (defined(positionsData.cartographicDegrees)) {
  93881. positionsData.array = Cartesian3.fromDegreesArrayHeights(positionsData.cartographicDegrees);
  93882. }
  93883. if (defined(positionsData.array)) {
  93884. processPacketData(Array, object, propertyName, positionsData, undefined, undefined, entityCollection);
  93885. }
  93886. }
  93887. }
  93888. function processPositions(object, propertyName, positionsData, entityCollection) {
  93889. if (!defined(positionsData)) {
  93890. return;
  93891. }
  93892. if (isArray(positionsData)) {
  93893. for (var i = 0, length = positionsData.length; i < length; i++) {
  93894. processPositionsPacketData(object, propertyName, positionsData[i], entityCollection);
  93895. }
  93896. } else {
  93897. processPositionsPacketData(object, propertyName, positionsData, entityCollection);
  93898. }
  93899. }
  93900. function processAvailability(entity, packet, entityCollection, sourceUri) {
  93901. var interval;
  93902. var packetData = packet.availability;
  93903. if (!defined(packetData)) {
  93904. return;
  93905. }
  93906. var intervals;
  93907. if (isArray(packetData)) {
  93908. var length = packetData.length;
  93909. for (var i = 0; i < length; i++) {
  93910. if (!defined(intervals)) {
  93911. intervals = new TimeIntervalCollection();
  93912. }
  93913. iso8601Scratch.iso8601 = packetData[i];
  93914. interval = TimeInterval.fromIso8601(iso8601Scratch);
  93915. intervals.addInterval(interval);
  93916. }
  93917. } else {
  93918. iso8601Scratch.iso8601 = packetData;
  93919. interval = TimeInterval.fromIso8601(iso8601Scratch);
  93920. intervals = new TimeIntervalCollection();
  93921. intervals.addInterval(interval);
  93922. }
  93923. entity.availability = intervals;
  93924. }
  93925. var iso8601Scratch = {
  93926. iso8601 : undefined
  93927. };
  93928. function processAlignedAxis(billboard, packetData, interval, sourceUri, entityCollection) {
  93929. if (!defined(packetData)) {
  93930. return;
  93931. }
  93932. if (defined(packetData.velocityReference)) {
  93933. billboard.alignedAxis = new VelocityVectorProperty(makeReference(entityCollection, packetData.velocityReference), true);
  93934. } else {
  93935. processPacketData(Cartesian3, billboard, 'alignedAxis', packetData, interval, sourceUri, entityCollection);
  93936. }
  93937. }
  93938. function processBillboard(entity, packet, entityCollection, sourceUri) {
  93939. var billboardData = packet.billboard;
  93940. if (!defined(billboardData)) {
  93941. return;
  93942. }
  93943. var interval;
  93944. var intervalString = billboardData.interval;
  93945. if (defined(intervalString)) {
  93946. iso8601Scratch.iso8601 = intervalString;
  93947. interval = TimeInterval.fromIso8601(iso8601Scratch);
  93948. }
  93949. var billboard = entity.billboard;
  93950. if (!defined(billboard)) {
  93951. entity.billboard = billboard = new BillboardGraphics();
  93952. }
  93953. processPacketData(Boolean, billboard, 'show', billboardData.show, interval, sourceUri, entityCollection);
  93954. processPacketData(Image, billboard, 'image', billboardData.image, interval, sourceUri, entityCollection);
  93955. processPacketData(Number, billboard, 'scale', billboardData.scale, interval, sourceUri, entityCollection);
  93956. processPacketData(Cartesian2, billboard, 'pixelOffset', billboardData.pixelOffset, interval, sourceUri, entityCollection);
  93957. processPacketData(Cartesian3, billboard, 'eyeOffset', billboardData.eyeOffset, interval, sourceUri, entityCollection);
  93958. processPacketData(HorizontalOrigin, billboard, 'horizontalOrigin', billboardData.horizontalOrigin, interval, sourceUri, entityCollection);
  93959. processPacketData(VerticalOrigin, billboard, 'verticalOrigin', billboardData.verticalOrigin, interval, sourceUri, entityCollection);
  93960. processPacketData(HeightReference, billboard, 'heightReference', billboardData.heightReference, interval, sourceUri, entityCollection);
  93961. processPacketData(Color, billboard, 'color', billboardData.color, interval, sourceUri, entityCollection);
  93962. processPacketData(Rotation, billboard, 'rotation', billboardData.rotation, interval, sourceUri, entityCollection);
  93963. processAlignedAxis(billboard, billboardData.alignedAxis, interval, sourceUri, entityCollection);
  93964. processPacketData(Boolean, billboard, 'sizeInMeters', billboardData.sizeInMeters, interval, sourceUri, entityCollection);
  93965. processPacketData(Number, billboard, 'width', billboardData.width, interval, sourceUri, entityCollection);
  93966. processPacketData(Number, billboard, 'height', billboardData.height, interval, sourceUri, entityCollection);
  93967. processPacketData(NearFarScalar, billboard, 'scaleByDistance', billboardData.scaleByDistance, interval, sourceUri, entityCollection);
  93968. processPacketData(NearFarScalar, billboard, 'translucencyByDistance', billboardData.translucencyByDistance, interval, sourceUri, entityCollection);
  93969. processPacketData(NearFarScalar, billboard, 'pixelOffsetScaleByDistance', billboardData.pixelOffsetScaleByDistance, interval, sourceUri, entityCollection);
  93970. processPacketData(BoundingRectangle, billboard, 'imageSubRegion', billboardData.imageSubRegion, interval, sourceUri, entityCollection);
  93971. }
  93972. function processBox(entity, packet, entityCollection, sourceUri) {
  93973. var boxData = packet.box;
  93974. if (!defined(boxData)) {
  93975. return;
  93976. }
  93977. var interval;
  93978. var intervalString = boxData.interval;
  93979. if (defined(intervalString)) {
  93980. iso8601Scratch.iso8601 = intervalString;
  93981. interval = TimeInterval.fromIso8601(iso8601Scratch);
  93982. }
  93983. var box = entity.box;
  93984. if (!defined(box)) {
  93985. entity.box = box = new BoxGraphics();
  93986. }
  93987. processPacketData(Boolean, box, 'show', boxData.show, interval, sourceUri, entityCollection);
  93988. processPacketData(Cartesian3, box, 'dimensions', boxData.dimensions, interval, sourceUri, entityCollection);
  93989. processPacketData(Boolean, box, 'fill', boxData.fill, interval, sourceUri, entityCollection);
  93990. processMaterialPacketData(box, 'material', boxData.material, interval, sourceUri, entityCollection);
  93991. processPacketData(Boolean, box, 'outline', boxData.outline, interval, sourceUri, entityCollection);
  93992. processPacketData(Color, box, 'outlineColor', boxData.outlineColor, interval, sourceUri, entityCollection);
  93993. processPacketData(Number, box, 'outlineWidth', boxData.outlineWidth, interval, sourceUri, entityCollection);
  93994. processPacketData(ShadowMode, box, 'shadows', boxData.shadows, interval, sourceUri, entityCollection);
  93995. }
  93996. function processCorridor(entity, packet, entityCollection, sourceUri) {
  93997. var corridorData = packet.corridor;
  93998. if (!defined(corridorData)) {
  93999. return;
  94000. }
  94001. var interval;
  94002. var intervalString = corridorData.interval;
  94003. if (defined(intervalString)) {
  94004. iso8601Scratch.iso8601 = intervalString;
  94005. interval = TimeInterval.fromIso8601(iso8601Scratch);
  94006. }
  94007. var corridor = entity.corridor;
  94008. if (!defined(corridor)) {
  94009. entity.corridor = corridor = new CorridorGraphics();
  94010. }
  94011. processPacketData(Boolean, corridor, 'show', corridorData.show, interval, sourceUri, entityCollection);
  94012. processPositions(corridor, 'positions', corridorData.positions, entityCollection);
  94013. processPacketData(Number, corridor, 'width', corridorData.width, interval, sourceUri, entityCollection);
  94014. processPacketData(Number, corridor, 'height', corridorData.height, interval, sourceUri, entityCollection);
  94015. processPacketData(Number, corridor, 'extrudedHeight', corridorData.extrudedHeight, interval, sourceUri, entityCollection);
  94016. processPacketData(CornerType, corridor, 'cornerType', corridorData.cornerType, interval, sourceUri, entityCollection);
  94017. processPacketData(Number, corridor, 'granularity', corridorData.granularity, interval, sourceUri, entityCollection);
  94018. processPacketData(Boolean, corridor, 'fill', corridorData.fill, interval, sourceUri, entityCollection);
  94019. processMaterialPacketData(corridor, 'material', corridorData.material, interval, sourceUri, entityCollection);
  94020. processPacketData(Boolean, corridor, 'outline', corridorData.outline, interval, sourceUri, entityCollection);
  94021. processPacketData(Color, corridor, 'outlineColor', corridorData.outlineColor, interval, sourceUri, entityCollection);
  94022. processPacketData(Number, corridor, 'outlineWidth', corridorData.outlineWidth, interval, sourceUri, entityCollection);
  94023. processPacketData(ShadowMode, corridor, 'shadows', corridorData.shadows, interval, sourceUri, entityCollection);
  94024. }
  94025. function processCylinder(entity, packet, entityCollection, sourceUri) {
  94026. var cylinderData = packet.cylinder;
  94027. if (!defined(cylinderData)) {
  94028. return;
  94029. }
  94030. var interval;
  94031. var intervalString = cylinderData.interval;
  94032. if (defined(intervalString)) {
  94033. iso8601Scratch.iso8601 = intervalString;
  94034. interval = TimeInterval.fromIso8601(iso8601Scratch);
  94035. }
  94036. var cylinder = entity.cylinder;
  94037. if (!defined(cylinder)) {
  94038. entity.cylinder = cylinder = new CylinderGraphics();
  94039. }
  94040. processPacketData(Boolean, cylinder, 'show', cylinderData.show, interval, sourceUri, entityCollection);
  94041. processPacketData(Number, cylinder, 'length', cylinderData.length, interval, sourceUri, entityCollection);
  94042. processPacketData(Number, cylinder, 'topRadius', cylinderData.topRadius, interval, sourceUri, entityCollection);
  94043. processPacketData(Number, cylinder, 'bottomRadius', cylinderData.bottomRadius, interval, sourceUri, entityCollection);
  94044. processPacketData(Boolean, cylinder, 'fill', cylinderData.fill, interval, sourceUri, entityCollection);
  94045. processMaterialPacketData(cylinder, 'material', cylinderData.material, interval, sourceUri, entityCollection);
  94046. processPacketData(Boolean, cylinder, 'outline', cylinderData.outline, interval, sourceUri, entityCollection);
  94047. processPacketData(Color, cylinder, 'outlineColor', cylinderData.outlineColor, interval, sourceUri, entityCollection);
  94048. processPacketData(Number, cylinder, 'outlineWidth', cylinderData.outlineWidth, interval, sourceUri, entityCollection);
  94049. processPacketData(Number, cylinder, 'numberOfVerticalLines', cylinderData.numberOfVerticalLines, interval, sourceUri, entityCollection);
  94050. processPacketData(Number, cylinder, 'slices', cylinderData.slices, interval, sourceUri, entityCollection);
  94051. processPacketData(ShadowMode, cylinder, 'shadows', cylinderData.shadows, interval, sourceUri, entityCollection);
  94052. }
  94053. function processDocument(packet, dataSource) {
  94054. var version = packet.version;
  94055. if (defined(version)) {
  94056. if (typeof version === 'string') {
  94057. var tokens = version.split('.');
  94058. if (tokens.length === 2) {
  94059. if (tokens[0] !== '1') {
  94060. throw new RuntimeError('Cesium only supports CZML version 1.');
  94061. }
  94062. dataSource._version = version;
  94063. }
  94064. }
  94065. }
  94066. if (!defined(dataSource._version)) {
  94067. throw new RuntimeError('CZML version information invalid. It is expected to be a property on the document object in the <Major>.<Minor> version format.');
  94068. }
  94069. var documentPacket = dataSource._documentPacket;
  94070. if (defined(packet.name)) {
  94071. documentPacket.name = packet.name;
  94072. }
  94073. var clockPacket = packet.clock;
  94074. if (defined(clockPacket)) {
  94075. var clock = documentPacket.clock;
  94076. if (!defined(clock)) {
  94077. documentPacket.clock = {
  94078. interval : clockPacket.interval,
  94079. currentTime : clockPacket.currentTime,
  94080. range : clockPacket.range,
  94081. step : clockPacket.step,
  94082. multiplier : clockPacket.multiplier
  94083. };
  94084. } else {
  94085. clock.interval = defaultValue(clockPacket.interval, clock.interval);
  94086. clock.currentTime = defaultValue(clockPacket.currentTime, clock.currentTime);
  94087. clock.range = defaultValue(clockPacket.range, clock.range);
  94088. clock.step = defaultValue(clockPacket.step, clock.step);
  94089. clock.multiplier = defaultValue(clockPacket.multiplier, clock.multiplier);
  94090. }
  94091. }
  94092. }
  94093. function processEllipse(entity, packet, entityCollection, sourceUri) {
  94094. var ellipseData = packet.ellipse;
  94095. if (!defined(ellipseData)) {
  94096. return;
  94097. }
  94098. var interval;
  94099. var intervalString = ellipseData.interval;
  94100. if (defined(intervalString)) {
  94101. iso8601Scratch.iso8601 = intervalString;
  94102. interval = TimeInterval.fromIso8601(iso8601Scratch);
  94103. }
  94104. var ellipse = entity.ellipse;
  94105. if (!defined(ellipse)) {
  94106. entity.ellipse = ellipse = new EllipseGraphics();
  94107. }
  94108. processPacketData(Boolean, ellipse, 'show', ellipseData.show, interval, sourceUri, entityCollection);
  94109. processPacketData(Number, ellipse, 'semiMajorAxis', ellipseData.semiMajorAxis, interval, sourceUri, entityCollection);
  94110. processPacketData(Number, ellipse, 'semiMinorAxis', ellipseData.semiMinorAxis, interval, sourceUri, entityCollection);
  94111. processPacketData(Number, ellipse, 'height', ellipseData.height, interval, sourceUri, entityCollection);
  94112. processPacketData(Number, ellipse, 'extrudedHeight', ellipseData.extrudedHeight, interval, sourceUri, entityCollection);
  94113. processPacketData(Rotation, ellipse, 'rotation', ellipseData.rotation, interval, sourceUri, entityCollection);
  94114. processPacketData(Rotation, ellipse, 'stRotation', ellipseData.stRotation, interval, sourceUri, entityCollection);
  94115. processPacketData(Number, ellipse, 'granularity', ellipseData.granularity, interval, sourceUri, entityCollection);
  94116. processPacketData(Boolean, ellipse, 'fill', ellipseData.fill, interval, sourceUri, entityCollection);
  94117. processMaterialPacketData(ellipse, 'material', ellipseData.material, interval, sourceUri, entityCollection);
  94118. processPacketData(Boolean, ellipse, 'outline', ellipseData.outline, interval, sourceUri, entityCollection);
  94119. processPacketData(Color, ellipse, 'outlineColor', ellipseData.outlineColor, interval, sourceUri, entityCollection);
  94120. processPacketData(Number, ellipse, 'outlineWidth', ellipseData.outlineWidth, interval, sourceUri, entityCollection);
  94121. processPacketData(Number, ellipse, 'numberOfVerticalLines', ellipseData.numberOfVerticalLines, interval, sourceUri, entityCollection);
  94122. processPacketData(ShadowMode, ellipse, 'shadows', ellipseData.shadows, interval, sourceUri, entityCollection);
  94123. }
  94124. function processEllipsoid(entity, packet, entityCollection, sourceUri) {
  94125. var ellipsoidData = packet.ellipsoid;
  94126. if (!defined(ellipsoidData)) {
  94127. return;
  94128. }
  94129. var interval;
  94130. var intervalString = ellipsoidData.interval;
  94131. if (defined(intervalString)) {
  94132. iso8601Scratch.iso8601 = intervalString;
  94133. interval = TimeInterval.fromIso8601(iso8601Scratch);
  94134. }
  94135. var ellipsoid = entity.ellipsoid;
  94136. if (!defined(ellipsoid)) {
  94137. entity.ellipsoid = ellipsoid = new EllipsoidGraphics();
  94138. }
  94139. processPacketData(Boolean, ellipsoid, 'show', ellipsoidData.show, interval, sourceUri, entityCollection);
  94140. processPacketData(Cartesian3, ellipsoid, 'radii', ellipsoidData.radii, interval, sourceUri, entityCollection);
  94141. processPacketData(Boolean, ellipsoid, 'fill', ellipsoidData.fill, interval, sourceUri, entityCollection);
  94142. processMaterialPacketData(ellipsoid, 'material', ellipsoidData.material, interval, sourceUri, entityCollection);
  94143. processPacketData(Boolean, ellipsoid, 'outline', ellipsoidData.outline, interval, sourceUri, entityCollection);
  94144. processPacketData(Color, ellipsoid, 'outlineColor', ellipsoidData.outlineColor, interval, sourceUri, entityCollection);
  94145. processPacketData(Number, ellipsoid, 'outlineWidth', ellipsoidData.outlineWidth, interval, sourceUri, entityCollection);
  94146. processPacketData(Number, ellipsoid, 'stackPartitions', ellipsoidData.stackPartitions, interval, sourceUri, entityCollection);
  94147. processPacketData(Number, ellipsoid, 'slicePartitions', ellipsoidData.slicePartitions, interval, sourceUri, entityCollection);
  94148. processPacketData(Number, ellipsoid, 'subdivisions', ellipsoidData.subdivisions, interval, sourceUri, entityCollection);
  94149. processPacketData(ShadowMode, ellipsoid, 'shadows', ellipsoidData.shadows, interval, sourceUri, entityCollection);
  94150. }
  94151. function processLabel(entity, packet, entityCollection, sourceUri) {
  94152. var labelData = packet.label;
  94153. if (!defined(labelData)) {
  94154. return;
  94155. }
  94156. var interval;
  94157. var intervalString = labelData.interval;
  94158. if (defined(intervalString)) {
  94159. iso8601Scratch.iso8601 = intervalString;
  94160. interval = TimeInterval.fromIso8601(iso8601Scratch);
  94161. }
  94162. var label = entity.label;
  94163. if (!defined(label)) {
  94164. entity.label = label = new LabelGraphics();
  94165. }
  94166. processPacketData(Boolean, label, 'show', labelData.show, interval, sourceUri, entityCollection);
  94167. processPacketData(String, label, 'text', labelData.text, interval, sourceUri, entityCollection);
  94168. processPacketData(String, label, 'font', labelData.font, interval, sourceUri, entityCollection);
  94169. processPacketData(LabelStyle, label, 'style', labelData.style, interval, sourceUri, entityCollection);
  94170. processPacketData(Number, label, 'scale', labelData.scale, interval, sourceUri, entityCollection);
  94171. processPacketData(Boolean, label, 'showBackground', labelData.showBackground, interval, sourceUri, entityCollection);
  94172. processPacketData(Color, label, 'backgroundColor', labelData.backgroundColor, interval, sourceUri, entityCollection);
  94173. processPacketData(Cartesian2, label, 'backgroundPadding', labelData.backgroundPadding, interval, sourceUri, entityCollection);
  94174. processPacketData(Cartesian2, label, 'pixelOffset', labelData.pixelOffset, interval, sourceUri, entityCollection);
  94175. processPacketData(Cartesian3, label, 'eyeOffset', labelData.eyeOffset, interval, sourceUri, entityCollection);
  94176. processPacketData(HorizontalOrigin, label, 'horizontalOrigin', labelData.horizontalOrigin, interval, sourceUri, entityCollection);
  94177. processPacketData(VerticalOrigin, label, 'verticalOrigin', labelData.verticalOrigin, interval, sourceUri, entityCollection);
  94178. processPacketData(HeightReference, label, 'heightReference', labelData.heightReference, interval, sourceUri, entityCollection);
  94179. processPacketData(Color, label, 'fillColor', labelData.fillColor, interval, sourceUri, entityCollection);
  94180. processPacketData(Color, label, 'outlineColor', labelData.outlineColor, interval, sourceUri, entityCollection);
  94181. processPacketData(Number, label, 'outlineWidth', labelData.outlineWidth, interval, sourceUri, entityCollection);
  94182. processPacketData(NearFarScalar, label, 'translucencyByDistance', labelData.translucencyByDistance, interval, sourceUri, entityCollection);
  94183. processPacketData(NearFarScalar, label, 'pixelOffsetScaleByDistance', labelData.pixelOffsetScaleByDistance, interval, sourceUri, entityCollection);
  94184. }
  94185. function processModel(entity, packet, entityCollection, sourceUri) {
  94186. var modelData = packet.model;
  94187. if (!defined(modelData)) {
  94188. return;
  94189. }
  94190. var interval;
  94191. var intervalString = modelData.interval;
  94192. if (defined(intervalString)) {
  94193. iso8601Scratch.iso8601 = intervalString;
  94194. interval = TimeInterval.fromIso8601(iso8601Scratch);
  94195. }
  94196. var model = entity.model;
  94197. if (!defined(model)) {
  94198. entity.model = model = new ModelGraphics();
  94199. }
  94200. processPacketData(Boolean, model, 'show', modelData.show, interval, sourceUri, entityCollection);
  94201. processPacketData(Uri, model, 'uri', modelData.gltf, interval, sourceUri, entityCollection);
  94202. processPacketData(Number, model, 'scale', modelData.scale, interval, sourceUri, entityCollection);
  94203. processPacketData(Number, model, 'minimumPixelSize', modelData.minimumPixelSize, interval, sourceUri, entityCollection);
  94204. processPacketData(Number, model, 'maximumScale', modelData.maximumScale, interval, sourceUri, entityCollection);
  94205. processPacketData(Boolean, model, 'incrementallyLoadTextures', modelData.incrementallyLoadTextures, interval, sourceUri, entityCollection);
  94206. processPacketData(Boolean, model, 'runAnimations', modelData.runAnimations, interval, sourceUri, entityCollection);
  94207. processPacketData(ShadowMode, model, 'shadows', modelData.shadows, interval, sourceUri, entityCollection);
  94208. processPacketData(HeightReference, model, 'heightReference', modelData.heightReference, interval, sourceUri, entityCollection);
  94209. processPacketData(Color, model, 'silhouetteColor', modelData.silhouetteColor, interval, sourceUri, entityCollection);
  94210. processPacketData(Number, model, 'silhouetteSize', modelData.silhouetteSize, interval, sourceUri, entityCollection);
  94211. processPacketData(Color, model, 'color', modelData.color, interval, sourceUri, entityCollection);
  94212. processPacketData(ColorBlendMode, model, 'colorBlendMode', modelData.colorBlendMode, interval, sourceUri, entityCollection);
  94213. processPacketData(Number, model, 'colorBlendAmount', modelData.colorBlendAmount, interval, sourceUri, entityCollection);
  94214. var nodeTransformationsData = modelData.nodeTransformations;
  94215. if (defined(nodeTransformationsData)) {
  94216. if (isArray(nodeTransformationsData)) {
  94217. for (var i = 0, len = nodeTransformationsData.length; i < len; i++) {
  94218. processNodeTransformations(model, nodeTransformationsData[i], interval, sourceUri, entityCollection);
  94219. }
  94220. } else {
  94221. processNodeTransformations(model, nodeTransformationsData, interval, sourceUri, entityCollection);
  94222. }
  94223. }
  94224. }
  94225. function processNodeTransformations(model, nodeTransformationsData, constrainedInterval, sourceUri, entityCollection) {
  94226. var combinedInterval;
  94227. var packetInterval = nodeTransformationsData.interval;
  94228. if (defined(packetInterval)) {
  94229. iso8601Scratch.iso8601 = packetInterval;
  94230. combinedInterval = TimeInterval.fromIso8601(iso8601Scratch);
  94231. if (defined(constrainedInterval)) {
  94232. combinedInterval = TimeInterval.intersect(combinedInterval, constrainedInterval, scratchTimeInterval);
  94233. }
  94234. } else if (defined(constrainedInterval)) {
  94235. combinedInterval = constrainedInterval;
  94236. }
  94237. var nodeTransformations = model.nodeTransformations;
  94238. var nodeNames = Object.keys(nodeTransformationsData);
  94239. for (var i = 0, len = nodeNames.length; i < len; ++i) {
  94240. var nodeName = nodeNames[i];
  94241. if (nodeName === 'interval') {
  94242. continue;
  94243. }
  94244. var nodeTransformationData = nodeTransformationsData[nodeName];
  94245. if (!defined(nodeTransformationData)) {
  94246. continue;
  94247. }
  94248. if (!defined(nodeTransformations)) {
  94249. model.nodeTransformations = nodeTransformations = new PropertyBag();
  94250. }
  94251. if (!nodeTransformations.hasProperty(nodeName)) {
  94252. nodeTransformations.addProperty(nodeName);
  94253. }
  94254. var nodeTransformation = nodeTransformations[nodeName];
  94255. if (!defined(nodeTransformation)) {
  94256. nodeTransformations[nodeName] = nodeTransformation = new NodeTransformationProperty();
  94257. }
  94258. processPacketData(Cartesian3, nodeTransformation, 'translation', nodeTransformationData.translation, combinedInterval, sourceUri, entityCollection);
  94259. processPacketData(Quaternion, nodeTransformation, 'rotation', nodeTransformationData.rotation, combinedInterval, sourceUri, entityCollection);
  94260. processPacketData(Cartesian3, nodeTransformation, 'scale', nodeTransformationData.scale, combinedInterval, sourceUri, entityCollection);
  94261. }
  94262. }
  94263. function processPath(entity, packet, entityCollection, sourceUri) {
  94264. var pathData = packet.path;
  94265. if (!defined(pathData)) {
  94266. return;
  94267. }
  94268. var interval;
  94269. var intervalString = pathData.interval;
  94270. if (defined(intervalString)) {
  94271. iso8601Scratch.iso8601 = intervalString;
  94272. interval = TimeInterval.fromIso8601(iso8601Scratch);
  94273. }
  94274. var path = entity.path;
  94275. if (!defined(path)) {
  94276. entity.path = path = new PathGraphics();
  94277. }
  94278. processPacketData(Boolean, path, 'show', pathData.show, interval, sourceUri, entityCollection);
  94279. processPacketData(Number, path, 'width', pathData.width, interval, sourceUri, entityCollection);
  94280. processPacketData(Number, path, 'resolution', pathData.resolution, interval, sourceUri, entityCollection);
  94281. processPacketData(Number, path, 'leadTime', pathData.leadTime, interval, sourceUri, entityCollection);
  94282. processPacketData(Number, path, 'trailTime', pathData.trailTime, interval, sourceUri, entityCollection);
  94283. processMaterialPacketData(path, 'material', pathData.material, interval, sourceUri, entityCollection);
  94284. }
  94285. function processPoint(entity, packet, entityCollection, sourceUri) {
  94286. var pointData = packet.point;
  94287. if (!defined(pointData)) {
  94288. return;
  94289. }
  94290. var interval;
  94291. var intervalString = pointData.interval;
  94292. if (defined(intervalString)) {
  94293. iso8601Scratch.iso8601 = intervalString;
  94294. interval = TimeInterval.fromIso8601(iso8601Scratch);
  94295. }
  94296. var point = entity.point;
  94297. if (!defined(point)) {
  94298. entity.point = point = new PointGraphics();
  94299. }
  94300. processPacketData(Boolean, point, 'show', pointData.show, interval, sourceUri, entityCollection);
  94301. processPacketData(Number, point, 'pixelSize', pointData.pixelSize, interval, sourceUri, entityCollection);
  94302. processPacketData(HeightReference, point, 'heightReference', pointData.heightReference, interval, sourceUri, entityCollection);
  94303. processPacketData(Color, point, 'color', pointData.color, interval, sourceUri, entityCollection);
  94304. processPacketData(Color, point, 'outlineColor', pointData.outlineColor, interval, sourceUri, entityCollection);
  94305. processPacketData(Number, point, 'outlineWidth', pointData.outlineWidth, interval, sourceUri, entityCollection);
  94306. processPacketData(NearFarScalar, point, 'scaleByDistance', pointData.scaleByDistance, interval, sourceUri, entityCollection);
  94307. processPacketData(NearFarScalar, point, 'translucencyByDistance', pointData.translucencyByDistance, interval, sourceUri, entityCollection);
  94308. }
  94309. function processPolygon(entity, packet, entityCollection, sourceUri) {
  94310. var polygonData = packet.polygon;
  94311. if (!defined(polygonData)) {
  94312. return;
  94313. }
  94314. var interval;
  94315. var intervalString = polygonData.interval;
  94316. if (defined(intervalString)) {
  94317. iso8601Scratch.iso8601 = intervalString;
  94318. interval = TimeInterval.fromIso8601(iso8601Scratch);
  94319. }
  94320. var polygon = entity.polygon;
  94321. if (!defined(polygon)) {
  94322. entity.polygon = polygon = new PolygonGraphics();
  94323. }
  94324. processPacketData(Boolean, polygon, 'show', polygonData.show, interval, sourceUri, entityCollection);
  94325. processPositions(polygon, 'hierarchy', polygonData.positions, entityCollection);
  94326. processPacketData(Number, polygon, 'height', polygonData.height, interval, sourceUri, entityCollection);
  94327. processPacketData(Number, polygon, 'extrudedHeight', polygonData.extrudedHeight, interval, sourceUri, entityCollection);
  94328. processPacketData(Rotation, polygon, 'stRotation', polygonData.stRotation, interval, sourceUri, entityCollection);
  94329. processPacketData(Number, polygon, 'granularity', polygonData.granularity, interval, sourceUri, entityCollection);
  94330. processPacketData(Boolean, polygon, 'fill', polygonData.fill, interval, sourceUri, entityCollection);
  94331. processMaterialPacketData(polygon, 'material', polygonData.material, interval, sourceUri, entityCollection);
  94332. processPacketData(Boolean, polygon, 'outline', polygonData.outline, interval, sourceUri, entityCollection);
  94333. processPacketData(Color, polygon, 'outlineColor', polygonData.outlineColor, interval, sourceUri, entityCollection);
  94334. processPacketData(Number, polygon, 'outlineWidth', polygonData.outlineWidth, interval, sourceUri, entityCollection);
  94335. processPacketData(Boolean, polygon, 'perPositionHeight', polygonData.perPositionHeight, interval, sourceUri, entityCollection);
  94336. processPacketData(Boolean, polygon, 'closeTop', polygonData.closeTop, interval, sourceUri, entityCollection);
  94337. processPacketData(Boolean, polygon, 'closeBottom', polygonData.closeBottom, interval, sourceUri, entityCollection);
  94338. processPacketData(ShadowMode, polygon, 'shadows', polygonData.shadows, interval, sourceUri, entityCollection);
  94339. }
  94340. function processPolyline(entity, packet, entityCollection, sourceUri) {
  94341. var polylineData = packet.polyline;
  94342. if (!defined(polylineData)) {
  94343. return;
  94344. }
  94345. var interval;
  94346. var intervalString = polylineData.interval;
  94347. if (defined(intervalString)) {
  94348. iso8601Scratch.iso8601 = intervalString;
  94349. interval = TimeInterval.fromIso8601(iso8601Scratch);
  94350. }
  94351. var polyline = entity.polyline;
  94352. if (!defined(polyline)) {
  94353. entity.polyline = polyline = new PolylineGraphics();
  94354. }
  94355. processPacketData(Boolean, polyline, 'show', polylineData.show, interval, sourceUri, entityCollection);
  94356. processPositions(polyline, 'positions', polylineData.positions, entityCollection);
  94357. processPacketData(Number, polyline, 'width', polylineData.width, interval, sourceUri, entityCollection);
  94358. processPacketData(Number, polyline, 'granularity', polylineData.granularity, interval, sourceUri, entityCollection);
  94359. processMaterialPacketData(polyline, 'material', polylineData.material, interval, sourceUri, entityCollection);
  94360. processPacketData(Boolean, polyline, 'followSurface', polylineData.followSurface, interval, sourceUri, entityCollection);
  94361. processPacketData(ShadowMode, polyline, 'shadows', polylineData.shadows, interval, sourceUri, entityCollection);
  94362. }
  94363. function processRectangle(entity, packet, entityCollection, sourceUri) {
  94364. var rectangleData = packet.rectangle;
  94365. if (!defined(rectangleData)) {
  94366. return;
  94367. }
  94368. var interval;
  94369. var intervalString = rectangleData.interval;
  94370. if (defined(intervalString)) {
  94371. iso8601Scratch.iso8601 = intervalString;
  94372. interval = TimeInterval.fromIso8601(iso8601Scratch);
  94373. }
  94374. var rectangle = entity.rectangle;
  94375. if (!defined(rectangle)) {
  94376. entity.rectangle = rectangle = new RectangleGraphics();
  94377. }
  94378. processPacketData(Boolean, rectangle, 'show', rectangleData.show, interval, sourceUri, entityCollection);
  94379. processPacketData(Rectangle, rectangle, 'coordinates', rectangleData.coordinates, interval, sourceUri, entityCollection);
  94380. processPacketData(Number, rectangle, 'height', rectangleData.height, interval, sourceUri, entityCollection);
  94381. processPacketData(Number, rectangle, 'extrudedHeight', rectangleData.extrudedHeight, interval, sourceUri, entityCollection);
  94382. processPacketData(Rotation, rectangle, 'rotation', rectangleData.rotation, interval, sourceUri, entityCollection);
  94383. processPacketData(Rotation, rectangle, 'stRotation', rectangleData.stRotation, interval, sourceUri, entityCollection);
  94384. processPacketData(Number, rectangle, 'granularity', rectangleData.granularity, interval, sourceUri, entityCollection);
  94385. processPacketData(Boolean, rectangle, 'fill', rectangleData.fill, interval, sourceUri, entityCollection);
  94386. processMaterialPacketData(rectangle, 'material', rectangleData.material, interval, sourceUri, entityCollection);
  94387. processPacketData(Boolean, rectangle, 'outline', rectangleData.outline, interval, sourceUri, entityCollection);
  94388. processPacketData(Color, rectangle, 'outlineColor', rectangleData.outlineColor, interval, sourceUri, entityCollection);
  94389. processPacketData(Number, rectangle, 'outlineWidth', rectangleData.outlineWidth, interval, sourceUri, entityCollection);
  94390. processPacketData(Boolean, rectangle, 'closeTop', rectangleData.closeTop, interval, sourceUri, entityCollection);
  94391. processPacketData(Boolean, rectangle, 'closeBottom', rectangleData.closeBottom, interval, sourceUri, entityCollection);
  94392. processPacketData(ShadowMode, rectangle, 'shadows', rectangleData.shadows, interval, sourceUri, entityCollection);
  94393. }
  94394. function processWall(entity, packet, entityCollection, sourceUri) {
  94395. var wallData = packet.wall;
  94396. if (!defined(wallData)) {
  94397. return;
  94398. }
  94399. var interval;
  94400. var intervalString = wallData.interval;
  94401. if (defined(intervalString)) {
  94402. iso8601Scratch.iso8601 = intervalString;
  94403. interval = TimeInterval.fromIso8601(iso8601Scratch);
  94404. }
  94405. var wall = entity.wall;
  94406. if (!defined(wall)) {
  94407. entity.wall = wall = new WallGraphics();
  94408. }
  94409. processPacketData(Boolean, wall, 'show', wallData.show, interval, sourceUri, entityCollection);
  94410. processPositions(wall, 'positions', wallData.positions, entityCollection);
  94411. processArray(wall, 'minimumHeights', wallData.minimumHeights, entityCollection);
  94412. processArray(wall, 'maximumHeights', wallData.maximumHeights, entityCollection);
  94413. processPacketData(Number, wall, 'granularity', wallData.granularity, interval, sourceUri, entityCollection);
  94414. processPacketData(Boolean, wall, 'fill', wallData.fill, interval, sourceUri, entityCollection);
  94415. processMaterialPacketData(wall, 'material', wallData.material, interval, sourceUri, entityCollection);
  94416. processPacketData(Boolean, wall, 'outline', wallData.outline, interval, sourceUri, entityCollection);
  94417. processPacketData(Color, wall, 'outlineColor', wallData.outlineColor, interval, sourceUri, entityCollection);
  94418. processPacketData(Number, wall, 'outlineWidth', wallData.outlineWidth, interval, sourceUri, entityCollection);
  94419. processPacketData(ShadowMode, wall, 'shadows', wallData.shadows, interval, sourceUri, entityCollection);
  94420. }
  94421. function processCzmlPacket(packet, entityCollection, updaterFunctions, sourceUri, dataSource) {
  94422. var objectId = packet.id;
  94423. if (!defined(objectId)) {
  94424. objectId = createGuid();
  94425. }
  94426. currentId = objectId;
  94427. if (!defined(dataSource._version) && objectId !== 'document') {
  94428. throw new RuntimeError('The first CZML packet is required to be the document object.');
  94429. }
  94430. if (packet['delete'] === true) {
  94431. entityCollection.removeById(objectId);
  94432. } else if (objectId === 'document') {
  94433. processDocument(packet, dataSource);
  94434. } else {
  94435. var entity = entityCollection.getOrCreateEntity(objectId);
  94436. var parentId = packet.parent;
  94437. if (defined(parentId)) {
  94438. entity.parent = entityCollection.getOrCreateEntity(parentId);
  94439. }
  94440. for (var i = updaterFunctions.length - 1; i > -1; i--) {
  94441. updaterFunctions[i](entity, packet, entityCollection, sourceUri);
  94442. }
  94443. }
  94444. currentId = undefined;
  94445. }
  94446. function updateClock(dataSource) {
  94447. var clock;
  94448. var clockPacket = dataSource._documentPacket.clock;
  94449. if (!defined(clockPacket)) {
  94450. if (!defined(dataSource._clock)) {
  94451. var availability = dataSource._entityCollection.computeAvailability();
  94452. if (!availability.start.equals(Iso8601.MINIMUM_VALUE)) {
  94453. var startTime = availability.start;
  94454. var stopTime = availability.stop;
  94455. var totalSeconds = JulianDate.secondsDifference(stopTime, startTime);
  94456. var multiplier = Math.round(totalSeconds / 120.0);
  94457. clock = new DataSourceClock();
  94458. clock.startTime = JulianDate.clone(startTime);
  94459. clock.stopTime = JulianDate.clone(stopTime);
  94460. clock.clockRange = ClockRange.LOOP_STOP;
  94461. clock.multiplier = multiplier;
  94462. clock.currentTime = JulianDate.clone(startTime);
  94463. clock.clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER;
  94464. dataSource._clock = clock;
  94465. return true;
  94466. }
  94467. }
  94468. return false;
  94469. }
  94470. if (defined(dataSource._clock)) {
  94471. clock = dataSource._clock.clone();
  94472. } else {
  94473. clock = new DataSourceClock();
  94474. clock.startTime = Iso8601.MINIMUM_VALUE.clone();
  94475. clock.stopTime = Iso8601.MAXIMUM_VALUE.clone();
  94476. clock.currentTime = Iso8601.MINIMUM_VALUE.clone();
  94477. clock.clockRange = ClockRange.LOOP_STOP;
  94478. clock.clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER;
  94479. clock.multiplier = 1.0;
  94480. }
  94481. if (defined(clockPacket.interval)) {
  94482. iso8601Scratch.iso8601 = clockPacket.interval;
  94483. var interval = TimeInterval.fromIso8601(iso8601Scratch);
  94484. clock.startTime = interval.start;
  94485. clock.stopTime = interval.stop;
  94486. }
  94487. if (defined(clockPacket.currentTime)) {
  94488. clock.currentTime = JulianDate.fromIso8601(clockPacket.currentTime);
  94489. }
  94490. if (defined(clockPacket.range)) {
  94491. clock.clockRange = defaultValue(ClockRange[clockPacket.range], ClockRange.LOOP_STOP);
  94492. }
  94493. if (defined(clockPacket.step)) {
  94494. clock.clockStep = defaultValue(ClockStep[clockPacket.step], ClockStep.SYSTEM_CLOCK_MULTIPLIER);
  94495. }
  94496. if (defined(clockPacket.multiplier)) {
  94497. clock.multiplier = clockPacket.multiplier;
  94498. }
  94499. if (!clock.equals(dataSource._clock)) {
  94500. dataSource._clock = clock.clone(dataSource._clock);
  94501. return true;
  94502. }
  94503. return false;
  94504. }
  94505. function load(dataSource, czml, options, clear) {
  94506. if (!defined(czml)) {
  94507. throw new DeveloperError('czml is required.');
  94508. }
  94509. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  94510. var promise = czml;
  94511. var sourceUri = options.sourceUri;
  94512. if (typeof czml === 'string') {
  94513. promise = loadJson(czml);
  94514. sourceUri = defaultValue(sourceUri, czml);
  94515. }
  94516. DataSource.setLoading(dataSource, true);
  94517. return when(promise, function(czml) {
  94518. return loadCzml(dataSource, czml, sourceUri, clear);
  94519. }).otherwise(function(error) {
  94520. DataSource.setLoading(dataSource, false);
  94521. dataSource._error.raiseEvent(dataSource, error);
  94522. console.log(error);
  94523. return when.reject(error);
  94524. });
  94525. }
  94526. function loadCzml(dataSource, czml, sourceUri, clear) {
  94527. DataSource.setLoading(dataSource, true);
  94528. var entityCollection = dataSource._entityCollection;
  94529. if (clear) {
  94530. dataSource._version = undefined;
  94531. dataSource._documentPacket = new DocumentPacket();
  94532. entityCollection.removeAll();
  94533. }
  94534. CzmlDataSource._processCzml(czml, entityCollection, sourceUri, undefined, dataSource);
  94535. var raiseChangedEvent = updateClock(dataSource);
  94536. var documentPacket = dataSource._documentPacket;
  94537. if (defined(documentPacket.name) && dataSource._name !== documentPacket.name) {
  94538. dataSource._name = documentPacket.name;
  94539. raiseChangedEvent = true;
  94540. } else if (!defined(dataSource._name) && defined(sourceUri)) {
  94541. dataSource._name = getFilenameFromUri(sourceUri);
  94542. raiseChangedEvent = true;
  94543. }
  94544. DataSource.setLoading(dataSource, false);
  94545. if (raiseChangedEvent) {
  94546. dataSource._changed.raiseEvent(dataSource);
  94547. }
  94548. return dataSource;
  94549. }
  94550. function DocumentPacket() {
  94551. this.name = undefined;
  94552. this.clock = undefined;
  94553. }
  94554. /**
  94555. * A {@link DataSource} which processes {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/CZML-Guide|CZML}.
  94556. * @alias CzmlDataSource
  94557. * @constructor
  94558. *
  94559. * @param {String} [name] An optional name for the data source. This value will be overwritten if a loaded document contains a name.
  94560. *
  94561. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=CZML.html|Cesium Sandcastle CZML Demo}
  94562. */
  94563. function CzmlDataSource(name) {
  94564. this._name = name;
  94565. this._changed = new Event();
  94566. this._error = new Event();
  94567. this._isLoading = false;
  94568. this._loading = new Event();
  94569. this._clock = undefined;
  94570. this._documentPacket = new DocumentPacket();
  94571. this._version = undefined;
  94572. this._entityCollection = new EntityCollection(this);
  94573. this._entityCluster = new EntityCluster();
  94574. }
  94575. /**
  94576. * Creates a Promise to a new instance loaded with the provided CZML data.
  94577. *
  94578. * @param {String|Object} data A url or CZML object to be processed.
  94579. * @param {Object} [options] An object with the following properties:
  94580. * @param {String} [options.sourceUri] Overrides the url to use for resolving relative links.
  94581. * @returns {Promise.<CzmlDataSource>} A promise that resolves to the new instance once the data is processed.
  94582. */
  94583. CzmlDataSource.load = function(czml, options) {
  94584. return new CzmlDataSource().load(czml, options);
  94585. };
  94586. defineProperties(CzmlDataSource.prototype, {
  94587. /**
  94588. * Gets a human-readable name for this instance.
  94589. * @memberof CzmlDataSource.prototype
  94590. * @type {String}
  94591. */
  94592. name : {
  94593. get : function() {
  94594. return this._name;
  94595. }
  94596. },
  94597. /**
  94598. * Gets the clock settings defined by the loaded CZML. If no clock is explicitly
  94599. * defined in the CZML, the combined availability of all objects is returned. If
  94600. * only static data exists, this value is undefined.
  94601. * @memberof CzmlDataSource.prototype
  94602. * @type {DataSourceClock}
  94603. */
  94604. clock : {
  94605. get : function() {
  94606. return this._clock;
  94607. }
  94608. },
  94609. /**
  94610. * Gets the collection of {@link Entity} instances.
  94611. * @memberof CzmlDataSource.prototype
  94612. * @type {EntityCollection}
  94613. */
  94614. entities : {
  94615. get : function() {
  94616. return this._entityCollection;
  94617. }
  94618. },
  94619. /**
  94620. * Gets a value indicating if the data source is currently loading data.
  94621. * @memberof CzmlDataSource.prototype
  94622. * @type {Boolean}
  94623. */
  94624. isLoading : {
  94625. get : function() {
  94626. return this._isLoading;
  94627. }
  94628. },
  94629. /**
  94630. * Gets an event that will be raised when the underlying data changes.
  94631. * @memberof CzmlDataSource.prototype
  94632. * @type {Event}
  94633. */
  94634. changedEvent : {
  94635. get : function() {
  94636. return this._changed;
  94637. }
  94638. },
  94639. /**
  94640. * Gets an event that will be raised if an error is encountered during processing.
  94641. * @memberof CzmlDataSource.prototype
  94642. * @type {Event}
  94643. */
  94644. errorEvent : {
  94645. get : function() {
  94646. return this._error;
  94647. }
  94648. },
  94649. /**
  94650. * Gets an event that will be raised when the data source either starts or stops loading.
  94651. * @memberof CzmlDataSource.prototype
  94652. * @type {Event}
  94653. */
  94654. loadingEvent : {
  94655. get : function() {
  94656. return this._loading;
  94657. }
  94658. },
  94659. /**
  94660. * Gets whether or not this data source should be displayed.
  94661. * @memberof CzmlDataSource.prototype
  94662. * @type {Boolean}
  94663. */
  94664. show : {
  94665. get : function() {
  94666. return this._entityCollection.show;
  94667. },
  94668. set : function(value) {
  94669. this._entityCollection.show = value;
  94670. }
  94671. },
  94672. /**
  94673. * Gets or sets the clustering options for this data source. This object can be shared between multiple data sources.
  94674. *
  94675. * @memberof CzmlDataSource.prototype
  94676. * @type {EntityCluster}
  94677. */
  94678. clustering : {
  94679. get : function() {
  94680. return this._entityCluster;
  94681. },
  94682. set : function(value) {
  94683. if (!defined(value)) {
  94684. throw new DeveloperError('value must be defined.');
  94685. }
  94686. this._entityCluster = value;
  94687. }
  94688. }
  94689. });
  94690. /**
  94691. * Gets the array of CZML processing functions.
  94692. * @memberof CzmlDataSource
  94693. * @type Array
  94694. */
  94695. CzmlDataSource.updaters = [
  94696. processBillboard, //
  94697. processBox, //
  94698. processCorridor, //
  94699. processCylinder, //
  94700. processEllipse, //
  94701. processEllipsoid, //
  94702. processLabel, //
  94703. processModel, //
  94704. processName, //
  94705. processDescription, //
  94706. processPath, //
  94707. processPoint, //
  94708. processPolygon, //
  94709. processPolyline, //
  94710. processRectangle, //
  94711. processPosition, //
  94712. processViewFrom, //
  94713. processWall, //
  94714. processOrientation, //
  94715. processAvailability];
  94716. /**
  94717. * Processes the provided url or CZML object without clearing any existing data.
  94718. *
  94719. * @param {String|Object} czml A url or CZML object to be processed.
  94720. * @param {Object} [options] An object with the following properties:
  94721. * @param {String} [options.sourceUri] Overrides the url to use for resolving relative links.
  94722. * @returns {Promise.<CzmlDataSource>} A promise that resolves to this instances once the data is processed.
  94723. */
  94724. CzmlDataSource.prototype.process = function(czml, options) {
  94725. return load(this, czml, options, false);
  94726. };
  94727. /**
  94728. * Loads the provided url or CZML object, replacing any existing data.
  94729. *
  94730. * @param {String|Object} czml A url or CZML object to be processed.
  94731. * @param {Object} [options] An object with the following properties:
  94732. * @param {String} [options.sourceUri] Overrides the url to use for resolving relative links.
  94733. * @returns {Promise.<CzmlDataSource>} A promise that resolves to this instances once the data is processed.
  94734. */
  94735. CzmlDataSource.prototype.load = function(czml, options) {
  94736. return load(this, czml, options, true);
  94737. };
  94738. /**
  94739. * A helper function used by custom CZML updater functions
  94740. * which creates or updates a {@link Property} from a CZML packet.
  94741. * @function
  94742. *
  94743. * @param {Function} type The constructor function for the property being processed.
  94744. * @param {Object} object The object on which the property will be added or updated.
  94745. * @param {String} propertyName The name of the property on the object.
  94746. * @param {Object} packetData The CZML packet being processed.
  94747. * @param {TimeInterval} interval A constraining interval for which the data is valid.
  94748. * @param {String} sourceUri The originating uri of the data being processed.
  94749. * @param {EntityCollection} entityCollection The collection being processsed.
  94750. */
  94751. CzmlDataSource.processPacketData = processPacketData;
  94752. /**
  94753. * A helper function used by custom CZML updater functions
  94754. * which creates or updates a {@link PositionProperty} from a CZML packet.
  94755. * @function
  94756. *
  94757. * @param {Object} object The object on which the property will be added or updated.
  94758. * @param {String} propertyName The name of the property on the object.
  94759. * @param {Object} packetData The CZML packet being processed.
  94760. * @param {TimeInterval} interval A constraining interval for which the data is valid.
  94761. * @param {String} sourceUri The originating uri of the data being processed.
  94762. * @param {EntityCollection} entityCollection The collection being processsed.
  94763. */
  94764. CzmlDataSource.processPositionPacketData = processPositionPacketData;
  94765. /**
  94766. * A helper function used by custom CZML updater functions
  94767. * which creates or updates a {@link MaterialProperty} from a CZML packet.
  94768. * @function
  94769. *
  94770. * @param {Object} object The object on which the property will be added or updated.
  94771. * @param {String} propertyName The name of the property on the object.
  94772. * @param {Object} packetData The CZML packet being processed.
  94773. * @param {TimeInterval} interval A constraining interval for which the data is valid.
  94774. * @param {String} sourceUri The originating uri of the data being processed.
  94775. * @param {EntityCollection} entityCollection The collection being processsed.
  94776. */
  94777. CzmlDataSource.processMaterialPacketData = processMaterialPacketData;
  94778. CzmlDataSource._processCzml = function(czml, entityCollection, sourceUri, updaterFunctions, dataSource) {
  94779. updaterFunctions = defined(updaterFunctions) ? updaterFunctions : CzmlDataSource.updaters;
  94780. if (isArray(czml)) {
  94781. for (var i = 0, len = czml.length; i < len; i++) {
  94782. processCzmlPacket(czml[i], entityCollection, updaterFunctions, sourceUri, dataSource);
  94783. }
  94784. } else {
  94785. processCzmlPacket(czml, entityCollection, updaterFunctions, sourceUri, dataSource);
  94786. }
  94787. };
  94788. return CzmlDataSource;
  94789. });
  94790. /*global define*/
  94791. define('DataSources/DataSourceCollection',[
  94792. '../Core/defaultValue',
  94793. '../Core/defined',
  94794. '../Core/defineProperties',
  94795. '../Core/destroyObject',
  94796. '../Core/DeveloperError',
  94797. '../Core/Event',
  94798. '../ThirdParty/when'
  94799. ], function(
  94800. defaultValue,
  94801. defined,
  94802. defineProperties,
  94803. destroyObject,
  94804. DeveloperError,
  94805. Event,
  94806. when) {
  94807. 'use strict';
  94808. /**
  94809. * A collection of {@link DataSource} instances.
  94810. * @alias DataSourceCollection
  94811. * @constructor
  94812. */
  94813. function DataSourceCollection() {
  94814. this._dataSources = [];
  94815. this._dataSourceAdded = new Event();
  94816. this._dataSourceRemoved = new Event();
  94817. }
  94818. defineProperties(DataSourceCollection.prototype, {
  94819. /**
  94820. * Gets the number of data sources in this collection.
  94821. * @memberof DataSourceCollection.prototype
  94822. * @type {Number}
  94823. * @readonly
  94824. */
  94825. length : {
  94826. get : function() {
  94827. return this._dataSources.length;
  94828. }
  94829. },
  94830. /**
  94831. * An event that is raised when a data source is added to the collection.
  94832. * Event handlers are passed the data source that was added.
  94833. * @memberof DataSourceCollection.prototype
  94834. * @type {Event}
  94835. * @readonly
  94836. */
  94837. dataSourceAdded : {
  94838. get : function() {
  94839. return this._dataSourceAdded;
  94840. }
  94841. },
  94842. /**
  94843. * An event that is raised when a data source is removed from the collection.
  94844. * Event handlers are passed the data source that was removed.
  94845. * @memberof DataSourceCollection.prototype
  94846. * @type {Event}
  94847. * @readonly
  94848. */
  94849. dataSourceRemoved : {
  94850. get : function() {
  94851. return this._dataSourceRemoved;
  94852. }
  94853. }
  94854. });
  94855. /**
  94856. * Adds a data source to the collection.
  94857. *
  94858. * @param {DataSource|Promise.<DataSource>} dataSource A data source or a promise to a data source to add to the collection.
  94859. * When passing a promise, the data source will not actually be added
  94860. * to the collection until the promise resolves successfully.
  94861. * @returns {Promise.<DataSource>} A Promise that resolves once the data source has been added to the collection.
  94862. */
  94863. DataSourceCollection.prototype.add = function(dataSource) {
  94864. if (!defined(dataSource)) {
  94865. throw new DeveloperError('dataSource is required.');
  94866. }
  94867. var that = this;
  94868. var dataSources = this._dataSources;
  94869. return when(dataSource, function(value) {
  94870. //Only add the data source if removeAll has not been called
  94871. //Since it was added.
  94872. if (dataSources === that._dataSources) {
  94873. that._dataSources.push(value);
  94874. that._dataSourceAdded.raiseEvent(that, value);
  94875. }
  94876. return value;
  94877. });
  94878. };
  94879. /**
  94880. * Removes a data source from this collection, if present.
  94881. *
  94882. * @param {DataSource} dataSource The data source to remove.
  94883. * @param {Boolean} [destroy=false] Whether to destroy the data source in addition to removing it.
  94884. * @returns {Boolean} true if the data source was in the collection and was removed,
  94885. * false if the data source was not in the collection.
  94886. */
  94887. DataSourceCollection.prototype.remove = function(dataSource, destroy) {
  94888. destroy = defaultValue(destroy, false);
  94889. var index = this._dataSources.indexOf(dataSource);
  94890. if (index !== -1) {
  94891. this._dataSources.splice(index, 1);
  94892. this._dataSourceRemoved.raiseEvent(this, dataSource);
  94893. if (destroy && typeof dataSource.destroy === 'function') {
  94894. dataSource.destroy();
  94895. }
  94896. return true;
  94897. }
  94898. return false;
  94899. };
  94900. /**
  94901. * Removes all data sources from this collection.
  94902. *
  94903. * @param {Boolean} [destroy=false] whether to destroy the data sources in addition to removing them.
  94904. */
  94905. DataSourceCollection.prototype.removeAll = function(destroy) {
  94906. destroy = defaultValue(destroy, false);
  94907. var dataSources = this._dataSources;
  94908. for (var i = 0, len = dataSources.length; i < len; ++i) {
  94909. var dataSource = dataSources[i];
  94910. this._dataSourceRemoved.raiseEvent(this, dataSource);
  94911. if (destroy && typeof dataSource.destroy === 'function') {
  94912. dataSource.destroy();
  94913. }
  94914. }
  94915. this._dataSources = [];
  94916. };
  94917. /**
  94918. * Checks to see if the collection contains a given data source.
  94919. *
  94920. * @param {DataSource} dataSource The data source to check for.
  94921. * @returns {Boolean} true if the collection contains the data source, false otherwise.
  94922. */
  94923. DataSourceCollection.prototype.contains = function(dataSource) {
  94924. return this.indexOf(dataSource) !== -1;
  94925. };
  94926. /**
  94927. * Determines the index of a given data source in the collection.
  94928. *
  94929. * @param {DataSource} dataSource The data source to find the index of.
  94930. * @returns {Number} The index of the data source in the collection, or -1 if the data source does not exist in the collection.
  94931. */
  94932. DataSourceCollection.prototype.indexOf = function(dataSource) {
  94933. return this._dataSources.indexOf(dataSource);
  94934. };
  94935. /**
  94936. * Gets a data source by index from the collection.
  94937. *
  94938. * @param {Number} index the index to retrieve.
  94939. */
  94940. DataSourceCollection.prototype.get = function(index) {
  94941. if (!defined(index)) {
  94942. throw new DeveloperError('index is required.');
  94943. }
  94944. return this._dataSources[index];
  94945. };
  94946. /**
  94947. * Returns true if this object was destroyed; otherwise, false.
  94948. * If this object was destroyed, it should not be used; calling any function other than
  94949. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  94950. *
  94951. * @returns {Boolean} true if this object was destroyed; otherwise, false.
  94952. *
  94953. * @see DataSourceCollection#destroy
  94954. */
  94955. DataSourceCollection.prototype.isDestroyed = function() {
  94956. return false;
  94957. };
  94958. /**
  94959. * Destroys the resources held by all data sources in this collection. Explicitly destroying this
  94960. * object allows for deterministic release of WebGL resources, instead of relying on the garbage
  94961. * collector. Once this object is destroyed, it should not be used; calling any function other than
  94962. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  94963. * assign the return value (<code>undefined</code>) to the object as done in the example.
  94964. *
  94965. * @returns {undefined}
  94966. *
  94967. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  94968. *
  94969. *
  94970. * @example
  94971. * dataSourceCollection = dataSourceCollection && dataSourceCollection.destroy();
  94972. *
  94973. * @see DataSourceCollection#isDestroyed
  94974. */
  94975. DataSourceCollection.prototype.destroy = function() {
  94976. this.removeAll(true);
  94977. return destroyObject(this);
  94978. };
  94979. return DataSourceCollection;
  94980. });
  94981. /*global define*/
  94982. define('DataSources/EllipseGeometryUpdater',[
  94983. '../Core/Color',
  94984. '../Core/ColorGeometryInstanceAttribute',
  94985. '../Core/defaultValue',
  94986. '../Core/defined',
  94987. '../Core/defineProperties',
  94988. '../Core/destroyObject',
  94989. '../Core/DeveloperError',
  94990. '../Core/DistanceDisplayCondition',
  94991. '../Core/DistanceDisplayConditionGeometryInstanceAttribute',
  94992. '../Core/EllipseGeometry',
  94993. '../Core/EllipseOutlineGeometry',
  94994. '../Core/Event',
  94995. '../Core/GeometryInstance',
  94996. '../Core/Iso8601',
  94997. '../Core/oneTimeWarning',
  94998. '../Core/ShowGeometryInstanceAttribute',
  94999. '../Scene/GroundPrimitive',
  95000. '../Scene/MaterialAppearance',
  95001. '../Scene/PerInstanceColorAppearance',
  95002. '../Scene/Primitive',
  95003. '../Scene/ShadowMode',
  95004. './ColorMaterialProperty',
  95005. './ConstantProperty',
  95006. './dynamicGeometryGetBoundingSphere',
  95007. './MaterialProperty',
  95008. './Property'
  95009. ], function(
  95010. Color,
  95011. ColorGeometryInstanceAttribute,
  95012. defaultValue,
  95013. defined,
  95014. defineProperties,
  95015. destroyObject,
  95016. DeveloperError,
  95017. DistanceDisplayCondition,
  95018. DistanceDisplayConditionGeometryInstanceAttribute,
  95019. EllipseGeometry,
  95020. EllipseOutlineGeometry,
  95021. Event,
  95022. GeometryInstance,
  95023. Iso8601,
  95024. oneTimeWarning,
  95025. ShowGeometryInstanceAttribute,
  95026. GroundPrimitive,
  95027. MaterialAppearance,
  95028. PerInstanceColorAppearance,
  95029. Primitive,
  95030. ShadowMode,
  95031. ColorMaterialProperty,
  95032. ConstantProperty,
  95033. dynamicGeometryGetBoundingSphere,
  95034. MaterialProperty,
  95035. Property) {
  95036. 'use strict';
  95037. var defaultMaterial = new ColorMaterialProperty(Color.WHITE);
  95038. var defaultShow = new ConstantProperty(true);
  95039. var defaultFill = new ConstantProperty(true);
  95040. var defaultOutline = new ConstantProperty(false);
  95041. var defaultOutlineColor = new ConstantProperty(Color.BLACK);
  95042. var defaultShadows = new ConstantProperty(ShadowMode.DISABLED);
  95043. var defaultDistanceDisplayCondition = new ConstantProperty(new DistanceDisplayCondition());
  95044. var scratchColor = new Color();
  95045. function GeometryOptions(entity) {
  95046. this.id = entity;
  95047. this.vertexFormat = undefined;
  95048. this.center = undefined;
  95049. this.semiMajorAxis = undefined;
  95050. this.semiMinorAxis = undefined;
  95051. this.rotation = undefined;
  95052. this.height = undefined;
  95053. this.extrudedHeight = undefined;
  95054. this.granularity = undefined;
  95055. this.stRotation = undefined;
  95056. this.numberOfVerticalLines = undefined;
  95057. }
  95058. /**
  95059. * A {@link GeometryUpdater} for ellipses.
  95060. * Clients do not normally create this class directly, but instead rely on {@link DataSourceDisplay}.
  95061. * @alias EllipseGeometryUpdater
  95062. * @constructor
  95063. *
  95064. * @param {Entity} entity The entity containing the geometry to be visualized.
  95065. * @param {Scene} scene The scene where visualization is taking place.
  95066. */
  95067. function EllipseGeometryUpdater(entity, scene) {
  95068. if (!defined(entity)) {
  95069. throw new DeveloperError('entity is required');
  95070. }
  95071. if (!defined(scene)) {
  95072. throw new DeveloperError('scene is required');
  95073. }
  95074. this._entity = entity;
  95075. this._scene = scene;
  95076. this._entitySubscription = entity.definitionChanged.addEventListener(EllipseGeometryUpdater.prototype._onEntityPropertyChanged, this);
  95077. this._fillEnabled = false;
  95078. this._isClosed = false;
  95079. this._dynamic = false;
  95080. this._outlineEnabled = false;
  95081. this._geometryChanged = new Event();
  95082. this._showProperty = undefined;
  95083. this._materialProperty = undefined;
  95084. this._hasConstantOutline = true;
  95085. this._showOutlineProperty = undefined;
  95086. this._outlineColorProperty = undefined;
  95087. this._outlineWidth = 1.0;
  95088. this._shadowsProperty = undefined;
  95089. this._distanceDisplayConditionProperty = undefined;
  95090. this._onTerrain = false;
  95091. this._options = new GeometryOptions(entity);
  95092. this._onEntityPropertyChanged(entity, 'ellipse', entity.ellipse, undefined);
  95093. }
  95094. defineProperties(EllipseGeometryUpdater, {
  95095. /**
  95096. * Gets the type of Appearance to use for simple color-based geometry.
  95097. * @memberof EllipseGeometryUpdater
  95098. * @type {Appearance}
  95099. */
  95100. perInstanceColorAppearanceType : {
  95101. value : PerInstanceColorAppearance
  95102. },
  95103. /**
  95104. * Gets the type of Appearance to use for material-based geometry.
  95105. * @memberof EllipseGeometryUpdater
  95106. * @type {Appearance}
  95107. */
  95108. materialAppearanceType : {
  95109. value : MaterialAppearance
  95110. }
  95111. });
  95112. defineProperties(EllipseGeometryUpdater.prototype, {
  95113. /**
  95114. * Gets the entity associated with this geometry.
  95115. * @memberof EllipseGeometryUpdater.prototype
  95116. *
  95117. * @type {Entity}
  95118. * @readonly
  95119. */
  95120. entity : {
  95121. get : function() {
  95122. return this._entity;
  95123. }
  95124. },
  95125. /**
  95126. * Gets a value indicating if the geometry has a fill component.
  95127. * @memberof EllipseGeometryUpdater.prototype
  95128. *
  95129. * @type {Boolean}
  95130. * @readonly
  95131. */
  95132. fillEnabled : {
  95133. get : function() {
  95134. return this._fillEnabled;
  95135. }
  95136. },
  95137. /**
  95138. * Gets a value indicating if fill visibility varies with simulation time.
  95139. * @memberof EllipseGeometryUpdater.prototype
  95140. *
  95141. * @type {Boolean}
  95142. * @readonly
  95143. */
  95144. hasConstantFill : {
  95145. get : function() {
  95146. return !this._fillEnabled ||
  95147. (!defined(this._entity.availability) &&
  95148. Property.isConstant(this._showProperty) &&
  95149. Property.isConstant(this._fillProperty));
  95150. }
  95151. },
  95152. /**
  95153. * Gets the material property used to fill the geometry.
  95154. * @memberof EllipseGeometryUpdater.prototype
  95155. *
  95156. * @type {MaterialProperty}
  95157. * @readonly
  95158. */
  95159. fillMaterialProperty : {
  95160. get : function() {
  95161. return this._materialProperty;
  95162. }
  95163. },
  95164. /**
  95165. * Gets a value indicating if the geometry has an outline component.
  95166. * @memberof EllipseGeometryUpdater.prototype
  95167. *
  95168. * @type {Boolean}
  95169. * @readonly
  95170. */
  95171. outlineEnabled : {
  95172. get : function() {
  95173. return this._outlineEnabled;
  95174. }
  95175. },
  95176. /**
  95177. * Gets a value indicating if outline visibility varies with simulation time.
  95178. * @memberof EllipseGeometryUpdater.prototype
  95179. *
  95180. * @type {Boolean}
  95181. * @readonly
  95182. */
  95183. hasConstantOutline : {
  95184. get : function() {
  95185. return !this._outlineEnabled ||
  95186. (!defined(this._entity.availability) &&
  95187. Property.isConstant(this._showProperty) &&
  95188. Property.isConstant(this._showOutlineProperty));
  95189. }
  95190. },
  95191. /**
  95192. * Gets the {@link Color} property for the geometry outline.
  95193. * @memberof EllipseGeometryUpdater.prototype
  95194. *
  95195. * @type {Property}
  95196. * @readonly
  95197. */
  95198. outlineColorProperty : {
  95199. get : function() {
  95200. return this._outlineColorProperty;
  95201. }
  95202. },
  95203. /**
  95204. * Gets the constant with of the geometry outline, in pixels.
  95205. * This value is only valid if isDynamic is false.
  95206. * @memberof EllipseGeometryUpdater.prototype
  95207. *
  95208. * @type {Number}
  95209. * @readonly
  95210. */
  95211. outlineWidth : {
  95212. get : function() {
  95213. return this._outlineWidth;
  95214. }
  95215. },
  95216. /**
  95217. * Gets the property specifying whether the geometry
  95218. * casts or receives shadows from each light source.
  95219. * @memberof EllipseGeometryUpdater.prototype
  95220. *
  95221. * @type {Property}
  95222. * @readonly
  95223. */
  95224. shadowsProperty : {
  95225. get : function() {
  95226. return this._shadowsProperty;
  95227. }
  95228. },
  95229. /**
  95230. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this geometry will be displayed.
  95231. * @memberof EllipseGeometryUpdater.prototype
  95232. *
  95233. * @type {Property}
  95234. * @readonly
  95235. */
  95236. distanceDisplayConditionProperty : {
  95237. get : function() {
  95238. return this._distanceDisplayConditionProperty;
  95239. }
  95240. },
  95241. /**
  95242. * Gets a value indicating if the geometry is time-varying.
  95243. * If true, all visualization is delegated to the {@link DynamicGeometryUpdater}
  95244. * returned by GeometryUpdater#createDynamicUpdater.
  95245. * @memberof EllipseGeometryUpdater.prototype
  95246. *
  95247. * @type {Boolean}
  95248. * @readonly
  95249. */
  95250. isDynamic : {
  95251. get : function() {
  95252. return this._dynamic;
  95253. }
  95254. },
  95255. /**
  95256. * Gets a value indicating if the geometry is closed.
  95257. * This property is only valid for static geometry.
  95258. * @memberof EllipseGeometryUpdater.prototype
  95259. *
  95260. * @type {Boolean}
  95261. * @readonly
  95262. */
  95263. isClosed : {
  95264. get : function() {
  95265. return this._isClosed;
  95266. }
  95267. },
  95268. /**
  95269. * Gets a value indicating if the geometry should be drawn on terrain.
  95270. * @memberof EllipseGeometryUpdater.prototype
  95271. *
  95272. * @type {Boolean}
  95273. * @readonly
  95274. */
  95275. onTerrain : {
  95276. get : function() {
  95277. return this._onTerrain;
  95278. }
  95279. },
  95280. /**
  95281. * Gets an event that is raised whenever the public properties
  95282. * of this updater change.
  95283. * @memberof EllipseGeometryUpdater.prototype
  95284. *
  95285. * @type {Boolean}
  95286. * @readonly
  95287. */
  95288. geometryChanged : {
  95289. get : function() {
  95290. return this._geometryChanged;
  95291. }
  95292. }
  95293. });
  95294. /**
  95295. * Checks if the geometry is outlined at the provided time.
  95296. *
  95297. * @param {JulianDate} time The time for which to retrieve visibility.
  95298. * @returns {Boolean} true if geometry is outlined at the provided time, false otherwise.
  95299. */
  95300. EllipseGeometryUpdater.prototype.isOutlineVisible = function(time) {
  95301. var entity = this._entity;
  95302. return this._outlineEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time);
  95303. };
  95304. /**
  95305. * Checks if the geometry is filled at the provided time.
  95306. *
  95307. * @param {JulianDate} time The time for which to retrieve visibility.
  95308. * @returns {Boolean} true if geometry is filled at the provided time, false otherwise.
  95309. */
  95310. EllipseGeometryUpdater.prototype.isFilled = function(time) {
  95311. var entity = this._entity;
  95312. return this._fillEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._fillProperty.getValue(time);
  95313. };
  95314. /**
  95315. * Creates the geometry instance which represents the fill of the geometry.
  95316. *
  95317. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  95318. * @returns {GeometryInstance} The geometry instance representing the filled portion of the geometry.
  95319. *
  95320. * @exception {DeveloperError} This instance does not represent a filled geometry.
  95321. */
  95322. EllipseGeometryUpdater.prototype.createFillGeometryInstance = function(time) {
  95323. if (!defined(time)) {
  95324. throw new DeveloperError('time is required.');
  95325. }
  95326. if (!this._fillEnabled) {
  95327. throw new DeveloperError('This instance does not represent a filled geometry.');
  95328. }
  95329. var entity = this._entity;
  95330. var isAvailable = entity.isAvailable(time);
  95331. var attributes;
  95332. var color;
  95333. var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time));
  95334. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  95335. var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
  95336. if (this._materialProperty instanceof ColorMaterialProperty) {
  95337. var currentColor = Color.WHITE;
  95338. if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) {
  95339. currentColor = this._materialProperty.color.getValue(time);
  95340. }
  95341. color = ColorGeometryInstanceAttribute.fromColor(currentColor);
  95342. attributes = {
  95343. show : show,
  95344. distanceDisplayCondition : distanceDisplayConditionAttribute,
  95345. color : color
  95346. };
  95347. } else {
  95348. attributes = {
  95349. show : show,
  95350. distanceDisplayCondition : distanceDisplayConditionAttribute
  95351. };
  95352. }
  95353. return new GeometryInstance({
  95354. id : entity,
  95355. geometry : new EllipseGeometry(this._options),
  95356. attributes : attributes
  95357. });
  95358. };
  95359. /**
  95360. * Creates the geometry instance which represents the outline of the geometry.
  95361. *
  95362. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  95363. * @returns {GeometryInstance} The geometry instance representing the outline portion of the geometry.
  95364. *
  95365. * @exception {DeveloperError} This instance does not represent an outlined geometry.
  95366. */
  95367. EllipseGeometryUpdater.prototype.createOutlineGeometryInstance = function(time) {
  95368. if (!defined(time)) {
  95369. throw new DeveloperError('time is required.');
  95370. }
  95371. if (!this._outlineEnabled) {
  95372. throw new DeveloperError('This instance does not represent an outlined geometry.');
  95373. }
  95374. var entity = this._entity;
  95375. var isAvailable = entity.isAvailable(time);
  95376. var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK);
  95377. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  95378. return new GeometryInstance({
  95379. id : entity,
  95380. geometry : new EllipseOutlineGeometry(this._options),
  95381. attributes : {
  95382. show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
  95383. color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
  95384. distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition)
  95385. }
  95386. });
  95387. };
  95388. /**
  95389. * Returns true if this object was destroyed; otherwise, false.
  95390. *
  95391. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  95392. */
  95393. EllipseGeometryUpdater.prototype.isDestroyed = function() {
  95394. return false;
  95395. };
  95396. /**
  95397. * Destroys and resources used by the object. Once an object is destroyed, it should not be used.
  95398. *
  95399. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  95400. */
  95401. EllipseGeometryUpdater.prototype.destroy = function() {
  95402. this._entitySubscription();
  95403. destroyObject(this);
  95404. };
  95405. EllipseGeometryUpdater.prototype._onEntityPropertyChanged = function(entity, propertyName, newValue, oldValue) {
  95406. if (!(propertyName === 'availability' || propertyName === 'position' || propertyName === 'ellipse')) {
  95407. return;
  95408. }
  95409. var ellipse = this._entity.ellipse;
  95410. if (!defined(ellipse)) {
  95411. if (this._fillEnabled || this._outlineEnabled) {
  95412. this._fillEnabled = false;
  95413. this._outlineEnabled = false;
  95414. this._geometryChanged.raiseEvent(this);
  95415. }
  95416. return;
  95417. }
  95418. var fillProperty = ellipse.fill;
  95419. var fillEnabled = defined(fillProperty) && fillProperty.isConstant ? fillProperty.getValue(Iso8601.MINIMUM_VALUE) : true;
  95420. var outlineProperty = ellipse.outline;
  95421. var outlineEnabled = defined(outlineProperty);
  95422. if (outlineEnabled && outlineProperty.isConstant) {
  95423. outlineEnabled = outlineProperty.getValue(Iso8601.MINIMUM_VALUE);
  95424. }
  95425. if (!fillEnabled && !outlineEnabled) {
  95426. if (this._fillEnabled || this._outlineEnabled) {
  95427. this._fillEnabled = false;
  95428. this._outlineEnabled = false;
  95429. this._geometryChanged.raiseEvent(this);
  95430. }
  95431. return;
  95432. }
  95433. var position = this._entity.position;
  95434. var semiMajorAxis = ellipse.semiMajorAxis;
  95435. var semiMinorAxis = ellipse.semiMinorAxis;
  95436. var show = ellipse.show;
  95437. if ((defined(show) && show.isConstant && !show.getValue(Iso8601.MINIMUM_VALUE)) || //
  95438. (!defined(position) || !defined(semiMajorAxis) || !defined(semiMinorAxis))) {
  95439. if (this._fillEnabled || this._outlineEnabled) {
  95440. this._fillEnabled = false;
  95441. this._outlineEnabled = false;
  95442. this._geometryChanged.raiseEvent(this);
  95443. }
  95444. return;
  95445. }
  95446. var material = defaultValue(ellipse.material, defaultMaterial);
  95447. var isColorMaterial = material instanceof ColorMaterialProperty;
  95448. this._materialProperty = material;
  95449. this._fillProperty = defaultValue(fillProperty, defaultFill);
  95450. this._showProperty = defaultValue(show, defaultShow);
  95451. this._showOutlineProperty = defaultValue(ellipse.outline, defaultOutline);
  95452. this._outlineColorProperty = outlineEnabled ? defaultValue(ellipse.outlineColor, defaultOutlineColor) : undefined;
  95453. this._shadowsProperty = defaultValue(ellipse.shadows, defaultShadows);
  95454. this._distanceDisplayConditionProperty = defaultValue(ellipse.distanceDisplayCondition, defaultDistanceDisplayCondition);
  95455. var rotation = ellipse.rotation;
  95456. var height = ellipse.height;
  95457. var extrudedHeight = ellipse.extrudedHeight;
  95458. var granularity = ellipse.granularity;
  95459. var stRotation = ellipse.stRotation;
  95460. var outlineWidth = ellipse.outlineWidth;
  95461. var numberOfVerticalLines = ellipse.numberOfVerticalLines;
  95462. var onTerrain = fillEnabled && !defined(height) && !defined(extrudedHeight) &&
  95463. isColorMaterial && GroundPrimitive.isSupported(this._scene);
  95464. if (outlineEnabled && onTerrain) {
  95465. oneTimeWarning(oneTimeWarning.geometryOutlines);
  95466. outlineEnabled = false;
  95467. }
  95468. this._fillEnabled = fillEnabled;
  95469. this._onTerrain = onTerrain;
  95470. this._isClosed = defined(extrudedHeight) || onTerrain;
  95471. this._outlineEnabled = outlineEnabled;
  95472. if (!position.isConstant || //
  95473. !semiMajorAxis.isConstant || //
  95474. !semiMinorAxis.isConstant || //
  95475. !Property.isConstant(rotation) || //
  95476. !Property.isConstant(height) || //
  95477. !Property.isConstant(extrudedHeight) || //
  95478. !Property.isConstant(granularity) || //
  95479. !Property.isConstant(stRotation) || //
  95480. !Property.isConstant(outlineWidth) || //
  95481. !Property.isConstant(numberOfVerticalLines) || //
  95482. (onTerrain && !Property.isConstant(material))) {
  95483. if (!this._dynamic) {
  95484. this._dynamic = true;
  95485. this._geometryChanged.raiseEvent(this);
  95486. }
  95487. } else {
  95488. var options = this._options;
  95489. options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat;
  95490. options.center = position.getValue(Iso8601.MINIMUM_VALUE, options.center);
  95491. options.semiMajorAxis = semiMajorAxis.getValue(Iso8601.MINIMUM_VALUE, options.semiMajorAxis);
  95492. options.semiMinorAxis = semiMinorAxis.getValue(Iso8601.MINIMUM_VALUE, options.semiMinorAxis);
  95493. options.rotation = defined(rotation) ? rotation.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  95494. options.height = defined(height) ? height.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  95495. options.extrudedHeight = defined(extrudedHeight) ? extrudedHeight.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  95496. options.granularity = defined(granularity) ? granularity.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  95497. options.stRotation = defined(stRotation) ? stRotation.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  95498. options.numberOfVerticalLines = defined(numberOfVerticalLines) ? numberOfVerticalLines.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  95499. this._outlineWidth = defined(outlineWidth) ? outlineWidth.getValue(Iso8601.MINIMUM_VALUE) : 1.0;
  95500. this._dynamic = false;
  95501. this._geometryChanged.raiseEvent(this);
  95502. }
  95503. };
  95504. /**
  95505. * Creates the dynamic updater to be used when GeometryUpdater#isDynamic is true.
  95506. *
  95507. * @param {PrimitiveCollection} primitives The primitive collection to use.
  95508. * @returns {DynamicGeometryUpdater} The dynamic updater used to update the geometry each frame.
  95509. *
  95510. * @exception {DeveloperError} This instance does not represent dynamic geometry.
  95511. */
  95512. EllipseGeometryUpdater.prototype.createDynamicUpdater = function(primitives, groundPrimitives) {
  95513. if (!this._dynamic) {
  95514. throw new DeveloperError('This instance does not represent dynamic geometry.');
  95515. }
  95516. if (!defined(primitives)) {
  95517. throw new DeveloperError('primitives is required.');
  95518. }
  95519. return new DynamicGeometryUpdater(primitives, groundPrimitives, this);
  95520. };
  95521. /**
  95522. * @private
  95523. */
  95524. function DynamicGeometryUpdater(primitives, groundPrimitives, geometryUpdater) {
  95525. this._primitives = primitives;
  95526. this._groundPrimitives = groundPrimitives;
  95527. this._primitive = undefined;
  95528. this._outlinePrimitive = undefined;
  95529. this._geometryUpdater = geometryUpdater;
  95530. this._options = new GeometryOptions(geometryUpdater._entity);
  95531. }
  95532. DynamicGeometryUpdater.prototype.update = function(time) {
  95533. if (!defined(time)) {
  95534. throw new DeveloperError('time is required.');
  95535. }
  95536. var geometryUpdater = this._geometryUpdater;
  95537. var onTerrain = geometryUpdater._onTerrain;
  95538. var primitives = this._primitives;
  95539. var groundPrimitives = this._groundPrimitives;
  95540. if (onTerrain) {
  95541. groundPrimitives.removeAndDestroy(this._primitive);
  95542. } else {
  95543. primitives.removeAndDestroy(this._primitive);
  95544. primitives.removeAndDestroy(this._outlinePrimitive);
  95545. this._outlinePrimitive = undefined;
  95546. }
  95547. this._primitive = undefined;
  95548. var entity = geometryUpdater._entity;
  95549. var ellipse = entity.ellipse;
  95550. if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(ellipse.show, time, true)) {
  95551. return;
  95552. }
  95553. var options = this._options;
  95554. var center = Property.getValueOrUndefined(entity.position, time, options.center);
  95555. var semiMajorAxis = Property.getValueOrUndefined(ellipse.semiMajorAxis, time);
  95556. var semiMinorAxis = Property.getValueOrUndefined(ellipse.semiMinorAxis, time);
  95557. if (!defined(center) || !defined(semiMajorAxis) || !defined(semiMinorAxis)) {
  95558. return;
  95559. }
  95560. options.center = center;
  95561. options.semiMajorAxis = semiMajorAxis;
  95562. options.semiMinorAxis = semiMinorAxis;
  95563. options.rotation = Property.getValueOrUndefined(ellipse.rotation, time);
  95564. options.height = Property.getValueOrUndefined(ellipse.height, time);
  95565. options.extrudedHeight = Property.getValueOrUndefined(ellipse.extrudedHeight, time);
  95566. options.granularity = Property.getValueOrUndefined(ellipse.granularity, time);
  95567. options.stRotation = Property.getValueOrUndefined(ellipse.stRotation, time);
  95568. options.numberOfVerticalLines = Property.getValueOrUndefined(ellipse.numberOfVerticalLines, time);
  95569. var shadows = this._geometryUpdater.shadowsProperty.getValue(time);
  95570. var distanceDisplayConditionProperty = this._geometryUpdater.distanceDisplayConditionProperty;
  95571. var distanceDisplayCondition = distanceDisplayConditionProperty.getValue(time);
  95572. var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
  95573. if (Property.getValueOrDefault(ellipse.fill, time, true)) {
  95574. var fillMaterialProperty = geometryUpdater.fillMaterialProperty;
  95575. var material = MaterialProperty.getValue(time, fillMaterialProperty, this._material);
  95576. this._material = material;
  95577. if (onTerrain) {
  95578. var currentColor = Color.WHITE;
  95579. if (defined(fillMaterialProperty.color)) {
  95580. currentColor = fillMaterialProperty.color.getValue(time);
  95581. }
  95582. this._primitive = groundPrimitives.add(new GroundPrimitive({
  95583. geometryInstances : new GeometryInstance({
  95584. id : entity,
  95585. geometry : new EllipseGeometry(options),
  95586. attributes: {
  95587. color: ColorGeometryInstanceAttribute.fromColor(currentColor),
  95588. distanceDisplayCondition : distanceDisplayConditionAttribute
  95589. }
  95590. }),
  95591. asynchronous : false,
  95592. shadows : shadows
  95593. }));
  95594. } else {
  95595. var appearance = new MaterialAppearance({
  95596. material : material,
  95597. translucent : material.isTranslucent(),
  95598. closed : defined(options.extrudedHeight)
  95599. });
  95600. options.vertexFormat = appearance.vertexFormat;
  95601. this._primitive = primitives.add(new Primitive({
  95602. geometryInstances : new GeometryInstance({
  95603. id : entity,
  95604. geometry : new EllipseGeometry(options)
  95605. }),
  95606. attributes : {
  95607. distanceDisplayCondition : distanceDisplayConditionAttribute
  95608. },
  95609. appearance : appearance,
  95610. asynchronous : false,
  95611. shadows : shadows
  95612. }));
  95613. }
  95614. }
  95615. if (!onTerrain && Property.getValueOrDefault(ellipse.outline, time, false)) {
  95616. options.vertexFormat = PerInstanceColorAppearance.VERTEX_FORMAT;
  95617. var outlineColor = Property.getValueOrClonedDefault(ellipse.outlineColor, time, Color.BLACK, scratchColor);
  95618. var outlineWidth = Property.getValueOrDefault(ellipse.outlineWidth, time, 1.0);
  95619. var translucent = outlineColor.alpha !== 1.0;
  95620. this._outlinePrimitive = primitives.add(new Primitive({
  95621. geometryInstances : new GeometryInstance({
  95622. id : entity,
  95623. geometry : new EllipseOutlineGeometry(options),
  95624. attributes : {
  95625. color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
  95626. distanceDisplayCondition : distanceDisplayConditionAttribute
  95627. }
  95628. }),
  95629. appearance : new PerInstanceColorAppearance({
  95630. flat : true,
  95631. translucent : translucent,
  95632. renderState : {
  95633. lineWidth : geometryUpdater._scene.clampLineWidth(outlineWidth)
  95634. }
  95635. }),
  95636. asynchronous : false,
  95637. shadows : shadows
  95638. }));
  95639. }
  95640. };
  95641. DynamicGeometryUpdater.prototype.getBoundingSphere = function(entity, result) {
  95642. return dynamicGeometryGetBoundingSphere(entity, this._primitive, this._outlinePrimitive, result);
  95643. };
  95644. DynamicGeometryUpdater.prototype.isDestroyed = function() {
  95645. return false;
  95646. };
  95647. DynamicGeometryUpdater.prototype.destroy = function() {
  95648. var primitives = this._primitives;
  95649. var groundPrimitives = this._groundPrimitives;
  95650. if (this._geometryUpdater._onTerrain) {
  95651. groundPrimitives.removeAndDestroy(this._primitive);
  95652. } else {
  95653. primitives.removeAndDestroy(this._primitive);
  95654. }
  95655. primitives.removeAndDestroy(this._outlinePrimitive);
  95656. destroyObject(this);
  95657. };
  95658. return EllipseGeometryUpdater;
  95659. });
  95660. /*global define*/
  95661. define('DataSources/EllipsoidGeometryUpdater',[
  95662. '../Core/Cartesian3',
  95663. '../Core/Color',
  95664. '../Core/ColorGeometryInstanceAttribute',
  95665. '../Core/defaultValue',
  95666. '../Core/defined',
  95667. '../Core/defineProperties',
  95668. '../Core/destroyObject',
  95669. '../Core/DeveloperError',
  95670. '../Core/DistanceDisplayCondition',
  95671. '../Core/DistanceDisplayConditionGeometryInstanceAttribute',
  95672. '../Core/EllipsoidGeometry',
  95673. '../Core/EllipsoidOutlineGeometry',
  95674. '../Core/Event',
  95675. '../Core/GeometryInstance',
  95676. '../Core/Iso8601',
  95677. '../Core/Matrix4',
  95678. '../Core/ShowGeometryInstanceAttribute',
  95679. '../Scene/MaterialAppearance',
  95680. '../Scene/PerInstanceColorAppearance',
  95681. '../Scene/Primitive',
  95682. '../Scene/SceneMode',
  95683. '../Scene/ShadowMode',
  95684. './ColorMaterialProperty',
  95685. './ConstantProperty',
  95686. './dynamicGeometryGetBoundingSphere',
  95687. './MaterialProperty',
  95688. './Property'
  95689. ], function(
  95690. Cartesian3,
  95691. Color,
  95692. ColorGeometryInstanceAttribute,
  95693. defaultValue,
  95694. defined,
  95695. defineProperties,
  95696. destroyObject,
  95697. DeveloperError,
  95698. DistanceDisplayCondition,
  95699. DistanceDisplayConditionGeometryInstanceAttribute,
  95700. EllipsoidGeometry,
  95701. EllipsoidOutlineGeometry,
  95702. Event,
  95703. GeometryInstance,
  95704. Iso8601,
  95705. Matrix4,
  95706. ShowGeometryInstanceAttribute,
  95707. MaterialAppearance,
  95708. PerInstanceColorAppearance,
  95709. Primitive,
  95710. SceneMode,
  95711. ShadowMode,
  95712. ColorMaterialProperty,
  95713. ConstantProperty,
  95714. dynamicGeometryGetBoundingSphere,
  95715. MaterialProperty,
  95716. Property) {
  95717. 'use strict';
  95718. var defaultMaterial = new ColorMaterialProperty(Color.WHITE);
  95719. var defaultShow = new ConstantProperty(true);
  95720. var defaultFill = new ConstantProperty(true);
  95721. var defaultOutline = new ConstantProperty(false);
  95722. var defaultOutlineColor = new ConstantProperty(Color.BLACK);
  95723. var defaultShadows = new ConstantProperty(ShadowMode.DISABLED);
  95724. var defaultDistanceDisplayCondition = new ConstantProperty(new DistanceDisplayCondition());
  95725. var radiiScratch = new Cartesian3();
  95726. var scratchColor = new Color();
  95727. var unitSphere = new Cartesian3(1, 1, 1);
  95728. function GeometryOptions(entity) {
  95729. this.id = entity;
  95730. this.vertexFormat = undefined;
  95731. this.radii = undefined;
  95732. this.stackPartitions = undefined;
  95733. this.slicePartitions = undefined;
  95734. this.subdivisions = undefined;
  95735. }
  95736. /**
  95737. * A {@link GeometryUpdater} for ellipsoids.
  95738. * Clients do not normally create this class directly, but instead rely on {@link DataSourceDisplay}.
  95739. * @alias EllipsoidGeometryUpdater
  95740. * @constructor
  95741. *
  95742. * @param {Entity} entity The entity containing the geometry to be visualized.
  95743. * @param {Scene} scene The scene where visualization is taking place.
  95744. */
  95745. function EllipsoidGeometryUpdater(entity, scene) {
  95746. if (!defined(entity)) {
  95747. throw new DeveloperError('entity is required');
  95748. }
  95749. if (!defined(scene)) {
  95750. throw new DeveloperError('scene is required');
  95751. }
  95752. this._scene = scene;
  95753. this._entity = entity;
  95754. this._entitySubscription = entity.definitionChanged.addEventListener(EllipsoidGeometryUpdater.prototype._onEntityPropertyChanged, this);
  95755. this._fillEnabled = false;
  95756. this._dynamic = false;
  95757. this._outlineEnabled = false;
  95758. this._geometryChanged = new Event();
  95759. this._showProperty = undefined;
  95760. this._materialProperty = undefined;
  95761. this._hasConstantOutline = true;
  95762. this._showOutlineProperty = undefined;
  95763. this._outlineColorProperty = undefined;
  95764. this._outlineWidth = 1.0;
  95765. this._shadowsProperty = undefined;
  95766. this._distanceDisplayConditionProperty = undefined;
  95767. this._options = new GeometryOptions(entity);
  95768. this._onEntityPropertyChanged(entity, 'ellipsoid', entity.ellipsoid, undefined);
  95769. }
  95770. defineProperties(EllipsoidGeometryUpdater, {
  95771. /**
  95772. * Gets the type of Appearance to use for simple color-based geometry.
  95773. * @memberof EllipsoidGeometryUpdater
  95774. * @type {Appearance}
  95775. */
  95776. perInstanceColorAppearanceType : {
  95777. value : PerInstanceColorAppearance
  95778. },
  95779. /**
  95780. * Gets the type of Appearance to use for material-based geometry.
  95781. * @memberof EllipsoidGeometryUpdater
  95782. * @type {Appearance}
  95783. */
  95784. materialAppearanceType : {
  95785. value : MaterialAppearance
  95786. }
  95787. });
  95788. defineProperties(EllipsoidGeometryUpdater.prototype, {
  95789. /**
  95790. * Gets the entity associated with this geometry.
  95791. * @memberof EllipsoidGeometryUpdater.prototype
  95792. *
  95793. * @type {Entity}
  95794. * @readonly
  95795. */
  95796. entity : {
  95797. get : function() {
  95798. return this._entity;
  95799. }
  95800. },
  95801. /**
  95802. * Gets a value indicating if the geometry has a fill component.
  95803. * @memberof EllipsoidGeometryUpdater.prototype
  95804. *
  95805. * @type {Boolean}
  95806. * @readonly
  95807. */
  95808. fillEnabled : {
  95809. get : function() {
  95810. return this._fillEnabled;
  95811. }
  95812. },
  95813. /**
  95814. * Gets a value indicating if fill visibility varies with simulation time.
  95815. * @memberof EllipsoidGeometryUpdater.prototype
  95816. *
  95817. * @type {Boolean}
  95818. * @readonly
  95819. */
  95820. hasConstantFill : {
  95821. get : function() {
  95822. return !this._fillEnabled ||
  95823. (!defined(this._entity.availability) &&
  95824. Property.isConstant(this._showProperty) &&
  95825. Property.isConstant(this._fillProperty));
  95826. }
  95827. },
  95828. /**
  95829. * Gets the material property used to fill the geometry.
  95830. * @memberof EllipsoidGeometryUpdater.prototype
  95831. *
  95832. * @type {MaterialProperty}
  95833. * @readonly
  95834. */
  95835. fillMaterialProperty : {
  95836. get : function() {
  95837. return this._materialProperty;
  95838. }
  95839. },
  95840. /**
  95841. * Gets a value indicating if the geometry has an outline component.
  95842. * @memberof EllipsoidGeometryUpdater.prototype
  95843. *
  95844. * @type {Boolean}
  95845. * @readonly
  95846. */
  95847. outlineEnabled : {
  95848. get : function() {
  95849. return this._outlineEnabled;
  95850. }
  95851. },
  95852. /**
  95853. * Gets a value indicating if outline visibility varies with simulation time.
  95854. * @memberof EllipsoidGeometryUpdater.prototype
  95855. *
  95856. * @type {Boolean}
  95857. * @readonly
  95858. */
  95859. hasConstantOutline : {
  95860. get : function() {
  95861. return !this._outlineEnabled ||
  95862. (!defined(this._entity.availability) &&
  95863. Property.isConstant(this._showProperty) &&
  95864. Property.isConstant(this._showOutlineProperty));
  95865. }
  95866. },
  95867. /**
  95868. * Gets the {@link Color} property for the geometry outline.
  95869. * @memberof EllipsoidGeometryUpdater.prototype
  95870. *
  95871. * @type {Property}
  95872. * @readonly
  95873. */
  95874. outlineColorProperty : {
  95875. get : function() {
  95876. return this._outlineColorProperty;
  95877. }
  95878. },
  95879. /**
  95880. * Gets the constant with of the geometry outline, in pixels.
  95881. * This value is only valid if isDynamic is false.
  95882. * @memberof EllipsoidGeometryUpdater.prototype
  95883. *
  95884. * @type {Number}
  95885. * @readonly
  95886. */
  95887. outlineWidth : {
  95888. get : function() {
  95889. return this._outlineWidth;
  95890. }
  95891. },
  95892. /**
  95893. * Gets the property specifying whether the geometry
  95894. * casts or receives shadows from each light source.
  95895. * @memberof EllipsoidGeometryUpdater.prototype
  95896. *
  95897. * @type {Property}
  95898. * @readonly
  95899. */
  95900. shadowsProperty : {
  95901. get : function() {
  95902. return this._shadowsProperty;
  95903. }
  95904. },
  95905. /**
  95906. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this geometry will be displayed.
  95907. * @memberof EllipsoidGeometryUpdater.prototype
  95908. *
  95909. * @type {Property}
  95910. * @readonly
  95911. */
  95912. distanceDisplayConditionProperty : {
  95913. get : function() {
  95914. return this._distanceDisplayConditionProperty;
  95915. }
  95916. },
  95917. /**
  95918. * Gets a value indicating if the geometry is time-varying.
  95919. * If true, all visualization is delegated to the {@link DynamicGeometryUpdater}
  95920. * returned by GeometryUpdater#createDynamicUpdater.
  95921. * @memberof EllipsoidGeometryUpdater.prototype
  95922. *
  95923. * @type {Boolean}
  95924. * @readonly
  95925. */
  95926. isDynamic : {
  95927. get : function() {
  95928. return this._dynamic;
  95929. }
  95930. },
  95931. /**
  95932. * Gets a value indicating if the geometry is closed.
  95933. * This property is only valid for static geometry.
  95934. * @memberof EllipsoidGeometryUpdater.prototype
  95935. *
  95936. * @type {Boolean}
  95937. * @readonly
  95938. */
  95939. isClosed : {
  95940. value : true
  95941. },
  95942. /**
  95943. * Gets an event that is raised whenever the public properties
  95944. * of this updater change.
  95945. * @memberof EllipsoidGeometryUpdater.prototype
  95946. *
  95947. * @type {Boolean}
  95948. * @readonly
  95949. */
  95950. geometryChanged : {
  95951. get : function() {
  95952. return this._geometryChanged;
  95953. }
  95954. }
  95955. });
  95956. /**
  95957. * Checks if the geometry is outlined at the provided time.
  95958. *
  95959. * @param {JulianDate} time The time for which to retrieve visibility.
  95960. * @returns {Boolean} true if geometry is outlined at the provided time, false otherwise.
  95961. */
  95962. EllipsoidGeometryUpdater.prototype.isOutlineVisible = function(time) {
  95963. var entity = this._entity;
  95964. return this._outlineEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time);
  95965. };
  95966. /**
  95967. * Checks if the geometry is filled at the provided time.
  95968. *
  95969. * @param {JulianDate} time The time for which to retrieve visibility.
  95970. * @returns {Boolean} true if geometry is filled at the provided time, false otherwise.
  95971. */
  95972. EllipsoidGeometryUpdater.prototype.isFilled = function(time) {
  95973. var entity = this._entity;
  95974. return this._fillEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._fillProperty.getValue(time);
  95975. };
  95976. /**
  95977. * Creates the geometry instance which represents the fill of the geometry.
  95978. *
  95979. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  95980. * @returns {GeometryInstance} The geometry instance representing the filled portion of the geometry.
  95981. *
  95982. * @exception {DeveloperError} This instance does not represent a filled geometry.
  95983. */
  95984. EllipsoidGeometryUpdater.prototype.createFillGeometryInstance = function(time) {
  95985. if (!defined(time)) {
  95986. throw new DeveloperError('time is required.');
  95987. }
  95988. if (!this._fillEnabled) {
  95989. throw new DeveloperError('This instance does not represent a filled geometry.');
  95990. }
  95991. var entity = this._entity;
  95992. var isAvailable = entity.isAvailable(time);
  95993. var attributes;
  95994. var color;
  95995. var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time));
  95996. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  95997. var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
  95998. if (this._materialProperty instanceof ColorMaterialProperty) {
  95999. var currentColor = Color.WHITE;
  96000. if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) {
  96001. currentColor = this._materialProperty.color.getValue(time);
  96002. }
  96003. color = ColorGeometryInstanceAttribute.fromColor(currentColor);
  96004. attributes = {
  96005. show : show,
  96006. distanceDisplayCondition : distanceDisplayConditionAttribute,
  96007. color : color
  96008. };
  96009. } else {
  96010. attributes = {
  96011. show : show,
  96012. distanceDisplayCondition : distanceDisplayConditionAttribute
  96013. };
  96014. }
  96015. return new GeometryInstance({
  96016. id : entity,
  96017. geometry : new EllipsoidGeometry(this._options),
  96018. modelMatrix : entity._getModelMatrix(Iso8601.MINIMUM_VALUE),
  96019. attributes : attributes
  96020. });
  96021. };
  96022. /**
  96023. * Creates the geometry instance which represents the outline of the geometry.
  96024. *
  96025. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  96026. * @returns {GeometryInstance} The geometry instance representing the outline portion of the geometry.
  96027. *
  96028. * @exception {DeveloperError} This instance does not represent an outlined geometry.
  96029. */
  96030. EllipsoidGeometryUpdater.prototype.createOutlineGeometryInstance = function(time) {
  96031. if (!defined(time)) {
  96032. throw new DeveloperError('time is required.');
  96033. }
  96034. if (!this._outlineEnabled) {
  96035. throw new DeveloperError('This instance does not represent an outlined geometry.');
  96036. }
  96037. var entity = this._entity;
  96038. var isAvailable = entity.isAvailable(time);
  96039. var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK);
  96040. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  96041. return new GeometryInstance({
  96042. id : entity,
  96043. geometry : new EllipsoidOutlineGeometry(this._options),
  96044. modelMatrix : entity._getModelMatrix(Iso8601.MINIMUM_VALUE),
  96045. attributes : {
  96046. show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
  96047. color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
  96048. distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition)
  96049. }
  96050. });
  96051. };
  96052. /**
  96053. * Returns true if this object was destroyed; otherwise, false.
  96054. *
  96055. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  96056. */
  96057. EllipsoidGeometryUpdater.prototype.isDestroyed = function() {
  96058. return false;
  96059. };
  96060. /**
  96061. * Destroys and resources used by the object. Once an object is destroyed, it should not be used.
  96062. *
  96063. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  96064. */
  96065. EllipsoidGeometryUpdater.prototype.destroy = function() {
  96066. this._entitySubscription();
  96067. destroyObject(this);
  96068. };
  96069. EllipsoidGeometryUpdater.prototype._onEntityPropertyChanged = function(entity, propertyName, newValue, oldValue) {
  96070. if (!(propertyName === 'availability' || propertyName === 'position' || propertyName === 'orientation' || propertyName === 'ellipsoid')) {
  96071. return;
  96072. }
  96073. var ellipsoid = entity.ellipsoid;
  96074. if (!defined(ellipsoid)) {
  96075. if (this._fillEnabled || this._outlineEnabled) {
  96076. this._fillEnabled = false;
  96077. this._outlineEnabled = false;
  96078. this._geometryChanged.raiseEvent(this);
  96079. }
  96080. return;
  96081. }
  96082. var fillProperty = ellipsoid.fill;
  96083. var fillEnabled = defined(fillProperty) && fillProperty.isConstant ? fillProperty.getValue(Iso8601.MINIMUM_VALUE) : true;
  96084. var outlineProperty = ellipsoid.outline;
  96085. var outlineEnabled = defined(outlineProperty);
  96086. if (outlineEnabled && outlineProperty.isConstant) {
  96087. outlineEnabled = outlineProperty.getValue(Iso8601.MINIMUM_VALUE);
  96088. }
  96089. if (!fillEnabled && !outlineEnabled) {
  96090. if (this._fillEnabled || this._outlineEnabled) {
  96091. this._fillEnabled = false;
  96092. this._outlineEnabled = false;
  96093. this._geometryChanged.raiseEvent(this);
  96094. }
  96095. return;
  96096. }
  96097. var position = entity.position;
  96098. var radii = ellipsoid.radii;
  96099. var show = ellipsoid.show;
  96100. if ((defined(show) && show.isConstant && !show.getValue(Iso8601.MINIMUM_VALUE)) || //
  96101. (!defined(position) || !defined(radii))) {
  96102. if (this._fillEnabled || this._outlineEnabled) {
  96103. this._fillEnabled = false;
  96104. this._outlineEnabled = false;
  96105. this._geometryChanged.raiseEvent(this);
  96106. }
  96107. return;
  96108. }
  96109. var material = defaultValue(ellipsoid.material, defaultMaterial);
  96110. var isColorMaterial = material instanceof ColorMaterialProperty;
  96111. this._materialProperty = material;
  96112. this._fillProperty = defaultValue(fillProperty, defaultFill);
  96113. this._showProperty = defaultValue(show, defaultShow);
  96114. this._showOutlineProperty = defaultValue(ellipsoid.outline, defaultOutline);
  96115. this._outlineColorProperty = outlineEnabled ? defaultValue(ellipsoid.outlineColor, defaultOutlineColor) : undefined;
  96116. this._shadowsProperty = defaultValue(ellipsoid.shadows, defaultShadows);
  96117. this._distanceDisplayConditionProperty = defaultValue(ellipsoid.distanceDisplayCondition, defaultDistanceDisplayCondition);
  96118. this._fillEnabled = fillEnabled;
  96119. this._outlineEnabled = outlineEnabled;
  96120. var stackPartitions = ellipsoid.stackPartitions;
  96121. var slicePartitions = ellipsoid.slicePartitions;
  96122. var outlineWidth = ellipsoid.outlineWidth;
  96123. var subdivisions = ellipsoid.subdivisions;
  96124. if (!position.isConstant || //
  96125. !Property.isConstant(entity.orientation) || //
  96126. !radii.isConstant || //
  96127. !Property.isConstant(stackPartitions) || //
  96128. !Property.isConstant(slicePartitions) || //
  96129. !Property.isConstant(outlineWidth) || //
  96130. !Property.isConstant(subdivisions)) {
  96131. if (!this._dynamic) {
  96132. this._dynamic = true;
  96133. this._geometryChanged.raiseEvent(this);
  96134. }
  96135. } else {
  96136. var options = this._options;
  96137. options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat;
  96138. options.radii = radii.getValue(Iso8601.MINIMUM_VALUE, options.radii);
  96139. options.stackPartitions = defined(stackPartitions) ? stackPartitions.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  96140. options.slicePartitions = defined(slicePartitions) ? slicePartitions.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  96141. options.subdivisions = defined(subdivisions) ? subdivisions.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  96142. this._outlineWidth = defined(outlineWidth) ? outlineWidth.getValue(Iso8601.MINIMUM_VALUE) : 1.0;
  96143. this._dynamic = false;
  96144. this._geometryChanged.raiseEvent(this);
  96145. }
  96146. };
  96147. /**
  96148. * Creates the dynamic updater to be used when GeometryUpdater#isDynamic is true.
  96149. *
  96150. * @param {PrimitiveCollection} primitives The primitive collection to use.
  96151. * @returns {DynamicGeometryUpdater} The dynamic updater used to update the geometry each frame.
  96152. *
  96153. * @exception {DeveloperError} This instance does not represent dynamic geometry.
  96154. */
  96155. EllipsoidGeometryUpdater.prototype.createDynamicUpdater = function(primitives) {
  96156. if (!this._dynamic) {
  96157. throw new DeveloperError('This instance does not represent dynamic geometry.');
  96158. }
  96159. if (!defined(primitives)) {
  96160. throw new DeveloperError('primitives is required.');
  96161. }
  96162. return new DynamicGeometryUpdater(primitives, this);
  96163. };
  96164. /**
  96165. * @private
  96166. */
  96167. function DynamicGeometryUpdater(primitives, geometryUpdater) {
  96168. this._entity = geometryUpdater._entity;
  96169. this._scene = geometryUpdater._scene;
  96170. this._primitives = primitives;
  96171. this._primitive = undefined;
  96172. this._outlinePrimitive = undefined;
  96173. this._geometryUpdater = geometryUpdater;
  96174. this._options = new GeometryOptions(geometryUpdater._entity);
  96175. this._modelMatrix = new Matrix4();
  96176. this._material = undefined;
  96177. this._attributes = undefined;
  96178. this._outlineAttributes = undefined;
  96179. this._lastSceneMode = undefined;
  96180. this._lastShow = undefined;
  96181. this._lastOutlineShow = undefined;
  96182. this._lastOutlineWidth = undefined;
  96183. this._lastOutlineColor = undefined;
  96184. }
  96185. DynamicGeometryUpdater.prototype.update = function(time) {
  96186. if (!defined(time)) {
  96187. throw new DeveloperError('time is required.');
  96188. }
  96189. var entity = this._entity;
  96190. var ellipsoid = entity.ellipsoid;
  96191. if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(ellipsoid.show, time, true)) {
  96192. if (defined(this._primitive)) {
  96193. this._primitive.show = false;
  96194. }
  96195. if (defined(this._outlinePrimitive)) {
  96196. this._outlinePrimitive.show = false;
  96197. }
  96198. return;
  96199. }
  96200. var radii = Property.getValueOrUndefined(ellipsoid.radii, time, radiiScratch);
  96201. var modelMatrix = entity._getModelMatrix(time, this._modelMatrix);
  96202. if (!defined(modelMatrix) || !defined(radii)) {
  96203. if (defined(this._primitive)) {
  96204. this._primitive.show = false;
  96205. }
  96206. if (defined(this._outlinePrimitive)) {
  96207. this._outlinePrimitive.show = false;
  96208. }
  96209. return;
  96210. }
  96211. //Compute attributes and material.
  96212. var appearance;
  96213. var showFill = Property.getValueOrDefault(ellipsoid.fill, time, true);
  96214. var showOutline = Property.getValueOrDefault(ellipsoid.outline, time, false);
  96215. var outlineColor = Property.getValueOrClonedDefault(ellipsoid.outlineColor, time, Color.BLACK, scratchColor);
  96216. var material = MaterialProperty.getValue(time, defaultValue(ellipsoid.material, defaultMaterial), this._material);
  96217. this._material = material;
  96218. // Check properties that could trigger a primitive rebuild.
  96219. var stackPartitions = Property.getValueOrUndefined(ellipsoid.stackPartitions, time);
  96220. var slicePartitions = Property.getValueOrUndefined(ellipsoid.slicePartitions, time);
  96221. var subdivisions = Property.getValueOrUndefined(ellipsoid.subdivisions, time);
  96222. var outlineWidth = Property.getValueOrDefault(ellipsoid.outlineWidth, time, 1.0);
  96223. //In 3D we use a fast path by modifying Primitive.modelMatrix instead of regenerating the primitive every frame.
  96224. var sceneMode = this._scene.mode;
  96225. var in3D = sceneMode === SceneMode.SCENE3D;
  96226. var options = this._options;
  96227. var shadows = this._geometryUpdater.shadowsProperty.getValue(time);
  96228. var distanceDisplayConditionProperty = this._geometryUpdater.distanceDisplayConditionProperty;
  96229. var distanceDisplayCondition = distanceDisplayConditionProperty.getValue(time);
  96230. var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
  96231. //We only rebuild the primitive if something other than the radii has changed
  96232. //For the radii, we use unit sphere and then deform it with a scale matrix.
  96233. var rebuildPrimitives = !in3D || this._lastSceneMode !== sceneMode || !defined(this._primitive) || //
  96234. options.stackPartitions !== stackPartitions || options.slicePartitions !== slicePartitions || //
  96235. options.subdivisions !== subdivisions || this._lastOutlineWidth !== outlineWidth;
  96236. if (rebuildPrimitives) {
  96237. var primitives = this._primitives;
  96238. primitives.removeAndDestroy(this._primitive);
  96239. primitives.removeAndDestroy(this._outlinePrimitive);
  96240. this._primitive = undefined;
  96241. this._outlinePrimitive = undefined;
  96242. this._lastSceneMode = sceneMode;
  96243. this._lastOutlineWidth = outlineWidth;
  96244. options.stackPartitions = stackPartitions;
  96245. options.slicePartitions = slicePartitions;
  96246. options.subdivisions = subdivisions;
  96247. options.radii = in3D ? unitSphere : radii;
  96248. appearance = new MaterialAppearance({
  96249. material : material,
  96250. translucent : material.isTranslucent(),
  96251. closed : true
  96252. });
  96253. options.vertexFormat = appearance.vertexFormat;
  96254. this._primitive = primitives.add(new Primitive({
  96255. geometryInstances : new GeometryInstance({
  96256. id : entity,
  96257. geometry : new EllipsoidGeometry(options),
  96258. modelMatrix : !in3D ? modelMatrix : undefined,
  96259. attributes : {
  96260. show : new ShowGeometryInstanceAttribute(showFill),
  96261. distanceDisplayCondition : distanceDisplayConditionAttribute
  96262. }
  96263. }),
  96264. appearance : appearance,
  96265. asynchronous : false,
  96266. shadows : shadows
  96267. }));
  96268. options.vertexFormat = PerInstanceColorAppearance.VERTEX_FORMAT;
  96269. this._outlinePrimitive = primitives.add(new Primitive({
  96270. geometryInstances : new GeometryInstance({
  96271. id : entity,
  96272. geometry : new EllipsoidOutlineGeometry(options),
  96273. modelMatrix : !in3D ? modelMatrix : undefined,
  96274. attributes : {
  96275. show : new ShowGeometryInstanceAttribute(showOutline),
  96276. color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
  96277. distanceDisplayCondition : distanceDisplayConditionAttribute
  96278. }
  96279. }),
  96280. appearance : new PerInstanceColorAppearance({
  96281. flat : true,
  96282. translucent : outlineColor.alpha !== 1.0,
  96283. renderState : {
  96284. lineWidth : this._geometryUpdater._scene.clampLineWidth(outlineWidth)
  96285. }
  96286. }),
  96287. asynchronous : false,
  96288. shadows : shadows
  96289. }));
  96290. this._lastShow = showFill;
  96291. this._lastOutlineShow = showOutline;
  96292. this._lastOutlineColor = Color.clone(outlineColor, this._lastOutlineColor);
  96293. this._lastDistanceDisplayCondition = distanceDisplayCondition;
  96294. } else if (this._primitive.ready) {
  96295. //Update attributes only.
  96296. var primitive = this._primitive;
  96297. var outlinePrimitive = this._outlinePrimitive;
  96298. primitive.show = true;
  96299. outlinePrimitive.show = true;
  96300. appearance = primitive.appearance;
  96301. appearance.material = material;
  96302. var attributes = this._attributes;
  96303. if (!defined(attributes)) {
  96304. attributes = primitive.getGeometryInstanceAttributes(entity);
  96305. this._attributes = attributes;
  96306. }
  96307. if (showFill !== this._lastShow) {
  96308. attributes.show = ShowGeometryInstanceAttribute.toValue(showFill, attributes.show);
  96309. this._lastShow = showFill;
  96310. }
  96311. var outlineAttributes = this._outlineAttributes;
  96312. if (!defined(outlineAttributes)) {
  96313. outlineAttributes = outlinePrimitive.getGeometryInstanceAttributes(entity);
  96314. this._outlineAttributes = outlineAttributes;
  96315. }
  96316. if (showOutline !== this._lastOutlineShow) {
  96317. outlineAttributes.show = ShowGeometryInstanceAttribute.toValue(showOutline, outlineAttributes.show);
  96318. this._lastOutlineShow = showOutline;
  96319. }
  96320. if (!Color.equals(outlineColor, this._lastOutlineColor)) {
  96321. outlineAttributes.color = ColorGeometryInstanceAttribute.toValue(outlineColor, outlineAttributes.color);
  96322. Color.clone(outlineColor, this._lastOutlineColor);
  96323. }
  96324. if (!DistanceDisplayCondition.equals(distanceDisplayCondition, this._lastDistanceDisplayCondition)) {
  96325. attributes.distanceDisplayCondition = DistanceDisplayConditionGeometryInstanceAttribute.toValue(distanceDisplayCondition, attributes.distanceDisplayCondition);
  96326. outlineAttributes.distanceDisplayCondition = DistanceDisplayConditionGeometryInstanceAttribute.toValue(distanceDisplayCondition, outlineAttributes.distanceDisplayCondition);
  96327. DistanceDisplayCondition.clone(distanceDisplayCondition, this._lastDistanceDisplayCondition);
  96328. }
  96329. }
  96330. if (in3D) {
  96331. //Since we are scaling a unit sphere, we can't let any of the values go to zero.
  96332. //Instead we clamp them to a small value. To the naked eye, this produces the same results
  96333. //that you get passing EllipsoidGeometry a radii with a zero component.
  96334. radii.x = Math.max(radii.x, 0.001);
  96335. radii.y = Math.max(radii.y, 0.001);
  96336. radii.z = Math.max(radii.z, 0.001);
  96337. modelMatrix = Matrix4.multiplyByScale(modelMatrix, radii, modelMatrix);
  96338. this._primitive.modelMatrix = modelMatrix;
  96339. this._outlinePrimitive.modelMatrix = modelMatrix;
  96340. }
  96341. };
  96342. DynamicGeometryUpdater.prototype.getBoundingSphere = function(entity, result) {
  96343. return dynamicGeometryGetBoundingSphere(entity, this._primitive, this._outlinePrimitive, result);
  96344. };
  96345. DynamicGeometryUpdater.prototype.isDestroyed = function() {
  96346. return false;
  96347. };
  96348. DynamicGeometryUpdater.prototype.destroy = function() {
  96349. var primitives = this._primitives;
  96350. primitives.removeAndDestroy(this._primitive);
  96351. primitives.removeAndDestroy(this._outlinePrimitive);
  96352. destroyObject(this);
  96353. };
  96354. return EllipsoidGeometryUpdater;
  96355. });
  96356. /*global define*/
  96357. define('DataSources/StaticGeometryColorBatch',[
  96358. '../Core/AssociativeArray',
  96359. '../Core/Color',
  96360. '../Core/ColorGeometryInstanceAttribute',
  96361. '../Core/defined',
  96362. '../Core/DistanceDisplayCondition',
  96363. '../Core/DistanceDisplayConditionGeometryInstanceAttribute',
  96364. '../Core/ShowGeometryInstanceAttribute',
  96365. '../Scene/Primitive',
  96366. './BoundingSphereState',
  96367. './Property'
  96368. ], function(
  96369. AssociativeArray,
  96370. Color,
  96371. ColorGeometryInstanceAttribute,
  96372. defined,
  96373. DistanceDisplayCondition,
  96374. DistanceDisplayConditionGeometryInstanceAttribute,
  96375. ShowGeometryInstanceAttribute,
  96376. Primitive,
  96377. BoundingSphereState,
  96378. Property) {
  96379. 'use strict';
  96380. var colorScratch = new Color();
  96381. var distanceDisplayConditionScratch = new DistanceDisplayCondition();
  96382. function Batch(primitives, translucent, appearanceType, closed, shadows) {
  96383. this.translucent = translucent;
  96384. this.appearanceType = appearanceType;
  96385. this.closed = closed;
  96386. this.shadows = shadows;
  96387. this.primitives = primitives;
  96388. this.createPrimitive = false;
  96389. this.waitingOnCreate = false;
  96390. this.primitive = undefined;
  96391. this.oldPrimitive = undefined;
  96392. this.geometry = new AssociativeArray();
  96393. this.updaters = new AssociativeArray();
  96394. this.updatersWithAttributes = new AssociativeArray();
  96395. this.attributes = new AssociativeArray();
  96396. this.subscriptions = new AssociativeArray();
  96397. this.showsUpdated = new AssociativeArray();
  96398. this.itemsToRemove = [];
  96399. }
  96400. Batch.prototype.add = function(updater, instance) {
  96401. var id = updater.entity.id;
  96402. this.createPrimitive = true;
  96403. this.geometry.set(id, instance);
  96404. this.updaters.set(id, updater);
  96405. if (!updater.hasConstantFill || !updater.fillMaterialProperty.isConstant || !Property.isConstant(updater.distanceDisplayConditionProperty)) {
  96406. this.updatersWithAttributes.set(id, updater);
  96407. } else {
  96408. var that = this;
  96409. this.subscriptions.set(id, updater.entity.definitionChanged.addEventListener(function(entity, propertyName, newValue, oldValue) {
  96410. if (propertyName === 'isShowing') {
  96411. that.showsUpdated.set(entity.id, updater);
  96412. }
  96413. }));
  96414. }
  96415. };
  96416. Batch.prototype.remove = function(updater) {
  96417. var id = updater.entity.id;
  96418. this.createPrimitive = this.geometry.remove(id) || this.createPrimitive;
  96419. if (this.updaters.remove(id)) {
  96420. this.updatersWithAttributes.remove(id);
  96421. var unsubscribe = this.subscriptions.get(id);
  96422. if (defined(unsubscribe)) {
  96423. unsubscribe();
  96424. this.subscriptions.remove(id);
  96425. }
  96426. }
  96427. };
  96428. Batch.prototype.update = function(time) {
  96429. var isUpdated = true;
  96430. var removedCount = 0;
  96431. var primitive = this.primitive;
  96432. var primitives = this.primitives;
  96433. var attributes;
  96434. var i;
  96435. if (this.createPrimitive) {
  96436. var geometries = this.geometry.values;
  96437. var geometriesLength = geometries.length;
  96438. if (geometriesLength > 0) {
  96439. if (defined(primitive)) {
  96440. if (!defined(this.oldPrimitive)) {
  96441. this.oldPrimitive = primitive;
  96442. } else {
  96443. primitives.remove(primitive);
  96444. }
  96445. }
  96446. for (i = 0; i < geometriesLength; i++) {
  96447. var geometryItem = geometries[i];
  96448. var originalAttributes = geometryItem.attributes;
  96449. attributes = this.attributes.get(geometryItem.id.id);
  96450. if (defined(attributes)) {
  96451. if (defined(originalAttributes.show)) {
  96452. originalAttributes.show.value = attributes.show;
  96453. }
  96454. if (defined(originalAttributes.color)) {
  96455. originalAttributes.color.value = attributes.color;
  96456. }
  96457. }
  96458. }
  96459. primitive = new Primitive({
  96460. asynchronous : true,
  96461. geometryInstances : geometries,
  96462. appearance : new this.appearanceType({
  96463. translucent : this.translucent,
  96464. closed : this.closed
  96465. }),
  96466. shadows : this.shadows
  96467. });
  96468. primitives.add(primitive);
  96469. isUpdated = false;
  96470. } else {
  96471. if (defined(primitive)) {
  96472. primitives.remove(primitive);
  96473. primitive = undefined;
  96474. }
  96475. var oldPrimitive = this.oldPrimitive;
  96476. if (defined(oldPrimitive)) {
  96477. primitives.remove(oldPrimitive);
  96478. this.oldPrimitive = undefined;
  96479. }
  96480. }
  96481. this.attributes.removeAll();
  96482. this.primitive = primitive;
  96483. this.createPrimitive = false;
  96484. this.waitingOnCreate = true;
  96485. } else if (defined(primitive) && primitive.ready) {
  96486. if (defined(this.oldPrimitive)) {
  96487. primitives.remove(this.oldPrimitive);
  96488. this.oldPrimitive = undefined;
  96489. }
  96490. var updatersWithAttributes = this.updatersWithAttributes.values;
  96491. var length = updatersWithAttributes.length;
  96492. var waitingOnCreate = this.waitingOnCreate;
  96493. for (i = 0; i < length; i++) {
  96494. var updater = updatersWithAttributes[i];
  96495. var instance = this.geometry.get(updater.entity.id);
  96496. attributes = this.attributes.get(instance.id.id);
  96497. if (!defined(attributes)) {
  96498. attributes = primitive.getGeometryInstanceAttributes(instance.id);
  96499. this.attributes.set(instance.id.id, attributes);
  96500. }
  96501. if (!updater.fillMaterialProperty.isConstant || waitingOnCreate) {
  96502. var colorProperty = updater.fillMaterialProperty.color;
  96503. colorProperty.getValue(time, colorScratch);
  96504. if (!Color.equals(attributes._lastColor, colorScratch)) {
  96505. attributes._lastColor = Color.clone(colorScratch, attributes._lastColor);
  96506. attributes.color = ColorGeometryInstanceAttribute.toValue(colorScratch, attributes.color);
  96507. if ((this.translucent && attributes.color[3] === 255) || (!this.translucent && attributes.color[3] !== 255)) {
  96508. this.itemsToRemove[removedCount++] = updater;
  96509. }
  96510. }
  96511. }
  96512. var show = updater.entity.isShowing && (updater.hasConstantFill || updater.isFilled(time));
  96513. var currentShow = attributes.show[0] === 1;
  96514. if (show !== currentShow) {
  96515. attributes.show = ShowGeometryInstanceAttribute.toValue(show, attributes.show);
  96516. }
  96517. var distanceDisplayConditionProperty = updater.distanceDisplayConditionProperty;
  96518. if (!Property.isConstant(distanceDisplayConditionProperty)) {
  96519. var distanceDisplayCondition = distanceDisplayConditionProperty.getValue(time, distanceDisplayConditionScratch);
  96520. if (!DistanceDisplayCondition.equals(distanceDisplayCondition, attributes._lastDistanceDisplayCondition)) {
  96521. attributes._lastDistanceDisplayCondition = DistanceDisplayCondition.clone(distanceDisplayCondition, attributes._lastDistanceDisplayCondition);
  96522. attributes.distanceDisplayCondition = DistanceDisplayConditionGeometryInstanceAttribute.toValue(distanceDisplayCondition, attributes.distanceDisplayCondition);
  96523. }
  96524. }
  96525. }
  96526. this.updateShows(primitive);
  96527. this.waitingOnCreate = false;
  96528. } else if (defined(primitive) && !primitive.ready) {
  96529. isUpdated = false;
  96530. }
  96531. this.itemsToRemove.length = removedCount;
  96532. return isUpdated;
  96533. };
  96534. Batch.prototype.updateShows = function(primitive) {
  96535. var showsUpdated = this.showsUpdated.values;
  96536. var length = showsUpdated.length;
  96537. for (var i = 0; i < length; i++) {
  96538. var updater = showsUpdated[i];
  96539. var instance = this.geometry.get(updater.entity.id);
  96540. var attributes = this.attributes.get(instance.id.id);
  96541. if (!defined(attributes)) {
  96542. attributes = primitive.getGeometryInstanceAttributes(instance.id);
  96543. this.attributes.set(instance.id.id, attributes);
  96544. }
  96545. var show = updater.entity.isShowing;
  96546. var currentShow = attributes.show[0] === 1;
  96547. if (show !== currentShow) {
  96548. attributes.show = ShowGeometryInstanceAttribute.toValue(show, attributes.show);
  96549. }
  96550. }
  96551. this.showsUpdated.removeAll();
  96552. };
  96553. Batch.prototype.contains = function(entity) {
  96554. return this.updaters.contains(entity.id);
  96555. };
  96556. Batch.prototype.getBoundingSphere = function(entity, result) {
  96557. var primitive = this.primitive;
  96558. if (!primitive.ready) {
  96559. return BoundingSphereState.PENDING;
  96560. }
  96561. var attributes = primitive.getGeometryInstanceAttributes(entity);
  96562. if (!defined(attributes) || !defined(attributes.boundingSphere) ||//
  96563. (defined(attributes.show) && attributes.show[0] === 0)) {
  96564. return BoundingSphereState.FAILED;
  96565. }
  96566. attributes.boundingSphere.clone(result);
  96567. return BoundingSphereState.DONE;
  96568. };
  96569. Batch.prototype.removeAllPrimitives = function() {
  96570. var primitives = this.primitives;
  96571. var primitive = this.primitive;
  96572. if (defined(primitive)) {
  96573. primitives.remove(primitive);
  96574. this.primitive = undefined;
  96575. this.geometry.removeAll();
  96576. this.updaters.removeAll();
  96577. }
  96578. var oldPrimitive = this.oldPrimitive;
  96579. if (defined(oldPrimitive)) {
  96580. primitives.remove(oldPrimitive);
  96581. this.oldPrimitive = undefined;
  96582. }
  96583. };
  96584. /**
  96585. * @private
  96586. */
  96587. function StaticGeometryColorBatch(primitives, appearanceType, closed, shadows) {
  96588. this._solidBatch = new Batch(primitives, false, appearanceType, closed, shadows);
  96589. this._translucentBatch = new Batch(primitives, true, appearanceType, closed, shadows);
  96590. }
  96591. StaticGeometryColorBatch.prototype.add = function(time, updater) {
  96592. var instance = updater.createFillGeometryInstance(time);
  96593. if (instance.attributes.color.value[3] === 255) {
  96594. this._solidBatch.add(updater, instance);
  96595. } else {
  96596. this._translucentBatch.add(updater, instance);
  96597. }
  96598. };
  96599. StaticGeometryColorBatch.prototype.remove = function(updater) {
  96600. if (!this._solidBatch.remove(updater)) {
  96601. this._translucentBatch.remove(updater);
  96602. }
  96603. };
  96604. StaticGeometryColorBatch.prototype.update = function(time) {
  96605. var i;
  96606. var updater;
  96607. //Perform initial update
  96608. var isUpdated = this._solidBatch.update(time);
  96609. isUpdated = this._translucentBatch.update(time) && isUpdated;
  96610. //If any items swapped between solid/translucent, we need to
  96611. //move them between batches
  96612. var itemsToRemove = this._solidBatch.itemsToRemove;
  96613. var solidsToMoveLength = itemsToRemove.length;
  96614. if (solidsToMoveLength > 0) {
  96615. for (i = 0; i < solidsToMoveLength; i++) {
  96616. updater = itemsToRemove[i];
  96617. this._solidBatch.remove(updater);
  96618. this._translucentBatch.add(updater, updater.createFillGeometryInstance(time));
  96619. }
  96620. }
  96621. itemsToRemove = this._translucentBatch.itemsToRemove;
  96622. var translucentToMoveLength = itemsToRemove.length;
  96623. if (translucentToMoveLength > 0) {
  96624. for (i = 0; i < translucentToMoveLength; i++) {
  96625. updater = itemsToRemove[i];
  96626. this._translucentBatch.remove(updater);
  96627. this._solidBatch.add(updater, updater.createFillGeometryInstance(time));
  96628. }
  96629. }
  96630. //If we moved anything around, we need to re-build the primitive
  96631. if (solidsToMoveLength > 0 || translucentToMoveLength > 0) {
  96632. isUpdated = this._solidBatch.update(time) && isUpdated;
  96633. isUpdated = this._translucentBatch.update(time) && isUpdated;
  96634. }
  96635. return isUpdated;
  96636. };
  96637. StaticGeometryColorBatch.prototype.getBoundingSphere = function(entity, result) {
  96638. if (this._solidBatch.contains(entity)) {
  96639. return this._solidBatch.getBoundingSphere(entity, result);
  96640. } else if (this._translucentBatch.contains(entity)) {
  96641. return this._translucentBatch.getBoundingSphere(entity, result);
  96642. }
  96643. return BoundingSphereState.FAILED;
  96644. };
  96645. StaticGeometryColorBatch.prototype.removeAllPrimitives = function() {
  96646. this._solidBatch.removeAllPrimitives();
  96647. this._translucentBatch.removeAllPrimitives();
  96648. };
  96649. return StaticGeometryColorBatch;
  96650. });
  96651. /*global define*/
  96652. define('DataSources/StaticGeometryPerMaterialBatch',[
  96653. '../Core/AssociativeArray',
  96654. '../Core/defined',
  96655. '../Core/DistanceDisplayCondition',
  96656. '../Core/DistanceDisplayConditionGeometryInstanceAttribute',
  96657. '../Core/ShowGeometryInstanceAttribute',
  96658. '../Scene/Primitive',
  96659. './BoundingSphereState',
  96660. './MaterialProperty',
  96661. './Property'
  96662. ], function(
  96663. AssociativeArray,
  96664. defined,
  96665. DistanceDisplayCondition,
  96666. DistanceDisplayConditionGeometryInstanceAttribute,
  96667. ShowGeometryInstanceAttribute,
  96668. Primitive,
  96669. BoundingSphereState,
  96670. MaterialProperty,
  96671. Property) {
  96672. 'use strict';
  96673. var distanceDisplayConditionScratch = new DistanceDisplayCondition();
  96674. function Batch(primitives, appearanceType, materialProperty, closed, shadows) {
  96675. this.primitives = primitives;
  96676. this.appearanceType = appearanceType;
  96677. this.materialProperty = materialProperty;
  96678. this.closed = closed;
  96679. this.shadows = shadows;
  96680. this.updaters = new AssociativeArray();
  96681. this.createPrimitive = true;
  96682. this.primitive = undefined;
  96683. this.oldPrimitive = undefined;
  96684. this.geometry = new AssociativeArray();
  96685. this.material = undefined;
  96686. this.updatersWithAttributes = new AssociativeArray();
  96687. this.attributes = new AssociativeArray();
  96688. this.invalidated = false;
  96689. this.removeMaterialSubscription = materialProperty.definitionChanged.addEventListener(Batch.prototype.onMaterialChanged, this);
  96690. this.subscriptions = new AssociativeArray();
  96691. this.showsUpdated = new AssociativeArray();
  96692. }
  96693. Batch.prototype.onMaterialChanged = function() {
  96694. this.invalidated = true;
  96695. };
  96696. Batch.prototype.isMaterial = function(updater) {
  96697. var material = this.materialProperty;
  96698. var updaterMaterial = updater.fillMaterialProperty;
  96699. if (updaterMaterial === material) {
  96700. return true;
  96701. }
  96702. if (defined(material)) {
  96703. return material.equals(updaterMaterial);
  96704. }
  96705. return false;
  96706. };
  96707. Batch.prototype.add = function(time, updater) {
  96708. var id = updater.entity.id;
  96709. this.updaters.set(id, updater);
  96710. this.geometry.set(id, updater.createFillGeometryInstance(time));
  96711. if (!updater.hasConstantFill || !updater.fillMaterialProperty.isConstant || !Property.isConstant(updater.distanceDisplayConditionProperty)) {
  96712. this.updatersWithAttributes.set(id, updater);
  96713. } else {
  96714. var that = this;
  96715. this.subscriptions.set(id, updater.entity.definitionChanged.addEventListener(function(entity, propertyName, newValue, oldValue) {
  96716. if (propertyName === 'isShowing') {
  96717. that.showsUpdated.set(entity.id, updater);
  96718. }
  96719. }));
  96720. }
  96721. this.createPrimitive = true;
  96722. };
  96723. Batch.prototype.remove = function(updater) {
  96724. var id = updater.entity.id;
  96725. this.createPrimitive = this.geometry.remove(id) || this.createPrimitive;
  96726. if (this.updaters.remove(id)) {
  96727. this.updatersWithAttributes.remove(id);
  96728. var unsubscribe = this.subscriptions.get(id);
  96729. if (defined(unsubscribe)) {
  96730. unsubscribe();
  96731. this.subscriptions.remove(id);
  96732. }
  96733. }
  96734. return this.createPrimitive;
  96735. };
  96736. Batch.prototype.update = function(time) {
  96737. var isUpdated = true;
  96738. var primitive = this.primitive;
  96739. var primitives = this.primitives;
  96740. var geometries = this.geometry.values;
  96741. var attributes;
  96742. var i;
  96743. if (this.createPrimitive) {
  96744. var geometriesLength = geometries.length;
  96745. if (geometriesLength > 0) {
  96746. if (defined(primitive)) {
  96747. if (!defined(this.oldPrimitive)) {
  96748. this.oldPrimitive = primitive;
  96749. } else {
  96750. primitives.remove(primitive);
  96751. }
  96752. }
  96753. for (i = 0; i < geometriesLength; i++) {
  96754. var geometry = geometries[i];
  96755. var originalAttributes = geometry.attributes;
  96756. attributes = this.attributes.get(geometry.id.id);
  96757. if (defined(attributes)) {
  96758. if (defined(originalAttributes.show)) {
  96759. originalAttributes.show.value = attributes.show;
  96760. }
  96761. if (defined(originalAttributes.color)) {
  96762. originalAttributes.color.value = attributes.color;
  96763. }
  96764. }
  96765. }
  96766. this.material = MaterialProperty.getValue(time, this.materialProperty, this.material);
  96767. primitive = new Primitive({
  96768. asynchronous : true,
  96769. geometryInstances : geometries,
  96770. appearance : new this.appearanceType({
  96771. material : this.material,
  96772. translucent : this.material.isTranslucent(),
  96773. closed : this.closed
  96774. }),
  96775. shadows : this.shadows
  96776. });
  96777. primitives.add(primitive);
  96778. isUpdated = false;
  96779. } else {
  96780. if (defined(primitive)) {
  96781. primitives.remove(primitive);
  96782. primitive = undefined;
  96783. }
  96784. var oldPrimitive = this.oldPrimitive;
  96785. if (defined(oldPrimitive)) {
  96786. primitives.remove(oldPrimitive);
  96787. this.oldPrimitive = undefined;
  96788. }
  96789. }
  96790. this.attributes.removeAll();
  96791. this.primitive = primitive;
  96792. this.createPrimitive = false;
  96793. } else if (defined(primitive) && primitive.ready) {
  96794. if (defined(this.oldPrimitive)) {
  96795. primitives.remove(this.oldPrimitive);
  96796. this.oldPrimitive = undefined;
  96797. }
  96798. this.material = MaterialProperty.getValue(time, this.materialProperty, this.material);
  96799. this.primitive.appearance.material = this.material;
  96800. var updatersWithAttributes = this.updatersWithAttributes.values;
  96801. var length = updatersWithAttributes.length;
  96802. for (i = 0; i < length; i++) {
  96803. var updater = updatersWithAttributes[i];
  96804. var entity = updater.entity;
  96805. var instance = this.geometry.get(entity.id);
  96806. attributes = this.attributes.get(instance.id.id);
  96807. if (!defined(attributes)) {
  96808. attributes = primitive.getGeometryInstanceAttributes(instance.id);
  96809. this.attributes.set(instance.id.id, attributes);
  96810. }
  96811. var show = entity.isShowing && (updater.hasConstantFill || updater.isFilled(time));
  96812. var currentShow = attributes.show[0] === 1;
  96813. if (show !== currentShow) {
  96814. attributes.show = ShowGeometryInstanceAttribute.toValue(show, attributes.show);
  96815. }
  96816. var distanceDisplayConditionProperty = updater.distanceDisplayConditionProperty;
  96817. if (!Property.isConstant(distanceDisplayConditionProperty)) {
  96818. var distanceDisplayCondition = distanceDisplayConditionProperty.getValue(time, distanceDisplayConditionScratch);
  96819. if (!DistanceDisplayCondition.equals(distanceDisplayCondition, attributes._lastDistanceDisplayCondition)) {
  96820. attributes._lastDistanceDisplayCondition = DistanceDisplayCondition.clone(distanceDisplayCondition, attributes._lastDistanceDisplayCondition);
  96821. attributes.distanceDisplayCondition = DistanceDisplayConditionGeometryInstanceAttribute.toValue(distanceDisplayCondition, attributes.distanceDisplayCondition);
  96822. }
  96823. }
  96824. }
  96825. this.updateShows(primitive);
  96826. } else if (defined(primitive) && !primitive.ready) {
  96827. isUpdated = false;
  96828. }
  96829. return isUpdated;
  96830. };
  96831. Batch.prototype.updateShows = function(primitive) {
  96832. var showsUpdated = this.showsUpdated.values;
  96833. var length = showsUpdated.length;
  96834. for (var i = 0; i < length; i++) {
  96835. var updater = showsUpdated[i];
  96836. var entity = updater.entity;
  96837. var instance = this.geometry.get(entity.id);
  96838. var attributes = this.attributes.get(instance.id.id);
  96839. if (!defined(attributes)) {
  96840. attributes = primitive.getGeometryInstanceAttributes(instance.id);
  96841. this.attributes.set(instance.id.id, attributes);
  96842. }
  96843. var show = entity.isShowing;
  96844. var currentShow = attributes.show[0] === 1;
  96845. if (show !== currentShow) {
  96846. attributes.show = ShowGeometryInstanceAttribute.toValue(show, attributes.show);
  96847. }
  96848. }
  96849. this.showsUpdated.removeAll();
  96850. };
  96851. Batch.prototype.contains = function(entity) {
  96852. return this.updaters.contains(entity.id);
  96853. };
  96854. Batch.prototype.getBoundingSphere = function(entity, result) {
  96855. var primitive = this.primitive;
  96856. if (!primitive.ready) {
  96857. return BoundingSphereState.PENDING;
  96858. }
  96859. var attributes = primitive.getGeometryInstanceAttributes(entity);
  96860. if (!defined(attributes) || !defined(attributes.boundingSphere) ||
  96861. (defined(attributes.show) && attributes.show[0] === 0)) {
  96862. return BoundingSphereState.FAILED;
  96863. }
  96864. attributes.boundingSphere.clone(result);
  96865. return BoundingSphereState.DONE;
  96866. };
  96867. Batch.prototype.destroy = function(time) {
  96868. var primitive = this.primitive;
  96869. var primitives = this.primitives;
  96870. if (defined(primitive)) {
  96871. primitives.remove(primitive);
  96872. }
  96873. var oldPrimitive = this.oldPrimitive;
  96874. if (defined(oldPrimitive)) {
  96875. primitives.remove(oldPrimitive);
  96876. }
  96877. this.removeMaterialSubscription();
  96878. };
  96879. /**
  96880. * @private
  96881. */
  96882. function StaticGeometryPerMaterialBatch(primitives, appearanceType, closed, shadows) {
  96883. this._items = [];
  96884. this._primitives = primitives;
  96885. this._appearanceType = appearanceType;
  96886. this._closed = closed;
  96887. this._shadows = shadows;
  96888. }
  96889. StaticGeometryPerMaterialBatch.prototype.add = function(time, updater) {
  96890. var items = this._items;
  96891. var length = items.length;
  96892. for (var i = 0; i < length; i++) {
  96893. var item = items[i];
  96894. if (item.isMaterial(updater)) {
  96895. item.add(time, updater);
  96896. return;
  96897. }
  96898. }
  96899. var batch = new Batch(this._primitives, this._appearanceType, updater.fillMaterialProperty, this._closed, this._shadows);
  96900. batch.add(time, updater);
  96901. items.push(batch);
  96902. };
  96903. StaticGeometryPerMaterialBatch.prototype.remove = function(updater) {
  96904. var items = this._items;
  96905. var length = items.length;
  96906. for (var i = length - 1; i >= 0; i--) {
  96907. var item = items[i];
  96908. if (item.remove(updater)) {
  96909. if (item.updaters.length === 0) {
  96910. items.splice(i, 1);
  96911. item.destroy();
  96912. }
  96913. break;
  96914. }
  96915. }
  96916. };
  96917. StaticGeometryPerMaterialBatch.prototype.update = function(time) {
  96918. var i;
  96919. var items = this._items;
  96920. var length = items.length;
  96921. for (i = length - 1; i >= 0; i--) {
  96922. var item = items[i];
  96923. if (item.invalidated) {
  96924. items.splice(i, 1);
  96925. var updaters = item.updaters.values;
  96926. var updatersLength = updaters.length;
  96927. for (var h = 0; h < updatersLength; h++) {
  96928. this.add(time, updaters[h]);
  96929. }
  96930. item.destroy();
  96931. }
  96932. }
  96933. var isUpdated = true;
  96934. for (i = 0; i < length; i++) {
  96935. isUpdated = items[i].update(time) && isUpdated;
  96936. }
  96937. return isUpdated;
  96938. };
  96939. StaticGeometryPerMaterialBatch.prototype.getBoundingSphere = function(entity, result) {
  96940. var items = this._items;
  96941. var length = items.length;
  96942. for (var i = 0; i < length; i++) {
  96943. var item = items[i];
  96944. if(item.contains(entity)){
  96945. return item.getBoundingSphere(entity, result);
  96946. }
  96947. }
  96948. return BoundingSphereState.FAILED;
  96949. };
  96950. StaticGeometryPerMaterialBatch.prototype.removeAllPrimitives = function() {
  96951. var items = this._items;
  96952. var length = items.length;
  96953. for (var i = 0; i < length; i++) {
  96954. items[i].destroy();
  96955. }
  96956. this._items.length = 0;
  96957. };
  96958. return StaticGeometryPerMaterialBatch;
  96959. });
  96960. /*global define*/
  96961. define('DataSources/StaticGroundGeometryColorBatch',[
  96962. '../Core/AssociativeArray',
  96963. '../Core/Color',
  96964. '../Core/defined',
  96965. '../Core/DistanceDisplayCondition',
  96966. '../Core/DistanceDisplayConditionGeometryInstanceAttribute',
  96967. '../Core/ShowGeometryInstanceAttribute',
  96968. '../Scene/GroundPrimitive',
  96969. './BoundingSphereState',
  96970. './Property'
  96971. ], function(
  96972. AssociativeArray,
  96973. Color,
  96974. defined,
  96975. DistanceDisplayCondition,
  96976. DistanceDisplayConditionGeometryInstanceAttribute,
  96977. ShowGeometryInstanceAttribute,
  96978. GroundPrimitive,
  96979. BoundingSphereState,
  96980. Property) {
  96981. "use strict";
  96982. var colorScratch = new Color();
  96983. var distanceDisplayConditionScratch = new DistanceDisplayCondition();
  96984. function Batch(primitives, color, key) {
  96985. this.primitives = primitives;
  96986. this.color = color;
  96987. this.key = key;
  96988. this.createPrimitive = false;
  96989. this.waitingOnCreate = false;
  96990. this.primitive = undefined;
  96991. this.oldPrimitive = undefined;
  96992. this.geometry = new AssociativeArray();
  96993. this.updaters = new AssociativeArray();
  96994. this.updatersWithAttributes = new AssociativeArray();
  96995. this.attributes = new AssociativeArray();
  96996. this.subscriptions = new AssociativeArray();
  96997. this.showsUpdated = new AssociativeArray();
  96998. this.itemsToRemove = [];
  96999. this.isDirty = false;
  97000. }
  97001. Batch.prototype.add = function(updater, instance) {
  97002. var id = updater.entity.id;
  97003. this.createPrimitive = true;
  97004. this.geometry.set(id, instance);
  97005. this.updaters.set(id, updater);
  97006. if (!updater.hasConstantFill || !updater.fillMaterialProperty.isConstant || !Property.isConstant(updater.distanceDisplayConditionProperty)) {
  97007. this.updatersWithAttributes.set(id, updater);
  97008. } else {
  97009. var that = this;
  97010. this.subscriptions.set(id, updater.entity.definitionChanged.addEventListener(function(entity, propertyName, newValue, oldValue) {
  97011. if (propertyName === 'isShowing') {
  97012. that.showsUpdated.set(entity.id, updater);
  97013. }
  97014. }));
  97015. }
  97016. };
  97017. Batch.prototype.remove = function(updater) {
  97018. var id = updater.entity.id;
  97019. this.createPrimitive = this.geometry.remove(id) || this.createPrimitive;
  97020. if (this.updaters.remove(id)) {
  97021. this.updatersWithAttributes.remove(id);
  97022. var unsubscribe = this.subscriptions.get(id);
  97023. if (defined(unsubscribe)) {
  97024. unsubscribe();
  97025. this.subscriptions.remove(id);
  97026. }
  97027. }
  97028. };
  97029. var scratchArray = new Array(4);
  97030. Batch.prototype.update = function(time) {
  97031. var isUpdated = true;
  97032. var removedCount = 0;
  97033. var primitive = this.primitive;
  97034. var primitives = this.primitives;
  97035. var attributes;
  97036. var i;
  97037. if (this.createPrimitive) {
  97038. var geometries = this.geometry.values;
  97039. var geometriesLength = geometries.length;
  97040. if (geometriesLength > 0) {
  97041. if (defined(primitive)) {
  97042. if (!defined(this.oldPrimitive)) {
  97043. this.oldPrimitive = primitive;
  97044. } else {
  97045. primitives.remove(primitive);
  97046. }
  97047. }
  97048. for (i = 0; i < geometriesLength; i++) {
  97049. var geometryItem = geometries[i];
  97050. var originalAttributes = geometryItem.attributes;
  97051. attributes = this.attributes.get(geometryItem.id.id);
  97052. if (defined(attributes)) {
  97053. if (defined(originalAttributes.show)) {
  97054. originalAttributes.show.value = attributes.show;
  97055. }
  97056. if (defined(originalAttributes.color)) {
  97057. originalAttributes.color.value = attributes.color;
  97058. }
  97059. }
  97060. }
  97061. primitive = new GroundPrimitive({
  97062. asynchronous : true,
  97063. geometryInstances : geometries
  97064. });
  97065. primitives.add(primitive);
  97066. isUpdated = false;
  97067. } else {
  97068. if (defined(primitive)) {
  97069. primitives.remove(primitive);
  97070. primitive = undefined;
  97071. }
  97072. var oldPrimitive = this.oldPrimitive;
  97073. if (defined(oldPrimitive)) {
  97074. primitives.remove(oldPrimitive);
  97075. this.oldPrimitive = undefined;
  97076. }
  97077. }
  97078. this.attributes.removeAll();
  97079. this.primitive = primitive;
  97080. this.createPrimitive = false;
  97081. this.waitingOnCreate = true;
  97082. } else if (defined(primitive) && primitive.ready) {
  97083. if (defined(this.oldPrimitive)) {
  97084. primitives.remove(this.oldPrimitive);
  97085. this.oldPrimitive = undefined;
  97086. }
  97087. var updatersWithAttributes = this.updatersWithAttributes.values;
  97088. var length = updatersWithAttributes.length;
  97089. var waitingOnCreate = this.waitingOnCreate;
  97090. for (i = 0; i < length; i++) {
  97091. var updater = updatersWithAttributes[i];
  97092. var instance = this.geometry.get(updater.entity.id);
  97093. attributes = this.attributes.get(instance.id.id);
  97094. if (!defined(attributes)) {
  97095. attributes = primitive.getGeometryInstanceAttributes(instance.id);
  97096. this.attributes.set(instance.id.id, attributes);
  97097. }
  97098. if (!updater.fillMaterialProperty.isConstant || waitingOnCreate) {
  97099. var colorProperty = updater.fillMaterialProperty.color;
  97100. colorProperty.getValue(time, colorScratch);
  97101. if (!Color.equals(attributes._lastColor, colorScratch)) {
  97102. attributes._lastColor = Color.clone(colorScratch, attributes._lastColor);
  97103. var color = this.color;
  97104. var newColor = colorScratch.toBytes(scratchArray);
  97105. if (color[0] !== newColor[0] || color[1] !== newColor[1] ||
  97106. color[2] !== newColor[2] || color[3] !== newColor[3]) {
  97107. this.itemsToRemove[removedCount++] = updater;
  97108. }
  97109. }
  97110. }
  97111. var show = updater.entity.isShowing && (updater.hasConstantFill || updater.isFilled(time));
  97112. var currentShow = attributes.show[0] === 1;
  97113. if (show !== currentShow) {
  97114. attributes.show = ShowGeometryInstanceAttribute.toValue(show, attributes.show);
  97115. }
  97116. var distanceDisplayConditionProperty = updater.distanceDisplayConditionProperty;
  97117. if (!Property.isConstant(distanceDisplayConditionProperty)) {
  97118. var distanceDisplayCondition = distanceDisplayConditionProperty.getValue(time, distanceDisplayConditionScratch);
  97119. if (!DistanceDisplayCondition.equals(distanceDisplayCondition, attributes._lastDistanceDisplayCondition)) {
  97120. attributes._lastDistanceDisplayCondition = DistanceDisplayCondition.clone(distanceDisplayCondition, attributes._lastDistanceDisplayCondition);
  97121. attributes.distanceDisplayCondition = DistanceDisplayConditionGeometryInstanceAttribute.toValue(distanceDisplayCondition, attributes.distanceDisplayCondition);
  97122. }
  97123. }
  97124. }
  97125. this.updateShows(primitive);
  97126. this.waitingOnCreate = false;
  97127. } else if (defined(primitive) && !primitive.ready) {
  97128. isUpdated = false;
  97129. }
  97130. this.itemsToRemove.length = removedCount;
  97131. return isUpdated;
  97132. };
  97133. Batch.prototype.updateShows = function(primitive) {
  97134. var showsUpdated = this.showsUpdated.values;
  97135. var length = showsUpdated.length;
  97136. for (var i = 0; i < length; i++) {
  97137. var updater = showsUpdated[i];
  97138. var instance = this.geometry.get(updater.entity.id);
  97139. var attributes = this.attributes.get(instance.id.id);
  97140. if (!defined(attributes)) {
  97141. attributes = primitive.getGeometryInstanceAttributes(instance.id);
  97142. this.attributes.set(instance.id.id, attributes);
  97143. }
  97144. var show = updater.entity.isShowing;
  97145. var currentShow = attributes.show[0] === 1;
  97146. if (show !== currentShow) {
  97147. attributes.show = ShowGeometryInstanceAttribute.toValue(show, attributes.show);
  97148. }
  97149. }
  97150. this.showsUpdated.removeAll();
  97151. };
  97152. Batch.prototype.contains = function(entity) {
  97153. return this.updaters.contains(entity.id);
  97154. };
  97155. Batch.prototype.getBoundingSphere = function(entity, result) {
  97156. var primitive = this.primitive;
  97157. if (!primitive.ready) {
  97158. return BoundingSphereState.PENDING;
  97159. }
  97160. var bs = primitive.getBoundingSphere(entity);
  97161. if (!defined(bs)) {
  97162. return BoundingSphereState.FAILED;
  97163. }
  97164. bs.clone(result);
  97165. return BoundingSphereState.DONE;
  97166. };
  97167. Batch.prototype.removeAllPrimitives = function() {
  97168. var primitives = this.primitives;
  97169. var primitive = this.primitive;
  97170. if (defined(primitive)) {
  97171. primitives.remove(primitive);
  97172. this.primitive = undefined;
  97173. this.geometry.removeAll();
  97174. this.updaters.removeAll();
  97175. }
  97176. var oldPrimitive = this.oldPrimitive;
  97177. if (defined(oldPrimitive)) {
  97178. primitives.remove(oldPrimitive);
  97179. this.oldPrimitive = undefined;
  97180. }
  97181. };
  97182. /**
  97183. * @private
  97184. */
  97185. function StaticGroundGeometryColorBatch(primitives) {
  97186. this._batches = new AssociativeArray();
  97187. this._primitives = primitives;
  97188. }
  97189. StaticGroundGeometryColorBatch.prototype.add = function(time, updater) {
  97190. var instance = updater.createFillGeometryInstance(time);
  97191. var batches = this._batches;
  97192. // instance.attributes.color.value is a Uint8Array, so just read it as a Uint32 and make that the key
  97193. var batchKey = new Uint32Array(instance.attributes.color.value.buffer)[0];
  97194. var batch;
  97195. if (batches.contains(batchKey)) {
  97196. batch = batches.get(batchKey);
  97197. } else {
  97198. batch = new Batch(this._primitives, instance.attributes.color.value, batchKey);
  97199. batches.set(batchKey, batch);
  97200. }
  97201. batch.add(updater, instance);
  97202. return batch;
  97203. };
  97204. StaticGroundGeometryColorBatch.prototype.remove = function(updater) {
  97205. var batchesArray = this._batches.values;
  97206. var count = batchesArray.length;
  97207. for (var i = 0; i < count; ++i) {
  97208. if (batchesArray[i].remove(updater)) {
  97209. return;
  97210. }
  97211. }
  97212. };
  97213. StaticGroundGeometryColorBatch.prototype.update = function(time) {
  97214. var i;
  97215. var updater;
  97216. //Perform initial update
  97217. var isUpdated = true;
  97218. var batches = this._batches;
  97219. var batchesArray = batches.values;
  97220. var batchCount = batchesArray.length;
  97221. for (i = 0; i < batchCount; ++i) {
  97222. isUpdated = batchesArray[i].update(time) && isUpdated;
  97223. }
  97224. //If any items swapped between batches we need to move them
  97225. for (i = 0; i < batchCount; ++i) {
  97226. var oldBatch = batchesArray[i];
  97227. var itemsToRemove = oldBatch.itemsToRemove;
  97228. var itemsToMoveLength = itemsToRemove.length;
  97229. for (var j = 0; j < itemsToMoveLength; j++) {
  97230. updater = itemsToRemove[j];
  97231. oldBatch.remove(updater);
  97232. var newBatch = this.add(time, updater);
  97233. oldBatch.isDirty = true;
  97234. newBatch.isDirty = true;
  97235. }
  97236. }
  97237. //If we moved anything around, we need to re-build the primitive and remove empty batches
  97238. var batchesArrayCopy = batchesArray.slice();
  97239. var batchesCopyCount = batchesArrayCopy.length;
  97240. for (i = 0; i < batchesCopyCount; ++i) {
  97241. var batch = batchesArrayCopy[i];
  97242. if (batch.isDirty) {
  97243. isUpdated = batchesArrayCopy[i].update(time) && isUpdated;
  97244. batch.isDirty = false;
  97245. }
  97246. if (batch.geometry.length === 0) {
  97247. batches.remove(batch.key);
  97248. }
  97249. }
  97250. return isUpdated;
  97251. };
  97252. StaticGroundGeometryColorBatch.prototype.getBoundingSphere = function(entity, result) {
  97253. var batchesArray = this._batches.values;
  97254. var batchCount = batchesArray.length;
  97255. for (var i = 0; i < batchCount; ++i) {
  97256. var batch = batchesArray[i];
  97257. if (batch.contains(entity)) {
  97258. return batch.getBoundingSphere(entity, result);
  97259. }
  97260. }
  97261. return BoundingSphereState.FAILED;
  97262. };
  97263. StaticGroundGeometryColorBatch.prototype.removeAllPrimitives = function() {
  97264. var batchesArray = this._batches.values;
  97265. var batchCount = batchesArray.length;
  97266. for (var i = 0; i < batchCount; ++i) {
  97267. batchesArray[i].removeAllPrimitives();
  97268. }
  97269. };
  97270. return StaticGroundGeometryColorBatch;
  97271. });
  97272. /*global define*/
  97273. define('DataSources/StaticOutlineGeometryBatch',[
  97274. '../Core/AssociativeArray',
  97275. '../Core/Color',
  97276. '../Core/ColorGeometryInstanceAttribute',
  97277. '../Core/defined',
  97278. '../Core/DistanceDisplayCondition',
  97279. '../Core/DistanceDisplayConditionGeometryInstanceAttribute',
  97280. '../Core/ShowGeometryInstanceAttribute',
  97281. '../Scene/PerInstanceColorAppearance',
  97282. '../Scene/Primitive',
  97283. './BoundingSphereState',
  97284. './Property'
  97285. ], function(
  97286. AssociativeArray,
  97287. Color,
  97288. ColorGeometryInstanceAttribute,
  97289. defined,
  97290. DistanceDisplayCondition,
  97291. DistanceDisplayConditionGeometryInstanceAttribute,
  97292. ShowGeometryInstanceAttribute,
  97293. PerInstanceColorAppearance,
  97294. Primitive,
  97295. BoundingSphereState,
  97296. Property) {
  97297. 'use strict';
  97298. function Batch(primitives, translucent, width, shadows) {
  97299. this.translucent = translucent;
  97300. this.width = width;
  97301. this.shadows = shadows;
  97302. this.primitives = primitives;
  97303. this.createPrimitive = false;
  97304. this.waitingOnCreate = false;
  97305. this.primitive = undefined;
  97306. this.oldPrimitive = undefined;
  97307. this.geometry = new AssociativeArray();
  97308. this.updaters = new AssociativeArray();
  97309. this.updatersWithAttributes = new AssociativeArray();
  97310. this.attributes = new AssociativeArray();
  97311. this.itemsToRemove = [];
  97312. this.subscriptions = new AssociativeArray();
  97313. this.showsUpdated = new AssociativeArray();
  97314. }
  97315. Batch.prototype.add = function(updater, instance) {
  97316. var id = updater.entity.id;
  97317. this.createPrimitive = true;
  97318. this.geometry.set(id, instance);
  97319. this.updaters.set(id, updater);
  97320. if (!updater.hasConstantOutline || !updater.outlineColorProperty.isConstant || !Property.isConstant(updater.distanceDisplayConditionProperty)) {
  97321. this.updatersWithAttributes.set(id, updater);
  97322. } else {
  97323. var that = this;
  97324. this.subscriptions.set(id, updater.entity.definitionChanged.addEventListener(function(entity, propertyName, newValue, oldValue) {
  97325. if (propertyName === 'isShowing') {
  97326. that.showsUpdated.set(entity.id, updater);
  97327. }
  97328. }));
  97329. }
  97330. };
  97331. Batch.prototype.remove = function(updater) {
  97332. var id = updater.entity.id;
  97333. this.createPrimitive = this.geometry.remove(id) || this.createPrimitive;
  97334. if (this.updaters.remove(id)) {
  97335. this.updatersWithAttributes.remove(id);
  97336. var unsubscribe = this.subscriptions.get(id);
  97337. if (defined(unsubscribe)) {
  97338. unsubscribe();
  97339. this.subscriptions.remove(id);
  97340. }
  97341. }
  97342. };
  97343. var colorScratch = new Color();
  97344. var distanceDisplayConditionScratch = new DistanceDisplayCondition();
  97345. Batch.prototype.update = function(time) {
  97346. var isUpdated = true;
  97347. var removedCount = 0;
  97348. var primitive = this.primitive;
  97349. var primitives = this.primitives;
  97350. var attributes;
  97351. var i;
  97352. if (this.createPrimitive) {
  97353. var geometries = this.geometry.values;
  97354. var geometriesLength = geometries.length;
  97355. if (geometriesLength > 0) {
  97356. if (defined(primitive)) {
  97357. if (!defined(this.oldPrimitive)) {
  97358. this.oldPrimitive = primitive;
  97359. } else {
  97360. primitives.remove(primitive);
  97361. }
  97362. }
  97363. for (i = 0; i < geometriesLength; i++) {
  97364. var geometryItem = geometries[i];
  97365. var originalAttributes = geometryItem.attributes;
  97366. attributes = this.attributes.get(geometryItem.id.id);
  97367. if (defined(attributes)) {
  97368. if (defined(originalAttributes.show)) {
  97369. originalAttributes.show.value = attributes.show;
  97370. }
  97371. if (defined(originalAttributes.color)) {
  97372. originalAttributes.color.value = attributes.color;
  97373. }
  97374. }
  97375. }
  97376. primitive = new Primitive({
  97377. asynchronous : true,
  97378. geometryInstances : geometries,
  97379. appearance : new PerInstanceColorAppearance({
  97380. flat : true,
  97381. translucent : this.translucent,
  97382. renderState : {
  97383. lineWidth : this.width
  97384. }
  97385. }),
  97386. shadows : this.shadows
  97387. });
  97388. primitives.add(primitive);
  97389. isUpdated = false;
  97390. } else {
  97391. if (defined(primitive)) {
  97392. primitives.remove(primitive);
  97393. primitive = undefined;
  97394. }
  97395. var oldPrimitive = this.oldPrimitive;
  97396. if (defined(oldPrimitive)) {
  97397. primitives.remove(oldPrimitive);
  97398. this.oldPrimitive = undefined;
  97399. }
  97400. }
  97401. this.attributes.removeAll();
  97402. this.primitive = primitive;
  97403. this.createPrimitive = false;
  97404. this.waitingOnCreate = true;
  97405. } else if (defined(primitive) && primitive.ready) {
  97406. if (defined(this.oldPrimitive)) {
  97407. primitives.remove(this.oldPrimitive);
  97408. this.oldPrimitive = undefined;
  97409. }
  97410. var updatersWithAttributes = this.updatersWithAttributes.values;
  97411. var length = updatersWithAttributes.length;
  97412. var waitingOnCreate = this.waitingOnCreate;
  97413. for (i = 0; i < length; i++) {
  97414. var updater = updatersWithAttributes[i];
  97415. var instance = this.geometry.get(updater.entity.id);
  97416. attributes = this.attributes.get(instance.id.id);
  97417. if (!defined(attributes)) {
  97418. attributes = primitive.getGeometryInstanceAttributes(instance.id);
  97419. this.attributes.set(instance.id.id, attributes);
  97420. }
  97421. if (!updater.outlineColorProperty.isConstant || waitingOnCreate) {
  97422. var outlineColorProperty = updater.outlineColorProperty;
  97423. outlineColorProperty.getValue(time, colorScratch);
  97424. if (!Color.equals(attributes._lastColor, colorScratch)) {
  97425. attributes._lastColor = Color.clone(colorScratch, attributes._lastColor);
  97426. attributes.color = ColorGeometryInstanceAttribute.toValue(colorScratch, attributes.color);
  97427. if ((this.translucent && attributes.color[3] === 255) || (!this.translucent && attributes.color[3] !== 255)) {
  97428. this.itemsToRemove[removedCount++] = updater;
  97429. }
  97430. }
  97431. }
  97432. var show = updater.entity.isShowing && (updater.hasConstantOutline || updater.isOutlineVisible(time));
  97433. var currentShow = attributes.show[0] === 1;
  97434. if (show !== currentShow) {
  97435. attributes.show = ShowGeometryInstanceAttribute.toValue(show, attributes.show);
  97436. }
  97437. var distanceDisplayConditionProperty = updater.distanceDisplayConditionProperty;
  97438. if (!Property.isConstant(distanceDisplayConditionProperty)) {
  97439. var distanceDisplayCondition = distanceDisplayConditionProperty.getValue(time, distanceDisplayConditionScratch);
  97440. if (!DistanceDisplayCondition.equals(distanceDisplayCondition, attributes._lastDistanceDisplayCondition)) {
  97441. attributes._lastDistanceDisplayCondition = DistanceDisplayCondition.clone(distanceDisplayCondition, attributes._lastDistanceDisplayCondition);
  97442. attributes.distanceDisplayCondition = DistanceDisplayConditionGeometryInstanceAttribute.toValue(distanceDisplayCondition, attributes.distanceDisplayCondition);
  97443. }
  97444. }
  97445. }
  97446. this.updateShows(primitive);
  97447. this.waitingOnCreate = false;
  97448. } else if (defined(primitive) && !primitive.ready) {
  97449. isUpdated = false;
  97450. }
  97451. this.itemsToRemove.length = removedCount;
  97452. return isUpdated;
  97453. };
  97454. Batch.prototype.updateShows = function(primitive) {
  97455. var showsUpdated = this.showsUpdated.values;
  97456. var length = showsUpdated.length;
  97457. for (var i = 0; i < length; i++) {
  97458. var updater = showsUpdated[i];
  97459. var instance = this.geometry.get(updater.entity.id);
  97460. var attributes = this.attributes.get(instance.id.id);
  97461. if (!defined(attributes)) {
  97462. attributes = primitive.getGeometryInstanceAttributes(instance.id);
  97463. this.attributes.set(instance.id.id, attributes);
  97464. }
  97465. var show = updater.entity.isShowing;
  97466. var currentShow = attributes.show[0] === 1;
  97467. if (show !== currentShow) {
  97468. attributes.show = ShowGeometryInstanceAttribute.toValue(show, attributes.show);
  97469. }
  97470. }
  97471. this.showsUpdated.removeAll();
  97472. };
  97473. Batch.prototype.contains = function(entity) {
  97474. return this.updaters.contains(entity.id);
  97475. };
  97476. Batch.prototype.getBoundingSphere = function(entity, result) {
  97477. var primitive = this.primitive;
  97478. if (!primitive.ready) {
  97479. return BoundingSphereState.PENDING;
  97480. }
  97481. var attributes = primitive.getGeometryInstanceAttributes(entity);
  97482. if (!defined(attributes) || !defined(attributes.boundingSphere) ||//
  97483. (defined(attributes.show) && attributes.show[0] === 0)) {
  97484. return BoundingSphereState.FAILED;
  97485. }
  97486. attributes.boundingSphere.clone(result);
  97487. return BoundingSphereState.DONE;
  97488. };
  97489. Batch.prototype.removeAllPrimitives = function() {
  97490. var primitives = this.primitives;
  97491. var primitive = this.primitive;
  97492. if (defined(primitive)) {
  97493. primitives.remove(primitive);
  97494. this.primitive = undefined;
  97495. this.geometry.removeAll();
  97496. this.updaters.removeAll();
  97497. }
  97498. var oldPrimitive = this.oldPrimitive;
  97499. if (defined(oldPrimitive)) {
  97500. primitives.remove(oldPrimitive);
  97501. this.oldPrimitive = undefined;
  97502. }
  97503. };
  97504. /**
  97505. * @private
  97506. */
  97507. function StaticOutlineGeometryBatch(primitives, scene, shadows) {
  97508. this._primitives = primitives;
  97509. this._scene = scene;
  97510. this._shadows = shadows;
  97511. this._solidBatches = new AssociativeArray();
  97512. this._translucentBatches = new AssociativeArray();
  97513. }
  97514. StaticOutlineGeometryBatch.prototype.add = function(time, updater) {
  97515. var instance = updater.createOutlineGeometryInstance(time);
  97516. var width = this._scene.clampLineWidth(updater.outlineWidth);
  97517. var batches;
  97518. var batch;
  97519. if (instance.attributes.color.value[3] === 255) {
  97520. batches = this._solidBatches;
  97521. batch = batches.get(width);
  97522. if (!defined(batch)) {
  97523. batch = new Batch(this._primitives, false, width, this._shadows);
  97524. batches.set(width, batch);
  97525. }
  97526. batch.add(updater, instance);
  97527. } else {
  97528. batches = this._translucentBatches;
  97529. batch = batches.get(width);
  97530. if (!defined(batch)) {
  97531. batch = new Batch(this._primitives, true, width, this._shadows);
  97532. batches.set(width, batch);
  97533. }
  97534. batch.add(updater, instance);
  97535. }
  97536. };
  97537. StaticOutlineGeometryBatch.prototype.remove = function(updater) {
  97538. var i;
  97539. var solidBatches = this._solidBatches.values;
  97540. var solidBatchesLength = solidBatches.length;
  97541. for (i = 0; i < solidBatchesLength; i++) {
  97542. if (solidBatches[i].remove(updater)) {
  97543. return;
  97544. }
  97545. }
  97546. var translucentBatches = this._translucentBatches.values;
  97547. var translucentBatchesLength = translucentBatches.length;
  97548. for (i = 0; i < translucentBatchesLength; i++) {
  97549. if (translucentBatches[i].remove(updater)) {
  97550. return;
  97551. }
  97552. }
  97553. };
  97554. StaticOutlineGeometryBatch.prototype.update = function(time) {
  97555. var i;
  97556. var x;
  97557. var updater;
  97558. var batch;
  97559. var solidBatches = this._solidBatches.values;
  97560. var solidBatchesLength = solidBatches.length;
  97561. var translucentBatches = this._translucentBatches.values;
  97562. var translucentBatchesLength = translucentBatches.length;
  97563. var itemsToRemove;
  97564. var isUpdated = true;
  97565. var needUpdate = false;
  97566. do {
  97567. needUpdate = false;
  97568. for (x = 0; x < solidBatchesLength; x++) {
  97569. batch = solidBatches[x];
  97570. //Perform initial update
  97571. isUpdated = batch.update(time);
  97572. //If any items swapped between solid/translucent, we need to
  97573. //move them between batches
  97574. itemsToRemove = batch.itemsToRemove;
  97575. var solidsToMoveLength = itemsToRemove.length;
  97576. if (solidsToMoveLength > 0) {
  97577. needUpdate = true;
  97578. for (i = 0; i < solidsToMoveLength; i++) {
  97579. updater = itemsToRemove[i];
  97580. batch.remove(updater);
  97581. this.add(time, updater);
  97582. }
  97583. }
  97584. }
  97585. for (x = 0; x < translucentBatchesLength; x++) {
  97586. batch = translucentBatches[x];
  97587. //Perform initial update
  97588. isUpdated = batch.update(time);
  97589. //If any items swapped between solid/translucent, we need to
  97590. //move them between batches
  97591. itemsToRemove = batch.itemsToRemove;
  97592. var translucentToMoveLength = itemsToRemove.length;
  97593. if (translucentToMoveLength > 0) {
  97594. needUpdate = true;
  97595. for (i = 0; i < translucentToMoveLength; i++) {
  97596. updater = itemsToRemove[i];
  97597. batch.remove(updater);
  97598. this.add(time, updater);
  97599. }
  97600. }
  97601. }
  97602. } while (needUpdate);
  97603. return isUpdated;
  97604. };
  97605. StaticOutlineGeometryBatch.prototype.getBoundingSphere = function(entity, result) {
  97606. var i;
  97607. var solidBatches = this._solidBatches.values;
  97608. var solidBatchesLength = solidBatches.length;
  97609. for (i = 0; i < solidBatchesLength; i++) {
  97610. var solidBatch = solidBatches[i];
  97611. if(solidBatch.contains(entity)){
  97612. return solidBatch.getBoundingSphere(entity, result);
  97613. }
  97614. }
  97615. var translucentBatches = this._translucentBatches.values;
  97616. var translucentBatchesLength = translucentBatches.length;
  97617. for (i = 0; i < translucentBatchesLength; i++) {
  97618. var translucentBatch = translucentBatches[i];
  97619. if(translucentBatch.contains(entity)){
  97620. return translucentBatch.getBoundingSphere(entity, result);
  97621. }
  97622. }
  97623. return BoundingSphereState.FAILED;
  97624. };
  97625. StaticOutlineGeometryBatch.prototype.removeAllPrimitives = function() {
  97626. var i;
  97627. var solidBatches = this._solidBatches.values;
  97628. var solidBatchesLength = solidBatches.length;
  97629. for (i = 0; i < solidBatchesLength; i++) {
  97630. solidBatches[i].removeAllPrimitives();
  97631. }
  97632. var translucentBatches = this._translucentBatches.values;
  97633. var translucentBatchesLength = translucentBatches.length;
  97634. for (i = 0; i < translucentBatchesLength; i++) {
  97635. translucentBatches[i].removeAllPrimitives();
  97636. }
  97637. };
  97638. return StaticOutlineGeometryBatch;
  97639. });
  97640. /*global define*/
  97641. define('DataSources/GeometryVisualizer',[
  97642. '../Core/AssociativeArray',
  97643. '../Core/BoundingSphere',
  97644. '../Core/defined',
  97645. '../Core/destroyObject',
  97646. '../Core/DeveloperError',
  97647. '../Scene/ShadowMode',
  97648. './BoundingSphereState',
  97649. './ColorMaterialProperty',
  97650. './StaticGeometryColorBatch',
  97651. './StaticGeometryPerMaterialBatch',
  97652. './StaticGroundGeometryColorBatch',
  97653. './StaticOutlineGeometryBatch'
  97654. ], function(
  97655. AssociativeArray,
  97656. BoundingSphere,
  97657. defined,
  97658. destroyObject,
  97659. DeveloperError,
  97660. ShadowMode,
  97661. BoundingSphereState,
  97662. ColorMaterialProperty,
  97663. StaticGeometryColorBatch,
  97664. StaticGeometryPerMaterialBatch,
  97665. StaticGroundGeometryColorBatch,
  97666. StaticOutlineGeometryBatch) {
  97667. 'use strict';
  97668. var emptyArray = [];
  97669. function DynamicGeometryBatch(primitives, groundPrimitives) {
  97670. this._primitives = primitives;
  97671. this._groundPrimitives = groundPrimitives;
  97672. this._dynamicUpdaters = new AssociativeArray();
  97673. }
  97674. DynamicGeometryBatch.prototype.add = function(time, updater) {
  97675. this._dynamicUpdaters.set(updater.entity.id, updater.createDynamicUpdater(this._primitives, this._groundPrimitives));
  97676. };
  97677. DynamicGeometryBatch.prototype.remove = function(updater) {
  97678. var id = updater.entity.id;
  97679. var dynamicUpdater = this._dynamicUpdaters.get(id);
  97680. if (defined(dynamicUpdater)) {
  97681. this._dynamicUpdaters.remove(id);
  97682. dynamicUpdater.destroy();
  97683. }
  97684. };
  97685. DynamicGeometryBatch.prototype.update = function(time) {
  97686. var geometries = this._dynamicUpdaters.values;
  97687. for (var i = 0, len = geometries.length; i < len; i++) {
  97688. geometries[i].update(time);
  97689. }
  97690. return true;
  97691. };
  97692. DynamicGeometryBatch.prototype.removeAllPrimitives = function() {
  97693. var geometries = this._dynamicUpdaters.values;
  97694. for (var i = 0, len = geometries.length; i < len; i++) {
  97695. geometries[i].destroy();
  97696. }
  97697. this._dynamicUpdaters.removeAll();
  97698. };
  97699. DynamicGeometryBatch.prototype.getBoundingSphere = function(entity, result) {
  97700. var updater = this._dynamicUpdaters.get(entity.id);
  97701. if (defined(updater) && defined(updater.getBoundingSphere)) {
  97702. return updater.getBoundingSphere(entity, result);
  97703. }
  97704. return BoundingSphereState.FAILED;
  97705. };
  97706. function removeUpdater(that, updater) {
  97707. //We don't keep track of which batch an updater is in, so just remove it from all of them.
  97708. var batches = that._batches;
  97709. var length = batches.length;
  97710. for (var i = 0; i < length; i++) {
  97711. batches[i].remove(updater);
  97712. }
  97713. }
  97714. function insertUpdaterIntoBatch(that, time, updater) {
  97715. if (updater.isDynamic) {
  97716. that._dynamicBatch.add(time, updater);
  97717. return;
  97718. }
  97719. var shadows;
  97720. if (updater.outlineEnabled || updater.fillEnabled) {
  97721. shadows = updater.shadowsProperty.getValue(time);
  97722. }
  97723. if (updater.outlineEnabled) {
  97724. that._outlineBatches[shadows].add(time, updater);
  97725. }
  97726. if (updater.fillEnabled) {
  97727. if (updater.onTerrain) {
  97728. that._groundColorBatch.add(time, updater);
  97729. } else {
  97730. if (updater.isClosed) {
  97731. if (updater.fillMaterialProperty instanceof ColorMaterialProperty) {
  97732. that._closedColorBatches[shadows].add(time, updater);
  97733. } else {
  97734. that._closedMaterialBatches[shadows].add(time, updater);
  97735. }
  97736. } else {
  97737. if (updater.fillMaterialProperty instanceof ColorMaterialProperty) {
  97738. that._openColorBatches[shadows].add(time, updater);
  97739. } else {
  97740. that._openMaterialBatches[shadows].add(time, updater);
  97741. }
  97742. }
  97743. }
  97744. }
  97745. }
  97746. /**
  97747. * A general purpose visualizer for geometry represented by {@link Primitive} instances.
  97748. * @alias GeometryVisualizer
  97749. * @constructor
  97750. *
  97751. * @param {GeometryUpdater} type The updater to be used for creating the geometry.
  97752. * @param {Scene} scene The scene the primitives will be rendered in.
  97753. * @param {EntityCollection} entityCollection The entityCollection to visualize.
  97754. */
  97755. function GeometryVisualizer(type, scene, entityCollection) {
  97756. if (!defined(type)) {
  97757. throw new DeveloperError('type is required.');
  97758. }
  97759. if (!defined(scene)) {
  97760. throw new DeveloperError('scene is required.');
  97761. }
  97762. if (!defined(entityCollection)) {
  97763. throw new DeveloperError('entityCollection is required.');
  97764. }
  97765. this._type = type;
  97766. var primitives = scene.primitives;
  97767. var groundPrimitives = scene.groundPrimitives;
  97768. this._scene = scene;
  97769. this._primitives = primitives;
  97770. this._groundPrimitives = groundPrimitives;
  97771. this._entityCollection = undefined;
  97772. this._addedObjects = new AssociativeArray();
  97773. this._removedObjects = new AssociativeArray();
  97774. this._changedObjects = new AssociativeArray();
  97775. var numberOfShadowModes = ShadowMode.NUMBER_OF_SHADOW_MODES;
  97776. this._outlineBatches = new Array(numberOfShadowModes);
  97777. this._closedColorBatches = new Array(numberOfShadowModes);
  97778. this._closedMaterialBatches = new Array(numberOfShadowModes);
  97779. this._openColorBatches = new Array(numberOfShadowModes);
  97780. this._openMaterialBatches = new Array(numberOfShadowModes);
  97781. for (var i = 0; i < numberOfShadowModes; ++i) {
  97782. this._outlineBatches[i] = new StaticOutlineGeometryBatch(primitives, scene, i);
  97783. this._closedColorBatches[i] = new StaticGeometryColorBatch(primitives, type.perInstanceColorAppearanceType, true, i);
  97784. this._closedMaterialBatches[i] = new StaticGeometryPerMaterialBatch(primitives, type.materialAppearanceType, true, i);
  97785. this._openColorBatches[i] = new StaticGeometryColorBatch(primitives, type.perInstanceColorAppearanceType, false, i);
  97786. this._openMaterialBatches[i] = new StaticGeometryPerMaterialBatch(primitives, type.materialAppearanceType, false, i);
  97787. }
  97788. this._groundColorBatch = new StaticGroundGeometryColorBatch(groundPrimitives);
  97789. this._dynamicBatch = new DynamicGeometryBatch(primitives, groundPrimitives);
  97790. this._batches = this._outlineBatches.concat(this._closedColorBatches, this._closedMaterialBatches, this._openColorBatches, this._openMaterialBatches, this._groundColorBatch, this._dynamicBatch);
  97791. this._subscriptions = new AssociativeArray();
  97792. this._updaters = new AssociativeArray();
  97793. this._entityCollection = entityCollection;
  97794. entityCollection.collectionChanged.addEventListener(GeometryVisualizer.prototype._onCollectionChanged, this);
  97795. this._onCollectionChanged(entityCollection, entityCollection.values, emptyArray);
  97796. }
  97797. /**
  97798. * Updates all of the primitives created by this visualizer to match their
  97799. * Entity counterpart at the given time.
  97800. *
  97801. * @param {JulianDate} time The time to update to.
  97802. * @returns {Boolean} True if the visualizer successfully updated to the provided time,
  97803. * false if the visualizer is waiting for asynchronous primitives to be created.
  97804. */
  97805. GeometryVisualizer.prototype.update = function(time) {
  97806. if (!defined(time)) {
  97807. throw new DeveloperError('time is required.');
  97808. }
  97809. var addedObjects = this._addedObjects;
  97810. var added = addedObjects.values;
  97811. var removedObjects = this._removedObjects;
  97812. var removed = removedObjects.values;
  97813. var changedObjects = this._changedObjects;
  97814. var changed = changedObjects.values;
  97815. var i;
  97816. var entity;
  97817. var id;
  97818. var updater;
  97819. for (i = changed.length - 1; i > -1; i--) {
  97820. entity = changed[i];
  97821. id = entity.id;
  97822. updater = this._updaters.get(id);
  97823. //If in a single update, an entity gets removed and a new instance
  97824. //re-added with the same id, the updater no longer tracks the
  97825. //correct entity, we need to both remove the old one and
  97826. //add the new one, which is done by pushing the entity
  97827. //onto the removed/added lists.
  97828. if (updater.entity === entity) {
  97829. removeUpdater(this, updater);
  97830. insertUpdaterIntoBatch(this, time, updater);
  97831. } else {
  97832. removed.push(entity);
  97833. added.push(entity);
  97834. }
  97835. }
  97836. for (i = removed.length - 1; i > -1; i--) {
  97837. entity = removed[i];
  97838. id = entity.id;
  97839. updater = this._updaters.get(id);
  97840. removeUpdater(this, updater);
  97841. updater.destroy();
  97842. this._updaters.remove(id);
  97843. this._subscriptions.get(id)();
  97844. this._subscriptions.remove(id);
  97845. }
  97846. for (i = added.length - 1; i > -1; i--) {
  97847. entity = added[i];
  97848. id = entity.id;
  97849. updater = new this._type(entity, this._scene);
  97850. this._updaters.set(id, updater);
  97851. insertUpdaterIntoBatch(this, time, updater);
  97852. this._subscriptions.set(id, updater.geometryChanged.addEventListener(GeometryVisualizer._onGeometryChanged, this));
  97853. }
  97854. addedObjects.removeAll();
  97855. removedObjects.removeAll();
  97856. changedObjects.removeAll();
  97857. var isUpdated = true;
  97858. var batches = this._batches;
  97859. var length = batches.length;
  97860. for (i = 0; i < length; i++) {
  97861. isUpdated = batches[i].update(time) && isUpdated;
  97862. }
  97863. return isUpdated;
  97864. };
  97865. var getBoundingSphereArrayScratch = [];
  97866. var getBoundingSphereBoundingSphereScratch = new BoundingSphere();
  97867. /**
  97868. * Computes a bounding sphere which encloses the visualization produced for the specified entity.
  97869. * The bounding sphere is in the fixed frame of the scene's globe.
  97870. *
  97871. * @param {Entity} entity The entity whose bounding sphere to compute.
  97872. * @param {BoundingSphere} result The bounding sphere onto which to store the result.
  97873. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere,
  97874. * BoundingSphereState.PENDING if the result is still being computed, or
  97875. * BoundingSphereState.FAILED if the entity has no visualization in the current scene.
  97876. * @private
  97877. */
  97878. GeometryVisualizer.prototype.getBoundingSphere = function(entity, result) {
  97879. if (!defined(entity)) {
  97880. throw new DeveloperError('entity is required.');
  97881. }
  97882. if (!defined(result)) {
  97883. throw new DeveloperError('result is required.');
  97884. }
  97885. var boundingSpheres = getBoundingSphereArrayScratch;
  97886. var tmp = getBoundingSphereBoundingSphereScratch;
  97887. var count = 0;
  97888. var state = BoundingSphereState.DONE;
  97889. var batches = this._batches;
  97890. var batchesLength = batches.length;
  97891. for (var i = 0; i < batchesLength; i++) {
  97892. state = batches[i].getBoundingSphere(entity, tmp);
  97893. if (state === BoundingSphereState.PENDING) {
  97894. return BoundingSphereState.PENDING;
  97895. } else if (state === BoundingSphereState.DONE) {
  97896. boundingSpheres[count] = BoundingSphere.clone(tmp, boundingSpheres[count]);
  97897. count++;
  97898. }
  97899. }
  97900. if (count === 0) {
  97901. return BoundingSphereState.FAILED;
  97902. }
  97903. boundingSpheres.length = count;
  97904. BoundingSphere.fromBoundingSpheres(boundingSpheres, result);
  97905. return BoundingSphereState.DONE;
  97906. };
  97907. /**
  97908. * Returns true if this object was destroyed; otherwise, false.
  97909. *
  97910. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  97911. */
  97912. GeometryVisualizer.prototype.isDestroyed = function() {
  97913. return false;
  97914. };
  97915. /**
  97916. * Removes and destroys all primitives created by this instance.
  97917. */
  97918. GeometryVisualizer.prototype.destroy = function() {
  97919. this._entityCollection.collectionChanged.removeEventListener(GeometryVisualizer.prototype._onCollectionChanged, this);
  97920. this._addedObjects.removeAll();
  97921. this._removedObjects.removeAll();
  97922. var i;
  97923. var batches = this._batches;
  97924. var length = batches.length;
  97925. for (i = 0; i < length; i++) {
  97926. batches[i].removeAllPrimitives();
  97927. }
  97928. var subscriptions = this._subscriptions.values;
  97929. length = subscriptions.length;
  97930. for (i = 0; i < length; i++) {
  97931. subscriptions[i]();
  97932. }
  97933. this._subscriptions.removeAll();
  97934. return destroyObject(this);
  97935. };
  97936. /**
  97937. * @private
  97938. */
  97939. GeometryVisualizer._onGeometryChanged = function(updater) {
  97940. var removedObjects = this._removedObjects;
  97941. var changedObjects = this._changedObjects;
  97942. var entity = updater.entity;
  97943. var id = entity.id;
  97944. if (!defined(removedObjects.get(id)) && !defined(changedObjects.get(id))) {
  97945. changedObjects.set(id, entity);
  97946. }
  97947. };
  97948. /**
  97949. * @private
  97950. */
  97951. GeometryVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed) {
  97952. var addedObjects = this._addedObjects;
  97953. var removedObjects = this._removedObjects;
  97954. var changedObjects = this._changedObjects;
  97955. var i;
  97956. var id;
  97957. var entity;
  97958. for (i = removed.length - 1; i > -1; i--) {
  97959. entity = removed[i];
  97960. id = entity.id;
  97961. if (!addedObjects.remove(id)) {
  97962. removedObjects.set(id, entity);
  97963. changedObjects.remove(id);
  97964. }
  97965. }
  97966. for (i = added.length - 1; i > -1; i--) {
  97967. entity = added[i];
  97968. id = entity.id;
  97969. if (removedObjects.remove(id)) {
  97970. changedObjects.set(id, entity);
  97971. } else {
  97972. addedObjects.set(id, entity);
  97973. }
  97974. }
  97975. };
  97976. return GeometryVisualizer;
  97977. });
  97978. /*global define*/
  97979. define('DataSources/LabelVisualizer',[
  97980. '../Core/AssociativeArray',
  97981. '../Core/Cartesian2',
  97982. '../Core/Cartesian3',
  97983. '../Core/Color',
  97984. '../Core/defaultValue',
  97985. '../Core/defined',
  97986. '../Core/destroyObject',
  97987. '../Core/DeveloperError',
  97988. '../Core/DistanceDisplayCondition',
  97989. '../Core/NearFarScalar',
  97990. '../Scene/HeightReference',
  97991. '../Scene/HorizontalOrigin',
  97992. '../Scene/LabelStyle',
  97993. '../Scene/VerticalOrigin',
  97994. './BoundingSphereState',
  97995. './Property'
  97996. ], function(
  97997. AssociativeArray,
  97998. Cartesian2,
  97999. Cartesian3,
  98000. Color,
  98001. defaultValue,
  98002. defined,
  98003. destroyObject,
  98004. DeveloperError,
  98005. DistanceDisplayCondition,
  98006. NearFarScalar,
  98007. HeightReference,
  98008. HorizontalOrigin,
  98009. LabelStyle,
  98010. VerticalOrigin,
  98011. BoundingSphereState,
  98012. Property) {
  98013. 'use strict';
  98014. var defaultScale = 1.0;
  98015. var defaultFont = '30px sans-serif';
  98016. var defaultStyle = LabelStyle.FILL;
  98017. var defaultFillColor = Color.WHITE;
  98018. var defaultOutlineColor = Color.BLACK;
  98019. var defaultOutlineWidth = 1.0;
  98020. var defaultShowBackground = false;
  98021. var defaultBackgroundColor = new Color(0.165, 0.165, 0.165, 0.8);
  98022. var defaultBackgroundPadding = new Cartesian2(7, 5);
  98023. var defaultPixelOffset = Cartesian2.ZERO;
  98024. var defaultEyeOffset = Cartesian3.ZERO;
  98025. var defaultHeightReference = HeightReference.NONE;
  98026. var defaultHorizontalOrigin = HorizontalOrigin.CENTER;
  98027. var defaultVerticalOrigin = VerticalOrigin.CENTER;
  98028. var position = new Cartesian3();
  98029. var fillColor = new Color();
  98030. var outlineColor = new Color();
  98031. var backgroundColor = new Color();
  98032. var backgroundPadding = new Cartesian2();
  98033. var eyeOffset = new Cartesian3();
  98034. var pixelOffset = new Cartesian2();
  98035. var translucencyByDistance = new NearFarScalar();
  98036. var pixelOffsetScaleByDistance = new NearFarScalar();
  98037. var distanceDisplayCondition = new DistanceDisplayCondition();
  98038. function EntityData(entity) {
  98039. this.entity = entity;
  98040. this.label = undefined;
  98041. this.index = undefined;
  98042. }
  98043. /**
  98044. * A {@link Visualizer} which maps the {@link LabelGraphics} instance
  98045. * in {@link Entity#label} to a {@link Label}.
  98046. * @alias LabelVisualizer
  98047. * @constructor
  98048. *
  98049. * @param {EntityCluster} entityCluster The entity cluster to manage the collection of billboards and optionally cluster with other entities.
  98050. * @param {EntityCollection} entityCollection The entityCollection to visualize.
  98051. */
  98052. function LabelVisualizer(entityCluster, entityCollection) {
  98053. if (!defined(entityCluster)) {
  98054. throw new DeveloperError('entityCluster is required.');
  98055. }
  98056. if (!defined(entityCollection)) {
  98057. throw new DeveloperError('entityCollection is required.');
  98058. }
  98059. entityCollection.collectionChanged.addEventListener(LabelVisualizer.prototype._onCollectionChanged, this);
  98060. this._cluster = entityCluster;
  98061. this._entityCollection = entityCollection;
  98062. this._items = new AssociativeArray();
  98063. this._onCollectionChanged(entityCollection, entityCollection.values, [], []);
  98064. }
  98065. /**
  98066. * Updates the primitives created by this visualizer to match their
  98067. * Entity counterpart at the given time.
  98068. *
  98069. * @param {JulianDate} time The time to update to.
  98070. * @returns {Boolean} This function always returns true.
  98071. */
  98072. LabelVisualizer.prototype.update = function(time) {
  98073. if (!defined(time)) {
  98074. throw new DeveloperError('time is required.');
  98075. }
  98076. var items = this._items.values;
  98077. var cluster = this._cluster;
  98078. for (var i = 0, len = items.length; i < len; i++) {
  98079. var item = items[i];
  98080. var entity = item.entity;
  98081. var labelGraphics = entity._label;
  98082. var text;
  98083. var label = item.label;
  98084. var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(labelGraphics._show, time, true);
  98085. if (show) {
  98086. position = Property.getValueOrUndefined(entity._position, time, position);
  98087. text = Property.getValueOrUndefined(labelGraphics._text, time);
  98088. show = defined(position) && defined(text);
  98089. }
  98090. if (!show) {
  98091. //don't bother creating or updating anything else
  98092. returnPrimitive(item, entity, cluster);
  98093. continue;
  98094. }
  98095. if (!Property.isConstant(entity._position)) {
  98096. cluster._clusterDirty = true;
  98097. }
  98098. if (!defined(label)) {
  98099. label = cluster.getLabel(entity);
  98100. label.id = entity;
  98101. item.label = label;
  98102. }
  98103. label.show = true;
  98104. label.position = position;
  98105. label.text = text;
  98106. label.scale = Property.getValueOrDefault(labelGraphics._scale, time, defaultScale);
  98107. label.font = Property.getValueOrDefault(labelGraphics._font, time, defaultFont);
  98108. label.style = Property.getValueOrDefault(labelGraphics._style, time, defaultStyle);
  98109. label.fillColor = Property.getValueOrDefault(labelGraphics._fillColor, time, defaultFillColor, fillColor);
  98110. label.outlineColor = Property.getValueOrDefault(labelGraphics._outlineColor, time, defaultOutlineColor, outlineColor);
  98111. label.outlineWidth = Property.getValueOrDefault(labelGraphics._outlineWidth, time, defaultOutlineWidth);
  98112. label.showBackground = Property.getValueOrDefault(labelGraphics._showBackground, time, defaultShowBackground);
  98113. label.backgroundColor = Property.getValueOrDefault(labelGraphics._backgroundColor, time, defaultBackgroundColor, backgroundColor);
  98114. label.backgroundPadding = Property.getValueOrDefault(labelGraphics._backgroundPadding, time, defaultBackgroundPadding, backgroundPadding);
  98115. label.pixelOffset = Property.getValueOrDefault(labelGraphics._pixelOffset, time, defaultPixelOffset, pixelOffset);
  98116. label.eyeOffset = Property.getValueOrDefault(labelGraphics._eyeOffset, time, defaultEyeOffset, eyeOffset);
  98117. label.heightReference = Property.getValueOrDefault(labelGraphics._heightReference, time, defaultHeightReference);
  98118. label.horizontalOrigin = Property.getValueOrDefault(labelGraphics._horizontalOrigin, time, defaultHorizontalOrigin);
  98119. label.verticalOrigin = Property.getValueOrDefault(labelGraphics._verticalOrigin, time, defaultVerticalOrigin);
  98120. label.translucencyByDistance = Property.getValueOrUndefined(labelGraphics._translucencyByDistance, time, translucencyByDistance);
  98121. label.pixelOffsetScaleByDistance = Property.getValueOrUndefined(labelGraphics._pixelOffsetScaleByDistance, time, pixelOffsetScaleByDistance);
  98122. label.distanceDisplayCondition = Property.getValueOrUndefined(labelGraphics._distanceDisplayCondition, time, distanceDisplayCondition);
  98123. }
  98124. return true;
  98125. };
  98126. /**
  98127. * Computes a bounding sphere which encloses the visualization produced for the specified entity.
  98128. * The bounding sphere is in the fixed frame of the scene's globe.
  98129. *
  98130. * @param {Entity} entity The entity whose bounding sphere to compute.
  98131. * @param {BoundingSphere} result The bounding sphere onto which to store the result.
  98132. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere,
  98133. * BoundingSphereState.PENDING if the result is still being computed, or
  98134. * BoundingSphereState.FAILED if the entity has no visualization in the current scene.
  98135. * @private
  98136. */
  98137. LabelVisualizer.prototype.getBoundingSphere = function(entity, result) {
  98138. if (!defined(entity)) {
  98139. throw new DeveloperError('entity is required.');
  98140. }
  98141. if (!defined(result)) {
  98142. throw new DeveloperError('result is required.');
  98143. }
  98144. var item = this._items.get(entity.id);
  98145. if (!defined(item) || !defined(item.label)) {
  98146. return BoundingSphereState.FAILED;
  98147. }
  98148. var label = item.label;
  98149. result.center = Cartesian3.clone(defaultValue(label._clampedPosition, label.position), result.center);
  98150. result.radius = 0;
  98151. return BoundingSphereState.DONE;
  98152. };
  98153. /**
  98154. * Returns true if this object was destroyed; otherwise, false.
  98155. *
  98156. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  98157. */
  98158. LabelVisualizer.prototype.isDestroyed = function() {
  98159. return false;
  98160. };
  98161. /**
  98162. * Removes and destroys all primitives created by this instance.
  98163. */
  98164. LabelVisualizer.prototype.destroy = function() {
  98165. this._entityCollection.collectionChanged.removeEventListener(LabelVisualizer.prototype._onCollectionChanged, this);
  98166. var entities = this._entityCollection.values;
  98167. for (var i = 0; i < entities.length; i++) {
  98168. this._cluster.removeLabel(entities[i]);
  98169. }
  98170. return destroyObject(this);
  98171. };
  98172. LabelVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed, changed) {
  98173. var i;
  98174. var entity;
  98175. var items = this._items;
  98176. var cluster = this._cluster;
  98177. for (i = added.length - 1; i > -1; i--) {
  98178. entity = added[i];
  98179. if (defined(entity._label) && defined(entity._position)) {
  98180. items.set(entity.id, new EntityData(entity));
  98181. }
  98182. }
  98183. for (i = changed.length - 1; i > -1; i--) {
  98184. entity = changed[i];
  98185. if (defined(entity._label) && defined(entity._position)) {
  98186. if (!items.contains(entity.id)) {
  98187. items.set(entity.id, new EntityData(entity));
  98188. }
  98189. } else {
  98190. returnPrimitive(items.get(entity.id), entity, cluster);
  98191. items.remove(entity.id);
  98192. }
  98193. }
  98194. for (i = removed.length - 1; i > -1; i--) {
  98195. entity = removed[i];
  98196. returnPrimitive(items.get(entity.id), entity, cluster);
  98197. items.remove(entity.id);
  98198. }
  98199. };
  98200. function returnPrimitive(item, entity, cluster) {
  98201. if (defined(item)) {
  98202. item.label = undefined;
  98203. cluster.removeLabel(entity);
  98204. }
  98205. }
  98206. return LabelVisualizer;
  98207. });
  98208. /*global define*/
  98209. define('ThirdParty/gltfDefaults',[
  98210. '../Core/Cartesian3',
  98211. '../Core/defaultValue',
  98212. '../Core/defined',
  98213. '../Core/Quaternion',
  98214. '../Core/WebGLConstants'
  98215. ], function(
  98216. Cartesian3,
  98217. defaultValue,
  98218. defined,
  98219. Quaternion,
  98220. WebGLConstants) {
  98221. "use strict";
  98222. function accessorDefaults(gltf) {
  98223. if (!defined(gltf.accessors)) {
  98224. gltf.accessors = {};
  98225. }
  98226. var accessors = gltf.accessors;
  98227. for (var name in accessors) {
  98228. if (accessors.hasOwnProperty(name)) {
  98229. var accessor = accessors[name];
  98230. accessor.byteStride = defaultValue(accessor.byteStride, 0);
  98231. }
  98232. }
  98233. }
  98234. function animationDefaults(gltf) {
  98235. if (!defined(gltf.animations)) {
  98236. gltf.animations = {};
  98237. }
  98238. var animations = gltf.animations;
  98239. for (var name in animations) {
  98240. if (animations.hasOwnProperty(name)) {
  98241. var animation = animations[name];
  98242. if (!defined(animation.channels)) {
  98243. animation.channels = [];
  98244. }
  98245. if (!defined(animation.parameters)) {
  98246. animation.parameters = {};
  98247. }
  98248. if (!defined(animation.samplers)) {
  98249. animation.samplers = {};
  98250. }
  98251. var samplers = animations.samplers;
  98252. for (var samplerName in samplers) {
  98253. if (samplers.hasOwnProperty(samplerName)) {
  98254. var sampler = samplers[samplerName];
  98255. sampler.interpolation = defaultValue(sampler.interpolation, 'LINEAR');
  98256. }
  98257. }
  98258. }
  98259. }
  98260. }
  98261. function assetDefaults(gltf) {
  98262. if (!defined(gltf.asset)) {
  98263. gltf.asset = {};
  98264. }
  98265. var asset = gltf.asset;
  98266. // Backwards compatibility for glTF 0.8. profile was a string.
  98267. if (!defined(asset.profile) || (typeof asset.profile === 'string')) {
  98268. asset.profile = {};
  98269. }
  98270. var profile = asset.profile;
  98271. asset.premultipliedAlpha = defaultValue(asset.premultipliedAlpha, false);
  98272. profile.api = defaultValue(profile.api, 'WebGL');
  98273. profile.version = defaultValue(profile.version, '1.0.2');
  98274. if (defined(gltf.version)) {
  98275. asset.version = defaultValue(asset.version, gltf.version);
  98276. delete gltf.version;
  98277. }
  98278. if (typeof asset.version === 'number') {
  98279. asset.version = asset.version.toFixed(1).toString();
  98280. }
  98281. }
  98282. function bufferDefaults(gltf) {
  98283. if (!defined(gltf.buffers)) {
  98284. gltf.buffers = {};
  98285. }
  98286. var buffers = gltf.buffers;
  98287. for (var name in buffers) {
  98288. if (buffers.hasOwnProperty(name)) {
  98289. var buffer = buffers[name];
  98290. buffer.type = defaultValue(buffer.type, 'arraybuffer');
  98291. }
  98292. }
  98293. }
  98294. function bufferViewDefaults(gltf) {
  98295. if (!defined(gltf.bufferViews)) {
  98296. gltf.bufferViews = {};
  98297. }
  98298. }
  98299. function cameraDefaults(gltf) {
  98300. if (!defined(gltf.cameras)) {
  98301. gltf.cameras = {};
  98302. }
  98303. }
  98304. function imageDefaults(gltf) {
  98305. if (!defined(gltf.images)) {
  98306. gltf.images = {};
  98307. }
  98308. }
  98309. function lightDefaults(gltf) {
  98310. if (!defined(gltf.extensions)) {
  98311. gltf.extensions = {};
  98312. }
  98313. var extensions = gltf.extensions;
  98314. if (!defined(extensions.KHR_materials_common)) {
  98315. extensions.KHR_materials_common = {};
  98316. }
  98317. var khrMaterialsCommon = extensions.KHR_materials_common;
  98318. if (defined(gltf.lights)) {
  98319. khrMaterialsCommon.lights = gltf.lights;
  98320. delete gltf.lights;
  98321. }
  98322. else if (!defined(khrMaterialsCommon.lights)) {
  98323. khrMaterialsCommon.lights = {};
  98324. }
  98325. var lights = khrMaterialsCommon.lights;
  98326. for (var name in lights) {
  98327. if (lights.hasOwnProperty(name)) {
  98328. var light = lights[name];
  98329. if (light.type === 'ambient') {
  98330. if (!defined(light.ambient)) {
  98331. light.ambient = {};
  98332. }
  98333. var ambientLight = light.ambient;
  98334. if (!defined(ambientLight.color)) {
  98335. ambientLight.color = [1.0, 1.0, 1.0];
  98336. }
  98337. } else if (light.type === 'directional') {
  98338. if (!defined(light.directional)) {
  98339. light.directional = {};
  98340. }
  98341. var directionalLight = light.directional;
  98342. if (!defined(directionalLight.color)) {
  98343. directionalLight.color = [1.0, 1.0, 1.0];
  98344. }
  98345. } else if (light.type === 'point') {
  98346. if (!defined(light.point)) {
  98347. light.point = {};
  98348. }
  98349. var pointLight = light.point;
  98350. if (!defined(pointLight.color)) {
  98351. pointLight.color = [1.0, 1.0, 1.0];
  98352. }
  98353. pointLight.constantAttenuation = defaultValue(pointLight.constantAttenuation, 1.0);
  98354. pointLight.linearAttenuation = defaultValue(pointLight.linearAttenuation, 0.0);
  98355. pointLight.quadraticAttenuation = defaultValue(pointLight.quadraticAttenuation, 0.0);
  98356. } else if (light.type === 'spot') {
  98357. if (!defined(light.spot)) {
  98358. light.spot = {};
  98359. }
  98360. var spotLight = light.spot;
  98361. if (!defined(spotLight.color)) {
  98362. spotLight.color = [1.0, 1.0, 1.0];
  98363. }
  98364. spotLight.constantAttenuation = defaultValue(spotLight.constantAttenuation, 1.0);
  98365. spotLight.fallOffAngle = defaultValue(spotLight.fallOffAngle, 3.14159265);
  98366. spotLight.fallOffExponent = defaultValue(spotLight.fallOffExponent, 0.0);
  98367. spotLight.linearAttenuation = defaultValue(spotLight.linearAttenuation, 0.0);
  98368. spotLight.quadraticAttenuation = defaultValue(spotLight.quadraticAttenuation, 0.0);
  98369. }
  98370. }
  98371. }
  98372. }
  98373. function materialDefaults(gltf) {
  98374. if (!defined(gltf.materials)) {
  98375. gltf.materials = {};
  98376. }
  98377. var materials = gltf.materials;
  98378. for (var name in materials) {
  98379. if (materials.hasOwnProperty(name)) {
  98380. var material = materials[name];
  98381. var instanceTechnique = material.instanceTechnique;
  98382. if (defined(instanceTechnique)) {
  98383. material.technique = instanceTechnique.technique;
  98384. material.values = instanceTechnique.values;
  98385. delete material.instanceTechnique;
  98386. }
  98387. if (!defined(material.extensions)) {
  98388. if (!defined(material.technique)) {
  98389. delete material.values;
  98390. material.extensions = {
  98391. KHR_materials_common : {
  98392. technique : 'CONSTANT',
  98393. transparent: false,
  98394. values : {
  98395. emission : {
  98396. type: WebGLConstants.FLOAT_VEC4,
  98397. value: [
  98398. 0.5,
  98399. 0.5,
  98400. 0.5,
  98401. 1
  98402. ]
  98403. }
  98404. }
  98405. }
  98406. };
  98407. if (!defined(gltf.extensionsUsed)) {
  98408. gltf.extensionsUsed = [];
  98409. }
  98410. var extensionsUsed = gltf.extensionsUsed;
  98411. if (extensionsUsed.indexOf('KHR_materials_common') === -1) {
  98412. extensionsUsed.push('KHR_materials_common');
  98413. }
  98414. }
  98415. else if (!defined(material.values)) {
  98416. material.values = {};
  98417. }
  98418. }
  98419. }
  98420. }
  98421. }
  98422. function meshDefaults(gltf) {
  98423. if (!defined(gltf.meshes)) {
  98424. gltf.meshes = {};
  98425. }
  98426. var meshes = gltf.meshes;
  98427. for (var name in meshes) {
  98428. if (meshes.hasOwnProperty(name)) {
  98429. var mesh = meshes[name];
  98430. if (!defined(mesh.primitives)) {
  98431. mesh.primitives = [];
  98432. }
  98433. var primitives = mesh.primitives.length;
  98434. var length = primitives.length;
  98435. for (var i = 0; i < length; ++i) {
  98436. var primitive = primitives[i];
  98437. if (!defined(primitive.attributes)) {
  98438. primitive.attributes = {};
  98439. }
  98440. // Backwards compatibility for glTF 0.8. primitive was renamed to mode.
  98441. var defaultMode = defaultValue(primitive.primitive, WebGLConstants.TRIANGLES);
  98442. primitive.mode = defaultValue(primitive.mode, defaultMode);
  98443. }
  98444. }
  98445. }
  98446. }
  98447. function nodeDefaults(gltf) {
  98448. if (!defined(gltf.nodes)) {
  98449. gltf.nodes = {};
  98450. }
  98451. var nodes = gltf.nodes;
  98452. var hasAxisAngle = (parseFloat(gltf.asset.version) < 1.0);
  98453. var axis = new Cartesian3();
  98454. var quat = new Quaternion();
  98455. for (var name in nodes) {
  98456. if (nodes.hasOwnProperty(name)) {
  98457. var node = nodes[name];
  98458. if (!defined(node.children)) {
  98459. node.children = [];
  98460. }
  98461. if (hasAxisAngle && defined(node.rotation)) {
  98462. var rotation = node.rotation;
  98463. Cartesian3.fromArray(rotation, 0, axis);
  98464. Quaternion.fromAxisAngle(axis, rotation[3], quat);
  98465. node.rotation = [quat.x, quat.y, quat.z, quat.w];
  98466. }
  98467. if (!defined(node.matrix)) {
  98468. // Add default identity matrix if there is no matrix property and no TRS properties
  98469. if (!defined(node.translation) && !defined(node.rotation) && !defined(node.scale)) {
  98470. node.matrix = [
  98471. 1.0, 0.0, 0.0, 0.0,
  98472. 0.0, 1.0, 0.0, 0.0,
  98473. 0.0, 0.0, 1.0, 0.0,
  98474. 0.0, 0.0, 0.0, 1.0
  98475. ];
  98476. } else {
  98477. if (!defined(node.translation)) {
  98478. node.translation = [0.0, 0.0, 0.0];
  98479. }
  98480. if (!defined(node.rotation)) {
  98481. node.rotation = [0.0, 0.0, 0.0, 1.0];
  98482. }
  98483. if (!defined(node.scale)) {
  98484. node.scale = [1.0, 1.0, 1.0];
  98485. }
  98486. }
  98487. }
  98488. var instanceSkin = node.instanceSkin;
  98489. if (defined(instanceSkin)) {
  98490. node.skeletons = instanceSkin.skeletons;
  98491. node.skin = instanceSkin.skin;
  98492. node.meshes = instanceSkin.meshes;
  98493. delete node.instanceSkin;
  98494. }
  98495. }
  98496. }
  98497. }
  98498. function programDefaults(gltf) {
  98499. if (!defined(gltf.programs)) {
  98500. gltf.programs = {};
  98501. }
  98502. var programs = gltf.programs;
  98503. for (var name in programs) {
  98504. if (programs.hasOwnProperty(name)) {
  98505. var program = programs[name];
  98506. if (!defined(program.attributes)) {
  98507. program.attributes = [];
  98508. }
  98509. }
  98510. }
  98511. }
  98512. function samplerDefaults(gltf) {
  98513. if (!defined(gltf.samplers)) {
  98514. gltf.samplers = {};
  98515. }
  98516. var samplers = gltf.samplers;
  98517. for (var name in samplers) {
  98518. if (samplers.hasOwnProperty(name)) {
  98519. var sampler = samplers[name];
  98520. sampler.magFilter = defaultValue(sampler.magFilter, WebGLConstants.LINEAR);
  98521. sampler.minFilter = defaultValue(sampler.minFilter, WebGLConstants.NEAREST_MIPMAP_LINEAR);
  98522. sampler.wrapS = defaultValue(sampler.wrapS, WebGLConstants.REPEAT);
  98523. sampler.wrapT = defaultValue(sampler.wrapT, WebGLConstants.REPEAT);
  98524. }
  98525. }
  98526. }
  98527. function sceneDefaults(gltf) {
  98528. if (!defined(gltf.scenes)) {
  98529. gltf.scenes = {};
  98530. }
  98531. var scenes = gltf.scenes;
  98532. for (var name in scenes) {
  98533. if (scenes.hasOwnProperty(name)) {
  98534. var scene = scenes[name];
  98535. if (!defined(scene.node)) {
  98536. scene.node = [];
  98537. }
  98538. }
  98539. }
  98540. }
  98541. function shaderDefaults(gltf) {
  98542. if (!defined(gltf.shaders)) {
  98543. gltf.shaders = {};
  98544. }
  98545. }
  98546. function skinDefaults(gltf) {
  98547. if (!defined(gltf.skins)) {
  98548. gltf.skins = {};
  98549. }
  98550. var skins = gltf.skins;
  98551. for (var name in skins) {
  98552. if (skins.hasOwnProperty(name)) {
  98553. var skin = skins[name];
  98554. if (!defined(skin.bindShapeMatrix)) {
  98555. skin.bindShapeMatrix = [
  98556. 1.0, 0.0, 0.0, 0.0,
  98557. 0.0, 1.0, 0.0, 0.0,
  98558. 0.0, 0.0, 1.0, 0.0,
  98559. 0.0, 0.0, 0.0, 1.0
  98560. ];
  98561. }
  98562. }
  98563. }
  98564. }
  98565. function statesDefaults(states) {
  98566. if (!defined(states.enable)) {
  98567. states.enable = [];
  98568. }
  98569. if (!defined(states.disable)) {
  98570. states.disable = [];
  98571. }
  98572. }
  98573. function techniqueDefaults(gltf) {
  98574. if (!defined(gltf.techniques)) {
  98575. gltf.techniques = {};
  98576. }
  98577. var techniques = gltf.techniques;
  98578. for (var name in techniques) {
  98579. if (techniques.hasOwnProperty(name)) {
  98580. var technique = techniques[name];
  98581. if (!defined(technique.parameters)) {
  98582. technique.parameters = {};
  98583. }
  98584. var parameters = technique.parameters;
  98585. for (var parameterName in parameters) {
  98586. var parameter = parameters[parameterName];
  98587. parameter.node = defaultValue(parameter.node, parameter.source);
  98588. parameter.source = undefined;
  98589. }
  98590. var passes = technique.passes;
  98591. if (defined(passes)) {
  98592. var passName = defaultValue(technique.pass, 'defaultPass');
  98593. if (passes.hasOwnProperty(passName)) {
  98594. var pass = passes[passName];
  98595. var instanceProgram = pass.instanceProgram;
  98596. technique.attributes = defaultValue(technique.attributes, instanceProgram.attributes);
  98597. technique.program = defaultValue(technique.program, instanceProgram.program);
  98598. technique.uniforms = defaultValue(technique.uniforms, instanceProgram.uniforms);
  98599. technique.states = defaultValue(technique.states, pass.states);
  98600. }
  98601. technique.passes = undefined;
  98602. technique.pass = undefined;
  98603. }
  98604. if (!defined(technique.attributes)) {
  98605. technique.attributes = {};
  98606. }
  98607. if (!defined(technique.uniforms)) {
  98608. technique.uniforms = {};
  98609. }
  98610. if (!defined(technique.states)) {
  98611. technique.states = {};
  98612. }
  98613. statesDefaults(technique.states);
  98614. }
  98615. }
  98616. }
  98617. function textureDefaults(gltf) {
  98618. if (!defined(gltf.textures)) {
  98619. gltf.textures = {};
  98620. }
  98621. var textures = gltf.textures;
  98622. for (var name in textures) {
  98623. if (textures.hasOwnProperty(name)) {
  98624. var texture = textures[name];
  98625. texture.format = defaultValue(texture.format, WebGLConstants.RGBA);
  98626. texture.internalFormat = defaultValue(texture.internalFormat, texture.format);
  98627. texture.target = defaultValue(texture.target, WebGLConstants.TEXTURE_2D);
  98628. texture.type = defaultValue(texture.type, WebGLConstants.UNSIGNED_BYTE);
  98629. }
  98630. }
  98631. }
  98632. /**
  98633. * Modifies gltf in place.
  98634. *
  98635. * @private
  98636. */
  98637. var gltfDefaults = function(gltf) {
  98638. if (!defined(gltf)) {
  98639. return undefined;
  98640. }
  98641. if (defined(gltf.allExtensions)) {
  98642. gltf.extensionsUsed = gltf.allExtensions;
  98643. gltf.allExtensions = undefined;
  98644. }
  98645. gltf.extensionsUsed = defaultValue(gltf.extensionsUsed, []);
  98646. accessorDefaults(gltf);
  98647. animationDefaults(gltf);
  98648. assetDefaults(gltf);
  98649. bufferDefaults(gltf);
  98650. bufferViewDefaults(gltf);
  98651. cameraDefaults(gltf);
  98652. imageDefaults(gltf);
  98653. lightDefaults(gltf);
  98654. materialDefaults(gltf);
  98655. meshDefaults(gltf);
  98656. nodeDefaults(gltf);
  98657. programDefaults(gltf);
  98658. samplerDefaults(gltf);
  98659. sceneDefaults(gltf);
  98660. shaderDefaults(gltf);
  98661. skinDefaults(gltf);
  98662. techniqueDefaults(gltf);
  98663. textureDefaults(gltf);
  98664. return gltf;
  98665. };
  98666. return gltfDefaults;
  98667. });
  98668. /*global define*/
  98669. define('Scene/getAttributeOrUniformBySemantic',[], function() {
  98670. 'use strict';
  98671. /**
  98672. * Return the uniform or attribute that has the given semantic.
  98673. *
  98674. * @private
  98675. */
  98676. function getAttributeOrUniformBySemantic(gltf, semantic) {
  98677. var techniques = gltf.techniques;
  98678. for (var techniqueName in techniques) {
  98679. if (techniques.hasOwnProperty(techniqueName)) {
  98680. var technique = techniques[techniqueName];
  98681. var parameters = technique.parameters;
  98682. var attributes = technique.attributes;
  98683. var uniforms = technique.uniforms;
  98684. for (var attributeName in attributes) {
  98685. if (attributes.hasOwnProperty(attributeName)) {
  98686. if (parameters[attributes[attributeName]].semantic === semantic) {
  98687. return attributeName;
  98688. }
  98689. }
  98690. }
  98691. for (var uniformName in uniforms) {
  98692. if (uniforms.hasOwnProperty(uniformName)) {
  98693. if (parameters[uniforms[uniformName]].semantic === semantic) {
  98694. return uniformName;
  98695. }
  98696. }
  98697. }
  98698. }
  98699. }
  98700. return undefined;
  98701. }
  98702. return getAttributeOrUniformBySemantic;
  98703. });
  98704. /*global define*/
  98705. define('Scene/getBinaryAccessor',[
  98706. '../Core/Cartesian2',
  98707. '../Core/Cartesian3',
  98708. '../Core/Cartesian4',
  98709. '../Core/ComponentDatatype',
  98710. '../Core/Matrix2',
  98711. '../Core/Matrix3',
  98712. '../Core/Matrix4'
  98713. ], function(
  98714. Cartesian2,
  98715. Cartesian3,
  98716. Cartesian4,
  98717. ComponentDatatype,
  98718. Matrix2,
  98719. Matrix3,
  98720. Matrix4) {
  98721. 'use strict';
  98722. var ComponentsPerAttribute = {
  98723. SCALAR : 1,
  98724. VEC2 : 2,
  98725. VEC3 : 3,
  98726. VEC4 : 4,
  98727. MAT2 : 4,
  98728. MAT3 : 9,
  98729. MAT4 : 16
  98730. };
  98731. var ClassPerType = {
  98732. SCALAR : undefined,
  98733. VEC2 : Cartesian2,
  98734. VEC3 : Cartesian3,
  98735. VEC4 : Cartesian4,
  98736. MAT2 : Matrix2,
  98737. MAT3 : Matrix3,
  98738. MAT4 : Matrix4
  98739. };
  98740. /**
  98741. * @private
  98742. */
  98743. function getBinaryAccessor(accessor) {
  98744. var componentType = accessor.componentType;
  98745. var componentDatatype;
  98746. if (typeof componentType === 'string') {
  98747. componentDatatype = ComponentDatatype.fromName(componentType);
  98748. } else {
  98749. componentDatatype = componentType;
  98750. }
  98751. var componentsPerAttribute = ComponentsPerAttribute[accessor.type];
  98752. var classType = ClassPerType[accessor.type];
  98753. return {
  98754. componentsPerAttribute : componentsPerAttribute,
  98755. classType : classType,
  98756. createArrayBufferView : function(buffer, byteOffset, length) {
  98757. return ComponentDatatype.createArrayBufferView(componentDatatype, buffer, byteOffset, componentsPerAttribute * length);
  98758. }
  98759. };
  98760. }
  98761. return getBinaryAccessor;
  98762. });
  98763. /*global define*/
  98764. define('Scene/ModelAnimationCache',[
  98765. '../Core/Cartesian3',
  98766. '../Core/defaultValue',
  98767. '../Core/defined',
  98768. '../Core/LinearSpline',
  98769. '../Core/Matrix4',
  98770. '../Core/Quaternion',
  98771. '../Core/QuaternionSpline',
  98772. '../Core/WebGLConstants',
  98773. './getBinaryAccessor'
  98774. ], function(
  98775. Cartesian3,
  98776. defaultValue,
  98777. defined,
  98778. LinearSpline,
  98779. Matrix4,
  98780. Quaternion,
  98781. QuaternionSpline,
  98782. WebGLConstants,
  98783. getBinaryAccessor) {
  98784. 'use strict';
  98785. /**
  98786. * @private
  98787. */
  98788. function ModelAnimationCache() {
  98789. }
  98790. function getAccessorKey(model, accessor) {
  98791. var gltf = model.gltf;
  98792. var buffers = gltf.buffers;
  98793. var bufferViews = gltf.bufferViews;
  98794. var bufferView = bufferViews[accessor.bufferView];
  98795. var buffer = buffers[bufferView.buffer];
  98796. var byteOffset = bufferView.byteOffset + accessor.byteOffset;
  98797. var byteLength = accessor.count * getBinaryAccessor(accessor).componentsPerAttribute;
  98798. // buffer.path will be undefined when animations are embedded.
  98799. return model.cacheKey + '//' + defaultValue(buffer.path, '') + '/' + byteOffset + '/' + byteLength;
  98800. }
  98801. var cachedAnimationParameters = {
  98802. };
  98803. var axisScratch = new Cartesian3();
  98804. ModelAnimationCache.getAnimationParameterValues = function(model, accessor) {
  98805. var key = getAccessorKey(model, accessor);
  98806. var values = cachedAnimationParameters[key];
  98807. if (!defined(values)) {
  98808. // Cache miss
  98809. var loadResources = model._loadResources;
  98810. var gltf = model.gltf;
  98811. var hasAxisAngle = (parseFloat(gltf.asset.version) < 1.0);
  98812. var bufferViews = gltf.bufferViews;
  98813. var bufferView = bufferViews[accessor.bufferView];
  98814. var componentType = accessor.componentType;
  98815. var type = accessor.type;
  98816. var count = accessor.count;
  98817. // Convert typed array to Cesium types
  98818. var buffer = loadResources.getBuffer(bufferView);
  98819. var typedArray = getBinaryAccessor(accessor).createArrayBufferView(buffer.buffer, buffer.byteOffset + accessor.byteOffset, count);
  98820. var i;
  98821. if ((componentType === WebGLConstants.FLOAT) && (type === 'SCALAR')) {
  98822. values = typedArray;
  98823. }
  98824. else if ((componentType === WebGLConstants.FLOAT) && (type === 'VEC3')) {
  98825. values = new Array(count);
  98826. for (i = 0; i < count; ++i) {
  98827. values[i] = Cartesian3.fromArray(typedArray, 3 * i);
  98828. }
  98829. } else if ((componentType === WebGLConstants.FLOAT) && (type === 'VEC4')) {
  98830. values = new Array(count);
  98831. for (i = 0; i < count; ++i) {
  98832. var byteOffset = 4 * i;
  98833. if (hasAxisAngle) {
  98834. values[i] = Quaternion.fromAxisAngle(Cartesian3.fromArray(typedArray, byteOffset, axisScratch), typedArray[byteOffset + 3]);
  98835. }
  98836. else {
  98837. values[i] = Quaternion.unpack(typedArray, byteOffset);
  98838. }
  98839. }
  98840. }
  98841. // GLTF_SPEC: Support more parameter types when glTF supports targeting materials. https://github.com/KhronosGroup/glTF/issues/142
  98842. if (defined(model.cacheKey)) {
  98843. // Only cache when we can create a unique id
  98844. cachedAnimationParameters[key] = values;
  98845. }
  98846. }
  98847. return values;
  98848. };
  98849. var cachedAnimationSplines = {
  98850. };
  98851. function getAnimationSplineKey(model, animationName, samplerName) {
  98852. return model.cacheKey + '//' + animationName + '/' + samplerName;
  98853. }
  98854. // GLTF_SPEC: https://github.com/KhronosGroup/glTF/issues/185
  98855. function ConstantSpline(value) {
  98856. this._value = value;
  98857. }
  98858. ConstantSpline.prototype.evaluate = function(time, result) {
  98859. return this._value;
  98860. };
  98861. // END GLTF_SPEC
  98862. ModelAnimationCache.getAnimationSpline = function(model, animationName, animation, samplerName, sampler, parameterValues) {
  98863. var key = getAnimationSplineKey(model, animationName, samplerName);
  98864. var spline = cachedAnimationSplines[key];
  98865. if (!defined(spline)) {
  98866. var times = parameterValues[sampler.input];
  98867. var accessor = model.gltf.accessors[animation.parameters[sampler.output]];
  98868. var controlPoints = parameterValues[sampler.output];
  98869. // GLTF_SPEC: https://github.com/KhronosGroup/glTF/issues/185
  98870. if ((times.length === 1) && (controlPoints.length === 1)) {
  98871. spline = new ConstantSpline(controlPoints[0]);
  98872. } else {
  98873. // END GLTF_SPEC
  98874. var componentType = accessor.componentType;
  98875. var type = accessor.type;
  98876. if (sampler.interpolation === 'LINEAR') {
  98877. if ((componentType === WebGLConstants.FLOAT) && (type === 'VEC3')) {
  98878. spline = new LinearSpline({
  98879. times : times,
  98880. points : controlPoints
  98881. });
  98882. } else if ((componentType === WebGLConstants.FLOAT) && (type === 'VEC4')) {
  98883. spline = new QuaternionSpline({
  98884. times : times,
  98885. points : controlPoints
  98886. });
  98887. }
  98888. // GLTF_SPEC: Support more parameter types when glTF supports targeting materials. https://github.com/KhronosGroup/glTF/issues/142
  98889. }
  98890. // GLTF_SPEC: Support new interpolators. https://github.com/KhronosGroup/glTF/issues/156
  98891. }
  98892. if (defined(model.cacheKey)) {
  98893. // Only cache when we can create a unique id
  98894. cachedAnimationSplines[key] = spline;
  98895. }
  98896. }
  98897. return spline;
  98898. };
  98899. var cachedSkinInverseBindMatrices = {
  98900. };
  98901. ModelAnimationCache.getSkinInverseBindMatrices = function(model, accessor) {
  98902. var key = getAccessorKey(model, accessor);
  98903. var matrices = cachedSkinInverseBindMatrices[key];
  98904. if (!defined(matrices)) {
  98905. // Cache miss
  98906. var loadResources = model._loadResources;
  98907. var gltf = model.gltf;
  98908. var bufferViews = gltf.bufferViews;
  98909. var bufferView = bufferViews[accessor.bufferView];
  98910. var componentType = accessor.componentType;
  98911. var type = accessor.type;
  98912. var count = accessor.count;
  98913. var buffer = loadResources.getBuffer(bufferView);
  98914. var typedArray = getBinaryAccessor(accessor).createArrayBufferView(buffer.buffer, buffer.byteOffset + accessor.byteOffset, count);
  98915. matrices = new Array(count);
  98916. if ((componentType === WebGLConstants.FLOAT) && (type === 'MAT4')) {
  98917. for (var i = 0; i < count; ++i) {
  98918. matrices[i] = Matrix4.fromArray(typedArray, 16 * i);
  98919. }
  98920. }
  98921. cachedSkinInverseBindMatrices[key] = matrices;
  98922. }
  98923. return matrices;
  98924. };
  98925. return ModelAnimationCache;
  98926. });
  98927. /*global define*/
  98928. define('Scene/ModelAnimationLoop',[
  98929. '../Core/freezeObject'
  98930. ], function(
  98931. freezeObject) {
  98932. 'use strict';
  98933. /**
  98934. * Determines if and how a glTF animation is looped.
  98935. *
  98936. * @exports ModelAnimationLoop
  98937. *
  98938. * @see ModelAnimationCollection#add
  98939. */
  98940. var ModelAnimationLoop = {
  98941. /**
  98942. * Play the animation once; do not loop it.
  98943. *
  98944. * @type {Number}
  98945. * @constant
  98946. */
  98947. NONE : 0,
  98948. /**
  98949. * Loop the animation playing it from the start immediately after it stops.
  98950. *
  98951. * @type {Number}
  98952. * @constant
  98953. */
  98954. REPEAT : 1,
  98955. /**
  98956. * Loop the animation. First, playing it forward, then in reverse, then forward, and so on.
  98957. *
  98958. * @type {Number}
  98959. * @constant
  98960. */
  98961. MIRRORED_REPEAT : 2
  98962. };
  98963. return freezeObject(ModelAnimationLoop);
  98964. });
  98965. /*global define*/
  98966. define('Scene/ModelAnimationState',[
  98967. '../Core/freezeObject'
  98968. ], function(
  98969. freezeObject) {
  98970. 'use strict';
  98971. /**
  98972. * @private
  98973. */
  98974. return freezeObject({
  98975. STOPPED : 0,
  98976. ANIMATING : 1
  98977. });
  98978. });
  98979. /*global define*/
  98980. define('Scene/ModelAnimation',[
  98981. '../Core/defaultValue',
  98982. '../Core/defineProperties',
  98983. '../Core/Event',
  98984. '../Core/JulianDate',
  98985. './ModelAnimationLoop',
  98986. './ModelAnimationState'
  98987. ], function(
  98988. defaultValue,
  98989. defineProperties,
  98990. Event,
  98991. JulianDate,
  98992. ModelAnimationLoop,
  98993. ModelAnimationState) {
  98994. 'use strict';
  98995. /**
  98996. * An active glTF animation. A glTF asset can contain animations. An active animation
  98997. * is an animation that is currently playing or scheduled to be played because it was
  98998. * added to a model's {@link ModelAnimationCollection}. An active animation is an
  98999. * instance of an animation; for example, there can be multiple active animations
  99000. * for the same glTF animation, each with a different start time.
  99001. * <p>
  99002. * Create this by calling {@link ModelAnimationCollection#add}.
  99003. * </p>
  99004. *
  99005. * @alias ModelAnimation
  99006. * @internalConstructor
  99007. *
  99008. * @see ModelAnimationCollection#add
  99009. */
  99010. function ModelAnimation(options, model, runtimeAnimation) {
  99011. this._name = options.name;
  99012. this._startTime = JulianDate.clone(options.startTime);
  99013. this._delay = defaultValue(options.delay, 0.0); // in seconds
  99014. this._stopTime = options.stopTime;
  99015. /**
  99016. * When <code>true</code>, the animation is removed after it stops playing.
  99017. * This is slightly more efficient that not removing it, but if, for example,
  99018. * time is reversed, the animation is not played again.
  99019. *
  99020. * @type {Boolean}
  99021. * @default false
  99022. */
  99023. this.removeOnStop = defaultValue(options.removeOnStop, false);
  99024. this._speedup = defaultValue(options.speedup, 1.0);
  99025. this._reverse = defaultValue(options.reverse, false);
  99026. this._loop = defaultValue(options.loop, ModelAnimationLoop.NONE);
  99027. /**
  99028. * The event fired when this animation is started. This can be used, for
  99029. * example, to play a sound or start a particle system, when the animation starts.
  99030. * <p>
  99031. * This event is fired at the end of the frame after the scene is rendered.
  99032. * </p>
  99033. *
  99034. * @type {Event}
  99035. * @default new Event()
  99036. *
  99037. * @example
  99038. * animation.start.addEventListener(function(model, animation) {
  99039. * console.log('Animation started: ' + animation.name);
  99040. * });
  99041. */
  99042. this.start = new Event();
  99043. /**
  99044. * The event fired when on each frame when this animation is updated. The
  99045. * current time of the animation, relative to the glTF animation time span, is
  99046. * passed to the event, which allows, for example, starting new animations at a
  99047. * specific time relative to a playing animation.
  99048. * <p>
  99049. * This event is fired at the end of the frame after the scene is rendered.
  99050. * </p>
  99051. *
  99052. * @type {Event}
  99053. * @default new Event()
  99054. *
  99055. * @example
  99056. * animation.update.addEventListener(function(model, animation, time) {
  99057. * console.log('Animation updated: ' + animation.name + '. glTF animation time: ' + time);
  99058. * });
  99059. */
  99060. this.update = new Event();
  99061. /**
  99062. * The event fired when this animation is stopped. This can be used, for
  99063. * example, to play a sound or start a particle system, when the animation stops.
  99064. * <p>
  99065. * This event is fired at the end of the frame after the scene is rendered.
  99066. * </p>
  99067. *
  99068. * @type {Event}
  99069. * @default new Event()
  99070. *
  99071. * @example
  99072. * animation.stop.addEventListener(function(model, animation) {
  99073. * console.log('Animation stopped: ' + animation.name);
  99074. * });
  99075. */
  99076. this.stop = new Event();
  99077. this._state = ModelAnimationState.STOPPED;
  99078. this._runtimeAnimation = runtimeAnimation;
  99079. // Set during animation update
  99080. this._computedStartTime = undefined;
  99081. this._duration = undefined;
  99082. // To avoid allocations in ModelAnimationCollection.update
  99083. var that = this;
  99084. this._raiseStartEvent = function() {
  99085. that.start.raiseEvent(model, that);
  99086. };
  99087. this._updateEventTime = 0.0;
  99088. this._raiseUpdateEvent = function() {
  99089. that.update.raiseEvent(model, that, that._updateEventTime);
  99090. };
  99091. this._raiseStopEvent = function() {
  99092. that.stop.raiseEvent(model, that);
  99093. };
  99094. }
  99095. defineProperties(ModelAnimation.prototype, {
  99096. /**
  99097. * The glTF animation name that identifies this animation.
  99098. *
  99099. * @memberof ModelAnimation.prototype
  99100. *
  99101. * @type {String}
  99102. * @readonly
  99103. */
  99104. name : {
  99105. get : function() {
  99106. return this._name;
  99107. }
  99108. },
  99109. /**
  99110. * The scene time to start playing this animation. When this is <code>undefined</code>,
  99111. * the animation starts at the next frame.
  99112. *
  99113. * @memberof ModelAnimation.prototype
  99114. *
  99115. * @type {JulianDate}
  99116. * @readonly
  99117. *
  99118. * @default undefined
  99119. */
  99120. startTime : {
  99121. get : function() {
  99122. return this._startTime;
  99123. }
  99124. },
  99125. /**
  99126. * The delay, in seconds, from {@link ModelAnimation#startTime} to start playing.
  99127. *
  99128. * @memberof ModelAnimation.prototype
  99129. *
  99130. * @type {Number}
  99131. * @readonly
  99132. *
  99133. * @default undefined
  99134. */
  99135. delay : {
  99136. get : function() {
  99137. return this._delay;
  99138. }
  99139. },
  99140. /**
  99141. * The scene time to stop playing this animation. When this is <code>undefined</code>,
  99142. * the animation is played for its full duration and perhaps repeated depending on
  99143. * {@link ModelAnimation#loop}.
  99144. *
  99145. * @memberof ModelAnimation.prototype
  99146. *
  99147. * @type {JulianDate}
  99148. * @readonly
  99149. *
  99150. * @default undefined
  99151. */
  99152. stopTime : {
  99153. get : function() {
  99154. return this._stopTime;
  99155. }
  99156. },
  99157. /**
  99158. * Values greater than <code>1.0</code> increase the speed that the animation is played relative
  99159. * to the scene clock speed; values less than <code>1.0</code> decrease the speed. A value of
  99160. * <code>1.0</code> plays the animation at the speed in the glTF animation mapped to the scene
  99161. * clock speed. For example, if the scene is played at 2x real-time, a two-second glTF animation
  99162. * will play in one second even if <code>speedup</code> is <code>1.0</code>.
  99163. *
  99164. * @memberof ModelAnimation.prototype
  99165. *
  99166. * @type {Number}
  99167. * @readonly
  99168. *
  99169. * @default 1.0
  99170. */
  99171. speedup : {
  99172. get : function() {
  99173. return this._speedup;
  99174. }
  99175. },
  99176. /**
  99177. * When <code>true</code>, the animation is played in reverse.
  99178. *
  99179. * @memberof ModelAnimation.prototype
  99180. *
  99181. * @type {Boolean}
  99182. * @readonly
  99183. *
  99184. * @default false
  99185. */
  99186. reverse : {
  99187. get : function() {
  99188. return this._reverse;
  99189. }
  99190. },
  99191. /**
  99192. * Determines if and how the animation is looped.
  99193. *
  99194. * @memberof ModelAnimation.prototype
  99195. *
  99196. * @type {ModelAnimationLoop}
  99197. * @readonly
  99198. *
  99199. * @default {@link ModelAnimationLoop.NONE}
  99200. */
  99201. loop : {
  99202. get : function() {
  99203. return this._loop;
  99204. }
  99205. }
  99206. });
  99207. return ModelAnimation;
  99208. });
  99209. /*global define*/
  99210. define('Scene/ModelAnimationCollection',[
  99211. '../Core/clone',
  99212. '../Core/defaultValue',
  99213. '../Core/defined',
  99214. '../Core/defineProperties',
  99215. '../Core/DeveloperError',
  99216. '../Core/Event',
  99217. '../Core/JulianDate',
  99218. '../Core/Math',
  99219. './ModelAnimation',
  99220. './ModelAnimationLoop',
  99221. './ModelAnimationState'
  99222. ], function(
  99223. clone,
  99224. defaultValue,
  99225. defined,
  99226. defineProperties,
  99227. DeveloperError,
  99228. Event,
  99229. JulianDate,
  99230. CesiumMath,
  99231. ModelAnimation,
  99232. ModelAnimationLoop,
  99233. ModelAnimationState) {
  99234. 'use strict';
  99235. /**
  99236. * A collection of active model animations. Access this using {@link Model#activeAnimations}.
  99237. *
  99238. * @alias ModelAnimationCollection
  99239. * @internalConstructor
  99240. *
  99241. * @see Model#activeAnimations
  99242. */
  99243. function ModelAnimationCollection(model) {
  99244. /**
  99245. * The event fired when an animation is added to the collection. This can be used, for
  99246. * example, to keep a UI in sync.
  99247. *
  99248. * @type {Event}
  99249. * @default new Event()
  99250. *
  99251. * @example
  99252. * model.activeAnimations.animationAdded.addEventListener(function(model, animation) {
  99253. * console.log('Animation added: ' + animation.name);
  99254. * });
  99255. */
  99256. this.animationAdded = new Event();
  99257. /**
  99258. * The event fired when an animation is removed from the collection. This can be used, for
  99259. * example, to keep a UI in sync.
  99260. *
  99261. * @type {Event}
  99262. * @default new Event()
  99263. *
  99264. * @example
  99265. * model.activeAnimations.animationRemoved.addEventListener(function(model, animation) {
  99266. * console.log('Animation removed: ' + animation.name);
  99267. * });
  99268. */
  99269. this.animationRemoved = new Event();
  99270. this._model = model;
  99271. this._scheduledAnimations = [];
  99272. this._previousTime = undefined;
  99273. }
  99274. defineProperties(ModelAnimationCollection.prototype, {
  99275. /**
  99276. * The number of animations in the collection.
  99277. *
  99278. * @memberof ModelAnimationCollection.prototype
  99279. *
  99280. * @type {Number}
  99281. * @readonly
  99282. */
  99283. length : {
  99284. get : function() {
  99285. return this._scheduledAnimations.length;
  99286. }
  99287. }
  99288. });
  99289. /**
  99290. * Creates and adds an animation with the specified initial properties to the collection.
  99291. * <p>
  99292. * This raises the {@link ModelAnimationCollection#animationAdded} event so, for example, a UI can stay in sync.
  99293. * </p>
  99294. *
  99295. * @param {Object} options Object with the following properties:
  99296. * @param {String} options.name The glTF animation name that identifies the animation.
  99297. * @param {JulianDate} [options.startTime] The scene time to start playing the animation. When this is <code>undefined</code>, the animation starts at the next frame.
  99298. * @param {Number} [options.delay=0.0] The delay, in seconds, from <code>startTime</code> to start playing.
  99299. * @param {JulianDate} [options.stopTime] The scene time to stop playing the animation. When this is <code>undefined</code>, the animation is played for its full duration.
  99300. * @param {Boolean} [options.removeOnStop=false] When <code>true</code>, the animation is removed after it stops playing.
  99301. * @param {Number} [options.speedup=1.0] Values greater than <code>1.0</code> increase the speed that the animation is played relative to the scene clock speed; values less than <code>1.0</code> decrease the speed.
  99302. * @param {Boolean} [options.reverse=false] When <code>true</code>, the animation is played in reverse.
  99303. * @param {ModelAnimationLoop} [options.loop=ModelAnimationLoop.NONE] Determines if and how the animation is looped.
  99304. * @returns {ModelAnimation} The animation that was added to the collection.
  99305. *
  99306. * @exception {DeveloperError} Animations are not loaded. Wait for the {@link Model#readyPromise} to resolve.
  99307. * @exception {DeveloperError} options.name must be a valid animation name.
  99308. * @exception {DeveloperError} options.speedup must be greater than zero.
  99309. *
  99310. * @example
  99311. * // Example 1. Add an animation
  99312. * model.activeAnimations.add({
  99313. * name : 'animation name'
  99314. * });
  99315. *
  99316. * @example
  99317. * // Example 2. Add an animation and provide all properties and events
  99318. * var startTime = Cesium.JulianDate.now();
  99319. *
  99320. * var animation = model.activeAnimations.add({
  99321. * name : 'another animation name',
  99322. * startTime : startTime,
  99323. * delay : 0.0, // Play at startTime (default)
  99324. * stopTime : Cesium.JulianDate.addSeconds(startTime, 4.0, new Cesium.JulianDate()),
  99325. * removeOnStop : false, // Do not remove when animation stops (default)
  99326. * speedup : 2.0, // Play at double speed
  99327. * reverse : true, // Play in reverse
  99328. * loop : Cesium.ModelAnimationLoop.REPEAT // Loop the animation
  99329. * });
  99330. *
  99331. * animation.start.addEventListener(function(model, animation) {
  99332. * console.log('Animation started: ' + animation.name);
  99333. * });
  99334. * animation.update.addEventListener(function(model, animation, time) {
  99335. * console.log('Animation updated: ' + animation.name + '. glTF animation time: ' + time);
  99336. * });
  99337. * animation.stop.addEventListener(function(model, animation) {
  99338. * console.log('Animation stopped: ' + animation.name);
  99339. * });
  99340. */
  99341. ModelAnimationCollection.prototype.add = function(options) {
  99342. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  99343. var model = this._model;
  99344. var animations = model._runtime.animations;
  99345. if (!defined(animations)) {
  99346. throw new DeveloperError('Animations are not loaded. Wait for Model.readyPromise to resolve.');
  99347. }
  99348. var animation = animations[options.name];
  99349. if (!defined(animation)) {
  99350. throw new DeveloperError('options.name must be a valid animation name.');
  99351. }
  99352. if (defined(options.speedup) && (options.speedup <= 0.0)) {
  99353. throw new DeveloperError('options.speedup must be greater than zero.');
  99354. }
  99355. var scheduledAnimation = new ModelAnimation(options, model, animation);
  99356. this._scheduledAnimations.push(scheduledAnimation);
  99357. this.animationAdded.raiseEvent(model, scheduledAnimation);
  99358. return scheduledAnimation;
  99359. };
  99360. /**
  99361. * Creates and adds an animation with the specified initial properties to the collection
  99362. * for each animation in the model.
  99363. * <p>
  99364. * This raises the {@link ModelAnimationCollection#animationAdded} event for each model so, for example, a UI can stay in sync.
  99365. * </p>
  99366. *
  99367. * @param {Object} [options] Object with the following properties:
  99368. * @param {JulianDate} [options.startTime] The scene time to start playing the animations. When this is <code>undefined</code>, the animations starts at the next frame.
  99369. * @param {Number} [options.delay=0.0] The delay, in seconds, from <code>startTime</code> to start playing.
  99370. * @param {JulianDate} [options.stopTime] The scene time to stop playing the animations. When this is <code>undefined</code>, the animations are played for its full duration.
  99371. * @param {Boolean} [options.removeOnStop=false] When <code>true</code>, the animations are removed after they stop playing.
  99372. * @param {Number} [options.speedup=1.0] Values greater than <code>1.0</code> increase the speed that the animations play relative to the scene clock speed; values less than <code>1.0</code> decrease the speed.
  99373. * @param {Boolean} [options.reverse=false] When <code>true</code>, the animations are played in reverse.
  99374. * @param {ModelAnimationLoop} [options.loop=ModelAnimationLoop.NONE] Determines if and how the animations are looped.
  99375. * @returns {ModelAnimation[]} An array of {@link ModelAnimation} objects, one for each animation added to the collection. If there are no glTF animations, the array is empty.
  99376. *
  99377. * @exception {DeveloperError} Animations are not loaded. Wait for the {@link Model#readyPromise} to resolve.
  99378. * @exception {DeveloperError} options.speedup must be greater than zero.
  99379. *
  99380. * @example
  99381. * model.activeAnimations.addAll({
  99382. * speedup : 0.5, // Play at half-speed
  99383. * loop : Cesium.ModelAnimationLoop.REPEAT // Loop the animations
  99384. * });
  99385. */
  99386. ModelAnimationCollection.prototype.addAll = function(options) {
  99387. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  99388. if (!defined(this._model._runtime.animations)) {
  99389. throw new DeveloperError('Animations are not loaded. Wait for Model.readyPromise to resolve.');
  99390. }
  99391. if (defined(options.speedup) && (options.speedup <= 0.0)) {
  99392. throw new DeveloperError('options.speedup must be greater than zero.');
  99393. }
  99394. options = clone(options);
  99395. var scheduledAnimations = [];
  99396. var animationIds = this._model._animationIds;
  99397. var length = animationIds.length;
  99398. for (var i = 0; i < length; ++i) {
  99399. options.name = animationIds[i];
  99400. scheduledAnimations.push(this.add(options));
  99401. }
  99402. return scheduledAnimations;
  99403. };
  99404. /**
  99405. * Removes an animation from the collection.
  99406. * <p>
  99407. * This raises the {@link ModelAnimationCollection#animationRemoved} event so, for example, a UI can stay in sync.
  99408. * </p>
  99409. * <p>
  99410. * An animation can also be implicitly removed from the collection by setting {@link ModelAnimation#removeOnStop} to
  99411. * <code>true</code>. The {@link ModelAnimationCollection#animationRemoved} event is still fired when the animation is removed.
  99412. * </p>
  99413. *
  99414. * @param {ModelAnimation} animation The animation to remove.
  99415. * @returns {Boolean} <code>true</code> if the animation was removed; <code>false</code> if the animation was not found in the collection.
  99416. *
  99417. * @example
  99418. * var a = model.activeAnimations.add({
  99419. * name : 'animation name'
  99420. * });
  99421. * model.activeAnimations.remove(a); // Returns true
  99422. */
  99423. ModelAnimationCollection.prototype.remove = function(animation) {
  99424. if (defined(animation)) {
  99425. var animations = this._scheduledAnimations;
  99426. var i = animations.indexOf(animation);
  99427. if (i !== -1) {
  99428. animations.splice(i, 1);
  99429. this.animationRemoved.raiseEvent(this._model, animation);
  99430. return true;
  99431. }
  99432. }
  99433. return false;
  99434. };
  99435. /**
  99436. * Removes all animations from the collection.
  99437. * <p>
  99438. * This raises the {@link ModelAnimationCollection#animationRemoved} event for each
  99439. * animation so, for example, a UI can stay in sync.
  99440. * </p>
  99441. */
  99442. ModelAnimationCollection.prototype.removeAll = function() {
  99443. var model = this._model;
  99444. var animations = this._scheduledAnimations;
  99445. var length = animations.length;
  99446. this._scheduledAnimations = [];
  99447. for (var i = 0; i < length; ++i) {
  99448. this.animationRemoved.raiseEvent(model, animations[i]);
  99449. }
  99450. };
  99451. /**
  99452. * Determines whether this collection contains a given animation.
  99453. *
  99454. * @param {ModelAnimation} animation The animation to check for.
  99455. * @returns {Boolean} <code>true</code> if this collection contains the animation, <code>false</code> otherwise.
  99456. */
  99457. ModelAnimationCollection.prototype.contains = function(animation) {
  99458. if (defined(animation)) {
  99459. return (this._scheduledAnimations.indexOf(animation) !== -1);
  99460. }
  99461. return false;
  99462. };
  99463. /**
  99464. * Returns the animation in the collection at the specified index. Indices are zero-based
  99465. * and increase as animations are added. Removing an animation shifts all animations after
  99466. * it to the left, changing their indices. This function is commonly used to iterate over
  99467. * all the animations in the collection.
  99468. *
  99469. * @param {Number} index The zero-based index of the animation.
  99470. * @returns {ModelAnimation} The animation at the specified index.
  99471. *
  99472. * @example
  99473. * // Output the names of all the animations in the collection.
  99474. * var animations = model.activeAnimations;
  99475. * var length = animations.length;
  99476. * for (var i = 0; i < length; ++i) {
  99477. * console.log(animations.get(i).name);
  99478. * }
  99479. */
  99480. ModelAnimationCollection.prototype.get = function(index) {
  99481. if (!defined(index)) {
  99482. throw new DeveloperError('index is required.');
  99483. }
  99484. return this._scheduledAnimations[index];
  99485. };
  99486. function animateChannels(runtimeAnimation, localAnimationTime) {
  99487. var channelEvaluators = runtimeAnimation.channelEvaluators;
  99488. var length = channelEvaluators.length;
  99489. for (var i = 0; i < length; ++i) {
  99490. channelEvaluators[i](localAnimationTime);
  99491. }
  99492. }
  99493. var animationsToRemove = [];
  99494. function createAnimationRemovedFunction(modelAnimationCollection, model, animation) {
  99495. return function() {
  99496. modelAnimationCollection.animationRemoved.raiseEvent(model, animation);
  99497. };
  99498. }
  99499. /**
  99500. * @private
  99501. */
  99502. ModelAnimationCollection.prototype.update = function(frameState) {
  99503. var scheduledAnimations = this._scheduledAnimations;
  99504. var length = scheduledAnimations.length;
  99505. if (length === 0) {
  99506. // No animations - quick return for performance
  99507. this._previousTime = undefined;
  99508. return false;
  99509. }
  99510. if (JulianDate.equals(frameState.time, this._previousTime)) {
  99511. // Animations are currently only time-dependent so do not animate when paused or picking
  99512. return false;
  99513. }
  99514. this._previousTime = JulianDate.clone(frameState.time, this._previousTime);
  99515. var animationOccured = false;
  99516. var sceneTime = frameState.time;
  99517. var model = this._model;
  99518. for (var i = 0; i < length; ++i) {
  99519. var scheduledAnimation = scheduledAnimations[i];
  99520. var runtimeAnimation = scheduledAnimation._runtimeAnimation;
  99521. if (!defined(scheduledAnimation._computedStartTime)) {
  99522. scheduledAnimation._computedStartTime = JulianDate.addSeconds(defaultValue(scheduledAnimation.startTime, sceneTime), scheduledAnimation.delay, new JulianDate());
  99523. }
  99524. if (!defined(scheduledAnimation._duration)) {
  99525. scheduledAnimation._duration = runtimeAnimation.stopTime * (1.0 / scheduledAnimation.speedup);
  99526. }
  99527. var startTime = scheduledAnimation._computedStartTime;
  99528. var duration = scheduledAnimation._duration;
  99529. var stopTime = scheduledAnimation.stopTime;
  99530. // [0.0, 1.0] normalized local animation time
  99531. var delta = (duration !== 0.0) ? (JulianDate.secondsDifference(sceneTime, startTime) / duration) : 0.0;
  99532. var pastStartTime = (delta >= 0.0);
  99533. // Play animation if
  99534. // * we are after the start time or the animation is being repeated, and
  99535. // * before the end of the animation's duration or the animation is being repeated, and
  99536. // * we did not reach a user-provided stop time.
  99537. var repeat = ((scheduledAnimation.loop === ModelAnimationLoop.REPEAT) ||
  99538. (scheduledAnimation.loop === ModelAnimationLoop.MIRRORED_REPEAT));
  99539. var play = (pastStartTime || (repeat && !defined(scheduledAnimation.startTime))) &&
  99540. ((delta <= 1.0) || repeat) &&
  99541. (!defined(stopTime) || JulianDate.lessThanOrEquals(sceneTime, stopTime));
  99542. if (play) {
  99543. // STOPPED -> ANIMATING state transition?
  99544. if (scheduledAnimation._state === ModelAnimationState.STOPPED) {
  99545. scheduledAnimation._state = ModelAnimationState.ANIMATING;
  99546. if (scheduledAnimation.start.numberOfListeners > 0) {
  99547. frameState.afterRender.push(scheduledAnimation._raiseStartEvent);
  99548. }
  99549. }
  99550. // Truncate to [0.0, 1.0] for repeating animations
  99551. if (scheduledAnimation.loop === ModelAnimationLoop.REPEAT) {
  99552. delta = delta - Math.floor(delta);
  99553. } else if (scheduledAnimation.loop === ModelAnimationLoop.MIRRORED_REPEAT) {
  99554. var floor = Math.floor(delta);
  99555. var fract = delta - floor;
  99556. // When even use (1.0 - fract) to mirror repeat
  99557. delta = (floor % 2 === 1.0) ? (1.0 - fract) : fract;
  99558. }
  99559. if (scheduledAnimation.reverse) {
  99560. delta = 1.0 - delta;
  99561. }
  99562. var localAnimationTime = delta * duration * scheduledAnimation.speedup;
  99563. // Clamp in case floating-point roundoff goes outside the animation's first or last keyframe
  99564. localAnimationTime = CesiumMath.clamp(localAnimationTime, runtimeAnimation.startTime, runtimeAnimation.stopTime);
  99565. animateChannels(runtimeAnimation, localAnimationTime);
  99566. if (scheduledAnimation.update.numberOfListeners > 0) {
  99567. scheduledAnimation._updateEventTime = localAnimationTime;
  99568. frameState.afterRender.push(scheduledAnimation._raiseUpdateEvent);
  99569. }
  99570. animationOccured = true;
  99571. } else {
  99572. // ANIMATING -> STOPPED state transition?
  99573. if (pastStartTime && (scheduledAnimation._state === ModelAnimationState.ANIMATING)) {
  99574. scheduledAnimation._state = ModelAnimationState.STOPPED;
  99575. if (scheduledAnimation.stop.numberOfListeners > 0) {
  99576. frameState.afterRender.push(scheduledAnimation._raiseStopEvent);
  99577. }
  99578. if (scheduledAnimation.removeOnStop) {
  99579. animationsToRemove.push(scheduledAnimation);
  99580. }
  99581. }
  99582. }
  99583. }
  99584. // Remove animations that stopped
  99585. length = animationsToRemove.length;
  99586. for (var j = 0; j < length; ++j) {
  99587. var animationToRemove = animationsToRemove[j];
  99588. scheduledAnimations.splice(scheduledAnimations.indexOf(animationToRemove), 1);
  99589. frameState.afterRender.push(createAnimationRemovedFunction(this, model, animationToRemove));
  99590. }
  99591. animationsToRemove.length = 0;
  99592. return animationOccured;
  99593. };
  99594. return ModelAnimationCollection;
  99595. });
  99596. /*global define*/
  99597. define('Scene/ModelMaterial',[
  99598. '../Core/defined',
  99599. '../Core/defineProperties',
  99600. '../Core/DeveloperError'
  99601. ], function(
  99602. defined,
  99603. defineProperties,
  99604. DeveloperError) {
  99605. 'use strict';
  99606. /**
  99607. * A model's material with modifiable parameters. A glTF material
  99608. * contains parameters defined by the material's technique with values
  99609. * defined by the technique and potentially overridden by the material.
  99610. * This class allows changing these values at runtime.
  99611. * <p>
  99612. * Use {@link Model#getMaterial} to create an instance.
  99613. * </p>
  99614. *
  99615. * @alias ModelMaterial
  99616. * @internalConstructor
  99617. *
  99618. * @see Model#getMaterial
  99619. */
  99620. function ModelMaterial(model, material, id) {
  99621. this._name = material.name;
  99622. this._id = id;
  99623. this._uniformMap = model._uniformMaps[id];
  99624. }
  99625. defineProperties(ModelMaterial.prototype, {
  99626. /**
  99627. * The value of the <code>name</code> property of this material. This is the
  99628. * name assigned by the artist when the asset is created. This can be
  99629. * different than the name of the material property ({@link ModelMaterial#id}),
  99630. * which is internal to glTF.
  99631. *
  99632. * @memberof ModelMaterial.prototype
  99633. *
  99634. * @type {String}
  99635. * @readonly
  99636. */
  99637. name : {
  99638. get : function() {
  99639. return this._name;
  99640. }
  99641. },
  99642. /**
  99643. * The name of the glTF JSON property for this material. This is guaranteed
  99644. * to be unique among all materials. It may not match the material's <code>
  99645. * name</code> property (@link ModelMaterial#name), which is assigned by
  99646. * the artist when the asset is created.
  99647. *
  99648. * @memberof ModelMaterial.prototype
  99649. *
  99650. * @type {String}
  99651. * @readonly
  99652. */
  99653. id : {
  99654. get : function() {
  99655. return this._id;
  99656. }
  99657. }
  99658. });
  99659. /**
  99660. * Assigns a value to a material parameter. The type for <code>value</code>
  99661. * depends on the glTF type of the parameter. It will be a floating-point
  99662. * number, Cartesian, or matrix.
  99663. *
  99664. * @param {String} name The name of the parameter.
  99665. * @param {Object} [value] The value to assign to the parameter.
  99666. *
  99667. * @exception {DeveloperError} name must match a parameter name in the material's technique that is targetable and not optimized out.
  99668. *
  99669. * @example
  99670. * material.setValue('diffuse', new Cesium.Cartesian4(1.0, 0.0, 0.0, 1.0)); // vec4
  99671. * material.setValue('shininess', 256.0); // scalar
  99672. */
  99673. ModelMaterial.prototype.setValue = function(name, value) {
  99674. if (!defined(name)) {
  99675. throw new DeveloperError('name is required.');
  99676. }
  99677. var v = this._uniformMap.values[name];
  99678. if (!defined(v)) {
  99679. throw new DeveloperError('name must match a parameter name in the material\'s technique that is targetable and not optimized out.');
  99680. }
  99681. v.value = v.clone(value, v.value);
  99682. };
  99683. /**
  99684. * Returns the value of the parameter with the given <code>name</code>. The type of the
  99685. * returned object depends on the glTF type of the parameter. It will be a floating-point
  99686. * number, Cartesian, or matrix.
  99687. *
  99688. * @param {String} name The name of the parameter.
  99689. * @returns {Object} The value of the parameter or <code>undefined</code> if the parameter does not exist.
  99690. */
  99691. ModelMaterial.prototype.getValue = function(name) {
  99692. if (!defined(name)) {
  99693. throw new DeveloperError('name is required.');
  99694. }
  99695. var v = this._uniformMap.values[name];
  99696. if (!defined(v)) {
  99697. return undefined;
  99698. }
  99699. return v.value;
  99700. };
  99701. return ModelMaterial;
  99702. });
  99703. /*global define*/
  99704. define('Scene/modelMaterialsCommon',[
  99705. '../Core/defaultValue',
  99706. '../Core/defined',
  99707. '../Core/WebGLConstants'
  99708. ], function(
  99709. defaultValue,
  99710. defined,
  99711. WebGLConstants) {
  99712. 'use strict';
  99713. function webGLConstantToGlslType(webGLValue) {
  99714. switch(webGLValue) {
  99715. case WebGLConstants.FLOAT:
  99716. return 'float';
  99717. case WebGLConstants.FLOAT_VEC2:
  99718. return 'vec2';
  99719. case WebGLConstants.FLOAT_VEC3:
  99720. return 'vec3';
  99721. case WebGLConstants.FLOAT_VEC4:
  99722. return 'vec4';
  99723. case WebGLConstants.FLOAT_MAT2:
  99724. return 'mat2';
  99725. case WebGLConstants.FLOAT_MAT3:
  99726. return 'mat3';
  99727. case WebGLConstants.FLOAT_MAT4:
  99728. return 'mat4';
  99729. case WebGLConstants.SAMPLER_2D:
  99730. return 'sampler2D';
  99731. }
  99732. }
  99733. function generateLightParameters(gltf) {
  99734. var result = {};
  99735. var lights;
  99736. if (defined(gltf.extensions) && defined(gltf.extensions.KHR_materials_common)) {
  99737. lights = gltf.extensions.KHR_materials_common.lights;
  99738. }
  99739. if (defined(lights)) {
  99740. // Figure out which node references the light
  99741. var nodes = gltf.nodes;
  99742. for (var nodeName in nodes) {
  99743. if (nodes.hasOwnProperty(nodeName)) {
  99744. var node = nodes[nodeName];
  99745. if (defined(node.extensions) && defined(node.extensions.KHR_materials_common)) {
  99746. var nodeLightId = node.extensions.KHR_materials_common.light;
  99747. if (defined(nodeLightId) && defined(lights[nodeLightId])) {
  99748. lights[nodeLightId].node = nodeName;
  99749. }
  99750. delete node.extensions.KHR_materials_common;
  99751. }
  99752. }
  99753. }
  99754. // Add light parameters to result
  99755. var lightCount = 0;
  99756. for(var lightName in lights) {
  99757. if (lights.hasOwnProperty(lightName)) {
  99758. var light = lights[lightName];
  99759. var lightType = light.type;
  99760. if ((lightType !== 'ambient') && !defined(light.node)) {
  99761. delete lights[lightName];
  99762. continue;
  99763. }
  99764. var lightBaseName = 'light' + lightCount.toString();
  99765. light.baseName = lightBaseName;
  99766. switch(lightType) {
  99767. case 'ambient':
  99768. var ambient = light.ambient;
  99769. result[lightBaseName + 'Color'] = {
  99770. type: WebGLConstants.FLOAT_VEC3,
  99771. value: ambient.color
  99772. };
  99773. break;
  99774. case 'directional':
  99775. var directional = light.directional;
  99776. result[lightBaseName + 'Color'] =
  99777. {
  99778. type: WebGLConstants.FLOAT_VEC3,
  99779. value: directional.color
  99780. };
  99781. if (defined(light.node)) {
  99782. result[lightBaseName + 'Transform'] =
  99783. {
  99784. node: light.node,
  99785. semantic: 'MODELVIEW',
  99786. type: WebGLConstants.FLOAT_MAT4
  99787. };
  99788. }
  99789. break;
  99790. case 'point':
  99791. var point = light.point;
  99792. result[lightBaseName + 'Color'] =
  99793. {
  99794. type: WebGLConstants.FLOAT_VEC3,
  99795. value: point.color
  99796. };
  99797. if (defined(light.node)) {
  99798. result[lightBaseName + 'Transform'] =
  99799. {
  99800. node: light.node,
  99801. semantic: 'MODELVIEW',
  99802. type: WebGLConstants.FLOAT_MAT4
  99803. };
  99804. }
  99805. result[lightBaseName + 'Attenuation'] =
  99806. {
  99807. type: WebGLConstants.FLOAT_VEC3,
  99808. value: [point.constantAttenuation, point.linearAttenuation, point.quadraticAttenuation]
  99809. };
  99810. break;
  99811. case 'spot':
  99812. var spot = light.spot;
  99813. result[lightBaseName + 'Color'] =
  99814. {
  99815. type: WebGLConstants.FLOAT_VEC3,
  99816. value: spot.color
  99817. };
  99818. if (defined(light.node)) {
  99819. result[lightBaseName + 'Transform'] =
  99820. {
  99821. node: light.node,
  99822. semantic: 'MODELVIEW',
  99823. type: WebGLConstants.FLOAT_MAT4
  99824. };
  99825. result[lightBaseName + 'InverseTransform'] = {
  99826. node: light.node,
  99827. semantic: 'MODELVIEWINVERSE',
  99828. type: WebGLConstants.FLOAT_MAT4,
  99829. useInFragment: true
  99830. };
  99831. }
  99832. result[lightBaseName + 'Attenuation'] =
  99833. {
  99834. type: WebGLConstants.FLOAT_VEC3,
  99835. value: [spot.constantAttenuation, spot.linearAttenuation, spot.quadraticAttenuation]
  99836. };
  99837. result[lightBaseName + 'FallOff'] =
  99838. {
  99839. type: WebGLConstants.FLOAT_VEC2,
  99840. value: [spot.fallOffAngle, spot.fallOffExponent]
  99841. };
  99842. break;
  99843. }
  99844. ++lightCount;
  99845. }
  99846. }
  99847. }
  99848. return result;
  99849. }
  99850. function getNextId(dictionary, baseName, startingCount) {
  99851. var count = defaultValue(startingCount, 0);
  99852. var nextId;
  99853. do {
  99854. nextId = baseName + (count++).toString();
  99855. } while(defined(dictionary[nextId]));
  99856. return nextId;
  99857. }
  99858. var techniqueCount = 0;
  99859. var vertexShaderCount = 0;
  99860. var fragmentShaderCount = 0;
  99861. var programCount = 0;
  99862. function generateTechnique(gltf, khrMaterialsCommon, lightParameters) {
  99863. var techniques = gltf.techniques;
  99864. var shaders = gltf.shaders;
  99865. var programs = gltf.programs;
  99866. var lightingModel = khrMaterialsCommon.technique.toUpperCase();
  99867. var lights;
  99868. if (defined(gltf.extensions) && defined(gltf.extensions.KHR_materials_common)) {
  99869. lights = gltf.extensions.KHR_materials_common.lights;
  99870. }
  99871. var jointCount = defaultValue(khrMaterialsCommon.jointCount, 0);
  99872. var hasSkinning = (jointCount > 0);
  99873. var parameterValues = khrMaterialsCommon.values;
  99874. var vertexShader = 'precision highp float;\n';
  99875. var fragmentShader = 'precision highp float;\n';
  99876. // Generate IDs for our new objects
  99877. var techniqueId = getNextId(techniques, 'technique', techniqueCount);
  99878. var vertexShaderId = getNextId(shaders, 'vertexShader', vertexShaderCount);
  99879. var fragmentShaderId = getNextId(shaders, 'fragmentShader', fragmentShaderCount);
  99880. var programId = getNextId(programs, 'program', programCount);
  99881. var hasNormals = (lightingModel !== 'CONSTANT');
  99882. // Add techniques
  99883. var techniqueParameters = {
  99884. // Add matrices
  99885. modelViewMatrix: {
  99886. semantic: 'MODELVIEW',
  99887. type: WebGLConstants.FLOAT_MAT4
  99888. },
  99889. projectionMatrix: {
  99890. semantic: 'PROJECTION',
  99891. type: WebGLConstants.FLOAT_MAT4
  99892. }
  99893. };
  99894. if (hasNormals) {
  99895. techniqueParameters.normalMatrix = {
  99896. semantic: 'MODELVIEWINVERSETRANSPOSE',
  99897. type: WebGLConstants.FLOAT_MAT3
  99898. };
  99899. }
  99900. if (hasSkinning) {
  99901. techniqueParameters.jointMatrix = {
  99902. count: jointCount,
  99903. semantic: 'JOINTMATRIX',
  99904. type: WebGLConstants.FLOAT_MAT4
  99905. };
  99906. }
  99907. // Add material parameters
  99908. var lowerCase;
  99909. var hasTexCoords = false;
  99910. for(var name in parameterValues) {
  99911. //generate shader parameters for KHR_materials_common attributes
  99912. //(including a check, because some boolean flags should not be used as shader parameters)
  99913. if (parameterValues.hasOwnProperty(name) && (name !== 'transparent') && (name !== 'doubleSided')) {
  99914. var valType = getKHRMaterialsCommonValueType(name, parameterValues[name]);
  99915. lowerCase = name.toLowerCase();
  99916. if (!hasTexCoords && (valType === WebGLConstants.SAMPLER_2D)) {
  99917. hasTexCoords = true;
  99918. }
  99919. techniqueParameters[lowerCase] = {
  99920. type: valType
  99921. };
  99922. }
  99923. }
  99924. // Copy light parameters into technique parameters
  99925. if (defined(lightParameters)) {
  99926. for (var lightParamName in lightParameters) {
  99927. if (lightParameters.hasOwnProperty(lightParamName)) {
  99928. techniqueParameters[lightParamName] = lightParameters[lightParamName];
  99929. }
  99930. }
  99931. }
  99932. // Generate uniforms object before attributes are added
  99933. var techniqueUniforms = {};
  99934. for (var paramName in techniqueParameters) {
  99935. if (techniqueParameters.hasOwnProperty(paramName)) {
  99936. var param = techniqueParameters[paramName];
  99937. techniqueUniforms['u_' + paramName] = paramName;
  99938. var arraySize = defined(param.count) ? '['+param.count+']' : '';
  99939. if (((param.type !== WebGLConstants.FLOAT_MAT3) && (param.type !== WebGLConstants.FLOAT_MAT4)) ||
  99940. param.useInFragment) {
  99941. fragmentShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n';
  99942. delete param.useInFragment;
  99943. }
  99944. else {
  99945. vertexShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n';
  99946. }
  99947. }
  99948. }
  99949. // Add attributes with semantics
  99950. var vertexShaderMain = '';
  99951. if (hasSkinning) {
  99952. vertexShaderMain += ' mat4 skinMat = a_weight.x * u_jointMatrix[int(a_joint.x)];\n';
  99953. vertexShaderMain += ' skinMat += a_weight.y * u_jointMatrix[int(a_joint.y)];\n';
  99954. vertexShaderMain += ' skinMat += a_weight.z * u_jointMatrix[int(a_joint.z)];\n';
  99955. vertexShaderMain += ' skinMat += a_weight.w * u_jointMatrix[int(a_joint.w)];\n';
  99956. }
  99957. // Add position always
  99958. var techniqueAttributes = {
  99959. a_position: 'position'
  99960. };
  99961. techniqueParameters.position = {
  99962. semantic: 'POSITION',
  99963. type: WebGLConstants.FLOAT_VEC3
  99964. };
  99965. vertexShader += 'attribute vec3 a_position;\n';
  99966. vertexShader += 'varying vec3 v_positionEC;\n';
  99967. if (hasSkinning) {
  99968. vertexShaderMain += ' vec4 pos = u_modelViewMatrix * skinMat * vec4(a_position,1.0);\n';
  99969. }
  99970. else {
  99971. vertexShaderMain += ' vec4 pos = u_modelViewMatrix * vec4(a_position,1.0);\n';
  99972. }
  99973. vertexShaderMain += ' v_positionEC = pos.xyz;\n';
  99974. vertexShaderMain += ' gl_Position = u_projectionMatrix * pos;\n';
  99975. fragmentShader += 'varying vec3 v_positionEC;\n';
  99976. // Add normal if we don't have constant lighting
  99977. if (hasNormals) {
  99978. techniqueAttributes.a_normal = 'normal';
  99979. techniqueParameters.normal = {
  99980. semantic: 'NORMAL',
  99981. type: WebGLConstants.FLOAT_VEC3
  99982. };
  99983. vertexShader += 'attribute vec3 a_normal;\n';
  99984. vertexShader += 'varying vec3 v_normal;\n';
  99985. if (hasSkinning) {
  99986. vertexShaderMain += ' v_normal = u_normalMatrix * mat3(skinMat) * a_normal;\n';
  99987. }
  99988. else {
  99989. vertexShaderMain += ' v_normal = u_normalMatrix * a_normal;\n';
  99990. }
  99991. fragmentShader += 'varying vec3 v_normal;\n';
  99992. }
  99993. // Add texture coordinates if the material uses them
  99994. var v_texcoord;
  99995. if (hasTexCoords) {
  99996. techniqueAttributes.a_texcoord_0 = 'texcoord_0';
  99997. techniqueParameters.texcoord_0 = {
  99998. semantic: 'TEXCOORD_0',
  99999. type: WebGLConstants.FLOAT_VEC2
  100000. };
  100001. v_texcoord = 'v_texcoord_0';
  100002. vertexShader += 'attribute vec2 a_texcoord_0;\n';
  100003. vertexShader += 'varying vec2 ' + v_texcoord + ';\n';
  100004. vertexShaderMain += ' ' + v_texcoord + ' = a_texcoord_0;\n';
  100005. fragmentShader += 'varying vec2 ' + v_texcoord + ';\n';
  100006. }
  100007. if (hasSkinning) {
  100008. techniqueAttributes.a_joint = 'joint';
  100009. techniqueParameters.joint = {
  100010. semantic: 'JOINT',
  100011. type: WebGLConstants.FLOAT_VEC4
  100012. };
  100013. techniqueAttributes.a_weight = 'weight';
  100014. techniqueParameters.weight = {
  100015. semantic: 'WEIGHT',
  100016. type: WebGLConstants.FLOAT_VEC4
  100017. };
  100018. vertexShader += 'attribute vec4 a_joint;\n';
  100019. vertexShader += 'attribute vec4 a_weight;\n';
  100020. }
  100021. var hasSpecular = hasNormals && ((lightingModel === 'BLINN') || (lightingModel === 'PHONG')) &&
  100022. defined(techniqueParameters.specular) && defined(techniqueParameters.shininess);
  100023. // Generate lighting code blocks
  100024. var hasNonAmbientLights = false;
  100025. var hasAmbientLights = false;
  100026. var fragmentLightingBlock = '';
  100027. for (var lightName in lights) {
  100028. if (lights.hasOwnProperty(lightName)) {
  100029. var light = lights[lightName];
  100030. var lightType = light.type.toLowerCase();
  100031. var lightBaseName = light.baseName;
  100032. fragmentLightingBlock += ' {\n';
  100033. var lightColorName = 'u_' + lightBaseName + 'Color';
  100034. var varyingDirectionName;
  100035. var varyingPositionName;
  100036. if(lightType === 'ambient') {
  100037. hasAmbientLights = true;
  100038. fragmentLightingBlock += ' ambientLight += ' + lightColorName + ';\n';
  100039. }
  100040. else if (hasNormals) {
  100041. hasNonAmbientLights = true;
  100042. varyingDirectionName = 'v_' + lightBaseName + 'Direction';
  100043. varyingPositionName = 'v_' + lightBaseName + 'Position';
  100044. if (lightType !== 'point') {
  100045. vertexShader += 'varying vec3 ' + varyingDirectionName + ';\n';
  100046. fragmentShader += 'varying vec3 ' + varyingDirectionName + ';\n';
  100047. vertexShaderMain += ' ' + varyingDirectionName + ' = mat3(u_' + lightBaseName + 'Transform) * vec3(0.,0.,1.);\n';
  100048. if (lightType === 'directional') {
  100049. fragmentLightingBlock += ' vec3 l = normalize(' + varyingDirectionName + ');\n';
  100050. }
  100051. }
  100052. if (lightType !== 'directional') {
  100053. vertexShader += 'varying vec3 ' + varyingPositionName + ';\n';
  100054. fragmentShader += 'varying vec3 ' + varyingPositionName + ';\n';
  100055. vertexShaderMain += ' ' + varyingPositionName + ' = u_' + lightBaseName + 'Transform[3].xyz;\n';
  100056. fragmentLightingBlock += ' vec3 VP = ' + varyingPositionName + ' - v_positionEC;\n';
  100057. fragmentLightingBlock += ' vec3 l = normalize(VP);\n';
  100058. fragmentLightingBlock += ' float range = length(VP);\n';
  100059. fragmentLightingBlock += ' float attenuation = 1.0 / (u_' + lightBaseName + 'Attenuation.x + ';
  100060. fragmentLightingBlock += '(u_' + lightBaseName + 'Attenuation.y * range) + ';
  100061. fragmentLightingBlock += '(u_' + lightBaseName + 'Attenuation.z * range * range));\n';
  100062. }
  100063. else {
  100064. fragmentLightingBlock += ' float attenuation = 1.0;\n';
  100065. }
  100066. if (lightType === 'spot') {
  100067. fragmentLightingBlock += ' float spotDot = dot(l, normalize(' + varyingDirectionName + '));\n';
  100068. fragmentLightingBlock += ' if (spotDot < cos(u_' + lightBaseName + 'FallOff.x * 0.5))\n';
  100069. fragmentLightingBlock += ' {\n';
  100070. fragmentLightingBlock += ' attenuation = 0.0;\n';
  100071. fragmentLightingBlock += ' }\n';
  100072. fragmentLightingBlock += ' else\n';
  100073. fragmentLightingBlock += ' {\n';
  100074. fragmentLightingBlock += ' attenuation *= max(0.0, pow(spotDot, u_' + lightBaseName + 'FallOff.y));\n';
  100075. fragmentLightingBlock += ' }\n';
  100076. }
  100077. fragmentLightingBlock += ' diffuseLight += ' + lightColorName + '* max(dot(normal,l), 0.) * attenuation;\n';
  100078. if (hasSpecular) {
  100079. if (lightingModel === 'BLINN') {
  100080. fragmentLightingBlock += ' vec3 h = normalize(l + viewDir);\n';
  100081. fragmentLightingBlock += ' float specularIntensity = max(0., pow(max(dot(normal, h), 0.), u_shininess)) * attenuation;\n';
  100082. }
  100083. else { // PHONG
  100084. fragmentLightingBlock += ' vec3 reflectDir = reflect(-l, normal);\n';
  100085. fragmentLightingBlock += ' float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess)) * attenuation;\n';
  100086. }
  100087. fragmentLightingBlock += ' specularLight += ' + lightColorName + ' * specularIntensity;\n';
  100088. }
  100089. }
  100090. fragmentLightingBlock += ' }\n';
  100091. }
  100092. }
  100093. if (!hasAmbientLights) {
  100094. // Add an ambient light if we don't have one
  100095. fragmentLightingBlock += ' ambientLight += vec3(0.2, 0.2, 0.2);\n';
  100096. }
  100097. if (!hasNonAmbientLights && (lightingModel !== 'CONSTANT')) {
  100098. fragmentLightingBlock += ' vec3 l = normalize(czm_sunDirectionEC);\n';
  100099. fragmentLightingBlock += ' diffuseLight += vec3(1.0, 1.0, 1.0) * max(dot(normal,l), 0.);\n';
  100100. if (hasSpecular) {
  100101. if (lightingModel === 'BLINN') {
  100102. fragmentLightingBlock += ' vec3 h = normalize(l + viewDir);\n';
  100103. fragmentLightingBlock += ' float specularIntensity = max(0., pow(max(dot(normal, h), 0.), u_shininess));\n';
  100104. }
  100105. else { // PHONG
  100106. fragmentLightingBlock += ' vec3 reflectDir = reflect(-l, normal);\n';
  100107. fragmentLightingBlock += ' float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess));\n';
  100108. }
  100109. fragmentLightingBlock += ' specularLight += vec3(1.0, 1.0, 1.0) * specularIntensity;\n';
  100110. }
  100111. }
  100112. vertexShader += 'void main(void) {\n';
  100113. vertexShader += vertexShaderMain;
  100114. vertexShader += '}\n';
  100115. fragmentShader += 'void main(void) {\n';
  100116. var colorCreationBlock = ' vec3 color = vec3(0.0, 0.0, 0.0);\n';
  100117. if (hasNormals) {
  100118. fragmentShader += ' vec3 normal = normalize(v_normal);\n';
  100119. if (khrMaterialsCommon.doubleSided) {
  100120. fragmentShader += ' if (gl_FrontFacing == false)\n';
  100121. fragmentShader += ' {\n';
  100122. fragmentShader += ' normal = -normal;\n';
  100123. fragmentShader += ' }\n';
  100124. }
  100125. }
  100126. var finalColorComputation;
  100127. if (lightingModel !== 'CONSTANT') {
  100128. if (defined(techniqueParameters.diffuse)) {
  100129. if (techniqueParameters.diffuse.type === WebGLConstants.SAMPLER_2D) {
  100130. fragmentShader += ' vec4 diffuse = texture2D(u_diffuse, ' + v_texcoord + ');\n';
  100131. }
  100132. else {
  100133. fragmentShader += ' vec4 diffuse = u_diffuse;\n';
  100134. }
  100135. fragmentShader += ' vec3 diffuseLight = vec3(0.0, 0.0, 0.0);\n';
  100136. colorCreationBlock += ' color += diffuse.rgb * diffuseLight;\n';
  100137. }
  100138. if (hasSpecular) {
  100139. if (techniqueParameters.specular.type === WebGLConstants.SAMPLER_2D) {
  100140. fragmentShader += ' vec3 specular = texture2D(u_specular, ' + v_texcoord + ').rgb;\n';
  100141. }
  100142. else {
  100143. fragmentShader += ' vec3 specular = u_specular.rgb;\n';
  100144. }
  100145. fragmentShader += ' vec3 specularLight = vec3(0.0, 0.0, 0.0);\n';
  100146. colorCreationBlock += ' color += specular * specularLight;\n';
  100147. }
  100148. if (defined(techniqueParameters.transparency)) {
  100149. finalColorComputation = ' gl_FragColor = vec4(color * diffuse.a, diffuse.a * u_transparency);\n';
  100150. }
  100151. else {
  100152. finalColorComputation = ' gl_FragColor = vec4(color * diffuse.a, diffuse.a);\n';
  100153. }
  100154. }
  100155. else {
  100156. if (defined(techniqueParameters.transparency)) {
  100157. finalColorComputation = ' gl_FragColor = vec4(color, u_transparency);\n';
  100158. }
  100159. else {
  100160. finalColorComputation = ' gl_FragColor = vec4(color, 1.0);\n';
  100161. }
  100162. }
  100163. if (defined(techniqueParameters.emission)) {
  100164. if (techniqueParameters.emission.type === WebGLConstants.SAMPLER_2D) {
  100165. fragmentShader += ' vec3 emission = texture2D(u_emission, ' + v_texcoord + ').rgb;\n';
  100166. }
  100167. else {
  100168. fragmentShader += ' vec3 emission = u_emission.rgb;\n';
  100169. }
  100170. colorCreationBlock += ' color += emission;\n';
  100171. }
  100172. if (defined(techniqueParameters.ambient) || (lightingModel !== 'CONSTANT')) {
  100173. if (defined(techniqueParameters.ambient)) {
  100174. if (techniqueParameters.ambient.type === WebGLConstants.SAMPLER_2D) {
  100175. fragmentShader += ' vec3 ambient = texture2D(u_ambient, ' + v_texcoord + ').rgb;\n';
  100176. }
  100177. else {
  100178. fragmentShader += ' vec3 ambient = u_ambient.rgb;\n';
  100179. }
  100180. }
  100181. else {
  100182. fragmentShader += ' vec3 ambient = diffuse.rgb;\n';
  100183. }
  100184. colorCreationBlock += ' color += ambient * ambientLight;\n';
  100185. }
  100186. fragmentShader += ' vec3 viewDir = -normalize(v_positionEC);\n';
  100187. fragmentShader += ' vec3 ambientLight = vec3(0.0, 0.0, 0.0);\n';
  100188. // Add in light computations
  100189. fragmentShader += fragmentLightingBlock;
  100190. fragmentShader += colorCreationBlock;
  100191. fragmentShader += finalColorComputation;
  100192. fragmentShader += '}\n';
  100193. var techniqueStates;
  100194. if (khrMaterialsCommon.transparent) {
  100195. techniqueStates = {
  100196. enable: [
  100197. WebGLConstants.DEPTH_TEST,
  100198. WebGLConstants.BLEND
  100199. ],
  100200. depthMask: false,
  100201. functions: {
  100202. blendEquationSeparate: [
  100203. WebGLConstants.FUNC_ADD,
  100204. WebGLConstants.FUNC_ADD
  100205. ],
  100206. blendFuncSeparate: [
  100207. WebGLConstants.ONE,
  100208. WebGLConstants.ONE_MINUS_SRC_ALPHA,
  100209. WebGLConstants.ONE,
  100210. WebGLConstants.ONE_MINUS_SRC_ALPHA
  100211. ]
  100212. }
  100213. };
  100214. }
  100215. else if (khrMaterialsCommon.doubleSided) {
  100216. techniqueStates = {
  100217. enable: [
  100218. WebGLConstants.DEPTH_TEST
  100219. ]
  100220. };
  100221. }
  100222. else { // Not transparent or double sided
  100223. techniqueStates = {
  100224. enable: [
  100225. WebGLConstants.CULL_FACE,
  100226. WebGLConstants.DEPTH_TEST
  100227. ]
  100228. };
  100229. }
  100230. techniques[techniqueId] = {
  100231. attributes: techniqueAttributes,
  100232. parameters: techniqueParameters,
  100233. program: programId,
  100234. states: techniqueStates,
  100235. uniforms: techniqueUniforms
  100236. };
  100237. // Add shaders
  100238. shaders[vertexShaderId] = {
  100239. type: WebGLConstants.VERTEX_SHADER,
  100240. uri: '',
  100241. extras: {
  100242. source: vertexShader
  100243. }
  100244. };
  100245. shaders[fragmentShaderId] = {
  100246. type: WebGLConstants.FRAGMENT_SHADER,
  100247. uri: '',
  100248. extras: {
  100249. source: fragmentShader
  100250. }
  100251. };
  100252. // Add program
  100253. var programAttributes = Object.keys(techniqueAttributes);
  100254. programs[programId] = {
  100255. attributes: programAttributes,
  100256. fragmentShader: fragmentShaderId,
  100257. vertexShader: vertexShaderId
  100258. };
  100259. return techniqueId;
  100260. }
  100261. function getKHRMaterialsCommonValueType(paramName, paramValue)
  100262. {
  100263. var value;
  100264. // Backwards compatibility for COLLADA2GLTF v1.0-draft when it encoding
  100265. // materials using KHR_materials_common with explicit type/value members
  100266. if (defined(paramValue.value)) {
  100267. value = paramValue.value;
  100268. } else {
  100269. value = paramValue;
  100270. }
  100271. switch (paramName) {
  100272. case 'ambient':
  100273. return (value instanceof String || typeof value === 'string') ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4;
  100274. case 'diffuse':
  100275. return (value instanceof String || typeof value === 'string') ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4;
  100276. case 'emission':
  100277. return (value instanceof String || typeof value === 'string') ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4;
  100278. case 'specular':
  100279. return (value instanceof String || typeof value === 'string') ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4;
  100280. case 'shininess':
  100281. return WebGLConstants.FLOAT;
  100282. case 'transparency':
  100283. return WebGLConstants.FLOAT;
  100284. // these two are usually not used directly within shaders,
  100285. // they are just added here for completeness
  100286. case 'transparent':
  100287. return WebGLConstants.BOOL;
  100288. case 'doubleSided':
  100289. return WebGLConstants.BOOL;
  100290. }
  100291. }
  100292. function getTechniqueKey(khrMaterialsCommon) {
  100293. var techniqueKey = '';
  100294. techniqueKey += 'technique:' + khrMaterialsCommon.technique + ';';
  100295. var values = khrMaterialsCommon.values;
  100296. var keys = Object.keys(values).sort();
  100297. var keysCount = keys.length;
  100298. for (var i=0;i<keysCount;++i) {
  100299. var name = keys[i];
  100300. //generate first part of key using shader parameters for KHR_materials_common attributes
  100301. //(including a check, because some boolean flags should not be used as shader parameters)
  100302. if (values.hasOwnProperty(name) && (name !== 'transparent') && (name !== 'doubleSided')) {
  100303. techniqueKey += name + ':' + getKHRMaterialsCommonValueType(name, values[name]);
  100304. techniqueKey += ';';
  100305. }
  100306. }
  100307. var doubleSided = defaultValue(khrMaterialsCommon.doubleSided, false);
  100308. techniqueKey += doubleSided.toString() + ';';
  100309. var transparent = defaultValue(khrMaterialsCommon.transparent, false);
  100310. techniqueKey += transparent.toString() + ';';
  100311. var jointCount = defaultValue(khrMaterialsCommon.jointCount, 0);
  100312. techniqueKey += jointCount.toString() + ';';
  100313. return techniqueKey;
  100314. }
  100315. /**
  100316. * Modifies gltf in place.
  100317. *
  100318. * @private
  100319. */
  100320. function modelMaterialsCommon(gltf) {
  100321. if (!defined(gltf)) {
  100322. return undefined;
  100323. }
  100324. var hasExtension = false;
  100325. var extensionsUsed = gltf.extensionsUsed;
  100326. if (defined(extensionsUsed)) {
  100327. var extensionsUsedCount = extensionsUsed.length;
  100328. for(var i=0;i<extensionsUsedCount;++i) {
  100329. if (extensionsUsed[i] === 'KHR_materials_common') {
  100330. hasExtension = true;
  100331. extensionsUsed.splice(i, 1);
  100332. break;
  100333. }
  100334. }
  100335. }
  100336. if (hasExtension) {
  100337. if (!defined(gltf.programs)) {
  100338. gltf.programs = {};
  100339. }
  100340. if (!defined(gltf.shaders)) {
  100341. gltf.shaders = {};
  100342. }
  100343. if (!defined(gltf.techniques)) {
  100344. gltf.techniques = {};
  100345. }
  100346. var lightParameters = generateLightParameters(gltf);
  100347. var techniques = {};
  100348. var materials = gltf.materials;
  100349. for (var name in materials) {
  100350. if (materials.hasOwnProperty(name)) {
  100351. var material = materials[name];
  100352. if (defined(material.extensions) && defined(material.extensions.KHR_materials_common)) {
  100353. var khrMaterialsCommon = material.extensions.KHR_materials_common;
  100354. var techniqueKey = getTechniqueKey(khrMaterialsCommon);
  100355. var technique = techniques[techniqueKey];
  100356. if (!defined(technique)) {
  100357. technique = generateTechnique(gltf, khrMaterialsCommon, lightParameters);
  100358. techniques[techniqueKey] = technique;
  100359. }
  100360. // Take advantage of the fact that we generate techniques that use the
  100361. // same parameter names as the extension values.
  100362. material.values = {};
  100363. var values = khrMaterialsCommon.values;
  100364. for (var valueName in values) {
  100365. if (values.hasOwnProperty(valueName)) {
  100366. var value = values[valueName];
  100367. // Backwards compatibility for COLLADA2GLTF v1.0-draft when it encoding
  100368. // materials using KHR_materials_common with explicit type/value members
  100369. if (defined(value.value)) {
  100370. material.values[valueName] = value.value;
  100371. } else {
  100372. material.values[valueName] = value;
  100373. }
  100374. }
  100375. }
  100376. material.technique = technique;
  100377. delete material.extensions.KHR_materials_common;
  100378. }
  100379. }
  100380. }
  100381. if (defined(gltf.extensions)) {
  100382. delete gltf.extensions.KHR_materials_common;
  100383. }
  100384. }
  100385. return gltf;
  100386. }
  100387. return modelMaterialsCommon;
  100388. });
  100389. /*global define*/
  100390. define('Scene/ModelMesh',[
  100391. '../Core/defineProperties'
  100392. ], function(
  100393. defineProperties) {
  100394. 'use strict';
  100395. /**
  100396. * A model's mesh and its materials.
  100397. * <p>
  100398. * Use {@link Model#getMesh} to create an instance.
  100399. * </p>
  100400. *
  100401. * @alias ModelMesh
  100402. * @internalConstructor
  100403. *
  100404. * @see Model#getMesh
  100405. */
  100406. function ModelMesh(mesh, runtimeMaterialsById, id) {
  100407. var materials = [];
  100408. var primitives = mesh.primitives;
  100409. var length = primitives.length;
  100410. for (var i = 0; i < length; ++i) {
  100411. var p = primitives[i];
  100412. materials[i] = runtimeMaterialsById[p.material];
  100413. }
  100414. this._name = mesh.name;
  100415. this._materials = materials;
  100416. this._id = id;
  100417. }
  100418. defineProperties(ModelMesh.prototype, {
  100419. /**
  100420. * The value of the <code>name</code> property of this mesh. This is the
  100421. * name assigned by the artist when the asset is created. This can be
  100422. * different than the name of the mesh property ({@link ModelMesh#id}),
  100423. * which is internal to glTF.
  100424. *
  100425. * @memberof ModelMesh.prototype
  100426. *
  100427. * @type {String}
  100428. * @readonly
  100429. */
  100430. name : {
  100431. get : function() {
  100432. return this._name;
  100433. }
  100434. },
  100435. /**
  100436. * The name of the glTF JSON property for this mesh. This is guaranteed
  100437. * to be unique among all meshes. It may not match the mesh's <code>
  100438. * name</code> property (@link ModelMesh#name), which is assigned by
  100439. * the artist when the asset is created.
  100440. *
  100441. * @memberof ModelMesh.prototype
  100442. *
  100443. * @type {String}
  100444. * @readonly
  100445. */
  100446. id : {
  100447. get : function() {
  100448. return this._id;
  100449. }
  100450. },
  100451. /**
  100452. * An array of {@link ModelMaterial} instances indexed by the mesh's
  100453. * primitive indices.
  100454. *
  100455. * @memberof ModelMesh.prototype
  100456. *
  100457. * @type {ModelMaterial[]}
  100458. * @readonly
  100459. */
  100460. materials : {
  100461. get : function() {
  100462. return this._materials;
  100463. }
  100464. }
  100465. });
  100466. return ModelMesh;
  100467. });
  100468. /*global define*/
  100469. define('Scene/ModelNode',[
  100470. '../Core/defineProperties',
  100471. '../Core/Matrix4'
  100472. ], function(
  100473. defineProperties,
  100474. Matrix4) {
  100475. 'use strict';
  100476. /**
  100477. * A model node with a transform for user-defined animations. A glTF asset can
  100478. * contain animations that target a node's transform. This class allows
  100479. * changing a node's transform externally so animation can be driven by another
  100480. * source, not just an animation in the glTF asset.
  100481. * <p>
  100482. * Use {@link Model#getNode} to create an instance.
  100483. * </p>
  100484. *
  100485. * @alias ModelNode
  100486. * @internalConstructor
  100487. *
  100488. *
  100489. * @example
  100490. * var node = model.getNode('LOD3sp');
  100491. * node.matrix = Cesium.Matrix4.fromScale(new Cesium.Cartesian3(5.0, 1.0, 1.0), node.matrix);
  100492. *
  100493. * @see Model#getNode
  100494. */
  100495. function ModelNode(model, node, runtimeNode, id, matrix) {
  100496. this._model = model;
  100497. this._runtimeNode = runtimeNode;
  100498. this._name = node.name;
  100499. this._id = id;
  100500. /**
  100501. * @private
  100502. */
  100503. this.useMatrix = false;
  100504. this._show = true;
  100505. this._matrix = Matrix4.clone(matrix);
  100506. }
  100507. defineProperties(ModelNode.prototype, {
  100508. /**
  100509. * The value of the <code>name</code> property of this node. This is the
  100510. * name assigned by the artist when the asset is created. This can be
  100511. * different than the name of the node property ({@link ModelNode#id}),
  100512. * which is internal to glTF.
  100513. *
  100514. * @memberof ModelNode.prototype
  100515. *
  100516. * @type {String}
  100517. * @readonly
  100518. */
  100519. name : {
  100520. get : function() {
  100521. return this._name;
  100522. }
  100523. },
  100524. /**
  100525. * The name of the glTF JSON property for this node. This is guaranteed
  100526. * to be unique among all nodes. It may not match the node's <code>
  100527. * name</code> property (@link ModelNode#name), which is assigned by
  100528. * the artist when the asset is created.
  100529. *
  100530. * @memberof ModelNode.prototype
  100531. *
  100532. * @type {String}
  100533. * @readonly
  100534. */
  100535. id : {
  100536. get : function() {
  100537. return this._id;
  100538. }
  100539. },
  100540. /**
  100541. * Determines if this node and its children will be shown.
  100542. *
  100543. * @memberof ModelNode.prototype
  100544. * @type {Boolean}
  100545. *
  100546. * @default true
  100547. */
  100548. show : {
  100549. get : function() {
  100550. return this._show;
  100551. },
  100552. set : function(value) {
  100553. if (this._show !== value) {
  100554. this._show = value;
  100555. this._model._perNodeShowDirty = true;
  100556. }
  100557. }
  100558. },
  100559. /**
  100560. * The node's 4x4 matrix transform from its local coordinates to
  100561. * its parent's.
  100562. * <p>
  100563. * For changes to take effect, this property must be assigned to;
  100564. * setting individual elements of the matrix will not work.
  100565. * </p>
  100566. *
  100567. * @memberof ModelNode.prototype
  100568. * @type {Matrix4}
  100569. */
  100570. matrix : {
  100571. get : function() {
  100572. return this._matrix;
  100573. },
  100574. set : function(value) {
  100575. this._matrix = Matrix4.clone(value, this._matrix);
  100576. this.useMatrix = true;
  100577. var model = this._model;
  100578. model._cesiumAnimationsDirty = true;
  100579. this._runtimeNode.dirtyNumber = model._maxDirtyNumber;
  100580. }
  100581. }
  100582. });
  100583. /**
  100584. * @private
  100585. */
  100586. ModelNode.prototype.setMatrix = function(matrix) {
  100587. // Update matrix but do not set the dirty flag since this is used internally
  100588. // to keep the matrix in-sync during a glTF animation.
  100589. Matrix4.clone(matrix, this._matrix);
  100590. };
  100591. return ModelNode;
  100592. });
  100593. /*global define*/
  100594. define('Scene/Model',[
  100595. '../Core/BoundingSphere',
  100596. '../Core/Cartesian2',
  100597. '../Core/Cartesian3',
  100598. '../Core/Cartesian4',
  100599. '../Core/Cartographic',
  100600. '../Core/clone',
  100601. '../Core/Color',
  100602. '../Core/combine',
  100603. '../Core/defaultValue',
  100604. '../Core/defined',
  100605. '../Core/defineProperties',
  100606. '../Core/destroyObject',
  100607. '../Core/DeveloperError',
  100608. '../Core/DistanceDisplayCondition',
  100609. '../Core/FeatureDetection',
  100610. '../Core/getAbsoluteUri',
  100611. '../Core/getBaseUri',
  100612. '../Core/getMagic',
  100613. '../Core/getStringFromTypedArray',
  100614. '../Core/IndexDatatype',
  100615. '../Core/loadArrayBuffer',
  100616. '../Core/loadImage',
  100617. '../Core/loadImageFromTypedArray',
  100618. '../Core/loadText',
  100619. '../Core/Math',
  100620. '../Core/Matrix2',
  100621. '../Core/Matrix3',
  100622. '../Core/Matrix4',
  100623. '../Core/PrimitiveType',
  100624. '../Core/Quaternion',
  100625. '../Core/Queue',
  100626. '../Core/RuntimeError',
  100627. '../Core/Transforms',
  100628. '../Core/WebGLConstants',
  100629. '../Renderer/Buffer',
  100630. '../Renderer/BufferUsage',
  100631. '../Renderer/DrawCommand',
  100632. '../Renderer/Pass',
  100633. '../Renderer/RenderState',
  100634. '../Renderer/Sampler',
  100635. '../Renderer/ShaderProgram',
  100636. '../Renderer/ShaderSource',
  100637. '../Renderer/Texture',
  100638. '../Renderer/TextureMinificationFilter',
  100639. '../Renderer/TextureWrap',
  100640. '../Renderer/VertexArray',
  100641. '../ThirdParty/gltfDefaults',
  100642. '../ThirdParty/Uri',
  100643. '../ThirdParty/when',
  100644. './BlendingState',
  100645. './ColorBlendMode',
  100646. './getAttributeOrUniformBySemantic',
  100647. './getBinaryAccessor',
  100648. './HeightReference',
  100649. './ModelAnimationCache',
  100650. './ModelAnimationCollection',
  100651. './ModelMaterial',
  100652. './modelMaterialsCommon',
  100653. './ModelMesh',
  100654. './ModelNode',
  100655. './SceneMode',
  100656. './ShadowMode'
  100657. ], function(
  100658. BoundingSphere,
  100659. Cartesian2,
  100660. Cartesian3,
  100661. Cartesian4,
  100662. Cartographic,
  100663. clone,
  100664. Color,
  100665. combine,
  100666. defaultValue,
  100667. defined,
  100668. defineProperties,
  100669. destroyObject,
  100670. DeveloperError,
  100671. DistanceDisplayCondition,
  100672. FeatureDetection,
  100673. getAbsoluteUri,
  100674. getBaseUri,
  100675. getMagic,
  100676. getStringFromTypedArray,
  100677. IndexDatatype,
  100678. loadArrayBuffer,
  100679. loadImage,
  100680. loadImageFromTypedArray,
  100681. loadText,
  100682. CesiumMath,
  100683. Matrix2,
  100684. Matrix3,
  100685. Matrix4,
  100686. PrimitiveType,
  100687. Quaternion,
  100688. Queue,
  100689. RuntimeError,
  100690. Transforms,
  100691. WebGLConstants,
  100692. Buffer,
  100693. BufferUsage,
  100694. DrawCommand,
  100695. Pass,
  100696. RenderState,
  100697. Sampler,
  100698. ShaderProgram,
  100699. ShaderSource,
  100700. Texture,
  100701. TextureMinificationFilter,
  100702. TextureWrap,
  100703. VertexArray,
  100704. gltfDefaults,
  100705. Uri,
  100706. when,
  100707. BlendingState,
  100708. ColorBlendMode,
  100709. getAttributeOrUniformBySemantic,
  100710. getBinaryAccessor,
  100711. HeightReference,
  100712. ModelAnimationCache,
  100713. ModelAnimationCollection,
  100714. ModelMaterial,
  100715. modelMaterialsCommon,
  100716. ModelMesh,
  100717. ModelNode,
  100718. SceneMode,
  100719. ShadowMode) {
  100720. 'use strict';
  100721. // Bail out if the browser doesn't support typed arrays, to prevent the setup function
  100722. // from failing, since we won't be able to create a WebGL context anyway.
  100723. if (!FeatureDetection.supportsTypedArrays()) {
  100724. return {};
  100725. }
  100726. var yUpToZUp = Matrix4.fromRotationTranslation(Matrix3.fromRotationX(CesiumMath.PI_OVER_TWO));
  100727. var boundingSphereCartesian3Scratch = new Cartesian3();
  100728. var ModelState = {
  100729. NEEDS_LOAD : 0,
  100730. LOADING : 1,
  100731. LOADED : 2, // Renderable, but textures can still be pending when incrementallyLoadTextures is true.
  100732. FAILED : 3
  100733. };
  100734. // GLTF_SPEC: Figure out correct mime types (https://github.com/KhronosGroup/glTF/issues/412)
  100735. var defaultModelAccept = 'model/vnd.gltf.binary,model/vnd.gltf+json,model/gltf.binary,model/gltf+json;q=0.8,application/json;q=0.2,*/*;q=0.01';
  100736. function LoadResources() {
  100737. this.buffersToCreate = new Queue();
  100738. this.buffers = {};
  100739. this.pendingBufferLoads = 0;
  100740. this.programsToCreate = new Queue();
  100741. this.shaders = {};
  100742. this.pendingShaderLoads = 0;
  100743. this.texturesToCreate = new Queue();
  100744. this.pendingTextureLoads = 0;
  100745. this.texturesToCreateFromBufferView = new Queue();
  100746. this.pendingBufferViewToImage = 0;
  100747. this.createSamplers = true;
  100748. this.createSkins = true;
  100749. this.createRuntimeAnimations = true;
  100750. this.createVertexArrays = true;
  100751. this.createRenderStates = true;
  100752. this.createUniformMaps = true;
  100753. this.createRuntimeNodes = true;
  100754. this.skinnedNodesIds = [];
  100755. }
  100756. LoadResources.prototype.getBuffer = function(bufferView) {
  100757. return getSubarray(this.buffers[bufferView.buffer], bufferView.byteOffset, bufferView.byteLength);
  100758. };
  100759. LoadResources.prototype.finishedPendingBufferLoads = function() {
  100760. return (this.pendingBufferLoads === 0);
  100761. };
  100762. LoadResources.prototype.finishedBuffersCreation = function() {
  100763. return ((this.pendingBufferLoads === 0) && (this.buffersToCreate.length === 0));
  100764. };
  100765. LoadResources.prototype.finishedProgramCreation = function() {
  100766. return ((this.pendingShaderLoads === 0) && (this.programsToCreate.length === 0));
  100767. };
  100768. LoadResources.prototype.finishedTextureCreation = function() {
  100769. var finishedPendingLoads = (this.pendingTextureLoads === 0);
  100770. var finishedResourceCreation =
  100771. (this.texturesToCreate.length === 0) &&
  100772. (this.texturesToCreateFromBufferView.length === 0);
  100773. return finishedPendingLoads && finishedResourceCreation;
  100774. };
  100775. LoadResources.prototype.finishedEverythingButTextureCreation = function() {
  100776. var finishedPendingLoads =
  100777. (this.pendingBufferLoads === 0) &&
  100778. (this.pendingShaderLoads === 0);
  100779. var finishedResourceCreation =
  100780. (this.buffersToCreate.length === 0) &&
  100781. (this.programsToCreate.length === 0) &&
  100782. (this.pendingBufferViewToImage === 0);
  100783. return finishedPendingLoads && finishedResourceCreation;
  100784. };
  100785. LoadResources.prototype.finished = function() {
  100786. return this.finishedTextureCreation() && this.finishedEverythingButTextureCreation();
  100787. };
  100788. ///////////////////////////////////////////////////////////////////////////
  100789. function setCachedGltf(model, cachedGltf) {
  100790. model._cachedGltf = cachedGltf;
  100791. model._animationIds = getAnimationIds(cachedGltf);
  100792. }
  100793. // glTF JSON can be big given embedded geometry, textures, and animations, so we
  100794. // cache it across all models using the same url/cache-key. This also reduces the
  100795. // slight overhead in assigning defaults to missing values.
  100796. //
  100797. // Note that this is a global cache, compared to renderer resources, which
  100798. // are cached per context.
  100799. function CachedGltf(options) {
  100800. this._gltf = modelMaterialsCommon(gltfDefaults(options.gltf));
  100801. this._bgltf = options.bgltf;
  100802. this.ready = options.ready;
  100803. this.modelsToLoad = [];
  100804. this.count = 0;
  100805. }
  100806. defineProperties(CachedGltf.prototype, {
  100807. gltf : {
  100808. set : function(value) {
  100809. this._gltf = modelMaterialsCommon(gltfDefaults(value));
  100810. },
  100811. get : function() {
  100812. return this._gltf;
  100813. }
  100814. },
  100815. bgltf : {
  100816. get : function() {
  100817. return this._bgltf;
  100818. }
  100819. }
  100820. });
  100821. CachedGltf.prototype.makeReady = function(gltfJson, bgltf) {
  100822. this.gltf = gltfJson;
  100823. this._bgltf = bgltf;
  100824. var models = this.modelsToLoad;
  100825. var length = models.length;
  100826. for (var i = 0; i < length; ++i) {
  100827. var m = models[i];
  100828. if (!m.isDestroyed()) {
  100829. setCachedGltf(m, this);
  100830. }
  100831. }
  100832. this.modelsToLoad = undefined;
  100833. this.ready = true;
  100834. };
  100835. function getAnimationIds(cachedGltf) {
  100836. var animationIds = [];
  100837. if (defined(cachedGltf) && defined(cachedGltf.gltf)) {
  100838. var animations = cachedGltf.gltf.animations;
  100839. for (var id in animations) {
  100840. if (animations.hasOwnProperty(id)) {
  100841. animationIds.push(id);
  100842. }
  100843. }
  100844. }
  100845. return animationIds;
  100846. }
  100847. var gltfCache = {};
  100848. ///////////////////////////////////////////////////////////////////////////
  100849. /**
  100850. * A 3D model based on glTF, the runtime asset format for WebGL, OpenGL ES, and OpenGL.
  100851. * <p>
  100852. * Cesium includes support for geometry and materials, glTF animations, and glTF skinning.
  100853. * In addition, individual glTF nodes are pickable with {@link Scene#pick} and animatable
  100854. * with {@link Model#getNode}. glTF cameras and lights are not currently supported.
  100855. * </p>
  100856. * <p>
  100857. * An external glTF asset is created with {@link Model.fromGltf}. glTF JSON can also be
  100858. * created at runtime and passed to this constructor function. In either case, the
  100859. * {@link Model#readyPromise} is resolved when the model is ready to render, i.e.,
  100860. * when the external binary, image, and shader files are downloaded and the WebGL
  100861. * resources are created.
  100862. * </p>
  100863. * <p>
  100864. * For high-precision rendering, Cesium supports the CESIUM_RTC extension, which introduces the
  100865. * CESIUM_RTC_MODELVIEW parameter semantic that says the node is in WGS84 coordinates translated
  100866. * relative to a local origin.
  100867. * </p>
  100868. *
  100869. * @alias Model
  100870. * @constructor
  100871. *
  100872. * @param {Object} [options] Object with the following properties:
  100873. * @param {Object|ArrayBuffer|Uint8Array} [options.gltf] The object for the glTF JSON or an arraybuffer of Binary glTF defined by the KHR_binary_glTF extension.
  100874. * @param {String} [options.basePath=''] The base path that paths in the glTF JSON are relative to.
  100875. * @param {Boolean} [options.show=true] Determines if the model primitive will be shown.
  100876. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms the model from model to world coordinates.
  100877. * @param {Number} [options.scale=1.0] A uniform scale applied to this model.
  100878. * @param {Number} [options.minimumPixelSize=0.0] The approximate minimum pixel size of the model regardless of zoom.
  100879. * @param {Number} [options.maximumScale] The maximum scale size of a model. An upper limit for minimumPixelSize.
  100880. * @param {Object} [options.id] A user-defined object to return when the model is picked with {@link Scene#pick}.
  100881. * @param {Boolean} [options.allowPicking=true] When <code>true</code>, each glTF mesh and primitive is pickable with {@link Scene#pick}.
  100882. * @param {Boolean} [options.incrementallyLoadTextures=true] Determine if textures may continue to stream in after the model is loaded.
  100883. * @param {Boolean} [options.asynchronous=true] Determines if model WebGL resource creation will be spread out over several frames or block until completion once all glTF files are loaded.
  100884. * @param {ShadowMode} [options.shadows=ShadowMode.ENABLED] Determines whether the model casts or receives shadows from each light source.
  100885. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Draws the bounding sphere for each draw command in the model.
  100886. * @param {Boolean} [options.debugWireframe=false] For debugging only. Draws the model in wireframe.
  100887. * @param {HeightReference} [options.heightReference] Determines how the model is drawn relative to terrain.
  100888. * @param {Scene} [options.scene] Must be passed in for models that use the height reference property.
  100889. * @param {DistanceDisplayCondition} [options.distanceDisplayCondition] The condition specifying at what distance from the camera that this model will be displayed.
  100890. * @param {Color} [options.color=Color.WHITE] A color that blends with the model's rendered color.
  100891. * @param {ColorBlendMode} [options.colorBlendMode=ColorBlendMode.HIGHLIGHT] Defines how the color blends with the model.
  100892. * @param {Number} [options.colorBlendAmount=0.5] Value used to determine the color strength when the <code>colorBlendMode</code> is <code>MIX</code>. A value of 0.0 results in the model's rendered color while a value of 1.0 results in a solid color, with any value in-between resulting in a mix of the two.
  100893. * @param {Color} [options.silhouetteColor=Color.RED] The silhouette color. If more than 256 models have silhouettes enabled, there is a small chance that overlapping models will have minor artifacts.
  100894. * @param {Number} [options.silhouetteSize=0.0] The size of the silhouette in pixels.
  100895. *
  100896. * @exception {DeveloperError} bgltf is not a valid Binary glTF file.
  100897. * @exception {DeveloperError} Only glTF Binary version 1 is supported.
  100898. *
  100899. * @see Model.fromGltf
  100900. *
  100901. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=3D%20Models.html|Cesium Sandcastle Models Demo}
  100902. */
  100903. function Model(options) {
  100904. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  100905. var cacheKey = options.cacheKey;
  100906. this._cacheKey = cacheKey;
  100907. this._cachedGltf = undefined;
  100908. this._releaseGltfJson = defaultValue(options.releaseGltfJson, false);
  100909. this._animationIds = undefined;
  100910. var cachedGltf;
  100911. if (defined(cacheKey) && defined(gltfCache[cacheKey]) && gltfCache[cacheKey].ready) {
  100912. // glTF JSON is in cache and ready
  100913. cachedGltf = gltfCache[cacheKey];
  100914. ++cachedGltf.count;
  100915. } else {
  100916. // glTF was explicitly provided, e.g., when a user uses the Model constructor directly
  100917. var gltf = options.gltf;
  100918. if (defined(gltf)) {
  100919. if (gltf instanceof ArrayBuffer) {
  100920. gltf = new Uint8Array(gltf);
  100921. }
  100922. if (gltf instanceof Uint8Array) {
  100923. // Binary glTF
  100924. var result = parseBinaryGltfHeader(gltf);
  100925. // KHR_binary_glTF is from the beginning of the binary section
  100926. if (result.binaryOffset !== 0) {
  100927. gltf = gltf.subarray(result.binaryOffset);
  100928. }
  100929. cachedGltf = new CachedGltf({
  100930. gltf : result.glTF,
  100931. bgltf : gltf,
  100932. ready : true
  100933. });
  100934. } else {
  100935. // Normal glTF (JSON)
  100936. cachedGltf = new CachedGltf({
  100937. gltf : options.gltf,
  100938. ready : true
  100939. });
  100940. }
  100941. cachedGltf.count = 1;
  100942. if (defined(cacheKey)) {
  100943. gltfCache[cacheKey] = cachedGltf;
  100944. }
  100945. }
  100946. }
  100947. setCachedGltf(this, cachedGltf);
  100948. this._basePath = defaultValue(options.basePath, '');
  100949. var docUri = new Uri(document.location.href);
  100950. var modelUri = new Uri(this._basePath);
  100951. this._baseUri = modelUri.resolve(docUri);
  100952. /**
  100953. * Determines if the model primitive will be shown.
  100954. *
  100955. * @type {Boolean}
  100956. *
  100957. * @default true
  100958. */
  100959. this.show = defaultValue(options.show, true);
  100960. /**
  100961. * The silhouette color.
  100962. *
  100963. * @type {Color}
  100964. *
  100965. * @default Color.RED
  100966. */
  100967. this.silhouetteColor = defaultValue(options.silhouetteColor, Color.RED);
  100968. this._silhouetteColor = new Color();
  100969. this._normalAttributeName = undefined;
  100970. /**
  100971. * The size of the silhouette in pixels.
  100972. *
  100973. * @type {Number}
  100974. *
  100975. * @default 0.0
  100976. */
  100977. this.silhouetteSize = defaultValue(options.silhouetteSize, 0.0);
  100978. /**
  100979. * The 4x4 transformation matrix that transforms the model from model to world coordinates.
  100980. * When this is the identity matrix, the model is drawn in world coordinates, i.e., Earth's WGS84 coordinates.
  100981. * Local reference frames can be used by providing a different transformation matrix, like that returned
  100982. * by {@link Transforms.eastNorthUpToFixedFrame}.
  100983. *
  100984. * @type {Matrix4}
  100985. *
  100986. * @default {@link Matrix4.IDENTITY}
  100987. *
  100988. * @example
  100989. * var origin = Cesium.Cartesian3.fromDegrees(-95.0, 40.0, 200000.0);
  100990. * m.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin);
  100991. */
  100992. this.modelMatrix = Matrix4.clone(defaultValue(options.modelMatrix, Matrix4.IDENTITY));
  100993. this._modelMatrix = Matrix4.clone(this.modelMatrix);
  100994. this._clampedModelMatrix = undefined;
  100995. /**
  100996. * A uniform scale applied to this model before the {@link Model#modelMatrix}.
  100997. * Values greater than <code>1.0</code> increase the size of the model; values
  100998. * less than <code>1.0</code> decrease.
  100999. *
  101000. * @type {Number}
  101001. *
  101002. * @default 1.0
  101003. */
  101004. this.scale = defaultValue(options.scale, 1.0);
  101005. this._scale = this.scale;
  101006. /**
  101007. * The approximate minimum pixel size of the model regardless of zoom.
  101008. * This can be used to ensure that a model is visible even when the viewer
  101009. * zooms out. When <code>0.0</code>, no minimum size is enforced.
  101010. *
  101011. * @type {Number}
  101012. *
  101013. * @default 0.0
  101014. */
  101015. this.minimumPixelSize = defaultValue(options.minimumPixelSize, 0.0);
  101016. this._minimumPixelSize = this.minimumPixelSize;
  101017. /**
  101018. * The maximum scale size for a model. This can be used to give
  101019. * an upper limit to the {@link Model#minimumPixelSize}, ensuring that the model
  101020. * is never an unreasonable scale.
  101021. *
  101022. * @type {Number}
  101023. */
  101024. this.maximumScale = options.maximumScale;
  101025. this._maximumScale = this.maximumScale;
  101026. /**
  101027. * User-defined object returned when the model is picked.
  101028. *
  101029. * @type Object
  101030. *
  101031. * @default undefined
  101032. *
  101033. * @see Scene#pick
  101034. */
  101035. this.id = options.id;
  101036. this._id = options.id;
  101037. /**
  101038. * Returns the height reference of the model
  101039. *
  101040. * @memberof Model.prototype
  101041. *
  101042. * @type {HeightReference}
  101043. *
  101044. * @default HeightReference.NONE
  101045. */
  101046. this.heightReference = defaultValue(options.heightReference, HeightReference.NONE);
  101047. this._heightReference = this.heightReference;
  101048. this._heightChanged = false;
  101049. this._removeUpdateHeightCallback = undefined;
  101050. var scene = options.scene;
  101051. this._scene = scene;
  101052. if (defined(scene)) {
  101053. scene.terrainProviderChanged.addEventListener(function() {
  101054. this._heightChanged = true;
  101055. }, this);
  101056. }
  101057. /**
  101058. * Used for picking primitives that wrap a model.
  101059. *
  101060. * @private
  101061. */
  101062. this.pickPrimitive = options.pickPrimitive;
  101063. this._allowPicking = defaultValue(options.allowPicking, true);
  101064. this._ready = false;
  101065. this._readyPromise = when.defer();
  101066. /**
  101067. * The currently playing glTF animations.
  101068. *
  101069. * @type {ModelAnimationCollection}
  101070. */
  101071. this.activeAnimations = new ModelAnimationCollection(this);
  101072. this._defaultTexture = undefined;
  101073. this._incrementallyLoadTextures = defaultValue(options.incrementallyLoadTextures, true);
  101074. this._asynchronous = defaultValue(options.asynchronous, true);
  101075. /**
  101076. * Determines whether the model casts or receives shadows from each light source.
  101077. *
  101078. * @type {ShadowMode}
  101079. *
  101080. * @default ShadowMode.ENABLED
  101081. */
  101082. this.shadows = defaultValue(options.shadows, ShadowMode.ENABLED);
  101083. this._shadows = this.shadows;
  101084. /**
  101085. * A color that blends with the model's rendered color.
  101086. *
  101087. * @type {Color}
  101088. *
  101089. * @default Color.WHITE
  101090. */
  101091. this.color = defaultValue(options.color, Color.WHITE);
  101092. this._color = new Color();
  101093. /**
  101094. * Defines how the color blends with the model.
  101095. *
  101096. * @type {ColorBlendMode}
  101097. *
  101098. * @default ColorBlendMode.HIGHLIGHT
  101099. */
  101100. this.colorBlendMode = defaultValue(options.colorBlendMode, ColorBlendMode.HIGHLIGHT);
  101101. /**
  101102. * Value used to determine the color strength when the <code>colorBlendMode</code> is <code>MIX</code>.
  101103. * A value of 0.0 results in the model's rendered color while a value of 1.0 results in a solid color, with
  101104. * any value in-between resulting in a mix of the two.
  101105. *
  101106. * @type {Number}
  101107. *
  101108. * @default 0.5
  101109. */
  101110. this.colorBlendAmount = defaultValue(options.colorBlendAmount, 0.5);
  101111. /**
  101112. * This property is for debugging only; it is not for production use nor is it optimized.
  101113. * <p>
  101114. * Draws the bounding sphere for each draw command in the model. A glTF primitive corresponds
  101115. * to one draw command. A glTF mesh has an array of primitives, often of length one.
  101116. * </p>
  101117. *
  101118. * @type {Boolean}
  101119. *
  101120. * @default false
  101121. */
  101122. this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false);
  101123. this._debugShowBoundingVolume = false;
  101124. /**
  101125. * This property is for debugging only; it is not for production use nor is it optimized.
  101126. * <p>
  101127. * Draws the model in wireframe.
  101128. * </p>
  101129. *
  101130. * @type {Boolean}
  101131. *
  101132. * @default false
  101133. */
  101134. this.debugWireframe = defaultValue(options.debugWireframe, false);
  101135. this._debugWireframe = false;
  101136. this._distanceDisplayCondition = options.distanceDisplayCondition;
  101137. // Undocumented options
  101138. this._precreatedAttributes = options.precreatedAttributes;
  101139. this._vertexShaderLoaded = options.vertexShaderLoaded;
  101140. this._fragmentShaderLoaded = options.fragmentShaderLoaded;
  101141. this._uniformMapLoaded = options.uniformMapLoaded;
  101142. this._pickVertexShaderLoaded = options.pickVertexShaderLoaded;
  101143. this._pickFragmentShaderLoaded = options.pickFragmentShaderLoaded;
  101144. this._pickUniformMapLoaded = options.pickUniformMapLoaded;
  101145. this._ignoreCommands = defaultValue(options.ignoreCommands, false);
  101146. /**
  101147. * @private
  101148. * @readonly
  101149. */
  101150. this.cull = defaultValue(options.cull, true);
  101151. this._computedModelMatrix = new Matrix4(); // Derived from modelMatrix and scale
  101152. this._initialRadius = undefined; // Radius without model's scale property, model-matrix scale, animations, or skins
  101153. this._boundingSphere = undefined;
  101154. this._scaledBoundingSphere = new BoundingSphere();
  101155. this._state = ModelState.NEEDS_LOAD;
  101156. this._loadResources = undefined;
  101157. this._mode = undefined;
  101158. this._perNodeShowDirty = false; // true when the Cesium API was used to change a node's show property
  101159. this._cesiumAnimationsDirty = false; // true when the Cesium API, not a glTF animation, changed a node transform
  101160. this._dirty = false; // true when the model was transformed this frame
  101161. this._maxDirtyNumber = 0; // Used in place of a dirty boolean flag to avoid an extra graph traversal
  101162. this._runtime = {
  101163. animations : undefined,
  101164. rootNodes : undefined,
  101165. nodes : undefined, // Indexed with the node property's name, i.e., glTF id
  101166. nodesByName : undefined, // Indexed with name property in the node
  101167. skinnedNodes : undefined,
  101168. meshesByName : undefined, // Indexed with the name property in the mesh
  101169. materialsByName : undefined, // Indexed with the name property in the material
  101170. materialsById : undefined // Indexed with the material's property name
  101171. };
  101172. this._uniformMaps = {}; // Not cached since it can be targeted by glTF animation
  101173. this._extensionsUsed = undefined; // Cached used extensions in a hash-map so we don't have to search the gltf array
  101174. this._quantizedUniforms = {}; // Quantized uniforms for each program for WEB3D_quantized_attributes
  101175. this._programPrimitives = {};
  101176. this._rendererResources = { // Cached between models with the same url/cache-key
  101177. buffers : {},
  101178. vertexArrays : {},
  101179. programs : {},
  101180. pickPrograms : {},
  101181. silhouettePrograms: {},
  101182. textures : {},
  101183. samplers : {},
  101184. renderStates : {}
  101185. };
  101186. this._cachedRendererResources = undefined;
  101187. this._loadRendererResourcesFromCache = false;
  101188. this._nodeCommands = [];
  101189. this._pickIds = [];
  101190. // CESIUM_RTC extension
  101191. this._rtcCenter = undefined; // in world coordinates
  101192. this._rtcCenterEye = undefined; // in eye coordinates
  101193. }
  101194. defineProperties(Model.prototype, {
  101195. /**
  101196. * The object for the glTF JSON, including properties with default values omitted
  101197. * from the JSON provided to this model.
  101198. *
  101199. * @memberof Model.prototype
  101200. *
  101201. * @type {Object}
  101202. * @readonly
  101203. *
  101204. * @default undefined
  101205. */
  101206. gltf : {
  101207. get : function() {
  101208. return defined(this._cachedGltf) ? this._cachedGltf.gltf : undefined;
  101209. }
  101210. },
  101211. /**
  101212. * When <code>true</code>, the glTF JSON is not stored with the model once the model is
  101213. * loaded (when {@link Model#ready} is <code>true</code>). This saves memory when
  101214. * geometry, textures, and animations are embedded in the .gltf file, which is the
  101215. * default for the {@link http://cesiumjs.org/convertmodel.html|Cesium model converter}.
  101216. * This is especially useful for cases like 3D buildings, where each .gltf model is unique
  101217. * and caching the glTF JSON is not effective.
  101218. *
  101219. * @memberof Model.prototype
  101220. *
  101221. * @type {Boolean}
  101222. * @readonly
  101223. *
  101224. * @default false
  101225. *
  101226. * @private
  101227. */
  101228. releaseGltfJson : {
  101229. get : function() {
  101230. return this._releaseGltfJson;
  101231. }
  101232. },
  101233. /**
  101234. * The key identifying this model in the model cache for glTF JSON, renderer resources, and animations.
  101235. * Caching saves memory and improves loading speed when several models with the same url are created.
  101236. * <p>
  101237. * This key is automatically generated when the model is created with {@link Model.fromGltf}. If the model
  101238. * is created directly from glTF JSON using the {@link Model} constructor, this key can be manually
  101239. * provided; otherwise, the model will not be changed.
  101240. * </p>
  101241. *
  101242. * @memberof Model.prototype
  101243. *
  101244. * @type {String}
  101245. * @readonly
  101246. *
  101247. * @private
  101248. */
  101249. cacheKey : {
  101250. get : function() {
  101251. return this._cacheKey;
  101252. }
  101253. },
  101254. /**
  101255. * The base path that paths in the glTF JSON are relative to. The base
  101256. * path is the same path as the path containing the .gltf file
  101257. * minus the .gltf file, when binary, image, and shader files are
  101258. * in the same directory as the .gltf. When this is <code>''</code>,
  101259. * the app's base path is used.
  101260. *
  101261. * @memberof Model.prototype
  101262. *
  101263. * @type {String}
  101264. * @readonly
  101265. *
  101266. * @default ''
  101267. */
  101268. basePath : {
  101269. get : function() {
  101270. return this._basePath;
  101271. }
  101272. },
  101273. /**
  101274. * The model's bounding sphere in its local coordinate system. This does not take into
  101275. * account glTF animations and skins nor does it take into account {@link Model#minimumPixelSize}.
  101276. *
  101277. * @memberof Model.prototype
  101278. *
  101279. * @type {BoundingSphere}
  101280. * @readonly
  101281. *
  101282. * @default undefined
  101283. *
  101284. * @exception {DeveloperError} The model is not loaded. Use Model.readyPromise or wait for Model.ready to be true.
  101285. *
  101286. * @example
  101287. * // Center in WGS84 coordinates
  101288. * var center = Cesium.Matrix4.multiplyByPoint(model.modelMatrix, model.boundingSphere.center, new Cesium.Cartesian3());
  101289. */
  101290. boundingSphere : {
  101291. get : function() {
  101292. if (this._state !== ModelState.LOADED) {
  101293. throw new DeveloperError('The model is not loaded. Use Model.readyPromise or wait for Model.ready to be true.');
  101294. }
  101295. var modelMatrix = this.modelMatrix;
  101296. if ((this.heightReference !== HeightReference.NONE) && this._clampedModelMatrix) {
  101297. modelMatrix = this._clampedModelMatrix;
  101298. }
  101299. var nonUniformScale = Matrix4.getScale(modelMatrix, boundingSphereCartesian3Scratch);
  101300. var scale = defined(this.maximumScale) ? Math.min(this.maximumScale, this.scale) : this.scale;
  101301. Cartesian3.multiplyByScalar(nonUniformScale, scale, nonUniformScale);
  101302. var scaledBoundingSphere = this._scaledBoundingSphere;
  101303. scaledBoundingSphere.center = Cartesian3.multiplyComponents(this._boundingSphere.center, nonUniformScale, scaledBoundingSphere.center);
  101304. scaledBoundingSphere.radius = Cartesian3.maximumComponent(nonUniformScale) * this._initialRadius;
  101305. if (defined(this._rtcCenter)) {
  101306. Cartesian3.add(this._rtcCenter, scaledBoundingSphere.center, scaledBoundingSphere.center);
  101307. }
  101308. return scaledBoundingSphere;
  101309. }
  101310. },
  101311. /**
  101312. * When <code>true</code>, this model is ready to render, i.e., the external binary, image,
  101313. * and shader files were downloaded and the WebGL resources were created. This is set to
  101314. * <code>true</code> right before {@link Model#readyPromise} is resolved.
  101315. *
  101316. * @memberof Model.prototype
  101317. *
  101318. * @type {Boolean}
  101319. * @readonly
  101320. *
  101321. * @default false
  101322. */
  101323. ready : {
  101324. get : function() {
  101325. return this._ready;
  101326. }
  101327. },
  101328. /**
  101329. * Gets the promise that will be resolved when this model is ready to render, i.e., when the external binary, image,
  101330. * and shader files were downloaded and the WebGL resources were created.
  101331. * <p>
  101332. * This promise is resolved at the end of the frame before the first frame the model is rendered in.
  101333. * </p>
  101334. *
  101335. * @memberof Model.prototype
  101336. * @type {Promise.<Model>}
  101337. * @readonly
  101338. *
  101339. * @example
  101340. * // Play all animations at half-speed when the model is ready to render
  101341. * Cesium.when(model.readyPromise).then(function(model) {
  101342. * model.activeAnimations.addAll({
  101343. * speedup : 0.5
  101344. * });
  101345. * }).otherwise(function(error){
  101346. * window.alert(error);
  101347. * });
  101348. *
  101349. * @see Model#ready
  101350. */
  101351. readyPromise : {
  101352. get : function() {
  101353. return this._readyPromise.promise;
  101354. }
  101355. },
  101356. /**
  101357. * Determines if model WebGL resource creation will be spread out over several frames or
  101358. * block until completion once all glTF files are loaded.
  101359. *
  101360. * @memberof Model.prototype
  101361. *
  101362. * @type {Boolean}
  101363. * @readonly
  101364. *
  101365. * @default true
  101366. */
  101367. asynchronous : {
  101368. get : function() {
  101369. return this._asynchronous;
  101370. }
  101371. },
  101372. /**
  101373. * When <code>true</code>, each glTF mesh and primitive is pickable with {@link Scene#pick}. When <code>false</code>, GPU memory is saved.
  101374. *
  101375. * @memberof Model.prototype
  101376. *
  101377. * @type {Boolean}
  101378. * @readonly
  101379. *
  101380. * @default true
  101381. */
  101382. allowPicking : {
  101383. get : function() {
  101384. return this._allowPicking;
  101385. }
  101386. },
  101387. /**
  101388. * Determine if textures may continue to stream in after the model is loaded.
  101389. *
  101390. * @memberof Model.prototype
  101391. *
  101392. * @type {Boolean}
  101393. * @readonly
  101394. *
  101395. * @default true
  101396. */
  101397. incrementallyLoadTextures : {
  101398. get : function() {
  101399. return this._incrementallyLoadTextures;
  101400. }
  101401. },
  101402. /**
  101403. * Return the number of pending texture loads.
  101404. *
  101405. * @memberof Model.prototype
  101406. *
  101407. * @type {Number}
  101408. * @readonly
  101409. */
  101410. pendingTextureLoads : {
  101411. get : function() {
  101412. return defined(this._loadResources) ? this._loadResources.pendingTextureLoads : 0;
  101413. }
  101414. },
  101415. /**
  101416. * Returns true if the model was transformed this frame
  101417. *
  101418. * @memberof Model.prototype
  101419. *
  101420. * @type {Boolean}
  101421. * @readonly
  101422. *
  101423. * @private
  101424. */
  101425. dirty : {
  101426. get : function() {
  101427. return this._dirty;
  101428. }
  101429. },
  101430. /**
  101431. * Gets or sets the condition specifying at what distance from the camera that this model will be displayed.
  101432. * @memberof Model.prototype
  101433. * @type {DistanceDisplayCondition}
  101434. * @default undefined
  101435. */
  101436. distanceDisplayCondition : {
  101437. get : function() {
  101438. return this._distanceDisplayCondition;
  101439. },
  101440. set : function(value) {
  101441. if (defined(value) && value.far <= value.near) {
  101442. throw new DeveloperError('far must be greater than near');
  101443. }
  101444. this._distanceDisplayCondition = DistanceDisplayCondition.clone(value, this._distanceDisplayCondition);
  101445. }
  101446. }
  101447. });
  101448. var sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT;
  101449. function silhouetteSupported(context) {
  101450. return context.stencilBuffer;
  101451. }
  101452. /**
  101453. * Determines if silhouettes are supported.
  101454. *
  101455. * @param {Scene} scene The scene.
  101456. * @returns {Boolean} <code>true</code> if silhouettes are supported; otherwise, returns <code>false</code>
  101457. */
  101458. Model.silhouetteSupported = function(scene) {
  101459. return silhouetteSupported(scene.context);
  101460. };
  101461. /**
  101462. * This function differs from the normal subarray function
  101463. * because it takes offset and length, rather than begin and end.
  101464. */
  101465. function getSubarray(array, offset, length) {
  101466. return array.subarray(offset, offset + length);
  101467. }
  101468. function containsGltfMagic(uint8Array) {
  101469. var magic = getMagic(uint8Array);
  101470. return magic === 'glTF';
  101471. }
  101472. function parseBinaryGltfHeader(uint8Array) {
  101473. if (!containsGltfMagic(uint8Array)) {
  101474. throw new DeveloperError('bgltf is not a valid Binary glTF file.');
  101475. }
  101476. var view = new DataView(uint8Array.buffer, uint8Array.byteOffset, uint8Array.byteLength);
  101477. var byteOffset = 0;
  101478. byteOffset += sizeOfUint32; // Skip magic number
  101479. var version = view.getUint32(byteOffset, true);
  101480. if (version !== 1) {
  101481. throw new DeveloperError('Only Binary glTF version 1 is supported. Version ' + version + ' is not.');
  101482. }
  101483. byteOffset += sizeOfUint32;
  101484. byteOffset += sizeOfUint32; // Skip length
  101485. var sceneLength = view.getUint32(byteOffset, true);
  101486. byteOffset += sizeOfUint32 + sizeOfUint32; // Skip sceneFormat
  101487. var sceneOffset = byteOffset;
  101488. var binOffset = sceneOffset + sceneLength;
  101489. var json = getStringFromTypedArray(uint8Array, sceneOffset, sceneLength);
  101490. return {
  101491. glTF: JSON.parse(json),
  101492. binaryOffset: binOffset
  101493. };
  101494. }
  101495. /**
  101496. * <p>
  101497. * Creates a model from a glTF asset. When the model is ready to render, i.e., when the external binary, image,
  101498. * and shader files are downloaded and the WebGL resources are created, the {@link Model#readyPromise} is resolved.
  101499. * </p>
  101500. * <p>
  101501. * The model can be a traditional glTF asset with a .gltf extension or a Binary glTF using the
  101502. * KHR_binary_glTF extension with a .glb extension.
  101503. * </p>
  101504. * <p>
  101505. * For high-precision rendering, Cesium supports the CESIUM_RTC extension, which introduces the
  101506. * CESIUM_RTC_MODELVIEW parameter semantic that says the node is in WGS84 coordinates translated
  101507. * relative to a local origin.
  101508. * </p>
  101509. *
  101510. * @param {Object} options Object with the following properties:
  101511. * @param {String} options.url The url to the .gltf file.
  101512. * @param {Object} [options.headers] HTTP headers to send with the request.
  101513. * @param {Boolean} [options.show=true] Determines if the model primitive will be shown.
  101514. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms the model from model to world coordinates.
  101515. * @param {Number} [options.scale=1.0] A uniform scale applied to this model.
  101516. * @param {Number} [options.minimumPixelSize=0.0] The approximate minimum pixel size of the model regardless of zoom.
  101517. * @param {Number} [options.maximumScale] The maximum scale for the model.
  101518. * @param {Object} [options.id] A user-defined object to return when the model is picked with {@link Scene#pick}.
  101519. * @param {Boolean} [options.allowPicking=true] When <code>true</code>, each glTF mesh and primitive is pickable with {@link Scene#pick}.
  101520. * @param {Boolean} [options.incrementallyLoadTextures=true] Determine if textures may continue to stream in after the model is loaded.
  101521. * @param {Boolean} [options.asynchronous=true] Determines if model WebGL resource creation will be spread out over several frames or block until completion once all glTF files are loaded.
  101522. * @param {ShadowMode} [options.shadows=ShadowMode.ENABLED] Determines whether the model casts or receives shadows from each light source.
  101523. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Draws the bounding sphere for each {@link DrawCommand} in the model.
  101524. * @param {Boolean} [options.debugWireframe=false] For debugging only. Draws the model in wireframe.
  101525. *
  101526. * @returns {Model} The newly created model.
  101527. *
  101528. * @exception {DeveloperError} bgltf is not a valid Binary glTF file.
  101529. * @exception {DeveloperError} Only glTF Binary version 1 is supported.
  101530. *
  101531. * @example
  101532. * // Example 1. Create a model from a glTF asset
  101533. * var model = scene.primitives.add(Cesium.Model.fromGltf({
  101534. * url : './duck/duck.gltf'
  101535. * }));
  101536. *
  101537. * @example
  101538. * // Example 2. Create model and provide all properties and events
  101539. * var origin = Cesium.Cartesian3.fromDegrees(-95.0, 40.0, 200000.0);
  101540. * var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin);
  101541. *
  101542. * var model = scene.primitives.add(Cesium.Model.fromGltf({
  101543. * url : './duck/duck.gltf',
  101544. * show : true, // default
  101545. * modelMatrix : modelMatrix,
  101546. * scale : 2.0, // double size
  101547. * minimumPixelSize : 128, // never smaller than 128 pixels
  101548. * maximumScale: 20000, // never larger than 20000 * model size (overrides minimumPixelSize)
  101549. * allowPicking : false, // not pickable
  101550. * debugShowBoundingVolume : false, // default
  101551. * debugWireframe : false
  101552. * }));
  101553. *
  101554. * model.readyPromise.then(function(model) {
  101555. * // Play all animations when the model is ready to render
  101556. * model.activeAnimations.addAll();
  101557. * });
  101558. */
  101559. Model.fromGltf = function(options) {
  101560. if (!defined(options) || !defined(options.url)) {
  101561. throw new DeveloperError('options.url is required');
  101562. }
  101563. var url = options.url;
  101564. // If no cache key is provided, use the absolute URL, since two URLs with
  101565. // different relative paths could point to the same model.
  101566. var cacheKey = defaultValue(options.cacheKey, getAbsoluteUri(url));
  101567. options = clone(options);
  101568. options.basePath = getBaseUri(url);
  101569. options.cacheKey = cacheKey;
  101570. var model = new Model(options);
  101571. options.headers = defined(options.headers) ? clone(options.headers) : {};
  101572. if (!defined(options.headers.Accept)) {
  101573. options.headers.Accept = defaultModelAccept;
  101574. }
  101575. var cachedGltf = gltfCache[cacheKey];
  101576. if (!defined(cachedGltf)) {
  101577. cachedGltf = new CachedGltf({
  101578. ready : false
  101579. });
  101580. cachedGltf.count = 1;
  101581. cachedGltf.modelsToLoad.push(model);
  101582. setCachedGltf(model, cachedGltf);
  101583. gltfCache[cacheKey] = cachedGltf;
  101584. loadArrayBuffer(url, options.headers).then(function(arrayBuffer) {
  101585. var array = new Uint8Array(arrayBuffer);
  101586. if (containsGltfMagic(array)) {
  101587. // Load binary glTF
  101588. var result = parseBinaryGltfHeader(array);
  101589. // KHR_binary_glTF is from the beginning of the binary section
  101590. if (result.binaryOffset !== 0) {
  101591. array = array.subarray(result.binaryOffset);
  101592. }
  101593. cachedGltf.makeReady(result.glTF, array);
  101594. } else {
  101595. // Load text (JSON) glTF
  101596. var json = getStringFromTypedArray(array);
  101597. cachedGltf.makeReady(JSON.parse(json));
  101598. }
  101599. }).otherwise(getFailedLoadFunction(model, 'model', url));
  101600. } else if (!cachedGltf.ready) {
  101601. // Cache hit but the loadArrayBuffer() or loadText() request is still pending
  101602. ++cachedGltf.count;
  101603. cachedGltf.modelsToLoad.push(model);
  101604. }
  101605. // else if the cached glTF is defined and ready, the
  101606. // model constructor will pick it up using the cache key.
  101607. return model;
  101608. };
  101609. /**
  101610. * For the unit tests to verify model caching.
  101611. *
  101612. * @private
  101613. */
  101614. Model._gltfCache = gltfCache;
  101615. function getRuntime(model, runtimeName, name) {
  101616. if (model._state !== ModelState.LOADED) {
  101617. throw new DeveloperError('The model is not loaded. Use Model.readyPromise or wait for Model.ready to be true.');
  101618. }
  101619. if (!defined(name)) {
  101620. throw new DeveloperError('name is required.');
  101621. }
  101622. return (model._runtime[runtimeName])[name];
  101623. }
  101624. /**
  101625. * Returns the glTF node with the given <code>name</code> property. This is used to
  101626. * modify a node's transform for animation outside of glTF animations.
  101627. *
  101628. * @param {String} name The glTF name of the node.
  101629. * @returns {ModelNode} The node or <code>undefined</code> if no node with <code>name</code> exists.
  101630. *
  101631. * @exception {DeveloperError} The model is not loaded. Use Model.readyPromise or wait for Model.ready to be true.
  101632. *
  101633. * @example
  101634. * // Apply non-uniform scale to node LOD3sp
  101635. * var node = model.getNode('LOD3sp');
  101636. * node.matrix = Cesium.Matrix4.fromScale(new Cesium.Cartesian3(5.0, 1.0, 1.0), node.matrix);
  101637. */
  101638. Model.prototype.getNode = function(name) {
  101639. var node = getRuntime(this, 'nodesByName', name);
  101640. return defined(node) ? node.publicNode : undefined;
  101641. };
  101642. /**
  101643. * Returns the glTF mesh with the given <code>name</code> property.
  101644. *
  101645. * @param {String} name The glTF name of the mesh.
  101646. *
  101647. * @returns {ModelMesh} The mesh or <code>undefined</code> if no mesh with <code>name</code> exists.
  101648. *
  101649. * @exception {DeveloperError} The model is not loaded. Use Model.readyPromise or wait for Model.ready to be true.
  101650. */
  101651. Model.prototype.getMesh = function(name) {
  101652. return getRuntime(this, 'meshesByName', name);
  101653. };
  101654. /**
  101655. * Returns the glTF material with the given <code>name</code> property.
  101656. *
  101657. * @param {String} name The glTF name of the material.
  101658. * @returns {ModelMaterial} The material or <code>undefined</code> if no material with <code>name</code> exists.
  101659. *
  101660. * @exception {DeveloperError} The model is not loaded. Use Model.readyPromise or wait for Model.ready to be true.
  101661. */
  101662. Model.prototype.getMaterial = function(name) {
  101663. return getRuntime(this, 'materialsByName', name);
  101664. };
  101665. var aMinScratch = new Cartesian3();
  101666. var aMaxScratch = new Cartesian3();
  101667. function getAccessorMinMax(gltf, accessorId) {
  101668. var accessor = gltf.accessors[accessorId];
  101669. var extensions = accessor.extensions;
  101670. var accessorMin = accessor.min;
  101671. var accessorMax = accessor.max;
  101672. // If this accessor is quantized, we should use the decoded min and max
  101673. if (defined(extensions)) {
  101674. var quantizedAttributes = extensions.WEB3D_quantized_attributes;
  101675. if (defined(quantizedAttributes)) {
  101676. accessorMin = quantizedAttributes.decodedMin;
  101677. accessorMax = quantizedAttributes.decodedMax;
  101678. }
  101679. }
  101680. return {
  101681. min : accessorMin,
  101682. max : accessorMax
  101683. };
  101684. }
  101685. function computeBoundingSphere(gltf) {
  101686. var gltfNodes = gltf.nodes;
  101687. var gltfMeshes = gltf.meshes;
  101688. var rootNodes = gltf.scenes[gltf.scene].nodes;
  101689. var rootNodesLength = rootNodes.length;
  101690. var nodeStack = [];
  101691. var min = new Cartesian3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  101692. var max = new Cartesian3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
  101693. for (var i = 0; i < rootNodesLength; ++i) {
  101694. var n = gltfNodes[rootNodes[i]];
  101695. n._transformToRoot = getTransform(n);
  101696. nodeStack.push(n);
  101697. while (nodeStack.length > 0) {
  101698. n = nodeStack.pop();
  101699. var transformToRoot = n._transformToRoot;
  101700. var meshes = n.meshes;
  101701. if (defined(meshes)) {
  101702. var meshesLength = meshes.length;
  101703. for (var j = 0; j < meshesLength; ++j) {
  101704. var primitives = gltfMeshes[meshes[j]].primitives;
  101705. var primitivesLength = primitives.length;
  101706. for (var m = 0; m < primitivesLength; ++m) {
  101707. var positionAccessor = primitives[m].attributes.POSITION;
  101708. if (defined(positionAccessor)) {
  101709. var minMax = getAccessorMinMax(gltf, positionAccessor);
  101710. var aMin = Cartesian3.fromArray(minMax.min, 0, aMinScratch);
  101711. var aMax = Cartesian3.fromArray(minMax.max, 0, aMaxScratch);
  101712. if (defined(min) && defined(max)) {
  101713. Matrix4.multiplyByPoint(transformToRoot, aMin, aMin);
  101714. Matrix4.multiplyByPoint(transformToRoot, aMax, aMax);
  101715. Cartesian3.minimumByComponent(min, aMin, min);
  101716. Cartesian3.maximumByComponent(max, aMax, max);
  101717. }
  101718. }
  101719. }
  101720. }
  101721. }
  101722. var children = n.children;
  101723. var childrenLength = children.length;
  101724. for (var k = 0; k < childrenLength; ++k) {
  101725. var child = gltfNodes[children[k]];
  101726. child._transformToRoot = getTransform(child);
  101727. Matrix4.multiplyTransformation(transformToRoot, child._transformToRoot, child._transformToRoot);
  101728. nodeStack.push(child);
  101729. }
  101730. delete n._transformToRoot;
  101731. }
  101732. }
  101733. var boundingSphere = BoundingSphere.fromCornerPoints(min, max);
  101734. return BoundingSphere.transformWithoutScale(boundingSphere, yUpToZUp, boundingSphere);
  101735. }
  101736. ///////////////////////////////////////////////////////////////////////////
  101737. function getFailedLoadFunction(model, type, path) {
  101738. return function() {
  101739. model._state = ModelState.FAILED;
  101740. model._readyPromise.reject(new RuntimeError('Failed to load ' + type + ': ' + path));
  101741. };
  101742. }
  101743. function bufferLoad(model, id) {
  101744. return function(arrayBuffer) {
  101745. var loadResources = model._loadResources;
  101746. loadResources.buffers[id] = new Uint8Array(arrayBuffer);
  101747. --loadResources.pendingBufferLoads;
  101748. };
  101749. }
  101750. function parseBuffers(model) {
  101751. var buffers = model.gltf.buffers;
  101752. for (var id in buffers) {
  101753. if (buffers.hasOwnProperty(id)) {
  101754. var buffer = buffers[id];
  101755. // The extension 'KHR_binary_glTF' uses a special buffer entitled just 'binary_glTF'.
  101756. // The 'KHR_binary_glTF' check is for backwards compatibility for the Cesium model converter
  101757. // circa Cesium 1.15-1.20 when the converter incorrectly used the buffer name 'KHR_binary_glTF'.
  101758. if ((id === 'binary_glTF') || (id === 'KHR_binary_glTF')) {
  101759. // Buffer is the binary glTF file itself that is already loaded
  101760. var loadResources = model._loadResources;
  101761. loadResources.buffers[id] = model._cachedGltf.bgltf;
  101762. }
  101763. else if (buffer.type === 'arraybuffer') {
  101764. ++model._loadResources.pendingBufferLoads;
  101765. var uri = new Uri(buffer.uri);
  101766. var bufferPath = uri.resolve(model._baseUri).toString();
  101767. loadArrayBuffer(bufferPath).then(bufferLoad(model, id)).otherwise(getFailedLoadFunction(model, 'buffer', bufferPath));
  101768. }
  101769. }
  101770. }
  101771. }
  101772. function parseBufferViews(model) {
  101773. var bufferViews = model.gltf.bufferViews;
  101774. for (var id in bufferViews) {
  101775. if (bufferViews.hasOwnProperty(id)) {
  101776. if (bufferViews[id].target === WebGLConstants.ARRAY_BUFFER) {
  101777. model._loadResources.buffersToCreate.enqueue(id);
  101778. }
  101779. }
  101780. }
  101781. }
  101782. function shaderLoad(model, id) {
  101783. return function(source) {
  101784. var loadResources = model._loadResources;
  101785. loadResources.shaders[id] = {
  101786. source : source,
  101787. bufferView : undefined
  101788. };
  101789. --loadResources.pendingShaderLoads;
  101790. };
  101791. }
  101792. function parseShaders(model) {
  101793. var shaders = model.gltf.shaders;
  101794. for (var id in shaders) {
  101795. if (shaders.hasOwnProperty(id)) {
  101796. var shader = shaders[id];
  101797. // Shader references either uri (external or base64-encoded) or bufferView
  101798. if (defined(shader.extras) && defined(shader.extras.source)) {
  101799. model._loadResources.shaders[id] = {
  101800. source : shader.extras.source,
  101801. bufferView : undefined
  101802. };
  101803. }
  101804. else if (defined(shader.extensions) && defined(shader.extensions.KHR_binary_glTF)) {
  101805. var binary = shader.extensions.KHR_binary_glTF;
  101806. model._loadResources.shaders[id] = {
  101807. source : undefined,
  101808. bufferView : binary.bufferView
  101809. };
  101810. } else {
  101811. ++model._loadResources.pendingShaderLoads;
  101812. var uri = new Uri(shader.uri);
  101813. var shaderPath = uri.resolve(model._baseUri).toString();
  101814. loadText(shaderPath).then(shaderLoad(model, id)).otherwise(getFailedLoadFunction(model, 'shader', shaderPath));
  101815. }
  101816. }
  101817. }
  101818. }
  101819. function parsePrograms(model) {
  101820. var programs = model.gltf.programs;
  101821. for (var id in programs) {
  101822. if (programs.hasOwnProperty(id)) {
  101823. model._loadResources.programsToCreate.enqueue(id);
  101824. }
  101825. }
  101826. }
  101827. function imageLoad(model, id) {
  101828. return function(image) {
  101829. var loadResources = model._loadResources;
  101830. --loadResources.pendingTextureLoads;
  101831. loadResources.texturesToCreate.enqueue({
  101832. id : id,
  101833. image : image,
  101834. bufferView : undefined
  101835. });
  101836. };
  101837. }
  101838. function parseTextures(model) {
  101839. var images = model.gltf.images;
  101840. var textures = model.gltf.textures;
  101841. for (var id in textures) {
  101842. if (textures.hasOwnProperty(id)) {
  101843. var gltfImage = images[textures[id].source];
  101844. // Image references either uri (external or base64-encoded) or bufferView
  101845. if (defined(gltfImage.extensions) && defined(gltfImage.extensions.KHR_binary_glTF)) {
  101846. var binary = gltfImage.extensions.KHR_binary_glTF;
  101847. model._loadResources.texturesToCreateFromBufferView.enqueue({
  101848. id : id,
  101849. image : undefined,
  101850. bufferView : binary.bufferView,
  101851. mimeType : binary.mimeType
  101852. });
  101853. } else {
  101854. ++model._loadResources.pendingTextureLoads;
  101855. var uri = new Uri(gltfImage.uri);
  101856. var imagePath = uri.resolve(model._baseUri).toString();
  101857. loadImage(imagePath).then(imageLoad(model, id)).otherwise(getFailedLoadFunction(model, 'image', imagePath));
  101858. }
  101859. }
  101860. }
  101861. }
  101862. var nodeTranslationScratch = new Cartesian3();
  101863. var nodeQuaternionScratch = new Quaternion();
  101864. var nodeScaleScratch = new Cartesian3();
  101865. function getTransform(node) {
  101866. if (defined(node.matrix)) {
  101867. return Matrix4.fromArray(node.matrix);
  101868. }
  101869. return Matrix4.fromTranslationQuaternionRotationScale(
  101870. Cartesian3.fromArray(node.translation, 0, nodeTranslationScratch),
  101871. Quaternion.unpack(node.rotation, 0, nodeQuaternionScratch),
  101872. Cartesian3.fromArray(node.scale, 0 , nodeScaleScratch));
  101873. }
  101874. function parseNodes(model) {
  101875. var runtimeNodes = {};
  101876. var runtimeNodesByName = {};
  101877. var skinnedNodes = [];
  101878. var skinnedNodesIds = model._loadResources.skinnedNodesIds;
  101879. var nodes = model.gltf.nodes;
  101880. for (var id in nodes) {
  101881. if (nodes.hasOwnProperty(id)) {
  101882. var node = nodes[id];
  101883. var runtimeNode = {
  101884. // Animation targets
  101885. matrix : undefined,
  101886. translation : undefined,
  101887. rotation : undefined,
  101888. scale : undefined,
  101889. // Per-node show inherited from parent
  101890. computedShow : true,
  101891. // Computed transforms
  101892. transformToRoot : new Matrix4(),
  101893. computedMatrix : new Matrix4(),
  101894. dirtyNumber : 0, // The frame this node was made dirty by an animation; for graph traversal
  101895. // Rendering
  101896. commands : [], // empty for transform, light, and camera nodes
  101897. // Skinned node
  101898. inverseBindMatrices : undefined, // undefined when node is not skinned
  101899. bindShapeMatrix : undefined, // undefined when node is not skinned or identity
  101900. joints : [], // empty when node is not skinned
  101901. computedJointMatrices : [], // empty when node is not skinned
  101902. // Joint node
  101903. jointName : node.jointName, // undefined when node is not a joint
  101904. // Graph pointers
  101905. children : [], // empty for leaf nodes
  101906. parents : [], // empty for root nodes
  101907. // Publicly-accessible ModelNode instance to modify animation targets
  101908. publicNode : undefined
  101909. };
  101910. runtimeNode.publicNode = new ModelNode(model, node, runtimeNode, id, getTransform(node));
  101911. runtimeNodes[id] = runtimeNode;
  101912. runtimeNodesByName[node.name] = runtimeNode;
  101913. if (defined(node.skin)) {
  101914. skinnedNodesIds.push(id);
  101915. skinnedNodes.push(runtimeNode);
  101916. }
  101917. }
  101918. }
  101919. model._runtime.nodes = runtimeNodes;
  101920. model._runtime.nodesByName = runtimeNodesByName;
  101921. model._runtime.skinnedNodes = skinnedNodes;
  101922. }
  101923. function parseMaterials(model) {
  101924. var runtimeMaterialsByName = {};
  101925. var runtimeMaterialsById = {};
  101926. var materials = model.gltf.materials;
  101927. var uniformMaps = model._uniformMaps;
  101928. for (var id in materials) {
  101929. if (materials.hasOwnProperty(id)) {
  101930. // Allocated now so ModelMaterial can keep a reference to it.
  101931. uniformMaps[id] = {
  101932. uniformMap : undefined,
  101933. values : undefined,
  101934. jointMatrixUniformName : undefined
  101935. };
  101936. var material = materials[id];
  101937. var modelMaterial = new ModelMaterial(model, material, id);
  101938. runtimeMaterialsByName[material.name] = modelMaterial;
  101939. runtimeMaterialsById[id] = modelMaterial;
  101940. }
  101941. }
  101942. model._runtime.materialsByName = runtimeMaterialsByName;
  101943. model._runtime.materialsById = runtimeMaterialsById;
  101944. }
  101945. function parseMeshes(model) {
  101946. var runtimeMeshesByName = {};
  101947. var runtimeMaterialsById = model._runtime.materialsById;
  101948. var meshes = model.gltf.meshes;
  101949. var usesQuantizedAttributes = usesExtension(model, 'WEB3D_quantized_attributes');
  101950. for (var id in meshes) {
  101951. if (meshes.hasOwnProperty(id)) {
  101952. var mesh = meshes[id];
  101953. runtimeMeshesByName[mesh.name] = new ModelMesh(mesh, runtimeMaterialsById, id);
  101954. if (usesQuantizedAttributes) {
  101955. // Cache primitives according to their program
  101956. var primitives = mesh.primitives;
  101957. var primitivesLength = primitives.length;
  101958. for (var i = 0; i < primitivesLength; i++) {
  101959. var primitive = primitives[i];
  101960. var programId = getProgramForPrimitive(model, primitive);
  101961. var programPrimitives = model._programPrimitives[programId];
  101962. if (!defined(programPrimitives)) {
  101963. programPrimitives = [];
  101964. model._programPrimitives[programId] = programPrimitives;
  101965. }
  101966. programPrimitives.push(primitive);
  101967. }
  101968. }
  101969. }
  101970. }
  101971. model._runtime.meshesByName = runtimeMeshesByName;
  101972. }
  101973. function parse(model) {
  101974. if (!model._loadRendererResourcesFromCache) {
  101975. parseBuffers(model);
  101976. parseBufferViews(model);
  101977. parseShaders(model);
  101978. parsePrograms(model);
  101979. parseTextures(model);
  101980. }
  101981. parseMaterials(model);
  101982. parseMeshes(model);
  101983. parseNodes(model);
  101984. }
  101985. function usesExtension(model, extension) {
  101986. var cachedExtensionsUsed = model._extensionsUsed;
  101987. if (!defined(cachedExtensionsUsed)) {
  101988. var extensionsUsed = model.gltf.extensionsUsed;
  101989. cachedExtensionsUsed = {};
  101990. var extensionsLength = extensionsUsed.length;
  101991. for (var i = 0; i < extensionsLength; i++) {
  101992. cachedExtensionsUsed[extensionsUsed[i]] = true;
  101993. }
  101994. }
  101995. return defined(cachedExtensionsUsed[extension]);
  101996. }
  101997. ///////////////////////////////////////////////////////////////////////////
  101998. function createBuffers(model, context) {
  101999. var loadResources = model._loadResources;
  102000. if (loadResources.pendingBufferLoads !== 0) {
  102001. return;
  102002. }
  102003. var bufferView;
  102004. var bufferViews = model.gltf.bufferViews;
  102005. var rendererBuffers = model._rendererResources.buffers;
  102006. while (loadResources.buffersToCreate.length > 0) {
  102007. var bufferViewId = loadResources.buffersToCreate.dequeue();
  102008. bufferView = bufferViews[bufferViewId];
  102009. // Only ARRAY_BUFFER here. ELEMENT_ARRAY_BUFFER created below.
  102010. var vertexBuffer = Buffer.createVertexBuffer({
  102011. context : context,
  102012. typedArray : loadResources.getBuffer(bufferView),
  102013. usage : BufferUsage.STATIC_DRAW
  102014. });
  102015. vertexBuffer.vertexArrayDestroyable = false;
  102016. rendererBuffers[bufferViewId] = vertexBuffer;
  102017. }
  102018. // The Cesium Renderer requires knowing the datatype for an index buffer
  102019. // at creation type, which is not part of the glTF bufferview so loop
  102020. // through glTF accessors to create the bufferview's index buffer.
  102021. var accessors = model.gltf.accessors;
  102022. for (var id in accessors) {
  102023. if (accessors.hasOwnProperty(id)) {
  102024. var accessor = accessors[id];
  102025. bufferView = bufferViews[accessor.bufferView];
  102026. if ((bufferView.target === WebGLConstants.ELEMENT_ARRAY_BUFFER) && !defined(rendererBuffers[accessor.bufferView])) {
  102027. var indexBuffer = Buffer.createIndexBuffer({
  102028. context : context,
  102029. typedArray : loadResources.getBuffer(bufferView),
  102030. usage : BufferUsage.STATIC_DRAW,
  102031. indexDatatype : accessor.componentType
  102032. });
  102033. indexBuffer.vertexArrayDestroyable = false;
  102034. rendererBuffers[accessor.bufferView] = indexBuffer;
  102035. // In theory, several glTF accessors with different componentTypes could
  102036. // point to the same glTF bufferView, which would break this.
  102037. // In practice, it is unlikely as it will be UNSIGNED_SHORT.
  102038. }
  102039. }
  102040. }
  102041. }
  102042. function createAttributeLocations(model, attributes) {
  102043. var attributeLocations = {};
  102044. var length = attributes.length;
  102045. var i;
  102046. // Set the position attribute to the 0th index. In some WebGL implementations the shader
  102047. // will not work correctly if the 0th attribute is not active. For example, some glTF models
  102048. // list the normal attribute first but derived shaders like the cast-shadows shader do not use
  102049. // the normal attribute.
  102050. for (i = 1; i < length; ++i) {
  102051. var attribute = attributes[i];
  102052. if (/position/i.test(attribute)) {
  102053. attributes[i] = attributes[0];
  102054. attributes[0] = attribute;
  102055. break;
  102056. }
  102057. }
  102058. for (i = 0; i < length; ++i) {
  102059. attributeLocations[attributes[i]] = i;
  102060. }
  102061. return attributeLocations;
  102062. }
  102063. function getShaderSource(model, shader) {
  102064. if (defined(shader.source)) {
  102065. return shader.source;
  102066. }
  102067. var loadResources = model._loadResources;
  102068. var gltf = model.gltf;
  102069. var bufferView = gltf.bufferViews[shader.bufferView];
  102070. return getStringFromTypedArray(loadResources.getBuffer(bufferView));
  102071. }
  102072. function replaceAllButFirstInString(string, find, replace) {
  102073. var index = string.indexOf(find);
  102074. return string.replace(new RegExp(find, 'g'), function(match, offset, all) {
  102075. return index === offset ? match : replace;
  102076. });
  102077. }
  102078. function getProgramForPrimitive(model, primitive) {
  102079. var gltf = model.gltf;
  102080. var materialId = primitive.material;
  102081. var material = gltf.materials[materialId];
  102082. var techniqueId = material.technique;
  102083. var technique = gltf.techniques[techniqueId];
  102084. return technique.program;
  102085. }
  102086. function getQuantizedAttributes(model, accessorId) {
  102087. var gltf = model.gltf;
  102088. var accessor = gltf.accessors[accessorId];
  102089. var extensions = accessor.extensions;
  102090. if (defined(extensions)) {
  102091. return extensions.WEB3D_quantized_attributes;
  102092. }
  102093. return undefined;
  102094. }
  102095. function getAttributeVariableName(model, primitive, attributeSemantic) {
  102096. var gltf = model.gltf;
  102097. var materialId = primitive.material;
  102098. var material = gltf.materials[materialId];
  102099. var techniqueId = material.technique;
  102100. var technique = gltf.techniques[techniqueId];
  102101. for (var parameter in technique.parameters) {
  102102. if (technique.parameters.hasOwnProperty(parameter)) {
  102103. var semantic = technique.parameters[parameter].semantic;
  102104. if (semantic === attributeSemantic) {
  102105. var attributes = technique.attributes;
  102106. for (var attributeVarName in attributes) {
  102107. if (attributes.hasOwnProperty(attributeVarName)) {
  102108. var name = attributes[attributeVarName];
  102109. if (name === parameter) {
  102110. return attributeVarName;
  102111. }
  102112. }
  102113. }
  102114. }
  102115. }
  102116. }
  102117. return undefined;
  102118. }
  102119. function modifyShaderForQuantizedAttributes(shader, programName, model, context) {
  102120. var quantizedUniforms = {};
  102121. model._quantizedUniforms[programName] = quantizedUniforms;
  102122. var primitives = model._programPrimitives[programName];
  102123. for (var i = 0; i < primitives.length; i++) {
  102124. var primitive = primitives[i];
  102125. if (getProgramForPrimitive(model, primitive) === programName) {
  102126. for (var attributeSemantic in primitive.attributes) {
  102127. if (primitive.attributes.hasOwnProperty(attributeSemantic)) {
  102128. var decodeUniformVarName = 'gltf_u_dec_' + attributeSemantic.toLowerCase();
  102129. var decodeUniformVarNameScale = decodeUniformVarName + '_scale';
  102130. var decodeUniformVarNameTranslate = decodeUniformVarName + '_translate';
  102131. if (!defined(quantizedUniforms[decodeUniformVarName]) && !defined(quantizedUniforms[decodeUniformVarNameScale])) {
  102132. var accessorId = primitive.attributes[attributeSemantic];
  102133. var quantizedAttributes = getQuantizedAttributes(model, accessorId);
  102134. if (defined(quantizedAttributes)) {
  102135. var attributeVarName = getAttributeVariableName(model, primitive, attributeSemantic);
  102136. var decodeMatrix = quantizedAttributes.decodeMatrix;
  102137. var newMain = 'gltf_decoded_' + attributeSemantic;
  102138. var decodedAttributeVarName = attributeVarName.replace('a_', 'gltf_a_dec_');
  102139. var size = Math.floor(Math.sqrt(decodeMatrix.length));
  102140. // replace usages of the original attribute with the decoded version, but not the declaration
  102141. shader = replaceAllButFirstInString(shader, attributeVarName, decodedAttributeVarName);
  102142. // declare decoded attribute
  102143. var variableType;
  102144. if (size > 2) {
  102145. variableType = 'vec' + (size - 1);
  102146. } else {
  102147. variableType = 'float';
  102148. }
  102149. shader = variableType + ' ' + decodedAttributeVarName + ';\n' + shader;
  102150. // splice decode function into the shader - attributes are pre-multiplied with the decode matrix
  102151. // uniform in the shader (32-bit floating point)
  102152. var decode = '';
  102153. if (size === 5) {
  102154. // separate scale and translate since glsl doesn't have mat5
  102155. shader = 'uniform mat4 ' + decodeUniformVarNameScale + ';\n' + shader;
  102156. shader = 'uniform vec4 ' + decodeUniformVarNameTranslate + ';\n' + shader;
  102157. decode = '\n' +
  102158. 'void main() {\n' +
  102159. ' ' + decodedAttributeVarName + ' = ' + decodeUniformVarNameScale + ' * ' + attributeVarName + ' + ' + decodeUniformVarNameTranslate + ';\n' +
  102160. ' ' + newMain + '();\n' +
  102161. '}\n';
  102162. quantizedUniforms[decodeUniformVarNameScale] = {mat : 4};
  102163. quantizedUniforms[decodeUniformVarNameTranslate] = {vec : 4};
  102164. }
  102165. else {
  102166. shader = 'uniform mat' + size + ' ' + decodeUniformVarName + ';\n' + shader;
  102167. decode = '\n' +
  102168. 'void main() {\n' +
  102169. ' ' + decodedAttributeVarName + ' = ' + variableType + '(' + decodeUniformVarName + ' * vec' + size + '(' + attributeVarName + ',1.0));\n' +
  102170. ' ' + newMain + '();\n' +
  102171. '}\n';
  102172. quantizedUniforms[decodeUniformVarName] = {mat : size};
  102173. }
  102174. shader = ShaderSource.replaceMain(shader, newMain);
  102175. shader += decode;
  102176. }
  102177. }
  102178. }
  102179. }
  102180. }
  102181. }
  102182. // This is not needed after the program is processed, free the memory
  102183. model._programPrimitives[programName] = undefined;
  102184. return shader;
  102185. }
  102186. function hasPremultipliedAlpha(model) {
  102187. var gltf = model.gltf;
  102188. return defined(gltf.asset) ? defaultValue(gltf.asset.premultipliedAlpha, false) : false;
  102189. }
  102190. function modifyShaderForColor(shader, premultipliedAlpha) {
  102191. shader = ShaderSource.replaceMain(shader, 'gltf_blend_main');
  102192. shader +=
  102193. 'uniform vec4 gltf_color; \n' +
  102194. 'uniform float gltf_colorBlend; \n' +
  102195. 'void main() \n' +
  102196. '{ \n' +
  102197. ' gltf_blend_main(); \n';
  102198. // Un-premultiply the alpha so that blending is correct.
  102199. // Avoid divide-by-zero. The code below is equivalent to:
  102200. // if (gl_FragColor.a > 0.0)
  102201. // {
  102202. // gl_FragColor.rgb /= gl_FragColor.a;
  102203. // }
  102204. if (premultipliedAlpha) {
  102205. shader +=
  102206. ' float alpha = 1.0 - ceil(gl_FragColor.a) + gl_FragColor.a; \n' +
  102207. ' gl_FragColor.rgb /= alpha; \n';
  102208. }
  102209. shader +=
  102210. ' gl_FragColor.rgb = mix(gl_FragColor.rgb, gltf_color.rgb, gltf_colorBlend); \n' +
  102211. ' float highlight = ceil(gltf_colorBlend); \n' +
  102212. ' gl_FragColor.rgb *= mix(gltf_color.rgb, vec3(1.0), highlight); \n' +
  102213. ' gl_FragColor.a *= gltf_color.a; \n' +
  102214. '} \n';
  102215. return shader;
  102216. }
  102217. function modifyShader(shader, programName, callback) {
  102218. if (defined(callback)) {
  102219. shader = callback(shader, programName);
  102220. }
  102221. return shader;
  102222. }
  102223. function createProgram(id, model, context) {
  102224. var programs = model.gltf.programs;
  102225. var shaders = model._loadResources.shaders;
  102226. var program = programs[id];
  102227. var attributeLocations = createAttributeLocations(model, program.attributes);
  102228. var vs = getShaderSource(model, shaders[program.vertexShader]);
  102229. var fs = getShaderSource(model, shaders[program.fragmentShader]);
  102230. // Add pre-created attributes to attributeLocations
  102231. var attributesLength = program.attributes.length;
  102232. var precreatedAttributes = model._precreatedAttributes;
  102233. if (defined(precreatedAttributes)) {
  102234. for (var attrName in precreatedAttributes) {
  102235. if (precreatedAttributes.hasOwnProperty(attrName)) {
  102236. attributeLocations[attrName] = attributesLength++;
  102237. }
  102238. }
  102239. }
  102240. if (usesExtension(model, 'WEB3D_quantized_attributes')) {
  102241. vs = modifyShaderForQuantizedAttributes(vs, id, model, context);
  102242. }
  102243. var premultipliedAlpha = hasPremultipliedAlpha(model);
  102244. var blendFS = modifyShaderForColor(fs, premultipliedAlpha);
  102245. var drawVS = modifyShader(vs, id, model._vertexShaderLoaded);
  102246. var drawFS = modifyShader(blendFS, id, model._fragmentShaderLoaded);
  102247. model._rendererResources.programs[id] = ShaderProgram.fromCache({
  102248. context : context,
  102249. vertexShaderSource : drawVS,
  102250. fragmentShaderSource : drawFS,
  102251. attributeLocations : attributeLocations
  102252. });
  102253. if (model.allowPicking) {
  102254. // PERFORMANCE_IDEA: Can optimize this shader with a glTF hint. https://github.com/KhronosGroup/glTF/issues/181
  102255. var pickVS = modifyShader(vs, id, model._pickVertexShaderLoaded);
  102256. var pickFS = modifyShader(fs, id, model._pickFragmentShaderLoaded);
  102257. if (!model._pickFragmentShaderLoaded) {
  102258. pickFS = ShaderSource.createPickFragmentShaderSource(fs, 'uniform');
  102259. }
  102260. model._rendererResources.pickPrograms[id] = ShaderProgram.fromCache({
  102261. context : context,
  102262. vertexShaderSource : pickVS,
  102263. fragmentShaderSource : pickFS,
  102264. attributeLocations : attributeLocations
  102265. });
  102266. }
  102267. }
  102268. function createPrograms(model, context) {
  102269. var loadResources = model._loadResources;
  102270. var id;
  102271. if (loadResources.pendingShaderLoads !== 0) {
  102272. return;
  102273. }
  102274. // PERFORMANCE_IDEA: this could be more fine-grained by looking
  102275. // at the shader's bufferView's to determine the buffer dependencies.
  102276. if (loadResources.pendingBufferLoads !== 0) {
  102277. return;
  102278. }
  102279. if (model.asynchronous) {
  102280. // Create one program per frame
  102281. if (loadResources.programsToCreate.length > 0) {
  102282. id = loadResources.programsToCreate.dequeue();
  102283. createProgram(id, model, context);
  102284. }
  102285. } else {
  102286. // Create all loaded programs this frame
  102287. while (loadResources.programsToCreate.length > 0) {
  102288. id = loadResources.programsToCreate.dequeue();
  102289. createProgram(id, model, context);
  102290. }
  102291. }
  102292. }
  102293. function getOnImageCreatedFromTypedArray(loadResources, gltfTexture) {
  102294. return function(image) {
  102295. loadResources.texturesToCreate.enqueue({
  102296. id : gltfTexture.id,
  102297. image : image,
  102298. bufferView : undefined
  102299. });
  102300. --loadResources.pendingBufferViewToImage;
  102301. };
  102302. }
  102303. function loadTexturesFromBufferViews(model) {
  102304. var loadResources = model._loadResources;
  102305. if (loadResources.pendingBufferLoads !== 0) {
  102306. return;
  102307. }
  102308. while (loadResources.texturesToCreateFromBufferView.length > 0) {
  102309. var gltfTexture = loadResources.texturesToCreateFromBufferView.dequeue();
  102310. var gltf = model.gltf;
  102311. var bufferView = gltf.bufferViews[gltfTexture.bufferView];
  102312. var onload = getOnImageCreatedFromTypedArray(loadResources, gltfTexture);
  102313. var onerror = getFailedLoadFunction(model, 'image', 'id: ' + gltfTexture.id + ', bufferView: ' + gltfTexture.bufferView);
  102314. loadImageFromTypedArray(loadResources.getBuffer(bufferView), gltfTexture.mimeType).
  102315. then(onload).otherwise(onerror);
  102316. ++loadResources.pendingBufferViewToImage;
  102317. }
  102318. }
  102319. function createSamplers(model, context) {
  102320. var loadResources = model._loadResources;
  102321. if (loadResources.createSamplers) {
  102322. loadResources.createSamplers = false;
  102323. var rendererSamplers = model._rendererResources.samplers;
  102324. var samplers = model.gltf.samplers;
  102325. for (var id in samplers) {
  102326. if (samplers.hasOwnProperty(id)) {
  102327. var sampler = samplers[id];
  102328. rendererSamplers[id] = new Sampler({
  102329. wrapS : sampler.wrapS,
  102330. wrapT : sampler.wrapT,
  102331. minificationFilter : sampler.minFilter,
  102332. magnificationFilter : sampler.magFilter
  102333. });
  102334. }
  102335. }
  102336. }
  102337. }
  102338. function createTexture(gltfTexture, model, context) {
  102339. var textures = model.gltf.textures;
  102340. var texture = textures[gltfTexture.id];
  102341. var rendererSamplers = model._rendererResources.samplers;
  102342. var sampler = rendererSamplers[texture.sampler];
  102343. var mipmap =
  102344. (sampler.minificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST) ||
  102345. (sampler.minificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR) ||
  102346. (sampler.minificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_NEAREST) ||
  102347. (sampler.minificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_LINEAR);
  102348. var requiresNpot = mipmap ||
  102349. (sampler.wrapS === TextureWrap.REPEAT) ||
  102350. (sampler.wrapS === TextureWrap.MIRRORED_REPEAT) ||
  102351. (sampler.wrapT === TextureWrap.REPEAT) ||
  102352. (sampler.wrapT === TextureWrap.MIRRORED_REPEAT);
  102353. var source = gltfTexture.image;
  102354. var npot = !CesiumMath.isPowerOfTwo(source.width) || !CesiumMath.isPowerOfTwo(source.height);
  102355. if (requiresNpot && npot) {
  102356. // WebGL requires power-of-two texture dimensions for mipmapping and REPEAT/MIRRORED_REPEAT wrap modes.
  102357. var canvas = document.createElement('canvas');
  102358. canvas.width = CesiumMath.nextPowerOfTwo(source.width);
  102359. canvas.height = CesiumMath.nextPowerOfTwo(source.height);
  102360. var canvasContext = canvas.getContext('2d');
  102361. canvasContext.drawImage(source, 0, 0, source.width, source.height, 0, 0, canvas.width, canvas.height);
  102362. source = canvas;
  102363. }
  102364. var tx;
  102365. if (texture.target === WebGLConstants.TEXTURE_2D) {
  102366. tx = new Texture({
  102367. context : context,
  102368. source : source,
  102369. pixelFormat : texture.internalFormat,
  102370. pixelDatatype : texture.type,
  102371. sampler : sampler,
  102372. flipY : false
  102373. });
  102374. }
  102375. // GLTF_SPEC: Support TEXTURE_CUBE_MAP. https://github.com/KhronosGroup/glTF/issues/40
  102376. if (mipmap) {
  102377. tx.generateMipmap();
  102378. }
  102379. model._rendererResources.textures[gltfTexture.id] = tx;
  102380. }
  102381. function createTextures(model, context) {
  102382. var loadResources = model._loadResources;
  102383. var gltfTexture;
  102384. if (model.asynchronous) {
  102385. // Create one texture per frame
  102386. if (loadResources.texturesToCreate.length > 0) {
  102387. gltfTexture = loadResources.texturesToCreate.dequeue();
  102388. createTexture(gltfTexture, model, context);
  102389. }
  102390. } else {
  102391. // Create all loaded textures this frame
  102392. while (loadResources.texturesToCreate.length > 0) {
  102393. gltfTexture = loadResources.texturesToCreate.dequeue();
  102394. createTexture(gltfTexture, model, context);
  102395. }
  102396. }
  102397. }
  102398. function getAttributeLocations(model, primitive) {
  102399. var gltf = model.gltf;
  102400. var techniques = gltf.techniques;
  102401. var materials = gltf.materials;
  102402. // Retrieve the compiled shader program to assign index values to attributes
  102403. var attributeLocations = {};
  102404. var technique = techniques[materials[primitive.material].technique];
  102405. var parameters = technique.parameters;
  102406. var attributes = technique.attributes;
  102407. var programAttributeLocations = model._rendererResources.programs[technique.program].vertexAttributes;
  102408. // Note: WebGL shader compiler may have optimized and removed some attributes from programAttributeLocations
  102409. for (var location in programAttributeLocations){
  102410. if (programAttributeLocations.hasOwnProperty(location)) {
  102411. var attribute = attributes[location];
  102412. var index = programAttributeLocations[location].index;
  102413. if (defined(attribute)) {
  102414. var parameter = parameters[attribute];
  102415. attributeLocations[parameter.semantic] = index;
  102416. } else {
  102417. // Pre-created attributes
  102418. attributeLocations[location] = index;
  102419. }
  102420. }
  102421. }
  102422. return attributeLocations;
  102423. }
  102424. function searchForest(forest, jointName, nodes) {
  102425. var length = forest.length;
  102426. for (var i = 0; i < length; ++i) {
  102427. var stack = [forest[i]]; // Push root node of tree
  102428. while (stack.length > 0) {
  102429. var id = stack.pop();
  102430. var n = nodes[id];
  102431. if (n.jointName === jointName) {
  102432. return id;
  102433. }
  102434. var children = n.children;
  102435. var childrenLength = children.length;
  102436. for (var k = 0; k < childrenLength; ++k) {
  102437. stack.push(children[k]);
  102438. }
  102439. }
  102440. }
  102441. // This should never happen; the skeleton should have a node for all joints in the skin.
  102442. return undefined;
  102443. }
  102444. function createJoints(model, runtimeSkins) {
  102445. var gltf = model.gltf;
  102446. var skins = gltf.skins;
  102447. var nodes = gltf.nodes;
  102448. var runtimeNodes = model._runtime.nodes;
  102449. var skinnedNodesIds = model._loadResources.skinnedNodesIds;
  102450. var length = skinnedNodesIds.length;
  102451. for (var j = 0; j < length; ++j) {
  102452. var id = skinnedNodesIds[j];
  102453. var skinnedNode = runtimeNodes[id];
  102454. var node = nodes[id];
  102455. var runtimeSkin = runtimeSkins[node.skin];
  102456. skinnedNode.inverseBindMatrices = runtimeSkin.inverseBindMatrices;
  102457. skinnedNode.bindShapeMatrix = runtimeSkin.bindShapeMatrix;
  102458. // 1. Find nodes with the names in node.skeletons (the node's skeletons)
  102459. // 2. These nodes form the root nodes of the forest to search for each joint in skin.jointNames. This search uses jointName, not the node's name.
  102460. // 3. Search for the joint name among the gltf node hierarchy instead of the runtime node hierarchy. Child links aren't set up yet for runtime nodes.
  102461. var forest = [];
  102462. var gltfSkeletons = node.skeletons;
  102463. var skeletonsLength = gltfSkeletons.length;
  102464. for (var k = 0; k < skeletonsLength; ++k) {
  102465. forest.push(gltfSkeletons[k]);
  102466. }
  102467. var gltfJointNames = skins[node.skin].jointNames;
  102468. var jointNamesLength = gltfJointNames.length;
  102469. for (var i = 0; i < jointNamesLength; ++i) {
  102470. var jointName = gltfJointNames[i];
  102471. var jointNode = runtimeNodes[searchForest(forest, jointName, nodes)];
  102472. skinnedNode.joints.push(jointNode);
  102473. }
  102474. }
  102475. }
  102476. function createSkins(model) {
  102477. var loadResources = model._loadResources;
  102478. if (loadResources.pendingBufferLoads !== 0) {
  102479. return;
  102480. }
  102481. if (!loadResources.createSkins) {
  102482. return;
  102483. }
  102484. loadResources.createSkins = false;
  102485. var gltf = model.gltf;
  102486. var accessors = gltf.accessors;
  102487. var skins = gltf.skins;
  102488. var runtimeSkins = {};
  102489. for (var id in skins) {
  102490. if (skins.hasOwnProperty(id)) {
  102491. var skin = skins[id];
  102492. var accessor = accessors[skin.inverseBindMatrices];
  102493. var bindShapeMatrix;
  102494. if (!Matrix4.equals(skin.bindShapeMatrix, Matrix4.IDENTITY)) {
  102495. bindShapeMatrix = Matrix4.clone(skin.bindShapeMatrix);
  102496. }
  102497. runtimeSkins[id] = {
  102498. inverseBindMatrices : ModelAnimationCache.getSkinInverseBindMatrices(model, accessor),
  102499. bindShapeMatrix : bindShapeMatrix // not used when undefined
  102500. };
  102501. }
  102502. }
  102503. createJoints(model, runtimeSkins);
  102504. }
  102505. function getChannelEvaluator(model, runtimeNode, targetPath, spline) {
  102506. return function(localAnimationTime) {
  102507. // Workaround for https://github.com/KhronosGroup/glTF/issues/219
  102508. //if (targetPath === 'translation') {
  102509. // return;
  102510. //}
  102511. runtimeNode[targetPath] = spline.evaluate(localAnimationTime, runtimeNode[targetPath]);
  102512. runtimeNode.dirtyNumber = model._maxDirtyNumber;
  102513. };
  102514. }
  102515. function createRuntimeAnimations(model) {
  102516. var loadResources = model._loadResources;
  102517. if (!loadResources.finishedPendingBufferLoads()) {
  102518. return;
  102519. }
  102520. if (!loadResources.createRuntimeAnimations) {
  102521. return;
  102522. }
  102523. loadResources.createRuntimeAnimations = false;
  102524. model._runtime.animations = {
  102525. };
  102526. var runtimeNodes = model._runtime.nodes;
  102527. var animations = model.gltf.animations;
  102528. var accessors = model.gltf.accessors;
  102529. for (var animationId in animations) {
  102530. if (animations.hasOwnProperty(animationId)) {
  102531. var animation = animations[animationId];
  102532. var channels = animation.channels;
  102533. var parameters = animation.parameters;
  102534. var samplers = animation.samplers;
  102535. var parameterValues = {};
  102536. for (var name in parameters) {
  102537. if (parameters.hasOwnProperty(name)) {
  102538. parameterValues[name] = ModelAnimationCache.getAnimationParameterValues(model, accessors[parameters[name]]);
  102539. }
  102540. }
  102541. // Find start and stop time for the entire animation
  102542. var startTime = Number.MAX_VALUE;
  102543. var stopTime = -Number.MAX_VALUE;
  102544. var length = channels.length;
  102545. var channelEvaluators = new Array(length);
  102546. for (var i = 0; i < length; ++i) {
  102547. var channel = channels[i];
  102548. var target = channel.target;
  102549. var sampler = samplers[channel.sampler];
  102550. var times = parameterValues[sampler.input];
  102551. startTime = Math.min(startTime, times[0]);
  102552. stopTime = Math.max(stopTime, times[times.length - 1]);
  102553. var spline = ModelAnimationCache.getAnimationSpline(model, animationId, animation, channel.sampler, sampler, parameterValues);
  102554. // GLTF_SPEC: Support more targets like materials. https://github.com/KhronosGroup/glTF/issues/142
  102555. channelEvaluators[i] = getChannelEvaluator(model, runtimeNodes[target.id], target.path, spline);
  102556. }
  102557. model._runtime.animations[animationId] = {
  102558. startTime : startTime,
  102559. stopTime : stopTime,
  102560. channelEvaluators : channelEvaluators
  102561. };
  102562. }
  102563. }
  102564. }
  102565. function createVertexArrays(model, context) {
  102566. var loadResources = model._loadResources;
  102567. if (!loadResources.finishedBuffersCreation() || !loadResources.finishedProgramCreation()) {
  102568. return;
  102569. }
  102570. if (!loadResources.createVertexArrays) {
  102571. return;
  102572. }
  102573. loadResources.createVertexArrays = false;
  102574. var rendererBuffers = model._rendererResources.buffers;
  102575. var rendererVertexArrays = model._rendererResources.vertexArrays;
  102576. var gltf = model.gltf;
  102577. var accessors = gltf.accessors;
  102578. var meshes = gltf.meshes;
  102579. for (var meshId in meshes) {
  102580. if (meshes.hasOwnProperty(meshId)) {
  102581. var primitives = meshes[meshId].primitives;
  102582. var primitivesLength = primitives.length;
  102583. for (var i = 0; i < primitivesLength; ++i) {
  102584. var primitive = primitives[i];
  102585. // GLTF_SPEC: This does not take into account attribute arrays,
  102586. // indicated by when an attribute points to a parameter with a
  102587. // count property.
  102588. //
  102589. // https://github.com/KhronosGroup/glTF/issues/258
  102590. var attributeLocations = getAttributeLocations(model, primitive);
  102591. var attributeName;
  102592. var attributeLocation;
  102593. var attribute;
  102594. var attributes = [];
  102595. var primitiveAttributes = primitive.attributes;
  102596. for (attributeName in primitiveAttributes) {
  102597. if (primitiveAttributes.hasOwnProperty(attributeName)) {
  102598. attributeLocation = attributeLocations[attributeName];
  102599. // Skip if the attribute is not used by the material, e.g., because the asset was exported
  102600. // with an attribute that wasn't used and the asset wasn't optimized.
  102601. if (defined(attributeLocation)) {
  102602. var a = accessors[primitiveAttributes[attributeName]];
  102603. attributes.push({
  102604. index : attributeLocation,
  102605. vertexBuffer : rendererBuffers[a.bufferView],
  102606. componentsPerAttribute : getBinaryAccessor(a).componentsPerAttribute,
  102607. componentDatatype : a.componentType,
  102608. normalize : false,
  102609. offsetInBytes : a.byteOffset,
  102610. strideInBytes : a.byteStride
  102611. });
  102612. }
  102613. }
  102614. }
  102615. // Add pre-created attributes
  102616. var precreatedAttributes = model._precreatedAttributes;
  102617. if (defined(precreatedAttributes)) {
  102618. for (attributeName in precreatedAttributes) {
  102619. if (precreatedAttributes.hasOwnProperty(attributeName)) {
  102620. attributeLocation = attributeLocations[attributeName];
  102621. if (defined(attributeLocation)) {
  102622. attribute = precreatedAttributes[attributeName];
  102623. attribute.index = attributeLocation;
  102624. attributes.push(attribute);
  102625. }
  102626. }
  102627. }
  102628. }
  102629. var indexBuffer;
  102630. if (defined(primitive.indices)) {
  102631. var accessor = accessors[primitive.indices];
  102632. indexBuffer = rendererBuffers[accessor.bufferView];
  102633. }
  102634. rendererVertexArrays[meshId + '.primitive.' + i] = new VertexArray({
  102635. context : context,
  102636. attributes : attributes,
  102637. indexBuffer : indexBuffer
  102638. });
  102639. }
  102640. }
  102641. }
  102642. }
  102643. function getBooleanStates(states) {
  102644. // GLTF_SPEC: SAMPLE_ALPHA_TO_COVERAGE not used by Cesium
  102645. var booleanStates = {};
  102646. booleanStates[WebGLConstants.BLEND] = false;
  102647. booleanStates[WebGLConstants.CULL_FACE] = false;
  102648. booleanStates[WebGLConstants.DEPTH_TEST] = false;
  102649. booleanStates[WebGLConstants.POLYGON_OFFSET_FILL] = false;
  102650. booleanStates[WebGLConstants.SCISSOR_TEST] = false;
  102651. var enable = states.enable;
  102652. var length = enable.length;
  102653. var i;
  102654. for (i = 0; i < length; ++i) {
  102655. booleanStates[enable[i]] = true;
  102656. }
  102657. return booleanStates;
  102658. }
  102659. function createRenderStates(model, context) {
  102660. var loadResources = model._loadResources;
  102661. var techniques = model.gltf.techniques;
  102662. if (loadResources.createRenderStates) {
  102663. loadResources.createRenderStates = false;
  102664. for (var id in techniques) {
  102665. if (techniques.hasOwnProperty(id)) {
  102666. createRenderStateForTechnique(model, id, context);
  102667. }
  102668. }
  102669. }
  102670. }
  102671. function createRenderStateForTechnique(model, id, context) {
  102672. var rendererRenderStates = model._rendererResources.renderStates;
  102673. var techniques = model.gltf.techniques;
  102674. var technique = techniques[id];
  102675. var states = technique.states;
  102676. var booleanStates = getBooleanStates(states);
  102677. var statesFunctions = defaultValue(states.functions, defaultValue.EMPTY_OBJECT);
  102678. var blendColor = defaultValue(statesFunctions.blendColor, [0.0, 0.0, 0.0, 0.0]);
  102679. var blendEquationSeparate = defaultValue(statesFunctions.blendEquationSeparate, [
  102680. WebGLConstants.FUNC_ADD,
  102681. WebGLConstants.FUNC_ADD]);
  102682. var blendFuncSeparate = defaultValue(statesFunctions.blendFuncSeparate, [
  102683. WebGLConstants.ONE,
  102684. WebGLConstants.ZERO,
  102685. WebGLConstants.ONE,
  102686. WebGLConstants.ZERO]);
  102687. var colorMask = defaultValue(statesFunctions.colorMask, [true, true, true, true]);
  102688. var depthRange = defaultValue(statesFunctions.depthRange, [0.0, 1.0]);
  102689. var polygonOffset = defaultValue(statesFunctions.polygonOffset, [0.0, 0.0]);
  102690. var scissor = defaultValue(statesFunctions.scissor, [0.0, 0.0, 0.0, 0.0]);
  102691. // Change the render state to use traditional alpha blending instead of premultiplied alpha blending
  102692. if (booleanStates[WebGLConstants.BLEND] && hasPremultipliedAlpha(model)) {
  102693. if ((blendFuncSeparate[0] === WebGLConstants.ONE) && (blendFuncSeparate[1] === WebGLConstants.ONE_MINUS_SRC_ALPHA)) {
  102694. blendFuncSeparate[0] = WebGLConstants.SRC_ALPHA;
  102695. blendFuncSeparate[1] = WebGLConstants.ONE_MINUS_SRC_ALPHA;
  102696. blendFuncSeparate[2] = WebGLConstants.SRC_ALPHA;
  102697. blendFuncSeparate[3] = WebGLConstants.ONE_MINUS_SRC_ALPHA;
  102698. }
  102699. }
  102700. rendererRenderStates[id] = RenderState.fromCache({
  102701. frontFace : defined(statesFunctions.frontFace) ? statesFunctions.frontFace[0] : WebGLConstants.CCW,
  102702. cull : {
  102703. enabled : booleanStates[WebGLConstants.CULL_FACE],
  102704. face : defined(statesFunctions.cullFace) ? statesFunctions.cullFace[0] : WebGLConstants.BACK
  102705. },
  102706. lineWidth : defined(statesFunctions.lineWidth) ? statesFunctions.lineWidth[0] : 1.0,
  102707. polygonOffset : {
  102708. enabled : booleanStates[WebGLConstants.POLYGON_OFFSET_FILL],
  102709. factor : polygonOffset[0],
  102710. units : polygonOffset[1]
  102711. },
  102712. scissorTest : {
  102713. enabled : booleanStates[WebGLConstants.SCISSOR_TEST],
  102714. rectangle : {
  102715. x : scissor[0],
  102716. y : scissor[1],
  102717. width : scissor[2],
  102718. height : scissor[3]
  102719. }
  102720. },
  102721. depthRange : {
  102722. near : depthRange[0],
  102723. far : depthRange[1]
  102724. },
  102725. depthTest : {
  102726. enabled : booleanStates[WebGLConstants.DEPTH_TEST],
  102727. func : defined(statesFunctions.depthFunc) ? statesFunctions.depthFunc[0] : WebGLConstants.LESS
  102728. },
  102729. colorMask : {
  102730. red : colorMask[0],
  102731. green : colorMask[1],
  102732. blue : colorMask[2],
  102733. alpha : colorMask[3]
  102734. },
  102735. depthMask : defined(statesFunctions.depthMask) ? statesFunctions.depthMask[0] : true,
  102736. blending : {
  102737. enabled : booleanStates[WebGLConstants.BLEND],
  102738. color : {
  102739. red : blendColor[0],
  102740. green : blendColor[1],
  102741. blue : blendColor[2],
  102742. alpha : blendColor[3]
  102743. },
  102744. equationRgb : blendEquationSeparate[0],
  102745. equationAlpha : blendEquationSeparate[1],
  102746. functionSourceRgb : blendFuncSeparate[0],
  102747. functionDestinationRgb : blendFuncSeparate[1],
  102748. functionSourceAlpha : blendFuncSeparate[2],
  102749. functionDestinationAlpha : blendFuncSeparate[3]
  102750. }
  102751. });
  102752. }
  102753. // This doesn't support LOCAL, which we could add if it is ever used.
  102754. var scratchTranslationRtc = new Cartesian3();
  102755. var gltfSemanticUniforms = {
  102756. MODEL : function(uniformState, model) {
  102757. return function() {
  102758. return uniformState.model;
  102759. };
  102760. },
  102761. VIEW : function(uniformState, model) {
  102762. return function() {
  102763. return uniformState.view;
  102764. };
  102765. },
  102766. PROJECTION : function(uniformState, model) {
  102767. return function() {
  102768. return uniformState.projection;
  102769. };
  102770. },
  102771. MODELVIEW : function(uniformState, model) {
  102772. return function() {
  102773. return uniformState.modelView;
  102774. };
  102775. },
  102776. CESIUM_RTC_MODELVIEW : function(uniformState, model) {
  102777. // CESIUM_RTC extension
  102778. var mvRtc = new Matrix4();
  102779. return function() {
  102780. Matrix4.getTranslation(uniformState.model, scratchTranslationRtc);
  102781. Cartesian3.add(scratchTranslationRtc, model._rtcCenter, scratchTranslationRtc);
  102782. Matrix4.multiplyByPoint(uniformState.view, scratchTranslationRtc, scratchTranslationRtc);
  102783. return Matrix4.setTranslation(uniformState.modelView, scratchTranslationRtc, mvRtc);
  102784. };
  102785. },
  102786. MODELVIEWPROJECTION : function(uniformState, model) {
  102787. return function() {
  102788. return uniformState.modelViewProjection;
  102789. };
  102790. },
  102791. MODELINVERSE : function(uniformState, model) {
  102792. return function() {
  102793. return uniformState.inverseModel;
  102794. };
  102795. },
  102796. VIEWINVERSE : function(uniformState, model) {
  102797. return function() {
  102798. return uniformState.inverseView;
  102799. };
  102800. },
  102801. PROJECTIONINVERSE : function(uniformState, model) {
  102802. return function() {
  102803. return uniformState.inverseProjection;
  102804. };
  102805. },
  102806. MODELVIEWINVERSE : function(uniformState, model) {
  102807. return function() {
  102808. return uniformState.inverseModelView;
  102809. };
  102810. },
  102811. MODELVIEWPROJECTIONINVERSE : function(uniformState, model) {
  102812. return function() {
  102813. return uniformState.inverseModelViewProjection;
  102814. };
  102815. },
  102816. MODELINVERSETRANSPOSE : function(uniformState, model) {
  102817. return function() {
  102818. return uniformState.inverseTransposeModel;
  102819. };
  102820. },
  102821. MODELVIEWINVERSETRANSPOSE : function(uniformState, model) {
  102822. return function() {
  102823. return uniformState.normal;
  102824. };
  102825. },
  102826. VIEWPORT : function(uniformState, model) {
  102827. return function() {
  102828. return uniformState.viewportCartesian4;
  102829. };
  102830. }
  102831. // JOINTMATRIX created in createCommand()
  102832. };
  102833. ///////////////////////////////////////////////////////////////////////////
  102834. function getScalarUniformFunction(value, model) {
  102835. var that = {
  102836. value : value,
  102837. clone : function(source, result) {
  102838. return source;
  102839. },
  102840. func : function() {
  102841. return that.value;
  102842. }
  102843. };
  102844. return that;
  102845. }
  102846. function getVec2UniformFunction(value, model) {
  102847. var that = {
  102848. value : Cartesian2.fromArray(value),
  102849. clone : Cartesian2.clone,
  102850. func : function() {
  102851. return that.value;
  102852. }
  102853. };
  102854. return that;
  102855. }
  102856. function getVec3UniformFunction(value, model) {
  102857. var that = {
  102858. value : Cartesian3.fromArray(value),
  102859. clone : Cartesian3.clone,
  102860. func : function() {
  102861. return that.value;
  102862. }
  102863. };
  102864. return that;
  102865. }
  102866. function getVec4UniformFunction(value, model) {
  102867. var that = {
  102868. value : Cartesian4.fromArray(value),
  102869. clone : Cartesian4.clone,
  102870. func : function() {
  102871. return that.value;
  102872. }
  102873. };
  102874. return that;
  102875. }
  102876. function getMat2UniformFunction(value, model) {
  102877. var that = {
  102878. value : Matrix2.fromColumnMajorArray(value),
  102879. clone : Matrix2.clone,
  102880. func : function() {
  102881. return that.value;
  102882. }
  102883. };
  102884. return that;
  102885. }
  102886. function getMat3UniformFunction(value, model) {
  102887. var that = {
  102888. value : Matrix3.fromColumnMajorArray(value),
  102889. clone : Matrix3.clone,
  102890. func : function() {
  102891. return that.value;
  102892. }
  102893. };
  102894. return that;
  102895. }
  102896. function getMat4UniformFunction(value, model) {
  102897. var that = {
  102898. value : Matrix4.fromColumnMajorArray(value),
  102899. clone : Matrix4.clone,
  102900. func : function() {
  102901. return that.value;
  102902. }
  102903. };
  102904. return that;
  102905. }
  102906. ///////////////////////////////////////////////////////////////////////////
  102907. function DelayLoadedTextureUniform(value, model) {
  102908. this._value = undefined;
  102909. this._textureId = value;
  102910. this._model = model;
  102911. }
  102912. defineProperties(DelayLoadedTextureUniform.prototype, {
  102913. value : {
  102914. get : function() {
  102915. // Use the default texture (1x1 white) until the model's texture is loaded
  102916. if (!defined(this._value)) {
  102917. var texture = this._model._rendererResources.textures[this._textureId];
  102918. if (defined(texture)) {
  102919. this._value = texture;
  102920. } else {
  102921. return this._model._defaultTexture;
  102922. }
  102923. }
  102924. return this._value;
  102925. },
  102926. set : function(value) {
  102927. this._value = value;
  102928. }
  102929. }
  102930. });
  102931. DelayLoadedTextureUniform.prototype.clone = function(source, result) {
  102932. return source;
  102933. };
  102934. DelayLoadedTextureUniform.prototype.func = undefined;
  102935. ///////////////////////////////////////////////////////////////////////////
  102936. function getTextureUniformFunction(value, model) {
  102937. var uniform = new DelayLoadedTextureUniform(value, model);
  102938. // Define function here to access closure since 'this' can't be
  102939. // used when the Renderer sets uniforms.
  102940. uniform.func = function() {
  102941. return uniform.value;
  102942. };
  102943. return uniform;
  102944. }
  102945. var gltfUniformFunctions = {};
  102946. gltfUniformFunctions[WebGLConstants.FLOAT] = getScalarUniformFunction;
  102947. gltfUniformFunctions[WebGLConstants.FLOAT_VEC2] = getVec2UniformFunction;
  102948. gltfUniformFunctions[WebGLConstants.FLOAT_VEC3] = getVec3UniformFunction;
  102949. gltfUniformFunctions[WebGLConstants.FLOAT_VEC4] = getVec4UniformFunction;
  102950. gltfUniformFunctions[WebGLConstants.INT] = getScalarUniformFunction;
  102951. gltfUniformFunctions[WebGLConstants.INT_VEC2] = getVec2UniformFunction;
  102952. gltfUniformFunctions[WebGLConstants.INT_VEC3] = getVec3UniformFunction;
  102953. gltfUniformFunctions[WebGLConstants.INT_VEC4] = getVec4UniformFunction;
  102954. gltfUniformFunctions[WebGLConstants.BOOL] = getScalarUniformFunction;
  102955. gltfUniformFunctions[WebGLConstants.BOOL_VEC2] = getVec2UniformFunction;
  102956. gltfUniformFunctions[WebGLConstants.BOOL_VEC3] = getVec3UniformFunction;
  102957. gltfUniformFunctions[WebGLConstants.BOOL_VEC4] = getVec4UniformFunction;
  102958. gltfUniformFunctions[WebGLConstants.FLOAT_MAT2] = getMat2UniformFunction;
  102959. gltfUniformFunctions[WebGLConstants.FLOAT_MAT3] = getMat3UniformFunction;
  102960. gltfUniformFunctions[WebGLConstants.FLOAT_MAT4] = getMat4UniformFunction;
  102961. gltfUniformFunctions[WebGLConstants.SAMPLER_2D] = getTextureUniformFunction;
  102962. // GLTF_SPEC: Support SAMPLER_CUBE. https://github.com/KhronosGroup/glTF/issues/40
  102963. var gltfUniformsFromNode = {
  102964. MODEL : function(uniformState, model, runtimeNode) {
  102965. return function() {
  102966. return runtimeNode.computedMatrix;
  102967. };
  102968. },
  102969. VIEW : function(uniformState, model, runtimeNode) {
  102970. return function() {
  102971. return uniformState.view;
  102972. };
  102973. },
  102974. PROJECTION : function(uniformState, model, runtimeNode) {
  102975. return function() {
  102976. return uniformState.projection;
  102977. };
  102978. },
  102979. MODELVIEW : function(uniformState, model, runtimeNode) {
  102980. var mv = new Matrix4();
  102981. return function() {
  102982. return Matrix4.multiplyTransformation(uniformState.view, runtimeNode.computedMatrix, mv);
  102983. };
  102984. },
  102985. CESIUM_RTC_MODELVIEW : function(uniformState, model, runtimeNode) {
  102986. // CESIUM_RTC extension
  102987. var mvRtc = new Matrix4();
  102988. return function() {
  102989. Matrix4.multiplyTransformation(uniformState.view, runtimeNode.computedMatrix, mvRtc);
  102990. return Matrix4.setTranslation(mvRtc, model._rtcCenterEye, mvRtc);
  102991. };
  102992. },
  102993. MODELVIEWPROJECTION : function(uniformState, model, runtimeNode) {
  102994. var mvp = new Matrix4();
  102995. return function() {
  102996. Matrix4.multiplyTransformation(uniformState.view, runtimeNode.computedMatrix, mvp);
  102997. return Matrix4.multiply(uniformState._projection, mvp, mvp);
  102998. };
  102999. },
  103000. MODELINVERSE : function(uniformState, model, runtimeNode) {
  103001. var mInverse = new Matrix4();
  103002. return function() {
  103003. return Matrix4.inverse(runtimeNode.computedMatrix, mInverse);
  103004. };
  103005. },
  103006. VIEWINVERSE : function(uniformState, model) {
  103007. return function() {
  103008. return uniformState.inverseView;
  103009. };
  103010. },
  103011. PROJECTIONINVERSE : function(uniformState, model, runtimeNode) {
  103012. return function() {
  103013. return uniformState.inverseProjection;
  103014. };
  103015. },
  103016. MODELVIEWINVERSE : function(uniformState, model, runtimeNode) {
  103017. var mv = new Matrix4();
  103018. var mvInverse = new Matrix4();
  103019. return function() {
  103020. Matrix4.multiplyTransformation(uniformState.view, runtimeNode.computedMatrix, mv);
  103021. return Matrix4.inverse(mv, mvInverse);
  103022. };
  103023. },
  103024. MODELVIEWPROJECTIONINVERSE : function(uniformState, model, runtimeNode) {
  103025. var mvp = new Matrix4();
  103026. var mvpInverse = new Matrix4();
  103027. return function() {
  103028. Matrix4.multiplyTransformation(uniformState.view, runtimeNode.computedMatrix, mvp);
  103029. Matrix4.multiply(uniformState._projection, mvp, mvp);
  103030. return Matrix4.inverse(mvp, mvpInverse);
  103031. };
  103032. },
  103033. MODELINVERSETRANSPOSE : function(uniformState, model, runtimeNode) {
  103034. var mInverse = new Matrix4();
  103035. var mInverseTranspose = new Matrix3();
  103036. return function() {
  103037. Matrix4.inverse(runtimeNode.computedMatrix, mInverse);
  103038. Matrix4.getRotation(mInverse, mInverseTranspose);
  103039. return Matrix3.transpose(mInverseTranspose, mInverseTranspose);
  103040. };
  103041. },
  103042. MODELVIEWINVERSETRANSPOSE : function(uniformState, model, runtimeNode) {
  103043. var mv = new Matrix4();
  103044. var mvInverse = new Matrix4();
  103045. var mvInverseTranspose = new Matrix3();
  103046. return function() {
  103047. Matrix4.multiplyTransformation(uniformState.view, runtimeNode.computedMatrix, mv);
  103048. Matrix4.inverse(mv, mvInverse);
  103049. Matrix4.getRotation(mvInverse, mvInverseTranspose);
  103050. return Matrix3.transpose(mvInverseTranspose, mvInverseTranspose);
  103051. };
  103052. },
  103053. VIEWPORT : function(uniformState, model, runtimeNode) {
  103054. return function() {
  103055. return uniformState.viewportCartesian4;
  103056. };
  103057. }
  103058. };
  103059. function getUniformFunctionFromSource(source, model, semantic, uniformState) {
  103060. var runtimeNode = model._runtime.nodes[source];
  103061. return gltfUniformsFromNode[semantic](uniformState, model, runtimeNode);
  103062. }
  103063. function createUniformMaps(model, context) {
  103064. var loadResources = model._loadResources;
  103065. if (!loadResources.finishedProgramCreation()) {
  103066. return;
  103067. }
  103068. if (!loadResources.createUniformMaps) {
  103069. return;
  103070. }
  103071. loadResources.createUniformMaps = false;
  103072. var gltf = model.gltf;
  103073. var materials = gltf.materials;
  103074. var techniques = gltf.techniques;
  103075. var uniformMaps = model._uniformMaps;
  103076. for (var materialId in materials) {
  103077. if (materials.hasOwnProperty(materialId)) {
  103078. var material = materials[materialId];
  103079. var instanceParameters = material.values;
  103080. var technique = techniques[material.technique];
  103081. var parameters = technique.parameters;
  103082. var uniforms = technique.uniforms;
  103083. var uniformMap = {};
  103084. var uniformValues = {};
  103085. var jointMatrixUniformName;
  103086. // Uniform parameters
  103087. for (var name in uniforms) {
  103088. if (uniforms.hasOwnProperty(name)) {
  103089. var parameterName = uniforms[name];
  103090. var parameter = parameters[parameterName];
  103091. // GLTF_SPEC: This does not take into account uniform arrays,
  103092. // indicated by parameters with a count property.
  103093. //
  103094. // https://github.com/KhronosGroup/glTF/issues/258
  103095. // GLTF_SPEC: In this implementation, material parameters with a
  103096. // semantic or targeted via a source (for animation) are not
  103097. // targetable for material animations. Is this too strict?
  103098. //
  103099. // https://github.com/KhronosGroup/glTF/issues/142
  103100. if (defined(instanceParameters[parameterName])) {
  103101. // Parameter overrides by the instance technique
  103102. var uv = gltfUniformFunctions[parameter.type](instanceParameters[parameterName], model);
  103103. uniformMap[name] = uv.func;
  103104. uniformValues[parameterName] = uv;
  103105. } else if (defined(parameter.node)) {
  103106. uniformMap[name] = getUniformFunctionFromSource(parameter.node, model, parameter.semantic, context.uniformState);
  103107. } else if (defined(parameter.semantic)) {
  103108. if (parameter.semantic !== 'JOINTMATRIX') {
  103109. // Map glTF semantic to Cesium automatic uniform
  103110. uniformMap[name] = gltfSemanticUniforms[parameter.semantic](context.uniformState, model);
  103111. } else {
  103112. jointMatrixUniformName = name;
  103113. }
  103114. } else if (defined(parameter.value)) {
  103115. // Technique value that isn't overridden by a material
  103116. var uv2 = gltfUniformFunctions[parameter.type](parameter.value, model);
  103117. uniformMap[name] = uv2.func;
  103118. uniformValues[parameterName] = uv2;
  103119. }
  103120. }
  103121. }
  103122. var u = uniformMaps[materialId];
  103123. u.uniformMap = uniformMap; // uniform name -> function for the renderer
  103124. u.values = uniformValues; // material parameter name -> ModelMaterial for modifying the parameter at runtime
  103125. u.jointMatrixUniformName = jointMatrixUniformName;
  103126. }
  103127. }
  103128. }
  103129. function scaleFromMatrix5Array(matrix) {
  103130. return [matrix[0], matrix[1], matrix[2], matrix[3],
  103131. matrix[5], matrix[6], matrix[7], matrix[8],
  103132. matrix[10], matrix[11], matrix[12], matrix[13],
  103133. matrix[15], matrix[16], matrix[17], matrix[18]];
  103134. }
  103135. function translateFromMatrix5Array(matrix) {
  103136. return [matrix[20], matrix[21], matrix[22], matrix[23]];
  103137. }
  103138. function createUniformsForQuantizedAttributes(model, primitive, context) {
  103139. var gltf = model.gltf;
  103140. var accessors = gltf.accessors;
  103141. var programId = getProgramForPrimitive(model, primitive);
  103142. var quantizedUniforms = model._quantizedUniforms[programId];
  103143. var setUniforms = {};
  103144. var uniformMap = {};
  103145. for (var attribute in primitive.attributes) {
  103146. if (primitive.attributes.hasOwnProperty(attribute)) {
  103147. var accessorId = primitive.attributes[attribute];
  103148. var a = accessors[accessorId];
  103149. var extensions = a.extensions;
  103150. if (defined(extensions)) {
  103151. var quantizedAttributes = extensions.WEB3D_quantized_attributes;
  103152. if (defined(quantizedAttributes)) {
  103153. var decodeMatrix = quantizedAttributes.decodeMatrix;
  103154. var uniformVariable = 'gltf_u_dec_' + attribute.toLowerCase();
  103155. switch (a.type) {
  103156. case 'SCALAR':
  103157. uniformMap[uniformVariable] = getMat2UniformFunction(decodeMatrix, model).func;
  103158. setUniforms[uniformVariable] = true;
  103159. break;
  103160. case 'VEC2':
  103161. uniformMap[uniformVariable] = getMat3UniformFunction(decodeMatrix, model).func;
  103162. setUniforms[uniformVariable] = true;
  103163. break;
  103164. case 'VEC3':
  103165. uniformMap[uniformVariable] = getMat4UniformFunction(decodeMatrix, model).func;
  103166. setUniforms[uniformVariable] = true;
  103167. break;
  103168. case 'VEC4':
  103169. // VEC4 attributes are split into scale and translate because there is no mat5 in GLSL
  103170. var uniformVariableScale = uniformVariable + '_scale';
  103171. var uniformVariableTranslate = uniformVariable + '_translate';
  103172. uniformMap[uniformVariableScale] = getMat4UniformFunction(scaleFromMatrix5Array(decodeMatrix), model).func;
  103173. uniformMap[uniformVariableTranslate] = getVec4UniformFunction(translateFromMatrix5Array(decodeMatrix), model).func;
  103174. setUniforms[uniformVariableScale] = true;
  103175. setUniforms[uniformVariableTranslate] = true;
  103176. break;
  103177. }
  103178. }
  103179. }
  103180. }
  103181. }
  103182. // If there are any unset quantized uniforms in this program, they should be set to the identity
  103183. for (var quantizedUniform in quantizedUniforms) {
  103184. if (quantizedUniforms.hasOwnProperty(quantizedUniform)) {
  103185. if (!setUniforms[quantizedUniform]) {
  103186. var properties = quantizedUniforms[quantizedUniform];
  103187. if (defined(properties.mat)) {
  103188. if (properties.mat === 2) {
  103189. uniformMap[quantizedUniform] = getMat2UniformFunction(Matrix2.IDENTITY, model).func;
  103190. } else if (properties.mat === 3) {
  103191. uniformMap[quantizedUniform] = getMat3UniformFunction(Matrix3.IDENTITY, model).func;
  103192. } else if (properties.mat === 4) {
  103193. uniformMap[quantizedUniform] = getMat4UniformFunction(Matrix4.IDENTITY, model).func;
  103194. }
  103195. }
  103196. if (defined(properties.vec)) {
  103197. if (properties.vec === 4) {
  103198. uniformMap[quantizedUniform] = getVec4UniformFunction([0, 0, 0, 0], model).func;
  103199. }
  103200. }
  103201. }
  103202. }
  103203. }
  103204. return uniformMap;
  103205. }
  103206. function createPickColorFunction(color) {
  103207. return function() {
  103208. return color;
  103209. };
  103210. }
  103211. function createJointMatricesFunction(runtimeNode) {
  103212. return function() {
  103213. return runtimeNode.computedJointMatrices;
  103214. };
  103215. }
  103216. function createSilhouetteColorFunction(model) {
  103217. return function() {
  103218. return model.silhouetteColor;
  103219. };
  103220. }
  103221. function createSilhouetteSizeFunction(model) {
  103222. return function() {
  103223. return model.silhouetteSize;
  103224. };
  103225. }
  103226. function createColorFunction(model) {
  103227. return function() {
  103228. return model.color;
  103229. };
  103230. }
  103231. function createColorBlendFunction(model) {
  103232. return function() {
  103233. return ColorBlendMode.getColorBlend(model.colorBlendMode, model.colorBlendAmount);
  103234. };
  103235. }
  103236. function createCommand(model, gltfNode, runtimeNode, context, scene3DOnly) {
  103237. var nodeCommands = model._nodeCommands;
  103238. var pickIds = model._pickIds;
  103239. var allowPicking = model.allowPicking;
  103240. var runtimeMeshesByName = model._runtime.meshesByName;
  103241. var resources = model._rendererResources;
  103242. var rendererVertexArrays = resources.vertexArrays;
  103243. var rendererPrograms = resources.programs;
  103244. var rendererPickPrograms = resources.pickPrograms;
  103245. var rendererRenderStates = resources.renderStates;
  103246. var uniformMaps = model._uniformMaps;
  103247. var gltf = model.gltf;
  103248. var accessors = gltf.accessors;
  103249. var gltfMeshes = gltf.meshes;
  103250. var techniques = gltf.techniques;
  103251. var materials = gltf.materials;
  103252. var meshes = gltfNode.meshes;
  103253. var meshesLength = meshes.length;
  103254. for (var j = 0; j < meshesLength; ++j) {
  103255. var id = meshes[j];
  103256. var mesh = gltfMeshes[id];
  103257. var primitives = mesh.primitives;
  103258. var length = primitives.length;
  103259. // The glTF node hierarchy is a DAG so a node can have more than one
  103260. // parent, so a node may already have commands. If so, append more
  103261. // since they will have a different model matrix.
  103262. for (var i = 0; i < length; ++i) {
  103263. var primitive = primitives[i];
  103264. var ix = accessors[primitive.indices];
  103265. var material = materials[primitive.material];
  103266. var technique = techniques[material.technique];
  103267. var programId = technique.program;
  103268. var boundingSphere;
  103269. var positionAccessor = primitive.attributes.POSITION;
  103270. if (defined(positionAccessor)) {
  103271. var minMax = getAccessorMinMax(gltf, positionAccessor);
  103272. boundingSphere = BoundingSphere.fromCornerPoints(Cartesian3.fromArray(minMax.min), Cartesian3.fromArray(minMax.max));
  103273. }
  103274. var vertexArray = rendererVertexArrays[id + '.primitive.' + i];
  103275. var offset;
  103276. var count;
  103277. if (defined(ix)) {
  103278. count = ix.count;
  103279. offset = (ix.byteOffset / IndexDatatype.getSizeInBytes(ix.componentType)); // glTF has offset in bytes. Cesium has offsets in indices
  103280. }
  103281. else {
  103282. var positions = accessors[primitive.attributes.POSITION];
  103283. count = positions.count;
  103284. offset = 0;
  103285. }
  103286. var um = uniformMaps[primitive.material];
  103287. var uniformMap = um.uniformMap;
  103288. if (defined(um.jointMatrixUniformName)) {
  103289. var jointUniformMap = {};
  103290. jointUniformMap[um.jointMatrixUniformName] = createJointMatricesFunction(runtimeNode);
  103291. uniformMap = combine(uniformMap, jointUniformMap);
  103292. }
  103293. uniformMap = combine(uniformMap, {
  103294. gltf_color : createColorFunction(model),
  103295. gltf_colorBlend : createColorBlendFunction(model)
  103296. });
  103297. // Allow callback to modify the uniformMap
  103298. if (defined(model._uniformMapLoaded)) {
  103299. uniformMap = model._uniformMapLoaded(uniformMap, programId, runtimeNode);
  103300. }
  103301. // Add uniforms for decoding quantized attributes if used
  103302. if (usesExtension(model, 'WEB3D_quantized_attributes')) {
  103303. var quantizedUniformMap = createUniformsForQuantizedAttributes(model, primitive, context);
  103304. uniformMap = combine(uniformMap, quantizedUniformMap);
  103305. }
  103306. var rs = rendererRenderStates[material.technique];
  103307. // GLTF_SPEC: Offical means to determine translucency. https://github.com/KhronosGroup/glTF/issues/105
  103308. var isTranslucent = rs.blending.enabled;
  103309. var owner = {
  103310. primitive : defaultValue(model.pickPrimitive, model),
  103311. id : model.id,
  103312. node : runtimeNode.publicNode,
  103313. mesh : runtimeMeshesByName[mesh.name]
  103314. };
  103315. var castShadows = ShadowMode.castShadows(model._shadows);
  103316. var receiveShadows = ShadowMode.receiveShadows(model._shadows);
  103317. var command = new DrawCommand({
  103318. boundingVolume : new BoundingSphere(), // updated in update()
  103319. cull : model.cull,
  103320. modelMatrix : new Matrix4(), // computed in update()
  103321. primitiveType : primitive.mode,
  103322. vertexArray : vertexArray,
  103323. count : count,
  103324. offset : offset,
  103325. shaderProgram : rendererPrograms[technique.program],
  103326. castShadows : castShadows,
  103327. receiveShadows : receiveShadows,
  103328. uniformMap : uniformMap,
  103329. renderState : rs,
  103330. owner : owner,
  103331. pass : isTranslucent ? Pass.TRANSLUCENT : Pass.OPAQUE
  103332. });
  103333. var pickCommand;
  103334. if (allowPicking) {
  103335. var pickUniformMap;
  103336. // Callback to override default model picking
  103337. if (defined(model._pickFragmentShaderLoaded)) {
  103338. if (defined(model._pickUniformMapLoaded)) {
  103339. pickUniformMap = model._pickUniformMapLoaded(uniformMap);
  103340. } else {
  103341. // This is unlikely, but could happen if the override shader does not
  103342. // need new uniforms since, for example, its pick ids are coming from
  103343. // a vertex attribute or are baked into the shader source.
  103344. pickUniformMap = combine(uniformMap);
  103345. }
  103346. } else {
  103347. var pickId = context.createPickId(owner);
  103348. pickIds.push(pickId);
  103349. var pickUniforms = {
  103350. czm_pickColor : createPickColorFunction(pickId.color)
  103351. };
  103352. pickUniformMap = combine(uniformMap, pickUniforms);
  103353. }
  103354. pickCommand = new DrawCommand({
  103355. boundingVolume : new BoundingSphere(), // updated in update()
  103356. cull : model.cull,
  103357. modelMatrix : new Matrix4(), // computed in update()
  103358. primitiveType : primitive.mode,
  103359. vertexArray : vertexArray,
  103360. count : count,
  103361. offset : offset,
  103362. shaderProgram : rendererPickPrograms[technique.program],
  103363. uniformMap : pickUniformMap,
  103364. renderState : rs,
  103365. owner : owner,
  103366. pass : isTranslucent ? Pass.TRANSLUCENT : Pass.OPAQUE
  103367. });
  103368. }
  103369. var command2D;
  103370. var pickCommand2D;
  103371. if (!scene3DOnly) {
  103372. command2D = DrawCommand.shallowClone(command);
  103373. command2D.boundingVolume = new BoundingSphere(); // updated in update()
  103374. command2D.modelMatrix = new Matrix4(); // updated in update()
  103375. if (allowPicking) {
  103376. pickCommand2D = DrawCommand.shallowClone(pickCommand);
  103377. pickCommand2D.boundingVolume = new BoundingSphere(); // updated in update()
  103378. pickCommand2D.modelMatrix = new Matrix4(); // updated in update()
  103379. }
  103380. }
  103381. var nodeCommand = {
  103382. show : true,
  103383. boundingSphere : boundingSphere,
  103384. command : command,
  103385. pickCommand : pickCommand,
  103386. command2D : command2D,
  103387. pickCommand2D : pickCommand2D,
  103388. // Generated on demand when silhouette size is greater than 0.0 and silhouette alpha is greater than 0.0
  103389. silhouetteModelCommand : undefined,
  103390. silhouetteModelCommand2D : undefined,
  103391. silhouetteColorCommand : undefined,
  103392. silhouetteColorCommand2D : undefined,
  103393. // Generated on demand when color alpha is less than 1.0
  103394. translucentCommand : undefined,
  103395. translucentCommand2D : undefined
  103396. };
  103397. runtimeNode.commands.push(nodeCommand);
  103398. nodeCommands.push(nodeCommand);
  103399. }
  103400. }
  103401. }
  103402. function createRuntimeNodes(model, context, scene3DOnly) {
  103403. var loadResources = model._loadResources;
  103404. if (!loadResources.finishedEverythingButTextureCreation()) {
  103405. return;
  103406. }
  103407. if (!loadResources.createRuntimeNodes) {
  103408. return;
  103409. }
  103410. loadResources.createRuntimeNodes = false;
  103411. var rootNodes = [];
  103412. var runtimeNodes = model._runtime.nodes;
  103413. var gltf = model.gltf;
  103414. var nodes = gltf.nodes;
  103415. var scene = gltf.scenes[gltf.scene];
  103416. var sceneNodes = scene.nodes;
  103417. var length = sceneNodes.length;
  103418. var stack = [];
  103419. for (var i = 0; i < length; ++i) {
  103420. stack.push({
  103421. parentRuntimeNode : undefined,
  103422. gltfNode : nodes[sceneNodes[i]],
  103423. id : sceneNodes[i]
  103424. });
  103425. while (stack.length > 0) {
  103426. var n = stack.pop();
  103427. var parentRuntimeNode = n.parentRuntimeNode;
  103428. var gltfNode = n.gltfNode;
  103429. // Node hierarchy is a DAG so a node can have more than one parent so it may already exist
  103430. var runtimeNode = runtimeNodes[n.id];
  103431. if (runtimeNode.parents.length === 0) {
  103432. if (defined(gltfNode.matrix)) {
  103433. runtimeNode.matrix = Matrix4.fromColumnMajorArray(gltfNode.matrix);
  103434. } else {
  103435. // TRS converted to Cesium types
  103436. var rotation = gltfNode.rotation;
  103437. runtimeNode.translation = Cartesian3.fromArray(gltfNode.translation);
  103438. runtimeNode.rotation = Quaternion.unpack(rotation);
  103439. runtimeNode.scale = Cartesian3.fromArray(gltfNode.scale);
  103440. }
  103441. }
  103442. if (defined(parentRuntimeNode)) {
  103443. parentRuntimeNode.children.push(runtimeNode);
  103444. runtimeNode.parents.push(parentRuntimeNode);
  103445. } else {
  103446. rootNodes.push(runtimeNode);
  103447. }
  103448. if (defined(gltfNode.meshes)) {
  103449. createCommand(model, gltfNode, runtimeNode, context, scene3DOnly);
  103450. }
  103451. var children = gltfNode.children;
  103452. var childrenLength = children.length;
  103453. for (var k = 0; k < childrenLength; ++k) {
  103454. stack.push({
  103455. parentRuntimeNode : runtimeNode,
  103456. gltfNode : nodes[children[k]],
  103457. id : children[k]
  103458. });
  103459. }
  103460. }
  103461. }
  103462. model._runtime.rootNodes = rootNodes;
  103463. model._runtime.nodes = runtimeNodes;
  103464. }
  103465. function createResources(model, frameState) {
  103466. var context = frameState.context;
  103467. var scene3DOnly = frameState.scene3DOnly;
  103468. if (model._loadRendererResourcesFromCache) {
  103469. var resources = model._rendererResources;
  103470. var cachedResources = model._cachedRendererResources;
  103471. resources.buffers = cachedResources.buffers;
  103472. resources.vertexArrays = cachedResources.vertexArrays;
  103473. resources.programs = cachedResources.programs;
  103474. resources.pickPrograms = cachedResources.pickPrograms;
  103475. resources.silhouettePrograms = cachedResources.silhouettePrograms;
  103476. resources.textures = cachedResources.textures;
  103477. resources.samplers = cachedResources.samplers;
  103478. resources.renderStates = cachedResources.renderStates;
  103479. // Vertex arrays are unique to this model, create instead of using the cache.
  103480. if (defined(model._precreatedAttributes)) {
  103481. createVertexArrays(model, context);
  103482. }
  103483. } else {
  103484. createBuffers(model, context); // using glTF bufferViews
  103485. createPrograms(model, context);
  103486. createSamplers(model, context);
  103487. loadTexturesFromBufferViews(model);
  103488. createTextures(model, context);
  103489. }
  103490. createSkins(model);
  103491. createRuntimeAnimations(model);
  103492. if (!model._loadRendererResourcesFromCache) {
  103493. createVertexArrays(model, context); // using glTF meshes
  103494. createRenderStates(model, context); // using glTF materials/techniques/states
  103495. // Long-term, we might not cache render states if they could change
  103496. // due to an animation, e.g., a uniform going from opaque to transparent.
  103497. // Could use copy-on-write if it is worth it. Probably overkill.
  103498. }
  103499. createUniformMaps(model, context); // using glTF materials/techniques
  103500. createRuntimeNodes(model, context, scene3DOnly); // using glTF scene
  103501. }
  103502. ///////////////////////////////////////////////////////////////////////////
  103503. function getNodeMatrix(node, result) {
  103504. var publicNode = node.publicNode;
  103505. var publicMatrix = publicNode.matrix;
  103506. if (publicNode.useMatrix && defined(publicMatrix)) {
  103507. // Public matrix overrides orginial glTF matrix and glTF animations
  103508. Matrix4.clone(publicMatrix, result);
  103509. } else if (defined(node.matrix)) {
  103510. Matrix4.clone(node.matrix, result);
  103511. } else {
  103512. Matrix4.fromTranslationQuaternionRotationScale(node.translation, node.rotation, node.scale, result);
  103513. // Keep matrix returned by the node in-sync if the node is targeted by an animation. Only TRS nodes can be targeted.
  103514. publicNode.setMatrix(result);
  103515. }
  103516. }
  103517. var scratchNodeStack = [];
  103518. var scratchComputedMatrixIn2D = new Matrix4();
  103519. function updateNodeHierarchyModelMatrix(model, modelTransformChanged, justLoaded, projection) {
  103520. var maxDirtyNumber = model._maxDirtyNumber;
  103521. var allowPicking = model.allowPicking;
  103522. var rootNodes = model._runtime.rootNodes;
  103523. var length = rootNodes.length;
  103524. var nodeStack = scratchNodeStack;
  103525. var computedModelMatrix = model._computedModelMatrix;
  103526. if (model._mode !== SceneMode.SCENE3D) {
  103527. computedModelMatrix = Transforms.basisTo2D(projection, computedModelMatrix, scratchComputedMatrixIn2D);
  103528. }
  103529. for (var i = 0; i < length; ++i) {
  103530. var n = rootNodes[i];
  103531. getNodeMatrix(n, n.transformToRoot);
  103532. nodeStack.push(n);
  103533. while (nodeStack.length > 0) {
  103534. n = nodeStack.pop();
  103535. var transformToRoot = n.transformToRoot;
  103536. var commands = n.commands;
  103537. if ((n.dirtyNumber === maxDirtyNumber) || modelTransformChanged || justLoaded) {
  103538. var nodeMatrix = Matrix4.multiplyTransformation(computedModelMatrix, transformToRoot, n.computedMatrix);
  103539. var commandsLength = commands.length;
  103540. if (commandsLength > 0) {
  103541. // Node has meshes, which has primitives. Update their commands.
  103542. for (var j = 0 ; j < commandsLength; ++j) {
  103543. var primitiveCommand = commands[j];
  103544. var command = primitiveCommand.command;
  103545. Matrix4.clone(nodeMatrix, command.modelMatrix);
  103546. // PERFORMANCE_IDEA: Can use transformWithoutScale if no node up to the root has scale (including animation)
  103547. BoundingSphere.transform(primitiveCommand.boundingSphere, command.modelMatrix, command.boundingVolume);
  103548. if (defined(model._rtcCenter)) {
  103549. Cartesian3.add(model._rtcCenter, command.boundingVolume.center, command.boundingVolume.center);
  103550. }
  103551. if (allowPicking) {
  103552. var pickCommand = primitiveCommand.pickCommand;
  103553. Matrix4.clone(command.modelMatrix, pickCommand.modelMatrix);
  103554. BoundingSphere.clone(command.boundingVolume, pickCommand.boundingVolume);
  103555. }
  103556. // If the model crosses the IDL in 2D, it will be drawn in one viewport, but part of it
  103557. // will be clipped by the viewport. We create a second command that translates the model
  103558. // model matrix to the opposite side of the map so the part that was clipped in one viewport
  103559. // is drawn in the other.
  103560. command = primitiveCommand.command2D;
  103561. if (defined(command) && model._mode === SceneMode.SCENE2D) {
  103562. Matrix4.clone(nodeMatrix, command.modelMatrix);
  103563. command.modelMatrix[13] -= CesiumMath.sign(command.modelMatrix[13]) * 2.0 * CesiumMath.PI * projection.ellipsoid.maximumRadius;
  103564. BoundingSphere.transform(primitiveCommand.boundingSphere, command.modelMatrix, command.boundingVolume);
  103565. if (allowPicking) {
  103566. var pickCommand2D = primitiveCommand.pickCommand2D;
  103567. Matrix4.clone(command.modelMatrix, pickCommand2D.modelMatrix);
  103568. BoundingSphere.clone(command.boundingVolume, pickCommand2D.boundingVolume);
  103569. }
  103570. }
  103571. }
  103572. }
  103573. }
  103574. var children = n.children;
  103575. var childrenLength = children.length;
  103576. for (var k = 0; k < childrenLength; ++k) {
  103577. var child = children[k];
  103578. // A node's transform needs to be updated if
  103579. // - It was targeted for animation this frame, or
  103580. // - Any of its ancestors were targeted for animation this frame
  103581. // PERFORMANCE_IDEA: if a child has multiple parents and only one of the parents
  103582. // is dirty, all the subtrees for each child instance will be dirty; we probably
  103583. // won't see this in the wild often.
  103584. child.dirtyNumber = Math.max(child.dirtyNumber, n.dirtyNumber);
  103585. if ((child.dirtyNumber === maxDirtyNumber) || justLoaded) {
  103586. // Don't check for modelTransformChanged since if only the model's model matrix changed,
  103587. // we do not need to rebuild the local transform-to-root, only the final
  103588. // [model's-model-matrix][transform-to-root] above.
  103589. getNodeMatrix(child, child.transformToRoot);
  103590. Matrix4.multiplyTransformation(transformToRoot, child.transformToRoot, child.transformToRoot);
  103591. }
  103592. nodeStack.push(child);
  103593. }
  103594. }
  103595. }
  103596. ++model._maxDirtyNumber;
  103597. }
  103598. var scratchObjectSpace = new Matrix4();
  103599. function applySkins(model) {
  103600. var skinnedNodes = model._runtime.skinnedNodes;
  103601. var length = skinnedNodes.length;
  103602. for (var i = 0; i < length; ++i) {
  103603. var node = skinnedNodes[i];
  103604. scratchObjectSpace = Matrix4.inverseTransformation(node.transformToRoot, scratchObjectSpace);
  103605. var computedJointMatrices = node.computedJointMatrices;
  103606. var joints = node.joints;
  103607. var bindShapeMatrix = node.bindShapeMatrix;
  103608. var inverseBindMatrices = node.inverseBindMatrices;
  103609. var inverseBindMatricesLength = inverseBindMatrices.length;
  103610. for (var m = 0; m < inverseBindMatricesLength; ++m) {
  103611. // [joint-matrix] = [node-to-root^-1][joint-to-root][inverse-bind][bind-shape]
  103612. if (!defined(computedJointMatrices[m])) {
  103613. computedJointMatrices[m] = new Matrix4();
  103614. }
  103615. computedJointMatrices[m] = Matrix4.multiplyTransformation(scratchObjectSpace, joints[m].transformToRoot, computedJointMatrices[m]);
  103616. computedJointMatrices[m] = Matrix4.multiplyTransformation(computedJointMatrices[m], inverseBindMatrices[m], computedJointMatrices[m]);
  103617. if (defined(bindShapeMatrix)) {
  103618. // Optimization for when bind shape matrix is the identity.
  103619. computedJointMatrices[m] = Matrix4.multiplyTransformation(computedJointMatrices[m], bindShapeMatrix, computedJointMatrices[m]);
  103620. }
  103621. }
  103622. }
  103623. }
  103624. function updatePerNodeShow(model) {
  103625. // Totally not worth it, but we could optimize this:
  103626. // http://blogs.agi.com/insight3d/index.php/2008/02/13/deletion-in-bounding-volume-hierarchies/
  103627. var rootNodes = model._runtime.rootNodes;
  103628. var length = rootNodes.length;
  103629. var nodeStack = scratchNodeStack;
  103630. for (var i = 0; i < length; ++i) {
  103631. var n = rootNodes[i];
  103632. n.computedShow = n.publicNode.show;
  103633. nodeStack.push(n);
  103634. while (nodeStack.length > 0) {
  103635. n = nodeStack.pop();
  103636. var show = n.computedShow;
  103637. var nodeCommands = n.commands;
  103638. var nodeCommandsLength = nodeCommands.length;
  103639. for (var j = 0 ; j < nodeCommandsLength; ++j) {
  103640. nodeCommands[j].show = show;
  103641. }
  103642. // if commandsLength is zero, the node has a light or camera
  103643. var children = n.children;
  103644. var childrenLength = children.length;
  103645. for (var k = 0; k < childrenLength; ++k) {
  103646. var child = children[k];
  103647. // Parent needs to be shown for child to be shown.
  103648. child.computedShow = show && child.publicNode.show;
  103649. nodeStack.push(child);
  103650. }
  103651. }
  103652. }
  103653. }
  103654. function updatePickIds(model, context) {
  103655. var id = model.id;
  103656. if (model._id !== id) {
  103657. model._id = id;
  103658. var pickIds = model._pickIds;
  103659. var length = pickIds.length;
  103660. for (var i = 0; i < length; ++i) {
  103661. pickIds[i].object.id = id;
  103662. }
  103663. }
  103664. }
  103665. function updateWireframe(model) {
  103666. if (model._debugWireframe !== model.debugWireframe) {
  103667. model._debugWireframe = model.debugWireframe;
  103668. // This assumes the original primitive was TRIANGLES and that the triangles
  103669. // are connected for the wireframe to look perfect.
  103670. var primitiveType = model.debugWireframe ? PrimitiveType.LINES : PrimitiveType.TRIANGLES;
  103671. var nodeCommands = model._nodeCommands;
  103672. var length = nodeCommands.length;
  103673. for (var i = 0; i < length; ++i) {
  103674. nodeCommands[i].command.primitiveType = primitiveType;
  103675. }
  103676. }
  103677. }
  103678. function updateShowBoundingVolume(model) {
  103679. if (model.debugShowBoundingVolume !== model._debugShowBoundingVolume) {
  103680. model._debugShowBoundingVolume = model.debugShowBoundingVolume;
  103681. var debugShowBoundingVolume = model.debugShowBoundingVolume;
  103682. var nodeCommands = model._nodeCommands;
  103683. var length = nodeCommands.length;
  103684. for (var i = 0; i < length; ++i) {
  103685. nodeCommands[i].command.debugShowBoundingVolume = debugShowBoundingVolume;
  103686. }
  103687. }
  103688. }
  103689. function updateShadows(model) {
  103690. if (model.shadows !== model._shadows) {
  103691. model._shadows = model.shadows;
  103692. var castShadows = ShadowMode.castShadows(model.shadows);
  103693. var receiveShadows = ShadowMode.receiveShadows(model.shadows);
  103694. var nodeCommands = model._nodeCommands;
  103695. var length = nodeCommands.length;
  103696. for (var i = 0; i < length; i++) {
  103697. var nodeCommand = nodeCommands[i];
  103698. nodeCommand.command.castShadows = castShadows;
  103699. nodeCommand.command.receiveShadows = receiveShadows;
  103700. }
  103701. }
  103702. }
  103703. function getTranslucentRenderState(renderState) {
  103704. var rs = clone(renderState, true);
  103705. rs.cull.enabled = false;
  103706. rs.depthTest.enabled = true;
  103707. rs.depthMask = false;
  103708. rs.blending = BlendingState.ALPHA_BLEND;
  103709. return RenderState.fromCache(rs);
  103710. }
  103711. function deriveTranslucentCommand(command) {
  103712. var translucentCommand = DrawCommand.shallowClone(command);
  103713. translucentCommand.pass = Pass.TRANSLUCENT;
  103714. translucentCommand.renderState = getTranslucentRenderState(command.renderState);
  103715. return translucentCommand;
  103716. }
  103717. function updateColor(model, frameState) {
  103718. // Generate translucent commands when the blend color has an alpha in the range (0.0, 1.0) exclusive
  103719. var scene3DOnly = frameState.scene3DOnly;
  103720. var alpha = model.color.alpha;
  103721. if ((alpha > 0.0) && (alpha < 1.0)) {
  103722. var nodeCommands = model._nodeCommands;
  103723. var length = nodeCommands.length;
  103724. if (!defined(nodeCommands[0].translucentCommand)) {
  103725. for (var i = 0; i < length; ++i) {
  103726. var nodeCommand = nodeCommands[i];
  103727. var command = nodeCommand.command;
  103728. nodeCommand.translucentCommand = deriveTranslucentCommand(command);
  103729. if (!scene3DOnly) {
  103730. var command2D = nodeCommand.command2D;
  103731. nodeCommand.translucentCommand2D = deriveTranslucentCommand(command2D);
  103732. }
  103733. }
  103734. }
  103735. }
  103736. }
  103737. function getProgramId(model, program) {
  103738. var programs = model._rendererResources.programs;
  103739. for (var id in programs) {
  103740. if (programs.hasOwnProperty(id)) {
  103741. if (programs[id] === program) {
  103742. return id;
  103743. }
  103744. }
  103745. }
  103746. }
  103747. function createSilhouetteProgram(model, program, frameState) {
  103748. var vs = program.vertexShaderSource.sources[0];
  103749. var attributeLocations = program._attributeLocations;
  103750. var normalAttributeName = model._normalAttributeName;
  103751. // Modified from http://forum.unity3d.com/threads/toon-outline-but-with-diffuse-surface.24668/
  103752. vs = ShaderSource.replaceMain(vs, 'gltf_silhouette_main');
  103753. vs +=
  103754. 'uniform float gltf_silhouetteSize; \n' +
  103755. 'void main() \n' +
  103756. '{ \n' +
  103757. ' gltf_silhouette_main(); \n' +
  103758. ' vec3 n = normalize(czm_normal3D * ' + normalAttributeName + '); \n' +
  103759. ' n.x *= czm_projection[0][0]; \n' +
  103760. ' n.y *= czm_projection[1][1]; \n' +
  103761. ' vec4 clip = gl_Position; \n' +
  103762. ' clip.xy += n.xy * clip.w * gltf_silhouetteSize / czm_viewport.z; \n' +
  103763. ' gl_Position = clip; \n' +
  103764. '}';
  103765. var fs =
  103766. 'uniform vec4 gltf_silhouetteColor; \n' +
  103767. 'void main() \n' +
  103768. '{ \n' +
  103769. ' gl_FragColor = gltf_silhouetteColor; \n' +
  103770. '}';
  103771. return ShaderProgram.fromCache({
  103772. context : frameState.context,
  103773. vertexShaderSource : vs,
  103774. fragmentShaderSource : fs,
  103775. attributeLocations : attributeLocations
  103776. });
  103777. }
  103778. function hasSilhouette(model, frameState) {
  103779. return silhouetteSupported(frameState.context) && (model.silhouetteSize > 0.0) && (model.silhouetteColor.alpha > 0.0) && defined(model._normalAttributeName);
  103780. }
  103781. function hasTranslucentCommands(model) {
  103782. var nodeCommands = model._nodeCommands;
  103783. var length = nodeCommands.length;
  103784. for (var i = 0; i < length; ++i) {
  103785. var nodeCommand = nodeCommands[i];
  103786. var command = nodeCommand.command;
  103787. if (command.pass === Pass.TRANSLUCENT) {
  103788. return true;
  103789. }
  103790. }
  103791. return false;
  103792. }
  103793. function isTranslucent(model) {
  103794. return (model.color.alpha > 0.0) && (model.color.alpha < 1.0);
  103795. }
  103796. function isInvisible(model) {
  103797. return (model.color.alpha === 0.0);
  103798. }
  103799. function alphaDirty(currAlpha, prevAlpha) {
  103800. // Returns whether the alpha state has changed between invisible, translucent, or opaque
  103801. return (Math.floor(currAlpha) !== Math.floor(prevAlpha)) || (Math.ceil(currAlpha) !== Math.ceil(prevAlpha));
  103802. }
  103803. var silhouettesLength = 0;
  103804. function createSilhouetteCommands(model, frameState) {
  103805. // Wrap around after exceeding the 8-bit stencil limit.
  103806. // The reference is unique to each model until this point.
  103807. var stencilReference = (++silhouettesLength) % 255;
  103808. // If the model is translucent the silhouette needs to be in the translucent pass.
  103809. // Otherwise the silhouette would be rendered before the model.
  103810. var silhouetteTranslucent = hasTranslucentCommands(model) || isTranslucent(model) || (model.silhouetteColor.alpha < 1.0);
  103811. var silhouettePrograms = model._rendererResources.silhouettePrograms;
  103812. var scene3DOnly = frameState.scene3DOnly;
  103813. var nodeCommands = model._nodeCommands;
  103814. var length = nodeCommands.length;
  103815. for (var i = 0; i < length; ++i) {
  103816. var nodeCommand = nodeCommands[i];
  103817. var command = nodeCommand.command;
  103818. // Create model command
  103819. var modelCommand = isTranslucent(model) ? nodeCommand.translucentCommand : command;
  103820. var silhouetteModelCommand = DrawCommand.shallowClone(modelCommand);
  103821. var renderState = clone(modelCommand.renderState);
  103822. // Write the reference value into the stencil buffer.
  103823. renderState.stencilTest = {
  103824. enabled : true,
  103825. frontFunction : WebGLConstants.ALWAYS,
  103826. backFunction : WebGLConstants.ALWAYS,
  103827. reference : stencilReference,
  103828. mask : ~0,
  103829. frontOperation : {
  103830. fail : WebGLConstants.KEEP,
  103831. zFail : WebGLConstants.KEEP,
  103832. zPass : WebGLConstants.REPLACE
  103833. },
  103834. backOperation : {
  103835. fail : WebGLConstants.KEEP,
  103836. zFail : WebGLConstants.KEEP,
  103837. zPass : WebGLConstants.REPLACE
  103838. }
  103839. };
  103840. if (isInvisible(model)) {
  103841. // When the model is invisible disable color and depth writes but still write into the stencil buffer
  103842. renderState.colorMask = {
  103843. red : false,
  103844. green : false,
  103845. blue : false,
  103846. alpha : false
  103847. };
  103848. renderState.depthMask = false;
  103849. }
  103850. renderState = RenderState.fromCache(renderState);
  103851. silhouetteModelCommand.renderState = renderState;
  103852. nodeCommand.silhouetteModelCommand = silhouetteModelCommand;
  103853. // Create color command
  103854. var silhouetteColorCommand = DrawCommand.shallowClone(command);
  103855. renderState = clone(command.renderState, true);
  103856. renderState.depthTest.enabled = true;
  103857. renderState.cull.enabled = false;
  103858. if (silhouetteTranslucent) {
  103859. silhouetteColorCommand.pass = Pass.TRANSLUCENT;
  103860. renderState.depthMask = false;
  103861. renderState.blending = BlendingState.ALPHA_BLEND;
  103862. }
  103863. // Only render silhouette if the value in the stencil buffer equals the reference
  103864. renderState.stencilTest = {
  103865. enabled : true,
  103866. frontFunction : WebGLConstants.NOTEQUAL,
  103867. backFunction : WebGLConstants.NOTEQUAL,
  103868. reference : stencilReference,
  103869. mask : ~0,
  103870. frontOperation : {
  103871. fail : WebGLConstants.KEEP,
  103872. zFail : WebGLConstants.KEEP,
  103873. zPass : WebGLConstants.KEEP
  103874. },
  103875. backOperation : {
  103876. fail : WebGLConstants.KEEP,
  103877. zFail : WebGLConstants.KEEP,
  103878. zPass : WebGLConstants.KEEP
  103879. }
  103880. };
  103881. renderState = RenderState.fromCache(renderState);
  103882. // If the silhouette program has already been cached use it
  103883. var program = command.shaderProgram;
  103884. var id = getProgramId(model, program);
  103885. var silhouetteProgram = silhouettePrograms[id];
  103886. if (!defined(silhouetteProgram)) {
  103887. silhouetteProgram = createSilhouetteProgram(model, program, frameState);
  103888. silhouettePrograms[id] = silhouetteProgram;
  103889. }
  103890. var silhouetteUniformMap = combine(command.uniformMap, {
  103891. gltf_silhouetteColor : createSilhouetteColorFunction(model),
  103892. gltf_silhouetteSize : createSilhouetteSizeFunction(model)
  103893. });
  103894. silhouetteColorCommand.renderState = renderState;
  103895. silhouetteColorCommand.shaderProgram = silhouetteProgram;
  103896. silhouetteColorCommand.uniformMap = silhouetteUniformMap;
  103897. silhouetteColorCommand.castShadows = false;
  103898. silhouetteColorCommand.receiveShadows = false;
  103899. nodeCommand.silhouetteColorCommand = silhouetteColorCommand;
  103900. if (!scene3DOnly) {
  103901. var command2D = nodeCommand.command2D;
  103902. var silhouetteModelCommand2D = DrawCommand.shallowClone(silhouetteModelCommand);
  103903. silhouetteModelCommand2D.boundingVolume = command2D.boundingVolume;
  103904. silhouetteModelCommand2D.modelMatrix = command2D.modelMatrix;
  103905. nodeCommand.silhouetteModelCommand2D = silhouetteModelCommand2D;
  103906. var silhouetteColorCommand2D = DrawCommand.shallowClone(silhouetteColorCommand);
  103907. silhouetteModelCommand2D.boundingVolume = command2D.boundingVolume;
  103908. silhouetteModelCommand2D.modelMatrix = command2D.modelMatrix;
  103909. nodeCommand.silhouetteColorCommand2D = silhouetteColorCommand2D;
  103910. }
  103911. }
  103912. }
  103913. function updateSilhouette(model, frameState) {
  103914. // Generate silhouette commands when the silhouette size is greater than 0.0 and the alpha is greater than 0.0
  103915. // There are two silhouette commands:
  103916. // 1. silhouetteModelCommand : render model normally while enabling stencil mask
  103917. // 2. silhouetteColorCommand : render enlarged model with a solid color while enabling stencil tests
  103918. if (!hasSilhouette(model, frameState)) {
  103919. return;
  103920. }
  103921. var nodeCommands = model._nodeCommands;
  103922. var dirty = alphaDirty(model.color.alpha, model._color.alpha) ||
  103923. alphaDirty(model.silhouetteColor.alpha, model._silhouetteColor.alpha) ||
  103924. !defined(nodeCommands[0].silhouetteModelCommand);
  103925. Color.clone(model.color, model._color);
  103926. Color.clone(model.silhouetteColor, model._silhouetteColor);
  103927. if (dirty) {
  103928. createSilhouetteCommands(model, frameState);
  103929. }
  103930. }
  103931. var scratchBoundingSphere = new BoundingSphere();
  103932. function scaleInPixels(positionWC, radius, frameState) {
  103933. scratchBoundingSphere.center = positionWC;
  103934. scratchBoundingSphere.radius = radius;
  103935. return frameState.camera.getPixelSize(scratchBoundingSphere, frameState.context.drawingBufferWidth, frameState.context.drawingBufferHeight);
  103936. }
  103937. var scratchPosition = new Cartesian3();
  103938. var scratchCartographic = new Cartographic();
  103939. function getScale(model, frameState) {
  103940. var scale = model.scale;
  103941. if (model.minimumPixelSize !== 0.0) {
  103942. // Compute size of bounding sphere in pixels
  103943. var context = frameState.context;
  103944. var maxPixelSize = Math.max(context.drawingBufferWidth, context.drawingBufferHeight);
  103945. var m = defined(model._clampedModelMatrix) ? model._clampedModelMatrix : model.modelMatrix;
  103946. scratchPosition.x = m[12];
  103947. scratchPosition.y = m[13];
  103948. scratchPosition.z = m[14];
  103949. if (defined(model._rtcCenter)) {
  103950. Cartesian3.add(model._rtcCenter, scratchPosition, scratchPosition);
  103951. }
  103952. if (model._mode !== SceneMode.SCENE3D) {
  103953. var projection = frameState.mapProjection;
  103954. var cartographic = projection.ellipsoid.cartesianToCartographic(scratchPosition, scratchCartographic);
  103955. projection.project(cartographic, scratchPosition);
  103956. Cartesian3.fromElements(scratchPosition.z, scratchPosition.x, scratchPosition.y, scratchPosition);
  103957. }
  103958. var radius = model.boundingSphere.radius;
  103959. var metersPerPixel = scaleInPixels(scratchPosition, radius, frameState);
  103960. // metersPerPixel is always > 0.0
  103961. var pixelsPerMeter = 1.0 / metersPerPixel;
  103962. var diameterInPixels = Math.min(pixelsPerMeter * (2.0 * radius), maxPixelSize);
  103963. // Maintain model's minimum pixel size
  103964. if (diameterInPixels < model.minimumPixelSize) {
  103965. scale = (model.minimumPixelSize * metersPerPixel) / (2.0 * model._initialRadius);
  103966. }
  103967. }
  103968. return defined(model.maximumScale) ? Math.min(model.maximumScale, scale) : scale;
  103969. }
  103970. function releaseCachedGltf(model) {
  103971. if (defined(model._cacheKey) && defined(model._cachedGltf) && (--model._cachedGltf.count === 0)) {
  103972. delete gltfCache[model._cacheKey];
  103973. }
  103974. model._cachedGltf = undefined;
  103975. }
  103976. function checkSupportedExtensions(model) {
  103977. var extensionsUsed = model.gltf.extensionsUsed;
  103978. if (defined(extensionsUsed)) {
  103979. var extensionsUsedCount = extensionsUsed.length;
  103980. for (var index=0;index<extensionsUsedCount;++index) {
  103981. var extension = extensionsUsed[index];
  103982. if (extension !== 'CESIUM_RTC' && extension !== 'KHR_binary_glTF' &&
  103983. extension !== 'KHR_materials_common' && extension !== 'WEB3D_quantized_attributes') {
  103984. throw new RuntimeError('Unsupported glTF Extension: ' + extension);
  103985. }
  103986. }
  103987. }
  103988. }
  103989. ///////////////////////////////////////////////////////////////////////////
  103990. function CachedRendererResources(context, cacheKey) {
  103991. this.buffers = undefined;
  103992. this.vertexArrays = undefined;
  103993. this.programs = undefined;
  103994. this.pickPrograms = undefined;
  103995. this.silhouettePrograms = undefined;
  103996. this.textures = undefined;
  103997. this.samplers = undefined;
  103998. this.renderStates = undefined;
  103999. this.ready = false;
  104000. this.context = context;
  104001. this.cacheKey = cacheKey;
  104002. this.count = 0;
  104003. }
  104004. function destroy(property) {
  104005. for (var name in property) {
  104006. if (property.hasOwnProperty(name)) {
  104007. property[name].destroy();
  104008. }
  104009. }
  104010. }
  104011. function destroyCachedRendererResources(resources) {
  104012. destroy(resources.buffers);
  104013. destroy(resources.vertexArrays);
  104014. destroy(resources.programs);
  104015. destroy(resources.pickPrograms);
  104016. destroy(resources.silhouettePrograms);
  104017. destroy(resources.textures);
  104018. }
  104019. CachedRendererResources.prototype.release = function() {
  104020. if (--this.count === 0) {
  104021. if (defined(this.cacheKey)) {
  104022. // Remove if this was cached
  104023. delete this.context.cache.modelRendererResourceCache[this.cacheKey];
  104024. }
  104025. destroyCachedRendererResources(this);
  104026. return destroyObject(this);
  104027. }
  104028. return undefined;
  104029. };
  104030. ///////////////////////////////////////////////////////////////////////////
  104031. function getUpdateHeightCallback(model, ellipsoid, cartoPosition) {
  104032. return function (clampedPosition) {
  104033. if (model.heightReference === HeightReference.RELATIVE_TO_GROUND) {
  104034. var clampedCart = ellipsoid.cartesianToCartographic(clampedPosition, scratchCartographic);
  104035. clampedCart.height += cartoPosition.height;
  104036. ellipsoid.cartographicToCartesian(clampedCart, clampedPosition);
  104037. }
  104038. var clampedModelMatrix = model._clampedModelMatrix;
  104039. // Modify clamped model matrix to use new height
  104040. Matrix4.clone(model.modelMatrix, clampedModelMatrix);
  104041. clampedModelMatrix[12] = clampedPosition.x;
  104042. clampedModelMatrix[13] = clampedPosition.y;
  104043. clampedModelMatrix[14] = clampedPosition.z;
  104044. model._heightChanged = true;
  104045. };
  104046. }
  104047. function updateClamping(model) {
  104048. if (defined(model._removeUpdateHeightCallback)) {
  104049. model._removeUpdateHeightCallback();
  104050. model._removeUpdateHeightCallback = undefined;
  104051. }
  104052. var scene = model._scene;
  104053. if (!defined(scene) || (model.heightReference === HeightReference.NONE)) {
  104054. if (model.heightReference !== HeightReference.NONE) {
  104055. throw new DeveloperError('Height reference is not supported without a scene.');
  104056. }
  104057. model._clampedModelMatrix = undefined;
  104058. return;
  104059. }
  104060. var globe = scene.globe;
  104061. var ellipsoid = globe.ellipsoid;
  104062. // Compute cartographic position so we don't recompute every update
  104063. var modelMatrix = model.modelMatrix;
  104064. scratchPosition.x = modelMatrix[12];
  104065. scratchPosition.y = modelMatrix[13];
  104066. scratchPosition.z = modelMatrix[14];
  104067. var cartoPosition = ellipsoid.cartesianToCartographic(scratchPosition);
  104068. if (!defined(model._clampedModelMatrix)) {
  104069. model._clampedModelMatrix = Matrix4.clone(modelMatrix, new Matrix4());
  104070. }
  104071. // Install callback to handle updating of terrain tiles
  104072. var surface = globe._surface;
  104073. model._removeUpdateHeightCallback = surface.updateHeight(cartoPosition, getUpdateHeightCallback(model, ellipsoid, cartoPosition));
  104074. // Set the correct height now
  104075. var height = globe.getHeight(cartoPosition);
  104076. if (defined(height)) {
  104077. // Get callback with cartoPosition being the non-clamped position
  104078. var cb = getUpdateHeightCallback(model, ellipsoid, cartoPosition);
  104079. // Compute the clamped cartesian and call updateHeight callback
  104080. Cartographic.clone(cartoPosition, scratchCartographic);
  104081. scratchCartographic.height = height;
  104082. ellipsoid.cartographicToCartesian(scratchCartographic, scratchPosition);
  104083. cb(scratchPosition);
  104084. }
  104085. }
  104086. var scratchDisplayConditionCartesian = new Cartesian3();
  104087. var scratchDistanceDisplayConditionCartographic = new Cartographic();
  104088. function distanceDisplayConditionVisible(model, frameState) {
  104089. var distance2;
  104090. var ddc = model.distanceDisplayCondition;
  104091. var nearSquared = ddc.near * ddc.near;
  104092. var farSquared = ddc.far * ddc.far;
  104093. if (frameState.mode === SceneMode.SCENE2D) {
  104094. var frustum2DWidth = frameState.camera.frustum.right - frameState.camera.frustum.left;
  104095. distance2 = frustum2DWidth * 0.5;
  104096. distance2 = distance2 * distance2;
  104097. } else {
  104098. // Distance to center of primitive's reference frame
  104099. var position = Matrix4.getTranslation(model.modelMatrix, scratchDisplayConditionCartesian);
  104100. if (frameState.mode === SceneMode.COLUMBUS_VIEW) {
  104101. var projection = frameState.mapProjection;
  104102. var ellipsoid = projection.ellipsoid;
  104103. var cartographic = ellipsoid.cartesianToCartographic(position, scratchDistanceDisplayConditionCartographic);
  104104. position = projection.project(cartographic, position);
  104105. Cartesian3.fromElements(position.z, position.x, position.y, position);
  104106. }
  104107. distance2 = Cartesian3.distanceSquared(position, frameState.camera.positionWC);
  104108. }
  104109. return (distance2 >= nearSquared) && (distance2 <= farSquared);
  104110. }
  104111. /**
  104112. * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
  104113. * get the draw commands needed to render this primitive.
  104114. * <p>
  104115. * Do not call this function directly. This is documented just to
  104116. * list the exceptions that may be propagated when the scene is rendered:
  104117. * </p>
  104118. *
  104119. * @exception {RuntimeError} Failed to load external reference.
  104120. */
  104121. Model.prototype.update = function(frameState) {
  104122. if (frameState.mode === SceneMode.MORPHING) {
  104123. return;
  104124. }
  104125. var context = frameState.context;
  104126. this._defaultTexture = context.defaultTexture;
  104127. if ((this._state === ModelState.NEEDS_LOAD) && defined(this.gltf)) {
  104128. // Use renderer resources from cache instead of loading/creating them?
  104129. var cachedRendererResources;
  104130. var cacheKey = this.cacheKey;
  104131. if (defined(cacheKey)) {
  104132. context.cache.modelRendererResourceCache = defaultValue(context.cache.modelRendererResourceCache, {});
  104133. var modelCaches = context.cache.modelRendererResourceCache;
  104134. cachedRendererResources = modelCaches[this.cacheKey];
  104135. if (defined(cachedRendererResources)) {
  104136. if (!cachedRendererResources.ready) {
  104137. // Cached resources for the model are not loaded yet. We'll
  104138. // try again every frame until they are.
  104139. return;
  104140. }
  104141. ++cachedRendererResources.count;
  104142. this._loadRendererResourcesFromCache = true;
  104143. } else {
  104144. cachedRendererResources = new CachedRendererResources(context, cacheKey);
  104145. cachedRendererResources.count = 1;
  104146. modelCaches[this.cacheKey] = cachedRendererResources;
  104147. }
  104148. this._cachedRendererResources = cachedRendererResources;
  104149. } else {
  104150. cachedRendererResources = new CachedRendererResources(context);
  104151. cachedRendererResources.count = 1;
  104152. this._cachedRendererResources = cachedRendererResources;
  104153. }
  104154. this._state = ModelState.LOADING;
  104155. this._boundingSphere = computeBoundingSphere(this.gltf);
  104156. this._initialRadius = this._boundingSphere.radius;
  104157. checkSupportedExtensions(this);
  104158. if (this._state !== ModelState.FAILED) {
  104159. var extensions = this.gltf.extensions;
  104160. if (defined(extensions) && defined(extensions.CESIUM_RTC)) {
  104161. this._rtcCenter = Cartesian3.fromArray(extensions.CESIUM_RTC.center);
  104162. this._rtcCenterEye = new Cartesian3();
  104163. }
  104164. this._loadResources = new LoadResources();
  104165. parse(this);
  104166. }
  104167. }
  104168. var loadResources = this._loadResources;
  104169. var incrementallyLoadTextures = this._incrementallyLoadTextures;
  104170. var justLoaded = false;
  104171. if (this._state === ModelState.LOADING) {
  104172. // Create WebGL resources as buffers/shaders/textures are downloaded
  104173. createResources(this, frameState);
  104174. // Transition from LOADING -> LOADED once resources are downloaded and created.
  104175. // Textures may continue to stream in while in the LOADED state.
  104176. if (loadResources.finished() ||
  104177. (incrementallyLoadTextures && loadResources.finishedEverythingButTextureCreation())) {
  104178. this._state = ModelState.LOADED;
  104179. justLoaded = true;
  104180. }
  104181. }
  104182. // Incrementally stream textures.
  104183. if (defined(loadResources) && (this._state === ModelState.LOADED)) {
  104184. // Also check justLoaded so we don't process twice during the transition frame
  104185. if (incrementallyLoadTextures && !justLoaded) {
  104186. createResources(this, frameState);
  104187. }
  104188. if (loadResources.finished()) {
  104189. this._loadResources = undefined; // Clear CPU memory since WebGL resources were created.
  104190. var resources = this._rendererResources;
  104191. var cachedResources = this._cachedRendererResources;
  104192. cachedResources.buffers = resources.buffers;
  104193. cachedResources.vertexArrays = resources.vertexArrays;
  104194. cachedResources.programs = resources.programs;
  104195. cachedResources.pickPrograms = resources.pickPrograms;
  104196. cachedResources.silhouettePrograms = resources.silhouettePrograms;
  104197. cachedResources.textures = resources.textures;
  104198. cachedResources.samplers = resources.samplers;
  104199. cachedResources.renderStates = resources.renderStates;
  104200. cachedResources.ready = true;
  104201. // The normal attribute name is required for silhouettes, so get it before the gltf JSON is released
  104202. this._normalAttributeName = getAttributeOrUniformBySemantic(this.gltf, 'NORMAL');
  104203. // Vertex arrays are unique to this model, do not store in cache.
  104204. if (defined(this._precreatedAttributes)) {
  104205. cachedResources.vertexArrays = {};
  104206. }
  104207. if (this.releaseGltfJson) {
  104208. releaseCachedGltf(this);
  104209. }
  104210. }
  104211. }
  104212. var silhouette = hasSilhouette(this, frameState);
  104213. var translucent = isTranslucent(this);
  104214. var invisible = isInvisible(this);
  104215. var displayConditionPassed = defined(this.distanceDisplayCondition) ? distanceDisplayConditionVisible(this, frameState) : true;
  104216. var show = this.show && displayConditionPassed && (this.scale !== 0.0) && (!invisible || silhouette);
  104217. if ((show && this._state === ModelState.LOADED) || justLoaded) {
  104218. var animated = this.activeAnimations.update(frameState) || this._cesiumAnimationsDirty;
  104219. this._cesiumAnimationsDirty = false;
  104220. this._dirty = false;
  104221. var modelMatrix = this.modelMatrix;
  104222. var modeChanged = frameState.mode !== this._mode;
  104223. this._mode = frameState.mode;
  104224. // Model's model matrix needs to be updated
  104225. var modelTransformChanged = !Matrix4.equals(this._modelMatrix, modelMatrix) ||
  104226. (this._scale !== this.scale) ||
  104227. (this._minimumPixelSize !== this.minimumPixelSize) || (this.minimumPixelSize !== 0.0) || // Minimum pixel size changed or is enabled
  104228. (this._maximumScale !== this.maximumScale) ||
  104229. (this._heightReference !== this.heightReference) || this._heightChanged ||
  104230. modeChanged;
  104231. if (modelTransformChanged || justLoaded) {
  104232. Matrix4.clone(modelMatrix, this._modelMatrix);
  104233. updateClamping(this);
  104234. if (defined(this._clampedModelMatrix)) {
  104235. modelMatrix = this._clampedModelMatrix;
  104236. }
  104237. this._scale = this.scale;
  104238. this._minimumPixelSize = this.minimumPixelSize;
  104239. this._maximumScale = this.maximumScale;
  104240. this._heightReference = this.heightReference;
  104241. this._heightChanged = false;
  104242. var scale = getScale(this, frameState);
  104243. var computedModelMatrix = this._computedModelMatrix;
  104244. Matrix4.multiplyByUniformScale(modelMatrix, scale, computedModelMatrix);
  104245. Matrix4.multiplyTransformation(computedModelMatrix, yUpToZUp, computedModelMatrix);
  104246. }
  104247. // Update modelMatrix throughout the graph as needed
  104248. if (animated || modelTransformChanged || justLoaded) {
  104249. updateNodeHierarchyModelMatrix(this, modelTransformChanged, justLoaded, frameState.mapProjection);
  104250. this._dirty = true;
  104251. if (animated || justLoaded) {
  104252. // Apply skins if animation changed any node transforms
  104253. applySkins(this);
  104254. }
  104255. }
  104256. if (this._perNodeShowDirty) {
  104257. this._perNodeShowDirty = false;
  104258. updatePerNodeShow(this);
  104259. }
  104260. updatePickIds(this, context);
  104261. updateWireframe(this);
  104262. updateShowBoundingVolume(this);
  104263. updateShadows(this);
  104264. updateColor(this, frameState);
  104265. updateSilhouette(this, frameState);
  104266. }
  104267. if (justLoaded) {
  104268. // Called after modelMatrix update.
  104269. var model = this;
  104270. frameState.afterRender.push(function() {
  104271. model._ready = true;
  104272. model._readyPromise.resolve(model);
  104273. });
  104274. return;
  104275. }
  104276. // We don't check show at the top of the function since we
  104277. // want to be able to progressively load models when they are not shown,
  104278. // and then have them visible immediately when show is set to true.
  104279. if (show && !this._ignoreCommands) {
  104280. // PERFORMANCE_IDEA: This is terrible
  104281. var commandList = frameState.commandList;
  104282. var passes = frameState.passes;
  104283. var nodeCommands = this._nodeCommands;
  104284. var length = nodeCommands.length;
  104285. var i;
  104286. var nc;
  104287. var idl2D = frameState.mapProjection.ellipsoid.maximumRadius * CesiumMath.PI;
  104288. var boundingVolume;
  104289. if (passes.render) {
  104290. for (i = 0; i < length; ++i) {
  104291. nc = nodeCommands[i];
  104292. if (nc.show) {
  104293. var command = translucent ? nc.translucentCommand : nc.command;
  104294. command = silhouette ? nc.silhouetteModelCommand : command;
  104295. commandList.push(command);
  104296. boundingVolume = nc.command.boundingVolume;
  104297. if (frameState.mode === SceneMode.SCENE2D &&
  104298. (boundingVolume.center.y + boundingVolume.radius > idl2D || boundingVolume.center.y - boundingVolume.radius < idl2D)) {
  104299. var command2D = translucent ? nc.translucentCommand2D : nc.command2D;
  104300. command2D = silhouette ? nc.silhouetteModelCommand2D : command2D;
  104301. commandList.push(command2D);
  104302. }
  104303. }
  104304. }
  104305. if (silhouette) {
  104306. // Render second silhouette pass
  104307. for (i = 0; i < length; ++i) {
  104308. nc = nodeCommands[i];
  104309. if (nc.show) {
  104310. commandList.push(nc.silhouetteColorCommand);
  104311. boundingVolume = nc.command.boundingVolume;
  104312. if (frameState.mode === SceneMode.SCENE2D &&
  104313. (boundingVolume.center.y + boundingVolume.radius > idl2D || boundingVolume.center.y - boundingVolume.radius < idl2D)) {
  104314. commandList.push(nc.silhouetteColorCommand2D);
  104315. }
  104316. }
  104317. }
  104318. }
  104319. }
  104320. if (passes.pick && this.allowPicking) {
  104321. for (i = 0; i < length; ++i) {
  104322. nc = nodeCommands[i];
  104323. if (nc.show) {
  104324. var pickCommand = nc.pickCommand;
  104325. commandList.push(pickCommand);
  104326. boundingVolume = pickCommand.boundingVolume;
  104327. if (frameState.mode === SceneMode.SCENE2D &&
  104328. (boundingVolume.center.y + boundingVolume.radius > idl2D || boundingVolume.center.y - boundingVolume.radius < idl2D)) {
  104329. commandList.push(nc.pickCommand2D);
  104330. }
  104331. }
  104332. }
  104333. }
  104334. }
  104335. };
  104336. /**
  104337. * Returns true if this object was destroyed; otherwise, false.
  104338. * <br /><br />
  104339. * If this object was destroyed, it should not be used; calling any function other than
  104340. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  104341. *
  104342. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  104343. *
  104344. * @see Model#destroy
  104345. */
  104346. Model.prototype.isDestroyed = function() {
  104347. return false;
  104348. };
  104349. /**
  104350. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  104351. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  104352. * <br /><br />
  104353. * Once an object is destroyed, it should not be used; calling any function other than
  104354. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  104355. * assign the return value (<code>undefined</code>) to the object as done in the example.
  104356. *
  104357. * @returns {undefined}
  104358. *
  104359. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  104360. *
  104361. *
  104362. * @example
  104363. * model = model && model.destroy();
  104364. *
  104365. * @see Model#isDestroyed
  104366. */
  104367. Model.prototype.destroy = function() {
  104368. // Vertex arrays are unique to this model, destroy here.
  104369. if (defined(this._precreatedAttributes)) {
  104370. destroy(this._rendererResources.vertexArrays);
  104371. }
  104372. this._rendererResources = undefined;
  104373. this._cachedRendererResources = this._cachedRendererResources && this._cachedRendererResources.release();
  104374. var pickIds = this._pickIds;
  104375. var length = pickIds.length;
  104376. for (var i = 0; i < length; ++i) {
  104377. pickIds[i].destroy();
  104378. }
  104379. releaseCachedGltf(this);
  104380. return destroyObject(this);
  104381. };
  104382. return Model;
  104383. });
  104384. /*global define*/
  104385. define('DataSources/ModelVisualizer',[
  104386. '../Core/AssociativeArray',
  104387. '../Core/BoundingSphere',
  104388. '../Core/Color',
  104389. '../Core/defined',
  104390. '../Core/destroyObject',
  104391. '../Core/DeveloperError',
  104392. '../Core/Matrix4',
  104393. '../Scene/ColorBlendMode',
  104394. '../Scene/HeightReference',
  104395. '../Scene/Model',
  104396. '../Scene/ModelAnimationLoop',
  104397. '../Scene/ShadowMode',
  104398. './BoundingSphereState',
  104399. './Property'
  104400. ], function(
  104401. AssociativeArray,
  104402. BoundingSphere,
  104403. Color,
  104404. defined,
  104405. destroyObject,
  104406. DeveloperError,
  104407. Matrix4,
  104408. ColorBlendMode,
  104409. HeightReference,
  104410. Model,
  104411. ModelAnimationLoop,
  104412. ShadowMode,
  104413. BoundingSphereState,
  104414. Property) {
  104415. 'use strict';
  104416. var defaultScale = 1.0;
  104417. var defaultMinimumPixelSize = 0.0;
  104418. var defaultIncrementallyLoadTextures = true;
  104419. var defaultShadows = ShadowMode.ENABLED;
  104420. var defaultHeightReference = HeightReference.NONE;
  104421. var defaultSilhouetteColor = Color.RED;
  104422. var defaultSilhouetteSize = 0.0;
  104423. var defaultColor = Color.WHITE;
  104424. var defaultColorBlendMode = ColorBlendMode.HIGHLIGHT;
  104425. var defaultColorBlendAmount = 0.5;
  104426. var color = new Color();
  104427. var modelMatrixScratch = new Matrix4();
  104428. var nodeMatrixScratch = new Matrix4();
  104429. /**
  104430. * A {@link Visualizer} which maps {@link Entity#model} to a {@link Model}.
  104431. * @alias ModelVisualizer
  104432. * @constructor
  104433. *
  104434. * @param {Scene} scene The scene the primitives will be rendered in.
  104435. * @param {EntityCollection} entityCollection The entityCollection to visualize.
  104436. */
  104437. function ModelVisualizer(scene, entityCollection) {
  104438. if (!defined(scene)) {
  104439. throw new DeveloperError('scene is required.');
  104440. }
  104441. if (!defined(entityCollection)) {
  104442. throw new DeveloperError('entityCollection is required.');
  104443. }
  104444. entityCollection.collectionChanged.addEventListener(ModelVisualizer.prototype._onCollectionChanged, this);
  104445. this._scene = scene;
  104446. this._primitives = scene.primitives;
  104447. this._entityCollection = entityCollection;
  104448. this._modelHash = {};
  104449. this._entitiesToVisualize = new AssociativeArray();
  104450. this._onCollectionChanged(entityCollection, entityCollection.values, [], []);
  104451. }
  104452. /**
  104453. * Updates models created this visualizer to match their
  104454. * Entity counterpart at the given time.
  104455. *
  104456. * @param {JulianDate} time The time to update to.
  104457. * @returns {Boolean} This function always returns true.
  104458. */
  104459. ModelVisualizer.prototype.update = function(time) {
  104460. if (!defined(time)) {
  104461. throw new DeveloperError('time is required.');
  104462. }
  104463. var entities = this._entitiesToVisualize.values;
  104464. var modelHash = this._modelHash;
  104465. var primitives = this._primitives;
  104466. for (var i = 0, len = entities.length; i < len; i++) {
  104467. var entity = entities[i];
  104468. var modelGraphics = entity._model;
  104469. var uri;
  104470. var modelData = modelHash[entity.id];
  104471. var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(modelGraphics._show, time, true);
  104472. var modelMatrix;
  104473. if (show) {
  104474. modelMatrix = entity._getModelMatrix(time, modelMatrixScratch);
  104475. uri = Property.getValueOrUndefined(modelGraphics._uri, time);
  104476. show = defined(modelMatrix) && defined(uri);
  104477. }
  104478. if (!show) {
  104479. if (defined(modelData)) {
  104480. modelData.modelPrimitive.show = false;
  104481. }
  104482. continue;
  104483. }
  104484. var model = defined(modelData) ? modelData.modelPrimitive : undefined;
  104485. if (!defined(model) || uri !== modelData.uri) {
  104486. if (defined(model)) {
  104487. primitives.removeAndDestroy(model);
  104488. delete modelHash[entity.id];
  104489. }
  104490. model = Model.fromGltf({
  104491. url : uri,
  104492. incrementallyLoadTextures : Property.getValueOrDefault(modelGraphics._incrementallyLoadTextures, time, defaultIncrementallyLoadTextures),
  104493. scene : this._scene
  104494. });
  104495. model.readyPromise.otherwise(onModelError);
  104496. model.id = entity;
  104497. primitives.add(model);
  104498. modelData = {
  104499. modelPrimitive : model,
  104500. uri : uri,
  104501. animationsRunning : false,
  104502. nodeTransformationsScratch : {},
  104503. originalNodeMatrixHash : {}
  104504. };
  104505. modelHash[entity.id] = modelData;
  104506. }
  104507. model.show = true;
  104508. model.scale = Property.getValueOrDefault(modelGraphics._scale, time, defaultScale);
  104509. model.minimumPixelSize = Property.getValueOrDefault(modelGraphics._minimumPixelSize, time, defaultMinimumPixelSize);
  104510. model.maximumScale = Property.getValueOrUndefined(modelGraphics._maximumScale, time);
  104511. model.modelMatrix = Matrix4.clone(modelMatrix, model.modelMatrix);
  104512. model.shadows = Property.getValueOrDefault(modelGraphics._shadows, time, defaultShadows);
  104513. model.heightReference = Property.getValueOrDefault(modelGraphics._heightReference, time, defaultHeightReference);
  104514. model.distanceDisplayCondition = Property.getValueOrUndefined(modelGraphics._distanceDisplayCondition, time);
  104515. model.silhouetteColor = Property.getValueOrDefault(modelGraphics.silhouetteColor, time, defaultSilhouetteColor);
  104516. model.silhouetteSize = Property.getValueOrDefault(modelGraphics.silhouetteSize, time, defaultSilhouetteSize);
  104517. model.color = Property.getValueOrDefault(modelGraphics._color, time, defaultColor, color);
  104518. model.colorBlendMode = Property.getValueOrDefault(modelGraphics._colorBlendMode, time, defaultColorBlendMode);
  104519. model.colorBlendAmount = Property.getValueOrDefault(modelGraphics._colorBlendAmount, time, defaultColorBlendAmount);
  104520. if (model.ready) {
  104521. var runAnimations = Property.getValueOrDefault(modelGraphics._runAnimations, time, true);
  104522. if (modelData.animationsRunning !== runAnimations) {
  104523. if (runAnimations) {
  104524. model.activeAnimations.addAll({
  104525. loop : ModelAnimationLoop.REPEAT
  104526. });
  104527. } else {
  104528. model.activeAnimations.removeAll();
  104529. }
  104530. modelData.animationsRunning = runAnimations;
  104531. }
  104532. // Apply node transformations
  104533. var nodeTransformations = Property.getValueOrUndefined(modelGraphics._nodeTransformations, time, modelData.nodeTransformationsScratch);
  104534. if (defined(nodeTransformations)) {
  104535. var originalNodeMatrixHash = modelData.originalNodeMatrixHash;
  104536. var nodeNames = Object.keys(nodeTransformations);
  104537. for (var nodeIndex = 0, nodeLength = nodeNames.length; nodeIndex < nodeLength; ++nodeIndex) {
  104538. var nodeName = nodeNames[nodeIndex];
  104539. var nodeTransformation = nodeTransformations[nodeName];
  104540. if (!defined(nodeTransformation)) {
  104541. continue;
  104542. }
  104543. var modelNode = model.getNode(nodeName);
  104544. if (!defined(modelNode)) {
  104545. continue;
  104546. }
  104547. var originalNodeMatrix = originalNodeMatrixHash[nodeName];
  104548. if (!defined(originalNodeMatrix)) {
  104549. originalNodeMatrix = modelNode.matrix.clone();
  104550. originalNodeMatrixHash[nodeName] = originalNodeMatrix;
  104551. }
  104552. var transformationMatrix = Matrix4.fromTranslationRotationScale(nodeTransformation, nodeMatrixScratch);
  104553. modelNode.matrix = Matrix4.multiply(originalNodeMatrix, transformationMatrix, transformationMatrix);
  104554. }
  104555. }
  104556. }
  104557. }
  104558. return true;
  104559. };
  104560. /**
  104561. * Returns true if this object was destroyed; otherwise, false.
  104562. *
  104563. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  104564. */
  104565. ModelVisualizer.prototype.isDestroyed = function() {
  104566. return false;
  104567. };
  104568. /**
  104569. * Removes and destroys all primitives created by this instance.
  104570. */
  104571. ModelVisualizer.prototype.destroy = function() {
  104572. this._entityCollection.collectionChanged.removeEventListener(ModelVisualizer.prototype._onCollectionChanged, this);
  104573. var entities = this._entitiesToVisualize.values;
  104574. var modelHash = this._modelHash;
  104575. var primitives = this._primitives;
  104576. for (var i = entities.length - 1; i > -1; i--) {
  104577. removeModel(this, entities[i], modelHash, primitives);
  104578. }
  104579. return destroyObject(this);
  104580. };
  104581. /**
  104582. * Computes a bounding sphere which encloses the visualization produced for the specified entity.
  104583. * The bounding sphere is in the fixed frame of the scene's globe.
  104584. *
  104585. * @param {Entity} entity The entity whose bounding sphere to compute.
  104586. * @param {BoundingSphere} result The bounding sphere onto which to store the result.
  104587. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere,
  104588. * BoundingSphereState.PENDING if the result is still being computed, or
  104589. * BoundingSphereState.FAILED if the entity has no visualization in the current scene.
  104590. * @private
  104591. */
  104592. ModelVisualizer.prototype.getBoundingSphere = function(entity, result) {
  104593. if (!defined(entity)) {
  104594. throw new DeveloperError('entity is required.');
  104595. }
  104596. if (!defined(result)) {
  104597. throw new DeveloperError('result is required.');
  104598. }
  104599. var modelData = this._modelHash[entity.id];
  104600. if (!defined(modelData)) {
  104601. return BoundingSphereState.FAILED;
  104602. }
  104603. var model = modelData.modelPrimitive;
  104604. if (!defined(model) || !model.show) {
  104605. return BoundingSphereState.FAILED;
  104606. }
  104607. if (!model.ready) {
  104608. return BoundingSphereState.PENDING;
  104609. }
  104610. if (model.heightReference === HeightReference.NONE) {
  104611. BoundingSphere.transform(model.boundingSphere, model.modelMatrix, result);
  104612. } else {
  104613. if (!defined(model._clampedModelMatrix)) {
  104614. return BoundingSphereState.PENDING;
  104615. }
  104616. BoundingSphere.transform(model.boundingSphere, model._clampedModelMatrix, result);
  104617. }
  104618. return BoundingSphereState.DONE;
  104619. };
  104620. /**
  104621. * @private
  104622. */
  104623. ModelVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed, changed) {
  104624. var i;
  104625. var entity;
  104626. var entities = this._entitiesToVisualize;
  104627. var modelHash = this._modelHash;
  104628. var primitives = this._primitives;
  104629. for (i = added.length - 1; i > -1; i--) {
  104630. entity = added[i];
  104631. if (defined(entity._model) && defined(entity._position)) {
  104632. entities.set(entity.id, entity);
  104633. }
  104634. }
  104635. for (i = changed.length - 1; i > -1; i--) {
  104636. entity = changed[i];
  104637. if (defined(entity._model) && defined(entity._position)) {
  104638. clearNodeTransformationsScratch(entity, modelHash);
  104639. entities.set(entity.id, entity);
  104640. } else {
  104641. removeModel(this, entity, modelHash, primitives);
  104642. entities.remove(entity.id);
  104643. }
  104644. }
  104645. for (i = removed.length - 1; i > -1; i--) {
  104646. entity = removed[i];
  104647. removeModel(this, entity, modelHash, primitives);
  104648. entities.remove(entity.id);
  104649. }
  104650. };
  104651. function removeModel(visualizer, entity, modelHash, primitives) {
  104652. var modelData = modelHash[entity.id];
  104653. if (defined(modelData)) {
  104654. primitives.removeAndDestroy(modelData.modelPrimitive);
  104655. delete modelHash[entity.id];
  104656. }
  104657. }
  104658. function clearNodeTransformationsScratch(entity, modelHash) {
  104659. var modelData = modelHash[entity.id];
  104660. if (defined(modelData)) {
  104661. modelData.nodeTransformationsScratch = {};
  104662. }
  104663. }
  104664. function onModelError(error) {
  104665. console.error(error);
  104666. }
  104667. return ModelVisualizer;
  104668. });
  104669. //This file is automatically rebuilt by the Cesium build process.
  104670. /*global define*/
  104671. define('Shaders/PolylineCommon',[],function() {
  104672. 'use strict';
  104673. return "void clipLineSegmentToNearPlane(\n\
  104674. vec3 p0,\n\
  104675. vec3 p1,\n\
  104676. out vec4 positionWC,\n\
  104677. out bool clipped,\n\
  104678. out bool culledByNearPlane)\n\
  104679. {\n\
  104680. culledByNearPlane = false;\n\
  104681. clipped = false;\n\
  104682. vec3 p1ToP0 = p1 - p0;\n\
  104683. float magnitude = length(p1ToP0);\n\
  104684. vec3 direction = normalize(p1ToP0);\n\
  104685. float endPoint0Distance = -(czm_currentFrustum.x + p0.z);\n\
  104686. float denominator = -direction.z;\n\
  104687. if (endPoint0Distance < 0.0 && abs(denominator) < czm_epsilon7)\n\
  104688. {\n\
  104689. culledByNearPlane = true;\n\
  104690. }\n\
  104691. else if (endPoint0Distance < 0.0 && abs(denominator) > czm_epsilon7)\n\
  104692. {\n\
  104693. float t = (czm_currentFrustum.x + p0.z) / denominator;\n\
  104694. if (t < 0.0 || t > magnitude)\n\
  104695. {\n\
  104696. culledByNearPlane = true;\n\
  104697. }\n\
  104698. else\n\
  104699. {\n\
  104700. p0 = p0 + t * direction;\n\
  104701. clipped = true;\n\
  104702. }\n\
  104703. }\n\
  104704. positionWC = czm_eyeToWindowCoordinates(vec4(p0, 1.0));\n\
  104705. }\n\
  104706. vec4 getPolylineWindowCoordinates(vec4 position, vec4 previous, vec4 next, float expandDirection, float width, bool usePrevious) {\n\
  104707. vec4 endPointWC, p0, p1;\n\
  104708. bool culledByNearPlane, clipped;\n\
  104709. vec4 positionEC = czm_modelViewRelativeToEye * position;\n\
  104710. vec4 prevEC = czm_modelViewRelativeToEye * previous;\n\
  104711. vec4 nextEC = czm_modelViewRelativeToEye * next;\n\
  104712. clipLineSegmentToNearPlane(prevEC.xyz, positionEC.xyz, p0, clipped, culledByNearPlane);\n\
  104713. clipLineSegmentToNearPlane(nextEC.xyz, positionEC.xyz, p1, clipped, culledByNearPlane);\n\
  104714. clipLineSegmentToNearPlane(positionEC.xyz, usePrevious ? prevEC.xyz : nextEC.xyz, endPointWC, clipped, culledByNearPlane);\n\
  104715. if (culledByNearPlane)\n\
  104716. {\n\
  104717. return vec4(0.0, 0.0, 0.0, 1.0);\n\
  104718. }\n\
  104719. vec2 prevWC = normalize(p0.xy - endPointWC.xy);\n\
  104720. vec2 nextWC = normalize(p1.xy - endPointWC.xy);\n\
  104721. float expandWidth = width * 0.5;\n\
  104722. vec2 direction;\n\
  104723. if (czm_equalsEpsilon(previous.xyz - position.xyz, vec3(0.0), czm_epsilon1) || czm_equalsEpsilon(prevWC, -nextWC, czm_epsilon1))\n\
  104724. {\n\
  104725. direction = vec2(-nextWC.y, nextWC.x);\n\
  104726. }\n\
  104727. else if (czm_equalsEpsilon(next.xyz - position.xyz, vec3(0.0), czm_epsilon1) || clipped)\n\
  104728. {\n\
  104729. direction = vec2(prevWC.y, -prevWC.x);\n\
  104730. }\n\
  104731. else\n\
  104732. {\n\
  104733. vec2 normal = vec2(-nextWC.y, nextWC.x);\n\
  104734. direction = normalize((nextWC + prevWC) * 0.5);\n\
  104735. if (dot(direction, normal) < 0.0)\n\
  104736. {\n\
  104737. direction = -direction;\n\
  104738. }\n\
  104739. float sinAngle = abs(direction.x * nextWC.y - direction.y * nextWC.x);\n\
  104740. expandWidth = clamp(expandWidth / sinAngle, 0.0, width * 2.0);\n\
  104741. }\n\
  104742. vec2 offset = direction * expandDirection * expandWidth * czm_resolutionScale;\n\
  104743. return vec4(endPointWC.xy + offset, -endPointWC.z, 1.0);\n\
  104744. }\n\
  104745. ";
  104746. });
  104747. //This file is automatically rebuilt by the Cesium build process.
  104748. /*global define*/
  104749. define('Shaders/PolylineFS',[],function() {
  104750. 'use strict';
  104751. return "varying vec2 v_st;\n\
  104752. void main()\n\
  104753. {\n\
  104754. czm_materialInput materialInput;\n\
  104755. materialInput.s = v_st.s;\n\
  104756. materialInput.st = v_st;\n\
  104757. materialInput.str = vec3(v_st, 0.0);\n\
  104758. czm_material material = czm_getMaterial(materialInput);\n\
  104759. gl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n\
  104760. }\n\
  104761. ";
  104762. });
  104763. //This file is automatically rebuilt by the Cesium build process.
  104764. /*global define*/
  104765. define('Shaders/PolylineVS',[],function() {
  104766. 'use strict';
  104767. return "attribute vec3 position3DHigh;\n\
  104768. attribute vec3 position3DLow;\n\
  104769. attribute vec3 position2DHigh;\n\
  104770. attribute vec3 position2DLow;\n\
  104771. attribute vec3 prevPosition3DHigh;\n\
  104772. attribute vec3 prevPosition3DLow;\n\
  104773. attribute vec3 prevPosition2DHigh;\n\
  104774. attribute vec3 prevPosition2DLow;\n\
  104775. attribute vec3 nextPosition3DHigh;\n\
  104776. attribute vec3 nextPosition3DLow;\n\
  104777. attribute vec3 nextPosition2DHigh;\n\
  104778. attribute vec3 nextPosition2DLow;\n\
  104779. attribute vec4 texCoordExpandAndBatchIndex;\n\
  104780. varying vec2 v_st;\n\
  104781. varying float v_width;\n\
  104782. varying vec4 czm_pickColor;\n\
  104783. void main()\n\
  104784. {\n\
  104785. float texCoord = texCoordExpandAndBatchIndex.x;\n\
  104786. float expandDir = texCoordExpandAndBatchIndex.y;\n\
  104787. bool usePrev = texCoordExpandAndBatchIndex.z < 0.0;\n\
  104788. float batchTableIndex = texCoordExpandAndBatchIndex.w;\n\
  104789. vec2 widthAndShow = batchTable_getWidthAndShow(batchTableIndex);\n\
  104790. float width = widthAndShow.x + 0.5;\n\
  104791. float show = widthAndShow.y;\n\
  104792. if (width < 1.0)\n\
  104793. {\n\
  104794. show = 0.0;\n\
  104795. }\n\
  104796. vec4 pickColor = batchTable_getPickColor(batchTableIndex);\n\
  104797. vec4 p, prev, next;\n\
  104798. if (czm_morphTime == 1.0)\n\
  104799. {\n\
  104800. p = czm_translateRelativeToEye(position3DHigh.xyz, position3DLow.xyz);\n\
  104801. prev = czm_translateRelativeToEye(prevPosition3DHigh.xyz, prevPosition3DLow.xyz);\n\
  104802. next = czm_translateRelativeToEye(nextPosition3DHigh.xyz, nextPosition3DLow.xyz);\n\
  104803. }\n\
  104804. else if (czm_morphTime == 0.0)\n\
  104805. {\n\
  104806. p = czm_translateRelativeToEye(position2DHigh.zxy, position2DLow.zxy);\n\
  104807. prev = czm_translateRelativeToEye(prevPosition2DHigh.zxy, prevPosition2DLow.zxy);\n\
  104808. next = czm_translateRelativeToEye(nextPosition2DHigh.zxy, nextPosition2DLow.zxy);\n\
  104809. }\n\
  104810. else\n\
  104811. {\n\
  104812. p = czm_columbusViewMorph(\n\
  104813. czm_translateRelativeToEye(position2DHigh.zxy, position2DLow.zxy),\n\
  104814. czm_translateRelativeToEye(position3DHigh.xyz, position3DLow.xyz),\n\
  104815. czm_morphTime);\n\
  104816. prev = czm_columbusViewMorph(\n\
  104817. czm_translateRelativeToEye(prevPosition2DHigh.zxy, prevPosition2DLow.zxy),\n\
  104818. czm_translateRelativeToEye(prevPosition3DHigh.xyz, prevPosition3DLow.xyz),\n\
  104819. czm_morphTime);\n\
  104820. next = czm_columbusViewMorph(\n\
  104821. czm_translateRelativeToEye(nextPosition2DHigh.zxy, nextPosition2DLow.zxy),\n\
  104822. czm_translateRelativeToEye(nextPosition3DHigh.xyz, nextPosition3DLow.xyz),\n\
  104823. czm_morphTime);\n\
  104824. }\n\
  104825. #ifdef DISTANCE_DISPLAY_CONDITION\n\
  104826. vec3 centerHigh = batchTable_getCenterHigh(batchTableIndex);\n\
  104827. vec4 centerLowAndRadius = batchTable_getCenterLowAndRadius(batchTableIndex);\n\
  104828. vec3 centerLow = centerLowAndRadius.xyz;\n\
  104829. float radius = centerLowAndRadius.w;\n\
  104830. vec2 distanceDisplayCondition = batchTable_getDistanceDisplayCondition(batchTableIndex);\n\
  104831. float lengthSq;\n\
  104832. if (czm_sceneMode == czm_sceneMode2D)\n\
  104833. {\n\
  104834. lengthSq = czm_eyeHeight2D.y;\n\
  104835. }\n\
  104836. else\n\
  104837. {\n\
  104838. vec4 center = czm_translateRelativeToEye(centerHigh.xyz, centerLow.xyz);\n\
  104839. lengthSq = max(0.0, dot(center.xyz, center.xyz) - radius * radius);\n\
  104840. }\n\
  104841. float nearSq = distanceDisplayCondition.x * distanceDisplayCondition.x;\n\
  104842. float farSq = distanceDisplayCondition.y * distanceDisplayCondition.y;\n\
  104843. if (lengthSq < nearSq || lengthSq > farSq)\n\
  104844. {\n\
  104845. show = 0.0;\n\
  104846. }\n\
  104847. #endif\n\
  104848. vec4 positionWC = getPolylineWindowCoordinates(p, prev, next, expandDir, width, usePrev);\n\
  104849. gl_Position = czm_viewportOrthographic * positionWC * show;\n\
  104850. v_st = vec2(texCoord, clamp(expandDir, 0.0, 1.0));\n\
  104851. v_width = width;\n\
  104852. czm_pickColor = pickColor;\n\
  104853. }\n\
  104854. ";
  104855. });
  104856. /*global define*/
  104857. define('Scene/Polyline',[
  104858. '../Core/arrayRemoveDuplicates',
  104859. '../Core/BoundingSphere',
  104860. '../Core/Cartesian3',
  104861. '../Core/Color',
  104862. '../Core/defaultValue',
  104863. '../Core/defined',
  104864. '../Core/defineProperties',
  104865. '../Core/DeveloperError',
  104866. '../Core/DistanceDisplayCondition',
  104867. '../Core/Matrix4',
  104868. '../Core/PolylinePipeline',
  104869. './Material'
  104870. ], function(
  104871. arrayRemoveDuplicates,
  104872. BoundingSphere,
  104873. Cartesian3,
  104874. Color,
  104875. defaultValue,
  104876. defined,
  104877. defineProperties,
  104878. DeveloperError,
  104879. DistanceDisplayCondition,
  104880. Matrix4,
  104881. PolylinePipeline,
  104882. Material) {
  104883. 'use strict';
  104884. /**
  104885. * A renderable polyline. Create this by calling {@link PolylineCollection#add}
  104886. *
  104887. * @alias Polyline
  104888. * @internalConstructor
  104889. *
  104890. * @param {Object} [options] Object with the following properties:
  104891. * @param {Boolean} [options.show=true] <code>true</code> if this polyline will be shown; otherwise, <code>false</code>.
  104892. * @param {Number} [options.width=1.0] The width of the polyline in pixels.
  104893. * @param {Boolean} [options.loop=false] Whether a line segment will be added between the last and first line positions to make this line a loop.
  104894. * @param {Material} [options.material=Material.ColorType] The material.
  104895. * @param {Cartesian3[]} [options.positions] The positions.
  104896. * @param {Object} [options.id] The user-defined object to be returned when this polyline is picked.
  104897. * @param {DistanceDisplayCondition} [options.distanceDisplayCondition] The condition specifying at what distance from the camera that this polyline will be displayed.
  104898. *
  104899. * @see PolylineCollection
  104900. *
  104901. */
  104902. function Polyline(options, polylineCollection) {
  104903. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  104904. this._show = defaultValue(options.show, true);
  104905. this._width = defaultValue(options.width, 1.0);
  104906. this._loop = defaultValue(options.loop, false);
  104907. this._distanceDisplayCondition = options.distanceDisplayCondition;
  104908. this._material = options.material;
  104909. if (!defined(this._material)) {
  104910. this._material = Material.fromType(Material.ColorType, {
  104911. color : new Color(1.0, 1.0, 1.0, 1.0)
  104912. });
  104913. }
  104914. var positions = options.positions;
  104915. if (!defined(positions)) {
  104916. positions = [];
  104917. }
  104918. this._positions = positions;
  104919. this._actualPositions = arrayRemoveDuplicates(positions, Cartesian3.equalsEpsilon);
  104920. if (this._loop && this._actualPositions.length > 2) {
  104921. if (this._actualPositions === this._positions) {
  104922. this._actualPositions = positions.slice();
  104923. }
  104924. this._actualPositions.push(Cartesian3.clone(this._actualPositions[0]));
  104925. }
  104926. this._length = this._actualPositions.length;
  104927. this._id = options.id;
  104928. var modelMatrix;
  104929. if (defined(polylineCollection)) {
  104930. modelMatrix = Matrix4.clone(polylineCollection.modelMatrix);
  104931. }
  104932. this._modelMatrix = modelMatrix;
  104933. this._segments = PolylinePipeline.wrapLongitude(this._actualPositions, modelMatrix);
  104934. this._actualLength = undefined;
  104935. this._propertiesChanged = new Uint32Array(NUMBER_OF_PROPERTIES);
  104936. this._polylineCollection = polylineCollection;
  104937. this._dirty = false;
  104938. this._pickId = undefined;
  104939. this._boundingVolume = BoundingSphere.fromPoints(this._actualPositions);
  104940. this._boundingVolumeWC = BoundingSphere.transform(this._boundingVolume, this._modelMatrix);
  104941. this._boundingVolume2D = new BoundingSphere(); // modified in PolylineCollection
  104942. }
  104943. var POSITION_INDEX = Polyline.POSITION_INDEX = 0;
  104944. var SHOW_INDEX = Polyline.SHOW_INDEX = 1;
  104945. var WIDTH_INDEX = Polyline.WIDTH_INDEX = 2;
  104946. var MATERIAL_INDEX = Polyline.MATERIAL_INDEX = 3;
  104947. var POSITION_SIZE_INDEX = Polyline.POSITION_SIZE_INDEX = 4;
  104948. var DISTANCE_DISPLAY_CONDITION = Polyline.DISTANCE_DISPLAY_CONDITION = 5;
  104949. var NUMBER_OF_PROPERTIES = Polyline.NUMBER_OF_PROPERTIES = 6;
  104950. function makeDirty(polyline, propertyChanged) {
  104951. ++polyline._propertiesChanged[propertyChanged];
  104952. var polylineCollection = polyline._polylineCollection;
  104953. if (defined(polylineCollection)) {
  104954. polylineCollection._updatePolyline(polyline, propertyChanged);
  104955. polyline._dirty = true;
  104956. }
  104957. }
  104958. defineProperties(Polyline.prototype, {
  104959. /**
  104960. * Determines if this polyline will be shown. Use this to hide or show a polyline, instead
  104961. * of removing it and re-adding it to the collection.
  104962. * @memberof Polyline.prototype
  104963. * @type {Boolean}
  104964. */
  104965. show: {
  104966. get: function() {
  104967. return this._show;
  104968. },
  104969. set: function(value) {
  104970. if (!defined(value)) {
  104971. throw new DeveloperError('value is required.');
  104972. }
  104973. if (value !== this._show) {
  104974. this._show = value;
  104975. makeDirty(this, SHOW_INDEX);
  104976. }
  104977. }
  104978. },
  104979. /**
  104980. * Gets or sets the positions of the polyline.
  104981. * @memberof Polyline.prototype
  104982. * @type {Cartesian3[]}
  104983. * @example
  104984. * polyline.positions = Cesium.Cartesian3.fromDegreesArray([
  104985. * 0.0, 0.0,
  104986. * 10.0, 0.0,
  104987. * 0.0, 20.0
  104988. * ]);
  104989. */
  104990. positions : {
  104991. get: function() {
  104992. return this._positions;
  104993. },
  104994. set: function(value) {
  104995. if (!defined(value)) {
  104996. throw new DeveloperError('value is required.');
  104997. }
  104998. var positions = arrayRemoveDuplicates(value, Cartesian3.equalsEpsilon);
  104999. if (this._loop && positions.length > 2) {
  105000. if (positions === value) {
  105001. positions = value.slice();
  105002. }
  105003. positions.push(Cartesian3.clone(positions[0]));
  105004. }
  105005. if (this._actualPositions.length !== positions.length || this._actualPositions.length !== this._length) {
  105006. makeDirty(this, POSITION_SIZE_INDEX);
  105007. }
  105008. this._positions = value;
  105009. this._actualPositions = positions;
  105010. this._length = positions.length;
  105011. this._boundingVolume = BoundingSphere.fromPoints(this._actualPositions, this._boundingVolume);
  105012. this._boundingVolumeWC = BoundingSphere.transform(this._boundingVolume, this._modelMatrix, this._boundingVolumeWC);
  105013. makeDirty(this, POSITION_INDEX);
  105014. this.update();
  105015. }
  105016. },
  105017. /**
  105018. * Gets or sets the surface appearance of the polyline. This can be one of several built-in {@link Material} objects or a custom material, scripted with
  105019. * {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}.
  105020. * @memberof Polyline.prototype
  105021. * @type {Material}
  105022. */
  105023. material: {
  105024. get: function() {
  105025. return this._material;
  105026. },
  105027. set: function(material) {
  105028. if (!defined(material)) {
  105029. throw new DeveloperError('material is required.');
  105030. }
  105031. if (this._material !== material) {
  105032. this._material = material;
  105033. makeDirty(this, MATERIAL_INDEX);
  105034. }
  105035. }
  105036. },
  105037. /**
  105038. * Gets or sets the width of the polyline.
  105039. * @memberof Polyline.prototype
  105040. * @type {Number}
  105041. */
  105042. width: {
  105043. get: function() {
  105044. return this._width;
  105045. },
  105046. set: function(value) {
  105047. if (!defined(value)) {
  105048. throw new DeveloperError('value is required.');
  105049. }
  105050. var width = this._width;
  105051. if (value !== width) {
  105052. this._width = value;
  105053. makeDirty(this, WIDTH_INDEX);
  105054. }
  105055. }
  105056. },
  105057. /**
  105058. * Gets or sets whether a line segment will be added between the first and last polyline positions.
  105059. * @memberof Polyline.prototype
  105060. * @type {Boolean}
  105061. */
  105062. loop: {
  105063. get: function() {
  105064. return this._loop;
  105065. },
  105066. set: function(value) {
  105067. if (!defined(value)) {
  105068. throw new DeveloperError('value is required.');
  105069. }
  105070. if (value !== this._loop) {
  105071. var positions = this._actualPositions;
  105072. if (value) {
  105073. if (positions.length > 2 && !Cartesian3.equals(positions[0], positions[positions.length - 1])) {
  105074. if (positions.length === this._positions.length) {
  105075. this._actualPositions = positions = this._positions.slice();
  105076. }
  105077. positions.push(Cartesian3.clone(positions[0]));
  105078. }
  105079. } else {
  105080. if (positions.length > 2 && Cartesian3.equals(positions[0], positions[positions.length - 1])) {
  105081. if (positions.length - 1 === this._positions.length) {
  105082. this._actualPositions = this._positions;
  105083. } else {
  105084. positions.pop();
  105085. }
  105086. }
  105087. }
  105088. this._loop = value;
  105089. makeDirty(this, POSITION_SIZE_INDEX);
  105090. }
  105091. }
  105092. },
  105093. /**
  105094. * Gets or sets the user-defined object returned when the polyline is picked.
  105095. * @memberof Polyline.prototype
  105096. * @type {Object}
  105097. */
  105098. id : {
  105099. get : function() {
  105100. return this._id;
  105101. },
  105102. set : function(value) {
  105103. this._id = value;
  105104. if (defined(this._pickId)) {
  105105. this._pickId.object.id = value;
  105106. }
  105107. }
  105108. },
  105109. /**
  105110. * Gets or sets the condition specifying at what distance from the camera that this polyline will be displayed.
  105111. * @memberof Polyline.prototype
  105112. * @type {DistanceDisplayCondition}
  105113. * @default undefined
  105114. */
  105115. distanceDisplayCondition : {
  105116. get : function() {
  105117. return this._distanceDisplayCondition;
  105118. },
  105119. set : function(value) {
  105120. if (defined(value) && value.far <= value.near) {
  105121. throw new DeveloperError('far distance must be greater than near distance.');
  105122. }
  105123. if (!DistanceDisplayCondition.equals(value, this._distanceDisplayCondition)) {
  105124. this._distanceDisplayCondition = DistanceDisplayCondition.clone(value, this._distanceDisplayCondition);
  105125. makeDirty(this, DISTANCE_DISPLAY_CONDITION);
  105126. }
  105127. }
  105128. }
  105129. });
  105130. /**
  105131. * @private
  105132. */
  105133. Polyline.prototype.update = function() {
  105134. var modelMatrix = Matrix4.IDENTITY;
  105135. if (defined(this._polylineCollection)) {
  105136. modelMatrix = this._polylineCollection.modelMatrix;
  105137. }
  105138. var segmentPositionsLength = this._segments.positions.length;
  105139. var segmentLengths = this._segments.lengths;
  105140. var positionsChanged = this._propertiesChanged[POSITION_INDEX] > 0 || this._propertiesChanged[POSITION_SIZE_INDEX] > 0;
  105141. if (!Matrix4.equals(modelMatrix, this._modelMatrix) || positionsChanged) {
  105142. this._segments = PolylinePipeline.wrapLongitude(this._actualPositions, modelMatrix);
  105143. this._boundingVolumeWC = BoundingSphere.transform(this._boundingVolume, modelMatrix, this._boundingVolumeWC);
  105144. }
  105145. this._modelMatrix = modelMatrix;
  105146. if (this._segments.positions.length !== segmentPositionsLength) {
  105147. // number of positions changed
  105148. makeDirty(this, POSITION_SIZE_INDEX);
  105149. } else {
  105150. var length = segmentLengths.length;
  105151. for (var i = 0; i < length; ++i) {
  105152. if (segmentLengths[i] !== this._segments.lengths[i]) {
  105153. // indices changed
  105154. makeDirty(this, POSITION_SIZE_INDEX);
  105155. break;
  105156. }
  105157. }
  105158. }
  105159. };
  105160. /**
  105161. * @private
  105162. */
  105163. Polyline.prototype.getPickId = function(context) {
  105164. if (!defined(this._pickId)) {
  105165. this._pickId = context.createPickId({
  105166. primitive : this,
  105167. collection : this._polylineCollection,
  105168. id : this._id
  105169. });
  105170. }
  105171. return this._pickId;
  105172. };
  105173. Polyline.prototype._clean = function() {
  105174. this._dirty = false;
  105175. var properties = this._propertiesChanged;
  105176. for ( var k = 0; k < NUMBER_OF_PROPERTIES - 1; ++k) {
  105177. properties[k] = 0;
  105178. }
  105179. };
  105180. Polyline.prototype._destroy = function() {
  105181. this._pickId = this._pickId && this._pickId.destroy();
  105182. this._material = this._material && this._material.destroy();
  105183. this._polylineCollection = undefined;
  105184. };
  105185. return Polyline;
  105186. });
  105187. /*global define*/
  105188. define('Scene/PolylineCollection',[
  105189. '../Core/BoundingSphere',
  105190. '../Core/Cartesian2',
  105191. '../Core/Cartesian3',
  105192. '../Core/Cartesian4',
  105193. '../Core/Cartographic',
  105194. '../Core/Color',
  105195. '../Core/ComponentDatatype',
  105196. '../Core/defaultValue',
  105197. '../Core/defined',
  105198. '../Core/defineProperties',
  105199. '../Core/destroyObject',
  105200. '../Core/DeveloperError',
  105201. '../Core/EncodedCartesian3',
  105202. '../Core/IndexDatatype',
  105203. '../Core/Intersect',
  105204. '../Core/Math',
  105205. '../Core/Matrix4',
  105206. '../Core/Plane',
  105207. '../Core/RuntimeError',
  105208. '../Renderer/Buffer',
  105209. '../Renderer/BufferUsage',
  105210. '../Renderer/ContextLimits',
  105211. '../Renderer/DrawCommand',
  105212. '../Renderer/Pass',
  105213. '../Renderer/RenderState',
  105214. '../Renderer/ShaderProgram',
  105215. '../Renderer/ShaderSource',
  105216. '../Renderer/VertexArray',
  105217. '../Shaders/PolylineCommon',
  105218. '../Shaders/PolylineFS',
  105219. '../Shaders/PolylineVS',
  105220. './BatchTable',
  105221. './BlendingState',
  105222. './Material',
  105223. './Polyline',
  105224. './SceneMode'
  105225. ], function(
  105226. BoundingSphere,
  105227. Cartesian2,
  105228. Cartesian3,
  105229. Cartesian4,
  105230. Cartographic,
  105231. Color,
  105232. ComponentDatatype,
  105233. defaultValue,
  105234. defined,
  105235. defineProperties,
  105236. destroyObject,
  105237. DeveloperError,
  105238. EncodedCartesian3,
  105239. IndexDatatype,
  105240. Intersect,
  105241. CesiumMath,
  105242. Matrix4,
  105243. Plane,
  105244. RuntimeError,
  105245. Buffer,
  105246. BufferUsage,
  105247. ContextLimits,
  105248. DrawCommand,
  105249. Pass,
  105250. RenderState,
  105251. ShaderProgram,
  105252. ShaderSource,
  105253. VertexArray,
  105254. PolylineCommon,
  105255. PolylineFS,
  105256. PolylineVS,
  105257. BatchTable,
  105258. BlendingState,
  105259. Material,
  105260. Polyline,
  105261. SceneMode) {
  105262. 'use strict';
  105263. var SHOW_INDEX = Polyline.SHOW_INDEX;
  105264. var WIDTH_INDEX = Polyline.WIDTH_INDEX;
  105265. var POSITION_INDEX = Polyline.POSITION_INDEX;
  105266. var MATERIAL_INDEX = Polyline.MATERIAL_INDEX;
  105267. //POSITION_SIZE_INDEX is needed for when the polyline's position array changes size.
  105268. //When it does, we need to recreate the indicesBuffer.
  105269. var POSITION_SIZE_INDEX = Polyline.POSITION_SIZE_INDEX;
  105270. var DISTANCE_DISPLAY_CONDITION = Polyline.DISTANCE_DISPLAY_CONDITION;
  105271. var NUMBER_OF_PROPERTIES = Polyline.NUMBER_OF_PROPERTIES;
  105272. var attributeLocations = {
  105273. texCoordExpandAndBatchIndex : 0,
  105274. position3DHigh : 1,
  105275. position3DLow : 2,
  105276. position2DHigh : 3,
  105277. position2DLow : 4,
  105278. prevPosition3DHigh : 5,
  105279. prevPosition3DLow : 6,
  105280. prevPosition2DHigh : 7,
  105281. prevPosition2DLow : 8,
  105282. nextPosition3DHigh : 9,
  105283. nextPosition3DLow : 10,
  105284. nextPosition2DHigh : 11,
  105285. nextPosition2DLow : 12
  105286. };
  105287. /**
  105288. * A renderable collection of polylines.
  105289. * <br /><br />
  105290. * <div align="center">
  105291. * <img src="images/Polyline.png" width="400" height="300" /><br />
  105292. * Example polylines
  105293. * </div>
  105294. * <br /><br />
  105295. * Polylines are added and removed from the collection using {@link PolylineCollection#add}
  105296. * and {@link PolylineCollection#remove}.
  105297. *
  105298. * @alias PolylineCollection
  105299. * @constructor
  105300. *
  105301. * @param {Object} [options] Object with the following properties:
  105302. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms each polyline from model to world coordinates.
  105303. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
  105304. *
  105305. * @performance For best performance, prefer a few collections, each with many polylines, to
  105306. * many collections with only a few polylines each. Organize collections so that polylines
  105307. * with the same update frequency are in the same collection, i.e., polylines that do not
  105308. * change should be in one collection; polylines that change every frame should be in another
  105309. * collection; and so on.
  105310. *
  105311. * @see PolylineCollection#add
  105312. * @see PolylineCollection#remove
  105313. * @see Polyline
  105314. * @see LabelCollection
  105315. *
  105316. * @example
  105317. * // Create a polyline collection with two polylines
  105318. * var polylines = new Cesium.PolylineCollection();
  105319. * polylines.add({
  105320. * positions : Cesium.Cartesian3.fromDegreesArray([
  105321. * -75.10, 39.57,
  105322. * -77.02, 38.53,
  105323. * -80.50, 35.14,
  105324. * -80.12, 25.46]),
  105325. * width : 2
  105326. * });
  105327. *
  105328. * polylines.add({
  105329. * positions : Cesium.Cartesian3.fromDegreesArray([
  105330. * -73.10, 37.57,
  105331. * -75.02, 36.53,
  105332. * -78.50, 33.14,
  105333. * -78.12, 23.46]),
  105334. * width : 4
  105335. * });
  105336. */
  105337. function PolylineCollection(options) {
  105338. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  105339. /**
  105340. * The 4x4 transformation matrix that transforms each polyline in this collection from model to world coordinates.
  105341. * When this is the identity matrix, the polylines are drawn in world coordinates, i.e., Earth's WGS84 coordinates.
  105342. * Local reference frames can be used by providing a different transformation matrix, like that returned
  105343. * by {@link Transforms.eastNorthUpToFixedFrame}.
  105344. *
  105345. * @type {Matrix4}
  105346. * @default {@link Matrix4.IDENTITY}
  105347. */
  105348. this.modelMatrix = Matrix4.clone(defaultValue(options.modelMatrix, Matrix4.IDENTITY));
  105349. this._modelMatrix = Matrix4.clone(Matrix4.IDENTITY);
  105350. /**
  105351. * This property is for debugging only; it is not for production use nor is it optimized.
  105352. * <p>
  105353. * Draws the bounding sphere for each draw command in the primitive.
  105354. * </p>
  105355. *
  105356. * @type {Boolean}
  105357. *
  105358. * @default false
  105359. */
  105360. this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false);
  105361. this._opaqueRS = undefined;
  105362. this._translucentRS = undefined;
  105363. this._colorCommands = [];
  105364. this._pickCommands = [];
  105365. this._polylinesUpdated = false;
  105366. this._polylinesRemoved = false;
  105367. this._createVertexArray = false;
  105368. this._propertiesChanged = new Uint32Array(NUMBER_OF_PROPERTIES);
  105369. this._polylines = [];
  105370. this._polylineBuckets = {};
  105371. // The buffer usage is determined based on the usage of the attribute over time.
  105372. this._positionBufferUsage = { bufferUsage : BufferUsage.STATIC_DRAW, frameCount : 0 };
  105373. this._mode = undefined;
  105374. this._polylinesToUpdate = [];
  105375. this._vertexArrays = [];
  105376. this._positionBuffer = undefined;
  105377. this._texCoordExpandAndBatchIndexBuffer = undefined;
  105378. this._batchTable = undefined;
  105379. this._createBatchTable = false;
  105380. }
  105381. defineProperties(PolylineCollection.prototype, {
  105382. /**
  105383. * Returns the number of polylines in this collection. This is commonly used with
  105384. * {@link PolylineCollection#get} to iterate over all the polylines
  105385. * in the collection.
  105386. * @memberof PolylineCollection.prototype
  105387. * @type {Number}
  105388. */
  105389. length : {
  105390. get : function() {
  105391. removePolylines(this);
  105392. return this._polylines.length;
  105393. }
  105394. }
  105395. });
  105396. /**
  105397. * Creates and adds a polyline with the specified initial properties to the collection.
  105398. * The added polyline is returned so it can be modified or removed from the collection later.
  105399. *
  105400. * @param {Object}[polyline] A template describing the polyline's properties as shown in Example 1.
  105401. * @returns {Polyline} The polyline that was added to the collection.
  105402. *
  105403. * @performance After calling <code>add</code>, {@link PolylineCollection#update} is called and
  105404. * the collection's vertex buffer is rewritten - an <code>O(n)</code> operation that also incurs CPU to GPU overhead.
  105405. * For best performance, add as many polylines as possible before calling <code>update</code>.
  105406. *
  105407. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  105408. *
  105409. *
  105410. * @example
  105411. * // Example 1: Add a polyline, specifying all the default values.
  105412. * var p = polylines.add({
  105413. * show : true,
  105414. * positions : ellipsoid.cartographicArrayToCartesianArray([
  105415. Cesium.Cartographic.fromDegrees(-75.10, 39.57),
  105416. Cesium.Cartographic.fromDegrees(-77.02, 38.53)]),
  105417. * width : 1
  105418. * });
  105419. *
  105420. * @see PolylineCollection#remove
  105421. * @see PolylineCollection#removeAll
  105422. * @see PolylineCollection#update
  105423. */
  105424. PolylineCollection.prototype.add = function(polyline) {
  105425. var p = new Polyline(polyline, this);
  105426. p._index = this._polylines.length;
  105427. this._polylines.push(p);
  105428. this._createVertexArray = true;
  105429. this._createBatchTable = true;
  105430. return p;
  105431. };
  105432. /**
  105433. * Removes a polyline from the collection.
  105434. *
  105435. * @param {Polyline} polyline The polyline to remove.
  105436. * @returns {Boolean} <code>true</code> if the polyline was removed; <code>false</code> if the polyline was not found in the collection.
  105437. *
  105438. * @performance After calling <code>remove</code>, {@link PolylineCollection#update} is called and
  105439. * the collection's vertex buffer is rewritten - an <code>O(n)</code> operation that also incurs CPU to GPU overhead.
  105440. * For best performance, remove as many polylines as possible before calling <code>update</code>.
  105441. * If you intend to temporarily hide a polyline, it is usually more efficient to call
  105442. * {@link Polyline#show} instead of removing and re-adding the polyline.
  105443. *
  105444. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  105445. *
  105446. *
  105447. * @example
  105448. * var p = polylines.add(...);
  105449. * polylines.remove(p); // Returns true
  105450. *
  105451. * @see PolylineCollection#add
  105452. * @see PolylineCollection#removeAll
  105453. * @see PolylineCollection#update
  105454. * @see Polyline#show
  105455. */
  105456. PolylineCollection.prototype.remove = function(polyline) {
  105457. if (this.contains(polyline)) {
  105458. this._polylines[polyline._index] = undefined; // Removed later
  105459. this._polylinesRemoved = true;
  105460. this._createVertexArray = true;
  105461. this._createBatchTable = true;
  105462. if (defined(polyline._bucket)) {
  105463. var bucket = polyline._bucket;
  105464. bucket.shaderProgram = bucket.shaderProgram && bucket.shaderProgram.destroy();
  105465. bucket.pickShaderProgram = bucket.pickShaderProgram && bucket.pickShaderProgram.destroy();
  105466. }
  105467. polyline._destroy();
  105468. return true;
  105469. }
  105470. return false;
  105471. };
  105472. /**
  105473. * Removes all polylines from the collection.
  105474. *
  105475. * @performance <code>O(n)</code>. It is more efficient to remove all the polylines
  105476. * from a collection and then add new ones than to create a new collection entirely.
  105477. *
  105478. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  105479. *
  105480. *
  105481. * @example
  105482. * polylines.add(...);
  105483. * polylines.add(...);
  105484. * polylines.removeAll();
  105485. *
  105486. * @see PolylineCollection#add
  105487. * @see PolylineCollection#remove
  105488. * @see PolylineCollection#update
  105489. */
  105490. PolylineCollection.prototype.removeAll = function() {
  105491. releaseShaders(this);
  105492. destroyPolylines(this);
  105493. this._polylineBuckets = {};
  105494. this._polylinesRemoved = false;
  105495. this._polylines.length = 0;
  105496. this._polylinesToUpdate.length = 0;
  105497. this._createVertexArray = true;
  105498. };
  105499. /**
  105500. * Determines if this collection contains the specified polyline.
  105501. *
  105502. * @param {Polyline} polyline The polyline to check for.
  105503. * @returns {Boolean} true if this collection contains the polyline, false otherwise.
  105504. *
  105505. * @see PolylineCollection#get
  105506. */
  105507. PolylineCollection.prototype.contains = function(polyline) {
  105508. return defined(polyline) && polyline._polylineCollection === this;
  105509. };
  105510. /**
  105511. * Returns the polyline in the collection at the specified index. Indices are zero-based
  105512. * and increase as polylines are added. Removing a polyline shifts all polylines after
  105513. * it to the left, changing their indices. This function is commonly used with
  105514. * {@link PolylineCollection#length} to iterate over all the polylines
  105515. * in the collection.
  105516. *
  105517. * @param {Number} index The zero-based index of the polyline.
  105518. * @returns {Polyline} The polyline at the specified index.
  105519. *
  105520. * @performance If polylines were removed from the collection and
  105521. * {@link PolylineCollection#update} was not called, an implicit <code>O(n)</code>
  105522. * operation is performed.
  105523. *
  105524. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  105525. *
  105526. * @example
  105527. * // Toggle the show property of every polyline in the collection
  105528. * var len = polylines.length;
  105529. * for (var i = 0; i < len; ++i) {
  105530. * var p = polylines.get(i);
  105531. * p.show = !p.show;
  105532. * }
  105533. *
  105534. * @see PolylineCollection#length
  105535. */
  105536. PolylineCollection.prototype.get = function(index) {
  105537. if (!defined(index)) {
  105538. throw new DeveloperError('index is required.');
  105539. }
  105540. removePolylines(this);
  105541. return this._polylines[index];
  105542. };
  105543. function createBatchTable(collection, context) {
  105544. if (defined(collection._batchTable)) {
  105545. collection._batchTable.destroy();
  105546. }
  105547. var attributes = [{
  105548. functionName : 'batchTable_getWidthAndShow',
  105549. componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
  105550. componentsPerAttribute : 2
  105551. }, {
  105552. functionName : 'batchTable_getPickColor',
  105553. componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
  105554. componentsPerAttribute : 4,
  105555. normalize : true
  105556. }, {
  105557. functionName : 'batchTable_getCenterHigh',
  105558. componentDatatype : ComponentDatatype.FLOAT,
  105559. componentsPerAttribute : 3
  105560. }, {
  105561. functionName : 'batchTable_getCenterLowAndRadius',
  105562. componentDatatype : ComponentDatatype.FLOAT,
  105563. componentsPerAttribute : 4
  105564. }, {
  105565. functionName : 'batchTable_getDistanceDisplayCondition',
  105566. componentDatatype : ComponentDatatype.FLOAT,
  105567. componentsPerAttribute : 2
  105568. }];
  105569. collection._batchTable = new BatchTable(context, attributes, collection._polylines.length);
  105570. }
  105571. var scratchUpdatePolylineEncodedCartesian = new EncodedCartesian3();
  105572. var scratchUpdatePolylineCartesian4 = new Cartesian4();
  105573. var scratchNearFarCartesian2 = new Cartesian2();
  105574. /**
  105575. * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
  105576. * get the draw commands needed to render this primitive.
  105577. * <p>
  105578. * Do not call this function directly. This is documented just to
  105579. * list the exceptions that may be propagated when the scene is rendered:
  105580. * </p>
  105581. *
  105582. * @exception {RuntimeError} Vertex texture fetch support is required to render primitives with per-instance attributes. The maximum number of vertex texture image units must be greater than zero.
  105583. */
  105584. PolylineCollection.prototype.update = function(frameState) {
  105585. removePolylines(this);
  105586. if (this._polylines.length === 0) {
  105587. return;
  105588. }
  105589. updateMode(this, frameState);
  105590. var context = frameState.context;
  105591. var projection = frameState.mapProjection;
  105592. var polyline;
  105593. var properties = this._propertiesChanged;
  105594. if (this._createBatchTable) {
  105595. if (ContextLimits.maximumVertexTextureImageUnits === 0) {
  105596. throw new RuntimeError('Vertex texture fetch support is required to render polylines. The maximum number of vertex texture image units must be greater than zero.');
  105597. }
  105598. createBatchTable(this, context);
  105599. this._createBatchTable = false;
  105600. }
  105601. if (this._createVertexArray || computeNewBuffersUsage(this)) {
  105602. createVertexArrays(this, context, projection);
  105603. } else if (this._polylinesUpdated) {
  105604. // Polylines were modified, but no polylines were added or removed.
  105605. var polylinesToUpdate = this._polylinesToUpdate;
  105606. if (this._mode !== SceneMode.SCENE3D) {
  105607. var updateLength = polylinesToUpdate.length;
  105608. for ( var i = 0; i < updateLength; ++i) {
  105609. polyline = polylinesToUpdate[i];
  105610. polyline.update();
  105611. }
  105612. }
  105613. // if a polyline's positions size changes, we need to recreate the vertex arrays and vertex buffers because the indices will be different.
  105614. // if a polyline's material changes, we need to recreate the VAOs and VBOs because they will be batched differently.
  105615. if (properties[POSITION_SIZE_INDEX] || properties[MATERIAL_INDEX]) {
  105616. createVertexArrays(this, context, projection);
  105617. } else {
  105618. var length = polylinesToUpdate.length;
  105619. var polylineBuckets = this._polylineBuckets;
  105620. for ( var ii = 0; ii < length; ++ii) {
  105621. polyline = polylinesToUpdate[ii];
  105622. properties = polyline._propertiesChanged;
  105623. var bucket = polyline._bucket;
  105624. var index = 0;
  105625. for (var x in polylineBuckets) {
  105626. if (polylineBuckets.hasOwnProperty(x)) {
  105627. if (polylineBuckets[x] === bucket) {
  105628. if (properties[POSITION_INDEX]) {
  105629. bucket.writeUpdate(index, polyline, this._positionBuffer, projection);
  105630. }
  105631. break;
  105632. }
  105633. index += polylineBuckets[x].lengthOfPositions;
  105634. }
  105635. }
  105636. if (properties[SHOW_INDEX] || properties[WIDTH_INDEX]) {
  105637. this._batchTable.setBatchedAttribute(polyline._index, 0, new Cartesian2(polyline._width, polyline._show));
  105638. }
  105639. if (this._batchTable.attributes.length > 2) {
  105640. if (properties[POSITION_INDEX] || properties[POSITION_SIZE_INDEX]) {
  105641. var boundingSphere = frameState.mode === SceneMode.SCENE2D ? polyline._boundingVolume2D : polyline._boundingVolumeWC;
  105642. var encodedCenter = EncodedCartesian3.fromCartesian(boundingSphere.center, scratchUpdatePolylineEncodedCartesian);
  105643. var low = Cartesian4.fromElements(encodedCenter.low.x, encodedCenter.low.y, encodedCenter.low.z, boundingSphere.radius, scratchUpdatePolylineCartesian4);
  105644. this._batchTable.setBatchedAttribute(polyline._index, 2, encodedCenter.high);
  105645. this._batchTable.setBatchedAttribute(polyline._index, 3, low);
  105646. }
  105647. if (properties[DISTANCE_DISPLAY_CONDITION]) {
  105648. var nearFarCartesian = scratchNearFarCartesian2;
  105649. nearFarCartesian.x = 0.0;
  105650. nearFarCartesian.y = Number.MAX_VALUE;
  105651. var distanceDisplayCondition = polyline.distanceDisplayCondition;
  105652. if (defined(distanceDisplayCondition)) {
  105653. nearFarCartesian.x = distanceDisplayCondition.near;
  105654. nearFarCartesian.x = distanceDisplayCondition.far;
  105655. }
  105656. this._batchTable.setBatchedAttribute(polyline._index, 4, nearFarCartesian);
  105657. }
  105658. }
  105659. polyline._clean();
  105660. }
  105661. }
  105662. polylinesToUpdate.length = 0;
  105663. this._polylinesUpdated = false;
  105664. }
  105665. properties = this._propertiesChanged;
  105666. for ( var k = 0; k < NUMBER_OF_PROPERTIES; ++k) {
  105667. properties[k] = 0;
  105668. }
  105669. var modelMatrix = Matrix4.IDENTITY;
  105670. if (frameState.mode === SceneMode.SCENE3D) {
  105671. modelMatrix = this.modelMatrix;
  105672. }
  105673. var pass = frameState.passes;
  105674. var useDepthTest = (frameState.morphTime !== 0.0);
  105675. if (!defined(this._opaqueRS) || this._opaqueRS.depthTest.enabled !== useDepthTest) {
  105676. this._opaqueRS = RenderState.fromCache({
  105677. depthMask : useDepthTest,
  105678. depthTest : {
  105679. enabled : useDepthTest
  105680. }
  105681. });
  105682. }
  105683. if (!defined(this._translucentRS) || this._translucentRS.depthTest.enabled !== useDepthTest) {
  105684. this._translucentRS = RenderState.fromCache({
  105685. blending : BlendingState.ALPHA_BLEND,
  105686. depthMask : !useDepthTest,
  105687. depthTest : {
  105688. enabled : useDepthTest
  105689. }
  105690. });
  105691. }
  105692. this._batchTable.update(frameState);
  105693. if (pass.render) {
  105694. var colorList = this._colorCommands;
  105695. createCommandLists(this, frameState, colorList, modelMatrix, true);
  105696. }
  105697. if (pass.pick) {
  105698. var pickList = this._pickCommands;
  105699. createCommandLists(this, frameState, pickList, modelMatrix, false);
  105700. }
  105701. };
  105702. var boundingSphereScratch = new BoundingSphere();
  105703. var boundingSphereScratch2 = new BoundingSphere();
  105704. function createCommandLists(polylineCollection, frameState, commands, modelMatrix, renderPass) {
  105705. var context = frameState.context;
  105706. var commandList = frameState.commandList;
  105707. var commandsLength = commands.length;
  105708. var commandIndex = 0;
  105709. var cloneBoundingSphere = true;
  105710. var vertexArrays = polylineCollection._vertexArrays;
  105711. var debugShowBoundingVolume = polylineCollection.debugShowBoundingVolume;
  105712. var batchTable = polylineCollection._batchTable;
  105713. var uniformCallback = batchTable.getUniformMapCallback();
  105714. var length = vertexArrays.length;
  105715. for ( var m = 0; m < length; ++m) {
  105716. var va = vertexArrays[m];
  105717. var buckets = va.buckets;
  105718. var bucketLength = buckets.length;
  105719. for ( var n = 0; n < bucketLength; ++n) {
  105720. var bucketLocator = buckets[n];
  105721. var offset = bucketLocator.offset;
  105722. var sp = renderPass ? bucketLocator.bucket.shaderProgram : bucketLocator.bucket.pickShaderProgram;
  105723. var polylines = bucketLocator.bucket.polylines;
  105724. var polylineLength = polylines.length;
  105725. var currentId;
  105726. var currentMaterial;
  105727. var count = 0;
  105728. var command;
  105729. for (var s = 0; s < polylineLength; ++s) {
  105730. var polyline = polylines[s];
  105731. var mId = createMaterialId(polyline._material);
  105732. if (mId !== currentId) {
  105733. if (defined(currentId) && count > 0) {
  105734. var translucent = currentMaterial.isTranslucent();
  105735. if (commandIndex >= commandsLength) {
  105736. command = new DrawCommand({
  105737. owner : polylineCollection
  105738. });
  105739. commands.push(command);
  105740. } else {
  105741. command = commands[commandIndex];
  105742. }
  105743. ++commandIndex;
  105744. command.boundingVolume = BoundingSphere.clone(boundingSphereScratch, command.boundingVolume);
  105745. command.modelMatrix = modelMatrix;
  105746. command.shaderProgram = sp;
  105747. command.vertexArray = va.va;
  105748. command.renderState = translucent ? polylineCollection._translucentRS : polylineCollection._opaqueRS;
  105749. command.pass = translucent ? Pass.TRANSLUCENT : Pass.OPAQUE;
  105750. command.debugShowBoundingVolume = renderPass ? debugShowBoundingVolume : false;
  105751. command.uniformMap = uniformCallback(currentMaterial._uniforms);
  105752. command.count = count;
  105753. command.offset = offset;
  105754. offset += count;
  105755. count = 0;
  105756. cloneBoundingSphere = true;
  105757. commandList.push(command);
  105758. }
  105759. currentMaterial = polyline._material;
  105760. currentMaterial.update(context);
  105761. currentId = mId;
  105762. }
  105763. var locators = polyline._locatorBuckets;
  105764. var locatorLength = locators.length;
  105765. for (var t = 0; t < locatorLength; ++t) {
  105766. var locator = locators[t];
  105767. if (locator.locator === bucketLocator) {
  105768. count += locator.count;
  105769. }
  105770. }
  105771. var boundingVolume;
  105772. if (frameState.mode === SceneMode.SCENE3D) {
  105773. boundingVolume = polyline._boundingVolumeWC;
  105774. } else if (frameState.mode === SceneMode.COLUMBUS_VIEW) {
  105775. boundingVolume = polyline._boundingVolume2D;
  105776. } else if (frameState.mode === SceneMode.SCENE2D) {
  105777. if (defined(polyline._boundingVolume2D)) {
  105778. boundingVolume = BoundingSphere.clone(polyline._boundingVolume2D, boundingSphereScratch2);
  105779. boundingVolume.center.x = 0.0;
  105780. }
  105781. } else if (defined(polyline._boundingVolumeWC) && defined(polyline._boundingVolume2D)) {
  105782. boundingVolume = BoundingSphere.union(polyline._boundingVolumeWC, polyline._boundingVolume2D, boundingSphereScratch2);
  105783. }
  105784. if (cloneBoundingSphere) {
  105785. cloneBoundingSphere = false;
  105786. BoundingSphere.clone(boundingVolume, boundingSphereScratch);
  105787. } else {
  105788. BoundingSphere.union(boundingVolume, boundingSphereScratch, boundingSphereScratch);
  105789. }
  105790. }
  105791. if (defined(currentId) && count > 0) {
  105792. if (commandIndex >= commandsLength) {
  105793. command = new DrawCommand({
  105794. owner : polylineCollection
  105795. });
  105796. commands.push(command);
  105797. } else {
  105798. command = commands[commandIndex];
  105799. }
  105800. ++commandIndex;
  105801. command.boundingVolume = BoundingSphere.clone(boundingSphereScratch, command.boundingVolume);
  105802. command.modelMatrix = modelMatrix;
  105803. command.shaderProgram = sp;
  105804. command.vertexArray = va.va;
  105805. command.renderState = currentMaterial.isTranslucent() ? polylineCollection._translucentRS : polylineCollection._opaqueRS;
  105806. command.pass = currentMaterial.isTranslucent() ? Pass.TRANSLUCENT : Pass.OPAQUE;
  105807. command.debugShowBoundingVolume = renderPass ? debugShowBoundingVolume : false;
  105808. command.uniformMap = uniformCallback(currentMaterial._uniforms);
  105809. command.count = count;
  105810. command.offset = offset;
  105811. cloneBoundingSphere = true;
  105812. commandList.push(command);
  105813. }
  105814. currentId = undefined;
  105815. }
  105816. }
  105817. commands.length = commandIndex;
  105818. }
  105819. /**
  105820. * Returns true if this object was destroyed; otherwise, false.
  105821. * <br /><br />
  105822. * If this object was destroyed, it should not be used; calling any function other than
  105823. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  105824. *
  105825. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  105826. *
  105827. * @see PolylineCollection#destroy
  105828. */
  105829. PolylineCollection.prototype.isDestroyed = function() {
  105830. return false;
  105831. };
  105832. /**
  105833. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  105834. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  105835. * <br /><br />
  105836. * Once an object is destroyed, it should not be used; calling any function other than
  105837. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  105838. * assign the return value (<code>undefined</code>) to the object as done in the example.
  105839. *
  105840. * @returns {undefined}
  105841. *
  105842. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  105843. *
  105844. *
  105845. * @example
  105846. * polylines = polylines && polylines.destroy();
  105847. *
  105848. * @see PolylineCollection#isDestroyed
  105849. */
  105850. PolylineCollection.prototype.destroy = function() {
  105851. destroyVertexArrays(this);
  105852. releaseShaders(this);
  105853. destroyPolylines(this);
  105854. this._batchTable = this._batchTable && this._batchTable.destroy();
  105855. return destroyObject(this);
  105856. };
  105857. function computeNewBuffersUsage(collection) {
  105858. var usageChanged = false;
  105859. var properties = collection._propertiesChanged;
  105860. var bufferUsage = collection._positionBufferUsage;
  105861. if (properties[POSITION_INDEX]) {
  105862. if (bufferUsage.bufferUsage !== BufferUsage.STREAM_DRAW) {
  105863. usageChanged = true;
  105864. bufferUsage.bufferUsage = BufferUsage.STREAM_DRAW;
  105865. bufferUsage.frameCount = 100;
  105866. } else {
  105867. bufferUsage.frameCount = 100;
  105868. }
  105869. } else {
  105870. if (bufferUsage.bufferUsage !== BufferUsage.STATIC_DRAW) {
  105871. if (bufferUsage.frameCount === 0) {
  105872. usageChanged = true;
  105873. bufferUsage.bufferUsage = BufferUsage.STATIC_DRAW;
  105874. } else {
  105875. bufferUsage.frameCount--;
  105876. }
  105877. }
  105878. }
  105879. return usageChanged;
  105880. }
  105881. var emptyVertexBuffer = [0.0, 0.0, 0.0];
  105882. function createVertexArrays(collection, context, projection) {
  105883. collection._createVertexArray = false;
  105884. releaseShaders(collection);
  105885. destroyVertexArrays(collection);
  105886. sortPolylinesIntoBuckets(collection);
  105887. //stores all of the individual indices arrays.
  105888. var totalIndices = [[]];
  105889. var indices = totalIndices[0];
  105890. var batchTable = collection._batchTable;
  105891. //used to determine the vertexBuffer offset if the indicesArray goes over 64k.
  105892. //if it's the same polyline while it goes over 64k, the offset needs to backtrack componentsPerAttribute * componentDatatype bytes
  105893. //so that the polyline looks contiguous.
  105894. //if the polyline ends at the 64k mark, then the offset is just 64k * componentsPerAttribute * componentDatatype
  105895. var vertexBufferOffset = [0];
  105896. var offset = 0;
  105897. var vertexArrayBuckets = [[]];
  105898. var totalLength = 0;
  105899. var polylineBuckets = collection._polylineBuckets;
  105900. var x;
  105901. var bucket;
  105902. for (x in polylineBuckets) {
  105903. if (polylineBuckets.hasOwnProperty(x)) {
  105904. bucket = polylineBuckets[x];
  105905. bucket.updateShader(context, batchTable);
  105906. totalLength += bucket.lengthOfPositions;
  105907. }
  105908. }
  105909. if (totalLength > 0) {
  105910. var mode = collection._mode;
  105911. var positionArray = new Float32Array(6 * totalLength * 3);
  105912. var texCoordExpandAndBatchIndexArray = new Float32Array(totalLength * 4);
  105913. var position3DArray;
  105914. var positionIndex = 0;
  105915. var colorIndex = 0;
  105916. var texCoordExpandAndBatchIndexIndex = 0;
  105917. for (x in polylineBuckets) {
  105918. if (polylineBuckets.hasOwnProperty(x)) {
  105919. bucket = polylineBuckets[x];
  105920. bucket.write(positionArray, texCoordExpandAndBatchIndexArray, positionIndex, colorIndex, texCoordExpandAndBatchIndexIndex, batchTable, context, projection);
  105921. if (mode === SceneMode.MORPHING) {
  105922. if (!defined(position3DArray)) {
  105923. position3DArray = new Float32Array(6 * totalLength * 3);
  105924. }
  105925. bucket.writeForMorph(position3DArray, positionIndex);
  105926. }
  105927. var bucketLength = bucket.lengthOfPositions;
  105928. positionIndex += 6 * bucketLength * 3;
  105929. colorIndex += bucketLength * 4;
  105930. texCoordExpandAndBatchIndexIndex += bucketLength * 4;
  105931. offset = bucket.updateIndices(totalIndices, vertexBufferOffset, vertexArrayBuckets, offset);
  105932. }
  105933. }
  105934. var positionBufferUsage = collection._positionBufferUsage.bufferUsage;
  105935. var texCoordExpandAndBatchIndexBufferUsage = BufferUsage.STATIC_DRAW;
  105936. collection._positionBuffer = Buffer.createVertexBuffer({
  105937. context : context,
  105938. typedArray : positionArray,
  105939. usage : positionBufferUsage
  105940. });
  105941. var position3DBuffer;
  105942. if (defined(position3DArray)) {
  105943. position3DBuffer = Buffer.createVertexBuffer({
  105944. context : context,
  105945. typedArray : position3DArray,
  105946. usage : positionBufferUsage
  105947. });
  105948. }
  105949. collection._texCoordExpandAndBatchIndexBuffer = Buffer.createVertexBuffer({
  105950. context : context,
  105951. typedArray : texCoordExpandAndBatchIndexArray,
  105952. usage : texCoordExpandAndBatchIndexBufferUsage
  105953. });
  105954. var positionSizeInBytes = 3 * Float32Array.BYTES_PER_ELEMENT;
  105955. var texCoordExpandAndBatchIndexSizeInBytes = 4 * Float32Array.BYTES_PER_ELEMENT;
  105956. var vbo = 0;
  105957. var numberOfIndicesArrays = totalIndices.length;
  105958. for ( var k = 0; k < numberOfIndicesArrays; ++k) {
  105959. indices = totalIndices[k];
  105960. if (indices.length > 0) {
  105961. var indicesArray = new Uint16Array(indices);
  105962. var indexBuffer = Buffer.createIndexBuffer({
  105963. context : context,
  105964. typedArray : indicesArray,
  105965. usage : BufferUsage.STATIC_DRAW,
  105966. indexDatatype : IndexDatatype.UNSIGNED_SHORT
  105967. });
  105968. vbo += vertexBufferOffset[k];
  105969. var positionHighOffset = 6 * (k * (positionSizeInBytes * CesiumMath.SIXTY_FOUR_KILOBYTES) - vbo * positionSizeInBytes);//componentsPerAttribute(3) * componentDatatype(4)
  105970. var positionLowOffset = positionSizeInBytes + positionHighOffset;
  105971. var prevPositionHighOffset = positionSizeInBytes + positionLowOffset;
  105972. var prevPositionLowOffset = positionSizeInBytes + prevPositionHighOffset;
  105973. var nextPositionHighOffset = positionSizeInBytes + prevPositionLowOffset;
  105974. var nextPositionLowOffset = positionSizeInBytes + nextPositionHighOffset;
  105975. var vertexTexCoordExpandAndBatchIndexBufferOffset = k * (texCoordExpandAndBatchIndexSizeInBytes * CesiumMath.SIXTY_FOUR_KILOBYTES) - vbo * texCoordExpandAndBatchIndexSizeInBytes;
  105976. var attributes = [{
  105977. index : attributeLocations.position3DHigh,
  105978. componentsPerAttribute : 3,
  105979. componentDatatype : ComponentDatatype.FLOAT,
  105980. offsetInBytes : positionHighOffset,
  105981. strideInBytes : 6 * positionSizeInBytes
  105982. }, {
  105983. index : attributeLocations.position3DLow,
  105984. componentsPerAttribute : 3,
  105985. componentDatatype : ComponentDatatype.FLOAT,
  105986. offsetInBytes : positionLowOffset,
  105987. strideInBytes : 6 * positionSizeInBytes
  105988. }, {
  105989. index : attributeLocations.position2DHigh,
  105990. componentsPerAttribute : 3,
  105991. componentDatatype : ComponentDatatype.FLOAT,
  105992. offsetInBytes : positionHighOffset,
  105993. strideInBytes : 6 * positionSizeInBytes
  105994. }, {
  105995. index : attributeLocations.position2DLow,
  105996. componentsPerAttribute : 3,
  105997. componentDatatype : ComponentDatatype.FLOAT,
  105998. offsetInBytes : positionLowOffset,
  105999. strideInBytes : 6 * positionSizeInBytes
  106000. }, {
  106001. index : attributeLocations.prevPosition3DHigh,
  106002. componentsPerAttribute : 3,
  106003. componentDatatype : ComponentDatatype.FLOAT,
  106004. offsetInBytes : prevPositionHighOffset,
  106005. strideInBytes : 6 * positionSizeInBytes
  106006. }, {
  106007. index : attributeLocations.prevPosition3DLow,
  106008. componentsPerAttribute : 3,
  106009. componentDatatype : ComponentDatatype.FLOAT,
  106010. offsetInBytes : prevPositionLowOffset,
  106011. strideInBytes : 6 * positionSizeInBytes
  106012. }, {
  106013. index : attributeLocations.prevPosition2DHigh,
  106014. componentsPerAttribute : 3,
  106015. componentDatatype : ComponentDatatype.FLOAT,
  106016. offsetInBytes : prevPositionHighOffset,
  106017. strideInBytes : 6 * positionSizeInBytes
  106018. }, {
  106019. index : attributeLocations.prevPosition2DLow,
  106020. componentsPerAttribute : 3,
  106021. componentDatatype : ComponentDatatype.FLOAT,
  106022. offsetInBytes : prevPositionLowOffset,
  106023. strideInBytes : 6 * positionSizeInBytes
  106024. }, {
  106025. index : attributeLocations.nextPosition3DHigh,
  106026. componentsPerAttribute : 3,
  106027. componentDatatype : ComponentDatatype.FLOAT,
  106028. offsetInBytes : nextPositionHighOffset,
  106029. strideInBytes : 6 * positionSizeInBytes
  106030. }, {
  106031. index : attributeLocations.nextPosition3DLow,
  106032. componentsPerAttribute : 3,
  106033. componentDatatype : ComponentDatatype.FLOAT,
  106034. offsetInBytes : nextPositionLowOffset,
  106035. strideInBytes : 6 * positionSizeInBytes
  106036. }, {
  106037. index : attributeLocations.nextPosition2DHigh,
  106038. componentsPerAttribute : 3,
  106039. componentDatatype : ComponentDatatype.FLOAT,
  106040. offsetInBytes : nextPositionHighOffset,
  106041. strideInBytes : 6 * positionSizeInBytes
  106042. }, {
  106043. index : attributeLocations.nextPosition2DLow,
  106044. componentsPerAttribute : 3,
  106045. componentDatatype : ComponentDatatype.FLOAT,
  106046. offsetInBytes : nextPositionLowOffset,
  106047. strideInBytes : 6 * positionSizeInBytes
  106048. }, {
  106049. index : attributeLocations.texCoordExpandAndBatchIndex,
  106050. componentsPerAttribute : 4,
  106051. componentDatatype : ComponentDatatype.FLOAT,
  106052. vertexBuffer : collection._texCoordExpandAndBatchIndexBuffer,
  106053. offsetInBytes : vertexTexCoordExpandAndBatchIndexBufferOffset
  106054. }];
  106055. var buffer3D;
  106056. var bufferProperty3D;
  106057. var buffer2D;
  106058. var bufferProperty2D;
  106059. if (mode === SceneMode.SCENE3D) {
  106060. buffer3D = collection._positionBuffer;
  106061. bufferProperty3D = 'vertexBuffer';
  106062. buffer2D = emptyVertexBuffer;
  106063. bufferProperty2D = 'value';
  106064. } else if (mode === SceneMode.SCENE2D || mode === SceneMode.COLUMBUS_VIEW) {
  106065. buffer3D = emptyVertexBuffer;
  106066. bufferProperty3D = 'value';
  106067. buffer2D = collection._positionBuffer;
  106068. bufferProperty2D = 'vertexBuffer';
  106069. } else {
  106070. buffer3D = position3DBuffer;
  106071. bufferProperty3D = 'vertexBuffer';
  106072. buffer2D = collection._positionBuffer;
  106073. bufferProperty2D = 'vertexBuffer';
  106074. }
  106075. attributes[0][bufferProperty3D] = buffer3D;
  106076. attributes[1][bufferProperty3D] = buffer3D;
  106077. attributes[2][bufferProperty2D] = buffer2D;
  106078. attributes[3][bufferProperty2D] = buffer2D;
  106079. attributes[4][bufferProperty3D] = buffer3D;
  106080. attributes[5][bufferProperty3D] = buffer3D;
  106081. attributes[6][bufferProperty2D] = buffer2D;
  106082. attributes[7][bufferProperty2D] = buffer2D;
  106083. attributes[8][bufferProperty3D] = buffer3D;
  106084. attributes[9][bufferProperty3D] = buffer3D;
  106085. attributes[10][bufferProperty2D] = buffer2D;
  106086. attributes[11][bufferProperty2D] = buffer2D;
  106087. var va = new VertexArray({
  106088. context : context,
  106089. attributes : attributes,
  106090. indexBuffer : indexBuffer
  106091. });
  106092. collection._vertexArrays.push({
  106093. va : va,
  106094. buckets : vertexArrayBuckets[k]
  106095. });
  106096. }
  106097. }
  106098. }
  106099. }
  106100. var scratchUniformArray = [];
  106101. function createMaterialId(material) {
  106102. var uniforms = Material._uniformList[material.type];
  106103. var length = uniforms.length;
  106104. scratchUniformArray.length = 2.0 * length;
  106105. var index = 0;
  106106. for (var i = 0; i < length; ++i) {
  106107. var uniform = uniforms[i];
  106108. scratchUniformArray[index] = uniform;
  106109. scratchUniformArray[index + 1] = material._uniforms[uniform]();
  106110. index += 2;
  106111. }
  106112. return material.type + ':' + JSON.stringify(scratchUniformArray);
  106113. }
  106114. function sortPolylinesIntoBuckets(collection) {
  106115. var mode = collection._mode;
  106116. var modelMatrix = collection._modelMatrix;
  106117. var polylineBuckets = collection._polylineBuckets = {};
  106118. var polylines = collection._polylines;
  106119. var length = polylines.length;
  106120. for ( var i = 0; i < length; ++i) {
  106121. var p = polylines[i];
  106122. if (p._actualPositions.length > 1) {
  106123. p.update();
  106124. var material = p.material;
  106125. var value = polylineBuckets[material.type];
  106126. if (!defined(value)) {
  106127. value = polylineBuckets[material.type] = new PolylineBucket(material, mode, modelMatrix);
  106128. }
  106129. value.addPolyline(p);
  106130. }
  106131. }
  106132. }
  106133. function updateMode(collection, frameState) {
  106134. var mode = frameState.mode;
  106135. if (collection._mode !== mode || (!Matrix4.equals(collection._modelMatrix, collection.modelMatrix))) {
  106136. collection._mode = mode;
  106137. collection._modelMatrix = Matrix4.clone(collection.modelMatrix);
  106138. collection._createVertexArray = true;
  106139. }
  106140. }
  106141. function removePolylines(collection) {
  106142. if (collection._polylinesRemoved) {
  106143. collection._polylinesRemoved = false;
  106144. var polylines = [];
  106145. var length = collection._polylines.length;
  106146. for ( var i = 0, j = 0; i < length; ++i) {
  106147. var polyline = collection._polylines[i];
  106148. if (defined(polyline)) {
  106149. polyline._index = j++;
  106150. polylines.push(polyline);
  106151. }
  106152. }
  106153. collection._polylines = polylines;
  106154. }
  106155. }
  106156. function releaseShaders(collection) {
  106157. var polylines = collection._polylines;
  106158. var length = polylines.length;
  106159. for ( var i = 0; i < length; ++i) {
  106160. if (defined(polylines[i])) {
  106161. var bucket = polylines[i]._bucket;
  106162. if (defined(bucket)) {
  106163. bucket.shaderProgram = bucket.shaderProgram && bucket.shaderProgram.destroy();
  106164. }
  106165. }
  106166. }
  106167. }
  106168. function destroyVertexArrays(collection) {
  106169. var length = collection._vertexArrays.length;
  106170. for ( var t = 0; t < length; ++t) {
  106171. collection._vertexArrays[t].va.destroy();
  106172. }
  106173. collection._vertexArrays.length = 0;
  106174. }
  106175. PolylineCollection.prototype._updatePolyline = function(polyline, propertyChanged) {
  106176. this._polylinesUpdated = true;
  106177. this._polylinesToUpdate.push(polyline);
  106178. ++this._propertiesChanged[propertyChanged];
  106179. };
  106180. function destroyPolylines(collection) {
  106181. var polylines = collection._polylines;
  106182. var length = polylines.length;
  106183. for ( var i = 0; i < length; ++i) {
  106184. if (defined(polylines[i])) {
  106185. polylines[i]._destroy();
  106186. }
  106187. }
  106188. }
  106189. function VertexArrayBucketLocator(count, offset, bucket) {
  106190. this.count = count;
  106191. this.offset = offset;
  106192. this.bucket = bucket;
  106193. }
  106194. function PolylineBucket(material, mode, modelMatrix) {
  106195. this.polylines = [];
  106196. this.lengthOfPositions = 0;
  106197. this.material = material;
  106198. this.shaderProgram = undefined;
  106199. this.pickShaderProgram = undefined;
  106200. this.mode = mode;
  106201. this.modelMatrix = modelMatrix;
  106202. }
  106203. PolylineBucket.prototype.addPolyline = function(p) {
  106204. var polylines = this.polylines;
  106205. polylines.push(p);
  106206. p._actualLength = this.getPolylinePositionsLength(p);
  106207. this.lengthOfPositions += p._actualLength;
  106208. p._bucket = this;
  106209. };
  106210. PolylineBucket.prototype.updateShader = function(context, batchTable) {
  106211. if (defined(this.shaderProgram)) {
  106212. return;
  106213. }
  106214. var defines = ['DISTANCE_DISPLAY_CONDITION'];
  106215. var vsSource = batchTable.getVertexShaderCallback()(PolylineVS);
  106216. var vs = new ShaderSource({
  106217. defines : defines,
  106218. sources : [PolylineCommon, vsSource]
  106219. });
  106220. var fs = new ShaderSource({
  106221. sources : [this.material.shaderSource, PolylineFS]
  106222. });
  106223. var fsPick = new ShaderSource({
  106224. sources : fs.sources,
  106225. pickColorQualifier : 'varying'
  106226. });
  106227. this.shaderProgram = ShaderProgram.fromCache({
  106228. context : context,
  106229. vertexShaderSource : vs,
  106230. fragmentShaderSource : fs,
  106231. attributeLocations : attributeLocations
  106232. });
  106233. this.pickShaderProgram = ShaderProgram.fromCache({
  106234. context : context,
  106235. vertexShaderSource : vs,
  106236. fragmentShaderSource : fsPick,
  106237. attributeLocations : attributeLocations
  106238. });
  106239. };
  106240. function intersectsIDL(polyline) {
  106241. return Cartesian3.dot(Cartesian3.UNIT_X, polyline._boundingVolume.center) < 0 ||
  106242. polyline._boundingVolume.intersectPlane(Plane.ORIGIN_ZX_PLANE) === Intersect.INTERSECTING;
  106243. }
  106244. PolylineBucket.prototype.getPolylinePositionsLength = function(polyline) {
  106245. var length;
  106246. if (this.mode === SceneMode.SCENE3D || !intersectsIDL(polyline)) {
  106247. length = polyline._actualPositions.length;
  106248. return length * 4.0 - 4.0;
  106249. }
  106250. var count = 0;
  106251. var segmentLengths = polyline._segments.lengths;
  106252. length = segmentLengths.length;
  106253. for (var i = 0; i < length; ++i) {
  106254. count += segmentLengths[i] * 4.0 - 4.0;
  106255. }
  106256. return count;
  106257. };
  106258. var scratchWritePosition = new Cartesian3();
  106259. var scratchWritePrevPosition = new Cartesian3();
  106260. var scratchWriteNextPosition = new Cartesian3();
  106261. var scratchWriteVector = new Cartesian3();
  106262. var scratchPickColorCartesian = new Cartesian4();
  106263. var scratchWidthShowCartesian = new Cartesian2();
  106264. PolylineBucket.prototype.write = function(positionArray, texCoordExpandAndBatchIndexArray, positionIndex, colorIndex, texCoordExpandAndBatchIndexIndex, batchTable, context, projection) {
  106265. var mode = this.mode;
  106266. var maxLon = projection.ellipsoid.maximumRadius * CesiumMath.PI;
  106267. var polylines = this.polylines;
  106268. var length = polylines.length;
  106269. for ( var i = 0; i < length; ++i) {
  106270. var polyline = polylines[i];
  106271. var width = polyline.width;
  106272. var show = polyline.show && width > 0.0;
  106273. var polylineBatchIndex = polyline._index;
  106274. var segments = this.getSegments(polyline, projection);
  106275. var positions = segments.positions;
  106276. var lengths = segments.lengths;
  106277. var positionsLength = positions.length;
  106278. var pickColor = polyline.getPickId(context).color;
  106279. var segmentIndex = 0;
  106280. var count = 0;
  106281. var position;
  106282. for ( var j = 0; j < positionsLength; ++j) {
  106283. if (j === 0) {
  106284. if (polyline._loop) {
  106285. position = positions[positionsLength - 2];
  106286. } else {
  106287. position = scratchWriteVector;
  106288. Cartesian3.subtract(positions[0], positions[1], position);
  106289. Cartesian3.add(positions[0], position, position);
  106290. }
  106291. } else {
  106292. position = positions[j - 1];
  106293. }
  106294. Cartesian3.clone(position, scratchWritePrevPosition);
  106295. Cartesian3.clone(positions[j], scratchWritePosition);
  106296. if (j === positionsLength - 1) {
  106297. if (polyline._loop) {
  106298. position = positions[1];
  106299. } else {
  106300. position = scratchWriteVector;
  106301. Cartesian3.subtract(positions[positionsLength - 1], positions[positionsLength - 2], position);
  106302. Cartesian3.add(positions[positionsLength - 1], position, position);
  106303. }
  106304. } else {
  106305. position = positions[j + 1];
  106306. }
  106307. Cartesian3.clone(position, scratchWriteNextPosition);
  106308. var segmentLength = lengths[segmentIndex];
  106309. if (j === count + segmentLength) {
  106310. count += segmentLength;
  106311. ++segmentIndex;
  106312. }
  106313. var segmentStart = j - count === 0;
  106314. var segmentEnd = j === count + lengths[segmentIndex] - 1;
  106315. if (mode === SceneMode.SCENE2D) {
  106316. scratchWritePrevPosition.z = 0.0;
  106317. scratchWritePosition.z = 0.0;
  106318. scratchWriteNextPosition.z = 0.0;
  106319. }
  106320. if (mode === SceneMode.SCENE2D || mode === SceneMode.MORPHING) {
  106321. if ((segmentStart || segmentEnd) && maxLon - Math.abs(scratchWritePosition.x) < 1.0) {
  106322. if ((scratchWritePosition.x < 0.0 && scratchWritePrevPosition.x > 0.0) ||
  106323. (scratchWritePosition.x > 0.0 && scratchWritePrevPosition.x < 0.0)) {
  106324. Cartesian3.clone(scratchWritePosition, scratchWritePrevPosition);
  106325. }
  106326. if ((scratchWritePosition.x < 0.0 && scratchWriteNextPosition.x > 0.0) ||
  106327. (scratchWritePosition.x > 0.0 && scratchWriteNextPosition.x < 0.0)) {
  106328. Cartesian3.clone(scratchWritePosition, scratchWriteNextPosition);
  106329. }
  106330. }
  106331. }
  106332. var startK = (segmentStart) ? 2 : 0;
  106333. var endK = (segmentEnd) ? 2 : 4;
  106334. for (var k = startK; k < endK; ++k) {
  106335. EncodedCartesian3.writeElements(scratchWritePosition, positionArray, positionIndex);
  106336. EncodedCartesian3.writeElements(scratchWritePrevPosition, positionArray, positionIndex + 6);
  106337. EncodedCartesian3.writeElements(scratchWriteNextPosition, positionArray, positionIndex + 12);
  106338. var direction = (k - 2 < 0) ? -1.0 : 1.0;
  106339. texCoordExpandAndBatchIndexArray[texCoordExpandAndBatchIndexIndex] = j / (positionsLength - 1); // s tex coord
  106340. texCoordExpandAndBatchIndexArray[texCoordExpandAndBatchIndexIndex + 1] = 2 * (k % 2) - 1; // expand direction
  106341. texCoordExpandAndBatchIndexArray[texCoordExpandAndBatchIndexIndex + 2] = direction;
  106342. texCoordExpandAndBatchIndexArray[texCoordExpandAndBatchIndexIndex + 3] = polylineBatchIndex;
  106343. positionIndex += 6 * 3;
  106344. texCoordExpandAndBatchIndexIndex += 4;
  106345. }
  106346. }
  106347. var colorCartesian = scratchPickColorCartesian;
  106348. colorCartesian.x = Color.floatToByte(pickColor.red);
  106349. colorCartesian.y = Color.floatToByte(pickColor.green);
  106350. colorCartesian.z = Color.floatToByte(pickColor.blue);
  106351. colorCartesian.w = Color.floatToByte(pickColor.alpha);
  106352. var widthShowCartesian = scratchWidthShowCartesian;
  106353. widthShowCartesian.x = width;
  106354. widthShowCartesian.y = show ? 1.0 : 0.0;
  106355. var boundingSphere = mode === SceneMode.SCENE2D ? polyline._boundingVolume2D : polyline._boundingVolumeWC;
  106356. var encodedCenter = EncodedCartesian3.fromCartesian(boundingSphere.center, scratchUpdatePolylineEncodedCartesian);
  106357. var high = encodedCenter.high;
  106358. var low = Cartesian4.fromElements(encodedCenter.low.x, encodedCenter.low.y, encodedCenter.low.z, boundingSphere.radius, scratchUpdatePolylineCartesian4);
  106359. var nearFarCartesian = scratchNearFarCartesian2;
  106360. nearFarCartesian.x = 0.0;
  106361. nearFarCartesian.y = Number.MAX_VALUE;
  106362. var distanceDisplayCondition = polyline.distanceDisplayCondition;
  106363. if (defined(distanceDisplayCondition)) {
  106364. nearFarCartesian.x = distanceDisplayCondition.near;
  106365. nearFarCartesian.y = distanceDisplayCondition.far;
  106366. }
  106367. batchTable.setBatchedAttribute(polylineBatchIndex, 0, widthShowCartesian);
  106368. batchTable.setBatchedAttribute(polylineBatchIndex, 1, colorCartesian);
  106369. if (batchTable.attributes.length > 2) {
  106370. batchTable.setBatchedAttribute(polylineBatchIndex, 2, high);
  106371. batchTable.setBatchedAttribute(polylineBatchIndex, 3, low);
  106372. batchTable.setBatchedAttribute(polylineBatchIndex, 4, nearFarCartesian);
  106373. }
  106374. }
  106375. };
  106376. var morphPositionScratch = new Cartesian3();
  106377. var morphPrevPositionScratch = new Cartesian3();
  106378. var morphNextPositionScratch = new Cartesian3();
  106379. var morphVectorScratch = new Cartesian3();
  106380. PolylineBucket.prototype.writeForMorph = function(positionArray, positionIndex) {
  106381. var modelMatrix = this.modelMatrix;
  106382. var polylines = this.polylines;
  106383. var length = polylines.length;
  106384. for ( var i = 0; i < length; ++i) {
  106385. var polyline = polylines[i];
  106386. var positions = polyline._segments.positions;
  106387. var lengths = polyline._segments.lengths;
  106388. var positionsLength = positions.length;
  106389. var segmentIndex = 0;
  106390. var count = 0;
  106391. for ( var j = 0; j < positionsLength; ++j) {
  106392. var prevPosition;
  106393. if (j === 0) {
  106394. if (polyline._loop) {
  106395. prevPosition = positions[positionsLength - 2];
  106396. } else {
  106397. prevPosition = morphVectorScratch;
  106398. Cartesian3.subtract(positions[0], positions[1], prevPosition);
  106399. Cartesian3.add(positions[0], prevPosition, prevPosition);
  106400. }
  106401. } else {
  106402. prevPosition = positions[j - 1];
  106403. }
  106404. prevPosition = Matrix4.multiplyByPoint(modelMatrix, prevPosition, morphPrevPositionScratch);
  106405. var position = Matrix4.multiplyByPoint(modelMatrix, positions[j], morphPositionScratch);
  106406. var nextPosition;
  106407. if (j === positionsLength - 1) {
  106408. if (polyline._loop) {
  106409. nextPosition = positions[1];
  106410. } else {
  106411. nextPosition = morphVectorScratch;
  106412. Cartesian3.subtract(positions[positionsLength - 1], positions[positionsLength - 2], nextPosition);
  106413. Cartesian3.add(positions[positionsLength - 1], nextPosition, nextPosition);
  106414. }
  106415. } else {
  106416. nextPosition = positions[j + 1];
  106417. }
  106418. nextPosition = Matrix4.multiplyByPoint(modelMatrix, nextPosition, morphNextPositionScratch);
  106419. var segmentLength = lengths[segmentIndex];
  106420. if (j === count + segmentLength) {
  106421. count += segmentLength;
  106422. ++segmentIndex;
  106423. }
  106424. var segmentStart = j - count === 0;
  106425. var segmentEnd = j === count + lengths[segmentIndex] - 1;
  106426. var startK = (segmentStart) ? 2 : 0;
  106427. var endK = (segmentEnd) ? 2 : 4;
  106428. for (var k = startK; k < endK; ++k) {
  106429. EncodedCartesian3.writeElements(position, positionArray, positionIndex);
  106430. EncodedCartesian3.writeElements(prevPosition, positionArray, positionIndex + 6);
  106431. EncodedCartesian3.writeElements(nextPosition, positionArray, positionIndex + 12);
  106432. positionIndex += 6 * 3;
  106433. }
  106434. }
  106435. }
  106436. };
  106437. var scratchSegmentLengths = new Array(1);
  106438. PolylineBucket.prototype.updateIndices = function(totalIndices, vertexBufferOffset, vertexArrayBuckets, offset) {
  106439. var vaCount = vertexArrayBuckets.length - 1;
  106440. var bucketLocator = new VertexArrayBucketLocator(0, offset, this);
  106441. vertexArrayBuckets[vaCount].push(bucketLocator);
  106442. var count = 0;
  106443. var indices = totalIndices[totalIndices.length - 1];
  106444. var indicesCount = 0;
  106445. if (indices.length > 0) {
  106446. indicesCount = indices[indices.length - 1] + 1;
  106447. }
  106448. var polylines = this.polylines;
  106449. var length = polylines.length;
  106450. for ( var i = 0; i < length; ++i) {
  106451. var polyline = polylines[i];
  106452. polyline._locatorBuckets = [];
  106453. var segments;
  106454. if (this.mode === SceneMode.SCENE3D) {
  106455. segments = scratchSegmentLengths;
  106456. var positionsLength = polyline._actualPositions.length;
  106457. if (positionsLength > 0) {
  106458. segments[0] = positionsLength;
  106459. } else {
  106460. continue;
  106461. }
  106462. } else {
  106463. segments = polyline._segments.lengths;
  106464. }
  106465. var numberOfSegments = segments.length;
  106466. if (numberOfSegments > 0) {
  106467. var segmentIndexCount = 0;
  106468. for ( var j = 0; j < numberOfSegments; ++j) {
  106469. var segmentLength = segments[j] - 1.0;
  106470. for ( var k = 0; k < segmentLength; ++k) {
  106471. if (indicesCount + 4 >= CesiumMath.SIXTY_FOUR_KILOBYTES - 2) {
  106472. polyline._locatorBuckets.push({
  106473. locator : bucketLocator,
  106474. count : segmentIndexCount
  106475. });
  106476. segmentIndexCount = 0;
  106477. vertexBufferOffset.push(4);
  106478. indices = [];
  106479. totalIndices.push(indices);
  106480. indicesCount = 0;
  106481. bucketLocator.count = count;
  106482. count = 0;
  106483. offset = 0;
  106484. bucketLocator = new VertexArrayBucketLocator(0, 0, this);
  106485. vertexArrayBuckets[++vaCount] = [bucketLocator];
  106486. }
  106487. indices.push(indicesCount, indicesCount + 2, indicesCount + 1);
  106488. indices.push(indicesCount + 1, indicesCount + 2, indicesCount + 3);
  106489. segmentIndexCount += 6;
  106490. count += 6;
  106491. offset += 6;
  106492. indicesCount += 4;
  106493. }
  106494. }
  106495. polyline._locatorBuckets.push({
  106496. locator : bucketLocator,
  106497. count : segmentIndexCount
  106498. });
  106499. if (indicesCount + 4 >= CesiumMath.SIXTY_FOUR_KILOBYTES - 2) {
  106500. vertexBufferOffset.push(0);
  106501. indices = [];
  106502. totalIndices.push(indices);
  106503. indicesCount = 0;
  106504. bucketLocator.count = count;
  106505. offset = 0;
  106506. count = 0;
  106507. bucketLocator = new VertexArrayBucketLocator(0, 0, this);
  106508. vertexArrayBuckets[++vaCount] = [bucketLocator];
  106509. }
  106510. }
  106511. polyline._clean();
  106512. }
  106513. bucketLocator.count = count;
  106514. return offset;
  106515. };
  106516. PolylineBucket.prototype.getPolylineStartIndex = function(polyline) {
  106517. var polylines = this.polylines;
  106518. var positionIndex = 0;
  106519. var length = polylines.length;
  106520. for ( var i = 0; i < length; ++i) {
  106521. var p = polylines[i];
  106522. if (p === polyline) {
  106523. break;
  106524. }
  106525. positionIndex += p._actualLength;
  106526. }
  106527. return positionIndex;
  106528. };
  106529. var scratchSegments = {
  106530. positions : undefined,
  106531. lengths : undefined
  106532. };
  106533. var scratchLengths = new Array(1);
  106534. var pscratch = new Cartesian3();
  106535. var scratchCartographic = new Cartographic();
  106536. PolylineBucket.prototype.getSegments = function(polyline, projection) {
  106537. var positions = polyline._actualPositions;
  106538. if (this.mode === SceneMode.SCENE3D) {
  106539. scratchLengths[0] = positions.length;
  106540. scratchSegments.positions = positions;
  106541. scratchSegments.lengths = scratchLengths;
  106542. return scratchSegments;
  106543. }
  106544. if (intersectsIDL(polyline)) {
  106545. positions = polyline._segments.positions;
  106546. }
  106547. var ellipsoid = projection.ellipsoid;
  106548. var newPositions = [];
  106549. var modelMatrix = this.modelMatrix;
  106550. var length = positions.length;
  106551. var position;
  106552. var p = pscratch;
  106553. for ( var n = 0; n < length; ++n) {
  106554. position = positions[n];
  106555. p = Matrix4.multiplyByPoint(modelMatrix, position, p);
  106556. newPositions.push(projection.project(ellipsoid.cartesianToCartographic(p, scratchCartographic)));
  106557. }
  106558. if (newPositions.length > 0) {
  106559. polyline._boundingVolume2D = BoundingSphere.fromPoints(newPositions, polyline._boundingVolume2D);
  106560. var center2D = polyline._boundingVolume2D.center;
  106561. polyline._boundingVolume2D.center = new Cartesian3(center2D.z, center2D.x, center2D.y);
  106562. }
  106563. scratchSegments.positions = newPositions;
  106564. scratchSegments.lengths = polyline._segments.lengths;
  106565. return scratchSegments;
  106566. };
  106567. var scratchPositionsArray;
  106568. PolylineBucket.prototype.writeUpdate = function(index, polyline, positionBuffer, projection) {
  106569. var mode = this.mode;
  106570. var maxLon = projection.ellipsoid.maximumRadius * CesiumMath.PI;
  106571. var positionsLength = polyline._actualLength;
  106572. if (positionsLength) {
  106573. index += this.getPolylineStartIndex(polyline);
  106574. var positionArray = scratchPositionsArray;
  106575. var positionsArrayLength = 6 * positionsLength * 3;
  106576. if (!defined(positionArray) || positionArray.length < positionsArrayLength) {
  106577. positionArray = scratchPositionsArray = new Float32Array(positionsArrayLength);
  106578. } else if (positionArray.length > positionsArrayLength) {
  106579. positionArray = new Float32Array(positionArray.buffer, 0, positionsArrayLength);
  106580. }
  106581. var segments = this.getSegments(polyline, projection);
  106582. var positions = segments.positions;
  106583. var lengths = segments.lengths;
  106584. var positionIndex = 0;
  106585. var segmentIndex = 0;
  106586. var count = 0;
  106587. var position;
  106588. positionsLength = positions.length;
  106589. for ( var i = 0; i < positionsLength; ++i) {
  106590. if (i === 0) {
  106591. if (polyline._loop) {
  106592. position = positions[positionsLength - 2];
  106593. } else {
  106594. position = scratchWriteVector;
  106595. Cartesian3.subtract(positions[0], positions[1], position);
  106596. Cartesian3.add(positions[0], position, position);
  106597. }
  106598. } else {
  106599. position = positions[i - 1];
  106600. }
  106601. Cartesian3.clone(position, scratchWritePrevPosition);
  106602. Cartesian3.clone(positions[i], scratchWritePosition);
  106603. if (i === positionsLength - 1) {
  106604. if (polyline._loop) {
  106605. position = positions[1];
  106606. } else {
  106607. position = scratchWriteVector;
  106608. Cartesian3.subtract(positions[positionsLength - 1], positions[positionsLength - 2], position);
  106609. Cartesian3.add(positions[positionsLength - 1], position, position);
  106610. }
  106611. } else {
  106612. position = positions[i + 1];
  106613. }
  106614. Cartesian3.clone(position, scratchWriteNextPosition);
  106615. var segmentLength = lengths[segmentIndex];
  106616. if (i === count + segmentLength) {
  106617. count += segmentLength;
  106618. ++segmentIndex;
  106619. }
  106620. var segmentStart = i - count === 0;
  106621. var segmentEnd = i === count + lengths[segmentIndex] - 1;
  106622. if (mode === SceneMode.SCENE2D) {
  106623. scratchWritePrevPosition.z = 0.0;
  106624. scratchWritePosition.z = 0.0;
  106625. scratchWriteNextPosition.z = 0.0;
  106626. }
  106627. if (mode === SceneMode.SCENE2D || mode === SceneMode.MORPHING) {
  106628. if ((segmentStart || segmentEnd) && maxLon - Math.abs(scratchWritePosition.x) < 1.0) {
  106629. if ((scratchWritePosition.x < 0.0 && scratchWritePrevPosition.x > 0.0) ||
  106630. (scratchWritePosition.x > 0.0 && scratchWritePrevPosition.x < 0.0)) {
  106631. Cartesian3.clone(scratchWritePosition, scratchWritePrevPosition);
  106632. }
  106633. if ((scratchWritePosition.x < 0.0 && scratchWriteNextPosition.x > 0.0) ||
  106634. (scratchWritePosition.x > 0.0 && scratchWriteNextPosition.x < 0.0)) {
  106635. Cartesian3.clone(scratchWritePosition, scratchWriteNextPosition);
  106636. }
  106637. }
  106638. }
  106639. var startJ = (segmentStart) ? 2 : 0;
  106640. var endJ = (segmentEnd) ? 2 : 4;
  106641. for (var j = startJ; j < endJ; ++j) {
  106642. EncodedCartesian3.writeElements(scratchWritePosition, positionArray, positionIndex);
  106643. EncodedCartesian3.writeElements(scratchWritePrevPosition, positionArray, positionIndex + 6);
  106644. EncodedCartesian3.writeElements(scratchWriteNextPosition, positionArray, positionIndex + 12);
  106645. positionIndex += 6 * 3;
  106646. }
  106647. }
  106648. positionBuffer.copyFromArrayView(positionArray, 6 * 3 * Float32Array.BYTES_PER_ELEMENT * index);
  106649. }
  106650. };
  106651. return PolylineCollection;
  106652. });
  106653. /*global define*/
  106654. define('DataSources/ScaledPositionProperty',[
  106655. '../Core/defined',
  106656. '../Core/defineProperties',
  106657. '../Core/DeveloperError',
  106658. '../Core/Ellipsoid',
  106659. '../Core/Event',
  106660. '../Core/ReferenceFrame',
  106661. './Property'
  106662. ], function(
  106663. defined,
  106664. defineProperties,
  106665. DeveloperError,
  106666. Ellipsoid,
  106667. Event,
  106668. ReferenceFrame,
  106669. Property) {
  106670. 'use strict';
  106671. /**
  106672. * This is a temporary class for scaling position properties to the WGS84 surface.
  106673. * It will go away or be refactored to support data with arbitrary height references.
  106674. * @private
  106675. */
  106676. function ScaledPositionProperty(value) {
  106677. this._definitionChanged = new Event();
  106678. this._value = undefined;
  106679. this._removeSubscription = undefined;
  106680. this.setValue(value);
  106681. }
  106682. defineProperties(ScaledPositionProperty.prototype, {
  106683. isConstant : {
  106684. get : function() {
  106685. return Property.isConstant(this._value);
  106686. }
  106687. },
  106688. definitionChanged : {
  106689. get : function() {
  106690. return this._definitionChanged;
  106691. }
  106692. },
  106693. referenceFrame : {
  106694. get : function() {
  106695. return defined(this._value) ? this._value.referenceFrame : ReferenceFrame.FIXED;
  106696. }
  106697. }
  106698. });
  106699. ScaledPositionProperty.prototype.getValue = function(time, result) {
  106700. return this.getValueInReferenceFrame(time, ReferenceFrame.FIXED, result);
  106701. };
  106702. ScaledPositionProperty.prototype.setValue = function(value) {
  106703. if (this._value !== value) {
  106704. this._value = value;
  106705. if (defined(this._removeSubscription)) {
  106706. this._removeSubscription();
  106707. this._removeSubscription = undefined;
  106708. }
  106709. if (defined(value)) {
  106710. this._removeSubscription = value.definitionChanged.addEventListener(this._raiseDefinitionChanged, this);
  106711. }
  106712. this._definitionChanged.raiseEvent(this);
  106713. }
  106714. };
  106715. ScaledPositionProperty.prototype.getValueInReferenceFrame = function(time, referenceFrame, result) {
  106716. if (!defined(time)) {
  106717. throw new DeveloperError('time is required.');
  106718. }
  106719. if (!defined(referenceFrame)) {
  106720. throw new DeveloperError('referenceFrame is required.');
  106721. }
  106722. if (!defined(this._value)) {
  106723. return undefined;
  106724. }
  106725. result = this._value.getValueInReferenceFrame(time, referenceFrame, result);
  106726. return defined(result) ? Ellipsoid.WGS84.scaleToGeodeticSurface(result, result) : undefined;
  106727. };
  106728. ScaledPositionProperty.prototype.equals = function(other) {
  106729. return this === other || (other instanceof ScaledPositionProperty && this._value === other._value);
  106730. };
  106731. ScaledPositionProperty.prototype._raiseDefinitionChanged = function() {
  106732. this._definitionChanged.raiseEvent(this);
  106733. };
  106734. return ScaledPositionProperty;
  106735. });
  106736. /*global define*/
  106737. define('DataSources/PathVisualizer',[
  106738. '../Core/AssociativeArray',
  106739. '../Core/Cartesian3',
  106740. '../Core/defined',
  106741. '../Core/destroyObject',
  106742. '../Core/DeveloperError',
  106743. '../Core/JulianDate',
  106744. '../Core/Matrix3',
  106745. '../Core/Matrix4',
  106746. '../Core/ReferenceFrame',
  106747. '../Core/TimeInterval',
  106748. '../Core/Transforms',
  106749. '../Scene/PolylineCollection',
  106750. '../Scene/SceneMode',
  106751. './CompositePositionProperty',
  106752. './ConstantPositionProperty',
  106753. './MaterialProperty',
  106754. './Property',
  106755. './ReferenceProperty',
  106756. './SampledPositionProperty',
  106757. './ScaledPositionProperty',
  106758. './TimeIntervalCollectionPositionProperty'
  106759. ], function(
  106760. AssociativeArray,
  106761. Cartesian3,
  106762. defined,
  106763. destroyObject,
  106764. DeveloperError,
  106765. JulianDate,
  106766. Matrix3,
  106767. Matrix4,
  106768. ReferenceFrame,
  106769. TimeInterval,
  106770. Transforms,
  106771. PolylineCollection,
  106772. SceneMode,
  106773. CompositePositionProperty,
  106774. ConstantPositionProperty,
  106775. MaterialProperty,
  106776. Property,
  106777. ReferenceProperty,
  106778. SampledPositionProperty,
  106779. ScaledPositionProperty,
  106780. TimeIntervalCollectionPositionProperty) {
  106781. 'use strict';
  106782. var defaultResolution = 60.0;
  106783. var defaultWidth = 1.0;
  106784. var scratchTimeInterval = new TimeInterval();
  106785. var subSampleCompositePropertyScratch = new TimeInterval();
  106786. var subSampleIntervalPropertyScratch = new TimeInterval();
  106787. function EntityData(entity) {
  106788. this.entity = entity;
  106789. this.polyline = undefined;
  106790. this.index = undefined;
  106791. this.updater = undefined;
  106792. }
  106793. function subSampleSampledProperty(property, start, stop, times, updateTime, referenceFrame, maximumStep, startingIndex, result) {
  106794. var r = startingIndex;
  106795. //Always step exactly on start (but only use it if it exists.)
  106796. var tmp;
  106797. tmp = property.getValueInReferenceFrame(start, referenceFrame, result[r]);
  106798. if (defined(tmp)) {
  106799. result[r++] = tmp;
  106800. }
  106801. var steppedOnNow = !defined(updateTime) || JulianDate.lessThanOrEquals(updateTime, start) || JulianDate.greaterThanOrEquals(updateTime, stop);
  106802. //Iterate over all interval times and add the ones that fall in our
  106803. //time range. Note that times can contain data outside of
  106804. //the intervals range. This is by design for use with interpolation.
  106805. var t = 0;
  106806. var len = times.length;
  106807. var current = times[t];
  106808. var loopStop = stop;
  106809. var sampling = false;
  106810. var sampleStepsToTake;
  106811. var sampleStepsTaken;
  106812. var sampleStepSize;
  106813. while (t < len) {
  106814. if (!steppedOnNow && JulianDate.greaterThanOrEquals(current, updateTime)) {
  106815. tmp = property.getValueInReferenceFrame(updateTime, referenceFrame, result[r]);
  106816. if (defined(tmp)) {
  106817. result[r++] = tmp;
  106818. }
  106819. steppedOnNow = true;
  106820. }
  106821. if (JulianDate.greaterThan(current, start) && JulianDate.lessThan(current, loopStop) && !current.equals(updateTime)) {
  106822. tmp = property.getValueInReferenceFrame(current, referenceFrame, result[r]);
  106823. if (defined(tmp)) {
  106824. result[r++] = tmp;
  106825. }
  106826. }
  106827. if (t < (len - 1)) {
  106828. if (maximumStep > 0 && !sampling) {
  106829. var next = times[t + 1];
  106830. var secondsUntilNext = JulianDate.secondsDifference(next, current);
  106831. sampling = secondsUntilNext > maximumStep;
  106832. if (sampling) {
  106833. sampleStepsToTake = Math.ceil(secondsUntilNext / maximumStep);
  106834. sampleStepsTaken = 0;
  106835. sampleStepSize = secondsUntilNext / Math.max(sampleStepsToTake, 2);
  106836. sampleStepsToTake = Math.max(sampleStepsToTake - 1, 1);
  106837. }
  106838. }
  106839. if (sampling && sampleStepsTaken < sampleStepsToTake) {
  106840. current = JulianDate.addSeconds(current, sampleStepSize, new JulianDate());
  106841. sampleStepsTaken++;
  106842. continue;
  106843. }
  106844. }
  106845. sampling = false;
  106846. t++;
  106847. current = times[t];
  106848. }
  106849. //Always step exactly on stop (but only use it if it exists.)
  106850. tmp = property.getValueInReferenceFrame(stop, referenceFrame, result[r]);
  106851. if (defined(tmp)) {
  106852. result[r++] = tmp;
  106853. }
  106854. return r;
  106855. }
  106856. function subSampleGenericProperty(property, start, stop, updateTime, referenceFrame, maximumStep, startingIndex, result) {
  106857. var tmp;
  106858. var i = 0;
  106859. var index = startingIndex;
  106860. var time = start;
  106861. var stepSize = Math.max(maximumStep, 60);
  106862. var steppedOnNow = !defined(updateTime) || JulianDate.lessThanOrEquals(updateTime, start) || JulianDate.greaterThanOrEquals(updateTime, stop);
  106863. while (JulianDate.lessThan(time, stop)) {
  106864. if (!steppedOnNow && JulianDate.greaterThanOrEquals(time, updateTime)) {
  106865. steppedOnNow = true;
  106866. tmp = property.getValueInReferenceFrame(updateTime, referenceFrame, result[index]);
  106867. if (defined(tmp)) {
  106868. result[index] = tmp;
  106869. index++;
  106870. }
  106871. }
  106872. tmp = property.getValueInReferenceFrame(time, referenceFrame, result[index]);
  106873. if (defined(tmp)) {
  106874. result[index] = tmp;
  106875. index++;
  106876. }
  106877. i++;
  106878. time = JulianDate.addSeconds(start, stepSize * i, new JulianDate());
  106879. }
  106880. //Always sample stop.
  106881. tmp = property.getValueInReferenceFrame(stop, referenceFrame, result[index]);
  106882. if (defined(tmp)) {
  106883. result[index] = tmp;
  106884. index++;
  106885. }
  106886. return index;
  106887. }
  106888. function subSampleIntervalProperty(property, start, stop, updateTime, referenceFrame, maximumStep, startingIndex, result) {
  106889. subSampleIntervalPropertyScratch.start = start;
  106890. subSampleIntervalPropertyScratch.stop = stop;
  106891. var index = startingIndex;
  106892. var intervals = property.intervals;
  106893. for (var i = 0; i < intervals.length; i++) {
  106894. var interval = intervals.get(i);
  106895. if (!TimeInterval.intersect(interval, subSampleIntervalPropertyScratch, scratchTimeInterval).isEmpty) {
  106896. var time = interval.start;
  106897. if (!interval.isStartIncluded) {
  106898. if (interval.isStopIncluded) {
  106899. time = interval.stop;
  106900. } else {
  106901. time = JulianDate.addSeconds(interval.start, JulianDate.secondsDifference(interval.stop, interval.start) / 2, new JulianDate());
  106902. }
  106903. }
  106904. var tmp = property.getValueInReferenceFrame(time, referenceFrame, result[index]);
  106905. if (defined(tmp)) {
  106906. result[index] = tmp;
  106907. index++;
  106908. }
  106909. }
  106910. }
  106911. return index;
  106912. }
  106913. function subSampleConstantProperty(property, start, stop, updateTime, referenceFrame, maximumStep, startingIndex, result) {
  106914. var tmp = property.getValueInReferenceFrame(start, referenceFrame, result[startingIndex]);
  106915. if (defined(tmp)) {
  106916. result[startingIndex++] = tmp;
  106917. }
  106918. return startingIndex;
  106919. }
  106920. function subSampleCompositeProperty(property, start, stop, updateTime, referenceFrame, maximumStep, startingIndex, result) {
  106921. subSampleCompositePropertyScratch.start = start;
  106922. subSampleCompositePropertyScratch.stop = stop;
  106923. var index = startingIndex;
  106924. var intervals = property.intervals;
  106925. for (var i = 0; i < intervals.length; i++) {
  106926. var interval = intervals.get(i);
  106927. if (!TimeInterval.intersect(interval, subSampleCompositePropertyScratch, scratchTimeInterval).isEmpty) {
  106928. var intervalStart = interval.start;
  106929. var intervalStop = interval.stop;
  106930. var sampleStart = start;
  106931. if (JulianDate.greaterThan(intervalStart, sampleStart)) {
  106932. sampleStart = intervalStart;
  106933. }
  106934. var sampleStop = stop;
  106935. if (JulianDate.lessThan(intervalStop, sampleStop)) {
  106936. sampleStop = intervalStop;
  106937. }
  106938. index = reallySubSample(interval.data, sampleStart, sampleStop, updateTime, referenceFrame, maximumStep, index, result);
  106939. }
  106940. }
  106941. return index;
  106942. }
  106943. function reallySubSample(property, start, stop, updateTime, referenceFrame, maximumStep, index, result) {
  106944. var innerProperty = property;
  106945. while (innerProperty instanceof ReferenceProperty || innerProperty instanceof ScaledPositionProperty) {
  106946. if (innerProperty instanceof ReferenceProperty) {
  106947. innerProperty = innerProperty.resolvedProperty;
  106948. }
  106949. if (innerProperty instanceof ScaledPositionProperty) {
  106950. innerProperty = innerProperty._value;
  106951. }
  106952. }
  106953. if (innerProperty instanceof SampledPositionProperty) {
  106954. var times = innerProperty._property._times;
  106955. index = subSampleSampledProperty(property, start, stop, times, updateTime, referenceFrame, maximumStep, index, result);
  106956. } else if (innerProperty instanceof CompositePositionProperty) {
  106957. index = subSampleCompositeProperty(property, start, stop, updateTime, referenceFrame, maximumStep, index, result);
  106958. } else if (innerProperty instanceof TimeIntervalCollectionPositionProperty) {
  106959. index = subSampleIntervalProperty(property, start, stop, updateTime, referenceFrame, maximumStep, index, result);
  106960. } else if (innerProperty instanceof ConstantPositionProperty) {
  106961. index = subSampleConstantProperty(property, start, stop, updateTime, referenceFrame, maximumStep, index, result);
  106962. } else {
  106963. //Fallback to generic sampling.
  106964. index = subSampleGenericProperty(property, start, stop, updateTime, referenceFrame, maximumStep, index, result);
  106965. }
  106966. return index;
  106967. }
  106968. function subSample(property, start, stop, updateTime, referenceFrame, maximumStep, result) {
  106969. if (!defined(result)) {
  106970. result = [];
  106971. }
  106972. var length = reallySubSample(property, start, stop, updateTime, referenceFrame, maximumStep, 0, result);
  106973. result.length = length;
  106974. return result;
  106975. }
  106976. var toFixedScratch = new Matrix3();
  106977. function PolylineUpdater(scene, referenceFrame) {
  106978. this._unusedIndexes = [];
  106979. this._polylineCollection = new PolylineCollection();
  106980. this._scene = scene;
  106981. this._referenceFrame = referenceFrame;
  106982. scene.primitives.add(this._polylineCollection);
  106983. }
  106984. PolylineUpdater.prototype.update = function(time) {
  106985. if (this._referenceFrame === ReferenceFrame.INERTIAL) {
  106986. var toFixed = Transforms.computeIcrfToFixedMatrix(time, toFixedScratch);
  106987. if (!defined(toFixed)) {
  106988. toFixed = Transforms.computeTemeToPseudoFixedMatrix(time, toFixedScratch);
  106989. }
  106990. Matrix4.fromRotationTranslation(toFixed, Cartesian3.ZERO, this._polylineCollection.modelMatrix);
  106991. }
  106992. };
  106993. PolylineUpdater.prototype.updateObject = function(time, item) {
  106994. var entity = item.entity;
  106995. var pathGraphics = entity._path;
  106996. var positionProperty = entity._position;
  106997. var sampleStart;
  106998. var sampleStop;
  106999. var showProperty = pathGraphics._show;
  107000. var polyline = item.polyline;
  107001. var show = entity.isShowing && (!defined(showProperty) || showProperty.getValue(time));
  107002. //While we want to show the path, there may not actually be anything to show
  107003. //depending on lead/trail settings. Compute the interval of the path to
  107004. //show and check against actual availability.
  107005. if (show) {
  107006. var leadTime = Property.getValueOrUndefined(pathGraphics._leadTime, time);
  107007. var trailTime = Property.getValueOrUndefined(pathGraphics._trailTime, time);
  107008. var availability = entity._availability;
  107009. var hasAvailability = defined(availability);
  107010. var hasLeadTime = defined(leadTime);
  107011. var hasTrailTime = defined(trailTime);
  107012. //Objects need to have either defined availability or both a lead and trail time in order to
  107013. //draw a path (since we can't draw "infinite" paths.
  107014. show = hasAvailability || (hasLeadTime && hasTrailTime);
  107015. //The final step is to compute the actual start/stop times of the path to show.
  107016. //If current time is outside of the availability interval, there's a chance that
  107017. //we won't have to draw anything anyway.
  107018. if (show) {
  107019. if (hasTrailTime) {
  107020. sampleStart = JulianDate.addSeconds(time, -trailTime, new JulianDate());
  107021. }
  107022. if (hasLeadTime) {
  107023. sampleStop = JulianDate.addSeconds(time, leadTime, new JulianDate());
  107024. }
  107025. if (hasAvailability) {
  107026. var start = availability.start;
  107027. var stop = availability.stop;
  107028. if (!hasTrailTime || JulianDate.greaterThan(start, sampleStart)) {
  107029. sampleStart = start;
  107030. }
  107031. if (!hasLeadTime || JulianDate.lessThan(stop, sampleStop)) {
  107032. sampleStop = stop;
  107033. }
  107034. }
  107035. show = JulianDate.lessThan(sampleStart, sampleStop);
  107036. }
  107037. }
  107038. if (!show) {
  107039. //don't bother creating or updating anything else
  107040. if (defined(polyline)) {
  107041. this._unusedIndexes.push(item.index);
  107042. item.polyline = undefined;
  107043. polyline.show = false;
  107044. item.index = undefined;
  107045. }
  107046. return;
  107047. }
  107048. if (!defined(polyline)) {
  107049. var unusedIndexes = this._unusedIndexes;
  107050. var length = unusedIndexes.length;
  107051. if (length > 0) {
  107052. var index = unusedIndexes.pop();
  107053. polyline = this._polylineCollection.get(index);
  107054. item.index = index;
  107055. } else {
  107056. item.index = this._polylineCollection.length;
  107057. polyline = this._polylineCollection.add();
  107058. }
  107059. polyline.id = entity;
  107060. item.polyline = polyline;
  107061. }
  107062. var resolution = Property.getValueOrDefault(pathGraphics._resolution, time, defaultResolution);
  107063. polyline.show = true;
  107064. polyline.positions = subSample(positionProperty, sampleStart, sampleStop, time, this._referenceFrame, resolution, polyline.positions.slice());
  107065. polyline.material = MaterialProperty.getValue(time, pathGraphics._material, polyline.material);
  107066. polyline.width = Property.getValueOrDefault(pathGraphics._width, time, defaultWidth);
  107067. polyline.distanceDisplayCondition = Property.getValueOrUndefined(pathGraphics._distanceDisplayCondition, time, polyline.distanceDisplayCondition);
  107068. };
  107069. PolylineUpdater.prototype.removeObject = function(item) {
  107070. var polyline = item.polyline;
  107071. if (defined(polyline)) {
  107072. this._unusedIndexes.push(item.index);
  107073. item.polyline = undefined;
  107074. polyline.show = false;
  107075. polyline.id = undefined;
  107076. item.index = undefined;
  107077. }
  107078. };
  107079. PolylineUpdater.prototype.destroy = function() {
  107080. this._scene.primitives.remove(this._polylineCollection);
  107081. return destroyObject(this);
  107082. };
  107083. /**
  107084. * A {@link Visualizer} which maps {@link Entity#path} to a {@link Polyline}.
  107085. * @alias PathVisualizer
  107086. * @constructor
  107087. *
  107088. * @param {Scene} scene The scene the primitives will be rendered in.
  107089. * @param {EntityCollection} entityCollection The entityCollection to visualize.
  107090. */
  107091. function PathVisualizer(scene, entityCollection) {
  107092. if (!defined(scene)) {
  107093. throw new DeveloperError('scene is required.');
  107094. }
  107095. if (!defined(entityCollection)) {
  107096. throw new DeveloperError('entityCollection is required.');
  107097. }
  107098. entityCollection.collectionChanged.addEventListener(PathVisualizer.prototype._onCollectionChanged, this);
  107099. this._scene = scene;
  107100. this._updaters = {};
  107101. this._entityCollection = entityCollection;
  107102. this._items = new AssociativeArray();
  107103. this._onCollectionChanged(entityCollection, entityCollection.values, [], []);
  107104. }
  107105. /**
  107106. * Updates all of the primitives created by this visualizer to match their
  107107. * Entity counterpart at the given time.
  107108. *
  107109. * @param {JulianDate} time The time to update to.
  107110. * @returns {Boolean} This function always returns true.
  107111. */
  107112. PathVisualizer.prototype.update = function(time) {
  107113. if (!defined(time)) {
  107114. throw new DeveloperError('time is required.');
  107115. }
  107116. var updaters = this._updaters;
  107117. for ( var key in updaters) {
  107118. if (updaters.hasOwnProperty(key)) {
  107119. updaters[key].update(time);
  107120. }
  107121. }
  107122. var items = this._items.values;
  107123. for (var i = 0, len = items.length; i < len; i++) {
  107124. var item = items[i];
  107125. var entity = item.entity;
  107126. var positionProperty = entity._position;
  107127. var lastUpdater = item.updater;
  107128. var frameToVisualize = ReferenceFrame.FIXED;
  107129. if (this._scene.mode === SceneMode.SCENE3D) {
  107130. frameToVisualize = positionProperty.referenceFrame;
  107131. }
  107132. var currentUpdater = this._updaters[frameToVisualize];
  107133. if ((lastUpdater === currentUpdater) && (defined(currentUpdater))) {
  107134. currentUpdater.updateObject(time, item);
  107135. continue;
  107136. }
  107137. if (defined(lastUpdater)) {
  107138. lastUpdater.removeObject(item);
  107139. }
  107140. if (!defined(currentUpdater)) {
  107141. currentUpdater = new PolylineUpdater(this._scene, frameToVisualize);
  107142. currentUpdater.update(time);
  107143. this._updaters[frameToVisualize] = currentUpdater;
  107144. }
  107145. item.updater = currentUpdater;
  107146. if (defined(currentUpdater)) {
  107147. currentUpdater.updateObject(time, item);
  107148. }
  107149. }
  107150. return true;
  107151. };
  107152. /**
  107153. * Returns true if this object was destroyed; otherwise, false.
  107154. *
  107155. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  107156. */
  107157. PathVisualizer.prototype.isDestroyed = function() {
  107158. return false;
  107159. };
  107160. /**
  107161. * Removes and destroys all primitives created by this instance.
  107162. */
  107163. PathVisualizer.prototype.destroy = function() {
  107164. this._entityCollection.collectionChanged.removeEventListener(PathVisualizer.prototype._onCollectionChanged, this);
  107165. var updaters = this._updaters;
  107166. for ( var key in updaters) {
  107167. if (updaters.hasOwnProperty(key)) {
  107168. updaters[key].destroy();
  107169. }
  107170. }
  107171. return destroyObject(this);
  107172. };
  107173. PathVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed, changed) {
  107174. var i;
  107175. var entity;
  107176. var item;
  107177. var items = this._items;
  107178. for (i = added.length - 1; i > -1; i--) {
  107179. entity = added[i];
  107180. if (defined(entity._path) && defined(entity._position)) {
  107181. items.set(entity.id, new EntityData(entity));
  107182. }
  107183. }
  107184. for (i = changed.length - 1; i > -1; i--) {
  107185. entity = changed[i];
  107186. if (defined(entity._path) && defined(entity._position)) {
  107187. if (!items.contains(entity.id)) {
  107188. items.set(entity.id, new EntityData(entity));
  107189. }
  107190. } else {
  107191. item = items.get(entity.id);
  107192. if (defined(item)) {
  107193. item.updater.removeObject(item);
  107194. items.remove(entity.id);
  107195. }
  107196. }
  107197. }
  107198. for (i = removed.length - 1; i > -1; i--) {
  107199. entity = removed[i];
  107200. item = items.get(entity.id);
  107201. if (defined(item)) {
  107202. if (defined(item.updater)) {
  107203. item.updater.removeObject(item);
  107204. }
  107205. items.remove(entity.id);
  107206. }
  107207. }
  107208. };
  107209. //for testing
  107210. PathVisualizer._subSample = subSample;
  107211. return PathVisualizer;
  107212. });
  107213. /*global define*/
  107214. define('DataSources/PointVisualizer',[
  107215. '../Core/AssociativeArray',
  107216. '../Core/Cartesian3',
  107217. '../Core/Color',
  107218. '../Core/defined',
  107219. '../Core/destroyObject',
  107220. '../Core/DeveloperError',
  107221. '../Core/DistanceDisplayCondition',
  107222. '../Core/NearFarScalar',
  107223. '../Scene/HeightReference',
  107224. './BoundingSphereState',
  107225. './Property'
  107226. ], function(
  107227. AssociativeArray,
  107228. Cartesian3,
  107229. Color,
  107230. defined,
  107231. destroyObject,
  107232. DeveloperError,
  107233. DistanceDisplayCondition,
  107234. NearFarScalar,
  107235. HeightReference,
  107236. BoundingSphereState,
  107237. Property) {
  107238. 'use strict';
  107239. var defaultColor = Color.WHITE;
  107240. var defaultOutlineColor = Color.BLACK;
  107241. var defaultOutlineWidth = 0.0;
  107242. var defaultPixelSize = 1.0;
  107243. var color = new Color();
  107244. var position = new Cartesian3();
  107245. var outlineColor = new Color();
  107246. var scaleByDistance = new NearFarScalar();
  107247. var translucencyByDistance = new NearFarScalar();
  107248. var distanceDisplayCondition = new DistanceDisplayCondition();
  107249. function EntityData(entity) {
  107250. this.entity = entity;
  107251. this.pointPrimitive = undefined;
  107252. this.billboard = undefined;
  107253. this.color = undefined;
  107254. this.outlineColor = undefined;
  107255. this.pixelSize = undefined;
  107256. this.outlineWidth = undefined;
  107257. }
  107258. /**
  107259. * A {@link Visualizer} which maps {@link Entity#point} to a {@link PointPrimitive}.
  107260. * @alias PointVisualizer
  107261. * @constructor
  107262. *
  107263. * @param {EntityCluster} entityCluster The entity cluster to manage the collection of billboards and optionally cluster with other entities.
  107264. * @param {EntityCollection} entityCollection The entityCollection to visualize.
  107265. */
  107266. function PointVisualizer(entityCluster, entityCollection) {
  107267. if (!defined(entityCluster)) {
  107268. throw new DeveloperError('entityCluster is required.');
  107269. }
  107270. if (!defined(entityCollection)) {
  107271. throw new DeveloperError('entityCollection is required.');
  107272. }
  107273. entityCollection.collectionChanged.addEventListener(PointVisualizer.prototype._onCollectionChanged, this);
  107274. this._cluster = entityCluster;
  107275. this._entityCollection = entityCollection;
  107276. this._items = new AssociativeArray();
  107277. this._onCollectionChanged(entityCollection, entityCollection.values, [], []);
  107278. }
  107279. /**
  107280. * Updates the primitives created by this visualizer to match their
  107281. * Entity counterpart at the given time.
  107282. *
  107283. * @param {JulianDate} time The time to update to.
  107284. * @returns {Boolean} This function always returns true.
  107285. */
  107286. PointVisualizer.prototype.update = function(time) {
  107287. if (!defined(time)) {
  107288. throw new DeveloperError('time is required.');
  107289. }
  107290. var items = this._items.values;
  107291. var cluster = this._cluster;
  107292. for (var i = 0, len = items.length; i < len; i++) {
  107293. var item = items[i];
  107294. var entity = item.entity;
  107295. var pointGraphics = entity._point;
  107296. var pointPrimitive = item.pointPrimitive;
  107297. var billboard = item.billboard;
  107298. var heightReference = Property.getValueOrDefault(pointGraphics._heightReference, time, HeightReference.NONE);
  107299. var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(pointGraphics._show, time, true);
  107300. if (show) {
  107301. position = Property.getValueOrUndefined(entity._position, time, position);
  107302. show = defined(position);
  107303. }
  107304. if (!show) {
  107305. returnPrimitive(item, entity, cluster);
  107306. continue;
  107307. }
  107308. if (!Property.isConstant(entity._position)) {
  107309. cluster._clusterDirty = true;
  107310. }
  107311. var needsRedraw = false;
  107312. if ((heightReference !== HeightReference.NONE) && !defined(billboard)) {
  107313. if (defined(pointPrimitive)) {
  107314. returnPrimitive(item, entity, cluster);
  107315. pointPrimitive = undefined;
  107316. }
  107317. billboard = cluster.getBillboard(entity);
  107318. billboard.id = entity;
  107319. billboard.image = undefined;
  107320. item.billboard = billboard;
  107321. needsRedraw = true;
  107322. } else if ((heightReference === HeightReference.NONE) && !defined(pointPrimitive)) {
  107323. if (defined(billboard)) {
  107324. returnPrimitive(item, entity, cluster);
  107325. billboard = undefined;
  107326. }
  107327. pointPrimitive = cluster.getPoint(entity);
  107328. pointPrimitive.id = entity;
  107329. item.pointPrimitive = pointPrimitive;
  107330. }
  107331. if (defined(pointPrimitive)) {
  107332. pointPrimitive.show = true;
  107333. pointPrimitive.position = position;
  107334. pointPrimitive.scaleByDistance = Property.getValueOrUndefined(pointGraphics._scaleByDistance, time, scaleByDistance);
  107335. pointPrimitive.translucencyByDistance = Property.getValueOrUndefined(pointGraphics._translucencyByDistance, time, translucencyByDistance);
  107336. pointPrimitive.color = Property.getValueOrDefault(pointGraphics._color, time, defaultColor, color);
  107337. pointPrimitive.outlineColor = Property.getValueOrDefault(pointGraphics._outlineColor, time, defaultOutlineColor, outlineColor);
  107338. pointPrimitive.outlineWidth = Property.getValueOrDefault(pointGraphics._outlineWidth, time, defaultOutlineWidth);
  107339. pointPrimitive.pixelSize = Property.getValueOrDefault(pointGraphics._pixelSize, time, defaultPixelSize);
  107340. pointPrimitive.distanceDisplayCondition = Property.getValueOrUndefined(pointGraphics._distanceDisplayCondition, time, distanceDisplayCondition);
  107341. } else { // billboard
  107342. billboard.show = true;
  107343. billboard.position = position;
  107344. billboard.scaleByDistance = Property.getValueOrUndefined(pointGraphics._scaleByDistance, time, scaleByDistance);
  107345. billboard.translucencyByDistance = Property.getValueOrUndefined(pointGraphics._translucencyByDistance, time, translucencyByDistance);
  107346. billboard.distanceDisplayCondition = Property.getValueOrUndefined(pointGraphics._distanceDisplayCondition, time, distanceDisplayCondition);
  107347. billboard.heightReference = heightReference;
  107348. var newColor = Property.getValueOrDefault(pointGraphics._color, time, defaultColor, color);
  107349. var newOutlineColor = Property.getValueOrDefault(pointGraphics._outlineColor, time, defaultOutlineColor, outlineColor);
  107350. var newOutlineWidth = Math.round(Property.getValueOrDefault(pointGraphics._outlineWidth, time, defaultOutlineWidth));
  107351. var newPixelSize = Math.max(1, Math.round(Property.getValueOrDefault(pointGraphics._pixelSize, time, defaultPixelSize)));
  107352. if (newOutlineWidth > 0) {
  107353. billboard.scale = 1.0;
  107354. needsRedraw = needsRedraw || //
  107355. newOutlineWidth !== item.outlineWidth || //
  107356. newPixelSize !== item.pixelSize || //
  107357. !Color.equals(newColor, item.color) || //
  107358. !Color.equals(newOutlineColor, item.outlineColor);
  107359. } else {
  107360. billboard.scale = newPixelSize / 50.0;
  107361. newPixelSize = 50.0;
  107362. needsRedraw = needsRedraw || //
  107363. newOutlineWidth !== item.outlineWidth || //
  107364. !Color.equals(newColor, item.color) || //
  107365. !Color.equals(newOutlineColor, item.outlineColor);
  107366. }
  107367. if (needsRedraw) {
  107368. item.color = Color.clone(newColor, item.color);
  107369. item.outlineColor = Color.clone(newOutlineColor, item.outlineColor);
  107370. item.pixelSize = newPixelSize;
  107371. item.outlineWidth = newOutlineWidth;
  107372. var centerAlpha = newColor.alpha;
  107373. var cssColor = newColor.toCssColorString();
  107374. var cssOutlineColor = newOutlineColor.toCssColorString();
  107375. var textureId = JSON.stringify([cssColor, newPixelSize, cssOutlineColor, newOutlineWidth]);
  107376. billboard.setImage(textureId, createCallback(centerAlpha, cssColor, cssOutlineColor, newOutlineWidth, newPixelSize));
  107377. }
  107378. }
  107379. }
  107380. return true;
  107381. };
  107382. /**
  107383. * Computes a bounding sphere which encloses the visualization produced for the specified entity.
  107384. * The bounding sphere is in the fixed frame of the scene's globe.
  107385. *
  107386. * @param {Entity} entity The entity whose bounding sphere to compute.
  107387. * @param {BoundingSphere} result The bounding sphere onto which to store the result.
  107388. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere,
  107389. * BoundingSphereState.PENDING if the result is still being computed, or
  107390. * BoundingSphereState.FAILED if the entity has no visualization in the current scene.
  107391. * @private
  107392. */
  107393. PointVisualizer.prototype.getBoundingSphere = function(entity, result) {
  107394. if (!defined(entity)) {
  107395. throw new DeveloperError('entity is required.');
  107396. }
  107397. if (!defined(result)) {
  107398. throw new DeveloperError('result is required.');
  107399. }
  107400. var item = this._items.get(entity.id);
  107401. if (!defined(item) || !(defined(item.pointPrimitive) || defined(item.billboard))) {
  107402. return BoundingSphereState.FAILED;
  107403. }
  107404. if (defined(item.pointPrimitive)) {
  107405. result.center = Cartesian3.clone(item.pointPrimitive.position, result.center);
  107406. } else {
  107407. var billboard = item.billboard;
  107408. if (!defined(billboard._clampedPosition)) {
  107409. return BoundingSphereState.PENDING;
  107410. }
  107411. result.center = Cartesian3.clone(billboard._clampedPosition, result.center);
  107412. }
  107413. result.radius = 0;
  107414. return BoundingSphereState.DONE;
  107415. };
  107416. /**
  107417. * Returns true if this object was destroyed; otherwise, false.
  107418. *
  107419. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  107420. */
  107421. PointVisualizer.prototype.isDestroyed = function() {
  107422. return false;
  107423. };
  107424. /**
  107425. * Removes and destroys all primitives created by this instance.
  107426. */
  107427. PointVisualizer.prototype.destroy = function() {
  107428. this._entityCollection.collectionChanged.removeEventListener(PointVisualizer.prototype._onCollectionChanged, this);
  107429. var entities = this._entityCollection.values;
  107430. for (var i = 0; i < entities.length; i++) {
  107431. this._cluster.removePoint(entities[i]);
  107432. }
  107433. return destroyObject(this);
  107434. };
  107435. PointVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed, changed) {
  107436. var i;
  107437. var entity;
  107438. var items = this._items;
  107439. var cluster = this._cluster;
  107440. for (i = added.length - 1; i > -1; i--) {
  107441. entity = added[i];
  107442. if (defined(entity._point) && defined(entity._position)) {
  107443. items.set(entity.id, new EntityData(entity));
  107444. }
  107445. }
  107446. for (i = changed.length - 1; i > -1; i--) {
  107447. entity = changed[i];
  107448. if (defined(entity._point) && defined(entity._position)) {
  107449. if (!items.contains(entity.id)) {
  107450. items.set(entity.id, new EntityData(entity));
  107451. }
  107452. } else {
  107453. returnPrimitive(items.get(entity.id), entity, cluster);
  107454. items.remove(entity.id);
  107455. }
  107456. }
  107457. for (i = removed.length - 1; i > -1; i--) {
  107458. entity = removed[i];
  107459. returnPrimitive(items.get(entity.id), entity, cluster);
  107460. items.remove(entity.id);
  107461. }
  107462. };
  107463. function returnPrimitive(item, entity, cluster) {
  107464. if (defined(item)) {
  107465. var pointPrimitive = item.pointPrimitive;
  107466. if (defined(pointPrimitive)) {
  107467. item.pointPrimitive = undefined;
  107468. cluster.removePoint(entity);
  107469. return;
  107470. }
  107471. var billboard = item.billboard;
  107472. if (defined(billboard)) {
  107473. item.billboard = undefined;
  107474. cluster.removeBillboard(entity);
  107475. }
  107476. }
  107477. }
  107478. function createCallback(centerAlpha, cssColor, cssOutlineColor, cssOutlineWidth, newPixelSize) {
  107479. return function(id) {
  107480. var canvas = document.createElement('canvas');
  107481. var length = newPixelSize + (2 * cssOutlineWidth);
  107482. canvas.height = canvas.width = length;
  107483. var context2D = canvas.getContext('2d');
  107484. context2D.clearRect(0, 0, length, length);
  107485. if (cssOutlineWidth !== 0) {
  107486. context2D.beginPath();
  107487. context2D.arc(length / 2, length / 2, length / 2, 0, 2 * Math.PI, true);
  107488. context2D.closePath();
  107489. context2D.fillStyle = cssOutlineColor;
  107490. context2D.fill();
  107491. // Punch a hole in the center if needed.
  107492. if (centerAlpha < 1.0) {
  107493. context2D.save();
  107494. context2D.globalCompositeOperation = 'destination-out';
  107495. context2D.beginPath();
  107496. context2D.arc(length / 2, length / 2, newPixelSize / 2, 0, 2 * Math.PI, true);
  107497. context2D.closePath();
  107498. context2D.fillStyle = 'black';
  107499. context2D.fill();
  107500. context2D.restore();
  107501. }
  107502. }
  107503. context2D.beginPath();
  107504. context2D.arc(length / 2, length / 2, newPixelSize / 2, 0, 2 * Math.PI, true);
  107505. context2D.closePath();
  107506. context2D.fillStyle = cssColor;
  107507. context2D.fill();
  107508. return canvas;
  107509. };
  107510. }
  107511. return PointVisualizer;
  107512. });
  107513. /*global define*/
  107514. define('DataSources/PolygonGeometryUpdater',[
  107515. '../Core/Color',
  107516. '../Core/ColorGeometryInstanceAttribute',
  107517. '../Core/defaultValue',
  107518. '../Core/defined',
  107519. '../Core/defineProperties',
  107520. '../Core/destroyObject',
  107521. '../Core/DeveloperError',
  107522. '../Core/DistanceDisplayCondition',
  107523. '../Core/DistanceDisplayConditionGeometryInstanceAttribute',
  107524. '../Core/Event',
  107525. '../Core/GeometryInstance',
  107526. '../Core/isArray',
  107527. '../Core/Iso8601',
  107528. '../Core/oneTimeWarning',
  107529. '../Core/PolygonGeometry',
  107530. '../Core/PolygonHierarchy',
  107531. '../Core/PolygonOutlineGeometry',
  107532. '../Core/ShowGeometryInstanceAttribute',
  107533. '../Scene/GroundPrimitive',
  107534. '../Scene/MaterialAppearance',
  107535. '../Scene/PerInstanceColorAppearance',
  107536. '../Scene/Primitive',
  107537. '../Scene/ShadowMode',
  107538. './ColorMaterialProperty',
  107539. './ConstantProperty',
  107540. './dynamicGeometryGetBoundingSphere',
  107541. './MaterialProperty',
  107542. './Property'
  107543. ], function(
  107544. Color,
  107545. ColorGeometryInstanceAttribute,
  107546. defaultValue,
  107547. defined,
  107548. defineProperties,
  107549. destroyObject,
  107550. DeveloperError,
  107551. DistanceDisplayCondition,
  107552. DistanceDisplayConditionGeometryInstanceAttribute,
  107553. Event,
  107554. GeometryInstance,
  107555. isArray,
  107556. Iso8601,
  107557. oneTimeWarning,
  107558. PolygonGeometry,
  107559. PolygonHierarchy,
  107560. PolygonOutlineGeometry,
  107561. ShowGeometryInstanceAttribute,
  107562. GroundPrimitive,
  107563. MaterialAppearance,
  107564. PerInstanceColorAppearance,
  107565. Primitive,
  107566. ShadowMode,
  107567. ColorMaterialProperty,
  107568. ConstantProperty,
  107569. dynamicGeometryGetBoundingSphere,
  107570. MaterialProperty,
  107571. Property) {
  107572. 'use strict';
  107573. var defaultMaterial = new ColorMaterialProperty(Color.WHITE);
  107574. var defaultShow = new ConstantProperty(true);
  107575. var defaultFill = new ConstantProperty(true);
  107576. var defaultOutline = new ConstantProperty(false);
  107577. var defaultOutlineColor = new ConstantProperty(Color.BLACK);
  107578. var defaultShadows = new ConstantProperty(ShadowMode.DISABLED);
  107579. var defaultDistanceDisplayCondition = new ConstantProperty(new DistanceDisplayCondition());
  107580. var scratchColor = new Color();
  107581. function GeometryOptions(entity) {
  107582. this.id = entity;
  107583. this.vertexFormat = undefined;
  107584. this.polygonHierarchy = undefined;
  107585. this.perPositionHeight = undefined;
  107586. this.closeTop = undefined;
  107587. this.closeBottom = undefined;
  107588. this.height = undefined;
  107589. this.extrudedHeight = undefined;
  107590. this.granularity = undefined;
  107591. this.stRotation = undefined;
  107592. }
  107593. /**
  107594. * A {@link GeometryUpdater} for polygons.
  107595. * Clients do not normally create this class directly, but instead rely on {@link DataSourceDisplay}.
  107596. * @alias PolygonGeometryUpdater
  107597. * @constructor
  107598. *
  107599. * @param {Entity} entity The entity containing the geometry to be visualized.
  107600. * @param {Scene} scene The scene where visualization is taking place.
  107601. */
  107602. function PolygonGeometryUpdater(entity, scene) {
  107603. if (!defined(entity)) {
  107604. throw new DeveloperError('entity is required');
  107605. }
  107606. if (!defined(scene)) {
  107607. throw new DeveloperError('scene is required');
  107608. }
  107609. this._entity = entity;
  107610. this._scene = scene;
  107611. this._entitySubscription = entity.definitionChanged.addEventListener(PolygonGeometryUpdater.prototype._onEntityPropertyChanged, this);
  107612. this._fillEnabled = false;
  107613. this._isClosed = false;
  107614. this._dynamic = false;
  107615. this._outlineEnabled = false;
  107616. this._geometryChanged = new Event();
  107617. this._showProperty = undefined;
  107618. this._materialProperty = undefined;
  107619. this._hasConstantOutline = true;
  107620. this._showOutlineProperty = undefined;
  107621. this._outlineColorProperty = undefined;
  107622. this._outlineWidth = 1.0;
  107623. this._shadowsProperty = undefined;
  107624. this._distanceDisplayConditionProperty = undefined;
  107625. this._onTerrain = false;
  107626. this._options = new GeometryOptions(entity);
  107627. this._onEntityPropertyChanged(entity, 'polygon', entity.polygon, undefined);
  107628. }
  107629. defineProperties(PolygonGeometryUpdater, {
  107630. /**
  107631. * Gets the type of Appearance to use for simple color-based geometry.
  107632. * @memberof PolygonGeometryUpdater
  107633. * @type {Appearance}
  107634. */
  107635. perInstanceColorAppearanceType : {
  107636. value : PerInstanceColorAppearance
  107637. },
  107638. /**
  107639. * Gets the type of Appearance to use for material-based geometry.
  107640. * @memberof PolygonGeometryUpdater
  107641. * @type {Appearance}
  107642. */
  107643. materialAppearanceType : {
  107644. value : MaterialAppearance
  107645. }
  107646. });
  107647. defineProperties(PolygonGeometryUpdater.prototype, {
  107648. /**
  107649. * Gets the entity associated with this geometry.
  107650. * @memberof PolygonGeometryUpdater.prototype
  107651. *
  107652. * @type {Entity}
  107653. * @readonly
  107654. */
  107655. entity : {
  107656. get : function() {
  107657. return this._entity;
  107658. }
  107659. },
  107660. /**
  107661. * Gets a value indicating if the geometry has a fill component.
  107662. * @memberof PolygonGeometryUpdater.prototype
  107663. *
  107664. * @type {Boolean}
  107665. * @readonly
  107666. */
  107667. fillEnabled : {
  107668. get : function() {
  107669. return this._fillEnabled;
  107670. }
  107671. },
  107672. /**
  107673. * Gets a value indicating if fill visibility varies with simulation time.
  107674. * @memberof PolygonGeometryUpdater.prototype
  107675. *
  107676. * @type {Boolean}
  107677. * @readonly
  107678. */
  107679. hasConstantFill : {
  107680. get : function() {
  107681. return !this._fillEnabled ||
  107682. (!defined(this._entity.availability) &&
  107683. Property.isConstant(this._showProperty) &&
  107684. Property.isConstant(this._fillProperty));
  107685. }
  107686. },
  107687. /**
  107688. * Gets the material property used to fill the geometry.
  107689. * @memberof PolygonGeometryUpdater.prototype
  107690. *
  107691. * @type {MaterialProperty}
  107692. * @readonly
  107693. */
  107694. fillMaterialProperty : {
  107695. get : function() {
  107696. return this._materialProperty;
  107697. }
  107698. },
  107699. /**
  107700. * Gets a value indicating if the geometry has an outline component.
  107701. * @memberof PolygonGeometryUpdater.prototype
  107702. *
  107703. * @type {Boolean}
  107704. * @readonly
  107705. */
  107706. outlineEnabled : {
  107707. get : function() {
  107708. return this._outlineEnabled;
  107709. }
  107710. },
  107711. /**
  107712. * Gets a value indicating if the geometry has an outline component.
  107713. * @memberof PolygonGeometryUpdater.prototype
  107714. *
  107715. * @type {Boolean}
  107716. * @readonly
  107717. */
  107718. hasConstantOutline : {
  107719. get : function() {
  107720. return !this._outlineEnabled ||
  107721. (!defined(this._entity.availability) &&
  107722. Property.isConstant(this._showProperty) &&
  107723. Property.isConstant(this._showOutlineProperty));
  107724. }
  107725. },
  107726. /**
  107727. * Gets the {@link Color} property for the geometry outline.
  107728. * @memberof PolygonGeometryUpdater.prototype
  107729. *
  107730. * @type {Property}
  107731. * @readonly
  107732. */
  107733. outlineColorProperty : {
  107734. get : function() {
  107735. return this._outlineColorProperty;
  107736. }
  107737. },
  107738. /**
  107739. * Gets the constant with of the geometry outline, in pixels.
  107740. * This value is only valid if isDynamic is false.
  107741. * @memberof PolygonGeometryUpdater.prototype
  107742. *
  107743. * @type {Number}
  107744. * @readonly
  107745. */
  107746. outlineWidth : {
  107747. get : function() {
  107748. return this._outlineWidth;
  107749. }
  107750. },
  107751. /**
  107752. * Gets the property specifying whether the geometry
  107753. * casts or receives shadows from each light source.
  107754. * @memberof PolygonGeometryUpdater.prototype
  107755. *
  107756. * @type {Property}
  107757. * @readonly
  107758. */
  107759. shadowsProperty : {
  107760. get : function() {
  107761. return this._shadowsProperty;
  107762. }
  107763. },
  107764. /**
  107765. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this geometry will be displayed.
  107766. * @memberof PolygonGeometryUpdater.prototype
  107767. *
  107768. * @type {Property}
  107769. * @readonly
  107770. */
  107771. distanceDisplayConditionProperty : {
  107772. get : function() {
  107773. return this._distanceDisplayConditionProperty;
  107774. }
  107775. },
  107776. /**
  107777. * Gets a value indicating if the geometry is time-varying.
  107778. * If true, all visualization is delegated to the {@link DynamicGeometryUpdater}
  107779. * returned by GeometryUpdater#createDynamicUpdater.
  107780. * @memberof PolygonGeometryUpdater.prototype
  107781. *
  107782. * @type {Boolean}
  107783. * @readonly
  107784. */
  107785. isDynamic : {
  107786. get : function() {
  107787. return this._dynamic;
  107788. }
  107789. },
  107790. /**
  107791. * Gets a value indicating if the geometry is closed.
  107792. * This property is only valid for static geometry.
  107793. * @memberof PolygonGeometryUpdater.prototype
  107794. *
  107795. * @type {Boolean}
  107796. * @readonly
  107797. */
  107798. isClosed : {
  107799. get : function() {
  107800. return this._isClosed;
  107801. }
  107802. },
  107803. /**
  107804. * Gets a value indicating if the geometry should be drawn on terrain.
  107805. * @memberof PolygonGeometryUpdater.prototype
  107806. *
  107807. * @type {Boolean}
  107808. * @readonly
  107809. */
  107810. onTerrain : {
  107811. get : function() {
  107812. return this._onTerrain;
  107813. }
  107814. },
  107815. /**
  107816. * Gets an event that is raised whenever the public properties
  107817. * of this updater change.
  107818. * @memberof PolygonGeometryUpdater.prototype
  107819. *
  107820. * @type {Boolean}
  107821. * @readonly
  107822. */
  107823. geometryChanged : {
  107824. get : function() {
  107825. return this._geometryChanged;
  107826. }
  107827. }
  107828. });
  107829. /**
  107830. * Checks if the geometry is outlined at the provided time.
  107831. *
  107832. * @param {JulianDate} time The time for which to retrieve visibility.
  107833. * @returns {Boolean} true if geometry is outlined at the provided time, false otherwise.
  107834. */
  107835. PolygonGeometryUpdater.prototype.isOutlineVisible = function(time) {
  107836. var entity = this._entity;
  107837. return this._outlineEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time);
  107838. };
  107839. /**
  107840. * Checks if the geometry is filled at the provided time.
  107841. *
  107842. * @param {JulianDate} time The time for which to retrieve visibility.
  107843. * @returns {Boolean} true if geometry is filled at the provided time, false otherwise.
  107844. */
  107845. PolygonGeometryUpdater.prototype.isFilled = function(time) {
  107846. var entity = this._entity;
  107847. return this._fillEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._fillProperty.getValue(time);
  107848. };
  107849. /**
  107850. * Creates the geometry instance which represents the fill of the geometry.
  107851. *
  107852. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  107853. * @returns {GeometryInstance} The geometry instance representing the filled portion of the geometry.
  107854. *
  107855. * @exception {DeveloperError} This instance does not represent a filled geometry.
  107856. */
  107857. PolygonGeometryUpdater.prototype.createFillGeometryInstance = function(time) {
  107858. if (!defined(time)) {
  107859. throw new DeveloperError('time is required.');
  107860. }
  107861. if (!this._fillEnabled) {
  107862. throw new DeveloperError('This instance does not represent a filled geometry.');
  107863. }
  107864. var entity = this._entity;
  107865. var isAvailable = entity.isAvailable(time);
  107866. var attributes;
  107867. var color;
  107868. var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time));
  107869. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  107870. var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
  107871. if (this._materialProperty instanceof ColorMaterialProperty) {
  107872. var currentColor = Color.WHITE;
  107873. if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) {
  107874. currentColor = this._materialProperty.color.getValue(time);
  107875. }
  107876. color = ColorGeometryInstanceAttribute.fromColor(currentColor);
  107877. attributes = {
  107878. show : show,
  107879. distanceDisplayCondition : distanceDisplayConditionAttribute,
  107880. color : color
  107881. };
  107882. } else {
  107883. attributes = {
  107884. show : show,
  107885. distanceDisplayCondition : distanceDisplayConditionAttribute
  107886. };
  107887. }
  107888. return new GeometryInstance({
  107889. id : entity,
  107890. geometry : new PolygonGeometry(this._options),
  107891. attributes : attributes
  107892. });
  107893. };
  107894. /**
  107895. * Creates the geometry instance which represents the outline of the geometry.
  107896. *
  107897. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  107898. * @returns {GeometryInstance} The geometry instance representing the outline portion of the geometry.
  107899. *
  107900. * @exception {DeveloperError} This instance does not represent an outlined geometry.
  107901. */
  107902. PolygonGeometryUpdater.prototype.createOutlineGeometryInstance = function(time) {
  107903. if (!defined(time)) {
  107904. throw new DeveloperError('time is required.');
  107905. }
  107906. if (!this._outlineEnabled) {
  107907. throw new DeveloperError('This instance does not represent an outlined geometry.');
  107908. }
  107909. var entity = this._entity;
  107910. var isAvailable = entity.isAvailable(time);
  107911. var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK);
  107912. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  107913. return new GeometryInstance({
  107914. id : entity,
  107915. geometry : new PolygonOutlineGeometry(this._options),
  107916. attributes : {
  107917. show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
  107918. color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
  107919. distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition)
  107920. }
  107921. });
  107922. };
  107923. /**
  107924. * Returns true if this object was destroyed; otherwise, false.
  107925. *
  107926. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  107927. */
  107928. PolygonGeometryUpdater.prototype.isDestroyed = function() {
  107929. return false;
  107930. };
  107931. /**
  107932. * Destroys and resources used by the object. Once an object is destroyed, it should not be used.
  107933. *
  107934. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  107935. */
  107936. PolygonGeometryUpdater.prototype.destroy = function() {
  107937. this._entitySubscription();
  107938. destroyObject(this);
  107939. };
  107940. PolygonGeometryUpdater.prototype._onEntityPropertyChanged = function(entity, propertyName, newValue, oldValue) {
  107941. if (!(propertyName === 'availability' || propertyName === 'polygon')) {
  107942. return;
  107943. }
  107944. var polygon = this._entity.polygon;
  107945. if (!defined(polygon)) {
  107946. if (this._fillEnabled || this._outlineEnabled) {
  107947. this._fillEnabled = false;
  107948. this._outlineEnabled = false;
  107949. this._geometryChanged.raiseEvent(this);
  107950. }
  107951. return;
  107952. }
  107953. var fillProperty = polygon.fill;
  107954. var fillEnabled = defined(fillProperty) && fillProperty.isConstant ? fillProperty.getValue(Iso8601.MINIMUM_VALUE) : true;
  107955. var perPositionHeightProperty = polygon.perPositionHeight;
  107956. var perPositionHeightEnabled = defined(perPositionHeightProperty) && (perPositionHeightProperty.isConstant ? perPositionHeightProperty.getValue(Iso8601.MINIMUM_VALUE) : true);
  107957. var outlineProperty = polygon.outline;
  107958. var outlineEnabled = defined(outlineProperty);
  107959. if (outlineEnabled && outlineProperty.isConstant) {
  107960. outlineEnabled = outlineProperty.getValue(Iso8601.MINIMUM_VALUE);
  107961. }
  107962. if (!fillEnabled && !outlineEnabled) {
  107963. if (this._fillEnabled || this._outlineEnabled) {
  107964. this._fillEnabled = false;
  107965. this._outlineEnabled = false;
  107966. this._geometryChanged.raiseEvent(this);
  107967. }
  107968. return;
  107969. }
  107970. var hierarchy = polygon.hierarchy;
  107971. var show = polygon.show;
  107972. if ((defined(show) && show.isConstant && !show.getValue(Iso8601.MINIMUM_VALUE)) || //
  107973. (!defined(hierarchy))) {
  107974. if (this._fillEnabled || this._outlineEnabled) {
  107975. this._fillEnabled = false;
  107976. this._outlineEnabled = false;
  107977. this._geometryChanged.raiseEvent(this);
  107978. }
  107979. return;
  107980. }
  107981. var material = defaultValue(polygon.material, defaultMaterial);
  107982. var isColorMaterial = material instanceof ColorMaterialProperty;
  107983. this._materialProperty = material;
  107984. this._fillProperty = defaultValue(fillProperty, defaultFill);
  107985. this._showProperty = defaultValue(show, defaultShow);
  107986. this._showOutlineProperty = defaultValue(polygon.outline, defaultOutline);
  107987. this._outlineColorProperty = outlineEnabled ? defaultValue(polygon.outlineColor, defaultOutlineColor) : undefined;
  107988. this._shadowsProperty = defaultValue(polygon.shadows, defaultShadows);
  107989. this._distanceDisplayConditionProperty = defaultValue(polygon.distanceDisplayCondition, defaultDistanceDisplayCondition);
  107990. var height = polygon.height;
  107991. var extrudedHeight = polygon.extrudedHeight;
  107992. var granularity = polygon.granularity;
  107993. var stRotation = polygon.stRotation;
  107994. var outlineWidth = polygon.outlineWidth;
  107995. var onTerrain = fillEnabled && !defined(height) && !defined(extrudedHeight) && isColorMaterial &&
  107996. !perPositionHeightEnabled && GroundPrimitive.isSupported(this._scene);
  107997. if (outlineEnabled && onTerrain) {
  107998. oneTimeWarning(oneTimeWarning.geometryOutlines);
  107999. outlineEnabled = false;
  108000. }
  108001. var perPositionHeight = polygon.perPositionHeight;
  108002. var closeTop = polygon.closeTop;
  108003. var closeBottom = polygon.closeBottom;
  108004. this._fillEnabled = fillEnabled;
  108005. this._onTerrain = onTerrain;
  108006. this._outlineEnabled = outlineEnabled;
  108007. if (!hierarchy.isConstant || //
  108008. !Property.isConstant(height) || //
  108009. !Property.isConstant(extrudedHeight) || //
  108010. !Property.isConstant(granularity) || //
  108011. !Property.isConstant(stRotation) || //
  108012. !Property.isConstant(outlineWidth) || //
  108013. !Property.isConstant(perPositionHeightProperty) || //
  108014. !Property.isConstant(perPositionHeight) || //
  108015. !Property.isConstant(closeTop) || //
  108016. !Property.isConstant(closeBottom) || //
  108017. (onTerrain && !Property.isConstant(material))) {
  108018. if (!this._dynamic) {
  108019. this._dynamic = true;
  108020. this._geometryChanged.raiseEvent(this);
  108021. }
  108022. } else {
  108023. var options = this._options;
  108024. options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat;
  108025. var hierarchyValue = hierarchy.getValue(Iso8601.MINIMUM_VALUE);
  108026. if (isArray(hierarchyValue)) {
  108027. hierarchyValue = new PolygonHierarchy(hierarchyValue);
  108028. }
  108029. var heightValue = Property.getValueOrUndefined(height, Iso8601.MINIMUM_VALUE);
  108030. var closeTopValue = Property.getValueOrDefault(closeTop, Iso8601.MINIMUM_VALUE, true);
  108031. var closeBottomValue = Property.getValueOrDefault(closeBottom, Iso8601.MINIMUM_VALUE, true);
  108032. var extrudedHeightValue = Property.getValueOrUndefined(extrudedHeight, Iso8601.MINIMUM_VALUE);
  108033. options.polygonHierarchy = hierarchyValue;
  108034. options.height = heightValue;
  108035. options.extrudedHeight = extrudedHeightValue;
  108036. options.granularity = Property.getValueOrUndefined(granularity, Iso8601.MINIMUM_VALUE);
  108037. options.stRotation = Property.getValueOrUndefined(stRotation, Iso8601.MINIMUM_VALUE);
  108038. options.perPositionHeight = Property.getValueOrUndefined(perPositionHeight, Iso8601.MINIMUM_VALUE);
  108039. options.closeTop = closeTopValue;
  108040. options.closeBottom = closeBottomValue;
  108041. this._outlineWidth = Property.getValueOrDefault(outlineWidth, Iso8601.MINIMUM_VALUE, 1.0);
  108042. this._isClosed = defined(extrudedHeightValue) && extrudedHeightValue !== heightValue && closeTopValue && closeBottomValue;
  108043. this._dynamic = false;
  108044. this._geometryChanged.raiseEvent(this);
  108045. }
  108046. };
  108047. /**
  108048. * Creates the dynamic updater to be used when GeometryUpdater#isDynamic is true.
  108049. *
  108050. * @param {PrimitiveCollection} primitives The primitive collection to use.
  108051. * @returns {DynamicGeometryUpdater} The dynamic updater used to update the geometry each frame.
  108052. *
  108053. * @exception {DeveloperError} This instance does not represent dynamic geometry.
  108054. */
  108055. PolygonGeometryUpdater.prototype.createDynamicUpdater = function(primitives, groundPrimitives) {
  108056. if (!this._dynamic) {
  108057. throw new DeveloperError('This instance does not represent dynamic geometry.');
  108058. }
  108059. if (!defined(primitives)) {
  108060. throw new DeveloperError('primitives is required.');
  108061. }
  108062. return new DynamicGeometryUpdater(primitives, groundPrimitives, this);
  108063. };
  108064. /**
  108065. * @private
  108066. */
  108067. function DynamicGeometryUpdater(primitives, groundPrimitives, geometryUpdater) {
  108068. this._primitives = primitives;
  108069. this._groundPrimitives = groundPrimitives;
  108070. this._primitive = undefined;
  108071. this._outlinePrimitive = undefined;
  108072. this._geometryUpdater = geometryUpdater;
  108073. this._options = new GeometryOptions(geometryUpdater._entity);
  108074. }
  108075. DynamicGeometryUpdater.prototype.update = function(time) {
  108076. if (!defined(time)) {
  108077. throw new DeveloperError('time is required.');
  108078. }
  108079. var geometryUpdater = this._geometryUpdater;
  108080. var onTerrain = geometryUpdater._onTerrain;
  108081. var primitives = this._primitives;
  108082. var groundPrimitives = this._groundPrimitives;
  108083. if (onTerrain) {
  108084. groundPrimitives.removeAndDestroy(this._primitive);
  108085. } else {
  108086. primitives.removeAndDestroy(this._primitive);
  108087. primitives.removeAndDestroy(this._outlinePrimitive);
  108088. this._outlinePrimitive = undefined;
  108089. }
  108090. this._primitive = undefined;
  108091. var entity = geometryUpdater._entity;
  108092. var polygon = entity.polygon;
  108093. if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(polygon.show, time, true)) {
  108094. return;
  108095. }
  108096. var options = this._options;
  108097. var hierarchy = Property.getValueOrUndefined(polygon.hierarchy, time);
  108098. if (!defined(hierarchy)) {
  108099. return;
  108100. }
  108101. if (isArray(hierarchy)) {
  108102. options.polygonHierarchy = new PolygonHierarchy(hierarchy);
  108103. } else {
  108104. options.polygonHierarchy = hierarchy;
  108105. }
  108106. var closeTopValue = Property.getValueOrDefault(polygon.closeTop, time, true);
  108107. var closeBottomValue = Property.getValueOrDefault(polygon.closeBottom, time, true);
  108108. options.height = Property.getValueOrUndefined(polygon.height, time);
  108109. options.extrudedHeight = Property.getValueOrUndefined(polygon.extrudedHeight, time);
  108110. options.granularity = Property.getValueOrUndefined(polygon.granularity, time);
  108111. options.stRotation = Property.getValueOrUndefined(polygon.stRotation, time);
  108112. options.perPositionHeight = Property.getValueOrUndefined(polygon.perPositionHeight, time);
  108113. options.closeTop = closeTopValue;
  108114. options.closeBottom = closeBottomValue;
  108115. var shadows = this._geometryUpdater.shadowsProperty.getValue(time);
  108116. if (Property.getValueOrDefault(polygon.fill, time, true)) {
  108117. var fillMaterialProperty = geometryUpdater.fillMaterialProperty;
  108118. var material = MaterialProperty.getValue(time, fillMaterialProperty, this._material);
  108119. this._material = material;
  108120. if (onTerrain) {
  108121. var currentColor = Color.WHITE;
  108122. if (defined(fillMaterialProperty.color)) {
  108123. currentColor = fillMaterialProperty.color.getValue(time);
  108124. }
  108125. this._primitive = groundPrimitives.add(new GroundPrimitive({
  108126. geometryInstances : new GeometryInstance({
  108127. id : entity,
  108128. geometry : new PolygonGeometry(options),
  108129. attributes: {
  108130. color: ColorGeometryInstanceAttribute.fromColor(currentColor)
  108131. }
  108132. }),
  108133. asynchronous : false,
  108134. shadows : shadows
  108135. }));
  108136. } else {
  108137. var appearance = new MaterialAppearance({
  108138. material : material,
  108139. translucent : material.isTranslucent(),
  108140. closed : defined(options.extrudedHeight) && options.extrudedHeight !== options.height && closeTopValue && closeBottomValue
  108141. });
  108142. options.vertexFormat = appearance.vertexFormat;
  108143. this._primitive = primitives.add(new Primitive({
  108144. geometryInstances : new GeometryInstance({
  108145. id : entity,
  108146. geometry : new PolygonGeometry(options)
  108147. }),
  108148. appearance : appearance,
  108149. asynchronous : false,
  108150. shadows : shadows
  108151. }));
  108152. }
  108153. }
  108154. if (!onTerrain && Property.getValueOrDefault(polygon.outline, time, false)) {
  108155. options.vertexFormat = PerInstanceColorAppearance.VERTEX_FORMAT;
  108156. var outlineColor = Property.getValueOrClonedDefault(polygon.outlineColor, time, Color.BLACK, scratchColor);
  108157. var outlineWidth = Property.getValueOrDefault(polygon.outlineWidth, time, 1.0);
  108158. var translucent = outlineColor.alpha !== 1.0;
  108159. this._outlinePrimitive = primitives.add(new Primitive({
  108160. geometryInstances : new GeometryInstance({
  108161. id : entity,
  108162. geometry : new PolygonOutlineGeometry(options),
  108163. attributes : {
  108164. color : ColorGeometryInstanceAttribute.fromColor(outlineColor)
  108165. }
  108166. }),
  108167. appearance : new PerInstanceColorAppearance({
  108168. flat : true,
  108169. translucent : translucent,
  108170. renderState : {
  108171. lineWidth : geometryUpdater._scene.clampLineWidth(outlineWidth)
  108172. }
  108173. }),
  108174. asynchronous : false,
  108175. shadows : shadows
  108176. }));
  108177. }
  108178. };
  108179. DynamicGeometryUpdater.prototype.getBoundingSphere = function(entity, result) {
  108180. return dynamicGeometryGetBoundingSphere(entity, this._primitive, this._outlinePrimitive, result);
  108181. };
  108182. DynamicGeometryUpdater.prototype.isDestroyed = function() {
  108183. return false;
  108184. };
  108185. DynamicGeometryUpdater.prototype.destroy = function() {
  108186. var primitives = this._primitives;
  108187. var groundPrimitives = this._groundPrimitives;
  108188. if (this._geometryUpdater._onTerrain) {
  108189. groundPrimitives.removeAndDestroy(this._primitive);
  108190. } else {
  108191. primitives.removeAndDestroy(this._primitive);
  108192. }
  108193. primitives.removeAndDestroy(this._outlinePrimitive);
  108194. destroyObject(this);
  108195. };
  108196. return PolygonGeometryUpdater;
  108197. });
  108198. //This file is automatically rebuilt by the Cesium build process.
  108199. /*global define*/
  108200. define('Shaders/Appearances/PolylineColorAppearanceVS',[],function() {
  108201. 'use strict';
  108202. return "attribute vec3 position3DHigh;\n\
  108203. attribute vec3 position3DLow;\n\
  108204. attribute vec3 prevPosition3DHigh;\n\
  108205. attribute vec3 prevPosition3DLow;\n\
  108206. attribute vec3 nextPosition3DHigh;\n\
  108207. attribute vec3 nextPosition3DLow;\n\
  108208. attribute vec2 expandAndWidth;\n\
  108209. attribute vec4 color;\n\
  108210. attribute float batchId;\n\
  108211. varying vec4 v_color;\n\
  108212. void main()\n\
  108213. {\n\
  108214. float expandDir = expandAndWidth.x;\n\
  108215. float width = abs(expandAndWidth.y) + 0.5;\n\
  108216. bool usePrev = expandAndWidth.y < 0.0;\n\
  108217. vec4 p = czm_computePosition();\n\
  108218. vec4 prev = czm_computePrevPosition();\n\
  108219. vec4 next = czm_computeNextPosition();\n\
  108220. v_color = color;\n\
  108221. vec4 positionWC = getPolylineWindowCoordinates(p, prev, next, expandDir, width, usePrev);\n\
  108222. gl_Position = czm_viewportOrthographic * positionWC;\n\
  108223. }\n\
  108224. ";
  108225. });
  108226. /*global define*/
  108227. define('Scene/PolylineColorAppearance',[
  108228. '../Core/defaultValue',
  108229. '../Core/defineProperties',
  108230. '../Core/VertexFormat',
  108231. '../Shaders/Appearances/PerInstanceFlatColorAppearanceFS',
  108232. '../Shaders/Appearances/PolylineColorAppearanceVS',
  108233. '../Shaders/PolylineCommon',
  108234. './Appearance'
  108235. ], function(
  108236. defaultValue,
  108237. defineProperties,
  108238. VertexFormat,
  108239. PerInstanceFlatColorAppearanceFS,
  108240. PolylineColorAppearanceVS,
  108241. PolylineCommon,
  108242. Appearance) {
  108243. 'use strict';
  108244. var defaultVertexShaderSource = PolylineCommon + '\n' + PolylineColorAppearanceVS;
  108245. var defaultFragmentShaderSource = PerInstanceFlatColorAppearanceFS;
  108246. /**
  108247. * An appearance for {@link GeometryInstance} instances with color attributes and {@link PolylineGeometry}.
  108248. * This allows several geometry instances, each with a different color, to
  108249. * be drawn with the same {@link Primitive}.
  108250. *
  108251. * @alias PolylineColorAppearance
  108252. * @constructor
  108253. *
  108254. * @param {Object} [options] Object with the following properties:
  108255. * @param {Boolean} [options.translucent=true] When <code>true</code>, the geometry is expected to appear translucent so {@link PolylineColorAppearance#renderState} has alpha blending enabled.
  108256. * @param {String} [options.vertexShaderSource] Optional GLSL vertex shader source to override the default vertex shader.
  108257. * @param {String} [options.fragmentShaderSource] Optional GLSL fragment shader source to override the default fragment shader.
  108258. * @param {RenderState} [options.renderState] Optional render state to override the default render state.
  108259. *
  108260. * @example
  108261. * // A solid white line segment
  108262. * var primitive = new Cesium.Primitive({
  108263. * geometryInstances : new Cesium.GeometryInstance({
  108264. * geometry : new Cesium.PolylineGeometry({
  108265. * positions : Cesium.Cartesian3.fromDegreesArray([
  108266. * 0.0, 0.0,
  108267. * 5.0, 0.0
  108268. * ]),
  108269. * width : 10.0,
  108270. * vertexFormat : Cesium.PolylineColorAppearance.VERTEX_FORMAT
  108271. * }),
  108272. * attributes : {
  108273. * color : Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(1.0, 1.0, 1.0, 1.0))
  108274. * }
  108275. * }),
  108276. * appearance : new Cesium.PolylineColorAppearance({
  108277. * translucent : false
  108278. * })
  108279. * });
  108280. */
  108281. function PolylineColorAppearance(options) {
  108282. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  108283. var translucent = defaultValue(options.translucent, true);
  108284. var closed = false;
  108285. var vertexFormat = PolylineColorAppearance.VERTEX_FORMAT;
  108286. /**
  108287. * This property is part of the {@link Appearance} interface, but is not
  108288. * used by {@link PolylineColorAppearance} since a fully custom fragment shader is used.
  108289. *
  108290. * @type Material
  108291. *
  108292. * @default undefined
  108293. */
  108294. this.material = undefined;
  108295. /**
  108296. * When <code>true</code>, the geometry is expected to appear translucent so
  108297. * {@link PolylineColorAppearance#renderState} has alpha blending enabled.
  108298. *
  108299. * @type {Boolean}
  108300. *
  108301. * @default true
  108302. */
  108303. this.translucent = translucent;
  108304. this._vertexShaderSource = defaultValue(options.vertexShaderSource, defaultVertexShaderSource);
  108305. this._fragmentShaderSource = defaultValue(options.fragmentShaderSource, defaultFragmentShaderSource);
  108306. this._renderState = Appearance.getDefaultRenderState(translucent, closed, options.renderState);
  108307. this._closed = closed;
  108308. // Non-derived members
  108309. this._vertexFormat = vertexFormat;
  108310. }
  108311. defineProperties(PolylineColorAppearance.prototype, {
  108312. /**
  108313. * The GLSL source code for the vertex shader.
  108314. *
  108315. * @memberof PolylineColorAppearance.prototype
  108316. *
  108317. * @type {String}
  108318. * @readonly
  108319. */
  108320. vertexShaderSource : {
  108321. get : function() {
  108322. return this._vertexShaderSource;
  108323. }
  108324. },
  108325. /**
  108326. * The GLSL source code for the fragment shader.
  108327. *
  108328. * @memberof PolylineColorAppearance.prototype
  108329. *
  108330. * @type {String}
  108331. * @readonly
  108332. */
  108333. fragmentShaderSource : {
  108334. get : function() {
  108335. return this._fragmentShaderSource;
  108336. }
  108337. },
  108338. /**
  108339. * The WebGL fixed-function state to use when rendering the geometry.
  108340. * <p>
  108341. * The render state can be explicitly defined when constructing a {@link PolylineColorAppearance}
  108342. * instance, or it is set implicitly via {@link PolylineColorAppearance#translucent}.
  108343. * </p>
  108344. *
  108345. * @memberof PolylineColorAppearance.prototype
  108346. *
  108347. * @type {Object}
  108348. * @readonly
  108349. */
  108350. renderState : {
  108351. get : function() {
  108352. return this._renderState;
  108353. }
  108354. },
  108355. /**
  108356. * When <code>true</code>, the geometry is expected to be closed so
  108357. * {@link PolylineColorAppearance#renderState} has backface culling enabled.
  108358. * This is always <code>false</code> for <code>PolylineColorAppearance</code>.
  108359. *
  108360. * @memberof PolylineColorAppearance.prototype
  108361. *
  108362. * @type {Boolean}
  108363. * @readonly
  108364. *
  108365. * @default false
  108366. */
  108367. closed : {
  108368. get : function() {
  108369. return this._closed;
  108370. }
  108371. },
  108372. /**
  108373. * The {@link VertexFormat} that this appearance instance is compatible with.
  108374. * A geometry can have more vertex attributes and still be compatible - at a
  108375. * potential performance cost - but it can't have less.
  108376. *
  108377. * @memberof PolylineColorAppearance.prototype
  108378. *
  108379. * @type VertexFormat
  108380. * @readonly
  108381. *
  108382. * @default {@link PolylineColorAppearance.VERTEX_FORMAT}
  108383. */
  108384. vertexFormat : {
  108385. get : function() {
  108386. return this._vertexFormat;
  108387. }
  108388. }
  108389. });
  108390. /**
  108391. * The {@link VertexFormat} that all {@link PolylineColorAppearance} instances
  108392. * are compatible with. This requires only a <code>position</code> attribute.
  108393. *
  108394. * @type VertexFormat
  108395. *
  108396. * @constant
  108397. */
  108398. PolylineColorAppearance.VERTEX_FORMAT = VertexFormat.POSITION_ONLY;
  108399. /**
  108400. * Procedurally creates the full GLSL fragment shader source.
  108401. *
  108402. * @function
  108403. *
  108404. * @returns {String} The full GLSL fragment shader source.
  108405. */
  108406. PolylineColorAppearance.prototype.getFragmentShaderSource = Appearance.prototype.getFragmentShaderSource;
  108407. /**
  108408. * Determines if the geometry is translucent based on {@link PolylineColorAppearance#translucent}.
  108409. *
  108410. * @function
  108411. *
  108412. * @returns {Boolean} <code>true</code> if the appearance is translucent.
  108413. */
  108414. PolylineColorAppearance.prototype.isTranslucent = Appearance.prototype.isTranslucent;
  108415. /**
  108416. * Creates a render state. This is not the final render state instance; instead,
  108417. * it can contain a subset of render state properties identical to the render state
  108418. * created in the context.
  108419. *
  108420. * @function
  108421. *
  108422. * @returns {Object} The render state.
  108423. */
  108424. PolylineColorAppearance.prototype.getRenderState = Appearance.prototype.getRenderState;
  108425. return PolylineColorAppearance;
  108426. });
  108427. //This file is automatically rebuilt by the Cesium build process.
  108428. /*global define*/
  108429. define('Shaders/Appearances/PolylineMaterialAppearanceVS',[],function() {
  108430. 'use strict';
  108431. return "attribute vec3 position3DHigh;\n\
  108432. attribute vec3 position3DLow;\n\
  108433. attribute vec3 prevPosition3DHigh;\n\
  108434. attribute vec3 prevPosition3DLow;\n\
  108435. attribute vec3 nextPosition3DHigh;\n\
  108436. attribute vec3 nextPosition3DLow;\n\
  108437. attribute vec2 expandAndWidth;\n\
  108438. attribute vec2 st;\n\
  108439. attribute float batchId;\n\
  108440. varying float v_width;\n\
  108441. varying vec2 v_st;\n\
  108442. void main()\n\
  108443. {\n\
  108444. float expandDir = expandAndWidth.x;\n\
  108445. float width = abs(expandAndWidth.y) + 0.5;\n\
  108446. bool usePrev = expandAndWidth.y < 0.0;\n\
  108447. vec4 p = czm_computePosition();\n\
  108448. vec4 prev = czm_computePrevPosition();\n\
  108449. vec4 next = czm_computeNextPosition();\n\
  108450. v_width = width;\n\
  108451. v_st = st;\n\
  108452. vec4 positionWC = getPolylineWindowCoordinates(p, prev, next, expandDir, width, usePrev);\n\
  108453. gl_Position = czm_viewportOrthographic * positionWC;\n\
  108454. }\n\
  108455. ";
  108456. });
  108457. /*global define*/
  108458. define('Scene/PolylineMaterialAppearance',[
  108459. '../Core/defaultValue',
  108460. '../Core/defined',
  108461. '../Core/defineProperties',
  108462. '../Core/VertexFormat',
  108463. '../Shaders/Appearances/PolylineMaterialAppearanceVS',
  108464. '../Shaders/PolylineCommon',
  108465. '../Shaders/PolylineFS',
  108466. './Appearance',
  108467. './Material'
  108468. ], function(
  108469. defaultValue,
  108470. defined,
  108471. defineProperties,
  108472. VertexFormat,
  108473. PolylineMaterialAppearanceVS,
  108474. PolylineCommon,
  108475. PolylineFS,
  108476. Appearance,
  108477. Material) {
  108478. 'use strict';
  108479. var defaultVertexShaderSource = PolylineCommon + '\n' + PolylineMaterialAppearanceVS;
  108480. var defaultFragmentShaderSource = PolylineFS;
  108481. /**
  108482. * An appearance for {@link PolylineGeometry} that supports shading with materials.
  108483. *
  108484. * @alias PolylineMaterialAppearance
  108485. * @constructor
  108486. *
  108487. * @param {Object} [options] Object with the following properties:
  108488. * @param {Boolean} [options.translucent=true] When <code>true</code>, the geometry is expected to appear translucent so {@link PolylineMaterialAppearance#renderState} has alpha blending enabled.
  108489. * @param {Material} [options.material=Material.ColorType] The material used to determine the fragment color.
  108490. * @param {String} [options.vertexShaderSource] Optional GLSL vertex shader source to override the default vertex shader.
  108491. * @param {String} [options.fragmentShaderSource] Optional GLSL fragment shader source to override the default fragment shader.
  108492. * @param {RenderState} [options.renderState] Optional render state to override the default render state.
  108493. *
  108494. * @see {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}
  108495. *
  108496. * @example
  108497. * var primitive = new Cesium.Primitive({
  108498. * geometryInstances : new Cesium.GeometryInstance({
  108499. * geometry : new Cesium.PolylineGeometry({
  108500. * positions : Cesium.Cartesian3.fromDegreesArray([
  108501. * 0.0, 0.0,
  108502. * 5.0, 0.0
  108503. * ]),
  108504. * width : 10.0,
  108505. * vertexFormat : Cesium.PolylineMaterialAppearance.VERTEX_FORMAT
  108506. * })
  108507. * }),
  108508. * appearance : new Cesium.PolylineMaterialAppearance({
  108509. * material : Cesium.Material.fromType('Color')
  108510. * })
  108511. * });
  108512. */
  108513. function PolylineMaterialAppearance(options) {
  108514. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  108515. var translucent = defaultValue(options.translucent, true);
  108516. var closed = false;
  108517. var vertexFormat = PolylineMaterialAppearance.VERTEX_FORMAT;
  108518. /**
  108519. * The material used to determine the fragment color. Unlike other {@link PolylineMaterialAppearance}
  108520. * properties, this is not read-only, so an appearance's material can change on the fly.
  108521. *
  108522. * @type Material
  108523. *
  108524. * @default {@link Material.ColorType}
  108525. *
  108526. * @see {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}
  108527. */
  108528. this.material = defined(options.material) ? options.material : Material.fromType(Material.ColorType);
  108529. /**
  108530. * When <code>true</code>, the geometry is expected to appear translucent so
  108531. * {@link PolylineMaterialAppearance#renderState} has alpha blending enabled.
  108532. *
  108533. * @type {Boolean}
  108534. *
  108535. * @default true
  108536. */
  108537. this.translucent = translucent;
  108538. this._vertexShaderSource = defaultValue(options.vertexShaderSource, defaultVertexShaderSource);
  108539. this._fragmentShaderSource = defaultValue(options.fragmentShaderSource, defaultFragmentShaderSource);
  108540. this._renderState = Appearance.getDefaultRenderState(translucent, closed, options.renderState);
  108541. this._closed = closed;
  108542. // Non-derived members
  108543. this._vertexFormat = vertexFormat;
  108544. }
  108545. defineProperties(PolylineMaterialAppearance.prototype, {
  108546. /**
  108547. * The GLSL source code for the vertex shader.
  108548. *
  108549. * @memberof PolylineMaterialAppearance.prototype
  108550. *
  108551. * @type {String}
  108552. * @readonly
  108553. */
  108554. vertexShaderSource : {
  108555. get : function() {
  108556. return this._vertexShaderSource;
  108557. }
  108558. },
  108559. /**
  108560. * The GLSL source code for the fragment shader.
  108561. *
  108562. * @memberof PolylineMaterialAppearance.prototype
  108563. *
  108564. * @type {String}
  108565. * @readonly
  108566. */
  108567. fragmentShaderSource : {
  108568. get : function() {
  108569. return this._fragmentShaderSource;
  108570. }
  108571. },
  108572. /**
  108573. * The WebGL fixed-function state to use when rendering the geometry.
  108574. * <p>
  108575. * The render state can be explicitly defined when constructing a {@link PolylineMaterialAppearance}
  108576. * instance, or it is set implicitly via {@link PolylineMaterialAppearance#translucent}
  108577. * and {@link PolylineMaterialAppearance#closed}.
  108578. * </p>
  108579. *
  108580. * @memberof PolylineMaterialAppearance.prototype
  108581. *
  108582. * @type {Object}
  108583. * @readonly
  108584. */
  108585. renderState : {
  108586. get : function() {
  108587. return this._renderState;
  108588. }
  108589. },
  108590. /**
  108591. * When <code>true</code>, the geometry is expected to be closed so
  108592. * {@link PolylineMaterialAppearance#renderState} has backface culling enabled.
  108593. * This is always <code>false</code> for <code>PolylineMaterialAppearance</code>.
  108594. *
  108595. * @memberof PolylineMaterialAppearance.prototype
  108596. *
  108597. * @type {Boolean}
  108598. * @readonly
  108599. *
  108600. * @default false
  108601. */
  108602. closed : {
  108603. get : function() {
  108604. return this._closed;
  108605. }
  108606. },
  108607. /**
  108608. * The {@link VertexFormat} that this appearance instance is compatible with.
  108609. * A geometry can have more vertex attributes and still be compatible - at a
  108610. * potential performance cost - but it can't have less.
  108611. *
  108612. * @memberof PolylineMaterialAppearance.prototype
  108613. *
  108614. * @type VertexFormat
  108615. * @readonly
  108616. *
  108617. * @default {@link PolylineMaterialAppearance.VERTEX_FORMAT}
  108618. */
  108619. vertexFormat : {
  108620. get : function() {
  108621. return this._vertexFormat;
  108622. }
  108623. }
  108624. });
  108625. /**
  108626. * The {@link VertexFormat} that all {@link PolylineMaterialAppearance} instances
  108627. * are compatible with. This requires <code>position</code> and <code>st</code> attributes.
  108628. *
  108629. * @type VertexFormat
  108630. *
  108631. * @constant
  108632. */
  108633. PolylineMaterialAppearance.VERTEX_FORMAT = VertexFormat.POSITION_AND_ST;
  108634. /**
  108635. * Procedurally creates the full GLSL fragment shader source. For {@link PolylineMaterialAppearance},
  108636. * this is derived from {@link PolylineMaterialAppearance#fragmentShaderSource} and {@link PolylineMaterialAppearance#material}.
  108637. *
  108638. * @function
  108639. *
  108640. * @returns {String} The full GLSL fragment shader source.
  108641. */
  108642. PolylineMaterialAppearance.prototype.getFragmentShaderSource = Appearance.prototype.getFragmentShaderSource;
  108643. /**
  108644. * Determines if the geometry is translucent based on {@link PolylineMaterialAppearance#translucent} and {@link Material#isTranslucent}.
  108645. *
  108646. * @function
  108647. *
  108648. * @returns {Boolean} <code>true</code> if the appearance is translucent.
  108649. */
  108650. PolylineMaterialAppearance.prototype.isTranslucent = Appearance.prototype.isTranslucent;
  108651. /**
  108652. * Creates a render state. This is not the final render state instance; instead,
  108653. * it can contain a subset of render state properties identical to the render state
  108654. * created in the context.
  108655. *
  108656. * @function
  108657. *
  108658. * @returns {Object} The render state.
  108659. */
  108660. PolylineMaterialAppearance.prototype.getRenderState = Appearance.prototype.getRenderState;
  108661. return PolylineMaterialAppearance;
  108662. });
  108663. /*global define*/
  108664. define('DataSources/PolylineGeometryUpdater',[
  108665. '../Core/BoundingSphere',
  108666. '../Core/Color',
  108667. '../Core/ColorGeometryInstanceAttribute',
  108668. '../Core/defaultValue',
  108669. '../Core/defined',
  108670. '../Core/defineProperties',
  108671. '../Core/destroyObject',
  108672. '../Core/DeveloperError',
  108673. '../Core/DistanceDisplayCondition',
  108674. '../Core/DistanceDisplayConditionGeometryInstanceAttribute',
  108675. '../Core/Event',
  108676. '../Core/GeometryInstance',
  108677. '../Core/Iso8601',
  108678. '../Core/PolylineGeometry',
  108679. '../Core/PolylinePipeline',
  108680. '../Core/ShowGeometryInstanceAttribute',
  108681. '../Scene/PolylineCollection',
  108682. '../Scene/PolylineColorAppearance',
  108683. '../Scene/PolylineMaterialAppearance',
  108684. '../Scene/ShadowMode',
  108685. './BoundingSphereState',
  108686. './ColorMaterialProperty',
  108687. './ConstantProperty',
  108688. './MaterialProperty',
  108689. './Property'
  108690. ], function(
  108691. BoundingSphere,
  108692. Color,
  108693. ColorGeometryInstanceAttribute,
  108694. defaultValue,
  108695. defined,
  108696. defineProperties,
  108697. destroyObject,
  108698. DeveloperError,
  108699. DistanceDisplayCondition,
  108700. DistanceDisplayConditionGeometryInstanceAttribute,
  108701. Event,
  108702. GeometryInstance,
  108703. Iso8601,
  108704. PolylineGeometry,
  108705. PolylinePipeline,
  108706. ShowGeometryInstanceAttribute,
  108707. PolylineCollection,
  108708. PolylineColorAppearance,
  108709. PolylineMaterialAppearance,
  108710. ShadowMode,
  108711. BoundingSphereState,
  108712. ColorMaterialProperty,
  108713. ConstantProperty,
  108714. MaterialProperty,
  108715. Property) {
  108716. 'use strict';
  108717. //We use this object to create one polyline collection per-scene.
  108718. var polylineCollections = {};
  108719. var defaultMaterial = new ColorMaterialProperty(Color.WHITE);
  108720. var defaultShow = new ConstantProperty(true);
  108721. var defaultShadows = new ConstantProperty(ShadowMode.DISABLED);
  108722. var defaultDistanceDisplayCondition = new ConstantProperty(new DistanceDisplayCondition());
  108723. function GeometryOptions(entity) {
  108724. this.id = entity;
  108725. this.vertexFormat = undefined;
  108726. this.positions = undefined;
  108727. this.width = undefined;
  108728. this.followSurface = undefined;
  108729. this.granularity = undefined;
  108730. }
  108731. /**
  108732. * A {@link GeometryUpdater} for polylines.
  108733. * Clients do not normally create this class directly, but instead rely on {@link DataSourceDisplay}.
  108734. * @alias PolylineGeometryUpdater
  108735. * @constructor
  108736. *
  108737. * @param {Entity} entity The entity containing the geometry to be visualized.
  108738. * @param {Scene} scene The scene where visualization is taking place.
  108739. */
  108740. function PolylineGeometryUpdater(entity, scene) {
  108741. if (!defined(entity)) {
  108742. throw new DeveloperError('entity is required');
  108743. }
  108744. if (!defined(scene)) {
  108745. throw new DeveloperError('scene is required');
  108746. }
  108747. this._entity = entity;
  108748. this._scene = scene;
  108749. this._entitySubscription = entity.definitionChanged.addEventListener(PolylineGeometryUpdater.prototype._onEntityPropertyChanged, this);
  108750. this._fillEnabled = false;
  108751. this._dynamic = false;
  108752. this._geometryChanged = new Event();
  108753. this._showProperty = undefined;
  108754. this._materialProperty = undefined;
  108755. this._shadowsProperty = undefined;
  108756. this._distanceDisplayConditionProperty = undefined;
  108757. this._options = new GeometryOptions(entity);
  108758. this._onEntityPropertyChanged(entity, 'polyline', entity.polyline, undefined);
  108759. }
  108760. defineProperties(PolylineGeometryUpdater, {
  108761. /**
  108762. * Gets the type of Appearance to use for simple color-based geometry.
  108763. * @memberof PolylineGeometryUpdater
  108764. * @type {Appearance}
  108765. */
  108766. perInstanceColorAppearanceType : {
  108767. value : PolylineColorAppearance
  108768. },
  108769. /**
  108770. * Gets the type of Appearance to use for material-based geometry.
  108771. * @memberof PolylineGeometryUpdater
  108772. * @type {Appearance}
  108773. */
  108774. materialAppearanceType : {
  108775. value : PolylineMaterialAppearance
  108776. }
  108777. });
  108778. defineProperties(PolylineGeometryUpdater.prototype, {
  108779. /**
  108780. * Gets the entity associated with this geometry.
  108781. * @memberof PolylineGeometryUpdater.prototype
  108782. *
  108783. * @type {Entity}
  108784. * @readonly
  108785. */
  108786. entity : {
  108787. get : function() {
  108788. return this._entity;
  108789. }
  108790. },
  108791. /**
  108792. * Gets a value indicating if the geometry has a fill component.
  108793. * @memberof PolylineGeometryUpdater.prototype
  108794. *
  108795. * @type {Boolean}
  108796. * @readonly
  108797. */
  108798. fillEnabled : {
  108799. get : function() {
  108800. return this._fillEnabled;
  108801. }
  108802. },
  108803. /**
  108804. * Gets a value indicating if fill visibility varies with simulation time.
  108805. * @memberof PolylineGeometryUpdater.prototype
  108806. *
  108807. * @type {Boolean}
  108808. * @readonly
  108809. */
  108810. hasConstantFill : {
  108811. get : function() {
  108812. return !this._fillEnabled || (!defined(this._entity.availability) && Property.isConstant(this._showProperty));
  108813. }
  108814. },
  108815. /**
  108816. * Gets the material property used to fill the geometry.
  108817. * @memberof PolylineGeometryUpdater.prototype
  108818. *
  108819. * @type {MaterialProperty}
  108820. * @readonly
  108821. */
  108822. fillMaterialProperty : {
  108823. get : function() {
  108824. return this._materialProperty;
  108825. }
  108826. },
  108827. /**
  108828. * Gets a value indicating if the geometry has an outline component.
  108829. * @memberof PolylineGeometryUpdater.prototype
  108830. *
  108831. * @type {Boolean}
  108832. * @readonly
  108833. */
  108834. outlineEnabled : {
  108835. value : false
  108836. },
  108837. /**
  108838. * Gets a value indicating if outline visibility varies with simulation time.
  108839. * @memberof PolylineGeometryUpdater.prototype
  108840. *
  108841. * @type {Boolean}
  108842. * @readonly
  108843. */
  108844. hasConstantOutline : {
  108845. value : true
  108846. },
  108847. /**
  108848. * Gets the {@link Color} property for the geometry outline.
  108849. * @memberof PolylineGeometryUpdater.prototype
  108850. *
  108851. * @type {Property}
  108852. * @readonly
  108853. */
  108854. outlineColorProperty : {
  108855. value : undefined
  108856. },
  108857. /**
  108858. * Gets the property specifying whether the geometry
  108859. * casts or receives shadows from each light source.
  108860. * @memberof PolylineGeometryUpdater.prototype
  108861. *
  108862. * @type {Property}
  108863. * @readonly
  108864. */
  108865. shadowsProperty : {
  108866. get : function() {
  108867. return this._shadowsProperty;
  108868. }
  108869. },
  108870. /**
  108871. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this geometry will be displayed.
  108872. * @memberof PolylineGeometryUpdater.prototype
  108873. *
  108874. * @type {Property}
  108875. * @readonly
  108876. */
  108877. distanceDisplayConditionProperty : {
  108878. get : function() {
  108879. return this._distanceDisplayConditionProperty;
  108880. }
  108881. },
  108882. /**
  108883. * Gets a value indicating if the geometry is time-varying.
  108884. * If true, all visualization is delegated to the {@link DynamicGeometryUpdater}
  108885. * returned by GeometryUpdater#createDynamicUpdater.
  108886. * @memberof PolylineGeometryUpdater.prototype
  108887. *
  108888. * @type {Boolean}
  108889. * @readonly
  108890. */
  108891. isDynamic : {
  108892. get : function() {
  108893. return this._dynamic;
  108894. }
  108895. },
  108896. /**
  108897. * Gets a value indicating if the geometry is closed.
  108898. * This property is only valid for static geometry.
  108899. * @memberof PolylineGeometryUpdater.prototype
  108900. *
  108901. * @type {Boolean}
  108902. * @readonly
  108903. */
  108904. isClosed : {
  108905. value : false
  108906. },
  108907. /**
  108908. * Gets an event that is raised whenever the public properties
  108909. * of this updater change.
  108910. * @memberof PolylineGeometryUpdater.prototype
  108911. *
  108912. * @type {Boolean}
  108913. * @readonly
  108914. */
  108915. geometryChanged : {
  108916. get : function() {
  108917. return this._geometryChanged;
  108918. }
  108919. }
  108920. });
  108921. /**
  108922. * Checks if the geometry is outlined at the provided time.
  108923. *
  108924. * @param {JulianDate} time The time for which to retrieve visibility.
  108925. * @returns {Boolean} true if geometry is outlined at the provided time, false otherwise.
  108926. */
  108927. PolylineGeometryUpdater.prototype.isOutlineVisible = function(time) {
  108928. return false;
  108929. };
  108930. /**
  108931. * Checks if the geometry is filled at the provided time.
  108932. *
  108933. * @param {JulianDate} time The time for which to retrieve visibility.
  108934. * @returns {Boolean} true if geometry is filled at the provided time, false otherwise.
  108935. */
  108936. PolylineGeometryUpdater.prototype.isFilled = function(time) {
  108937. var entity = this._entity;
  108938. return this._fillEnabled && entity.isAvailable(time) && this._showProperty.getValue(time);
  108939. };
  108940. /**
  108941. * Creates the geometry instance which represents the fill of the geometry.
  108942. *
  108943. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  108944. * @returns {GeometryInstance} The geometry instance representing the filled portion of the geometry.
  108945. *
  108946. * @exception {DeveloperError} This instance does not represent a filled geometry.
  108947. */
  108948. PolylineGeometryUpdater.prototype.createFillGeometryInstance = function(time) {
  108949. if (!defined(time)) {
  108950. throw new DeveloperError('time is required.');
  108951. }
  108952. if (!this._fillEnabled) {
  108953. throw new DeveloperError('This instance does not represent a filled geometry.');
  108954. }
  108955. var color;
  108956. var attributes;
  108957. var entity = this._entity;
  108958. var isAvailable = entity.isAvailable(time);
  108959. var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time));
  108960. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  108961. var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
  108962. if (this._materialProperty instanceof ColorMaterialProperty) {
  108963. var currentColor = Color.WHITE;
  108964. if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) {
  108965. currentColor = this._materialProperty.color.getValue(time);
  108966. }
  108967. color = ColorGeometryInstanceAttribute.fromColor(currentColor);
  108968. attributes = {
  108969. show : show,
  108970. distanceDisplayCondition : distanceDisplayConditionAttribute,
  108971. color : color
  108972. };
  108973. } else {
  108974. attributes = {
  108975. show : show,
  108976. distanceDisplayCondition : distanceDisplayConditionAttribute
  108977. };
  108978. }
  108979. return new GeometryInstance({
  108980. id : entity,
  108981. geometry : new PolylineGeometry(this._options),
  108982. attributes : attributes
  108983. });
  108984. };
  108985. /**
  108986. * Creates the geometry instance which represents the outline of the geometry.
  108987. *
  108988. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  108989. * @returns {GeometryInstance} The geometry instance representing the outline portion of the geometry.
  108990. *
  108991. * @exception {DeveloperError} This instance does not represent an outlined geometry.
  108992. */
  108993. PolylineGeometryUpdater.prototype.createOutlineGeometryInstance = function(time) {
  108994. throw new DeveloperError('This instance does not represent an outlined geometry.');
  108995. };
  108996. /**
  108997. * Returns true if this object was destroyed; otherwise, false.
  108998. *
  108999. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  109000. */
  109001. PolylineGeometryUpdater.prototype.isDestroyed = function() {
  109002. return false;
  109003. };
  109004. /**
  109005. * Destroys and resources used by the object. Once an object is destroyed, it should not be used.
  109006. *
  109007. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  109008. */
  109009. PolylineGeometryUpdater.prototype.destroy = function() {
  109010. this._entitySubscription();
  109011. destroyObject(this);
  109012. };
  109013. PolylineGeometryUpdater.prototype._onEntityPropertyChanged = function(entity, propertyName, newValue, oldValue) {
  109014. if (!(propertyName === 'availability' || propertyName === 'polyline')) {
  109015. return;
  109016. }
  109017. var polyline = this._entity.polyline;
  109018. if (!defined(polyline)) {
  109019. if (this._fillEnabled) {
  109020. this._fillEnabled = false;
  109021. this._geometryChanged.raiseEvent(this);
  109022. }
  109023. return;
  109024. }
  109025. var positionsProperty = polyline.positions;
  109026. var show = polyline.show;
  109027. if ((defined(show) && show.isConstant && !show.getValue(Iso8601.MINIMUM_VALUE)) || //
  109028. (!defined(positionsProperty))) {
  109029. if (this._fillEnabled) {
  109030. this._fillEnabled = false;
  109031. this._geometryChanged.raiseEvent(this);
  109032. }
  109033. return;
  109034. }
  109035. var material = defaultValue(polyline.material, defaultMaterial);
  109036. var isColorMaterial = material instanceof ColorMaterialProperty;
  109037. this._materialProperty = material;
  109038. this._showProperty = defaultValue(show, defaultShow);
  109039. this._shadowsProperty = defaultValue(polyline.shadows, defaultShadows);
  109040. this._distanceDisplayConditionProperty = defaultValue(polyline.distanceDisplayCondition, defaultDistanceDisplayCondition);
  109041. this._fillEnabled = true;
  109042. var width = polyline.width;
  109043. var followSurface = polyline.followSurface;
  109044. var granularity = polyline.granularity;
  109045. if (!positionsProperty.isConstant || !Property.isConstant(width) ||
  109046. !Property.isConstant(followSurface) || !Property.isConstant(granularity)) {
  109047. if (!this._dynamic) {
  109048. this._dynamic = true;
  109049. this._geometryChanged.raiseEvent(this);
  109050. }
  109051. } else {
  109052. var options = this._options;
  109053. var positions = positionsProperty.getValue(Iso8601.MINIMUM_VALUE, options.positions);
  109054. //Because of the way we currently handle reference properties,
  109055. //we can't automatically assume the positions are always valid.
  109056. if (!defined(positions) || positions.length < 2) {
  109057. if (this._fillEnabled) {
  109058. this._fillEnabled = false;
  109059. this._geometryChanged.raiseEvent(this);
  109060. }
  109061. return;
  109062. }
  109063. options.vertexFormat = isColorMaterial ? PolylineColorAppearance.VERTEX_FORMAT : PolylineMaterialAppearance.VERTEX_FORMAT;
  109064. options.positions = positions;
  109065. options.width = defined(width) ? width.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  109066. options.followSurface = defined(followSurface) ? followSurface.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  109067. options.granularity = defined(granularity) ? granularity.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  109068. this._dynamic = false;
  109069. this._geometryChanged.raiseEvent(this);
  109070. }
  109071. };
  109072. /**
  109073. * Creates the dynamic updater to be used when GeometryUpdater#isDynamic is true.
  109074. *
  109075. * @param {PrimitiveCollection} primitives The primitive collection to use.
  109076. * @returns {DynamicGeometryUpdater} The dynamic updater used to update the geometry each frame.
  109077. *
  109078. * @exception {DeveloperError} This instance does not represent dynamic geometry.
  109079. */
  109080. PolylineGeometryUpdater.prototype.createDynamicUpdater = function(primitives) {
  109081. if (!this._dynamic) {
  109082. throw new DeveloperError('This instance does not represent dynamic geometry.');
  109083. }
  109084. if (!defined(primitives)) {
  109085. throw new DeveloperError('primitives is required.');
  109086. }
  109087. return new DynamicGeometryUpdater(primitives, this);
  109088. };
  109089. /**
  109090. * @private
  109091. */
  109092. var generateCartesianArcOptions = {
  109093. positions : undefined,
  109094. granularity : undefined,
  109095. height : undefined,
  109096. ellipsoid : undefined
  109097. };
  109098. function DynamicGeometryUpdater(primitives, geometryUpdater) {
  109099. var sceneId = geometryUpdater._scene.id;
  109100. var polylineCollection = polylineCollections[sceneId];
  109101. if (!defined(polylineCollection) || polylineCollection.isDestroyed()) {
  109102. polylineCollection = new PolylineCollection();
  109103. polylineCollections[sceneId] = polylineCollection;
  109104. primitives.add(polylineCollection);
  109105. } else if (!primitives.contains(polylineCollection)) {
  109106. primitives.add(polylineCollection);
  109107. }
  109108. var line = polylineCollection.add();
  109109. line.id = geometryUpdater._entity;
  109110. this._line = line;
  109111. this._primitives = primitives;
  109112. this._geometryUpdater = geometryUpdater;
  109113. this._positions = [];
  109114. generateCartesianArcOptions.ellipsoid = geometryUpdater._scene.globe.ellipsoid;
  109115. }
  109116. DynamicGeometryUpdater.prototype.update = function(time) {
  109117. var geometryUpdater = this._geometryUpdater;
  109118. var entity = geometryUpdater._entity;
  109119. var polyline = entity.polyline;
  109120. var line = this._line;
  109121. if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(polyline._show, time, true)) {
  109122. line.show = false;
  109123. return;
  109124. }
  109125. var positionsProperty = polyline.positions;
  109126. var positions = Property.getValueOrUndefined(positionsProperty, time, this._positions);
  109127. if (!defined(positions) || positions.length < 2) {
  109128. line.show = false;
  109129. return;
  109130. }
  109131. var followSurface = Property.getValueOrDefault(polyline._followSurface, time, true);
  109132. if (followSurface) {
  109133. generateCartesianArcOptions.positions = positions;
  109134. generateCartesianArcOptions.granularity = Property.getValueOrUndefined(polyline._granularity, time);
  109135. generateCartesianArcOptions.height = PolylinePipeline.extractHeights(positions, this._geometryUpdater._scene.globe.ellipsoid);
  109136. positions = PolylinePipeline.generateCartesianArc(generateCartesianArcOptions);
  109137. }
  109138. line.show = true;
  109139. line.positions = positions.slice();
  109140. line.material = MaterialProperty.getValue(time, geometryUpdater.fillMaterialProperty, line.material);
  109141. line.width = Property.getValueOrDefault(polyline._width, time, 1);
  109142. line.distanceDisplayCondition = Property.getValueOrUndefined(polyline._distanceDisplayCondition, time, line.distanceDisplayCondition);
  109143. };
  109144. DynamicGeometryUpdater.prototype.getBoundingSphere = function(entity, result) {
  109145. if (!defined(entity)) {
  109146. throw new DeveloperError('entity is required.');
  109147. }
  109148. if (!defined(result)) {
  109149. throw new DeveloperError('result is required.');
  109150. }
  109151. var line = this._line;
  109152. if (line.show && line.positions.length > 0) {
  109153. BoundingSphere.fromPoints(line.positions, result);
  109154. return BoundingSphereState.DONE;
  109155. }
  109156. return BoundingSphereState.FAILED;
  109157. };
  109158. DynamicGeometryUpdater.prototype.isDestroyed = function() {
  109159. return false;
  109160. };
  109161. DynamicGeometryUpdater.prototype.destroy = function() {
  109162. var geometryUpdater = this._geometryUpdater;
  109163. var sceneId = geometryUpdater._scene.id;
  109164. var polylineCollection = polylineCollections[sceneId];
  109165. polylineCollection.remove(this._line);
  109166. if (polylineCollection.length === 0) {
  109167. this._primitives.removeAndDestroy(polylineCollection);
  109168. delete polylineCollections[sceneId];
  109169. }
  109170. destroyObject(this);
  109171. };
  109172. return PolylineGeometryUpdater;
  109173. });
  109174. /*global define*/
  109175. define('DataSources/PolylineVolumeGeometryUpdater',[
  109176. '../Core/Color',
  109177. '../Core/ColorGeometryInstanceAttribute',
  109178. '../Core/defaultValue',
  109179. '../Core/defined',
  109180. '../Core/defineProperties',
  109181. '../Core/destroyObject',
  109182. '../Core/DeveloperError',
  109183. '../Core/DistanceDisplayCondition',
  109184. '../Core/DistanceDisplayConditionGeometryInstanceAttribute',
  109185. '../Core/Event',
  109186. '../Core/GeometryInstance',
  109187. '../Core/Iso8601',
  109188. '../Core/PolylineVolumeGeometry',
  109189. '../Core/PolylineVolumeOutlineGeometry',
  109190. '../Core/ShowGeometryInstanceAttribute',
  109191. '../Scene/MaterialAppearance',
  109192. '../Scene/PerInstanceColorAppearance',
  109193. '../Scene/Primitive',
  109194. '../Scene/ShadowMode',
  109195. './ColorMaterialProperty',
  109196. './ConstantProperty',
  109197. './dynamicGeometryGetBoundingSphere',
  109198. './MaterialProperty',
  109199. './Property'
  109200. ], function(
  109201. Color,
  109202. ColorGeometryInstanceAttribute,
  109203. defaultValue,
  109204. defined,
  109205. defineProperties,
  109206. destroyObject,
  109207. DeveloperError,
  109208. DistanceDisplayCondition,
  109209. DistanceDisplayConditionGeometryInstanceAttribute,
  109210. Event,
  109211. GeometryInstance,
  109212. Iso8601,
  109213. PolylineVolumeGeometry,
  109214. PolylineVolumeOutlineGeometry,
  109215. ShowGeometryInstanceAttribute,
  109216. MaterialAppearance,
  109217. PerInstanceColorAppearance,
  109218. Primitive,
  109219. ShadowMode,
  109220. ColorMaterialProperty,
  109221. ConstantProperty,
  109222. dynamicGeometryGetBoundingSphere,
  109223. MaterialProperty,
  109224. Property) {
  109225. 'use strict';
  109226. var defaultMaterial = new ColorMaterialProperty(Color.WHITE);
  109227. var defaultShow = new ConstantProperty(true);
  109228. var defaultFill = new ConstantProperty(true);
  109229. var defaultOutline = new ConstantProperty(false);
  109230. var defaultOutlineColor = new ConstantProperty(Color.BLACK);
  109231. var defaultShadows = new ConstantProperty(ShadowMode.DISABLED);
  109232. var defaultDistanceDisplayCondition = new ConstantProperty(new DistanceDisplayCondition());
  109233. var scratchColor = new Color();
  109234. function GeometryOptions(entity) {
  109235. this.id = entity;
  109236. this.vertexFormat = undefined;
  109237. this.polylinePositions = undefined;
  109238. this.shapePositions = undefined;
  109239. this.cornerType = undefined;
  109240. this.granularity = undefined;
  109241. }
  109242. /**
  109243. * A {@link GeometryUpdater} for polyline volumes.
  109244. * Clients do not normally create this class directly, but instead rely on {@link DataSourceDisplay}.
  109245. * @alias PolylineVolumeGeometryUpdater
  109246. * @constructor
  109247. *
  109248. * @param {Entity} entity The entity containing the geometry to be visualized.
  109249. * @param {Scene} scene The scene where visualization is taking place.
  109250. */
  109251. function PolylineVolumeGeometryUpdater(entity, scene) {
  109252. if (!defined(entity)) {
  109253. throw new DeveloperError('entity is required');
  109254. }
  109255. if (!defined(scene)) {
  109256. throw new DeveloperError('scene is required');
  109257. }
  109258. this._entity = entity;
  109259. this._scene = scene;
  109260. this._entitySubscription = entity.definitionChanged.addEventListener(PolylineVolumeGeometryUpdater.prototype._onEntityPropertyChanged, this);
  109261. this._fillEnabled = false;
  109262. this._dynamic = false;
  109263. this._outlineEnabled = false;
  109264. this._geometryChanged = new Event();
  109265. this._showProperty = undefined;
  109266. this._materialProperty = undefined;
  109267. this._hasConstantOutline = true;
  109268. this._showOutlineProperty = undefined;
  109269. this._outlineColorProperty = undefined;
  109270. this._outlineWidth = 1.0;
  109271. this._shadowsProperty = undefined;
  109272. this._distanceDisplayConditionProperty = undefined;
  109273. this._options = new GeometryOptions(entity);
  109274. this._onEntityPropertyChanged(entity, 'polylineVolume', entity.polylineVolume, undefined);
  109275. }
  109276. defineProperties(PolylineVolumeGeometryUpdater, {
  109277. /**
  109278. * Gets the type of appearance to use for simple color-based geometry.
  109279. * @memberof PolylineVolumeGeometryUpdater
  109280. * @type {Appearance}
  109281. */
  109282. perInstanceColorAppearanceType : {
  109283. value : PerInstanceColorAppearance
  109284. },
  109285. /**
  109286. * Gets the type of appearance to use for material-based geometry.
  109287. * @memberof PolylineVolumeGeometryUpdater
  109288. * @type {Appearance}
  109289. */
  109290. materialAppearanceType : {
  109291. value : MaterialAppearance
  109292. }
  109293. });
  109294. defineProperties(PolylineVolumeGeometryUpdater.prototype, {
  109295. /**
  109296. * Gets the entity associated with this geometry.
  109297. * @memberof PolylineVolumeGeometryUpdater.prototype
  109298. *
  109299. * @type {Entity}
  109300. * @readonly
  109301. */
  109302. entity : {
  109303. get : function() {
  109304. return this._entity;
  109305. }
  109306. },
  109307. /**
  109308. * Gets a value indicating if the geometry has a fill component.
  109309. * @memberof PolylineVolumeGeometryUpdater.prototype
  109310. *
  109311. * @type {Boolean}
  109312. * @readonly
  109313. */
  109314. fillEnabled : {
  109315. get : function() {
  109316. return this._fillEnabled;
  109317. }
  109318. },
  109319. /**
  109320. * Gets a value indicating if fill visibility varies with simulation time.
  109321. * @memberof PolylineVolumeGeometryUpdater.prototype
  109322. *
  109323. * @type {Boolean}
  109324. * @readonly
  109325. */
  109326. hasConstantFill : {
  109327. get : function() {
  109328. return !this._fillEnabled ||
  109329. (!defined(this._entity.availability) &&
  109330. Property.isConstant(this._showProperty) &&
  109331. Property.isConstant(this._fillProperty));
  109332. }
  109333. },
  109334. /**
  109335. * Gets the material property used to fill the geometry.
  109336. * @memberof PolylineVolumeGeometryUpdater.prototype
  109337. *
  109338. * @type {MaterialProperty}
  109339. * @readonly
  109340. */
  109341. fillMaterialProperty : {
  109342. get : function() {
  109343. return this._materialProperty;
  109344. }
  109345. },
  109346. /**
  109347. * Gets a value indicating if the geometry has an outline component.
  109348. * @memberof PolylineVolumeGeometryUpdater.prototype
  109349. *
  109350. * @type {Boolean}
  109351. * @readonly
  109352. */
  109353. outlineEnabled : {
  109354. get : function() {
  109355. return this._outlineEnabled;
  109356. }
  109357. },
  109358. /**
  109359. * Gets a value indicating if the geometry has an outline component.
  109360. * @memberof PolylineVolumeGeometryUpdater.prototype
  109361. *
  109362. * @type {Boolean}
  109363. * @readonly
  109364. */
  109365. hasConstantOutline : {
  109366. get : function() {
  109367. return !this._outlineEnabled ||
  109368. (!defined(this._entity.availability) &&
  109369. Property.isConstant(this._showProperty) &&
  109370. Property.isConstant(this._showOutlineProperty));
  109371. }
  109372. },
  109373. /**
  109374. * Gets the {@link Color} property for the geometry outline.
  109375. * @memberof PolylineVolumeGeometryUpdater.prototype
  109376. *
  109377. * @type {Property}
  109378. * @readonly
  109379. */
  109380. outlineColorProperty : {
  109381. get : function() {
  109382. return this._outlineColorProperty;
  109383. }
  109384. },
  109385. /**
  109386. * Gets the constant with of the geometry outline, in pixels.
  109387. * This value is only valid if isDynamic is false.
  109388. * @memberof PolylineVolumeGeometryUpdater.prototype
  109389. *
  109390. * @type {Number}
  109391. * @readonly
  109392. */
  109393. outlineWidth : {
  109394. get : function() {
  109395. return this._outlineWidth;
  109396. }
  109397. },
  109398. /**
  109399. * Gets the property specifying whether the geometry
  109400. * casts or receives shadows from each light source.
  109401. * @memberof PolylineVolumeGeometryUpdater.prototype
  109402. *
  109403. * @type {Property}
  109404. * @readonly
  109405. */
  109406. shadowsProperty : {
  109407. get : function() {
  109408. return this._shadowsProperty;
  109409. }
  109410. },
  109411. /**
  109412. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this geometry will be displayed.
  109413. * @memberof PolylineVolumeGeometryUpdater.prototype
  109414. *
  109415. * @type {Property}
  109416. * @readonly
  109417. */
  109418. distanceDisplayConditionProperty : {
  109419. get : function() {
  109420. return this._distanceDisplayConditionProperty;
  109421. }
  109422. },
  109423. /**
  109424. * Gets a value indicating if the geometry is time-varying.
  109425. * If true, all visualization is delegated to the {@link DynamicGeometryUpdater}
  109426. * returned by GeometryUpdater#createDynamicUpdater.
  109427. * @memberof PolylineVolumeGeometryUpdater.prototype
  109428. *
  109429. * @type {Boolean}
  109430. * @readonly
  109431. */
  109432. isDynamic : {
  109433. get : function() {
  109434. return this._dynamic;
  109435. }
  109436. },
  109437. /**
  109438. * Gets a value indicating if the geometry is closed.
  109439. * This property is only valid for static geometry.
  109440. * @memberof PolylineVolumeGeometryUpdater.prototype
  109441. *
  109442. * @type {Boolean}
  109443. * @readonly
  109444. */
  109445. isClosed : {
  109446. value : true
  109447. },
  109448. /**
  109449. * Gets an event that is raised whenever the public properties
  109450. * of this updater change.
  109451. * @memberof PolylineVolumeGeometryUpdater.prototype
  109452. *
  109453. * @type {Boolean}
  109454. * @readonly
  109455. */
  109456. geometryChanged : {
  109457. get : function() {
  109458. return this._geometryChanged;
  109459. }
  109460. }
  109461. });
  109462. /**
  109463. * Checks if the geometry is outlined at the provided time.
  109464. *
  109465. * @param {JulianDate} time The time for which to retrieve visibility.
  109466. * @returns {Boolean} true if geometry is outlined at the provided time, false otherwise.
  109467. */
  109468. PolylineVolumeGeometryUpdater.prototype.isOutlineVisible = function(time) {
  109469. var entity = this._entity;
  109470. return this._outlineEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time);
  109471. };
  109472. /**
  109473. * Checks if the geometry is filled at the provided time.
  109474. *
  109475. * @param {JulianDate} time The time for which to retrieve visibility.
  109476. * @returns {Boolean} true if geometry is filled at the provided time, false otherwise.
  109477. */
  109478. PolylineVolumeGeometryUpdater.prototype.isFilled = function(time) {
  109479. var entity = this._entity;
  109480. return this._fillEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._fillProperty.getValue(time);
  109481. };
  109482. /**
  109483. * Creates the geometry instance which represents the fill of the geometry.
  109484. *
  109485. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  109486. * @returns {GeometryInstance} The geometry instance representing the filled portion of the geometry.
  109487. *
  109488. * @exception {DeveloperError} This instance does not represent a filled geometry.
  109489. */
  109490. PolylineVolumeGeometryUpdater.prototype.createFillGeometryInstance = function(time) {
  109491. if (!defined(time)) {
  109492. throw new DeveloperError('time is required.');
  109493. }
  109494. if (!this._fillEnabled) {
  109495. throw new DeveloperError('This instance does not represent a filled geometry.');
  109496. }
  109497. var entity = this._entity;
  109498. var isAvailable = entity.isAvailable(time);
  109499. var attributes;
  109500. var color;
  109501. var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time));
  109502. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  109503. var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
  109504. if (this._materialProperty instanceof ColorMaterialProperty) {
  109505. var currentColor = Color.WHITE;
  109506. if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) {
  109507. currentColor = this._materialProperty.color.getValue(time);
  109508. }
  109509. color = ColorGeometryInstanceAttribute.fromColor(currentColor);
  109510. attributes = {
  109511. show : show,
  109512. distanceDisplayCondition : distanceDisplayConditionAttribute,
  109513. color : color
  109514. };
  109515. } else {
  109516. attributes = {
  109517. show : show,
  109518. distanceDisplayCondition : distanceDisplayConditionAttribute
  109519. };
  109520. }
  109521. return new GeometryInstance({
  109522. id : entity,
  109523. geometry : new PolylineVolumeGeometry(this._options),
  109524. attributes : attributes
  109525. });
  109526. };
  109527. /**
  109528. * Creates the geometry instance which represents the outline of the geometry.
  109529. *
  109530. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  109531. * @returns {GeometryInstance} The geometry instance representing the outline portion of the geometry.
  109532. *
  109533. * @exception {DeveloperError} This instance does not represent an outlined geometry.
  109534. */
  109535. PolylineVolumeGeometryUpdater.prototype.createOutlineGeometryInstance = function(time) {
  109536. if (!defined(time)) {
  109537. throw new DeveloperError('time is required.');
  109538. }
  109539. if (!this._outlineEnabled) {
  109540. throw new DeveloperError('This instance does not represent an outlined geometry.');
  109541. }
  109542. var entity = this._entity;
  109543. var isAvailable = entity.isAvailable(time);
  109544. var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK);
  109545. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  109546. return new GeometryInstance({
  109547. id : entity,
  109548. geometry : new PolylineVolumeOutlineGeometry(this._options),
  109549. attributes : {
  109550. show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
  109551. color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
  109552. distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition)
  109553. }
  109554. });
  109555. };
  109556. /**
  109557. * Returns true if this object was destroyed; otherwise, false.
  109558. *
  109559. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  109560. */
  109561. PolylineVolumeGeometryUpdater.prototype.isDestroyed = function() {
  109562. return false;
  109563. };
  109564. /**
  109565. * Destroys and resources used by the object. Once an object is destroyed, it should not be used.
  109566. *
  109567. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  109568. */
  109569. PolylineVolumeGeometryUpdater.prototype.destroy = function() {
  109570. this._entitySubscription();
  109571. destroyObject(this);
  109572. };
  109573. PolylineVolumeGeometryUpdater.prototype._onEntityPropertyChanged = function(entity, propertyName, newValue, oldValue) {
  109574. if (!(propertyName === 'availability' || propertyName === 'polylineVolume')) {
  109575. return;
  109576. }
  109577. var polylineVolume = this._entity.polylineVolume;
  109578. if (!defined(polylineVolume)) {
  109579. if (this._fillEnabled || this._outlineEnabled) {
  109580. this._fillEnabled = false;
  109581. this._outlineEnabled = false;
  109582. this._geometryChanged.raiseEvent(this);
  109583. }
  109584. return;
  109585. }
  109586. var fillProperty = polylineVolume.fill;
  109587. var fillEnabled = defined(fillProperty) && fillProperty.isConstant ? fillProperty.getValue(Iso8601.MINIMUM_VALUE) : true;
  109588. var outlineProperty = polylineVolume.outline;
  109589. var outlineEnabled = defined(outlineProperty);
  109590. if (outlineEnabled && outlineProperty.isConstant) {
  109591. outlineEnabled = outlineProperty.getValue(Iso8601.MINIMUM_VALUE);
  109592. }
  109593. if (!fillEnabled && !outlineEnabled) {
  109594. if (this._fillEnabled || this._outlineEnabled) {
  109595. this._fillEnabled = false;
  109596. this._outlineEnabled = false;
  109597. this._geometryChanged.raiseEvent(this);
  109598. }
  109599. return;
  109600. }
  109601. var positions = polylineVolume.positions;
  109602. var shape = polylineVolume.shape;
  109603. var show = polylineVolume.show;
  109604. if (!defined(positions) || !defined(shape) || (defined(show) && show.isConstant && !show.getValue(Iso8601.MINIMUM_VALUE))) {
  109605. if (this._fillEnabled || this._outlineEnabled) {
  109606. this._fillEnabled = false;
  109607. this._outlineEnabled = false;
  109608. this._geometryChanged.raiseEvent(this);
  109609. }
  109610. return;
  109611. }
  109612. var material = defaultValue(polylineVolume.material, defaultMaterial);
  109613. var isColorMaterial = material instanceof ColorMaterialProperty;
  109614. this._materialProperty = material;
  109615. this._fillProperty = defaultValue(fillProperty, defaultFill);
  109616. this._showProperty = defaultValue(show, defaultShow);
  109617. this._showOutlineProperty = defaultValue(polylineVolume.outline, defaultOutline);
  109618. this._outlineColorProperty = outlineEnabled ? defaultValue(polylineVolume.outlineColor, defaultOutlineColor) : undefined;
  109619. this._shadowsProperty = defaultValue(polylineVolume.shadows, defaultShadows);
  109620. this._distanceDisplayConditionProperty = defaultValue(polylineVolume.distanceDisplayCondition, defaultDistanceDisplayCondition);
  109621. var granularity = polylineVolume.granularity;
  109622. var outlineWidth = polylineVolume.outlineWidth;
  109623. var cornerType = polylineVolume.cornerType;
  109624. this._fillEnabled = fillEnabled;
  109625. this._outlineEnabled = outlineEnabled;
  109626. if (!positions.isConstant || //
  109627. !shape.isConstant || //
  109628. !Property.isConstant(granularity) || //
  109629. !Property.isConstant(outlineWidth) || //
  109630. !Property.isConstant(cornerType)) {
  109631. if (!this._dynamic) {
  109632. this._dynamic = true;
  109633. this._geometryChanged.raiseEvent(this);
  109634. }
  109635. } else {
  109636. var options = this._options;
  109637. options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat;
  109638. options.polylinePositions = positions.getValue(Iso8601.MINIMUM_VALUE, options.polylinePositions);
  109639. options.shapePositions = shape.getValue(Iso8601.MINIMUM_VALUE, options.shape);
  109640. options.granularity = defined(granularity) ? granularity.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  109641. options.cornerType = defined(cornerType) ? cornerType.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  109642. this._outlineWidth = defined(outlineWidth) ? outlineWidth.getValue(Iso8601.MINIMUM_VALUE) : 1.0;
  109643. this._dynamic = false;
  109644. this._geometryChanged.raiseEvent(this);
  109645. }
  109646. };
  109647. /**
  109648. * Creates the dynamic updater to be used when GeometryUpdater#isDynamic is true.
  109649. *
  109650. * @param {PrimitiveCollection} primitives The primitive collection to use.
  109651. * @returns {DynamicGeometryUpdater} The dynamic updater used to update the geometry each frame.
  109652. *
  109653. * @exception {DeveloperError} This instance does not represent dynamic geometry.
  109654. */
  109655. PolylineVolumeGeometryUpdater.prototype.createDynamicUpdater = function(primitives) {
  109656. if (!this._dynamic) {
  109657. throw new DeveloperError('This instance does not represent dynamic geometry.');
  109658. }
  109659. if (!defined(primitives)) {
  109660. throw new DeveloperError('primitives is required.');
  109661. }
  109662. return new DynamicGeometryUpdater(primitives, this);
  109663. };
  109664. /**
  109665. * @private
  109666. */
  109667. function DynamicGeometryUpdater(primitives, geometryUpdater) {
  109668. this._primitives = primitives;
  109669. this._primitive = undefined;
  109670. this._outlinePrimitive = undefined;
  109671. this._geometryUpdater = geometryUpdater;
  109672. this._options = new GeometryOptions(geometryUpdater._entity);
  109673. }
  109674. DynamicGeometryUpdater.prototype.update = function(time) {
  109675. if (!defined(time)) {
  109676. throw new DeveloperError('time is required.');
  109677. }
  109678. var primitives = this._primitives;
  109679. primitives.removeAndDestroy(this._primitive);
  109680. primitives.removeAndDestroy(this._outlinePrimitive);
  109681. this._primitive = undefined;
  109682. this._outlinePrimitive = undefined;
  109683. var geometryUpdater = this._geometryUpdater;
  109684. var entity = geometryUpdater._entity;
  109685. var polylineVolume = entity.polylineVolume;
  109686. if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(polylineVolume.show, time, true)) {
  109687. return;
  109688. }
  109689. var options = this._options;
  109690. var positions = Property.getValueOrUndefined(polylineVolume.positions, time, options.polylinePositions);
  109691. var shape = Property.getValueOrUndefined(polylineVolume.shape, time);
  109692. if (!defined(positions) || !defined(shape)) {
  109693. return;
  109694. }
  109695. options.polylinePositions = positions;
  109696. options.shapePositions = shape;
  109697. options.granularity = Property.getValueOrUndefined(polylineVolume.granularity, time);
  109698. options.cornerType = Property.getValueOrUndefined(polylineVolume.cornerType, time);
  109699. var shadows = this._geometryUpdater.shadowsProperty.getValue(time);
  109700. if (!defined(polylineVolume.fill) || polylineVolume.fill.getValue(time)) {
  109701. var material = MaterialProperty.getValue(time, geometryUpdater.fillMaterialProperty, this._material);
  109702. this._material = material;
  109703. var appearance = new MaterialAppearance({
  109704. material : material,
  109705. translucent : material.isTranslucent(),
  109706. closed : true
  109707. });
  109708. options.vertexFormat = appearance.vertexFormat;
  109709. this._primitive = primitives.add(new Primitive({
  109710. geometryInstances : new GeometryInstance({
  109711. id : entity,
  109712. geometry : new PolylineVolumeGeometry(options)
  109713. }),
  109714. appearance : appearance,
  109715. asynchronous : false,
  109716. shadows : shadows
  109717. }));
  109718. }
  109719. if (defined(polylineVolume.outline) && polylineVolume.outline.getValue(time)) {
  109720. options.vertexFormat = PerInstanceColorAppearance.VERTEX_FORMAT;
  109721. var outlineColor = Property.getValueOrClonedDefault(polylineVolume.outlineColor, time, Color.BLACK, scratchColor);
  109722. var outlineWidth = Property.getValueOrDefault(polylineVolume.outlineWidth, time, 1.0);
  109723. var translucent = outlineColor.alpha !== 1.0;
  109724. this._outlinePrimitive = primitives.add(new Primitive({
  109725. geometryInstances : new GeometryInstance({
  109726. id : entity,
  109727. geometry : new PolylineVolumeOutlineGeometry(options),
  109728. attributes : {
  109729. color : ColorGeometryInstanceAttribute.fromColor(outlineColor)
  109730. }
  109731. }),
  109732. appearance : new PerInstanceColorAppearance({
  109733. flat : true,
  109734. translucent : translucent,
  109735. renderState : {
  109736. lineWidth : geometryUpdater._scene.clampLineWidth(outlineWidth)
  109737. }
  109738. }),
  109739. asynchronous : false,
  109740. shadows : shadows
  109741. }));
  109742. }
  109743. };
  109744. DynamicGeometryUpdater.prototype.getBoundingSphere = function(entity, result) {
  109745. return dynamicGeometryGetBoundingSphere(entity, this._primitive, this._outlinePrimitive, result);
  109746. };
  109747. DynamicGeometryUpdater.prototype.isDestroyed = function() {
  109748. return false;
  109749. };
  109750. DynamicGeometryUpdater.prototype.destroy = function() {
  109751. var primitives = this._primitives;
  109752. primitives.removeAndDestroy(this._primitive);
  109753. primitives.removeAndDestroy(this._outlinePrimitive);
  109754. destroyObject(this);
  109755. };
  109756. return PolylineVolumeGeometryUpdater;
  109757. });
  109758. /*global define*/
  109759. define('DataSources/RectangleGeometryUpdater',[
  109760. '../Core/Color',
  109761. '../Core/ColorGeometryInstanceAttribute',
  109762. '../Core/defaultValue',
  109763. '../Core/defined',
  109764. '../Core/defineProperties',
  109765. '../Core/destroyObject',
  109766. '../Core/DeveloperError',
  109767. '../Core/DistanceDisplayCondition',
  109768. '../Core/DistanceDisplayConditionGeometryInstanceAttribute',
  109769. '../Core/Event',
  109770. '../Core/GeometryInstance',
  109771. '../Core/Iso8601',
  109772. '../Core/oneTimeWarning',
  109773. '../Core/RectangleGeometry',
  109774. '../Core/RectangleOutlineGeometry',
  109775. '../Core/ShowGeometryInstanceAttribute',
  109776. '../Scene/GroundPrimitive',
  109777. '../Scene/MaterialAppearance',
  109778. '../Scene/PerInstanceColorAppearance',
  109779. '../Scene/Primitive',
  109780. '../Scene/ShadowMode',
  109781. './ColorMaterialProperty',
  109782. './ConstantProperty',
  109783. './dynamicGeometryGetBoundingSphere',
  109784. './MaterialProperty',
  109785. './Property'
  109786. ], function(
  109787. Color,
  109788. ColorGeometryInstanceAttribute,
  109789. defaultValue,
  109790. defined,
  109791. defineProperties,
  109792. destroyObject,
  109793. DeveloperError,
  109794. DistanceDisplayCondition,
  109795. DistanceDisplayConditionGeometryInstanceAttribute,
  109796. Event,
  109797. GeometryInstance,
  109798. Iso8601,
  109799. oneTimeWarning,
  109800. RectangleGeometry,
  109801. RectangleOutlineGeometry,
  109802. ShowGeometryInstanceAttribute,
  109803. GroundPrimitive,
  109804. MaterialAppearance,
  109805. PerInstanceColorAppearance,
  109806. Primitive,
  109807. ShadowMode,
  109808. ColorMaterialProperty,
  109809. ConstantProperty,
  109810. dynamicGeometryGetBoundingSphere,
  109811. MaterialProperty,
  109812. Property) {
  109813. 'use strict';
  109814. var defaultMaterial = new ColorMaterialProperty(Color.WHITE);
  109815. var defaultShow = new ConstantProperty(true);
  109816. var defaultFill = new ConstantProperty(true);
  109817. var defaultOutline = new ConstantProperty(false);
  109818. var defaultOutlineColor = new ConstantProperty(Color.BLACK);
  109819. var defaultShadows = new ConstantProperty(ShadowMode.DISABLED);
  109820. var defaultDistanceDisplayCondition = new ConstantProperty(new DistanceDisplayCondition());
  109821. var scratchColor = new Color();
  109822. function GeometryOptions(entity) {
  109823. this.id = entity;
  109824. this.vertexFormat = undefined;
  109825. this.rectangle = undefined;
  109826. this.closeBottom = undefined;
  109827. this.closeTop = undefined;
  109828. this.height = undefined;
  109829. this.extrudedHeight = undefined;
  109830. this.granularity = undefined;
  109831. this.stRotation = undefined;
  109832. this.rotation = undefined;
  109833. }
  109834. /**
  109835. * A {@link GeometryUpdater} for rectangles.
  109836. * Clients do not normally create this class directly, but instead rely on {@link DataSourceDisplay}.
  109837. * @alias RectangleGeometryUpdater
  109838. * @constructor
  109839. *
  109840. * @param {Entity} entity The entity containing the geometry to be visualized.
  109841. * @param {Scene} scene The scene where visualization is taking place.
  109842. */
  109843. function RectangleGeometryUpdater(entity, scene) {
  109844. if (!defined(entity)) {
  109845. throw new DeveloperError('entity is required');
  109846. }
  109847. if (!defined(scene)) {
  109848. throw new DeveloperError('scene is required');
  109849. }
  109850. this._entity = entity;
  109851. this._scene = scene;
  109852. this._entitySubscription = entity.definitionChanged.addEventListener(RectangleGeometryUpdater.prototype._onEntityPropertyChanged, this);
  109853. this._fillEnabled = false;
  109854. this._isClosed = false;
  109855. this._dynamic = false;
  109856. this._outlineEnabled = false;
  109857. this._geometryChanged = new Event();
  109858. this._showProperty = undefined;
  109859. this._materialProperty = undefined;
  109860. this._hasConstantOutline = true;
  109861. this._showOutlineProperty = undefined;
  109862. this._outlineColorProperty = undefined;
  109863. this._outlineWidth = 1.0;
  109864. this._shadowsProperty = undefined;
  109865. this._distanceDisplayConditionProperty = undefined;
  109866. this._onTerrain = false;
  109867. this._options = new GeometryOptions(entity);
  109868. this._onEntityPropertyChanged(entity, 'rectangle', entity.rectangle, undefined);
  109869. }
  109870. defineProperties(RectangleGeometryUpdater, {
  109871. /**
  109872. * Gets the type of Appearance to use for simple color-based geometry.
  109873. * @memberof RectangleGeometryUpdater
  109874. * @type {Appearance}
  109875. */
  109876. perInstanceColorAppearanceType : {
  109877. value : PerInstanceColorAppearance
  109878. },
  109879. /**
  109880. * Gets the type of Appearance to use for material-based geometry.
  109881. * @memberof RectangleGeometryUpdater
  109882. * @type {Appearance}
  109883. */
  109884. materialAppearanceType : {
  109885. value : MaterialAppearance
  109886. }
  109887. });
  109888. defineProperties(RectangleGeometryUpdater.prototype, {
  109889. /**
  109890. * Gets the entity associated with this geometry.
  109891. * @memberof RectangleGeometryUpdater.prototype
  109892. *
  109893. * @type {Entity}
  109894. * @readonly
  109895. */
  109896. entity : {
  109897. get : function() {
  109898. return this._entity;
  109899. }
  109900. },
  109901. /**
  109902. * Gets a value indicating if the geometry has a fill component.
  109903. * @memberof RectangleGeometryUpdater.prototype
  109904. *
  109905. * @type {Boolean}
  109906. * @readonly
  109907. */
  109908. fillEnabled : {
  109909. get : function() {
  109910. return this._fillEnabled;
  109911. }
  109912. },
  109913. /**
  109914. * Gets a value indicating if fill visibility varies with simulation time.
  109915. * @memberof RectangleGeometryUpdater.prototype
  109916. *
  109917. * @type {Boolean}
  109918. * @readonly
  109919. */
  109920. hasConstantFill : {
  109921. get : function() {
  109922. return !this._fillEnabled ||
  109923. (!defined(this._entity.availability) &&
  109924. Property.isConstant(this._showProperty) &&
  109925. Property.isConstant(this._fillProperty));
  109926. }
  109927. },
  109928. /**
  109929. * Gets the material property used to fill the geometry.
  109930. * @memberof RectangleGeometryUpdater.prototype
  109931. *
  109932. * @type {MaterialProperty}
  109933. * @readonly
  109934. */
  109935. fillMaterialProperty : {
  109936. get : function() {
  109937. return this._materialProperty;
  109938. }
  109939. },
  109940. /**
  109941. * Gets a value indicating if the geometry has an outline component.
  109942. * @memberof RectangleGeometryUpdater.prototype
  109943. *
  109944. * @type {Boolean}
  109945. * @readonly
  109946. */
  109947. outlineEnabled : {
  109948. get : function() {
  109949. return this._outlineEnabled;
  109950. }
  109951. },
  109952. /**
  109953. * Gets a value indicating if the geometry has an outline component.
  109954. * @memberof RectangleGeometryUpdater.prototype
  109955. *
  109956. * @type {Boolean}
  109957. * @readonly
  109958. */
  109959. hasConstantOutline : {
  109960. get : function() {
  109961. return !this._outlineEnabled ||
  109962. (!defined(this._entity.availability) &&
  109963. Property.isConstant(this._showProperty) &&
  109964. Property.isConstant(this._showOutlineProperty));
  109965. }
  109966. },
  109967. /**
  109968. * Gets the {@link Color} property for the geometry outline.
  109969. * @memberof RectangleGeometryUpdater.prototype
  109970. *
  109971. * @type {Property}
  109972. * @readonly
  109973. */
  109974. outlineColorProperty : {
  109975. get : function() {
  109976. return this._outlineColorProperty;
  109977. }
  109978. },
  109979. /**
  109980. * Gets the constant with of the geometry outline, in pixels.
  109981. * This value is only valid if isDynamic is false.
  109982. * @memberof RectangleGeometryUpdater.prototype
  109983. *
  109984. * @type {Number}
  109985. * @readonly
  109986. */
  109987. outlineWidth : {
  109988. get : function() {
  109989. return this._outlineWidth;
  109990. }
  109991. },
  109992. /**
  109993. * Gets the property specifying whether the geometry
  109994. * casts or receives shadows from each light source.
  109995. * @memberof RectangleGeometryUpdater.prototype
  109996. *
  109997. * @type {Property}
  109998. * @readonly
  109999. */
  110000. shadowsProperty : {
  110001. get : function() {
  110002. return this._shadowsProperty;
  110003. }
  110004. },
  110005. /**
  110006. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this geometry will be displayed.
  110007. * @memberof RectangleGeometryUpdater.prototype
  110008. *
  110009. * @type {Property}
  110010. * @readonly
  110011. */
  110012. distanceDisplayConditionProperty : {
  110013. get : function() {
  110014. return this._distanceDisplayConditionProperty;
  110015. }
  110016. },
  110017. /**
  110018. * Gets a value indicating if the geometry is time-varying.
  110019. * If true, all visualization is delegated to the {@link DynamicGeometryUpdater}
  110020. * returned by GeometryUpdater#createDynamicUpdater.
  110021. * @memberof RectangleGeometryUpdater.prototype
  110022. *
  110023. * @type {Boolean}
  110024. * @readonly
  110025. */
  110026. isDynamic : {
  110027. get : function() {
  110028. return this._dynamic;
  110029. }
  110030. },
  110031. /**
  110032. * Gets a value indicating if the geometry is closed.
  110033. * This property is only valid for static geometry.
  110034. * @memberof RectangleGeometryUpdater.prototype
  110035. *
  110036. * @type {Boolean}
  110037. * @readonly
  110038. */
  110039. isClosed : {
  110040. get : function() {
  110041. return this._isClosed;
  110042. }
  110043. },
  110044. /**
  110045. * Gets a value indicating if the geometry should be drawn on terrain.
  110046. * @memberof RectangleGeometryUpdater.prototype
  110047. *
  110048. * @type {Boolean}
  110049. * @readonly
  110050. */
  110051. onTerrain : {
  110052. get : function() {
  110053. return this._onTerrain;
  110054. }
  110055. },
  110056. /**
  110057. * Gets an event that is raised whenever the public properties
  110058. * of this updater change.
  110059. * @memberof RectangleGeometryUpdater.prototype
  110060. *
  110061. * @type {Boolean}
  110062. * @readonly
  110063. */
  110064. geometryChanged : {
  110065. get : function() {
  110066. return this._geometryChanged;
  110067. }
  110068. }
  110069. });
  110070. /**
  110071. * Checks if the geometry is outlined at the provided time.
  110072. *
  110073. * @param {JulianDate} time The time for which to retrieve visibility.
  110074. * @returns {Boolean} true if geometry is outlined at the provided time, false otherwise.
  110075. */
  110076. RectangleGeometryUpdater.prototype.isOutlineVisible = function(time) {
  110077. var entity = this._entity;
  110078. return this._outlineEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time);
  110079. };
  110080. /**
  110081. * Checks if the geometry is filled at the provided time.
  110082. *
  110083. * @param {JulianDate} time The time for which to retrieve visibility.
  110084. * @returns {Boolean} true if geometry is filled at the provided time, false otherwise.
  110085. */
  110086. RectangleGeometryUpdater.prototype.isFilled = function(time) {
  110087. var entity = this._entity;
  110088. return this._fillEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._fillProperty.getValue(time);
  110089. };
  110090. /**
  110091. * Creates the geometry instance which represents the fill of the geometry.
  110092. *
  110093. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  110094. * @returns {GeometryInstance} The geometry instance representing the filled portion of the geometry.
  110095. *
  110096. * @exception {DeveloperError} This instance does not represent a filled geometry.
  110097. */
  110098. RectangleGeometryUpdater.prototype.createFillGeometryInstance = function(time) {
  110099. if (!defined(time)) {
  110100. throw new DeveloperError('time is required.');
  110101. }
  110102. if (!this._fillEnabled) {
  110103. throw new DeveloperError('This instance does not represent a filled geometry.');
  110104. }
  110105. var entity = this._entity;
  110106. var isAvailable = entity.isAvailable(time);
  110107. var attributes;
  110108. var color;
  110109. var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time));
  110110. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  110111. var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
  110112. if (this._materialProperty instanceof ColorMaterialProperty) {
  110113. var currentColor = Color.WHITE;
  110114. if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) {
  110115. currentColor = this._materialProperty.color.getValue(time);
  110116. }
  110117. color = ColorGeometryInstanceAttribute.fromColor(currentColor);
  110118. attributes = {
  110119. show : show,
  110120. distanceDisplayCondition : distanceDisplayConditionAttribute,
  110121. color : color
  110122. };
  110123. } else {
  110124. attributes = {
  110125. show : show,
  110126. distanceDisplayCondition : distanceDisplayConditionAttribute
  110127. };
  110128. }
  110129. return new GeometryInstance({
  110130. id : entity,
  110131. geometry : new RectangleGeometry(this._options),
  110132. attributes : attributes
  110133. });
  110134. };
  110135. /**
  110136. * Creates the geometry instance which represents the outline of the geometry.
  110137. *
  110138. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  110139. * @returns {GeometryInstance} The geometry instance representing the outline portion of the geometry.
  110140. *
  110141. * @exception {DeveloperError} This instance does not represent an outlined geometry.
  110142. */
  110143. RectangleGeometryUpdater.prototype.createOutlineGeometryInstance = function(time) {
  110144. if (!defined(time)) {
  110145. throw new DeveloperError('time is required.');
  110146. }
  110147. if (!this._outlineEnabled) {
  110148. throw new DeveloperError('This instance does not represent an outlined geometry.');
  110149. }
  110150. var entity = this._entity;
  110151. var isAvailable = entity.isAvailable(time);
  110152. var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK);
  110153. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  110154. return new GeometryInstance({
  110155. id : entity,
  110156. geometry : new RectangleOutlineGeometry(this._options),
  110157. attributes : {
  110158. show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
  110159. color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
  110160. distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition)
  110161. }
  110162. });
  110163. };
  110164. /**
  110165. * Returns true if this object was destroyed; otherwise, false.
  110166. *
  110167. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  110168. */
  110169. RectangleGeometryUpdater.prototype.isDestroyed = function() {
  110170. return false;
  110171. };
  110172. /**
  110173. * Destroys and resources used by the object. Once an object is destroyed, it should not be used.
  110174. *
  110175. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  110176. */
  110177. RectangleGeometryUpdater.prototype.destroy = function() {
  110178. this._entitySubscription();
  110179. destroyObject(this);
  110180. };
  110181. RectangleGeometryUpdater.prototype._onEntityPropertyChanged = function(entity, propertyName, newValue, oldValue) {
  110182. if (!(propertyName === 'availability' || propertyName === 'rectangle')) {
  110183. return;
  110184. }
  110185. var rectangle = this._entity.rectangle;
  110186. if (!defined(rectangle)) {
  110187. if (this._fillEnabled || this._outlineEnabled) {
  110188. this._fillEnabled = false;
  110189. this._outlineEnabled = false;
  110190. this._geometryChanged.raiseEvent(this);
  110191. }
  110192. return;
  110193. }
  110194. var fillProperty = rectangle.fill;
  110195. var fillEnabled = defined(fillProperty) && fillProperty.isConstant ? fillProperty.getValue(Iso8601.MINIMUM_VALUE) : true;
  110196. var outlineProperty = rectangle.outline;
  110197. var outlineEnabled = defined(outlineProperty);
  110198. if (outlineEnabled && outlineProperty.isConstant) {
  110199. outlineEnabled = outlineProperty.getValue(Iso8601.MINIMUM_VALUE);
  110200. }
  110201. if (!fillEnabled && !outlineEnabled) {
  110202. if (this._fillEnabled || this._outlineEnabled) {
  110203. this._fillEnabled = false;
  110204. this._outlineEnabled = false;
  110205. this._geometryChanged.raiseEvent(this);
  110206. }
  110207. return;
  110208. }
  110209. var coordinates = rectangle.coordinates;
  110210. var show = rectangle.show;
  110211. if ((defined(show) && show.isConstant && !show.getValue(Iso8601.MINIMUM_VALUE)) || //
  110212. (!defined(coordinates))) {
  110213. if (this._fillEnabled || this._outlineEnabled) {
  110214. this._fillEnabled = false;
  110215. this._outlineEnabled = false;
  110216. this._geometryChanged.raiseEvent(this);
  110217. }
  110218. return;
  110219. }
  110220. var material = defaultValue(rectangle.material, defaultMaterial);
  110221. var isColorMaterial = material instanceof ColorMaterialProperty;
  110222. this._materialProperty = material;
  110223. this._fillProperty = defaultValue(fillProperty, defaultFill);
  110224. this._showProperty = defaultValue(show, defaultShow);
  110225. this._showOutlineProperty = defaultValue(rectangle.outline, defaultOutline);
  110226. this._outlineColorProperty = outlineEnabled ? defaultValue(rectangle.outlineColor, defaultOutlineColor) : undefined;
  110227. this._shadowsProperty = defaultValue(rectangle.shadows, defaultShadows);
  110228. this._distanceDisplayConditionProperty = defaultValue(rectangle.distanceDisplayCondition, defaultDistanceDisplayCondition);
  110229. var height = rectangle.height;
  110230. var extrudedHeight = rectangle.extrudedHeight;
  110231. var granularity = rectangle.granularity;
  110232. var stRotation = rectangle.stRotation;
  110233. var rotation = rectangle.rotation;
  110234. var outlineWidth = rectangle.outlineWidth;
  110235. var closeBottom = rectangle.closeBottom;
  110236. var closeTop = rectangle.closeTop;
  110237. var onTerrain = fillEnabled && !defined(height) && !defined(extrudedHeight) &&
  110238. isColorMaterial && GroundPrimitive.isSupported(this._scene);
  110239. if (outlineEnabled && onTerrain) {
  110240. oneTimeWarning(oneTimeWarning.geometryOutlines);
  110241. outlineEnabled = false;
  110242. }
  110243. this._fillEnabled = fillEnabled;
  110244. this._onTerrain = onTerrain;
  110245. this._outlineEnabled = outlineEnabled;
  110246. if (!coordinates.isConstant || //
  110247. !Property.isConstant(height) || //
  110248. !Property.isConstant(extrudedHeight) || //
  110249. !Property.isConstant(granularity) || //
  110250. !Property.isConstant(stRotation) || //
  110251. !Property.isConstant(rotation) || //
  110252. !Property.isConstant(outlineWidth) || //
  110253. !Property.isConstant(closeBottom) || //
  110254. !Property.isConstant(closeTop) || //
  110255. (onTerrain && !Property.isConstant(material))) {
  110256. if (!this._dynamic) {
  110257. this._dynamic = true;
  110258. this._geometryChanged.raiseEvent(this);
  110259. }
  110260. } else {
  110261. var options = this._options;
  110262. options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat;
  110263. options.rectangle = coordinates.getValue(Iso8601.MINIMUM_VALUE, options.rectangle);
  110264. options.height = defined(height) ? height.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  110265. options.extrudedHeight = defined(extrudedHeight) ? extrudedHeight.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  110266. options.granularity = defined(granularity) ? granularity.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  110267. options.stRotation = defined(stRotation) ? stRotation.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  110268. options.rotation = defined(rotation) ? rotation.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  110269. options.closeBottom = defined(closeBottom) ? closeBottom.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  110270. options.closeTop = defined(closeTop) ? closeTop.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  110271. this._isClosed = defined(extrudedHeight) && defined(options.closeTop) && defined(options.closeBottom) && options.closeTop && options.closeBottom;
  110272. this._outlineWidth = defined(outlineWidth) ? outlineWidth.getValue(Iso8601.MINIMUM_VALUE) : 1.0;
  110273. this._dynamic = false;
  110274. this._geometryChanged.raiseEvent(this);
  110275. }
  110276. };
  110277. /**
  110278. * Creates the dynamic updater to be used when GeometryUpdater#isDynamic is true.
  110279. *
  110280. * @param {PrimitiveCollection} primitives The primitive collection to use.
  110281. * @param {PrimitiveCollection} groundPrimitives The primitive collection to use for GroundPrimitives.
  110282. * @returns {DynamicGeometryUpdater} The dynamic updater used to update the geometry each frame.
  110283. *
  110284. * @exception {DeveloperError} This instance does not represent dynamic geometry.
  110285. */
  110286. RectangleGeometryUpdater.prototype.createDynamicUpdater = function(primitives, groundPrimitives) {
  110287. if (!this._dynamic) {
  110288. throw new DeveloperError('This instance does not represent dynamic geometry.');
  110289. }
  110290. if (!defined(primitives)) {
  110291. throw new DeveloperError('primitives is required.');
  110292. }
  110293. return new DynamicGeometryUpdater(primitives, groundPrimitives, this);
  110294. };
  110295. /**
  110296. * @private
  110297. */
  110298. function DynamicGeometryUpdater(primitives, groundPrimitives, geometryUpdater) {
  110299. this._primitives = primitives;
  110300. this._groundPrimitives = groundPrimitives;
  110301. this._primitive = undefined;
  110302. this._outlinePrimitive = undefined;
  110303. this._geometryUpdater = geometryUpdater;
  110304. this._options = new GeometryOptions(geometryUpdater._entity);
  110305. }
  110306. DynamicGeometryUpdater.prototype.update = function(time) {
  110307. if (!defined(time)) {
  110308. throw new DeveloperError('time is required.');
  110309. }
  110310. var geometryUpdater = this._geometryUpdater;
  110311. var onTerrain = geometryUpdater._onTerrain;
  110312. var primitives = this._primitives;
  110313. var groundPrimitives = this._groundPrimitives;
  110314. if (onTerrain) {
  110315. groundPrimitives.removeAndDestroy(this._primitive);
  110316. } else {
  110317. primitives.removeAndDestroy(this._primitive);
  110318. primitives.removeAndDestroy(this._outlinePrimitive);
  110319. this._outlinePrimitive = undefined;
  110320. }
  110321. this._primitive = undefined;
  110322. var entity = geometryUpdater._entity;
  110323. var rectangle = entity.rectangle;
  110324. if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(rectangle.show, time, true)) {
  110325. return;
  110326. }
  110327. var options = this._options;
  110328. var coordinates = Property.getValueOrUndefined(rectangle.coordinates, time, options.rectangle);
  110329. if (!defined(coordinates)) {
  110330. return;
  110331. }
  110332. options.rectangle = coordinates;
  110333. options.height = Property.getValueOrUndefined(rectangle.height, time);
  110334. options.extrudedHeight = Property.getValueOrUndefined(rectangle.extrudedHeight, time);
  110335. options.granularity = Property.getValueOrUndefined(rectangle.granularity, time);
  110336. options.stRotation = Property.getValueOrUndefined(rectangle.stRotation, time);
  110337. options.rotation = Property.getValueOrUndefined(rectangle.rotation, time);
  110338. options.closeBottom = Property.getValueOrUndefined(rectangle.closeBottom, time);
  110339. options.closeTop = Property.getValueOrUndefined(rectangle.closeTop, time);
  110340. var shadows = this._geometryUpdater.shadowsProperty.getValue(time);
  110341. if (Property.getValueOrDefault(rectangle.fill, time, true)) {
  110342. var fillMaterialProperty = geometryUpdater.fillMaterialProperty;
  110343. var material = MaterialProperty.getValue(time, fillMaterialProperty, this._material);
  110344. this._material = material;
  110345. if (onTerrain) {
  110346. var currentColor = Color.WHITE;
  110347. if (defined(fillMaterialProperty.color)) {
  110348. currentColor = fillMaterialProperty.color.getValue(time);
  110349. }
  110350. this._primitive = groundPrimitives.add(new GroundPrimitive({
  110351. geometryInstances : new GeometryInstance({
  110352. id : entity,
  110353. geometry : new RectangleGeometry(options),
  110354. attributes: {
  110355. color: ColorGeometryInstanceAttribute.fromColor(currentColor)
  110356. }
  110357. }),
  110358. asynchronous : false,
  110359. shadows : shadows
  110360. }));
  110361. } else {
  110362. var appearance = new MaterialAppearance({
  110363. material : material,
  110364. translucent : material.isTranslucent(),
  110365. closed : defined(options.extrudedHeight)
  110366. });
  110367. options.vertexFormat = appearance.vertexFormat;
  110368. this._primitive = primitives.add(new Primitive({
  110369. geometryInstances : new GeometryInstance({
  110370. id : entity,
  110371. geometry : new RectangleGeometry(options)
  110372. }),
  110373. appearance : appearance,
  110374. asynchronous : false,
  110375. shadows : shadows
  110376. }));
  110377. }
  110378. }
  110379. if (!onTerrain && Property.getValueOrDefault(rectangle.outline, time, false)) {
  110380. options.vertexFormat = PerInstanceColorAppearance.VERTEX_FORMAT;
  110381. var outlineColor = Property.getValueOrClonedDefault(rectangle.outlineColor, time, Color.BLACK, scratchColor);
  110382. var outlineWidth = Property.getValueOrDefault(rectangle.outlineWidth, time, 1.0);
  110383. var translucent = outlineColor.alpha !== 1.0;
  110384. this._outlinePrimitive = primitives.add(new Primitive({
  110385. geometryInstances : new GeometryInstance({
  110386. id : entity,
  110387. geometry : new RectangleOutlineGeometry(options),
  110388. attributes : {
  110389. color : ColorGeometryInstanceAttribute.fromColor(outlineColor)
  110390. }
  110391. }),
  110392. appearance : new PerInstanceColorAppearance({
  110393. flat : true,
  110394. translucent : translucent,
  110395. renderState : {
  110396. lineWidth : geometryUpdater._scene.clampLineWidth(outlineWidth)
  110397. }
  110398. }),
  110399. asynchronous : false,
  110400. shadows : shadows
  110401. }));
  110402. }
  110403. };
  110404. DynamicGeometryUpdater.prototype.getBoundingSphere = function(entity, result) {
  110405. return dynamicGeometryGetBoundingSphere(entity, this._primitive, this._outlinePrimitive, result);
  110406. };
  110407. DynamicGeometryUpdater.prototype.isDestroyed = function() {
  110408. return false;
  110409. };
  110410. DynamicGeometryUpdater.prototype.destroy = function() {
  110411. var primitives = this._primitives;
  110412. var groundPrimitives = this._groundPrimitives;
  110413. if (this._geometryUpdater._onTerrain) {
  110414. groundPrimitives.removeAndDestroy(this._primitive);
  110415. } else {
  110416. primitives.removeAndDestroy(this._primitive);
  110417. }
  110418. primitives.removeAndDestroy(this._outlinePrimitive);
  110419. destroyObject(this);
  110420. };
  110421. return RectangleGeometryUpdater;
  110422. });
  110423. /*global define*/
  110424. define('DataSources/WallGeometryUpdater',[
  110425. '../Core/Color',
  110426. '../Core/ColorGeometryInstanceAttribute',
  110427. '../Core/defaultValue',
  110428. '../Core/defined',
  110429. '../Core/defineProperties',
  110430. '../Core/destroyObject',
  110431. '../Core/DeveloperError',
  110432. '../Core/DistanceDisplayCondition',
  110433. '../Core/DistanceDisplayConditionGeometryInstanceAttribute',
  110434. '../Core/Event',
  110435. '../Core/GeometryInstance',
  110436. '../Core/Iso8601',
  110437. '../Core/ShowGeometryInstanceAttribute',
  110438. '../Core/WallGeometry',
  110439. '../Core/WallOutlineGeometry',
  110440. '../Scene/MaterialAppearance',
  110441. '../Scene/PerInstanceColorAppearance',
  110442. '../Scene/Primitive',
  110443. '../Scene/ShadowMode',
  110444. './ColorMaterialProperty',
  110445. './ConstantProperty',
  110446. './dynamicGeometryGetBoundingSphere',
  110447. './MaterialProperty',
  110448. './Property'
  110449. ], function(
  110450. Color,
  110451. ColorGeometryInstanceAttribute,
  110452. defaultValue,
  110453. defined,
  110454. defineProperties,
  110455. destroyObject,
  110456. DeveloperError,
  110457. DistanceDisplayCondition,
  110458. DistanceDisplayConditionGeometryInstanceAttribute,
  110459. Event,
  110460. GeometryInstance,
  110461. Iso8601,
  110462. ShowGeometryInstanceAttribute,
  110463. WallGeometry,
  110464. WallOutlineGeometry,
  110465. MaterialAppearance,
  110466. PerInstanceColorAppearance,
  110467. Primitive,
  110468. ShadowMode,
  110469. ColorMaterialProperty,
  110470. ConstantProperty,
  110471. dynamicGeometryGetBoundingSphere,
  110472. MaterialProperty,
  110473. Property) {
  110474. 'use strict';
  110475. var defaultMaterial = new ColorMaterialProperty(Color.WHITE);
  110476. var defaultShow = new ConstantProperty(true);
  110477. var defaultFill = new ConstantProperty(true);
  110478. var defaultOutline = new ConstantProperty(false);
  110479. var defaultOutlineColor = new ConstantProperty(Color.BLACK);
  110480. var defaultShadows = new ConstantProperty(ShadowMode.DISABLED);
  110481. var defaultDistanceDisplayCondition = new ConstantProperty(new DistanceDisplayCondition());
  110482. var scratchColor = new Color();
  110483. function GeometryOptions(entity) {
  110484. this.id = entity;
  110485. this.vertexFormat = undefined;
  110486. this.positions = undefined;
  110487. this.minimumHeights = undefined;
  110488. this.maximumHeights = undefined;
  110489. this.granularity = undefined;
  110490. }
  110491. /**
  110492. * A {@link GeometryUpdater} for walls.
  110493. * Clients do not normally create this class directly, but instead rely on {@link DataSourceDisplay}.
  110494. * @alias WallGeometryUpdater
  110495. * @constructor
  110496. *
  110497. * @param {Entity} entity The entity containing the geometry to be visualized.
  110498. * @param {Scene} scene The scene where visualization is taking place.
  110499. */
  110500. function WallGeometryUpdater(entity, scene) {
  110501. if (!defined(entity)) {
  110502. throw new DeveloperError('entity is required');
  110503. }
  110504. if (!defined(scene)) {
  110505. throw new DeveloperError('scene is required');
  110506. }
  110507. this._entity = entity;
  110508. this._scene = scene;
  110509. this._entitySubscription = entity.definitionChanged.addEventListener(WallGeometryUpdater.prototype._onEntityPropertyChanged, this);
  110510. this._fillEnabled = false;
  110511. this._dynamic = false;
  110512. this._outlineEnabled = false;
  110513. this._geometryChanged = new Event();
  110514. this._showProperty = undefined;
  110515. this._materialProperty = undefined;
  110516. this._hasConstantOutline = true;
  110517. this._showOutlineProperty = undefined;
  110518. this._outlineColorProperty = undefined;
  110519. this._outlineWidth = 1.0;
  110520. this._shadowsProperty = undefined;
  110521. this._distanceDisplayConditionProperty = undefined;
  110522. this._options = new GeometryOptions(entity);
  110523. this._onEntityPropertyChanged(entity, 'wall', entity.wall, undefined);
  110524. }
  110525. defineProperties(WallGeometryUpdater, {
  110526. /**
  110527. * Gets the type of Appearance to use for simple color-based geometry.
  110528. * @memberof WallGeometryUpdater
  110529. * @type {Appearance}
  110530. */
  110531. perInstanceColorAppearanceType : {
  110532. value : PerInstanceColorAppearance
  110533. },
  110534. /**
  110535. * Gets the type of Appearance to use for material-based geometry.
  110536. * @memberof WallGeometryUpdater
  110537. * @type {Appearance}
  110538. */
  110539. materialAppearanceType : {
  110540. value : MaterialAppearance
  110541. }
  110542. });
  110543. defineProperties(WallGeometryUpdater.prototype, {
  110544. /**
  110545. * Gets the entity associated with this geometry.
  110546. * @memberof WallGeometryUpdater.prototype
  110547. *
  110548. * @type {Entity}
  110549. * @readonly
  110550. */
  110551. entity : {
  110552. get : function() {
  110553. return this._entity;
  110554. }
  110555. },
  110556. /**
  110557. * Gets a value indicating if the geometry has a fill component.
  110558. * @memberof WallGeometryUpdater.prototype
  110559. *
  110560. * @type {Boolean}
  110561. * @readonly
  110562. */
  110563. fillEnabled : {
  110564. get : function() {
  110565. return this._fillEnabled;
  110566. }
  110567. },
  110568. /**
  110569. * Gets a value indicating if fill visibility varies with simulation time.
  110570. * @memberof WallGeometryUpdater.prototype
  110571. *
  110572. * @type {Boolean}
  110573. * @readonly
  110574. */
  110575. hasConstantFill : {
  110576. get : function() {
  110577. return !this._fillEnabled ||
  110578. (!defined(this._entity.availability) &&
  110579. Property.isConstant(this._showProperty) &&
  110580. Property.isConstant(this._fillProperty));
  110581. }
  110582. },
  110583. /**
  110584. * Gets the material property used to fill the geometry.
  110585. * @memberof WallGeometryUpdater.prototype
  110586. *
  110587. * @type {MaterialProperty}
  110588. * @readonly
  110589. */
  110590. fillMaterialProperty : {
  110591. get : function() {
  110592. return this._materialProperty;
  110593. }
  110594. },
  110595. /**
  110596. * Gets a value indicating if the geometry has an outline component.
  110597. * @memberof WallGeometryUpdater.prototype
  110598. *
  110599. * @type {Boolean}
  110600. * @readonly
  110601. */
  110602. outlineEnabled : {
  110603. get : function() {
  110604. return this._outlineEnabled;
  110605. }
  110606. },
  110607. /**
  110608. * Gets a value indicating if the geometry has an outline component.
  110609. * @memberof WallGeometryUpdater.prototype
  110610. *
  110611. * @type {Boolean}
  110612. * @readonly
  110613. */
  110614. hasConstantOutline : {
  110615. get : function() {
  110616. return !this._outlineEnabled ||
  110617. (!defined(this._entity.availability) &&
  110618. Property.isConstant(this._showProperty) &&
  110619. Property.isConstant(this._showOutlineProperty));
  110620. }
  110621. },
  110622. /**
  110623. * Gets the {@link Color} property for the geometry outline.
  110624. * @memberof WallGeometryUpdater.prototype
  110625. *
  110626. * @type {Property}
  110627. * @readonly
  110628. */
  110629. outlineColorProperty : {
  110630. get : function() {
  110631. return this._outlineColorProperty;
  110632. }
  110633. },
  110634. /**
  110635. * Gets the constant with of the geometry outline, in pixels.
  110636. * This value is only valid if isDynamic is false.
  110637. * @memberof WallGeometryUpdater.prototype
  110638. *
  110639. * @type {Number}
  110640. * @readonly
  110641. */
  110642. outlineWidth : {
  110643. get : function() {
  110644. return this._outlineWidth;
  110645. }
  110646. },
  110647. /**
  110648. * Gets the property specifying whether the geometry
  110649. * casts or receives shadows from each light source.
  110650. * @memberof WallGeometryUpdater.prototype
  110651. *
  110652. * @type {Property}
  110653. * @readonly
  110654. */
  110655. shadowsProperty : {
  110656. get : function() {
  110657. return this._shadowsProperty;
  110658. }
  110659. },
  110660. /**
  110661. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this geometry will be displayed.
  110662. * @memberof WallGeometryUpdater.prototype
  110663. *
  110664. * @type {Property}
  110665. * @readonly
  110666. */
  110667. distanceDisplayConditionProperty : {
  110668. get : function() {
  110669. return this._distanceDisplayConditionProperty;
  110670. }
  110671. },
  110672. /**
  110673. * Gets a value indicating if the geometry is time-varying.
  110674. * If true, all visualization is delegated to the {@link DynamicGeometryUpdater}
  110675. * returned by GeometryUpdater#createDynamicUpdater.
  110676. * @memberof WallGeometryUpdater.prototype
  110677. *
  110678. * @type {Boolean}
  110679. * @readonly
  110680. */
  110681. isDynamic : {
  110682. get : function() {
  110683. return this._dynamic;
  110684. }
  110685. },
  110686. /**
  110687. * Gets a value indicating if the geometry is closed.
  110688. * This property is only valid for static geometry.
  110689. * @memberof WallGeometryUpdater.prototype
  110690. *
  110691. * @type {Boolean}
  110692. * @readonly
  110693. */
  110694. isClosed : {
  110695. get : function() {
  110696. return false;
  110697. }
  110698. },
  110699. /**
  110700. * Gets an event that is raised whenever the public properties
  110701. * of this updater change.
  110702. * @memberof WallGeometryUpdater.prototype
  110703. *
  110704. * @type {Boolean}
  110705. * @readonly
  110706. */
  110707. geometryChanged : {
  110708. get : function() {
  110709. return this._geometryChanged;
  110710. }
  110711. }
  110712. });
  110713. /**
  110714. * Checks if the geometry is outlined at the provided time.
  110715. *
  110716. * @param {JulianDate} time The time for which to retrieve visibility.
  110717. * @returns {Boolean} true if geometry is outlined at the provided time, false otherwise.
  110718. */
  110719. WallGeometryUpdater.prototype.isOutlineVisible = function(time) {
  110720. var entity = this._entity;
  110721. return this._outlineEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time);
  110722. };
  110723. /**
  110724. * Checks if the geometry is filled at the provided time.
  110725. *
  110726. * @param {JulianDate} time The time for which to retrieve visibility.
  110727. * @returns {Boolean} true if geometry is filled at the provided time, false otherwise.
  110728. */
  110729. WallGeometryUpdater.prototype.isFilled = function(time) {
  110730. var entity = this._entity;
  110731. return this._fillEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._fillProperty.getValue(time);
  110732. };
  110733. /**
  110734. * Creates the geometry instance which represents the fill of the geometry.
  110735. *
  110736. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  110737. * @returns {GeometryInstance} The geometry instance representing the filled portion of the geometry.
  110738. *
  110739. * @exception {DeveloperError} This instance does not represent a filled geometry.
  110740. */
  110741. WallGeometryUpdater.prototype.createFillGeometryInstance = function(time) {
  110742. if (!defined(time)) {
  110743. throw new DeveloperError('time is required.');
  110744. }
  110745. if (!this._fillEnabled) {
  110746. throw new DeveloperError('This instance does not represent a filled geometry.');
  110747. }
  110748. var entity = this._entity;
  110749. var isAvailable = entity.isAvailable(time);
  110750. var attributes;
  110751. var color;
  110752. var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time));
  110753. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  110754. var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
  110755. if (this._materialProperty instanceof ColorMaterialProperty) {
  110756. var currentColor = Color.WHITE;
  110757. if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) {
  110758. currentColor = this._materialProperty.color.getValue(time);
  110759. }
  110760. color = ColorGeometryInstanceAttribute.fromColor(currentColor);
  110761. attributes = {
  110762. show : show,
  110763. distanceDisplayCondition : distanceDisplayConditionAttribute,
  110764. color : color
  110765. };
  110766. } else {
  110767. attributes = {
  110768. show : show,
  110769. distanceDisplayCondition : distanceDisplayConditionAttribute
  110770. };
  110771. }
  110772. return new GeometryInstance({
  110773. id : entity,
  110774. geometry : new WallGeometry(this._options),
  110775. attributes : attributes
  110776. });
  110777. };
  110778. /**
  110779. * Creates the geometry instance which represents the outline of the geometry.
  110780. *
  110781. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  110782. * @returns {GeometryInstance} The geometry instance representing the outline portion of the geometry.
  110783. *
  110784. * @exception {DeveloperError} This instance does not represent an outlined geometry.
  110785. */
  110786. WallGeometryUpdater.prototype.createOutlineGeometryInstance = function(time) {
  110787. if (!defined(time)) {
  110788. throw new DeveloperError('time is required.');
  110789. }
  110790. if (!this._outlineEnabled) {
  110791. throw new DeveloperError('This instance does not represent an outlined geometry.');
  110792. }
  110793. var entity = this._entity;
  110794. var isAvailable = entity.isAvailable(time);
  110795. var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK);
  110796. var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
  110797. return new GeometryInstance({
  110798. id : entity,
  110799. geometry : new WallOutlineGeometry(this._options),
  110800. attributes : {
  110801. show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
  110802. color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
  110803. distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition)
  110804. }
  110805. });
  110806. };
  110807. /**
  110808. * Returns true if this object was destroyed; otherwise, false.
  110809. *
  110810. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  110811. */
  110812. WallGeometryUpdater.prototype.isDestroyed = function() {
  110813. return false;
  110814. };
  110815. /**
  110816. * Destroys and resources used by the object. Once an object is destroyed, it should not be used.
  110817. *
  110818. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  110819. */
  110820. WallGeometryUpdater.prototype.destroy = function() {
  110821. this._entitySubscription();
  110822. destroyObject(this);
  110823. };
  110824. WallGeometryUpdater.prototype._onEntityPropertyChanged = function(entity, propertyName, newValue, oldValue) {
  110825. if (!(propertyName === 'availability' || propertyName === 'wall')) {
  110826. return;
  110827. }
  110828. var wall = this._entity.wall;
  110829. if (!defined(wall)) {
  110830. if (this._fillEnabled || this._outlineEnabled) {
  110831. this._fillEnabled = false;
  110832. this._outlineEnabled = false;
  110833. this._geometryChanged.raiseEvent(this);
  110834. }
  110835. return;
  110836. }
  110837. var fillProperty = wall.fill;
  110838. var fillEnabled = defined(fillProperty) && fillProperty.isConstant ? fillProperty.getValue(Iso8601.MINIMUM_VALUE) : true;
  110839. var outlineProperty = wall.outline;
  110840. var outlineEnabled = defined(outlineProperty);
  110841. if (outlineEnabled && outlineProperty.isConstant) {
  110842. outlineEnabled = outlineProperty.getValue(Iso8601.MINIMUM_VALUE);
  110843. }
  110844. if (!fillEnabled && !outlineEnabled) {
  110845. if (this._fillEnabled || this._outlineEnabled) {
  110846. this._fillEnabled = false;
  110847. this._outlineEnabled = false;
  110848. this._geometryChanged.raiseEvent(this);
  110849. }
  110850. return;
  110851. }
  110852. var positions = wall.positions;
  110853. var show = wall.show;
  110854. if ((defined(show) && show.isConstant && !show.getValue(Iso8601.MINIMUM_VALUE)) || //
  110855. (!defined(positions))) {
  110856. if (this._fillEnabled || this._outlineEnabled) {
  110857. this._fillEnabled = false;
  110858. this._outlineEnabled = false;
  110859. this._geometryChanged.raiseEvent(this);
  110860. }
  110861. return;
  110862. }
  110863. var material = defaultValue(wall.material, defaultMaterial);
  110864. var isColorMaterial = material instanceof ColorMaterialProperty;
  110865. this._materialProperty = material;
  110866. this._fillProperty = defaultValue(fillProperty, defaultFill);
  110867. this._showProperty = defaultValue(show, defaultShow);
  110868. this._showOutlineProperty = defaultValue(wall.outline, defaultOutline);
  110869. this._outlineColorProperty = outlineEnabled ? defaultValue(wall.outlineColor, defaultOutlineColor) : undefined;
  110870. this._shadowsProperty = defaultValue(wall.shadows, defaultShadows);
  110871. this._distanceDisplayConditionProperty = defaultValue(wall.distanceDisplayCondition, defaultDistanceDisplayCondition);
  110872. var minimumHeights = wall.minimumHeights;
  110873. var maximumHeights = wall.maximumHeights;
  110874. var outlineWidth = wall.outlineWidth;
  110875. var granularity = wall.granularity;
  110876. this._fillEnabled = fillEnabled;
  110877. this._outlineEnabled = outlineEnabled;
  110878. if (!positions.isConstant || //
  110879. !Property.isConstant(minimumHeights) || //
  110880. !Property.isConstant(maximumHeights) || //
  110881. !Property.isConstant(outlineWidth) || //
  110882. !Property.isConstant(granularity)) {
  110883. if (!this._dynamic) {
  110884. this._dynamic = true;
  110885. this._geometryChanged.raiseEvent(this);
  110886. }
  110887. } else {
  110888. var options = this._options;
  110889. options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat;
  110890. options.positions = positions.getValue(Iso8601.MINIMUM_VALUE, options.positions);
  110891. options.minimumHeights = defined(minimumHeights) ? minimumHeights.getValue(Iso8601.MINIMUM_VALUE, options.minimumHeights) : undefined;
  110892. options.maximumHeights = defined(maximumHeights) ? maximumHeights.getValue(Iso8601.MINIMUM_VALUE, options.maximumHeights) : undefined;
  110893. options.granularity = defined(granularity) ? granularity.getValue(Iso8601.MINIMUM_VALUE) : undefined;
  110894. this._outlineWidth = defined(outlineWidth) ? outlineWidth.getValue(Iso8601.MINIMUM_VALUE) : 1.0;
  110895. this._dynamic = false;
  110896. this._geometryChanged.raiseEvent(this);
  110897. }
  110898. };
  110899. /**
  110900. * Creates the dynamic updater to be used when GeometryUpdater#isDynamic is true.
  110901. *
  110902. * @param {PrimitiveCollection} primitives The primitive collection to use.
  110903. * @returns {DynamicGeometryUpdater} The dynamic updater used to update the geometry each frame.
  110904. *
  110905. * @exception {DeveloperError} This instance does not represent dynamic geometry.
  110906. */
  110907. WallGeometryUpdater.prototype.createDynamicUpdater = function(primitives) {
  110908. if (!this._dynamic) {
  110909. throw new DeveloperError('This instance does not represent dynamic geometry.');
  110910. }
  110911. if (!defined(primitives)) {
  110912. throw new DeveloperError('primitives is required.');
  110913. }
  110914. return new DynamicGeometryUpdater(primitives, this);
  110915. };
  110916. /**
  110917. * @private
  110918. */
  110919. function DynamicGeometryUpdater(primitives, geometryUpdater) {
  110920. this._primitives = primitives;
  110921. this._primitive = undefined;
  110922. this._outlinePrimitive = undefined;
  110923. this._geometryUpdater = geometryUpdater;
  110924. this._options = new GeometryOptions(geometryUpdater._entity);
  110925. }
  110926. DynamicGeometryUpdater.prototype.update = function(time) {
  110927. if (!defined(time)) {
  110928. throw new DeveloperError('time is required.');
  110929. }
  110930. var primitives = this._primitives;
  110931. primitives.removeAndDestroy(this._primitive);
  110932. primitives.removeAndDestroy(this._outlinePrimitive);
  110933. this._primitive = undefined;
  110934. this._outlinePrimitive = undefined;
  110935. var geometryUpdater = this._geometryUpdater;
  110936. var entity = geometryUpdater._entity;
  110937. var wall = entity.wall;
  110938. if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(wall.show, time, true)) {
  110939. return;
  110940. }
  110941. var options = this._options;
  110942. var positions = Property.getValueOrUndefined(wall.positions, time, options.positions);
  110943. if (!defined(positions)) {
  110944. return;
  110945. }
  110946. options.positions = positions;
  110947. options.minimumHeights = Property.getValueOrUndefined(wall.minimumHeights, time, options.minimumHeights);
  110948. options.maximumHeights = Property.getValueOrUndefined(wall.maximumHeights, time, options.maximumHeights);
  110949. options.granularity = Property.getValueOrUndefined(wall.granularity, time);
  110950. var shadows = this._geometryUpdater.shadowsProperty.getValue(time);
  110951. if (Property.getValueOrDefault(wall.fill, time, true)) {
  110952. var material = MaterialProperty.getValue(time, geometryUpdater.fillMaterialProperty, this._material);
  110953. this._material = material;
  110954. var appearance = new MaterialAppearance({
  110955. material : material,
  110956. translucent : material.isTranslucent(),
  110957. closed : defined(options.extrudedHeight)
  110958. });
  110959. options.vertexFormat = appearance.vertexFormat;
  110960. this._primitive = primitives.add(new Primitive({
  110961. geometryInstances : new GeometryInstance({
  110962. id : entity,
  110963. geometry : new WallGeometry(options)
  110964. }),
  110965. appearance : appearance,
  110966. asynchronous : false,
  110967. shadows : shadows
  110968. }));
  110969. }
  110970. if (Property.getValueOrDefault(wall.outline, time, false)) {
  110971. options.vertexFormat = PerInstanceColorAppearance.VERTEX_FORMAT;
  110972. var outlineColor = Property.getValueOrClonedDefault(wall.outlineColor, time, Color.BLACK, scratchColor);
  110973. var outlineWidth = Property.getValueOrDefault(wall.outlineWidth, time, 1.0);
  110974. var translucent = outlineColor.alpha !== 1.0;
  110975. this._outlinePrimitive = primitives.add(new Primitive({
  110976. geometryInstances : new GeometryInstance({
  110977. id : entity,
  110978. geometry : new WallOutlineGeometry(options),
  110979. attributes : {
  110980. color : ColorGeometryInstanceAttribute.fromColor(outlineColor)
  110981. }
  110982. }),
  110983. appearance : new PerInstanceColorAppearance({
  110984. flat : true,
  110985. translucent : translucent,
  110986. renderState : {
  110987. lineWidth : geometryUpdater._scene.clampLineWidth(outlineWidth)
  110988. }
  110989. }),
  110990. asynchronous : false,
  110991. shadows : shadows
  110992. }));
  110993. }
  110994. };
  110995. DynamicGeometryUpdater.prototype.getBoundingSphere = function(entity, result) {
  110996. return dynamicGeometryGetBoundingSphere(entity, this._primitive, this._outlinePrimitive, result);
  110997. };
  110998. DynamicGeometryUpdater.prototype.isDestroyed = function() {
  110999. return false;
  111000. };
  111001. DynamicGeometryUpdater.prototype.destroy = function() {
  111002. var primitives = this._primitives;
  111003. primitives.removeAndDestroy(this._primitive);
  111004. primitives.removeAndDestroy(this._outlinePrimitive);
  111005. destroyObject(this);
  111006. };
  111007. return WallGeometryUpdater;
  111008. });
  111009. /*global define*/
  111010. define('DataSources/DataSourceDisplay',[
  111011. '../Core/BoundingSphere',
  111012. '../Core/defaultValue',
  111013. '../Core/defined',
  111014. '../Core/defineProperties',
  111015. '../Core/destroyObject',
  111016. '../Core/DeveloperError',
  111017. '../Core/EventHelper',
  111018. '../Scene/GroundPrimitive',
  111019. './BillboardVisualizer',
  111020. './BoundingSphereState',
  111021. './BoxGeometryUpdater',
  111022. './CorridorGeometryUpdater',
  111023. './CustomDataSource',
  111024. './CylinderGeometryUpdater',
  111025. './EllipseGeometryUpdater',
  111026. './EllipsoidGeometryUpdater',
  111027. './GeometryVisualizer',
  111028. './LabelVisualizer',
  111029. './ModelVisualizer',
  111030. './PathVisualizer',
  111031. './PointVisualizer',
  111032. './PolygonGeometryUpdater',
  111033. './PolylineGeometryUpdater',
  111034. './PolylineVolumeGeometryUpdater',
  111035. './RectangleGeometryUpdater',
  111036. './WallGeometryUpdater'
  111037. ], function(
  111038. BoundingSphere,
  111039. defaultValue,
  111040. defined,
  111041. defineProperties,
  111042. destroyObject,
  111043. DeveloperError,
  111044. EventHelper,
  111045. GroundPrimitive,
  111046. BillboardVisualizer,
  111047. BoundingSphereState,
  111048. BoxGeometryUpdater,
  111049. CorridorGeometryUpdater,
  111050. CustomDataSource,
  111051. CylinderGeometryUpdater,
  111052. EllipseGeometryUpdater,
  111053. EllipsoidGeometryUpdater,
  111054. GeometryVisualizer,
  111055. LabelVisualizer,
  111056. ModelVisualizer,
  111057. PathVisualizer,
  111058. PointVisualizer,
  111059. PolygonGeometryUpdater,
  111060. PolylineGeometryUpdater,
  111061. PolylineVolumeGeometryUpdater,
  111062. RectangleGeometryUpdater,
  111063. WallGeometryUpdater) {
  111064. 'use strict';
  111065. /**
  111066. * Visualizes a collection of {@link DataSource} instances.
  111067. * @alias DataSourceDisplay
  111068. * @constructor
  111069. *
  111070. * @param {Object} options Object with the following properties:
  111071. * @param {Scene} options.scene The scene in which to display the data.
  111072. * @param {DataSourceCollection} options.dataSourceCollection The data sources to display.
  111073. * @param {DataSourceDisplay~VisualizersCallback} [options.visualizersCallback=DataSourceDisplay.defaultVisualizersCallback]
  111074. * A function which creates an array of visualizers used for visualization.
  111075. * If undefined, all standard visualizers are used.
  111076. */
  111077. function DataSourceDisplay(options) {
  111078. if (!defined(options)) {
  111079. throw new DeveloperError('options is required.');
  111080. }
  111081. if (!defined(options.scene)) {
  111082. throw new DeveloperError('scene is required.');
  111083. }
  111084. if (!defined(options.dataSourceCollection)) {
  111085. throw new DeveloperError('dataSourceCollection is required.');
  111086. }
  111087. GroundPrimitive.initializeTerrainHeights();
  111088. var scene = options.scene;
  111089. var dataSourceCollection = options.dataSourceCollection;
  111090. this._eventHelper = new EventHelper();
  111091. this._eventHelper.add(dataSourceCollection.dataSourceAdded, this._onDataSourceAdded, this);
  111092. this._eventHelper.add(dataSourceCollection.dataSourceRemoved, this._onDataSourceRemoved, this);
  111093. this._dataSourceCollection = dataSourceCollection;
  111094. this._scene = scene;
  111095. this._visualizersCallback = defaultValue(options.visualizersCallback, DataSourceDisplay.defaultVisualizersCallback);
  111096. for (var i = 0, len = dataSourceCollection.length; i < len; i++) {
  111097. this._onDataSourceAdded(dataSourceCollection, dataSourceCollection.get(i));
  111098. }
  111099. var defaultDataSource = new CustomDataSource();
  111100. this._onDataSourceAdded(undefined, defaultDataSource);
  111101. this._defaultDataSource = defaultDataSource;
  111102. this._ready = false;
  111103. }
  111104. /**
  111105. * Gets or sets the default function which creates an array of visualizers used for visualization.
  111106. * By default, this function uses all standard visualizers.
  111107. *
  111108. * @member
  111109. * @type {DataSourceDisplay~VisualizersCallback}
  111110. */
  111111. DataSourceDisplay.defaultVisualizersCallback = function(scene, entityCluster, dataSource) {
  111112. var entities = dataSource.entities;
  111113. return [new BillboardVisualizer(entityCluster, entities),
  111114. new GeometryVisualizer(BoxGeometryUpdater, scene, entities),
  111115. new GeometryVisualizer(CylinderGeometryUpdater, scene, entities),
  111116. new GeometryVisualizer(CorridorGeometryUpdater, scene, entities),
  111117. new GeometryVisualizer(EllipseGeometryUpdater, scene, entities),
  111118. new GeometryVisualizer(EllipsoidGeometryUpdater, scene, entities),
  111119. new GeometryVisualizer(PolygonGeometryUpdater, scene, entities),
  111120. new GeometryVisualizer(PolylineGeometryUpdater, scene, entities),
  111121. new GeometryVisualizer(PolylineVolumeGeometryUpdater, scene, entities),
  111122. new GeometryVisualizer(RectangleGeometryUpdater, scene, entities),
  111123. new GeometryVisualizer(WallGeometryUpdater, scene, entities),
  111124. new LabelVisualizer(entityCluster, entities),
  111125. new ModelVisualizer(scene, entities),
  111126. new PointVisualizer(entityCluster, entities),
  111127. new PathVisualizer(scene, entities)];
  111128. };
  111129. defineProperties(DataSourceDisplay.prototype, {
  111130. /**
  111131. * Gets the scene associated with this display.
  111132. * @memberof DataSourceDisplay.prototype
  111133. * @type {Scene}
  111134. */
  111135. scene : {
  111136. get : function() {
  111137. return this._scene;
  111138. }
  111139. },
  111140. /**
  111141. * Gets the collection of data sources to display.
  111142. * @memberof DataSourceDisplay.prototype
  111143. * @type {DataSourceCollection}
  111144. */
  111145. dataSources : {
  111146. get : function() {
  111147. return this._dataSourceCollection;
  111148. }
  111149. },
  111150. /**
  111151. * Gets the default data source instance which can be used to
  111152. * manually create and visualize entities not tied to
  111153. * a specific data source. This instance is always available
  111154. * and does not appear in the list dataSources collection.
  111155. * @memberof DataSourceDisplay.prototype
  111156. * @type {CustomDataSource}
  111157. */
  111158. defaultDataSource : {
  111159. get : function() {
  111160. return this._defaultDataSource;
  111161. }
  111162. },
  111163. /**
  111164. * Gets a value indicating whether or not all entities in the data source are ready
  111165. * @memberof DataSourceDisplay.prototype
  111166. * @type {Boolean}
  111167. * @readonly
  111168. */
  111169. ready : {
  111170. get : function() {
  111171. return this._ready;
  111172. }
  111173. }
  111174. });
  111175. /**
  111176. * Returns true if this object was destroyed; otherwise, false.
  111177. * <br /><br />
  111178. * If this object was destroyed, it should not be used; calling any function other than
  111179. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  111180. *
  111181. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  111182. *
  111183. * @see DataSourceDisplay#destroy
  111184. */
  111185. DataSourceDisplay.prototype.isDestroyed = function() {
  111186. return false;
  111187. };
  111188. /**
  111189. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  111190. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  111191. * <br /><br />
  111192. * Once an object is destroyed, it should not be used; calling any function other than
  111193. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  111194. * assign the return value (<code>undefined</code>) to the object as done in the example.
  111195. *
  111196. * @returns {undefined}
  111197. *
  111198. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  111199. *
  111200. *
  111201. * @example
  111202. * dataSourceDisplay = dataSourceDisplay.destroy();
  111203. *
  111204. * @see DataSourceDisplay#isDestroyed
  111205. */
  111206. DataSourceDisplay.prototype.destroy = function() {
  111207. this._eventHelper.removeAll();
  111208. var dataSourceCollection = this._dataSourceCollection;
  111209. for (var i = 0, length = dataSourceCollection.length; i < length; ++i) {
  111210. this._onDataSourceRemoved(this._dataSourceCollection, dataSourceCollection.get(i));
  111211. }
  111212. this._onDataSourceRemoved(undefined, this._defaultDataSource);
  111213. return destroyObject(this);
  111214. };
  111215. /**
  111216. * Updates the display to the provided time.
  111217. *
  111218. * @param {JulianDate} time The simulation time.
  111219. * @returns {Boolean} True if all data sources are ready to be displayed, false otherwise.
  111220. */
  111221. DataSourceDisplay.prototype.update = function(time) {
  111222. if (!defined(time)) {
  111223. throw new DeveloperError('time is required.');
  111224. }
  111225. if (!GroundPrimitive._initialized) {
  111226. this._ready = false;
  111227. return false;
  111228. }
  111229. var result = true;
  111230. var i;
  111231. var x;
  111232. var visualizers;
  111233. var vLength;
  111234. var dataSources = this._dataSourceCollection;
  111235. var length = dataSources.length;
  111236. for (i = 0; i < length; i++) {
  111237. var dataSource = dataSources.get(i);
  111238. if (defined(dataSource.update)) {
  111239. result = dataSource.update(time) && result;
  111240. }
  111241. visualizers = dataSource._visualizers;
  111242. vLength = visualizers.length;
  111243. for (x = 0; x < vLength; x++) {
  111244. result = visualizers[x].update(time) && result;
  111245. }
  111246. }
  111247. visualizers = this._defaultDataSource._visualizers;
  111248. vLength = visualizers.length;
  111249. for (x = 0; x < vLength; x++) {
  111250. result = visualizers[x].update(time) && result;
  111251. }
  111252. this._ready = result;
  111253. return result;
  111254. };
  111255. var getBoundingSphereArrayScratch = [];
  111256. var getBoundingSphereBoundingSphereScratch = new BoundingSphere();
  111257. /**
  111258. * Computes a bounding sphere which encloses the visualization produced for the specified entity.
  111259. * The bounding sphere is in the fixed frame of the scene's globe.
  111260. *
  111261. * @param {Entity} entity The entity whose bounding sphere to compute.
  111262. * @param {Boolean} allowPartial If true, pending bounding spheres are ignored and an answer will be returned from the currently available data.
  111263. * If false, the the function will halt and return pending if any of the bounding spheres are pending.
  111264. * @param {BoundingSphere} result The bounding sphere onto which to store the result.
  111265. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere,
  111266. * BoundingSphereState.PENDING if the result is still being computed, or
  111267. * BoundingSphereState.FAILED if the entity has no visualization in the current scene.
  111268. * @private
  111269. */
  111270. DataSourceDisplay.prototype.getBoundingSphere = function(entity, allowPartial, result) {
  111271. if (!defined(entity)) {
  111272. throw new DeveloperError('entity is required.');
  111273. }
  111274. if (!defined(allowPartial)) {
  111275. throw new DeveloperError('allowPartial is required.');
  111276. }
  111277. if (!defined(result)) {
  111278. throw new DeveloperError('result is required.');
  111279. }
  111280. if (!this._ready) {
  111281. return BoundingSphereState.PENDING;
  111282. }
  111283. var i;
  111284. var length;
  111285. var dataSource = this._defaultDataSource;
  111286. if (!dataSource.entities.contains(entity)) {
  111287. dataSource = undefined;
  111288. var dataSources = this._dataSourceCollection;
  111289. length = dataSources.length;
  111290. for (i = 0; i < length; i++) {
  111291. var d = dataSources.get(i);
  111292. if (d.entities.contains(entity)) {
  111293. dataSource = d;
  111294. break;
  111295. }
  111296. }
  111297. }
  111298. if (!defined(dataSource)) {
  111299. return BoundingSphereState.FAILED;
  111300. }
  111301. var boundingSpheres = getBoundingSphereArrayScratch;
  111302. var tmp = getBoundingSphereBoundingSphereScratch;
  111303. var count = 0;
  111304. var state = BoundingSphereState.DONE;
  111305. var visualizers = dataSource._visualizers;
  111306. var visualizersLength = visualizers.length;
  111307. for (i = 0; i < visualizersLength; i++) {
  111308. var visualizer = visualizers[i];
  111309. if (defined(visualizer.getBoundingSphere)) {
  111310. state = visualizers[i].getBoundingSphere(entity, tmp);
  111311. if (!allowPartial && state === BoundingSphereState.PENDING) {
  111312. return BoundingSphereState.PENDING;
  111313. } else if (state === BoundingSphereState.DONE) {
  111314. boundingSpheres[count] = BoundingSphere.clone(tmp, boundingSpheres[count]);
  111315. count++;
  111316. }
  111317. }
  111318. }
  111319. if (count === 0) {
  111320. return BoundingSphereState.FAILED;
  111321. }
  111322. boundingSpheres.length = count;
  111323. BoundingSphere.fromBoundingSpheres(boundingSpheres, result);
  111324. return BoundingSphereState.DONE;
  111325. };
  111326. DataSourceDisplay.prototype._onDataSourceAdded = function(dataSourceCollection, dataSource) {
  111327. var scene = this._scene;
  111328. var entityCluster = dataSource.clustering;
  111329. entityCluster._initialize(scene);
  111330. scene.primitives.add(entityCluster);
  111331. dataSource._visualizers = this._visualizersCallback(scene, entityCluster, dataSource);
  111332. };
  111333. DataSourceDisplay.prototype._onDataSourceRemoved = function(dataSourceCollection, dataSource) {
  111334. var scene = this._scene;
  111335. var entityCluster = dataSource.clustering;
  111336. scene.primitives.remove(entityCluster);
  111337. var visualizers = dataSource._visualizers;
  111338. var length = visualizers.length;
  111339. for (var i = 0; i < length; i++) {
  111340. visualizers[i].destroy();
  111341. }
  111342. dataSource._visualizers = undefined;
  111343. };
  111344. /**
  111345. * A function which creates an array of visualizers used for visualization.
  111346. * @callback DataSourceDisplay~VisualizersCallback
  111347. *
  111348. * @param {Scene} scene The scene to create visualizers for.
  111349. * @param {DataSource} dataSource The data source to create visualizers for.
  111350. * @returns {Visualizer[]} An array of visualizers used for visualization.
  111351. *
  111352. * @example
  111353. * function createVisualizers(scene, dataSource) {
  111354. * return [new Cesium.BillboardVisualizer(scene, dataSource.entities)];
  111355. * }
  111356. */
  111357. return DataSourceDisplay;
  111358. });
  111359. /*global define*/
  111360. define('DataSources/DynamicGeometryUpdater',[
  111361. '../Core/DeveloperError'
  111362. ], function(
  111363. DeveloperError) {
  111364. 'use strict';
  111365. /**
  111366. * Defines the interface for a dynamic geometry updater. A DynamicGeometryUpdater
  111367. * is responsible for handling visualization of a specific type of geometry
  111368. * that needs to be recomputed based on simulation time.
  111369. * This object is never used directly by client code, but is instead created by
  111370. * {@link GeometryUpdater} implementations which contain dynamic geometry.
  111371. *
  111372. * This type defines an interface and cannot be instantiated directly.
  111373. *
  111374. * @alias DynamicGeometryUpdater
  111375. * @constructor
  111376. */
  111377. function DynamicGeometryUpdater() {
  111378. DeveloperError.throwInstantiationError();
  111379. }
  111380. /**
  111381. * Updates the geometry to the specified time.
  111382. * @memberof DynamicGeometryUpdater
  111383. * @function
  111384. *
  111385. * @param {JulianDate} time The current time.
  111386. */
  111387. DynamicGeometryUpdater.prototype.update = DeveloperError.throwInstantiationError;
  111388. /**
  111389. * Computes a bounding sphere which encloses the visualization produced for the specified entity.
  111390. * The bounding sphere is in the fixed frame of the scene's globe.
  111391. * @function
  111392. *
  111393. * @param {Entity} entity The entity whose bounding sphere to compute.
  111394. * @param {BoundingSphere} result The bounding sphere onto which to store the result.
  111395. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere,
  111396. * BoundingSphereState.PENDING if the result is still being computed, or
  111397. * BoundingSphereState.FAILED if the entity has no visualization in the current scene.
  111398. * @private
  111399. */
  111400. DynamicGeometryUpdater.prototype.getBoundingSphere = DeveloperError.throwInstantiationError;
  111401. /**
  111402. * Returns true if this object was destroyed; otherwise, false.
  111403. * @memberof DynamicGeometryUpdater
  111404. * @function
  111405. *
  111406. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  111407. */
  111408. DynamicGeometryUpdater.prototype.isDestroyed = DeveloperError.throwInstantiationError;
  111409. /**
  111410. * Destroys and resources used by the object. Once an object is destroyed, it should not be used.
  111411. * @memberof DynamicGeometryUpdater
  111412. * @function
  111413. *
  111414. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  111415. */
  111416. DynamicGeometryUpdater.prototype.destroy = DeveloperError.throwInstantiationError;
  111417. return DynamicGeometryUpdater;
  111418. });
  111419. /*global define*/
  111420. define('DataSources/EntityView',[
  111421. '../Core/Cartesian3',
  111422. '../Core/defaultValue',
  111423. '../Core/defined',
  111424. '../Core/defineProperties',
  111425. '../Core/DeveloperError',
  111426. '../Core/Ellipsoid',
  111427. '../Core/HeadingPitchRange',
  111428. '../Core/JulianDate',
  111429. '../Core/Math',
  111430. '../Core/Matrix3',
  111431. '../Core/Matrix4',
  111432. '../Core/Transforms',
  111433. '../Scene/SceneMode'
  111434. ], function(
  111435. Cartesian3,
  111436. defaultValue,
  111437. defined,
  111438. defineProperties,
  111439. DeveloperError,
  111440. Ellipsoid,
  111441. HeadingPitchRange,
  111442. JulianDate,
  111443. CesiumMath,
  111444. Matrix3,
  111445. Matrix4,
  111446. Transforms,
  111447. SceneMode) {
  111448. 'use strict';
  111449. var updateTransformMatrix3Scratch1 = new Matrix3();
  111450. var updateTransformMatrix3Scratch2 = new Matrix3();
  111451. var updateTransformMatrix3Scratch3 = new Matrix3();
  111452. var updateTransformMatrix4Scratch = new Matrix4();
  111453. var updateTransformCartesian3Scratch1 = new Cartesian3();
  111454. var updateTransformCartesian3Scratch2 = new Cartesian3();
  111455. var updateTransformCartesian3Scratch3 = new Cartesian3();
  111456. var updateTransformCartesian3Scratch4 = new Cartesian3();
  111457. var updateTransformCartesian3Scratch5 = new Cartesian3();
  111458. var updateTransformCartesian3Scratch6 = new Cartesian3();
  111459. var deltaTime = new JulianDate();
  111460. var northUpAxisFactor = 1.25; // times ellipsoid's maximum radius
  111461. function updateTransform(that, camera, updateLookAt, saveCamera, positionProperty, time, ellipsoid) {
  111462. var mode = that.scene.mode;
  111463. var cartesian = positionProperty.getValue(time, that._lastCartesian);
  111464. if (defined(cartesian)) {
  111465. var hasBasis = false;
  111466. var xBasis;
  111467. var yBasis;
  111468. var zBasis;
  111469. if (mode === SceneMode.SCENE3D) {
  111470. // The time delta was determined based on how fast satellites move compared to vehicles near the surface.
  111471. // Slower moving vehicles will most likely default to east-north-up, while faster ones will be VVLH.
  111472. deltaTime = JulianDate.addSeconds(time, 0.001, deltaTime);
  111473. var deltaCartesian = positionProperty.getValue(deltaTime, updateTransformCartesian3Scratch1);
  111474. if (defined(deltaCartesian)) {
  111475. var toInertial = Transforms.computeFixedToIcrfMatrix(time, updateTransformMatrix3Scratch1);
  111476. var toInertialDelta = Transforms.computeFixedToIcrfMatrix(deltaTime, updateTransformMatrix3Scratch2);
  111477. var toFixed;
  111478. if (!defined(toInertial) || !defined(toInertialDelta)) {
  111479. toFixed = Transforms.computeTemeToPseudoFixedMatrix(time, updateTransformMatrix3Scratch3);
  111480. toInertial = Matrix3.transpose(toFixed, updateTransformMatrix3Scratch1);
  111481. toInertialDelta = Transforms.computeTemeToPseudoFixedMatrix(deltaTime, updateTransformMatrix3Scratch2);
  111482. Matrix3.transpose(toInertialDelta, toInertialDelta);
  111483. } else {
  111484. toFixed = Matrix3.transpose(toInertial, updateTransformMatrix3Scratch3);
  111485. }
  111486. var inertialCartesian = Matrix3.multiplyByVector(toInertial, cartesian, updateTransformCartesian3Scratch5);
  111487. var inertialDeltaCartesian = Matrix3.multiplyByVector(toInertialDelta, deltaCartesian, updateTransformCartesian3Scratch6);
  111488. Cartesian3.subtract(inertialCartesian, inertialDeltaCartesian, updateTransformCartesian3Scratch4);
  111489. var inertialVelocity = Cartesian3.magnitude(updateTransformCartesian3Scratch4) * 1000.0; // meters/sec
  111490. // http://en.wikipedia.org/wiki/Standard_gravitational_parameter
  111491. // Consider adding this to Cesium.Ellipsoid?
  111492. var mu = 3.986004418e14; // m^3 / sec^2
  111493. var semiMajorAxis = -mu / (inertialVelocity * inertialVelocity - (2 * mu / Cartesian3.magnitude(inertialCartesian)));
  111494. if (semiMajorAxis < 0 || semiMajorAxis > northUpAxisFactor * ellipsoid.maximumRadius) {
  111495. // North-up viewing from deep space.
  111496. // X along the nadir
  111497. xBasis = updateTransformCartesian3Scratch2;
  111498. Cartesian3.normalize(cartesian, xBasis);
  111499. Cartesian3.negate(xBasis, xBasis);
  111500. // Z is North
  111501. zBasis = Cartesian3.clone(Cartesian3.UNIT_Z, updateTransformCartesian3Scratch3);
  111502. // Y is along the cross of z and x (right handed basis / in the direction of motion)
  111503. yBasis = Cartesian3.cross(zBasis, xBasis, updateTransformCartesian3Scratch1);
  111504. if (Cartesian3.magnitude(yBasis) > CesiumMath.EPSILON7) {
  111505. Cartesian3.normalize(xBasis, xBasis);
  111506. Cartesian3.normalize(yBasis, yBasis);
  111507. zBasis = Cartesian3.cross(xBasis, yBasis, updateTransformCartesian3Scratch3);
  111508. Cartesian3.normalize(zBasis, zBasis);
  111509. hasBasis = true;
  111510. }
  111511. } else if (!Cartesian3.equalsEpsilon(cartesian, deltaCartesian, CesiumMath.EPSILON7)) {
  111512. // Approximation of VVLH (Vehicle Velocity Local Horizontal) with the Z-axis flipped.
  111513. // Z along the position
  111514. zBasis = updateTransformCartesian3Scratch2;
  111515. Cartesian3.normalize(inertialCartesian, zBasis);
  111516. Cartesian3.normalize(inertialDeltaCartesian, inertialDeltaCartesian);
  111517. // Y is along the angular momentum vector (e.g. "orbit normal")
  111518. yBasis = Cartesian3.cross(zBasis, inertialDeltaCartesian, updateTransformCartesian3Scratch3);
  111519. if (!Cartesian3.equalsEpsilon(yBasis, Cartesian3.ZERO, CesiumMath.EPSILON7)) {
  111520. // X is along the cross of y and z (right handed basis / in the direction of motion)
  111521. xBasis = Cartesian3.cross(yBasis, zBasis, updateTransformCartesian3Scratch1);
  111522. Matrix3.multiplyByVector(toFixed, xBasis, xBasis);
  111523. Matrix3.multiplyByVector(toFixed, yBasis, yBasis);
  111524. Matrix3.multiplyByVector(toFixed, zBasis, zBasis);
  111525. Cartesian3.normalize(xBasis, xBasis);
  111526. Cartesian3.normalize(yBasis, yBasis);
  111527. Cartesian3.normalize(zBasis, zBasis);
  111528. hasBasis = true;
  111529. }
  111530. }
  111531. }
  111532. }
  111533. if (defined(that.boundingSphere)) {
  111534. cartesian = that.boundingSphere.center;
  111535. }
  111536. var position;
  111537. var direction;
  111538. var up;
  111539. if (saveCamera) {
  111540. position = Cartesian3.clone(camera.position, updateTransformCartesian3Scratch4);
  111541. direction = Cartesian3.clone(camera.direction, updateTransformCartesian3Scratch5);
  111542. up = Cartesian3.clone(camera.up, updateTransformCartesian3Scratch6);
  111543. }
  111544. var transform = updateTransformMatrix4Scratch;
  111545. if (hasBasis) {
  111546. transform[0] = xBasis.x;
  111547. transform[1] = xBasis.y;
  111548. transform[2] = xBasis.z;
  111549. transform[3] = 0.0;
  111550. transform[4] = yBasis.x;
  111551. transform[5] = yBasis.y;
  111552. transform[6] = yBasis.z;
  111553. transform[7] = 0.0;
  111554. transform[8] = zBasis.x;
  111555. transform[9] = zBasis.y;
  111556. transform[10] = zBasis.z;
  111557. transform[11] = 0.0;
  111558. transform[12] = cartesian.x;
  111559. transform[13] = cartesian.y;
  111560. transform[14] = cartesian.z;
  111561. transform[15] = 0.0;
  111562. } else {
  111563. // Stationary or slow-moving, low-altitude objects use East-North-Up.
  111564. Transforms.eastNorthUpToFixedFrame(cartesian, ellipsoid, transform);
  111565. }
  111566. camera._setTransform(transform);
  111567. if (saveCamera) {
  111568. Cartesian3.clone(position, camera.position);
  111569. Cartesian3.clone(direction, camera.direction);
  111570. Cartesian3.clone(up, camera.up);
  111571. Cartesian3.cross(direction, up, camera.right);
  111572. }
  111573. }
  111574. if (updateLookAt) {
  111575. var offset = (mode === SceneMode.SCENE2D || Cartesian3.equals(that._offset3D, Cartesian3.ZERO)) ? undefined : that._offset3D;
  111576. camera.lookAtTransform(camera.transform, offset);
  111577. }
  111578. }
  111579. /**
  111580. * A utility object for tracking an entity with the camera.
  111581. * @alias EntityView
  111582. * @constructor
  111583. *
  111584. * @param {Entity} entity The entity to track with the camera.
  111585. * @param {Scene} scene The scene to use.
  111586. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid to use for orienting the camera.
  111587. */
  111588. function EntityView(entity, scene, ellipsoid) {
  111589. /**
  111590. * The entity to track with the camera.
  111591. * @type {Entity}
  111592. */
  111593. this.entity = entity;
  111594. /**
  111595. * The scene in which to track the object.
  111596. * @type {Scene}
  111597. */
  111598. this.scene = scene;
  111599. /**
  111600. * The ellipsoid to use for orienting the camera.
  111601. * @type {Ellipsoid}
  111602. */
  111603. this.ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  111604. /**
  111605. * The bounding sphere of the object.
  111606. * @type {BoundingSphere}
  111607. */
  111608. this.boundingSphere = undefined;
  111609. //Shadow copies of the objects so we can detect changes.
  111610. this._lastEntity = undefined;
  111611. this._mode = undefined;
  111612. this._lastCartesian = new Cartesian3();
  111613. this._defaultOffset3D = undefined;
  111614. this._offset3D = new Cartesian3();
  111615. }
  111616. // STATIC properties defined here, not per-instance.
  111617. defineProperties(EntityView, {
  111618. /**
  111619. * Gets or sets a camera offset that will be used to
  111620. * initialize subsequent EntityViews.
  111621. * @memberof EntityView
  111622. * @type {Cartesian3}
  111623. */
  111624. defaultOffset3D : {
  111625. get : function() {
  111626. return this._defaultOffset3D;
  111627. },
  111628. set : function(vector) {
  111629. this._defaultOffset3D = Cartesian3.clone(vector, new Cartesian3());
  111630. }
  111631. }
  111632. });
  111633. // Initialize the static property.
  111634. EntityView.defaultOffset3D = new Cartesian3(-14000, 3500, 3500);
  111635. var scratchHeadingPitchRange = new HeadingPitchRange();
  111636. var scratchCartesian = new Cartesian3();
  111637. /**
  111638. * Should be called each animation frame to update the camera
  111639. * to the latest settings.
  111640. * @param {JulianDate} time The current animation time.
  111641. * @param {BoundingSphere} current bounding sphere of the object.
  111642. *
  111643. */
  111644. EntityView.prototype.update = function(time, boundingSphere) {
  111645. var scene = this.scene;
  111646. var entity = this.entity;
  111647. var ellipsoid = this.ellipsoid;
  111648. if (!defined(time)) {
  111649. throw new DeveloperError('time is required.');
  111650. }
  111651. if (!defined(scene)) {
  111652. throw new DeveloperError('EntityView.scene is required.');
  111653. }
  111654. if (!defined(entity)) {
  111655. throw new DeveloperError('EntityView.entity is required.');
  111656. }
  111657. if (!defined(ellipsoid)) {
  111658. throw new DeveloperError('EntityView.ellipsoid is required.');
  111659. }
  111660. if (!defined(entity.position)) {
  111661. throw new DeveloperError('entity.position is required.');
  111662. }
  111663. var sceneMode = scene.mode;
  111664. if (sceneMode === SceneMode.MORPHING) {
  111665. return;
  111666. }
  111667. var positionProperty = entity.position;
  111668. var objectChanged = entity !== this._lastEntity;
  111669. var sceneModeChanged = sceneMode !== this._mode;
  111670. var offset3D = this._offset3D;
  111671. var camera = scene.camera;
  111672. var updateLookAt = objectChanged || sceneModeChanged;
  111673. var saveCamera = true;
  111674. if (objectChanged) {
  111675. var viewFromProperty = entity.viewFrom;
  111676. var hasViewFrom = defined(viewFromProperty);
  111677. if (!hasViewFrom && defined(boundingSphere)) {
  111678. var controller = scene.screenSpaceCameraController;
  111679. controller.minimumZoomDistance = Math.min(controller.minimumZoomDistance, boundingSphere.radius * 0.5);
  111680. //The default HPR is not ideal for high altitude objects so
  111681. //we scale the pitch as we get further from the earth for a more
  111682. //downward view.
  111683. scratchHeadingPitchRange.pitch = -CesiumMath.PI_OVER_FOUR;
  111684. scratchHeadingPitchRange.range = 0;
  111685. var position = positionProperty.getValue(time, scratchCartesian);
  111686. if (defined(position)) {
  111687. var factor = 2 - 1 / Math.max(1, Cartesian3.magnitude(position) / ellipsoid.maximumRadius);
  111688. scratchHeadingPitchRange.pitch *= factor;
  111689. }
  111690. camera.viewBoundingSphere(boundingSphere, scratchHeadingPitchRange);
  111691. this.boundingSphere = boundingSphere;
  111692. updateLookAt = false;
  111693. saveCamera = false;
  111694. } else if (!hasViewFrom || !defined(viewFromProperty.getValue(time, offset3D))) {
  111695. Cartesian3.clone(EntityView._defaultOffset3D, offset3D);
  111696. }
  111697. } else if (!sceneModeChanged && scene.mode !== SceneMode.MORPHING && this._mode !== SceneMode.SCENE2D) {
  111698. Cartesian3.clone(camera.position, offset3D);
  111699. }
  111700. this._lastEntity = entity;
  111701. this._mode = scene.mode !== SceneMode.MORPHING ? scene.mode : this._mode;
  111702. if (scene.mode !== SceneMode.MORPHING) {
  111703. updateTransform(this, camera, updateLookAt, saveCamera, positionProperty, time, ellipsoid);
  111704. }
  111705. };
  111706. return EntityView;
  111707. });
  111708. /**
  111709. @license
  111710. topojson - https://github.com/mbostock/topojson
  111711. Copyright (c) 2012, Michael Bostock
  111712. All rights reserved.
  111713. Redistribution and use in source and binary forms, with or without
  111714. modification, are permitted provided that the following conditions are met:
  111715. * Redistributions of source code must retain the above copyright notice, this
  111716. list of conditions and the following disclaimer.
  111717. * Redistributions in binary form must reproduce the above copyright notice,
  111718. this list of conditions and the following disclaimer in the documentation
  111719. and/or other materials provided with the distribution.
  111720. * The name Michael Bostock may not be used to endorse or promote products
  111721. derived from this software without specific prior written permission.
  111722. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  111723. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  111724. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  111725. DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
  111726. INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  111727. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  111728. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  111729. OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  111730. NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  111731. EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  111732. */
  111733. !function() {
  111734. var topojson = {
  111735. version: "1.6.18",
  111736. mesh: function(topology) { return object(topology, meshArcs.apply(this, arguments)); },
  111737. meshArcs: meshArcs,
  111738. merge: function(topology) { return object(topology, mergeArcs.apply(this, arguments)); },
  111739. mergeArcs: mergeArcs,
  111740. feature: featureOrCollection,
  111741. neighbors: neighbors,
  111742. presimplify: presimplify
  111743. };
  111744. function stitchArcs(topology, arcs) {
  111745. var stitchedArcs = {},
  111746. fragmentByStart = {},
  111747. fragmentByEnd = {},
  111748. fragments = [],
  111749. emptyIndex = -1;
  111750. // Stitch empty arcs first, since they may be subsumed by other arcs.
  111751. arcs.forEach(function(i, j) {
  111752. var arc = topology.arcs[i < 0 ? ~i : i], t;
  111753. if (arc.length < 3 && !arc[1][0] && !arc[1][1]) {
  111754. t = arcs[++emptyIndex], arcs[emptyIndex] = i, arcs[j] = t;
  111755. }
  111756. });
  111757. arcs.forEach(function(i) {
  111758. var e = ends(i),
  111759. start = e[0],
  111760. end = e[1],
  111761. f, g;
  111762. if (f = fragmentByEnd[start]) {
  111763. delete fragmentByEnd[f.end];
  111764. f.push(i);
  111765. f.end = end;
  111766. if (g = fragmentByStart[end]) {
  111767. delete fragmentByStart[g.start];
  111768. var fg = g === f ? f : f.concat(g);
  111769. fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.end] = fg;
  111770. } else {
  111771. fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
  111772. }
  111773. } else if (f = fragmentByStart[end]) {
  111774. delete fragmentByStart[f.start];
  111775. f.unshift(i);
  111776. f.start = start;
  111777. if (g = fragmentByEnd[start]) {
  111778. delete fragmentByEnd[g.end];
  111779. var gf = g === f ? f : g.concat(f);
  111780. fragmentByStart[gf.start = g.start] = fragmentByEnd[gf.end = f.end] = gf;
  111781. } else {
  111782. fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
  111783. }
  111784. } else {
  111785. f = [i];
  111786. fragmentByStart[f.start = start] = fragmentByEnd[f.end = end] = f;
  111787. }
  111788. });
  111789. function ends(i) {
  111790. var arc = topology.arcs[i < 0 ? ~i : i], p0 = arc[0], p1;
  111791. if (topology.transform) p1 = [0, 0], arc.forEach(function(dp) { p1[0] += dp[0], p1[1] += dp[1]; });
  111792. else p1 = arc[arc.length - 1];
  111793. return i < 0 ? [p1, p0] : [p0, p1];
  111794. }
  111795. function flush(fragmentByEnd, fragmentByStart) {
  111796. for (var k in fragmentByEnd) {
  111797. var f = fragmentByEnd[k];
  111798. delete fragmentByStart[f.start];
  111799. delete f.start;
  111800. delete f.end;
  111801. f.forEach(function(i) { stitchedArcs[i < 0 ? ~i : i] = 1; });
  111802. fragments.push(f);
  111803. }
  111804. }
  111805. flush(fragmentByEnd, fragmentByStart);
  111806. flush(fragmentByStart, fragmentByEnd);
  111807. arcs.forEach(function(i) { if (!stitchedArcs[i < 0 ? ~i : i]) fragments.push([i]); });
  111808. return fragments;
  111809. }
  111810. function meshArcs(topology, o, filter) {
  111811. var arcs = [];
  111812. if (arguments.length > 1) {
  111813. var geomsByArc = [],
  111814. geom;
  111815. function arc(i) {
  111816. var j = i < 0 ? ~i : i;
  111817. (geomsByArc[j] || (geomsByArc[j] = [])).push({i: i, g: geom});
  111818. }
  111819. function line(arcs) {
  111820. arcs.forEach(arc);
  111821. }
  111822. function polygon(arcs) {
  111823. arcs.forEach(line);
  111824. }
  111825. function geometry(o) {
  111826. if (o.type === "GeometryCollection") o.geometries.forEach(geometry);
  111827. else if (o.type in geometryType) geom = o, geometryType[o.type](o.arcs);
  111828. }
  111829. var geometryType = {
  111830. LineString: line,
  111831. MultiLineString: polygon,
  111832. Polygon: polygon,
  111833. MultiPolygon: function(arcs) { arcs.forEach(polygon); }
  111834. };
  111835. geometry(o);
  111836. geomsByArc.forEach(arguments.length < 3
  111837. ? function(geoms) { arcs.push(geoms[0].i); }
  111838. : function(geoms) { if (filter(geoms[0].g, geoms[geoms.length - 1].g)) arcs.push(geoms[0].i); });
  111839. } else {
  111840. for (var i = 0, n = topology.arcs.length; i < n; ++i) arcs.push(i);
  111841. }
  111842. return {type: "MultiLineString", arcs: stitchArcs(topology, arcs)};
  111843. }
  111844. function mergeArcs(topology, objects) {
  111845. var polygonsByArc = {},
  111846. polygons = [],
  111847. components = [];
  111848. objects.forEach(function(o) {
  111849. if (o.type === "Polygon") register(o.arcs);
  111850. else if (o.type === "MultiPolygon") o.arcs.forEach(register);
  111851. });
  111852. function register(polygon) {
  111853. polygon.forEach(function(ring) {
  111854. ring.forEach(function(arc) {
  111855. (polygonsByArc[arc = arc < 0 ? ~arc : arc] || (polygonsByArc[arc] = [])).push(polygon);
  111856. });
  111857. });
  111858. polygons.push(polygon);
  111859. }
  111860. function exterior(ring) {
  111861. return cartesianRingArea(object(topology, {type: "Polygon", arcs: [ring]}).coordinates[0]) > 0; // TODO allow spherical?
  111862. }
  111863. polygons.forEach(function(polygon) {
  111864. if (!polygon._) {
  111865. var component = [],
  111866. neighbors = [polygon];
  111867. polygon._ = 1;
  111868. components.push(component);
  111869. while (polygon = neighbors.pop()) {
  111870. component.push(polygon);
  111871. polygon.forEach(function(ring) {
  111872. ring.forEach(function(arc) {
  111873. polygonsByArc[arc < 0 ? ~arc : arc].forEach(function(polygon) {
  111874. if (!polygon._) {
  111875. polygon._ = 1;
  111876. neighbors.push(polygon);
  111877. }
  111878. });
  111879. });
  111880. });
  111881. }
  111882. }
  111883. });
  111884. polygons.forEach(function(polygon) {
  111885. delete polygon._;
  111886. });
  111887. return {
  111888. type: "MultiPolygon",
  111889. arcs: components.map(function(polygons) {
  111890. var arcs = [];
  111891. // Extract the exterior (unique) arcs.
  111892. polygons.forEach(function(polygon) {
  111893. polygon.forEach(function(ring) {
  111894. ring.forEach(function(arc) {
  111895. if (polygonsByArc[arc < 0 ? ~arc : arc].length < 2) {
  111896. arcs.push(arc);
  111897. }
  111898. });
  111899. });
  111900. });
  111901. // Stitch the arcs into one or more rings.
  111902. arcs = stitchArcs(topology, arcs);
  111903. // If more than one ring is returned,
  111904. // at most one of these rings can be the exterior;
  111905. // this exterior ring has the same winding order
  111906. // as any exterior ring in the original polygons.
  111907. if ((n = arcs.length) > 1) {
  111908. var sgn = exterior(polygons[0][0]);
  111909. for (var i = 0, t; i < n; ++i) {
  111910. if (sgn === exterior(arcs[i])) {
  111911. t = arcs[0], arcs[0] = arcs[i], arcs[i] = t;
  111912. break;
  111913. }
  111914. }
  111915. }
  111916. return arcs;
  111917. })
  111918. };
  111919. }
  111920. function featureOrCollection(topology, o) {
  111921. return o.type === "GeometryCollection" ? {
  111922. type: "FeatureCollection",
  111923. features: o.geometries.map(function(o) { return feature(topology, o); })
  111924. } : feature(topology, o);
  111925. }
  111926. function feature(topology, o) {
  111927. var f = {
  111928. type: "Feature",
  111929. id: o.id,
  111930. properties: o.properties || {},
  111931. geometry: object(topology, o)
  111932. };
  111933. if (o.id == null) delete f.id;
  111934. return f;
  111935. }
  111936. function object(topology, o) {
  111937. var absolute = transformAbsolute(topology.transform),
  111938. arcs = topology.arcs;
  111939. function arc(i, points) {
  111940. if (points.length) points.pop();
  111941. for (var a = arcs[i < 0 ? ~i : i], k = 0, n = a.length, p; k < n; ++k) {
  111942. points.push(p = a[k].slice());
  111943. absolute(p, k);
  111944. }
  111945. if (i < 0) reverse(points, n);
  111946. }
  111947. function point(p) {
  111948. p = p.slice();
  111949. absolute(p, 0);
  111950. return p;
  111951. }
  111952. function line(arcs) {
  111953. var points = [];
  111954. for (var i = 0, n = arcs.length; i < n; ++i) arc(arcs[i], points);
  111955. if (points.length < 2) points.push(points[0].slice());
  111956. return points;
  111957. }
  111958. function ring(arcs) {
  111959. var points = line(arcs);
  111960. while (points.length < 4) points.push(points[0].slice());
  111961. return points;
  111962. }
  111963. function polygon(arcs) {
  111964. return arcs.map(ring);
  111965. }
  111966. function geometry(o) {
  111967. var t = o.type;
  111968. return t === "GeometryCollection" ? {type: t, geometries: o.geometries.map(geometry)}
  111969. : t in geometryType ? {type: t, coordinates: geometryType[t](o)}
  111970. : null;
  111971. }
  111972. var geometryType = {
  111973. Point: function(o) { return point(o.coordinates); },
  111974. MultiPoint: function(o) { return o.coordinates.map(point); },
  111975. LineString: function(o) { return line(o.arcs); },
  111976. MultiLineString: function(o) { return o.arcs.map(line); },
  111977. Polygon: function(o) { return polygon(o.arcs); },
  111978. MultiPolygon: function(o) { return o.arcs.map(polygon); }
  111979. };
  111980. return geometry(o);
  111981. }
  111982. function reverse(array, n) {
  111983. var t, j = array.length, i = j - n; while (i < --j) t = array[i], array[i++] = array[j], array[j] = t;
  111984. }
  111985. function bisect(a, x) {
  111986. var lo = 0, hi = a.length;
  111987. while (lo < hi) {
  111988. var mid = lo + hi >>> 1;
  111989. if (a[mid] < x) lo = mid + 1;
  111990. else hi = mid;
  111991. }
  111992. return lo;
  111993. }
  111994. function neighbors(objects) {
  111995. var indexesByArc = {}, // arc index -> array of object indexes
  111996. neighbors = objects.map(function() { return []; });
  111997. function line(arcs, i) {
  111998. arcs.forEach(function(a) {
  111999. if (a < 0) a = ~a;
  112000. var o = indexesByArc[a];
  112001. if (o) o.push(i);
  112002. else indexesByArc[a] = [i];
  112003. });
  112004. }
  112005. function polygon(arcs, i) {
  112006. arcs.forEach(function(arc) { line(arc, i); });
  112007. }
  112008. function geometry(o, i) {
  112009. if (o.type === "GeometryCollection") o.geometries.forEach(function(o) { geometry(o, i); });
  112010. else if (o.type in geometryType) geometryType[o.type](o.arcs, i);
  112011. }
  112012. var geometryType = {
  112013. LineString: line,
  112014. MultiLineString: polygon,
  112015. Polygon: polygon,
  112016. MultiPolygon: function(arcs, i) { arcs.forEach(function(arc) { polygon(arc, i); }); }
  112017. };
  112018. objects.forEach(geometry);
  112019. for (var i in indexesByArc) {
  112020. for (var indexes = indexesByArc[i], m = indexes.length, j = 0; j < m; ++j) {
  112021. for (var k = j + 1; k < m; ++k) {
  112022. var ij = indexes[j], ik = indexes[k], n;
  112023. if ((n = neighbors[ij])[i = bisect(n, ik)] !== ik) n.splice(i, 0, ik);
  112024. if ((n = neighbors[ik])[i = bisect(n, ij)] !== ij) n.splice(i, 0, ij);
  112025. }
  112026. }
  112027. }
  112028. return neighbors;
  112029. }
  112030. function presimplify(topology, triangleArea) {
  112031. var absolute = transformAbsolute(topology.transform),
  112032. relative = transformRelative(topology.transform),
  112033. heap = minAreaHeap();
  112034. if (!triangleArea) triangleArea = cartesianTriangleArea;
  112035. topology.arcs.forEach(function(arc) {
  112036. var triangles = [],
  112037. maxArea = 0,
  112038. triangle;
  112039. // To store each point’s effective area, we create a new array rather than
  112040. // extending the passed-in point to workaround a Chrome/V8 bug (getting
  112041. // stuck in smi mode). For midpoints, the initial effective area of
  112042. // Infinity will be computed in the next step.
  112043. for (var i = 0, n = arc.length, p; i < n; ++i) {
  112044. p = arc[i];
  112045. absolute(arc[i] = [p[0], p[1], Infinity], i);
  112046. }
  112047. for (var i = 1, n = arc.length - 1; i < n; ++i) {
  112048. triangle = arc.slice(i - 1, i + 2);
  112049. triangle[1][2] = triangleArea(triangle);
  112050. triangles.push(triangle);
  112051. heap.push(triangle);
  112052. }
  112053. for (var i = 0, n = triangles.length; i < n; ++i) {
  112054. triangle = triangles[i];
  112055. triangle.previous = triangles[i - 1];
  112056. triangle.next = triangles[i + 1];
  112057. }
  112058. while (triangle = heap.pop()) {
  112059. var previous = triangle.previous,
  112060. next = triangle.next;
  112061. // If the area of the current point is less than that of the previous point
  112062. // to be eliminated, use the latter's area instead. This ensures that the
  112063. // current point cannot be eliminated without eliminating previously-
  112064. // eliminated points.
  112065. if (triangle[1][2] < maxArea) triangle[1][2] = maxArea;
  112066. else maxArea = triangle[1][2];
  112067. if (previous) {
  112068. previous.next = next;
  112069. previous[2] = triangle[2];
  112070. update(previous);
  112071. }
  112072. if (next) {
  112073. next.previous = previous;
  112074. next[0] = triangle[0];
  112075. update(next);
  112076. }
  112077. }
  112078. arc.forEach(relative);
  112079. });
  112080. function update(triangle) {
  112081. heap.remove(triangle);
  112082. triangle[1][2] = triangleArea(triangle);
  112083. heap.push(triangle);
  112084. }
  112085. return topology;
  112086. }
  112087. function cartesianRingArea(ring) {
  112088. var i = -1,
  112089. n = ring.length,
  112090. a,
  112091. b = ring[n - 1],
  112092. area = 0;
  112093. while (++i < n) {
  112094. a = b;
  112095. b = ring[i];
  112096. area += a[0] * b[1] - a[1] * b[0];
  112097. }
  112098. return area * .5;
  112099. }
  112100. function cartesianTriangleArea(triangle) {
  112101. var a = triangle[0], b = triangle[1], c = triangle[2];
  112102. return Math.abs((a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]));
  112103. }
  112104. function compareArea(a, b) {
  112105. return a[1][2] - b[1][2];
  112106. }
  112107. function minAreaHeap() {
  112108. var heap = {},
  112109. array = [],
  112110. size = 0;
  112111. heap.push = function(object) {
  112112. up(array[object._ = size] = object, size++);
  112113. return size;
  112114. };
  112115. heap.pop = function() {
  112116. if (size <= 0) return;
  112117. var removed = array[0], object;
  112118. if (--size > 0) object = array[size], down(array[object._ = 0] = object, 0);
  112119. return removed;
  112120. };
  112121. heap.remove = function(removed) {
  112122. var i = removed._, object;
  112123. if (array[i] !== removed) return; // invalid request
  112124. if (i !== --size) object = array[size], (compareArea(object, removed) < 0 ? up : down)(array[object._ = i] = object, i);
  112125. return i;
  112126. };
  112127. function up(object, i) {
  112128. while (i > 0) {
  112129. var j = ((i + 1) >> 1) - 1,
  112130. parent = array[j];
  112131. if (compareArea(object, parent) >= 0) break;
  112132. array[parent._ = i] = parent;
  112133. array[object._ = i = j] = object;
  112134. }
  112135. }
  112136. function down(object, i) {
  112137. while (true) {
  112138. var r = (i + 1) << 1,
  112139. l = r - 1,
  112140. j = i,
  112141. child = array[j];
  112142. if (l < size && compareArea(array[l], child) < 0) child = array[j = l];
  112143. if (r < size && compareArea(array[r], child) < 0) child = array[j = r];
  112144. if (j === i) break;
  112145. array[child._ = i] = child;
  112146. array[object._ = i = j] = object;
  112147. }
  112148. }
  112149. return heap;
  112150. }
  112151. function transformAbsolute(transform) {
  112152. if (!transform) return noop;
  112153. var x0,
  112154. y0,
  112155. kx = transform.scale[0],
  112156. ky = transform.scale[1],
  112157. dx = transform.translate[0],
  112158. dy = transform.translate[1];
  112159. return function(point, i) {
  112160. if (!i) x0 = y0 = 0;
  112161. point[0] = (x0 += point[0]) * kx + dx;
  112162. point[1] = (y0 += point[1]) * ky + dy;
  112163. };
  112164. }
  112165. function transformRelative(transform) {
  112166. if (!transform) return noop;
  112167. var x0,
  112168. y0,
  112169. kx = transform.scale[0],
  112170. ky = transform.scale[1],
  112171. dx = transform.translate[0],
  112172. dy = transform.translate[1];
  112173. return function(point, i) {
  112174. if (!i) x0 = y0 = 0;
  112175. var x1 = (point[0] - dx) / kx | 0,
  112176. y1 = (point[1] - dy) / ky | 0;
  112177. point[0] = x1 - x0;
  112178. point[1] = y1 - y0;
  112179. x0 = x1;
  112180. y0 = y1;
  112181. };
  112182. }
  112183. function noop() {}
  112184. if (typeof define === "function" && define.amd) define('ThirdParty/topojson',topojson);
  112185. else if (typeof module === "object" && module.exports) module.exports = topojson;
  112186. else this.topojson = topojson;
  112187. }();
  112188. /*global define*/
  112189. define('DataSources/GeoJsonDataSource',[
  112190. '../Core/Cartesian3',
  112191. '../Core/Color',
  112192. '../Core/createGuid',
  112193. '../Core/defaultValue',
  112194. '../Core/defined',
  112195. '../Core/defineProperties',
  112196. '../Core/DeveloperError',
  112197. '../Core/Event',
  112198. '../Core/getFilenameFromUri',
  112199. '../Core/loadJson',
  112200. '../Core/PinBuilder',
  112201. '../Core/PolygonHierarchy',
  112202. '../Core/RuntimeError',
  112203. '../Scene/HeightReference',
  112204. '../Scene/VerticalOrigin',
  112205. '../ThirdParty/topojson',
  112206. '../ThirdParty/when',
  112207. './BillboardGraphics',
  112208. './CallbackProperty',
  112209. './ColorMaterialProperty',
  112210. './ConstantPositionProperty',
  112211. './ConstantProperty',
  112212. './CorridorGraphics',
  112213. './DataSource',
  112214. './EntityCluster',
  112215. './EntityCollection',
  112216. './PolygonGraphics',
  112217. './PolylineGraphics'
  112218. ], function(
  112219. Cartesian3,
  112220. Color,
  112221. createGuid,
  112222. defaultValue,
  112223. defined,
  112224. defineProperties,
  112225. DeveloperError,
  112226. Event,
  112227. getFilenameFromUri,
  112228. loadJson,
  112229. PinBuilder,
  112230. PolygonHierarchy,
  112231. RuntimeError,
  112232. HeightReference,
  112233. VerticalOrigin,
  112234. topojson,
  112235. when,
  112236. BillboardGraphics,
  112237. CallbackProperty,
  112238. ColorMaterialProperty,
  112239. ConstantPositionProperty,
  112240. ConstantProperty,
  112241. CorridorGraphics,
  112242. DataSource,
  112243. EntityCluster,
  112244. EntityCollection,
  112245. PolygonGraphics,
  112246. PolylineGraphics) {
  112247. 'use strict';
  112248. function defaultCrsFunction(coordinates) {
  112249. return Cartesian3.fromDegrees(coordinates[0], coordinates[1], coordinates[2]);
  112250. }
  112251. var crsNames = {
  112252. 'urn:ogc:def:crs:OGC:1.3:CRS84' : defaultCrsFunction,
  112253. 'EPSG:4326' : defaultCrsFunction,
  112254. 'urn:ogc:def:crs:EPSG::4326' : defaultCrsFunction
  112255. };
  112256. var crsLinkHrefs = {};
  112257. var crsLinkTypes = {};
  112258. var defaultMarkerSize = 48;
  112259. var defaultMarkerSymbol;
  112260. var defaultMarkerColor = Color.ROYALBLUE;
  112261. var defaultStroke = Color.YELLOW;
  112262. var defaultStrokeWidth = 2;
  112263. var defaultFill = Color.fromBytes(255, 255, 0, 100);
  112264. var defaultClampToGround = false;
  112265. var defaultStrokeWidthProperty = new ConstantProperty(defaultStrokeWidth);
  112266. var defaultStrokeMaterialProperty = new ColorMaterialProperty(defaultStroke);
  112267. var defaultFillMaterialProperty = new ColorMaterialProperty(defaultFill);
  112268. var sizes = {
  112269. small : 24,
  112270. medium : 48,
  112271. large : 64
  112272. };
  112273. var simpleStyleIdentifiers = ['title', 'description', //
  112274. 'marker-size', 'marker-symbol', 'marker-color', 'stroke', //
  112275. 'stroke-opacity', 'stroke-width', 'fill', 'fill-opacity'];
  112276. function defaultDescribe(properties, nameProperty) {
  112277. var html = '';
  112278. for ( var key in properties) {
  112279. if (properties.hasOwnProperty(key)) {
  112280. if (key === nameProperty || simpleStyleIdentifiers.indexOf(key) !== -1) {
  112281. continue;
  112282. }
  112283. var value = properties[key];
  112284. if (defined(value)) {
  112285. if (typeof value === 'object') {
  112286. html += '<tr><th>' + key + '</th><td>' + defaultDescribe(value) + '</td></tr>';
  112287. } else {
  112288. html += '<tr><th>' + key + '</th><td>' + value + '</td></tr>';
  112289. }
  112290. }
  112291. }
  112292. }
  112293. if (html.length > 0) {
  112294. html = '<table class="cesium-infoBox-defaultTable"><tbody>' + html + '</tbody></table>';
  112295. }
  112296. return html;
  112297. }
  112298. function createDescriptionCallback(describe, properties, nameProperty) {
  112299. var description;
  112300. return function(time, result) {
  112301. if (!defined(description)) {
  112302. description = describe(properties, nameProperty);
  112303. }
  112304. return description;
  112305. };
  112306. }
  112307. function defaultDescribeProperty(properties, nameProperty) {
  112308. return new CallbackProperty(createDescriptionCallback(defaultDescribe, properties, nameProperty), true);
  112309. }
  112310. //GeoJSON specifies only the Feature object has a usable id property
  112311. //But since "multi" geometries create multiple entity,
  112312. //we can't use it for them either.
  112313. function createObject(geoJson, entityCollection, describe) {
  112314. var id = geoJson.id;
  112315. if (!defined(id) || geoJson.type !== 'Feature') {
  112316. id = createGuid();
  112317. } else {
  112318. var i = 2;
  112319. var finalId = id;
  112320. while (defined(entityCollection.getById(finalId))) {
  112321. finalId = id + "_" + i;
  112322. i++;
  112323. }
  112324. id = finalId;
  112325. }
  112326. var entity = entityCollection.getOrCreateEntity(id);
  112327. var properties = geoJson.properties;
  112328. if (defined(properties)) {
  112329. entity.addProperty('properties');
  112330. entity.properties = properties;
  112331. var nameProperty;
  112332. //Check for the simplestyle specified name first.
  112333. var name = properties.title;
  112334. if (defined(name)) {
  112335. entity.name = name;
  112336. nameProperty = 'title';
  112337. } else {
  112338. //Else, find the name by selecting an appropriate property.
  112339. //The name will be obtained based on this order:
  112340. //1) The first case-insensitive property with the name 'title',
  112341. //2) The first case-insensitive property with the name 'name',
  112342. //3) The first property containing the word 'title'.
  112343. //4) The first property containing the word 'name',
  112344. var namePropertyPrecedence = Number.MAX_VALUE;
  112345. for ( var key in properties) {
  112346. if (properties.hasOwnProperty(key) && properties[key]) {
  112347. var lowerKey = key.toLowerCase();
  112348. if (namePropertyPrecedence > 1 && lowerKey === 'title') {
  112349. namePropertyPrecedence = 1;
  112350. nameProperty = key;
  112351. break;
  112352. } else if (namePropertyPrecedence > 2 && lowerKey === 'name') {
  112353. namePropertyPrecedence = 2;
  112354. nameProperty = key;
  112355. } else if (namePropertyPrecedence > 3 && /title/i.test(key)) {
  112356. namePropertyPrecedence = 3;
  112357. nameProperty = key;
  112358. } else if (namePropertyPrecedence > 4 && /name/i.test(key)) {
  112359. namePropertyPrecedence = 4;
  112360. nameProperty = key;
  112361. }
  112362. }
  112363. }
  112364. if (defined(nameProperty)) {
  112365. entity.name = properties[nameProperty];
  112366. }
  112367. }
  112368. var description = properties.description;
  112369. if (description !== null) {
  112370. entity.description = !defined(description) ? describe(properties, nameProperty) : new ConstantProperty(description);
  112371. }
  112372. }
  112373. return entity;
  112374. }
  112375. function coordinatesArrayToCartesianArray(coordinates, crsFunction) {
  112376. var positions = new Array(coordinates.length);
  112377. for (var i = 0; i < coordinates.length; i++) {
  112378. positions[i] = crsFunction(coordinates[i]);
  112379. }
  112380. return positions;
  112381. }
  112382. // GeoJSON processing functions
  112383. function processFeature(dataSource, feature, notUsed, crsFunction, options) {
  112384. if (feature.geometry === null) {
  112385. //Null geometry is allowed, so just create an empty entity instance for it.
  112386. createObject(feature, dataSource._entityCollection, options.describe);
  112387. return;
  112388. }
  112389. if (!defined(feature.geometry)) {
  112390. throw new RuntimeError('feature.geometry is required.');
  112391. }
  112392. var geometryType = feature.geometry.type;
  112393. var geometryHandler = geometryTypes[geometryType];
  112394. if (!defined(geometryHandler)) {
  112395. throw new RuntimeError('Unknown geometry type: ' + geometryType);
  112396. }
  112397. geometryHandler(dataSource, feature, feature.geometry, crsFunction, options);
  112398. }
  112399. function processFeatureCollection(dataSource, featureCollection, notUsed, crsFunction, options) {
  112400. var features = featureCollection.features;
  112401. for (var i = 0, len = features.length; i < len; i++) {
  112402. processFeature(dataSource, features[i], undefined, crsFunction, options);
  112403. }
  112404. }
  112405. function processGeometryCollection(dataSource, geoJson, geometryCollection, crsFunction, options) {
  112406. var geometries = geometryCollection.geometries;
  112407. for (var i = 0, len = geometries.length; i < len; i++) {
  112408. var geometry = geometries[i];
  112409. var geometryType = geometry.type;
  112410. var geometryHandler = geometryTypes[geometryType];
  112411. if (!defined(geometryHandler)) {
  112412. throw new RuntimeError('Unknown geometry type: ' + geometryType);
  112413. }
  112414. geometryHandler(dataSource, geoJson, geometry, crsFunction, options);
  112415. }
  112416. }
  112417. function createPoint(dataSource, geoJson, crsFunction, coordinates, options) {
  112418. var symbol = options.markerSymbol;
  112419. var color = options.markerColor;
  112420. var size = options.markerSize;
  112421. var properties = geoJson.properties;
  112422. if (defined(properties)) {
  112423. var cssColor = properties['marker-color'];
  112424. if (defined(cssColor)) {
  112425. color = Color.fromCssColorString(cssColor);
  112426. }
  112427. size = defaultValue(sizes[properties['marker-size']], size);
  112428. var markerSymbol = properties['marker-symbol'];
  112429. if (defined(markerSymbol)) {
  112430. symbol = markerSymbol;
  112431. }
  112432. }
  112433. var canvasOrPromise;
  112434. if (defined(symbol)) {
  112435. if (symbol.length === 1) {
  112436. canvasOrPromise = dataSource._pinBuilder.fromText(symbol.toUpperCase(), color, size);
  112437. } else {
  112438. canvasOrPromise = dataSource._pinBuilder.fromMakiIconId(symbol, color, size);
  112439. }
  112440. } else {
  112441. canvasOrPromise = dataSource._pinBuilder.fromColor(color, size);
  112442. }
  112443. var billboard = new BillboardGraphics();
  112444. billboard.verticalOrigin = new ConstantProperty(VerticalOrigin.BOTTOM);
  112445. // Clamp to ground if there isn't a height specified
  112446. if (coordinates.length === 2 && options.clampToGround) {
  112447. billboard.heightReference = HeightReference.CLAMP_TO_GROUND;
  112448. }
  112449. var entity = createObject(geoJson, dataSource._entityCollection, options.describe);
  112450. entity.billboard = billboard;
  112451. entity.position = new ConstantPositionProperty(crsFunction(coordinates));
  112452. var promise = when(canvasOrPromise).then(function(image) {
  112453. billboard.image = new ConstantProperty(image);
  112454. }).otherwise(function() {
  112455. billboard.image = new ConstantProperty(dataSource._pinBuilder.fromColor(color, size));
  112456. });
  112457. dataSource._promises.push(promise);
  112458. }
  112459. function processPoint(dataSource, geoJson, geometry, crsFunction, options) {
  112460. createPoint(dataSource, geoJson, crsFunction, geometry.coordinates, options);
  112461. }
  112462. function processMultiPoint(dataSource, geoJson, geometry, crsFunction, options) {
  112463. var coordinates = geometry.coordinates;
  112464. for (var i = 0; i < coordinates.length; i++) {
  112465. createPoint(dataSource, geoJson, crsFunction, coordinates[i], options);
  112466. }
  112467. }
  112468. function createLineString(dataSource, geoJson, crsFunction, coordinates, options) {
  112469. var material = options.strokeMaterialProperty;
  112470. var widthProperty = options.strokeWidthProperty;
  112471. var properties = geoJson.properties;
  112472. if (defined(properties)) {
  112473. var width = properties['stroke-width'];
  112474. if (defined(width)) {
  112475. widthProperty = new ConstantProperty(width);
  112476. }
  112477. var color;
  112478. var stroke = properties.stroke;
  112479. if (defined(stroke)) {
  112480. color = Color.fromCssColorString(stroke);
  112481. }
  112482. var opacity = properties['stroke-opacity'];
  112483. if (defined(opacity) && opacity !== 1.0) {
  112484. if (!defined(color)) {
  112485. color = material.color.clone();
  112486. }
  112487. color.alpha = opacity;
  112488. }
  112489. if (defined(color)) {
  112490. material = new ColorMaterialProperty(color);
  112491. }
  112492. }
  112493. var entity = createObject(geoJson, dataSource._entityCollection, options.describe);
  112494. var graphics;
  112495. if (options.clampToGround) {
  112496. graphics = new CorridorGraphics();
  112497. entity.corridor = graphics;
  112498. } else {
  112499. graphics = new PolylineGraphics();
  112500. entity.polyline = graphics;
  112501. }
  112502. graphics.material = material;
  112503. graphics.width = widthProperty;
  112504. graphics.positions = new ConstantProperty(coordinatesArrayToCartesianArray(coordinates, crsFunction));
  112505. }
  112506. function processLineString(dataSource, geoJson, geometry, crsFunction, options) {
  112507. createLineString(dataSource, geoJson, crsFunction, geometry.coordinates, options);
  112508. }
  112509. function processMultiLineString(dataSource, geoJson, geometry, crsFunction, options) {
  112510. var lineStrings = geometry.coordinates;
  112511. for (var i = 0; i < lineStrings.length; i++) {
  112512. createLineString(dataSource, geoJson, crsFunction, lineStrings[i], options);
  112513. }
  112514. }
  112515. function createPolygon(dataSource, geoJson, crsFunction, coordinates, options) {
  112516. if (coordinates.length === 0 || coordinates[0].length === 0) {
  112517. return;
  112518. }
  112519. var outlineColorProperty = options.strokeMaterialProperty.color;
  112520. var material = options.fillMaterialProperty;
  112521. var widthProperty = options.strokeWidthProperty;
  112522. var properties = geoJson.properties;
  112523. if (defined(properties)) {
  112524. var width = properties['stroke-width'];
  112525. if (defined(width)) {
  112526. widthProperty = new ConstantProperty(width);
  112527. }
  112528. var color;
  112529. var stroke = properties.stroke;
  112530. if (defined(stroke)) {
  112531. color = Color.fromCssColorString(stroke);
  112532. }
  112533. var opacity = properties['stroke-opacity'];
  112534. if (defined(opacity) && opacity !== 1.0) {
  112535. if (!defined(color)) {
  112536. color = options.strokeMaterialProperty.color.clone();
  112537. }
  112538. color.alpha = opacity;
  112539. }
  112540. if (defined(color)) {
  112541. outlineColorProperty = new ConstantProperty(color);
  112542. }
  112543. var fillColor;
  112544. var fill = properties.fill;
  112545. if (defined(fill)) {
  112546. fillColor = Color.fromCssColorString(fill);
  112547. fillColor.alpha = material.color.alpha;
  112548. }
  112549. opacity = properties['fill-opacity'];
  112550. if (defined(opacity) && opacity !== material.color.alpha) {
  112551. if (!defined(fillColor)) {
  112552. fillColor = material.color.clone();
  112553. }
  112554. fillColor.alpha = opacity;
  112555. }
  112556. if (defined(fillColor)) {
  112557. material = new ColorMaterialProperty(fillColor);
  112558. }
  112559. }
  112560. var polygon = new PolygonGraphics();
  112561. polygon.outline = new ConstantProperty(true);
  112562. polygon.outlineColor = outlineColorProperty;
  112563. polygon.outlineWidth = widthProperty;
  112564. polygon.material = material;
  112565. var holes = [];
  112566. for (var i = 1, len = coordinates.length; i < len; i++) {
  112567. holes.push(new PolygonHierarchy(coordinatesArrayToCartesianArray(coordinates[i], crsFunction)));
  112568. }
  112569. var positions = coordinates[0];
  112570. polygon.hierarchy = new ConstantProperty(new PolygonHierarchy(coordinatesArrayToCartesianArray(positions, crsFunction), holes));
  112571. if (positions[0].length > 2) {
  112572. polygon.perPositionHeight = new ConstantProperty(true);
  112573. } else if (!options.clampToGround) {
  112574. polygon.height = 0;
  112575. }
  112576. var entity = createObject(geoJson, dataSource._entityCollection, options.describe);
  112577. entity.polygon = polygon;
  112578. }
  112579. function processPolygon(dataSource, geoJson, geometry, crsFunction, options) {
  112580. createPolygon(dataSource, geoJson, crsFunction, geometry.coordinates, options);
  112581. }
  112582. function processMultiPolygon(dataSource, geoJson, geometry, crsFunction, options) {
  112583. var polygons = geometry.coordinates;
  112584. for (var i = 0; i < polygons.length; i++) {
  112585. createPolygon(dataSource, geoJson, crsFunction, polygons[i], options);
  112586. }
  112587. }
  112588. function processTopology(dataSource, geoJson, geometry, crsFunction, options) {
  112589. for ( var property in geometry.objects) {
  112590. if (geometry.objects.hasOwnProperty(property)) {
  112591. var feature = topojson.feature(geometry, geometry.objects[property]);
  112592. var typeHandler = geoJsonObjectTypes[feature.type];
  112593. typeHandler(dataSource, feature, feature, crsFunction, options);
  112594. }
  112595. }
  112596. }
  112597. var geoJsonObjectTypes = {
  112598. Feature : processFeature,
  112599. FeatureCollection : processFeatureCollection,
  112600. GeometryCollection : processGeometryCollection,
  112601. LineString : processLineString,
  112602. MultiLineString : processMultiLineString,
  112603. MultiPoint : processMultiPoint,
  112604. MultiPolygon : processMultiPolygon,
  112605. Point : processPoint,
  112606. Polygon : processPolygon,
  112607. Topology : processTopology
  112608. };
  112609. var geometryTypes = {
  112610. GeometryCollection : processGeometryCollection,
  112611. LineString : processLineString,
  112612. MultiLineString : processMultiLineString,
  112613. MultiPoint : processMultiPoint,
  112614. MultiPolygon : processMultiPolygon,
  112615. Point : processPoint,
  112616. Polygon : processPolygon,
  112617. Topology : processTopology
  112618. };
  112619. /**
  112620. * A {@link DataSource} which processes both
  112621. * {@link http://www.geojson.org/|GeoJSON} and {@link https://github.com/mbostock/topojson|TopoJSON} data.
  112622. * {@link https://github.com/mapbox/simplestyle-spec|simplestyle-spec} properties will also be used if they
  112623. * are present.
  112624. *
  112625. * @alias GeoJsonDataSource
  112626. * @constructor
  112627. *
  112628. * @param {String} [name] The name of this data source. If undefined, a name will be taken from
  112629. * the name of the GeoJSON file.
  112630. *
  112631. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=GeoJSON%20and%20TopoJSON.html|Cesium Sandcastle GeoJSON and TopoJSON Demo}
  112632. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=GeoJSON%20simplestyle.html|Cesium Sandcastle GeoJSON simplestyle Demo}
  112633. *
  112634. * @example
  112635. * var viewer = new Cesium.Viewer('cesiumContainer');
  112636. * viewer.dataSources.add(Cesium.GeoJsonDataSource.load('../../SampleData/ne_10m_us_states.topojson', {
  112637. * stroke: Cesium.Color.HOTPINK,
  112638. * fill: Cesium.Color.PINK,
  112639. * strokeWidth: 3,
  112640. * markerSymbol: '?'
  112641. * }));
  112642. */
  112643. function GeoJsonDataSource(name) {
  112644. this._name = name;
  112645. this._changed = new Event();
  112646. this._error = new Event();
  112647. this._isLoading = false;
  112648. this._loading = new Event();
  112649. this._entityCollection = new EntityCollection(this);
  112650. this._promises = [];
  112651. this._pinBuilder = new PinBuilder();
  112652. this._entityCluster = new EntityCluster();
  112653. }
  112654. /**
  112655. * Creates a Promise to a new instance loaded with the provided GeoJSON or TopoJSON data.
  112656. *
  112657. * @param {String|Object} data A url, GeoJSON object, or TopoJSON object to be loaded.
  112658. * @param {Object} [options] An object with the following properties:
  112659. * @param {String} [options.sourceUri] Overrides the url to use for resolving relative links.
  112660. * @param {Number} [options.markerSize=GeoJsonDataSource.markerSize] The default size of the map pin created for each point, in pixels.
  112661. * @param {String} [options.markerSymbol=GeoJsonDataSource.markerSymbol] The default symbol of the map pin created for each point.
  112662. * @param {Color} [options.markerColor=GeoJsonDataSource.markerColor] The default color of the map pin created for each point.
  112663. * @param {Color} [options.stroke=GeoJsonDataSource.stroke] The default color of polylines and polygon outlines.
  112664. * @param {Number} [options.strokeWidth=GeoJsonDataSource.strokeWidth] The default width of polylines and polygon outlines.
  112665. * @param {Color} [options.fill=GeoJsonDataSource.fill] The default color for polygon interiors.
  112666. * @param {Boolean} [options.clampToGround=GeoJsonDataSource.clampToGround] true if we want the geometry features (polygons or linestrings) clamped to the ground. If true, lines will use corridors so use Entity.corridor instead of Entity.polyline.
  112667. *
  112668. * @returns {Promise.<GeoJsonDataSource>} A promise that will resolve when the data is loaded.
  112669. */
  112670. GeoJsonDataSource.load = function(data, options) {
  112671. return new GeoJsonDataSource().load(data, options);
  112672. };
  112673. defineProperties(GeoJsonDataSource, {
  112674. /**
  112675. * Gets or sets the default size of the map pin created for each point, in pixels.
  112676. * @memberof GeoJsonDataSource
  112677. * @type {Number}
  112678. * @default 48
  112679. */
  112680. markerSize : {
  112681. get : function() {
  112682. return defaultMarkerSize;
  112683. },
  112684. set : function(value) {
  112685. defaultMarkerSize = value;
  112686. }
  112687. },
  112688. /**
  112689. * Gets or sets the default symbol of the map pin created for each point.
  112690. * This can be any valid {@link http://mapbox.com/maki/|Maki} identifier, any single character,
  112691. * or blank if no symbol is to be used.
  112692. * @memberof GeoJsonDataSource
  112693. * @type {String}
  112694. */
  112695. markerSymbol : {
  112696. get : function() {
  112697. return defaultMarkerSymbol;
  112698. },
  112699. set : function(value) {
  112700. defaultMarkerSymbol = value;
  112701. }
  112702. },
  112703. /**
  112704. * Gets or sets the default color of the map pin created for each point.
  112705. * @memberof GeoJsonDataSource
  112706. * @type {Color}
  112707. * @default Color.ROYALBLUE
  112708. */
  112709. markerColor : {
  112710. get : function() {
  112711. return defaultMarkerColor;
  112712. },
  112713. set : function(value) {
  112714. defaultMarkerColor = value;
  112715. }
  112716. },
  112717. /**
  112718. * Gets or sets the default color of polylines and polygon outlines.
  112719. * @memberof GeoJsonDataSource
  112720. * @type {Color}
  112721. * @default Color.BLACK
  112722. */
  112723. stroke : {
  112724. get : function() {
  112725. return defaultStroke;
  112726. },
  112727. set : function(value) {
  112728. defaultStroke = value;
  112729. defaultStrokeMaterialProperty.color.setValue(value);
  112730. }
  112731. },
  112732. /**
  112733. * Gets or sets the default width of polylines and polygon outlines.
  112734. * @memberof GeoJsonDataSource
  112735. * @type {Number}
  112736. * @default 2.0
  112737. */
  112738. strokeWidth : {
  112739. get : function() {
  112740. return defaultStrokeWidth;
  112741. },
  112742. set : function(value) {
  112743. defaultStrokeWidth = value;
  112744. defaultStrokeWidthProperty.setValue(value);
  112745. }
  112746. },
  112747. /**
  112748. * Gets or sets default color for polygon interiors.
  112749. * @memberof GeoJsonDataSource
  112750. * @type {Color}
  112751. * @default Color.YELLOW
  112752. */
  112753. fill : {
  112754. get : function() {
  112755. return defaultFill;
  112756. },
  112757. set : function(value) {
  112758. defaultFill = value;
  112759. defaultFillMaterialProperty = new ColorMaterialProperty(defaultFill);
  112760. }
  112761. },
  112762. /**
  112763. * Gets or sets default of whether to clamp to the ground.
  112764. * @memberof GeoJsonDataSource
  112765. * @type {Boolean}
  112766. * @default false
  112767. */
  112768. clampToGround : {
  112769. get : function() {
  112770. return defaultClampToGround;
  112771. },
  112772. set : function(value) {
  112773. defaultClampToGround = value;
  112774. }
  112775. },
  112776. /**
  112777. * Gets an object that maps the name of a crs to a callback function which takes a GeoJSON coordinate
  112778. * and transforms it into a WGS84 Earth-fixed Cartesian. Older versions of GeoJSON which
  112779. * supported the EPSG type can be added to this list as well, by specifying the complete EPSG name,
  112780. * for example 'EPSG:4326'.
  112781. * @memberof GeoJsonDataSource
  112782. * @type {Object}
  112783. */
  112784. crsNames : {
  112785. get : function() {
  112786. return crsNames;
  112787. }
  112788. },
  112789. /**
  112790. * Gets an object that maps the href property of a crs link to a callback function
  112791. * which takes the crs properties object and returns a Promise that resolves
  112792. * to a function that takes a GeoJSON coordinate and transforms it into a WGS84 Earth-fixed Cartesian.
  112793. * Items in this object take precedence over those defined in <code>crsLinkHrefs</code>, assuming
  112794. * the link has a type specified.
  112795. * @memberof GeoJsonDataSource
  112796. * @type {Object}
  112797. */
  112798. crsLinkHrefs : {
  112799. get : function() {
  112800. return crsLinkHrefs;
  112801. }
  112802. },
  112803. /**
  112804. * Gets an object that maps the type property of a crs link to a callback function
  112805. * which takes the crs properties object and returns a Promise that resolves
  112806. * to a function that takes a GeoJSON coordinate and transforms it into a WGS84 Earth-fixed Cartesian.
  112807. * Items in <code>crsLinkHrefs</code> take precedence over this object.
  112808. * @memberof GeoJsonDataSource
  112809. * @type {Object}
  112810. */
  112811. crsLinkTypes : {
  112812. get : function() {
  112813. return crsLinkTypes;
  112814. }
  112815. }
  112816. });
  112817. defineProperties(GeoJsonDataSource.prototype, {
  112818. /**
  112819. * Gets a human-readable name for this instance.
  112820. * @memberof GeoJsonDataSource.prototype
  112821. * @type {String}
  112822. */
  112823. name : {
  112824. get : function() {
  112825. return this._name;
  112826. }
  112827. },
  112828. /**
  112829. * This DataSource only defines static data, therefore this property is always undefined.
  112830. * @memberof GeoJsonDataSource.prototype
  112831. * @type {DataSourceClock}
  112832. */
  112833. clock : {
  112834. value : undefined,
  112835. writable : false
  112836. },
  112837. /**
  112838. * Gets the collection of {@link Entity} instances.
  112839. * @memberof GeoJsonDataSource.prototype
  112840. * @type {EntityCollection}
  112841. */
  112842. entities : {
  112843. get : function() {
  112844. return this._entityCollection;
  112845. }
  112846. },
  112847. /**
  112848. * Gets a value indicating if the data source is currently loading data.
  112849. * @memberof GeoJsonDataSource.prototype
  112850. * @type {Boolean}
  112851. */
  112852. isLoading : {
  112853. get : function() {
  112854. return this._isLoading;
  112855. }
  112856. },
  112857. /**
  112858. * Gets an event that will be raised when the underlying data changes.
  112859. * @memberof GeoJsonDataSource.prototype
  112860. * @type {Event}
  112861. */
  112862. changedEvent : {
  112863. get : function() {
  112864. return this._changed;
  112865. }
  112866. },
  112867. /**
  112868. * Gets an event that will be raised if an error is encountered during processing.
  112869. * @memberof GeoJsonDataSource.prototype
  112870. * @type {Event}
  112871. */
  112872. errorEvent : {
  112873. get : function() {
  112874. return this._error;
  112875. }
  112876. },
  112877. /**
  112878. * Gets an event that will be raised when the data source either starts or stops loading.
  112879. * @memberof GeoJsonDataSource.prototype
  112880. * @type {Event}
  112881. */
  112882. loadingEvent : {
  112883. get : function() {
  112884. return this._loading;
  112885. }
  112886. },
  112887. /**
  112888. * Gets whether or not this data source should be displayed.
  112889. * @memberof GeoJsonDataSource.prototype
  112890. * @type {Boolean}
  112891. */
  112892. show : {
  112893. get : function() {
  112894. return this._entityCollection.show;
  112895. },
  112896. set : function(value) {
  112897. this._entityCollection.show = value;
  112898. }
  112899. },
  112900. /**
  112901. * Gets or sets the clustering options for this data source. This object can be shared between multiple data sources.
  112902. *
  112903. * @memberof GeoJsonDataSource.prototype
  112904. * @type {EntityCluster}
  112905. */
  112906. clustering : {
  112907. get : function() {
  112908. return this._entityCluster;
  112909. },
  112910. set : function(value) {
  112911. if (!defined(value)) {
  112912. throw new DeveloperError('value must be defined.');
  112913. }
  112914. this._entityCluster = value;
  112915. }
  112916. }
  112917. });
  112918. /**
  112919. * Asynchronously loads the provided GeoJSON or TopoJSON data, replacing any existing data.
  112920. *
  112921. * @param {String|Object} data A url, GeoJSON object, or TopoJSON object to be loaded.
  112922. * @param {Object} [options] An object with the following properties:
  112923. * @param {String} [options.sourceUri] Overrides the url to use for resolving relative links.
  112924. * @param {GeoJsonDataSource~describe} [options.describe=GeoJsonDataSource.defaultDescribeProperty] A function which returns a Property object (or just a string),
  112925. * which converts the properties into an html description.
  112926. * @param {Number} [options.markerSize=GeoJsonDataSource.markerSize] The default size of the map pin created for each point, in pixels.
  112927. * @param {String} [options.markerSymbol=GeoJsonDataSource.markerSymbol] The default symbol of the map pin created for each point.
  112928. * @param {Color} [options.markerColor=GeoJsonDataSource.markerColor] The default color of the map pin created for each point.
  112929. * @param {Color} [options.stroke=GeoJsonDataSource.stroke] The default color of polylines and polygon outlines.
  112930. * @param {Number} [options.strokeWidth=GeoJsonDataSource.strokeWidth] The default width of polylines and polygon outlines.
  112931. * @param {Color} [options.fill=GeoJsonDataSource.fill] The default color for polygon interiors.
  112932. * @param {Boolean} [options.clampToGround=GeoJsonDataSource.clampToGround] true if we want the features clamped to the ground.
  112933. *
  112934. * @returns {Promise.<GeoJsonDataSource>} a promise that will resolve when the GeoJSON is loaded.
  112935. */
  112936. GeoJsonDataSource.prototype.load = function(data, options) {
  112937. if (!defined(data)) {
  112938. throw new DeveloperError('data is required.');
  112939. }
  112940. DataSource.setLoading(this, true);
  112941. var promise = data;
  112942. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  112943. var sourceUri = options.sourceUri;
  112944. if (typeof data === 'string') {
  112945. if (!defined(sourceUri)) {
  112946. sourceUri = data;
  112947. }
  112948. promise = loadJson(data);
  112949. }
  112950. options = {
  112951. describe: defaultValue(options.describe, defaultDescribeProperty),
  112952. markerSize : defaultValue(options.markerSize, defaultMarkerSize),
  112953. markerSymbol : defaultValue(options.markerSymbol, defaultMarkerSymbol),
  112954. markerColor : defaultValue(options.markerColor, defaultMarkerColor),
  112955. strokeWidthProperty : new ConstantProperty(defaultValue(options.strokeWidth, defaultStrokeWidth)),
  112956. strokeMaterialProperty : new ColorMaterialProperty(defaultValue(options.stroke, defaultStroke)),
  112957. fillMaterialProperty : new ColorMaterialProperty(defaultValue(options.fill, defaultFill)),
  112958. clampToGround : defaultValue(options.clampToGround, defaultClampToGround)
  112959. };
  112960. var that = this;
  112961. return when(promise, function(geoJson) {
  112962. return load(that, geoJson, options, sourceUri);
  112963. }).otherwise(function(error) {
  112964. DataSource.setLoading(that, false);
  112965. that._error.raiseEvent(that, error);
  112966. console.log(error);
  112967. return when.reject(error);
  112968. });
  112969. };
  112970. function load(that, geoJson, options, sourceUri) {
  112971. var name;
  112972. if (defined(sourceUri)) {
  112973. name = getFilenameFromUri(sourceUri);
  112974. }
  112975. if (defined(name) && that._name !== name) {
  112976. that._name = name;
  112977. that._changed.raiseEvent(that);
  112978. }
  112979. var typeHandler = geoJsonObjectTypes[geoJson.type];
  112980. if (!defined(typeHandler)) {
  112981. throw new RuntimeError('Unsupported GeoJSON object type: ' + geoJson.type);
  112982. }
  112983. //Check for a Coordinate Reference System.
  112984. var crs = geoJson.crs;
  112985. var crsFunction = crs !== null ? defaultCrsFunction : null;
  112986. if (defined(crs)) {
  112987. if (!defined(crs.properties)) {
  112988. throw new RuntimeError('crs.properties is undefined.');
  112989. }
  112990. var properties = crs.properties;
  112991. if (crs.type === 'name') {
  112992. crsFunction = crsNames[properties.name];
  112993. if (!defined(crsFunction)) {
  112994. throw new RuntimeError('Unknown crs name: ' + properties.name);
  112995. }
  112996. } else if (crs.type === 'link') {
  112997. var handler = crsLinkHrefs[properties.href];
  112998. if (!defined(handler)) {
  112999. handler = crsLinkTypes[properties.type];
  113000. }
  113001. if (!defined(handler)) {
  113002. throw new RuntimeError('Unable to resolve crs link: ' + JSON.stringify(properties));
  113003. }
  113004. crsFunction = handler(properties);
  113005. } else if (crs.type === 'EPSG') {
  113006. crsFunction = crsNames['EPSG:' + properties.code];
  113007. if (!defined(crsFunction)) {
  113008. throw new RuntimeError('Unknown crs EPSG code: ' + properties.code);
  113009. }
  113010. } else {
  113011. throw new RuntimeError('Unknown crs type: ' + crs.type);
  113012. }
  113013. }
  113014. return when(crsFunction, function(crsFunction) {
  113015. that._entityCollection.removeAll();
  113016. // null is a valid value for the crs, but means the entire load process becomes a no-op
  113017. // because we can't assume anything about the coordinates.
  113018. if (crsFunction !== null) {
  113019. typeHandler(that, geoJson, geoJson, crsFunction, options);
  113020. }
  113021. return when.all(that._promises, function() {
  113022. that._promises.length = 0;
  113023. DataSource.setLoading(that, false);
  113024. return that;
  113025. });
  113026. });
  113027. }
  113028. /**
  113029. * This callback is displayed as part of the GeoJsonDataSource class.
  113030. * @callback GeoJsonDataSource~describe
  113031. * @param {Object} properties The properties of the feature.
  113032. * @param {String} nameProperty The property key that Cesium estimates to have the name of the feature.
  113033. */
  113034. return GeoJsonDataSource;
  113035. });
  113036. /*global define*/
  113037. define('DataSources/GeometryUpdater',[
  113038. '../Core/defineProperties',
  113039. '../Core/DeveloperError'
  113040. ], function(
  113041. defineProperties,
  113042. DeveloperError) {
  113043. 'use strict';
  113044. /**
  113045. * Defines the interface for a geometry updater. A GeometryUpdater maps
  113046. * geometry defined as part of a {@link Entity} into {@link Geometry}
  113047. * instances. These instances are then visualized by {@link GeometryVisualizer}.
  113048. *
  113049. * This type defines an interface and cannot be instantiated directly.
  113050. *
  113051. * @alias GeometryUpdater
  113052. * @constructor
  113053. *
  113054. * @param {Entity} entity The entity containing the geometry to be visualized.
  113055. * @param {Scene} scene The scene where visualization is taking place.
  113056. *
  113057. * @see EllipseGeometryUpdater
  113058. * @see EllipsoidGeometryUpdater
  113059. * @see PolygonGeometryUpdater
  113060. * @see PolylineGeometryUpdater
  113061. * @see RectangleGeometryUpdater
  113062. * @see WallGeometryUpdater
  113063. */
  113064. function GeometryUpdater(entity, scene) {
  113065. DeveloperError.throwInstantiationError();
  113066. }
  113067. defineProperties(GeometryUpdater, {
  113068. /**
  113069. * Gets the type of Appearance to use for simple color-based geometry.
  113070. * @memberof GeometryUpdater
  113071. * @type {Appearance}
  113072. */
  113073. perInstanceColorAppearanceType : {
  113074. get : DeveloperError.throwInstantiationError
  113075. },
  113076. /**
  113077. * Gets the type of Appearance to use for material-based geometry.
  113078. * @memberof GeometryUpdater
  113079. * @type {Appearance}
  113080. */
  113081. materialAppearanceType : {
  113082. get : DeveloperError.throwInstantiationError
  113083. }
  113084. });
  113085. defineProperties(GeometryUpdater.prototype, {
  113086. /**
  113087. * Gets the entity associated with this geometry.
  113088. * @memberof GeometryUpdater.prototype
  113089. *
  113090. * @type {Entity}
  113091. * @readonly
  113092. */
  113093. entity : {
  113094. get : DeveloperError.throwInstantiationError
  113095. },
  113096. /**
  113097. * Gets a value indicating if the geometry has a fill component.
  113098. * @memberof GeometryUpdater.prototype
  113099. *
  113100. * @type {Boolean}
  113101. * @readonly
  113102. */
  113103. fillEnabled : {
  113104. get : DeveloperError.throwInstantiationError
  113105. },
  113106. /**
  113107. * Gets a value indicating if fill visibility varies with simulation time.
  113108. * @memberof GeometryUpdater.prototype
  113109. *
  113110. * @type {Boolean}
  113111. * @readonly
  113112. */
  113113. hasConstantFill : {
  113114. get : DeveloperError.throwInstantiationError
  113115. },
  113116. /**
  113117. * Gets the material property used to fill the geometry.
  113118. * @memberof GeometryUpdater.prototype
  113119. *
  113120. * @type {MaterialProperty}
  113121. * @readonly
  113122. */
  113123. fillMaterialProperty : {
  113124. get : DeveloperError.throwInstantiationError
  113125. },
  113126. /**
  113127. * Gets a value indicating if the geometry has an outline component.
  113128. * @memberof GeometryUpdater.prototype
  113129. *
  113130. * @type {Boolean}
  113131. * @readonly
  113132. */
  113133. outlineEnabled : {
  113134. get : DeveloperError.throwInstantiationError
  113135. },
  113136. /**
  113137. * Gets a value indicating if outline visibility varies with simulation time.
  113138. * @memberof GeometryUpdater.prototype
  113139. *
  113140. * @type {Boolean}
  113141. * @readonly
  113142. */
  113143. hasConstantOutline : {
  113144. get : DeveloperError.throwInstantiationError
  113145. },
  113146. /**
  113147. * Gets the {@link Color} property for the geometry outline.
  113148. * @memberof GeometryUpdater.prototype
  113149. *
  113150. * @type {Property}
  113151. * @readonly
  113152. */
  113153. outlineColorProperty : {
  113154. get : DeveloperError.throwInstantiationError
  113155. },
  113156. /**
  113157. * Gets the constant with of the geometry outline, in pixels.
  113158. * This value is only valid if isDynamic is false.
  113159. * @memberof GeometryUpdater.prototype
  113160. *
  113161. * @type {Number}
  113162. * @readonly
  113163. */
  113164. outlineWidth : {
  113165. get : DeveloperError.throwInstantiationError
  113166. },
  113167. /**
  113168. * Gets a value indicating if the geometry is time-varying.
  113169. * If true, all visualization is delegated to the {@link DynamicGeometryUpdater}
  113170. * returned by GeometryUpdater#createDynamicUpdater.
  113171. * @memberof GeometryUpdater.prototype
  113172. *
  113173. * @type {Boolean}
  113174. * @readonly
  113175. */
  113176. isDynamic : {
  113177. get : DeveloperError.throwInstantiationError
  113178. },
  113179. /**
  113180. * Gets a value indicating if the geometry is closed.
  113181. * This property is only valid for static geometry.
  113182. * @memberof GeometryUpdater.prototype
  113183. *
  113184. * @type {Boolean}
  113185. * @readonly
  113186. */
  113187. isClosed : {
  113188. get : DeveloperError.throwInstantiationError
  113189. },
  113190. /**
  113191. * Gets an event that is raised whenever the public properties
  113192. * of this updater change.
  113193. * @memberof GeometryUpdater.prototype
  113194. *
  113195. * @type {Boolean}
  113196. * @readonly
  113197. */
  113198. geometryChanged : {
  113199. get : DeveloperError.throwInstantiationError
  113200. }
  113201. });
  113202. /**
  113203. * Checks if the geometry is outlined at the provided time.
  113204. * @function
  113205. *
  113206. * @param {JulianDate} time The time for which to retrieve visibility.
  113207. * @returns {Boolean} true if geometry is outlined at the provided time, false otherwise.
  113208. */
  113209. GeometryUpdater.prototype.isOutlineVisible = DeveloperError.throwInstantiationError;
  113210. /**
  113211. * Checks if the geometry is filled at the provided time.
  113212. * @function
  113213. *
  113214. * @param {JulianDate} time The time for which to retrieve visibility.
  113215. * @returns {Boolean} true if geometry is filled at the provided time, false otherwise.
  113216. */
  113217. GeometryUpdater.prototype.isFilled = DeveloperError.throwInstantiationError;
  113218. /**
  113219. * Creates the geometry instance which represents the fill of the geometry.
  113220. * @function
  113221. *
  113222. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  113223. * @returns {GeometryInstance} The geometry instance representing the filled portion of the geometry.
  113224. *
  113225. * @exception {DeveloperError} This instance does not represent a filled geometry.
  113226. */
  113227. GeometryUpdater.prototype.createFillGeometryInstance = DeveloperError.throwInstantiationError;
  113228. /**
  113229. * Creates the geometry instance which represents the outline of the geometry.
  113230. * @function
  113231. *
  113232. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  113233. * @returns {GeometryInstance} The geometry instance representing the outline portion of the geometry.
  113234. *
  113235. * @exception {DeveloperError} This instance does not represent an outlined geometry.
  113236. */
  113237. GeometryUpdater.prototype.createOutlineGeometryInstance = DeveloperError.throwInstantiationError;
  113238. /**
  113239. * Returns true if this object was destroyed; otherwise, false.
  113240. * @function
  113241. *
  113242. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  113243. */
  113244. GeometryUpdater.prototype.isDestroyed = DeveloperError.throwInstantiationError;
  113245. /**
  113246. * Destroys and resources used by the object. Once an object is destroyed, it should not be used.
  113247. * @function
  113248. *
  113249. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  113250. */
  113251. GeometryUpdater.prototype.destroy = DeveloperError.throwInstantiationError;
  113252. /**
  113253. * Creates the dynamic updater to be used when GeometryUpdater#isDynamic is true.
  113254. * @function
  113255. *
  113256. * @param {PrimitiveCollection} primitives The primitive collection to use.
  113257. * @returns {DynamicGeometryUpdater} The dynamic updater used to update the geometry each frame.
  113258. *
  113259. * @exception {DeveloperError} This instance does not represent dynamic geometry.
  113260. */
  113261. GeometryUpdater.prototype.createDynamicUpdater = DeveloperError.throwInstantiationError;
  113262. return GeometryUpdater;
  113263. });
  113264. (function (root, factory) {
  113265. if (typeof define === 'function' && define.amd) {
  113266. // AMD. Register as an anonymous module unless amdModuleId is set
  113267. define('ThirdParty/Autolinker',[], function () {
  113268. return (root['Autolinker'] = factory());
  113269. });
  113270. } else if (typeof exports === 'object') {
  113271. // Node. Does not work with strict CommonJS, but
  113272. // only CommonJS-like environments that support module.exports,
  113273. // like Node.
  113274. module.exports = factory();
  113275. } else {
  113276. root['Autolinker'] = factory();
  113277. }
  113278. }(this, function () {
  113279. /*!
  113280. * Autolinker.js
  113281. * 0.17.1
  113282. *
  113283. * Copyright(c) 2015 Gregory Jacobs <greg@greg-jacobs.com>
  113284. * MIT Licensed. http://www.opensource.org/licenses/mit-license.php
  113285. *
  113286. * https://github.com/gregjacobs/Autolinker.js
  113287. */
  113288. /**
  113289. * @class Autolinker
  113290. * @extends Object
  113291. *
  113292. * Utility class used to process a given string of text, and wrap the matches in
  113293. * the appropriate anchor (&lt;a&gt;) tags to turn them into links.
  113294. *
  113295. * Any of the configuration options may be provided in an Object (map) provided
  113296. * to the Autolinker constructor, which will configure how the {@link #link link()}
  113297. * method will process the links.
  113298. *
  113299. * For example:
  113300. *
  113301. * var autolinker = new Autolinker( {
  113302. * newWindow : false,
  113303. * truncate : 30
  113304. * } );
  113305. *
  113306. * var html = autolinker.link( "Joe went to www.yahoo.com" );
  113307. * // produces: 'Joe went to <a href="http://www.yahoo.com">yahoo.com</a>'
  113308. *
  113309. *
  113310. * The {@link #static-link static link()} method may also be used to inline options into a single call, which may
  113311. * be more convenient for one-off uses. For example:
  113312. *
  113313. * var html = Autolinker.link( "Joe went to www.yahoo.com", {
  113314. * newWindow : false,
  113315. * truncate : 30
  113316. * } );
  113317. * // produces: 'Joe went to <a href="http://www.yahoo.com">yahoo.com</a>'
  113318. *
  113319. *
  113320. * ## Custom Replacements of Links
  113321. *
  113322. * If the configuration options do not provide enough flexibility, a {@link #replaceFn}
  113323. * may be provided to fully customize the output of Autolinker. This function is
  113324. * called once for each URL/Email/Phone#/Twitter Handle/Hashtag match that is
  113325. * encountered.
  113326. *
  113327. * For example:
  113328. *
  113329. * var input = "..."; // string with URLs, Email Addresses, Phone #s, Twitter Handles, and Hashtags
  113330. *
  113331. * var linkedText = Autolinker.link( input, {
  113332. * replaceFn : function( autolinker, match ) {
  113333. * console.log( "href = ", match.getAnchorHref() );
  113334. * console.log( "text = ", match.getAnchorText() );
  113335. *
  113336. * switch( match.getType() ) {
  113337. * case 'url' :
  113338. * console.log( "url: ", match.getUrl() );
  113339. *
  113340. * if( match.getUrl().indexOf( 'mysite.com' ) === -1 ) {
  113341. * var tag = autolinker.getTagBuilder().build( match ); // returns an `Autolinker.HtmlTag` instance, which provides mutator methods for easy changes
  113342. * tag.setAttr( 'rel', 'nofollow' );
  113343. * tag.addClass( 'external-link' );
  113344. *
  113345. * return tag;
  113346. *
  113347. * } else {
  113348. * return true; // let Autolinker perform its normal anchor tag replacement
  113349. * }
  113350. *
  113351. * case 'email' :
  113352. * var email = match.getEmail();
  113353. * console.log( "email: ", email );
  113354. *
  113355. * if( email === "my@own.address" ) {
  113356. * return false; // don't auto-link this particular email address; leave as-is
  113357. * } else {
  113358. * return; // no return value will have Autolinker perform its normal anchor tag replacement (same as returning `true`)
  113359. * }
  113360. *
  113361. * case 'phone' :
  113362. * var phoneNumber = match.getPhoneNumber();
  113363. * console.log( phoneNumber );
  113364. *
  113365. * return '<a href="http://newplace.to.link.phone.numbers.to/">' + phoneNumber + '</a>';
  113366. *
  113367. * case 'twitter' :
  113368. * var twitterHandle = match.getTwitterHandle();
  113369. * console.log( twitterHandle );
  113370. *
  113371. * return '<a href="http://newplace.to.link.twitter.handles.to/">' + twitterHandle + '</a>';
  113372. *
  113373. * case 'hashtag' :
  113374. * var hashtag = match.getHashtag();
  113375. * console.log( hashtag );
  113376. *
  113377. * return '<a href="http://newplace.to.link.hashtag.handles.to/">' + hashtag + '</a>';
  113378. * }
  113379. * }
  113380. * } );
  113381. *
  113382. *
  113383. * The function may return the following values:
  113384. *
  113385. * - `true` (Boolean): Allow Autolinker to replace the match as it normally would.
  113386. * - `false` (Boolean): Do not replace the current match at all - leave as-is.
  113387. * - Any String: If a string is returned from the function, the string will be used directly as the replacement HTML for
  113388. * the match.
  113389. * - An {@link Autolinker.HtmlTag} instance, which can be used to build/modify an HTML tag before writing out its HTML text.
  113390. *
  113391. * @constructor
  113392. * @param {Object} [config] The configuration options for the Autolinker instance, specified in an Object (map).
  113393. */
  113394. var Autolinker = function( cfg ) {
  113395. Autolinker.Util.assign( this, cfg ); // assign the properties of `cfg` onto the Autolinker instance. Prototype properties will be used for missing configs.
  113396. // Validate the value of the `hashtag` cfg.
  113397. var hashtag = this.hashtag;
  113398. if( hashtag !== false && hashtag !== 'twitter' && hashtag !== 'facebook' ) {
  113399. throw new Error( "invalid `hashtag` cfg - see docs" );
  113400. }
  113401. };
  113402. Autolinker.prototype = {
  113403. constructor : Autolinker, // fix constructor property
  113404. /**
  113405. * @cfg {Boolean} urls
  113406. *
  113407. * `true` if miscellaneous URLs should be automatically linked, `false` if they should not be.
  113408. */
  113409. urls : true,
  113410. /**
  113411. * @cfg {Boolean} email
  113412. *
  113413. * `true` if email addresses should be automatically linked, `false` if they should not be.
  113414. */
  113415. email : true,
  113416. /**
  113417. * @cfg {Boolean} twitter
  113418. *
  113419. * `true` if Twitter handles ("@example") should be automatically linked, `false` if they should not be.
  113420. */
  113421. twitter : true,
  113422. /**
  113423. * @cfg {Boolean} phone
  113424. *
  113425. * `true` if Phone numbers ("(555)555-5555") should be automatically linked, `false` if they should not be.
  113426. */
  113427. phone: true,
  113428. /**
  113429. * @cfg {Boolean/String} hashtag
  113430. *
  113431. * A string for the service name to have hashtags (ex: "#myHashtag")
  113432. * auto-linked to. The currently-supported values are:
  113433. *
  113434. * - 'twitter'
  113435. * - 'facebook'
  113436. *
  113437. * Pass `false` to skip auto-linking of hashtags.
  113438. */
  113439. hashtag : false,
  113440. /**
  113441. * @cfg {Boolean} newWindow
  113442. *
  113443. * `true` if the links should open in a new window, `false` otherwise.
  113444. */
  113445. newWindow : true,
  113446. /**
  113447. * @cfg {Boolean} stripPrefix
  113448. *
  113449. * `true` if 'http://' or 'https://' and/or the 'www.' should be stripped
  113450. * from the beginning of URL links' text, `false` otherwise.
  113451. */
  113452. stripPrefix : true,
  113453. /**
  113454. * @cfg {Number} truncate
  113455. *
  113456. * A number for how many characters long matched text should be truncated to inside the text of
  113457. * a link. If the matched text is over this number of characters, it will be truncated to this length by
  113458. * adding a two period ellipsis ('..') to the end of the string.
  113459. *
  113460. * For example: A url like 'http://www.yahoo.com/some/long/path/to/a/file' truncated to 25 characters might look
  113461. * something like this: 'yahoo.com/some/long/pat..'
  113462. */
  113463. truncate : undefined,
  113464. /**
  113465. * @cfg {String} className
  113466. *
  113467. * A CSS class name to add to the generated links. This class will be added to all links, as well as this class
  113468. * plus match suffixes for styling url/email/phone/twitter/hashtag links differently.
  113469. *
  113470. * For example, if this config is provided as "myLink", then:
  113471. *
  113472. * - URL links will have the CSS classes: "myLink myLink-url"
  113473. * - Email links will have the CSS classes: "myLink myLink-email", and
  113474. * - Twitter links will have the CSS classes: "myLink myLink-twitter"
  113475. * - Phone links will have the CSS classes: "myLink myLink-phone"
  113476. * - Hashtag links will have the CSS classes: "myLink myLink-hashtag"
  113477. */
  113478. className : "",
  113479. /**
  113480. * @cfg {Function} replaceFn
  113481. *
  113482. * A function to individually process each match found in the input string.
  113483. *
  113484. * See the class's description for usage.
  113485. *
  113486. * This function is called with the following parameters:
  113487. *
  113488. * @cfg {Autolinker} replaceFn.autolinker The Autolinker instance, which may be used to retrieve child objects from (such
  113489. * as the instance's {@link #getTagBuilder tag builder}).
  113490. * @cfg {Autolinker.match.Match} replaceFn.match The Match instance which can be used to retrieve information about the
  113491. * match that the `replaceFn` is currently processing. See {@link Autolinker.match.Match} subclasses for details.
  113492. */
  113493. /**
  113494. * @private
  113495. * @property {Autolinker.htmlParser.HtmlParser} htmlParser
  113496. *
  113497. * The HtmlParser instance used to skip over HTML tags, while finding text nodes to process. This is lazily instantiated
  113498. * in the {@link #getHtmlParser} method.
  113499. */
  113500. htmlParser : undefined,
  113501. /**
  113502. * @private
  113503. * @property {Autolinker.matchParser.MatchParser} matchParser
  113504. *
  113505. * The MatchParser instance used to find matches in the text nodes of an input string passed to
  113506. * {@link #link}. This is lazily instantiated in the {@link #getMatchParser} method.
  113507. */
  113508. matchParser : undefined,
  113509. /**
  113510. * @private
  113511. * @property {Autolinker.AnchorTagBuilder} tagBuilder
  113512. *
  113513. * The AnchorTagBuilder instance used to build match replacement anchor tags. Note: this is lazily instantiated
  113514. * in the {@link #getTagBuilder} method.
  113515. */
  113516. tagBuilder : undefined,
  113517. /**
  113518. * Automatically links URLs, Email addresses, Phone numbers, Twitter
  113519. * handles, and Hashtags found in the given chunk of HTML. Does not link
  113520. * URLs found within HTML tags.
  113521. *
  113522. * For instance, if given the text: `You should go to http://www.yahoo.com`,
  113523. * then the result will be `You should go to
  113524. * &lt;a href="http://www.yahoo.com"&gt;http://www.yahoo.com&lt;/a&gt;`
  113525. *
  113526. * This method finds the text around any HTML elements in the input
  113527. * `textOrHtml`, which will be the text that is processed. Any original HTML
  113528. * elements will be left as-is, as well as the text that is already wrapped
  113529. * in anchor (&lt;a&gt;) tags.
  113530. *
  113531. * @param {String} textOrHtml The HTML or text to autolink matches within
  113532. * (depending on if the {@link #urls}, {@link #email}, {@link #phone},
  113533. * {@link #twitter}, and {@link #hashtag} options are enabled).
  113534. * @return {String} The HTML, with matches automatically linked.
  113535. */
  113536. link : function( textOrHtml ) {
  113537. var htmlParser = this.getHtmlParser(),
  113538. htmlNodes = htmlParser.parse( textOrHtml ),
  113539. anchorTagStackCount = 0, // used to only process text around anchor tags, and any inner text/html they may have
  113540. resultHtml = [];
  113541. for( var i = 0, len = htmlNodes.length; i < len; i++ ) {
  113542. var node = htmlNodes[ i ],
  113543. nodeType = node.getType(),
  113544. nodeText = node.getText();
  113545. if( nodeType === 'element' ) {
  113546. // Process HTML nodes in the input `textOrHtml`
  113547. if( node.getTagName() === 'a' ) {
  113548. if( !node.isClosing() ) { // it's the start <a> tag
  113549. anchorTagStackCount++;
  113550. } else { // it's the end </a> tag
  113551. anchorTagStackCount = Math.max( anchorTagStackCount - 1, 0 ); // attempt to handle extraneous </a> tags by making sure the stack count never goes below 0
  113552. }
  113553. }
  113554. resultHtml.push( nodeText ); // now add the text of the tag itself verbatim
  113555. } else if( nodeType === 'entity' || nodeType === 'comment' ) {
  113556. resultHtml.push( nodeText ); // append HTML entity nodes (such as '&nbsp;') or HTML comments (such as '<!-- Comment -->') verbatim
  113557. } else {
  113558. // Process text nodes in the input `textOrHtml`
  113559. if( anchorTagStackCount === 0 ) {
  113560. // If we're not within an <a> tag, process the text node to linkify
  113561. var linkifiedStr = this.linkifyStr( nodeText );
  113562. resultHtml.push( linkifiedStr );
  113563. } else {
  113564. // `text` is within an <a> tag, simply append the text - we do not want to autolink anything
  113565. // already within an <a>...</a> tag
  113566. resultHtml.push( nodeText );
  113567. }
  113568. }
  113569. }
  113570. return resultHtml.join( "" );
  113571. },
  113572. /**
  113573. * Process the text that lies in between HTML tags, performing the anchor
  113574. * tag replacements for the matches, and returns the string with the
  113575. * replacements made.
  113576. *
  113577. * This method does the actual wrapping of matches with anchor tags.
  113578. *
  113579. * @private
  113580. * @param {String} str The string of text to auto-link.
  113581. * @return {String} The text with anchor tags auto-filled.
  113582. */
  113583. linkifyStr : function( str ) {
  113584. return this.getMatchParser().replace( str, this.createMatchReturnVal, this );
  113585. },
  113586. /**
  113587. * Creates the return string value for a given match in the input string,
  113588. * for the {@link #linkifyStr} method.
  113589. *
  113590. * This method handles the {@link #replaceFn}, if one was provided.
  113591. *
  113592. * @private
  113593. * @param {Autolinker.match.Match} match The Match object that represents the match.
  113594. * @return {String} The string that the `match` should be replaced with. This is usually the anchor tag string, but
  113595. * may be the `matchStr` itself if the match is not to be replaced.
  113596. */
  113597. createMatchReturnVal : function( match ) {
  113598. // Handle a custom `replaceFn` being provided
  113599. var replaceFnResult;
  113600. if( this.replaceFn ) {
  113601. replaceFnResult = this.replaceFn.call( this, this, match ); // Autolinker instance is the context, and the first arg
  113602. }
  113603. if( typeof replaceFnResult === 'string' ) {
  113604. return replaceFnResult; // `replaceFn` returned a string, use that
  113605. } else if( replaceFnResult === false ) {
  113606. return match.getMatchedText(); // no replacement for the match
  113607. } else if( replaceFnResult instanceof Autolinker.HtmlTag ) {
  113608. return replaceFnResult.toAnchorString();
  113609. } else { // replaceFnResult === true, or no/unknown return value from function
  113610. // Perform Autolinker's default anchor tag generation
  113611. var tagBuilder = this.getTagBuilder(),
  113612. anchorTag = tagBuilder.build( match ); // returns an Autolinker.HtmlTag instance
  113613. return anchorTag.toAnchorString();
  113614. }
  113615. },
  113616. /**
  113617. * Lazily instantiates and returns the {@link #htmlParser} instance for this Autolinker instance.
  113618. *
  113619. * @protected
  113620. * @return {Autolinker.htmlParser.HtmlParser}
  113621. */
  113622. getHtmlParser : function() {
  113623. var htmlParser = this.htmlParser;
  113624. if( !htmlParser ) {
  113625. htmlParser = this.htmlParser = new Autolinker.htmlParser.HtmlParser();
  113626. }
  113627. return htmlParser;
  113628. },
  113629. /**
  113630. * Lazily instantiates and returns the {@link #matchParser} instance for this Autolinker instance.
  113631. *
  113632. * @protected
  113633. * @return {Autolinker.matchParser.MatchParser}
  113634. */
  113635. getMatchParser : function() {
  113636. var matchParser = this.matchParser;
  113637. if( !matchParser ) {
  113638. matchParser = this.matchParser = new Autolinker.matchParser.MatchParser( {
  113639. urls : this.urls,
  113640. email : this.email,
  113641. twitter : this.twitter,
  113642. phone : this.phone,
  113643. hashtag : this.hashtag,
  113644. stripPrefix : this.stripPrefix
  113645. } );
  113646. }
  113647. return matchParser;
  113648. },
  113649. /**
  113650. * Returns the {@link #tagBuilder} instance for this Autolinker instance, lazily instantiating it
  113651. * if it does not yet exist.
  113652. *
  113653. * This method may be used in a {@link #replaceFn} to generate the {@link Autolinker.HtmlTag HtmlTag} instance that
  113654. * Autolinker would normally generate, and then allow for modifications before returning it. For example:
  113655. *
  113656. * var html = Autolinker.link( "Test google.com", {
  113657. * replaceFn : function( autolinker, match ) {
  113658. * var tag = autolinker.getTagBuilder().build( match ); // returns an {@link Autolinker.HtmlTag} instance
  113659. * tag.setAttr( 'rel', 'nofollow' );
  113660. *
  113661. * return tag;
  113662. * }
  113663. * } );
  113664. *
  113665. * // generated html:
  113666. * // Test <a href="http://google.com" target="_blank" rel="nofollow">google.com</a>
  113667. *
  113668. * @return {Autolinker.AnchorTagBuilder}
  113669. */
  113670. getTagBuilder : function() {
  113671. var tagBuilder = this.tagBuilder;
  113672. if( !tagBuilder ) {
  113673. tagBuilder = this.tagBuilder = new Autolinker.AnchorTagBuilder( {
  113674. newWindow : this.newWindow,
  113675. truncate : this.truncate,
  113676. className : this.className
  113677. } );
  113678. }
  113679. return tagBuilder;
  113680. }
  113681. };
  113682. /**
  113683. * Automatically links URLs, Email addresses, Phone Numbers, Twitter handles,
  113684. * and Hashtags found in the given chunk of HTML. Does not link URLs found
  113685. * within HTML tags.
  113686. *
  113687. * For instance, if given the text: `You should go to http://www.yahoo.com`,
  113688. * then the result will be `You should go to &lt;a href="http://www.yahoo.com"&gt;http://www.yahoo.com&lt;/a&gt;`
  113689. *
  113690. * Example:
  113691. *
  113692. * var linkedText = Autolinker.link( "Go to google.com", { newWindow: false } );
  113693. * // Produces: "Go to <a href="http://google.com">google.com</a>"
  113694. *
  113695. * @static
  113696. * @param {String} textOrHtml The HTML or text to find matches within (depending
  113697. * on if the {@link #urls}, {@link #email}, {@link #phone}, {@link #twitter},
  113698. * and {@link #hashtag} options are enabled).
  113699. * @param {Object} [options] Any of the configuration options for the Autolinker
  113700. * class, specified in an Object (map). See the class description for an
  113701. * example call.
  113702. * @return {String} The HTML text, with matches automatically linked.
  113703. */
  113704. Autolinker.link = function( textOrHtml, options ) {
  113705. var autolinker = new Autolinker( options );
  113706. return autolinker.link( textOrHtml );
  113707. };
  113708. // Autolinker Namespaces
  113709. Autolinker.match = {};
  113710. Autolinker.htmlParser = {};
  113711. Autolinker.matchParser = {};
  113712. /*global Autolinker */
  113713. /*jshint eqnull:true, boss:true */
  113714. /**
  113715. * @class Autolinker.Util
  113716. * @singleton
  113717. *
  113718. * A few utility methods for Autolinker.
  113719. */
  113720. Autolinker.Util = {
  113721. /**
  113722. * @property {Function} abstractMethod
  113723. *
  113724. * A function object which represents an abstract method.
  113725. */
  113726. abstractMethod : function() { throw "abstract"; },
  113727. /**
  113728. * @private
  113729. * @property {RegExp} trimRegex
  113730. *
  113731. * The regular expression used to trim the leading and trailing whitespace
  113732. * from a string.
  113733. */
  113734. trimRegex : /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
  113735. /**
  113736. * Assigns (shallow copies) the properties of `src` onto `dest`.
  113737. *
  113738. * @param {Object} dest The destination object.
  113739. * @param {Object} src The source object.
  113740. * @return {Object} The destination object (`dest`)
  113741. */
  113742. assign : function( dest, src ) {
  113743. for( var prop in src ) {
  113744. if( src.hasOwnProperty( prop ) ) {
  113745. dest[ prop ] = src[ prop ];
  113746. }
  113747. }
  113748. return dest;
  113749. },
  113750. /**
  113751. * Extends `superclass` to create a new subclass, adding the `protoProps` to the new subclass's prototype.
  113752. *
  113753. * @param {Function} superclass The constructor function for the superclass.
  113754. * @param {Object} protoProps The methods/properties to add to the subclass's prototype. This may contain the
  113755. * special property `constructor`, which will be used as the new subclass's constructor function.
  113756. * @return {Function} The new subclass function.
  113757. */
  113758. extend : function( superclass, protoProps ) {
  113759. var superclassProto = superclass.prototype;
  113760. var F = function() {};
  113761. F.prototype = superclassProto;
  113762. var subclass;
  113763. if( protoProps.hasOwnProperty( 'constructor' ) ) {
  113764. subclass = protoProps.constructor;
  113765. } else {
  113766. subclass = function() { superclassProto.constructor.apply( this, arguments ); };
  113767. }
  113768. var subclassProto = subclass.prototype = new F(); // set up prototype chain
  113769. subclassProto.constructor = subclass; // fix constructor property
  113770. subclassProto.superclass = superclassProto;
  113771. delete protoProps.constructor; // don't re-assign constructor property to the prototype, since a new function may have been created (`subclass`), which is now already there
  113772. Autolinker.Util.assign( subclassProto, protoProps );
  113773. return subclass;
  113774. },
  113775. /**
  113776. * Truncates the `str` at `len - ellipsisChars.length`, and adds the `ellipsisChars` to the
  113777. * end of the string (by default, two periods: '..'). If the `str` length does not exceed
  113778. * `len`, the string will be returned unchanged.
  113779. *
  113780. * @param {String} str The string to truncate and add an ellipsis to.
  113781. * @param {Number} truncateLen The length to truncate the string at.
  113782. * @param {String} [ellipsisChars=..] The ellipsis character(s) to add to the end of `str`
  113783. * when truncated. Defaults to '..'
  113784. */
  113785. ellipsis : function( str, truncateLen, ellipsisChars ) {
  113786. if( str.length > truncateLen ) {
  113787. ellipsisChars = ( ellipsisChars == null ) ? '..' : ellipsisChars;
  113788. str = str.substring( 0, truncateLen - ellipsisChars.length ) + ellipsisChars;
  113789. }
  113790. return str;
  113791. },
  113792. /**
  113793. * Supports `Array.prototype.indexOf()` functionality for old IE (IE8 and below).
  113794. *
  113795. * @param {Array} arr The array to find an element of.
  113796. * @param {*} element The element to find in the array, and return the index of.
  113797. * @return {Number} The index of the `element`, or -1 if it was not found.
  113798. */
  113799. indexOf : function( arr, element ) {
  113800. if( Array.prototype.indexOf ) {
  113801. return arr.indexOf( element );
  113802. } else {
  113803. for( var i = 0, len = arr.length; i < len; i++ ) {
  113804. if( arr[ i ] === element ) return i;
  113805. }
  113806. return -1;
  113807. }
  113808. },
  113809. /**
  113810. * Performs the functionality of what modern browsers do when `String.prototype.split()` is called
  113811. * with a regular expression that contains capturing parenthesis.
  113812. *
  113813. * For example:
  113814. *
  113815. * // Modern browsers:
  113816. * "a,b,c".split( /(,)/ ); // --> [ 'a', ',', 'b', ',', 'c' ]
  113817. *
  113818. * // Old IE (including IE8):
  113819. * "a,b,c".split( /(,)/ ); // --> [ 'a', 'b', 'c' ]
  113820. *
  113821. * This method emulates the functionality of modern browsers for the old IE case.
  113822. *
  113823. * @param {String} str The string to split.
  113824. * @param {RegExp} splitRegex The regular expression to split the input `str` on. The splitting
  113825. * character(s) will be spliced into the array, as in the "modern browsers" example in the
  113826. * description of this method.
  113827. * Note #1: the supplied regular expression **must** have the 'g' flag specified.
  113828. * Note #2: for simplicity's sake, the regular expression does not need
  113829. * to contain capturing parenthesis - it will be assumed that any match has them.
  113830. * @return {String[]} The split array of strings, with the splitting character(s) included.
  113831. */
  113832. splitAndCapture : function( str, splitRegex ) {
  113833. if( !splitRegex.global ) throw new Error( "`splitRegex` must have the 'g' flag set" );
  113834. var result = [],
  113835. lastIdx = 0,
  113836. match;
  113837. while( match = splitRegex.exec( str ) ) {
  113838. result.push( str.substring( lastIdx, match.index ) );
  113839. result.push( match[ 0 ] ); // push the splitting char(s)
  113840. lastIdx = match.index + match[ 0 ].length;
  113841. }
  113842. result.push( str.substring( lastIdx ) );
  113843. return result;
  113844. },
  113845. /**
  113846. * Trims the leading and trailing whitespace from a string.
  113847. *
  113848. * @param {String} str The string to trim.
  113849. * @return {String}
  113850. */
  113851. trim : function( str ) {
  113852. return str.replace( this.trimRegex, '' );
  113853. }
  113854. };
  113855. /*global Autolinker */
  113856. /*jshint boss:true */
  113857. /**
  113858. * @class Autolinker.HtmlTag
  113859. * @extends Object
  113860. *
  113861. * Represents an HTML tag, which can be used to easily build/modify HTML tags programmatically.
  113862. *
  113863. * Autolinker uses this abstraction to create HTML tags, and then write them out as strings. You may also use
  113864. * this class in your code, especially within a {@link Autolinker#replaceFn replaceFn}.
  113865. *
  113866. * ## Examples
  113867. *
  113868. * Example instantiation:
  113869. *
  113870. * var tag = new Autolinker.HtmlTag( {
  113871. * tagName : 'a',
  113872. * attrs : { 'href': 'http://google.com', 'class': 'external-link' },
  113873. * innerHtml : 'Google'
  113874. * } );
  113875. *
  113876. * tag.toAnchorString(); // <a href="http://google.com" class="external-link">Google</a>
  113877. *
  113878. * // Individual accessor methods
  113879. * tag.getTagName(); // 'a'
  113880. * tag.getAttr( 'href' ); // 'http://google.com'
  113881. * tag.hasClass( 'external-link' ); // true
  113882. *
  113883. *
  113884. * Using mutator methods (which may be used in combination with instantiation config properties):
  113885. *
  113886. * var tag = new Autolinker.HtmlTag();
  113887. * tag.setTagName( 'a' );
  113888. * tag.setAttr( 'href', 'http://google.com' );
  113889. * tag.addClass( 'external-link' );
  113890. * tag.setInnerHtml( 'Google' );
  113891. *
  113892. * tag.getTagName(); // 'a'
  113893. * tag.getAttr( 'href' ); // 'http://google.com'
  113894. * tag.hasClass( 'external-link' ); // true
  113895. *
  113896. * tag.toAnchorString(); // <a href="http://google.com" class="external-link">Google</a>
  113897. *
  113898. *
  113899. * ## Example use within a {@link Autolinker#replaceFn replaceFn}
  113900. *
  113901. * var html = Autolinker.link( "Test google.com", {
  113902. * replaceFn : function( autolinker, match ) {
  113903. * var tag = autolinker.getTagBuilder().build( match ); // returns an {@link Autolinker.HtmlTag} instance, configured with the Match's href and anchor text
  113904. * tag.setAttr( 'rel', 'nofollow' );
  113905. *
  113906. * return tag;
  113907. * }
  113908. * } );
  113909. *
  113910. * // generated html:
  113911. * // Test <a href="http://google.com" target="_blank" rel="nofollow">google.com</a>
  113912. *
  113913. *
  113914. * ## Example use with a new tag for the replacement
  113915. *
  113916. * var html = Autolinker.link( "Test google.com", {
  113917. * replaceFn : function( autolinker, match ) {
  113918. * var tag = new Autolinker.HtmlTag( {
  113919. * tagName : 'button',
  113920. * attrs : { 'title': 'Load URL: ' + match.getAnchorHref() },
  113921. * innerHtml : 'Load URL: ' + match.getAnchorText()
  113922. * } );
  113923. *
  113924. * return tag;
  113925. * }
  113926. * } );
  113927. *
  113928. * // generated html:
  113929. * // Test <button title="Load URL: http://google.com">Load URL: google.com</button>
  113930. */
  113931. Autolinker.HtmlTag = Autolinker.Util.extend( Object, {
  113932. /**
  113933. * @cfg {String} tagName
  113934. *
  113935. * The tag name. Ex: 'a', 'button', etc.
  113936. *
  113937. * Not required at instantiation time, but should be set using {@link #setTagName} before {@link #toAnchorString}
  113938. * is executed.
  113939. */
  113940. /**
  113941. * @cfg {Object.<String, String>} attrs
  113942. *
  113943. * An key/value Object (map) of attributes to create the tag with. The keys are the attribute names, and the
  113944. * values are the attribute values.
  113945. */
  113946. /**
  113947. * @cfg {String} innerHtml
  113948. *
  113949. * The inner HTML for the tag.
  113950. *
  113951. * Note the camel case name on `innerHtml`. Acronyms are camelCased in this utility (such as not to run into the acronym
  113952. * naming inconsistency that the DOM developers created with `XMLHttpRequest`). You may alternatively use {@link #innerHTML}
  113953. * if you prefer, but this one is recommended.
  113954. */
  113955. /**
  113956. * @cfg {String} innerHTML
  113957. *
  113958. * Alias of {@link #innerHtml}, accepted for consistency with the browser DOM api, but prefer the camelCased version
  113959. * for acronym names.
  113960. */
  113961. /**
  113962. * @protected
  113963. * @property {RegExp} whitespaceRegex
  113964. *
  113965. * Regular expression used to match whitespace in a string of CSS classes.
  113966. */
  113967. whitespaceRegex : /\s+/,
  113968. /**
  113969. * @constructor
  113970. * @param {Object} [cfg] The configuration properties for this class, in an Object (map)
  113971. */
  113972. constructor : function( cfg ) {
  113973. Autolinker.Util.assign( this, cfg );
  113974. this.innerHtml = this.innerHtml || this.innerHTML; // accept either the camelCased form or the fully capitalized acronym
  113975. },
  113976. /**
  113977. * Sets the tag name that will be used to generate the tag with.
  113978. *
  113979. * @param {String} tagName
  113980. * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
  113981. */
  113982. setTagName : function( tagName ) {
  113983. this.tagName = tagName;
  113984. return this;
  113985. },
  113986. /**
  113987. * Retrieves the tag name.
  113988. *
  113989. * @return {String}
  113990. */
  113991. getTagName : function() {
  113992. return this.tagName || "";
  113993. },
  113994. /**
  113995. * Sets an attribute on the HtmlTag.
  113996. *
  113997. * @param {String} attrName The attribute name to set.
  113998. * @param {String} attrValue The attribute value to set.
  113999. * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
  114000. */
  114001. setAttr : function( attrName, attrValue ) {
  114002. var tagAttrs = this.getAttrs();
  114003. tagAttrs[ attrName ] = attrValue;
  114004. return this;
  114005. },
  114006. /**
  114007. * Retrieves an attribute from the HtmlTag. If the attribute does not exist, returns `undefined`.
  114008. *
  114009. * @param {String} name The attribute name to retrieve.
  114010. * @return {String} The attribute's value, or `undefined` if it does not exist on the HtmlTag.
  114011. */
  114012. getAttr : function( attrName ) {
  114013. return this.getAttrs()[ attrName ];
  114014. },
  114015. /**
  114016. * Sets one or more attributes on the HtmlTag.
  114017. *
  114018. * @param {Object.<String, String>} attrs A key/value Object (map) of the attributes to set.
  114019. * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
  114020. */
  114021. setAttrs : function( attrs ) {
  114022. var tagAttrs = this.getAttrs();
  114023. Autolinker.Util.assign( tagAttrs, attrs );
  114024. return this;
  114025. },
  114026. /**
  114027. * Retrieves the attributes Object (map) for the HtmlTag.
  114028. *
  114029. * @return {Object.<String, String>} A key/value object of the attributes for the HtmlTag.
  114030. */
  114031. getAttrs : function() {
  114032. return this.attrs || ( this.attrs = {} );
  114033. },
  114034. /**
  114035. * Sets the provided `cssClass`, overwriting any current CSS classes on the HtmlTag.
  114036. *
  114037. * @param {String} cssClass One or more space-separated CSS classes to set (overwrite).
  114038. * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
  114039. */
  114040. setClass : function( cssClass ) {
  114041. return this.setAttr( 'class', cssClass );
  114042. },
  114043. /**
  114044. * Convenience method to add one or more CSS classes to the HtmlTag. Will not add duplicate CSS classes.
  114045. *
  114046. * @param {String} cssClass One or more space-separated CSS classes to add.
  114047. * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
  114048. */
  114049. addClass : function( cssClass ) {
  114050. var classAttr = this.getClass(),
  114051. whitespaceRegex = this.whitespaceRegex,
  114052. indexOf = Autolinker.Util.indexOf, // to support IE8 and below
  114053. classes = ( !classAttr ) ? [] : classAttr.split( whitespaceRegex ),
  114054. newClasses = cssClass.split( whitespaceRegex ),
  114055. newClass;
  114056. while( newClass = newClasses.shift() ) {
  114057. if( indexOf( classes, newClass ) === -1 ) {
  114058. classes.push( newClass );
  114059. }
  114060. }
  114061. this.getAttrs()[ 'class' ] = classes.join( " " );
  114062. return this;
  114063. },
  114064. /**
  114065. * Convenience method to remove one or more CSS classes from the HtmlTag.
  114066. *
  114067. * @param {String} cssClass One or more space-separated CSS classes to remove.
  114068. * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
  114069. */
  114070. removeClass : function( cssClass ) {
  114071. var classAttr = this.getClass(),
  114072. whitespaceRegex = this.whitespaceRegex,
  114073. indexOf = Autolinker.Util.indexOf, // to support IE8 and below
  114074. classes = ( !classAttr ) ? [] : classAttr.split( whitespaceRegex ),
  114075. removeClasses = cssClass.split( whitespaceRegex ),
  114076. removeClass;
  114077. while( classes.length && ( removeClass = removeClasses.shift() ) ) {
  114078. var idx = indexOf( classes, removeClass );
  114079. if( idx !== -1 ) {
  114080. classes.splice( idx, 1 );
  114081. }
  114082. }
  114083. this.getAttrs()[ 'class' ] = classes.join( " " );
  114084. return this;
  114085. },
  114086. /**
  114087. * Convenience method to retrieve the CSS class(es) for the HtmlTag, which will each be separated by spaces when
  114088. * there are multiple.
  114089. *
  114090. * @return {String}
  114091. */
  114092. getClass : function() {
  114093. return this.getAttrs()[ 'class' ] || "";
  114094. },
  114095. /**
  114096. * Convenience method to check if the tag has a CSS class or not.
  114097. *
  114098. * @param {String} cssClass The CSS class to check for.
  114099. * @return {Boolean} `true` if the HtmlTag has the CSS class, `false` otherwise.
  114100. */
  114101. hasClass : function( cssClass ) {
  114102. return ( ' ' + this.getClass() + ' ' ).indexOf( ' ' + cssClass + ' ' ) !== -1;
  114103. },
  114104. /**
  114105. * Sets the inner HTML for the tag.
  114106. *
  114107. * @param {String} html The inner HTML to set.
  114108. * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
  114109. */
  114110. setInnerHtml : function( html ) {
  114111. this.innerHtml = html;
  114112. return this;
  114113. },
  114114. /**
  114115. * Retrieves the inner HTML for the tag.
  114116. *
  114117. * @return {String}
  114118. */
  114119. getInnerHtml : function() {
  114120. return this.innerHtml || "";
  114121. },
  114122. /**
  114123. * Override of superclass method used to generate the HTML string for the tag.
  114124. *
  114125. * @return {String}
  114126. */
  114127. toAnchorString : function() {
  114128. var tagName = this.getTagName(),
  114129. attrsStr = this.buildAttrsStr();
  114130. attrsStr = ( attrsStr ) ? ' ' + attrsStr : ''; // prepend a space if there are actually attributes
  114131. return [ '<', tagName, attrsStr, '>', this.getInnerHtml(), '</', tagName, '>' ].join( "" );
  114132. },
  114133. /**
  114134. * Support method for {@link #toAnchorString}, returns the string space-separated key="value" pairs, used to populate
  114135. * the stringified HtmlTag.
  114136. *
  114137. * @protected
  114138. * @return {String} Example return: `attr1="value1" attr2="value2"`
  114139. */
  114140. buildAttrsStr : function() {
  114141. if( !this.attrs ) return ""; // no `attrs` Object (map) has been set, return empty string
  114142. var attrs = this.getAttrs(),
  114143. attrsArr = [];
  114144. for( var prop in attrs ) {
  114145. if( attrs.hasOwnProperty( prop ) ) {
  114146. attrsArr.push( prop + '="' + attrs[ prop ] + '"' );
  114147. }
  114148. }
  114149. return attrsArr.join( " " );
  114150. }
  114151. } );
  114152. /*global Autolinker */
  114153. /*jshint sub:true */
  114154. /**
  114155. * @protected
  114156. * @class Autolinker.AnchorTagBuilder
  114157. * @extends Object
  114158. *
  114159. * Builds anchor (&lt;a&gt;) tags for the Autolinker utility when a match is found.
  114160. *
  114161. * Normally this class is instantiated, configured, and used internally by an {@link Autolinker} instance, but may
  114162. * actually be retrieved in a {@link Autolinker#replaceFn replaceFn} to create {@link Autolinker.HtmlTag HtmlTag} instances
  114163. * which may be modified before returning from the {@link Autolinker#replaceFn replaceFn}. For example:
  114164. *
  114165. * var html = Autolinker.link( "Test google.com", {
  114166. * replaceFn : function( autolinker, match ) {
  114167. * var tag = autolinker.getTagBuilder().build( match ); // returns an {@link Autolinker.HtmlTag} instance
  114168. * tag.setAttr( 'rel', 'nofollow' );
  114169. *
  114170. * return tag;
  114171. * }
  114172. * } );
  114173. *
  114174. * // generated html:
  114175. * // Test <a href="http://google.com" target="_blank" rel="nofollow">google.com</a>
  114176. */
  114177. Autolinker.AnchorTagBuilder = Autolinker.Util.extend( Object, {
  114178. /**
  114179. * @cfg {Boolean} newWindow
  114180. * @inheritdoc Autolinker#newWindow
  114181. */
  114182. /**
  114183. * @cfg {Number} truncate
  114184. * @inheritdoc Autolinker#truncate
  114185. */
  114186. /**
  114187. * @cfg {String} className
  114188. * @inheritdoc Autolinker#className
  114189. */
  114190. /**
  114191. * @constructor
  114192. * @param {Object} [cfg] The configuration options for the AnchorTagBuilder instance, specified in an Object (map).
  114193. */
  114194. constructor : function( cfg ) {
  114195. Autolinker.Util.assign( this, cfg );
  114196. },
  114197. /**
  114198. * Generates the actual anchor (&lt;a&gt;) tag to use in place of the
  114199. * matched text, via its `match` object.
  114200. *
  114201. * @param {Autolinker.match.Match} match The Match instance to generate an
  114202. * anchor tag from.
  114203. * @return {Autolinker.HtmlTag} The HtmlTag instance for the anchor tag.
  114204. */
  114205. build : function( match ) {
  114206. var tag = new Autolinker.HtmlTag( {
  114207. tagName : 'a',
  114208. attrs : this.createAttrs( match.getType(), match.getAnchorHref() ),
  114209. innerHtml : this.processAnchorText( match.getAnchorText() )
  114210. } );
  114211. return tag;
  114212. },
  114213. /**
  114214. * Creates the Object (map) of the HTML attributes for the anchor (&lt;a&gt;)
  114215. * tag being generated.
  114216. *
  114217. * @protected
  114218. * @param {"url"/"email"/"phone"/"twitter"/"hashtag"} matchType The type of
  114219. * match that an anchor tag is being generated for.
  114220. * @param {String} href The href for the anchor tag.
  114221. * @return {Object} A key/value Object (map) of the anchor tag's attributes.
  114222. */
  114223. createAttrs : function( matchType, anchorHref ) {
  114224. var attrs = {
  114225. 'href' : anchorHref // we'll always have the `href` attribute
  114226. };
  114227. var cssClass = this.createCssClass( matchType );
  114228. if( cssClass ) {
  114229. attrs[ 'class' ] = cssClass;
  114230. }
  114231. if( this.newWindow ) {
  114232. attrs[ 'target' ] = "_blank";
  114233. }
  114234. return attrs;
  114235. },
  114236. /**
  114237. * Creates the CSS class that will be used for a given anchor tag, based on
  114238. * the `matchType` and the {@link #className} config.
  114239. *
  114240. * @private
  114241. * @param {"url"/"email"/"phone"/"twitter"/"hashtag"} matchType The type of
  114242. * match that an anchor tag is being generated for.
  114243. * @return {String} The CSS class string for the link. Example return:
  114244. * "myLink myLink-url". If no {@link #className} was configured, returns
  114245. * an empty string.
  114246. */
  114247. createCssClass : function( matchType ) {
  114248. var className = this.className;
  114249. if( !className )
  114250. return "";
  114251. else
  114252. return className + " " + className + "-" + matchType; // ex: "myLink myLink-url", "myLink myLink-email", "myLink myLink-phone", "myLink myLink-twitter", or "myLink myLink-hashtag"
  114253. },
  114254. /**
  114255. * Processes the `anchorText` by truncating the text according to the
  114256. * {@link #truncate} config.
  114257. *
  114258. * @private
  114259. * @param {String} anchorText The anchor tag's text (i.e. what will be
  114260. * displayed).
  114261. * @return {String} The processed `anchorText`.
  114262. */
  114263. processAnchorText : function( anchorText ) {
  114264. anchorText = this.doTruncate( anchorText );
  114265. return anchorText;
  114266. },
  114267. /**
  114268. * Performs the truncation of the `anchorText`, if the `anchorText` is
  114269. * longer than the {@link #truncate} option. Truncates the text to 2
  114270. * characters fewer than the {@link #truncate} option, and adds ".." to the
  114271. * end.
  114272. *
  114273. * @private
  114274. * @param {String} text The anchor tag's text (i.e. what will be displayed).
  114275. * @return {String} The truncated anchor text.
  114276. */
  114277. doTruncate : function( anchorText ) {
  114278. return Autolinker.Util.ellipsis( anchorText, this.truncate || Number.POSITIVE_INFINITY );
  114279. }
  114280. } );
  114281. /*global Autolinker */
  114282. /**
  114283. * @private
  114284. * @class Autolinker.htmlParser.HtmlParser
  114285. * @extends Object
  114286. *
  114287. * An HTML parser implementation which simply walks an HTML string and returns an array of
  114288. * {@link Autolinker.htmlParser.HtmlNode HtmlNodes} that represent the basic HTML structure of the input string.
  114289. *
  114290. * Autolinker uses this to only link URLs/emails/Twitter handles within text nodes, effectively ignoring / "walking
  114291. * around" HTML tags.
  114292. */
  114293. Autolinker.htmlParser.HtmlParser = Autolinker.Util.extend( Object, {
  114294. /**
  114295. * @private
  114296. * @property {RegExp} htmlRegex
  114297. *
  114298. * The regular expression used to pull out HTML tags from a string. Handles namespaced HTML tags and
  114299. * attribute names, as specified by http://www.w3.org/TR/html-markup/syntax.html.
  114300. *
  114301. * Capturing groups:
  114302. *
  114303. * 1. The "!DOCTYPE" tag name, if a tag is a &lt;!DOCTYPE&gt; tag.
  114304. * 2. If it is an end tag, this group will have the '/'.
  114305. * 3. If it is a comment tag, this group will hold the comment text (i.e.
  114306. * the text inside the `&lt;!--` and `--&gt;`.
  114307. * 4. The tag name for all tags (other than the &lt;!DOCTYPE&gt; tag)
  114308. */
  114309. htmlRegex : (function() {
  114310. var commentTagRegex = /!--([\s\S]+?)--/,
  114311. tagNameRegex = /[0-9a-zA-Z][0-9a-zA-Z:]*/,
  114312. attrNameRegex = /[^\s\0"'>\/=\x01-\x1F\x7F]+/, // the unicode range accounts for excluding control chars, and the delete char
  114313. attrValueRegex = /(?:"[^"]*?"|'[^']*?'|[^'"=<>`\s]+)/, // double quoted, single quoted, or unquoted attribute values
  114314. nameEqualsValueRegex = attrNameRegex.source + '(?:\\s*=\\s*' + attrValueRegex.source + ')?'; // optional '=[value]'
  114315. return new RegExp( [
  114316. // for <!DOCTYPE> tag. Ex: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">)
  114317. '(?:',
  114318. '<(!DOCTYPE)', // *** Capturing Group 1 - If it's a doctype tag
  114319. // Zero or more attributes following the tag name
  114320. '(?:',
  114321. '\\s+', // one or more whitespace chars before an attribute
  114322. // Either:
  114323. // A. attr="value", or
  114324. // B. "value" alone (To cover example doctype tag: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">)
  114325. '(?:', nameEqualsValueRegex, '|', attrValueRegex.source + ')',
  114326. ')*',
  114327. '>',
  114328. ')',
  114329. '|',
  114330. // All other HTML tags (i.e. tags that are not <!DOCTYPE>)
  114331. '(?:',
  114332. '<(/)?', // Beginning of a tag or comment. Either '<' for a start tag, or '</' for an end tag.
  114333. // *** Capturing Group 2: The slash or an empty string. Slash ('/') for end tag, empty string for start or self-closing tag.
  114334. '(?:',
  114335. commentTagRegex.source, // *** Capturing Group 3 - A Comment Tag's Text
  114336. '|',
  114337. '(?:',
  114338. // *** Capturing Group 4 - The tag name
  114339. '(' + tagNameRegex.source + ')',
  114340. // Zero or more attributes following the tag name
  114341. '(?:',
  114342. '\\s+', // one or more whitespace chars before an attribute
  114343. nameEqualsValueRegex, // attr="value" (with optional ="value" part)
  114344. ')*',
  114345. '\\s*/?', // any trailing spaces and optional '/' before the closing '>'
  114346. ')',
  114347. ')',
  114348. '>',
  114349. ')'
  114350. ].join( "" ), 'gi' );
  114351. } )(),
  114352. /**
  114353. * @private
  114354. * @property {RegExp} htmlCharacterEntitiesRegex
  114355. *
  114356. * The regular expression that matches common HTML character entities.
  114357. *
  114358. * Ignoring &amp; as it could be part of a query string -- handling it separately.
  114359. */
  114360. htmlCharacterEntitiesRegex: /(&nbsp;|&#160;|&lt;|&#60;|&gt;|&#62;|&quot;|&#34;|&#39;)/gi,
  114361. /**
  114362. * Parses an HTML string and returns a simple array of {@link Autolinker.htmlParser.HtmlNode HtmlNodes}
  114363. * to represent the HTML structure of the input string.
  114364. *
  114365. * @param {String} html The HTML to parse.
  114366. * @return {Autolinker.htmlParser.HtmlNode[]}
  114367. */
  114368. parse : function( html ) {
  114369. var htmlRegex = this.htmlRegex,
  114370. currentResult,
  114371. lastIndex = 0,
  114372. textAndEntityNodes,
  114373. nodes = []; // will be the result of the method
  114374. while( ( currentResult = htmlRegex.exec( html ) ) !== null ) {
  114375. var tagText = currentResult[ 0 ],
  114376. commentText = currentResult[ 3 ], // if we've matched a comment
  114377. tagName = currentResult[ 1 ] || currentResult[ 4 ], // The <!DOCTYPE> tag (ex: "!DOCTYPE"), or another tag (ex: "a" or "img")
  114378. isClosingTag = !!currentResult[ 2 ],
  114379. inBetweenTagsText = html.substring( lastIndex, currentResult.index );
  114380. // Push TextNodes and EntityNodes for any text found between tags
  114381. if( inBetweenTagsText ) {
  114382. textAndEntityNodes = this.parseTextAndEntityNodes( inBetweenTagsText );
  114383. nodes.push.apply( nodes, textAndEntityNodes );
  114384. }
  114385. // Push the CommentNode or ElementNode
  114386. if( commentText ) {
  114387. nodes.push( this.createCommentNode( tagText, commentText ) );
  114388. } else {
  114389. nodes.push( this.createElementNode( tagText, tagName, isClosingTag ) );
  114390. }
  114391. lastIndex = currentResult.index + tagText.length;
  114392. }
  114393. // Process any remaining text after the last HTML element. Will process all of the text if there were no HTML elements.
  114394. if( lastIndex < html.length ) {
  114395. var text = html.substring( lastIndex );
  114396. // Push TextNodes and EntityNodes for any text found between tags
  114397. if( text ) {
  114398. textAndEntityNodes = this.parseTextAndEntityNodes( text );
  114399. nodes.push.apply( nodes, textAndEntityNodes );
  114400. }
  114401. }
  114402. return nodes;
  114403. },
  114404. /**
  114405. * Parses text and HTML entity nodes from a given string. The input string
  114406. * should not have any HTML tags (elements) within it.
  114407. *
  114408. * @private
  114409. * @param {String} text The text to parse.
  114410. * @return {Autolinker.htmlParser.HtmlNode[]} An array of HtmlNodes to
  114411. * represent the {@link Autolinker.htmlParser.TextNode TextNodes} and
  114412. * {@link Autolinker.htmlParser.EntityNode EntityNodes} found.
  114413. */
  114414. parseTextAndEntityNodes : function( text ) {
  114415. var nodes = [],
  114416. textAndEntityTokens = Autolinker.Util.splitAndCapture( text, this.htmlCharacterEntitiesRegex ); // split at HTML entities, but include the HTML entities in the results array
  114417. // Every even numbered token is a TextNode, and every odd numbered token is an EntityNode
  114418. // For example: an input `text` of "Test &quot;this&quot; today" would turn into the
  114419. // `textAndEntityTokens`: [ 'Test ', '&quot;', 'this', '&quot;', ' today' ]
  114420. for( var i = 0, len = textAndEntityTokens.length; i < len; i += 2 ) {
  114421. var textToken = textAndEntityTokens[ i ],
  114422. entityToken = textAndEntityTokens[ i + 1 ];
  114423. if( textToken ) nodes.push( this.createTextNode( textToken ) );
  114424. if( entityToken ) nodes.push( this.createEntityNode( entityToken ) );
  114425. }
  114426. return nodes;
  114427. },
  114428. /**
  114429. * Factory method to create an {@link Autolinker.htmlParser.CommentNode CommentNode}.
  114430. *
  114431. * @private
  114432. * @param {String} tagText The full text of the tag (comment) that was
  114433. * matched, including its &lt;!-- and --&gt;.
  114434. * @param {String} comment The full text of the comment that was matched.
  114435. */
  114436. createCommentNode : function( tagText, commentText ) {
  114437. return new Autolinker.htmlParser.CommentNode( {
  114438. text: tagText,
  114439. comment: Autolinker.Util.trim( commentText )
  114440. } );
  114441. },
  114442. /**
  114443. * Factory method to create an {@link Autolinker.htmlParser.ElementNode ElementNode}.
  114444. *
  114445. * @private
  114446. * @param {String} tagText The full text of the tag (element) that was
  114447. * matched, including its attributes.
  114448. * @param {String} tagName The name of the tag. Ex: An &lt;img&gt; tag would
  114449. * be passed to this method as "img".
  114450. * @param {Boolean} isClosingTag `true` if it's a closing tag, false
  114451. * otherwise.
  114452. * @return {Autolinker.htmlParser.ElementNode}
  114453. */
  114454. createElementNode : function( tagText, tagName, isClosingTag ) {
  114455. return new Autolinker.htmlParser.ElementNode( {
  114456. text : tagText,
  114457. tagName : tagName.toLowerCase(),
  114458. closing : isClosingTag
  114459. } );
  114460. },
  114461. /**
  114462. * Factory method to create a {@link Autolinker.htmlParser.EntityNode EntityNode}.
  114463. *
  114464. * @private
  114465. * @param {String} text The text that was matched for the HTML entity (such
  114466. * as '&amp;nbsp;').
  114467. * @return {Autolinker.htmlParser.EntityNode}
  114468. */
  114469. createEntityNode : function( text ) {
  114470. return new Autolinker.htmlParser.EntityNode( { text: text } );
  114471. },
  114472. /**
  114473. * Factory method to create a {@link Autolinker.htmlParser.TextNode TextNode}.
  114474. *
  114475. * @private
  114476. * @param {String} text The text that was matched.
  114477. * @return {Autolinker.htmlParser.TextNode}
  114478. */
  114479. createTextNode : function( text ) {
  114480. return new Autolinker.htmlParser.TextNode( { text: text } );
  114481. }
  114482. } );
  114483. /*global Autolinker */
  114484. /**
  114485. * @abstract
  114486. * @class Autolinker.htmlParser.HtmlNode
  114487. *
  114488. * Represents an HTML node found in an input string. An HTML node is one of the following:
  114489. *
  114490. * 1. An {@link Autolinker.htmlParser.ElementNode ElementNode}, which represents HTML tags.
  114491. * 2. A {@link Autolinker.htmlParser.TextNode TextNode}, which represents text outside or within HTML tags.
  114492. * 3. A {@link Autolinker.htmlParser.EntityNode EntityNode}, which represents one of the known HTML
  114493. * entities that Autolinker looks for. This includes common ones such as &amp;quot; and &amp;nbsp;
  114494. */
  114495. Autolinker.htmlParser.HtmlNode = Autolinker.Util.extend( Object, {
  114496. /**
  114497. * @cfg {String} text (required)
  114498. *
  114499. * The original text that was matched for the HtmlNode.
  114500. *
  114501. * - In the case of an {@link Autolinker.htmlParser.ElementNode ElementNode}, this will be the tag's
  114502. * text.
  114503. * - In the case of a {@link Autolinker.htmlParser.TextNode TextNode}, this will be the text itself.
  114504. * - In the case of a {@link Autolinker.htmlParser.EntityNode EntityNode}, this will be the text of
  114505. * the HTML entity.
  114506. */
  114507. text : "",
  114508. /**
  114509. * @constructor
  114510. * @param {Object} cfg The configuration properties for the Match instance, specified in an Object (map).
  114511. */
  114512. constructor : function( cfg ) {
  114513. Autolinker.Util.assign( this, cfg );
  114514. },
  114515. /**
  114516. * Returns a string name for the type of node that this class represents.
  114517. *
  114518. * @abstract
  114519. * @return {String}
  114520. */
  114521. getType : Autolinker.Util.abstractMethod,
  114522. /**
  114523. * Retrieves the {@link #text} for the HtmlNode.
  114524. *
  114525. * @return {String}
  114526. */
  114527. getText : function() {
  114528. return this.text;
  114529. }
  114530. } );
  114531. /*global Autolinker */
  114532. /**
  114533. * @class Autolinker.htmlParser.CommentNode
  114534. * @extends Autolinker.htmlParser.HtmlNode
  114535. *
  114536. * Represents an HTML comment node that has been parsed by the
  114537. * {@link Autolinker.htmlParser.HtmlParser}.
  114538. *
  114539. * See this class's superclass ({@link Autolinker.htmlParser.HtmlNode}) for more
  114540. * details.
  114541. */
  114542. Autolinker.htmlParser.CommentNode = Autolinker.Util.extend( Autolinker.htmlParser.HtmlNode, {
  114543. /**
  114544. * @cfg {String} comment (required)
  114545. *
  114546. * The text inside the comment tag. This text is stripped of any leading or
  114547. * trailing whitespace.
  114548. */
  114549. comment : '',
  114550. /**
  114551. * Returns a string name for the type of node that this class represents.
  114552. *
  114553. * @return {String}
  114554. */
  114555. getType : function() {
  114556. return 'comment';
  114557. },
  114558. /**
  114559. * Returns the comment inside the comment tag.
  114560. *
  114561. * @return {String}
  114562. */
  114563. getComment : function() {
  114564. return this.comment;
  114565. }
  114566. } );
  114567. /*global Autolinker */
  114568. /**
  114569. * @class Autolinker.htmlParser.ElementNode
  114570. * @extends Autolinker.htmlParser.HtmlNode
  114571. *
  114572. * Represents an HTML element node that has been parsed by the {@link Autolinker.htmlParser.HtmlParser}.
  114573. *
  114574. * See this class's superclass ({@link Autolinker.htmlParser.HtmlNode}) for more details.
  114575. */
  114576. Autolinker.htmlParser.ElementNode = Autolinker.Util.extend( Autolinker.htmlParser.HtmlNode, {
  114577. /**
  114578. * @cfg {String} tagName (required)
  114579. *
  114580. * The name of the tag that was matched.
  114581. */
  114582. tagName : '',
  114583. /**
  114584. * @cfg {Boolean} closing (required)
  114585. *
  114586. * `true` if the element (tag) is a closing tag, `false` if its an opening tag.
  114587. */
  114588. closing : false,
  114589. /**
  114590. * Returns a string name for the type of node that this class represents.
  114591. *
  114592. * @return {String}
  114593. */
  114594. getType : function() {
  114595. return 'element';
  114596. },
  114597. /**
  114598. * Returns the HTML element's (tag's) name. Ex: for an &lt;img&gt; tag, returns "img".
  114599. *
  114600. * @return {String}
  114601. */
  114602. getTagName : function() {
  114603. return this.tagName;
  114604. },
  114605. /**
  114606. * Determines if the HTML element (tag) is a closing tag. Ex: &lt;div&gt; returns
  114607. * `false`, while &lt;/div&gt; returns `true`.
  114608. *
  114609. * @return {Boolean}
  114610. */
  114611. isClosing : function() {
  114612. return this.closing;
  114613. }
  114614. } );
  114615. /*global Autolinker */
  114616. /**
  114617. * @class Autolinker.htmlParser.EntityNode
  114618. * @extends Autolinker.htmlParser.HtmlNode
  114619. *
  114620. * Represents a known HTML entity node that has been parsed by the {@link Autolinker.htmlParser.HtmlParser}.
  114621. * Ex: '&amp;nbsp;', or '&amp#160;' (which will be retrievable from the {@link #getText} method.
  114622. *
  114623. * Note that this class will only be returned from the HtmlParser for the set of checked HTML entity nodes
  114624. * defined by the {@link Autolinker.htmlParser.HtmlParser#htmlCharacterEntitiesRegex}.
  114625. *
  114626. * See this class's superclass ({@link Autolinker.htmlParser.HtmlNode}) for more details.
  114627. */
  114628. Autolinker.htmlParser.EntityNode = Autolinker.Util.extend( Autolinker.htmlParser.HtmlNode, {
  114629. /**
  114630. * Returns a string name for the type of node that this class represents.
  114631. *
  114632. * @return {String}
  114633. */
  114634. getType : function() {
  114635. return 'entity';
  114636. }
  114637. } );
  114638. /*global Autolinker */
  114639. /**
  114640. * @class Autolinker.htmlParser.TextNode
  114641. * @extends Autolinker.htmlParser.HtmlNode
  114642. *
  114643. * Represents a text node that has been parsed by the {@link Autolinker.htmlParser.HtmlParser}.
  114644. *
  114645. * See this class's superclass ({@link Autolinker.htmlParser.HtmlNode}) for more details.
  114646. */
  114647. Autolinker.htmlParser.TextNode = Autolinker.Util.extend( Autolinker.htmlParser.HtmlNode, {
  114648. /**
  114649. * Returns a string name for the type of node that this class represents.
  114650. *
  114651. * @return {String}
  114652. */
  114653. getType : function() {
  114654. return 'text';
  114655. }
  114656. } );
  114657. /*global Autolinker */
  114658. /**
  114659. * @private
  114660. * @class Autolinker.matchParser.MatchParser
  114661. * @extends Object
  114662. *
  114663. * Used by Autolinker to parse potential matches, given an input string of text.
  114664. *
  114665. * The MatchParser is fed a non-HTML string in order to search for matches.
  114666. * Autolinker first uses the {@link Autolinker.htmlParser.HtmlParser} to "walk
  114667. * around" HTML tags, and then the text around the HTML tags is passed into the
  114668. * MatchParser in order to find the actual matches.
  114669. */
  114670. Autolinker.matchParser.MatchParser = Autolinker.Util.extend( Object, {
  114671. /**
  114672. * @cfg {Boolean} urls
  114673. * @inheritdoc Autolinker#urls
  114674. */
  114675. urls : true,
  114676. /**
  114677. * @cfg {Boolean} email
  114678. * @inheritdoc Autolinker#email
  114679. */
  114680. email : true,
  114681. /**
  114682. * @cfg {Boolean} twitter
  114683. * @inheritdoc Autolinker#twitter
  114684. */
  114685. twitter : true,
  114686. /**
  114687. * @cfg {Boolean} phone
  114688. * @inheritdoc Autolinker#phone
  114689. */
  114690. phone: true,
  114691. /**
  114692. * @cfg {Boolean/String} hashtag
  114693. * @inheritdoc Autolinker#hashtag
  114694. */
  114695. hashtag : false,
  114696. /**
  114697. * @cfg {Boolean} stripPrefix
  114698. * @inheritdoc Autolinker#stripPrefix
  114699. */
  114700. stripPrefix : true,
  114701. /**
  114702. * @private
  114703. * @property {RegExp} matcherRegex
  114704. *
  114705. * The regular expression that matches URLs, email addresses, phone #s,
  114706. * Twitter handles, and Hashtags.
  114707. *
  114708. * This regular expression has the following capturing groups:
  114709. *
  114710. * 1. Group that is used to determine if there is a Twitter handle match
  114711. * (i.e. \@someTwitterUser). Simply check for its existence to determine
  114712. * if there is a Twitter handle match. The next couple of capturing
  114713. * groups give information about the Twitter handle match.
  114714. * 2. The whitespace character before the \@sign in a Twitter handle. This
  114715. * is needed because there are no lookbehinds in JS regular expressions,
  114716. * and can be used to reconstruct the original string in a replace().
  114717. * 3. The Twitter handle itself in a Twitter match. If the match is
  114718. * '@someTwitterUser', the handle is 'someTwitterUser'.
  114719. * 4. Group that matches an email address. Used to determine if the match
  114720. * is an email address, as well as holding the full address. Ex:
  114721. * 'me@my.com'
  114722. * 5. Group that matches a URL in the input text. Ex: 'http://google.com',
  114723. * 'www.google.com', or just 'google.com'. This also includes a path,
  114724. * url parameters, or hash anchors. Ex: google.com/path/to/file?q1=1&q2=2#myAnchor
  114725. * 6. Group that matches a protocol URL (i.e. 'http://google.com'). This is
  114726. * used to match protocol URLs with just a single word, like 'http://localhost',
  114727. * where we won't double check that the domain name has at least one '.'
  114728. * in it.
  114729. * 7. A protocol-relative ('//') match for the case of a 'www.' prefixed
  114730. * URL. Will be an empty string if it is not a protocol-relative match.
  114731. * We need to know the character before the '//' in order to determine
  114732. * if it is a valid match or the // was in a string we don't want to
  114733. * auto-link.
  114734. * 8. A protocol-relative ('//') match for the case of a known TLD prefixed
  114735. * URL. Will be an empty string if it is not a protocol-relative match.
  114736. * See #6 for more info.
  114737. * 9. Group that is used to determine if there is a phone number match. The
  114738. * next 3 groups give segments of the phone number.
  114739. * 10. Group that is used to determine if there is a Hashtag match
  114740. * (i.e. \#someHashtag). Simply check for its existence to determine if
  114741. * there is a Hashtag match. The next couple of capturing groups give
  114742. * information about the Hashtag match.
  114743. * 11. The whitespace character before the #sign in a Hashtag handle. This
  114744. * is needed because there are no look-behinds in JS regular
  114745. * expressions, and can be used to reconstruct the original string in a
  114746. * replace().
  114747. * 12. The Hashtag itself in a Hashtag match. If the match is
  114748. * '#someHashtag', the hashtag is 'someHashtag'.
  114749. */
  114750. matcherRegex : (function() {
  114751. var twitterRegex = /(^|[^\w])@(\w{1,15})/, // For matching a twitter handle. Ex: @gregory_jacobs
  114752. hashtagRegex = /(^|[^\w])#(\w{1,15})/, // For matching a Hashtag. Ex: #games
  114753. emailRegex = /(?:[\-;:&=\+\$,\w\.]+@)/, // something@ for email addresses (a.k.a. local-part)
  114754. phoneRegex = /(?:\+?\d{1,3}[-\s.])?\(?\d{3}\)?[-\s.]?\d{3}[-\s.]\d{4}/, // ex: (123) 456-7890, 123 456 7890, 123-456-7890, etc.
  114755. protocolRegex = /(?:[A-Za-z][-.+A-Za-z0-9]+:(?![A-Za-z][-.+A-Za-z0-9]+:\/\/)(?!\d+\/?)(?:\/\/)?)/, // match protocol, allow in format "http://" or "mailto:". However, do not match the first part of something like 'link:http://www.google.com' (i.e. don't match "link:"). Also, make sure we don't interpret 'google.com:8000' as if 'google.com' was a protocol here (i.e. ignore a trailing port number in this regex)
  114756. wwwRegex = /(?:www\.)/, // starting with 'www.'
  114757. domainNameRegex = /[A-Za-z0-9\.\-]*[A-Za-z0-9\-]/, // anything looking at all like a domain, non-unicode domains, not ending in a period
  114758. tldRegex = /\.(?:international|construction|contractors|enterprises|photography|productions|foundation|immobilien|industries|management|properties|technology|christmas|community|directory|education|equipment|institute|marketing|solutions|vacations|bargains|boutique|builders|catering|cleaning|clothing|computer|democrat|diamonds|graphics|holdings|lighting|partners|plumbing|supplies|training|ventures|academy|careers|company|cruises|domains|exposed|flights|florist|gallery|guitars|holiday|kitchen|neustar|okinawa|recipes|rentals|reviews|shiksha|singles|support|systems|agency|berlin|camera|center|coffee|condos|dating|estate|events|expert|futbol|kaufen|luxury|maison|monash|museum|nagoya|photos|repair|report|social|supply|tattoo|tienda|travel|viajes|villas|vision|voting|voyage|actor|build|cards|cheap|codes|dance|email|glass|house|mango|ninja|parts|photo|shoes|solar|today|tokyo|tools|watch|works|aero|arpa|asia|best|bike|blue|buzz|camp|club|cool|coop|farm|fish|gift|guru|info|jobs|kiwi|kred|land|limo|link|menu|mobi|moda|name|pics|pink|post|qpon|rich|ruhr|sexy|tips|vote|voto|wang|wien|wiki|zone|bar|bid|biz|cab|cat|ceo|com|edu|gov|int|kim|mil|net|onl|org|pro|pub|red|tel|uno|wed|xxx|xyz|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cw|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|za|zm|zw)\b/, // match our known top level domains (TLDs)
  114759. // Allow optional path, query string, and hash anchor, not ending in the following characters: "?!:,.;"
  114760. // http://blog.codinghorror.com/the-problem-with-urls/
  114761. urlSuffixRegex = /[\-A-Za-z0-9+&@#\/%=~_()|'$*\[\]?!:,.;]*[\-A-Za-z0-9+&@#\/%=~_()|'$*\[\]]/;
  114762. return new RegExp( [
  114763. '(', // *** Capturing group $1, which can be used to check for a twitter handle match. Use group $3 for the actual twitter handle though. $2 may be used to reconstruct the original string in a replace()
  114764. // *** Capturing group $2, which matches the whitespace character before the '@' sign (needed because of no lookbehinds), and
  114765. // *** Capturing group $3, which matches the actual twitter handle
  114766. twitterRegex.source,
  114767. ')',
  114768. '|',
  114769. '(', // *** Capturing group $4, which is used to determine an email match
  114770. emailRegex.source,
  114771. domainNameRegex.source,
  114772. tldRegex.source,
  114773. ')',
  114774. '|',
  114775. '(', // *** Capturing group $5, which is used to match a URL
  114776. '(?:', // parens to cover match for protocol (optional), and domain
  114777. '(', // *** Capturing group $6, for a protocol-prefixed url (ex: http://google.com)
  114778. protocolRegex.source,
  114779. domainNameRegex.source,
  114780. ')',
  114781. '|',
  114782. '(?:', // non-capturing paren for a 'www.' prefixed url (ex: www.google.com)
  114783. '(.?//)?', // *** Capturing group $7 for an optional protocol-relative URL. Must be at the beginning of the string or start with a non-word character
  114784. wwwRegex.source,
  114785. domainNameRegex.source,
  114786. ')',
  114787. '|',
  114788. '(?:', // non-capturing paren for known a TLD url (ex: google.com)
  114789. '(.?//)?', // *** Capturing group $8 for an optional protocol-relative URL. Must be at the beginning of the string or start with a non-word character
  114790. domainNameRegex.source,
  114791. tldRegex.source,
  114792. ')',
  114793. ')',
  114794. '(?:' + urlSuffixRegex.source + ')?', // match for path, query string, and/or hash anchor - optional
  114795. ')',
  114796. '|',
  114797. // this setup does not scale well for open extension :( Need to rethink design of autolinker...
  114798. // *** Capturing group $9, which matches a (USA for now) phone number
  114799. '(',
  114800. phoneRegex.source,
  114801. ')',
  114802. '|',
  114803. '(', // *** Capturing group $10, which can be used to check for a Hashtag match. Use group $12 for the actual Hashtag though. $11 may be used to reconstruct the original string in a replace()
  114804. // *** Capturing group $11, which matches the whitespace character before the '#' sign (needed because of no lookbehinds), and
  114805. // *** Capturing group $12, which matches the actual Hashtag
  114806. hashtagRegex.source,
  114807. ')'
  114808. ].join( "" ), 'gi' );
  114809. } )(),
  114810. /**
  114811. * @private
  114812. * @property {RegExp} charBeforeProtocolRelMatchRegex
  114813. *
  114814. * The regular expression used to retrieve the character before a
  114815. * protocol-relative URL match.
  114816. *
  114817. * This is used in conjunction with the {@link #matcherRegex}, which needs
  114818. * to grab the character before a protocol-relative '//' due to the lack of
  114819. * a negative look-behind in JavaScript regular expressions. The character
  114820. * before the match is stripped from the URL.
  114821. */
  114822. charBeforeProtocolRelMatchRegex : /^(.)?\/\//,
  114823. /**
  114824. * @private
  114825. * @property {Autolinker.MatchValidator} matchValidator
  114826. *
  114827. * The MatchValidator object, used to filter out any false positives from
  114828. * the {@link #matcherRegex}. See {@link Autolinker.MatchValidator} for details.
  114829. */
  114830. /**
  114831. * @constructor
  114832. * @param {Object} [cfg] The configuration options for the AnchorTagBuilder
  114833. * instance, specified in an Object (map).
  114834. */
  114835. constructor : function( cfg ) {
  114836. Autolinker.Util.assign( this, cfg );
  114837. this.matchValidator = new Autolinker.MatchValidator();
  114838. },
  114839. /**
  114840. * Parses the input `text` to search for matches, and calls the `replaceFn`
  114841. * to allow replacements of the matches. Returns the `text` with matches
  114842. * replaced.
  114843. *
  114844. * @param {String} text The text to search and repace matches in.
  114845. * @param {Function} replaceFn The iterator function to handle the
  114846. * replacements. The function takes a single argument, a {@link Autolinker.match.Match}
  114847. * object, and should return the text that should make the replacement.
  114848. * @param {Object} [contextObj=window] The context object ("scope") to run
  114849. * the `replaceFn` in.
  114850. * @return {String}
  114851. */
  114852. replace : function( text, replaceFn, contextObj ) {
  114853. var me = this; // for closure
  114854. return text.replace( this.matcherRegex, function( matchStr, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12 ) {
  114855. var matchDescObj = me.processCandidateMatch( matchStr, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12 ); // "match description" object
  114856. // Return out with no changes for match types that are disabled (url,
  114857. // email, phone, etc.), or for matches that are invalid (false
  114858. // positives from the matcherRegex, which can't use look-behinds
  114859. // since they are unavailable in JS).
  114860. if( !matchDescObj ) {
  114861. return matchStr;
  114862. } else {
  114863. // Generate replacement text for the match from the `replaceFn`
  114864. var replaceStr = replaceFn.call( contextObj, matchDescObj.match );
  114865. return matchDescObj.prefixStr + replaceStr + matchDescObj.suffixStr;
  114866. }
  114867. } );
  114868. },
  114869. /**
  114870. * Processes a candidate match from the {@link #matcherRegex}.
  114871. *
  114872. * Not all matches found by the regex are actual URL/Email/Phone/Twitter/Hashtag
  114873. * matches, as determined by the {@link #matchValidator}. In this case, the
  114874. * method returns `null`. Otherwise, a valid Object with `prefixStr`,
  114875. * `match`, and `suffixStr` is returned.
  114876. *
  114877. * @private
  114878. * @param {String} matchStr The full match that was found by the
  114879. * {@link #matcherRegex}.
  114880. * @param {String} twitterMatch The matched text of a Twitter handle, if the
  114881. * match is a Twitter match.
  114882. * @param {String} twitterHandlePrefixWhitespaceChar The whitespace char
  114883. * before the @ sign in a Twitter handle match. This is needed because of
  114884. * no lookbehinds in JS regexes, and is need to re-include the character
  114885. * for the anchor tag replacement.
  114886. * @param {String} twitterHandle The actual Twitter user (i.e the word after
  114887. * the @ sign in a Twitter match).
  114888. * @param {String} emailAddressMatch The matched email address for an email
  114889. * address match.
  114890. * @param {String} urlMatch The matched URL string for a URL match.
  114891. * @param {String} protocolUrlMatch The match URL string for a protocol
  114892. * match. Ex: 'http://yahoo.com'. This is used to match something like
  114893. * 'http://localhost', where we won't double check that the domain name
  114894. * has at least one '.' in it.
  114895. * @param {String} wwwProtocolRelativeMatch The '//' for a protocol-relative
  114896. * match from a 'www' url, with the character that comes before the '//'.
  114897. * @param {String} tldProtocolRelativeMatch The '//' for a protocol-relative
  114898. * match from a TLD (top level domain) match, with the character that
  114899. * comes before the '//'.
  114900. * @param {String} phoneMatch The matched text of a phone number
  114901. * @param {String} hashtagMatch The matched text of a Twitter
  114902. * Hashtag, if the match is a Hashtag match.
  114903. * @param {String} hashtagPrefixWhitespaceChar The whitespace char
  114904. * before the # sign in a Hashtag match. This is needed because of no
  114905. * lookbehinds in JS regexes, and is need to re-include the character for
  114906. * the anchor tag replacement.
  114907. * @param {String} hashtag The actual Hashtag (i.e the word
  114908. * after the # sign in a Hashtag match).
  114909. *
  114910. * @return {Object} A "match description object". This will be `null` if the
  114911. * match was invalid, or if a match type is disabled. Otherwise, this will
  114912. * be an Object (map) with the following properties:
  114913. * @return {String} return.prefixStr The char(s) that should be prepended to
  114914. * the replacement string. These are char(s) that were needed to be
  114915. * included from the regex match that were ignored by processing code, and
  114916. * should be re-inserted into the replacement stream.
  114917. * @return {String} return.suffixStr The char(s) that should be appended to
  114918. * the replacement string. These are char(s) that were needed to be
  114919. * included from the regex match that were ignored by processing code, and
  114920. * should be re-inserted into the replacement stream.
  114921. * @return {Autolinker.match.Match} return.match The Match object that
  114922. * represents the match that was found.
  114923. */
  114924. processCandidateMatch : function(
  114925. matchStr, twitterMatch, twitterHandlePrefixWhitespaceChar, twitterHandle,
  114926. emailAddressMatch, urlMatch, protocolUrlMatch, wwwProtocolRelativeMatch,
  114927. tldProtocolRelativeMatch, phoneMatch, hashtagMatch,
  114928. hashtagPrefixWhitespaceChar, hashtag
  114929. ) {
  114930. // Note: The `matchStr` variable wil be fixed up to remove characters that are no longer needed (which will
  114931. // be added to `prefixStr` and `suffixStr`).
  114932. var protocolRelativeMatch = wwwProtocolRelativeMatch || tldProtocolRelativeMatch,
  114933. match, // Will be an Autolinker.match.Match object
  114934. prefixStr = "", // A string to use to prefix the anchor tag that is created. This is needed for the Twitter and Hashtag matches.
  114935. suffixStr = ""; // A string to suffix the anchor tag that is created. This is used if there is a trailing parenthesis that should not be auto-linked.
  114936. // Return out with `null` for match types that are disabled (url, email,
  114937. // twitter, hashtag), or for matches that are invalid (false positives
  114938. // from the matcherRegex, which can't use look-behinds since they are
  114939. // unavailable in JS).
  114940. if(
  114941. ( urlMatch && !this.urls ) ||
  114942. ( emailAddressMatch && !this.email ) ||
  114943. ( phoneMatch && !this.phone ) ||
  114944. ( twitterMatch && !this.twitter ) ||
  114945. ( hashtagMatch && !this.hashtag ) ||
  114946. !this.matchValidator.isValidMatch( urlMatch, protocolUrlMatch, protocolRelativeMatch )
  114947. ) {
  114948. return null;
  114949. }
  114950. // Handle a closing parenthesis at the end of the match, and exclude it
  114951. // if there is not a matching open parenthesis
  114952. // in the match itself.
  114953. if( this.matchHasUnbalancedClosingParen( matchStr ) ) {
  114954. matchStr = matchStr.substr( 0, matchStr.length - 1 ); // remove the trailing ")"
  114955. suffixStr = ")"; // this will be added after the generated <a> tag
  114956. }
  114957. if( emailAddressMatch ) {
  114958. match = new Autolinker.match.Email( { matchedText: matchStr, email: emailAddressMatch } );
  114959. } else if( twitterMatch ) {
  114960. // fix up the `matchStr` if there was a preceding whitespace char,
  114961. // which was needed to determine the match itself (since there are
  114962. // no look-behinds in JS regexes)
  114963. if( twitterHandlePrefixWhitespaceChar ) {
  114964. prefixStr = twitterHandlePrefixWhitespaceChar;
  114965. matchStr = matchStr.slice( 1 ); // remove the prefixed whitespace char from the match
  114966. }
  114967. match = new Autolinker.match.Twitter( { matchedText: matchStr, twitterHandle: twitterHandle } );
  114968. } else if( phoneMatch ) {
  114969. // remove non-numeric values from phone number string
  114970. var cleanNumber = matchStr.replace( /\D/g, '' );
  114971. match = new Autolinker.match.Phone( { matchedText: matchStr, number: cleanNumber } );
  114972. } else if( hashtagMatch ) {
  114973. // fix up the `matchStr` if there was a preceding whitespace char,
  114974. // which was needed to determine the match itself (since there are
  114975. // no look-behinds in JS regexes)
  114976. if( hashtagPrefixWhitespaceChar ) {
  114977. prefixStr = hashtagPrefixWhitespaceChar;
  114978. matchStr = matchStr.slice( 1 ); // remove the prefixed whitespace char from the match
  114979. }
  114980. match = new Autolinker.match.Hashtag( { matchedText: matchStr, serviceName: this.hashtag, hashtag: hashtag } );
  114981. } else { // url match
  114982. // If it's a protocol-relative '//' match, remove the character
  114983. // before the '//' (which the matcherRegex needed to match due to
  114984. // the lack of a negative look-behind in JavaScript regular
  114985. // expressions)
  114986. if( protocolRelativeMatch ) {
  114987. var charBeforeMatch = protocolRelativeMatch.match( this.charBeforeProtocolRelMatchRegex )[ 1 ] || "";
  114988. if( charBeforeMatch ) { // fix up the `matchStr` if there was a preceding char before a protocol-relative match, which was needed to determine the match itself (since there are no look-behinds in JS regexes)
  114989. prefixStr = charBeforeMatch;
  114990. matchStr = matchStr.slice( 1 ); // remove the prefixed char from the match
  114991. }
  114992. }
  114993. match = new Autolinker.match.Url( {
  114994. matchedText : matchStr,
  114995. url : matchStr,
  114996. protocolUrlMatch : !!protocolUrlMatch,
  114997. protocolRelativeMatch : !!protocolRelativeMatch,
  114998. stripPrefix : this.stripPrefix
  114999. } );
  115000. }
  115001. return {
  115002. prefixStr : prefixStr,
  115003. suffixStr : suffixStr,
  115004. match : match
  115005. };
  115006. },
  115007. /**
  115008. * Determines if a match found has an unmatched closing parenthesis. If so,
  115009. * this parenthesis will be removed from the match itself, and appended
  115010. * after the generated anchor tag in {@link #processCandidateMatch}.
  115011. *
  115012. * A match may have an extra closing parenthesis at the end of the match
  115013. * because the regular expression must include parenthesis for URLs such as
  115014. * "wikipedia.com/something_(disambiguation)", which should be auto-linked.
  115015. *
  115016. * However, an extra parenthesis *will* be included when the URL itself is
  115017. * wrapped in parenthesis, such as in the case of "(wikipedia.com/something_(disambiguation))".
  115018. * In this case, the last closing parenthesis should *not* be part of the
  115019. * URL itself, and this method will return `true`.
  115020. *
  115021. * @private
  115022. * @param {String} matchStr The full match string from the {@link #matcherRegex}.
  115023. * @return {Boolean} `true` if there is an unbalanced closing parenthesis at
  115024. * the end of the `matchStr`, `false` otherwise.
  115025. */
  115026. matchHasUnbalancedClosingParen : function( matchStr ) {
  115027. var lastChar = matchStr.charAt( matchStr.length - 1 );
  115028. if( lastChar === ')' ) {
  115029. var openParensMatch = matchStr.match( /\(/g ),
  115030. closeParensMatch = matchStr.match( /\)/g ),
  115031. numOpenParens = ( openParensMatch && openParensMatch.length ) || 0,
  115032. numCloseParens = ( closeParensMatch && closeParensMatch.length ) || 0;
  115033. if( numOpenParens < numCloseParens ) {
  115034. return true;
  115035. }
  115036. }
  115037. return false;
  115038. }
  115039. } );
  115040. /*global Autolinker */
  115041. /*jshint scripturl:true */
  115042. /**
  115043. * @private
  115044. * @class Autolinker.MatchValidator
  115045. * @extends Object
  115046. *
  115047. * Used by Autolinker to filter out false positives from the
  115048. * {@link Autolinker.matchParser.MatchParser#matcherRegex}.
  115049. *
  115050. * Due to the limitations of regular expressions (including the missing feature
  115051. * of look-behinds in JS regular expressions), we cannot always determine the
  115052. * validity of a given match. This class applies a bit of additional logic to
  115053. * filter out any false positives that have been matched by the
  115054. * {@link Autolinker.matchParser.MatchParser#matcherRegex}.
  115055. */
  115056. Autolinker.MatchValidator = Autolinker.Util.extend( Object, {
  115057. /**
  115058. * @private
  115059. * @property {RegExp} invalidProtocolRelMatchRegex
  115060. *
  115061. * The regular expression used to check a potential protocol-relative URL
  115062. * match, coming from the {@link Autolinker.matchParser.MatchParser#matcherRegex}.
  115063. * A protocol-relative URL is, for example, "//yahoo.com"
  115064. *
  115065. * This regular expression checks to see if there is a word character before
  115066. * the '//' match in order to determine if we should actually autolink a
  115067. * protocol-relative URL. This is needed because there is no negative
  115068. * look-behind in JavaScript regular expressions.
  115069. *
  115070. * For instance, we want to autolink something like "Go to: //google.com",
  115071. * but we don't want to autolink something like "abc//google.com"
  115072. */
  115073. invalidProtocolRelMatchRegex : /^[\w]\/\//,
  115074. /**
  115075. * Regex to test for a full protocol, with the two trailing slashes. Ex: 'http://'
  115076. *
  115077. * @private
  115078. * @property {RegExp} hasFullProtocolRegex
  115079. */
  115080. hasFullProtocolRegex : /^[A-Za-z][-.+A-Za-z0-9]+:\/\//,
  115081. /**
  115082. * Regex to find the URI scheme, such as 'mailto:'.
  115083. *
  115084. * This is used to filter out 'javascript:' and 'vbscript:' schemes.
  115085. *
  115086. * @private
  115087. * @property {RegExp} uriSchemeRegex
  115088. */
  115089. uriSchemeRegex : /^[A-Za-z][-.+A-Za-z0-9]+:/,
  115090. /**
  115091. * Regex to determine if at least one word char exists after the protocol (i.e. after the ':')
  115092. *
  115093. * @private
  115094. * @property {RegExp} hasWordCharAfterProtocolRegex
  115095. */
  115096. hasWordCharAfterProtocolRegex : /:[^\s]*?[A-Za-z]/,
  115097. /**
  115098. * Determines if a given match found by the {@link Autolinker.matchParser.MatchParser}
  115099. * is valid. Will return `false` for:
  115100. *
  115101. * 1) URL matches which do not have at least have one period ('.') in the
  115102. * domain name (effectively skipping over matches like "abc:def").
  115103. * However, URL matches with a protocol will be allowed (ex: 'http://localhost')
  115104. * 2) URL matches which do not have at least one word character in the
  115105. * domain name (effectively skipping over matches like "git:1.0").
  115106. * 3) A protocol-relative url match (a URL beginning with '//') whose
  115107. * previous character is a word character (effectively skipping over
  115108. * strings like "abc//google.com")
  115109. *
  115110. * Otherwise, returns `true`.
  115111. *
  115112. * @param {String} urlMatch The matched URL, if there was one. Will be an
  115113. * empty string if the match is not a URL match.
  115114. * @param {String} protocolUrlMatch The match URL string for a protocol
  115115. * match. Ex: 'http://yahoo.com'. This is used to match something like
  115116. * 'http://localhost', where we won't double check that the domain name
  115117. * has at least one '.' in it.
  115118. * @param {String} protocolRelativeMatch The protocol-relative string for a
  115119. * URL match (i.e. '//'), possibly with a preceding character (ex, a
  115120. * space, such as: ' //', or a letter, such as: 'a//'). The match is
  115121. * invalid if there is a word character preceding the '//'.
  115122. * @return {Boolean} `true` if the match given is valid and should be
  115123. * processed, or `false` if the match is invalid and/or should just not be
  115124. * processed.
  115125. */
  115126. isValidMatch : function( urlMatch, protocolUrlMatch, protocolRelativeMatch ) {
  115127. if(
  115128. ( protocolUrlMatch && !this.isValidUriScheme( protocolUrlMatch ) ) ||
  115129. this.urlMatchDoesNotHaveProtocolOrDot( urlMatch, protocolUrlMatch ) || // At least one period ('.') must exist in the URL match for us to consider it an actual URL, *unless* it was a full protocol match (like 'http://localhost')
  115130. this.urlMatchDoesNotHaveAtLeastOneWordChar( urlMatch, protocolUrlMatch ) || // At least one letter character must exist in the domain name after a protocol match. Ex: skip over something like "git:1.0"
  115131. this.isInvalidProtocolRelativeMatch( protocolRelativeMatch ) // A protocol-relative match which has a word character in front of it (so we can skip something like "abc//google.com")
  115132. ) {
  115133. return false;
  115134. }
  115135. return true;
  115136. },
  115137. /**
  115138. * Determines if the URI scheme is a valid scheme to be autolinked. Returns
  115139. * `false` if the scheme is 'javascript:' or 'vbscript:'
  115140. *
  115141. * @private
  115142. * @param {String} uriSchemeMatch The match URL string for a full URI scheme
  115143. * match. Ex: 'http://yahoo.com' or 'mailto:a@a.com'.
  115144. * @return {Boolean} `true` if the scheme is a valid one, `false` otherwise.
  115145. */
  115146. isValidUriScheme : function( uriSchemeMatch ) {
  115147. var uriScheme = uriSchemeMatch.match( this.uriSchemeRegex )[ 0 ].toLowerCase();
  115148. return ( uriScheme !== 'javascript:' && uriScheme !== 'vbscript:' );
  115149. },
  115150. /**
  115151. * Determines if a URL match does not have either:
  115152. *
  115153. * a) a full protocol (i.e. 'http://'), or
  115154. * b) at least one dot ('.') in the domain name (for a non-full-protocol
  115155. * match).
  115156. *
  115157. * Either situation is considered an invalid URL (ex: 'git:d' does not have
  115158. * either the '://' part, or at least one dot in the domain name. If the
  115159. * match was 'git:abc.com', we would consider this valid.)
  115160. *
  115161. * @private
  115162. * @param {String} urlMatch The matched URL, if there was one. Will be an
  115163. * empty string if the match is not a URL match.
  115164. * @param {String} protocolUrlMatch The match URL string for a protocol
  115165. * match. Ex: 'http://yahoo.com'. This is used to match something like
  115166. * 'http://localhost', where we won't double check that the domain name
  115167. * has at least one '.' in it.
  115168. * @return {Boolean} `true` if the URL match does not have a full protocol,
  115169. * or at least one dot ('.') in a non-full-protocol match.
  115170. */
  115171. urlMatchDoesNotHaveProtocolOrDot : function( urlMatch, protocolUrlMatch ) {
  115172. return ( !!urlMatch && ( !protocolUrlMatch || !this.hasFullProtocolRegex.test( protocolUrlMatch ) ) && urlMatch.indexOf( '.' ) === -1 );
  115173. },
  115174. /**
  115175. * Determines if a URL match does not have at least one word character after
  115176. * the protocol (i.e. in the domain name).
  115177. *
  115178. * At least one letter character must exist in the domain name after a
  115179. * protocol match. Ex: skip over something like "git:1.0"
  115180. *
  115181. * @private
  115182. * @param {String} urlMatch The matched URL, if there was one. Will be an
  115183. * empty string if the match is not a URL match.
  115184. * @param {String} protocolUrlMatch The match URL string for a protocol
  115185. * match. Ex: 'http://yahoo.com'. This is used to know whether or not we
  115186. * have a protocol in the URL string, in order to check for a word
  115187. * character after the protocol separator (':').
  115188. * @return {Boolean} `true` if the URL match does not have at least one word
  115189. * character in it after the protocol, `false` otherwise.
  115190. */
  115191. urlMatchDoesNotHaveAtLeastOneWordChar : function( urlMatch, protocolUrlMatch ) {
  115192. if( urlMatch && protocolUrlMatch ) {
  115193. return !this.hasWordCharAfterProtocolRegex.test( urlMatch );
  115194. } else {
  115195. return false;
  115196. }
  115197. },
  115198. /**
  115199. * Determines if a protocol-relative match is an invalid one. This method
  115200. * returns `true` if there is a `protocolRelativeMatch`, and that match
  115201. * contains a word character before the '//' (i.e. it must contain
  115202. * whitespace or nothing before the '//' in order to be considered valid).
  115203. *
  115204. * @private
  115205. * @param {String} protocolRelativeMatch The protocol-relative string for a
  115206. * URL match (i.e. '//'), possibly with a preceding character (ex, a
  115207. * space, such as: ' //', or a letter, such as: 'a//'). The match is
  115208. * invalid if there is a word character preceding the '//'.
  115209. * @return {Boolean} `true` if it is an invalid protocol-relative match,
  115210. * `false` otherwise.
  115211. */
  115212. isInvalidProtocolRelativeMatch : function( protocolRelativeMatch ) {
  115213. return ( !!protocolRelativeMatch && this.invalidProtocolRelMatchRegex.test( protocolRelativeMatch ) );
  115214. }
  115215. } );
  115216. /*global Autolinker */
  115217. /**
  115218. * @abstract
  115219. * @class Autolinker.match.Match
  115220. *
  115221. * Represents a match found in an input string which should be Autolinked. A Match object is what is provided in a
  115222. * {@link Autolinker#replaceFn replaceFn}, and may be used to query for details about the match.
  115223. *
  115224. * For example:
  115225. *
  115226. * var input = "..."; // string with URLs, Email Addresses, and Twitter Handles
  115227. *
  115228. * var linkedText = Autolinker.link( input, {
  115229. * replaceFn : function( autolinker, match ) {
  115230. * console.log( "href = ", match.getAnchorHref() );
  115231. * console.log( "text = ", match.getAnchorText() );
  115232. *
  115233. * switch( match.getType() ) {
  115234. * case 'url' :
  115235. * console.log( "url: ", match.getUrl() );
  115236. *
  115237. * case 'email' :
  115238. * console.log( "email: ", match.getEmail() );
  115239. *
  115240. * case 'twitter' :
  115241. * console.log( "twitter: ", match.getTwitterHandle() );
  115242. * }
  115243. * }
  115244. * } );
  115245. *
  115246. * See the {@link Autolinker} class for more details on using the {@link Autolinker#replaceFn replaceFn}.
  115247. */
  115248. Autolinker.match.Match = Autolinker.Util.extend( Object, {
  115249. /**
  115250. * @cfg {String} matchedText (required)
  115251. *
  115252. * The original text that was matched.
  115253. */
  115254. /**
  115255. * @constructor
  115256. * @param {Object} cfg The configuration properties for the Match instance, specified in an Object (map).
  115257. */
  115258. constructor : function( cfg ) {
  115259. Autolinker.Util.assign( this, cfg );
  115260. },
  115261. /**
  115262. * Returns a string name for the type of match that this class represents.
  115263. *
  115264. * @abstract
  115265. * @return {String}
  115266. */
  115267. getType : Autolinker.Util.abstractMethod,
  115268. /**
  115269. * Returns the original text that was matched.
  115270. *
  115271. * @return {String}
  115272. */
  115273. getMatchedText : function() {
  115274. return this.matchedText;
  115275. },
  115276. /**
  115277. * Returns the anchor href that should be generated for the match.
  115278. *
  115279. * @abstract
  115280. * @return {String}
  115281. */
  115282. getAnchorHref : Autolinker.Util.abstractMethod,
  115283. /**
  115284. * Returns the anchor text that should be generated for the match.
  115285. *
  115286. * @abstract
  115287. * @return {String}
  115288. */
  115289. getAnchorText : Autolinker.Util.abstractMethod
  115290. } );
  115291. /*global Autolinker */
  115292. /**
  115293. * @class Autolinker.match.Email
  115294. * @extends Autolinker.match.Match
  115295. *
  115296. * Represents a Email match found in an input string which should be Autolinked.
  115297. *
  115298. * See this class's superclass ({@link Autolinker.match.Match}) for more details.
  115299. */
  115300. Autolinker.match.Email = Autolinker.Util.extend( Autolinker.match.Match, {
  115301. /**
  115302. * @cfg {String} email (required)
  115303. *
  115304. * The email address that was matched.
  115305. */
  115306. /**
  115307. * Returns a string name for the type of match that this class represents.
  115308. *
  115309. * @return {String}
  115310. */
  115311. getType : function() {
  115312. return 'email';
  115313. },
  115314. /**
  115315. * Returns the email address that was matched.
  115316. *
  115317. * @return {String}
  115318. */
  115319. getEmail : function() {
  115320. return this.email;
  115321. },
  115322. /**
  115323. * Returns the anchor href that should be generated for the match.
  115324. *
  115325. * @return {String}
  115326. */
  115327. getAnchorHref : function() {
  115328. return 'mailto:' + this.email;
  115329. },
  115330. /**
  115331. * Returns the anchor text that should be generated for the match.
  115332. *
  115333. * @return {String}
  115334. */
  115335. getAnchorText : function() {
  115336. return this.email;
  115337. }
  115338. } );
  115339. /*global Autolinker */
  115340. /**
  115341. * @class Autolinker.match.Hashtag
  115342. * @extends Autolinker.match.Match
  115343. *
  115344. * Represents a Hashtag match found in an input string which should be
  115345. * Autolinked.
  115346. *
  115347. * See this class's superclass ({@link Autolinker.match.Match}) for more
  115348. * details.
  115349. */
  115350. Autolinker.match.Hashtag = Autolinker.Util.extend( Autolinker.match.Match, {
  115351. /**
  115352. * @cfg {String} serviceName (required)
  115353. *
  115354. * The service to point hashtag matches to. See {@link Autolinker#hashtag}
  115355. * for available values.
  115356. */
  115357. /**
  115358. * @cfg {String} hashtag (required)
  115359. *
  115360. * The Hashtag that was matched, without the '#'.
  115361. */
  115362. /**
  115363. * Returns the type of match that this class represents.
  115364. *
  115365. * @return {String}
  115366. */
  115367. getType : function() {
  115368. return 'hashtag';
  115369. },
  115370. /**
  115371. * Returns the matched hashtag.
  115372. *
  115373. * @return {String}
  115374. */
  115375. getHashtag : function() {
  115376. return this.hashtag;
  115377. },
  115378. /**
  115379. * Returns the anchor href that should be generated for the match.
  115380. *
  115381. * @return {String}
  115382. */
  115383. getAnchorHref : function() {
  115384. var serviceName = this.serviceName,
  115385. hashtag = this.hashtag;
  115386. switch( serviceName ) {
  115387. case 'twitter' :
  115388. return 'https://twitter.com/hashtag/' + hashtag;
  115389. case 'facebook' :
  115390. return 'https://www.facebook.com/hashtag/' + hashtag;
  115391. default : // Shouldn't happen because Autolinker's constructor should block any invalid values, but just in case.
  115392. throw new Error( 'Unknown service name to point hashtag to: ', serviceName );
  115393. }
  115394. },
  115395. /**
  115396. * Returns the anchor text that should be generated for the match.
  115397. *
  115398. * @return {String}
  115399. */
  115400. getAnchorText : function() {
  115401. return '#' + this.hashtag;
  115402. }
  115403. } );
  115404. /*global Autolinker */
  115405. /**
  115406. * @class Autolinker.match.Phone
  115407. * @extends Autolinker.match.Match
  115408. *
  115409. * Represents a Phone number match found in an input string which should be
  115410. * Autolinked.
  115411. *
  115412. * See this class's superclass ({@link Autolinker.match.Match}) for more
  115413. * details.
  115414. */
  115415. Autolinker.match.Phone = Autolinker.Util.extend( Autolinker.match.Match, {
  115416. /**
  115417. * @cfg {String} number (required)
  115418. *
  115419. * The phone number that was matched.
  115420. */
  115421. /**
  115422. * Returns a string name for the type of match that this class represents.
  115423. *
  115424. * @return {String}
  115425. */
  115426. getType : function() {
  115427. return 'phone';
  115428. },
  115429. /**
  115430. * Returns the phone number that was matched.
  115431. *
  115432. * @return {String}
  115433. */
  115434. getNumber: function() {
  115435. return this.number;
  115436. },
  115437. /**
  115438. * Returns the anchor href that should be generated for the match.
  115439. *
  115440. * @return {String}
  115441. */
  115442. getAnchorHref : function() {
  115443. return 'tel:' + this.number;
  115444. },
  115445. /**
  115446. * Returns the anchor text that should be generated for the match.
  115447. *
  115448. * @return {String}
  115449. */
  115450. getAnchorText : function() {
  115451. return this.matchedText;
  115452. }
  115453. } );
  115454. /*global Autolinker */
  115455. /**
  115456. * @class Autolinker.match.Twitter
  115457. * @extends Autolinker.match.Match
  115458. *
  115459. * Represents a Twitter match found in an input string which should be Autolinked.
  115460. *
  115461. * See this class's superclass ({@link Autolinker.match.Match}) for more details.
  115462. */
  115463. Autolinker.match.Twitter = Autolinker.Util.extend( Autolinker.match.Match, {
  115464. /**
  115465. * @cfg {String} twitterHandle (required)
  115466. *
  115467. * The Twitter handle that was matched.
  115468. */
  115469. /**
  115470. * Returns the type of match that this class represents.
  115471. *
  115472. * @return {String}
  115473. */
  115474. getType : function() {
  115475. return 'twitter';
  115476. },
  115477. /**
  115478. * Returns a string name for the type of match that this class represents.
  115479. *
  115480. * @return {String}
  115481. */
  115482. getTwitterHandle : function() {
  115483. return this.twitterHandle;
  115484. },
  115485. /**
  115486. * Returns the anchor href that should be generated for the match.
  115487. *
  115488. * @return {String}
  115489. */
  115490. getAnchorHref : function() {
  115491. return 'https://twitter.com/' + this.twitterHandle;
  115492. },
  115493. /**
  115494. * Returns the anchor text that should be generated for the match.
  115495. *
  115496. * @return {String}
  115497. */
  115498. getAnchorText : function() {
  115499. return '@' + this.twitterHandle;
  115500. }
  115501. } );
  115502. /*global Autolinker */
  115503. /**
  115504. * @class Autolinker.match.Url
  115505. * @extends Autolinker.match.Match
  115506. *
  115507. * Represents a Url match found in an input string which should be Autolinked.
  115508. *
  115509. * See this class's superclass ({@link Autolinker.match.Match}) for more details.
  115510. */
  115511. Autolinker.match.Url = Autolinker.Util.extend( Autolinker.match.Match, {
  115512. /**
  115513. * @cfg {String} url (required)
  115514. *
  115515. * The url that was matched.
  115516. */
  115517. /**
  115518. * @cfg {Boolean} protocolUrlMatch (required)
  115519. *
  115520. * `true` if the URL is a match which already has a protocol (i.e. 'http://'), `false` if the match was from a 'www' or
  115521. * known TLD match.
  115522. */
  115523. /**
  115524. * @cfg {Boolean} protocolRelativeMatch (required)
  115525. *
  115526. * `true` if the URL is a protocol-relative match. A protocol-relative match is a URL that starts with '//',
  115527. * and will be either http:// or https:// based on the protocol that the site is loaded under.
  115528. */
  115529. /**
  115530. * @cfg {Boolean} stripPrefix (required)
  115531. * @inheritdoc Autolinker#stripPrefix
  115532. */
  115533. /**
  115534. * @private
  115535. * @property {RegExp} urlPrefixRegex
  115536. *
  115537. * A regular expression used to remove the 'http://' or 'https://' and/or the 'www.' from URLs.
  115538. */
  115539. urlPrefixRegex: /^(https?:\/\/)?(www\.)?/i,
  115540. /**
  115541. * @private
  115542. * @property {RegExp} protocolRelativeRegex
  115543. *
  115544. * The regular expression used to remove the protocol-relative '//' from the {@link #url} string, for purposes
  115545. * of {@link #getAnchorText}. A protocol-relative URL is, for example, "//yahoo.com"
  115546. */
  115547. protocolRelativeRegex : /^\/\//,
  115548. /**
  115549. * @private
  115550. * @property {Boolean} protocolPrepended
  115551. *
  115552. * Will be set to `true` if the 'http://' protocol has been prepended to the {@link #url} (because the
  115553. * {@link #url} did not have a protocol)
  115554. */
  115555. protocolPrepended : false,
  115556. /**
  115557. * Returns a string name for the type of match that this class represents.
  115558. *
  115559. * @return {String}
  115560. */
  115561. getType : function() {
  115562. return 'url';
  115563. },
  115564. /**
  115565. * Returns the url that was matched, assuming the protocol to be 'http://' if the original
  115566. * match was missing a protocol.
  115567. *
  115568. * @return {String}
  115569. */
  115570. getUrl : function() {
  115571. var url = this.url;
  115572. // if the url string doesn't begin with a protocol, assume 'http://'
  115573. if( !this.protocolRelativeMatch && !this.protocolUrlMatch && !this.protocolPrepended ) {
  115574. url = this.url = 'http://' + url;
  115575. this.protocolPrepended = true;
  115576. }
  115577. return url;
  115578. },
  115579. /**
  115580. * Returns the anchor href that should be generated for the match.
  115581. *
  115582. * @return {String}
  115583. */
  115584. getAnchorHref : function() {
  115585. var url = this.getUrl();
  115586. return url.replace( /&amp;/g, '&' ); // any &amp;'s in the URL should be converted back to '&' if they were displayed as &amp; in the source html
  115587. },
  115588. /**
  115589. * Returns the anchor text that should be generated for the match.
  115590. *
  115591. * @return {String}
  115592. */
  115593. getAnchorText : function() {
  115594. var anchorText = this.getUrl();
  115595. if( this.protocolRelativeMatch ) {
  115596. // Strip off any protocol-relative '//' from the anchor text
  115597. anchorText = this.stripProtocolRelativePrefix( anchorText );
  115598. }
  115599. if( this.stripPrefix ) {
  115600. anchorText = this.stripUrlPrefix( anchorText );
  115601. }
  115602. anchorText = this.removeTrailingSlash( anchorText ); // remove trailing slash, if there is one
  115603. return anchorText;
  115604. },
  115605. // ---------------------------------------
  115606. // Utility Functionality
  115607. /**
  115608. * Strips the URL prefix (such as "http://" or "https://") from the given text.
  115609. *
  115610. * @private
  115611. * @param {String} text The text of the anchor that is being generated, for which to strip off the
  115612. * url prefix (such as stripping off "http://")
  115613. * @return {String} The `anchorText`, with the prefix stripped.
  115614. */
  115615. stripUrlPrefix : function( text ) {
  115616. return text.replace( this.urlPrefixRegex, '' );
  115617. },
  115618. /**
  115619. * Strips any protocol-relative '//' from the anchor text.
  115620. *
  115621. * @private
  115622. * @param {String} text The text of the anchor that is being generated, for which to strip off the
  115623. * protocol-relative prefix (such as stripping off "//")
  115624. * @return {String} The `anchorText`, with the protocol-relative prefix stripped.
  115625. */
  115626. stripProtocolRelativePrefix : function( text ) {
  115627. return text.replace( this.protocolRelativeRegex, '' );
  115628. },
  115629. /**
  115630. * Removes any trailing slash from the given `anchorText`, in preparation for the text to be displayed.
  115631. *
  115632. * @private
  115633. * @param {String} anchorText The text of the anchor that is being generated, for which to remove any trailing
  115634. * slash ('/') that may exist.
  115635. * @return {String} The `anchorText`, with the trailing slash removed.
  115636. */
  115637. removeTrailingSlash : function( anchorText ) {
  115638. if( anchorText.charAt( anchorText.length - 1 ) === '/' ) {
  115639. anchorText = anchorText.slice( 0, -1 );
  115640. }
  115641. return anchorText;
  115642. }
  115643. } );
  115644. return Autolinker;
  115645. }));
  115646. /**
  115647. @license
  115648. Copyright (c) 2013 Gildas Lormeau. All rights reserved.
  115649. Redistribution and use in source and binary forms, with or without
  115650. modification, are permitted provided that the following conditions are met:
  115651. 1. Redistributions of source code must retain the above copyright notice,
  115652. this list of conditions and the following disclaimer.
  115653. 2. Redistributions in binary form must reproduce the above copyright
  115654. notice, this list of conditions and the following disclaimer in
  115655. the documentation and/or other materials provided with the distribution.
  115656. 3. The names of the authors may not be used to endorse or promote products
  115657. derived from this software without specific prior written permission.
  115658. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
  115659. INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  115660. FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
  115661. INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
  115662. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  115663. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  115664. OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  115665. LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  115666. NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  115667. EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  115668. **/
  115669. define('ThirdParty/zip',[
  115670. '../Core/buildModuleUrl',
  115671. '../Core/defineProperties'
  115672. ], function(
  115673. buildModuleUrl,
  115674. defineProperties) {
  115675. var tmp = {};
  115676. (function(obj) {
  115677. var ERR_BAD_FORMAT = "File format is not recognized.";
  115678. var ERR_ENCRYPTED = "File contains encrypted entry.";
  115679. var ERR_ZIP64 = "File is using Zip64 (4gb+ file size).";
  115680. var ERR_READ = "Error while reading zip file.";
  115681. var ERR_WRITE = "Error while writing zip file.";
  115682. var ERR_WRITE_DATA = "Error while writing file data.";
  115683. var ERR_READ_DATA = "Error while reading file data.";
  115684. var ERR_DUPLICATED_NAME = "File already exists.";
  115685. var CHUNK_SIZE = 512 * 1024;
  115686. var INFLATE_JS = "inflate.js";
  115687. var DEFLATE_JS = "deflate.js";
  115688. var TEXT_PLAIN = "text/plain";
  115689. var MESSAGE_EVENT = "message";
  115690. var appendABViewSupported;
  115691. try {
  115692. appendABViewSupported = new Blob([ new DataView(new ArrayBuffer(0)) ]).size === 0;
  115693. } catch (e) {
  115694. }
  115695. function Crc32() {
  115696. var crc = -1, that = this;
  115697. that.append = function(data) {
  115698. var offset, table = that.table;
  115699. for (offset = 0; offset < data.length; offset++)
  115700. crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF];
  115701. };
  115702. that.get = function() {
  115703. return ~crc;
  115704. };
  115705. }
  115706. Crc32.prototype.table = (function() {
  115707. var i, j, t, table = [];
  115708. for (i = 0; i < 256; i++) {
  115709. t = i;
  115710. for (j = 0; j < 8; j++)
  115711. if (t & 1)
  115712. t = (t >>> 1) ^ 0xEDB88320;
  115713. else
  115714. t = t >>> 1;
  115715. table[i] = t;
  115716. }
  115717. return table;
  115718. })();
  115719. function blobSlice(blob, index, length) {
  115720. if (blob.slice)
  115721. return blob.slice(index, index + length);
  115722. else if (blob.webkitSlice)
  115723. return blob.webkitSlice(index, index + length);
  115724. else if (blob.mozSlice)
  115725. return blob.mozSlice(index, index + length);
  115726. else if (blob.msSlice)
  115727. return blob.msSlice(index, index + length);
  115728. }
  115729. function getDataHelper(byteLength, bytes) {
  115730. var dataBuffer, dataArray;
  115731. dataBuffer = new ArrayBuffer(byteLength);
  115732. dataArray = new Uint8Array(dataBuffer);
  115733. if (bytes)
  115734. dataArray.set(bytes, 0);
  115735. return {
  115736. buffer : dataBuffer,
  115737. array : dataArray,
  115738. view : new DataView(dataBuffer)
  115739. };
  115740. }
  115741. // Readers
  115742. function Reader() {
  115743. }
  115744. function TextReader(text) {
  115745. var that = this, blobReader;
  115746. function init(callback, onerror) {
  115747. var blob = new Blob([ text ], {
  115748. type : TEXT_PLAIN
  115749. });
  115750. blobReader = new BlobReader(blob);
  115751. blobReader.init(function() {
  115752. that.size = blobReader.size;
  115753. callback();
  115754. }, onerror);
  115755. }
  115756. function readUint8Array(index, length, callback, onerror) {
  115757. blobReader.readUint8Array(index, length, callback, onerror);
  115758. }
  115759. that.size = 0;
  115760. that.init = init;
  115761. that.readUint8Array = readUint8Array;
  115762. }
  115763. TextReader.prototype = new Reader();
  115764. TextReader.prototype.constructor = TextReader;
  115765. function Data64URIReader(dataURI) {
  115766. var that = this, dataStart;
  115767. function init(callback) {
  115768. var dataEnd = dataURI.length;
  115769. while (dataURI.charAt(dataEnd - 1) == "=")
  115770. dataEnd--;
  115771. dataStart = dataURI.indexOf(",") + 1;
  115772. that.size = Math.floor((dataEnd - dataStart) * 0.75);
  115773. callback();
  115774. }
  115775. function readUint8Array(index, length, callback) {
  115776. var i, data = getDataHelper(length);
  115777. var start = Math.floor(index / 3) * 4;
  115778. var end = Math.ceil((index + length) / 3) * 4;
  115779. var bytes = window.atob(dataURI.substring(start + dataStart, end + dataStart));
  115780. var delta = index - Math.floor(start / 4) * 3;
  115781. for (i = delta; i < delta + length; i++)
  115782. data.array[i - delta] = bytes.charCodeAt(i);
  115783. callback(data.array);
  115784. }
  115785. that.size = 0;
  115786. that.init = init;
  115787. that.readUint8Array = readUint8Array;
  115788. }
  115789. Data64URIReader.prototype = new Reader();
  115790. Data64URIReader.prototype.constructor = Data64URIReader;
  115791. function BlobReader(blob) {
  115792. var that = this;
  115793. function init(callback) {
  115794. this.size = blob.size;
  115795. callback();
  115796. }
  115797. function readUint8Array(index, length, callback, onerror) {
  115798. var reader = new FileReader();
  115799. reader.onload = function(e) {
  115800. callback(new Uint8Array(e.target.result));
  115801. };
  115802. reader.onerror = onerror;
  115803. reader.readAsArrayBuffer(blobSlice(blob, index, length));
  115804. }
  115805. that.size = 0;
  115806. that.init = init;
  115807. that.readUint8Array = readUint8Array;
  115808. }
  115809. BlobReader.prototype = new Reader();
  115810. BlobReader.prototype.constructor = BlobReader;
  115811. // Writers
  115812. function Writer() {
  115813. }
  115814. Writer.prototype.getData = function(callback) {
  115815. callback(this.data);
  115816. };
  115817. function TextWriter(encoding) {
  115818. var that = this, blob;
  115819. function init(callback) {
  115820. blob = new Blob([], {
  115821. type : TEXT_PLAIN
  115822. });
  115823. callback();
  115824. }
  115825. function writeUint8Array(array, callback) {
  115826. blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
  115827. type : TEXT_PLAIN
  115828. });
  115829. callback();
  115830. }
  115831. function getData(callback, onerror) {
  115832. var reader = new FileReader();
  115833. reader.onload = function(e) {
  115834. callback(e.target.result);
  115835. };
  115836. reader.onerror = onerror;
  115837. reader.readAsText(blob, encoding);
  115838. }
  115839. that.init = init;
  115840. that.writeUint8Array = writeUint8Array;
  115841. that.getData = getData;
  115842. }
  115843. TextWriter.prototype = new Writer();
  115844. TextWriter.prototype.constructor = TextWriter;
  115845. function Data64URIWriter(contentType) {
  115846. var that = this, data = "", pending = "";
  115847. function init(callback) {
  115848. data += "data:" + (contentType || "") + ";base64,";
  115849. callback();
  115850. }
  115851. function writeUint8Array(array, callback) {
  115852. var i, delta = pending.length, dataString = pending;
  115853. pending = "";
  115854. for (i = 0; i < (Math.floor((delta + array.length) / 3) * 3) - delta; i++)
  115855. dataString += String.fromCharCode(array[i]);
  115856. for (; i < array.length; i++)
  115857. pending += String.fromCharCode(array[i]);
  115858. if (dataString.length > 2)
  115859. data += window.btoa(dataString);
  115860. else
  115861. pending = dataString;
  115862. callback();
  115863. }
  115864. function getData(callback) {
  115865. callback(data + window.btoa(pending));
  115866. }
  115867. that.init = init;
  115868. that.writeUint8Array = writeUint8Array;
  115869. that.getData = getData;
  115870. }
  115871. Data64URIWriter.prototype = new Writer();
  115872. Data64URIWriter.prototype.constructor = Data64URIWriter;
  115873. function BlobWriter(contentType) {
  115874. var blob, that = this;
  115875. function init(callback) {
  115876. blob = new Blob([], {
  115877. type : contentType
  115878. });
  115879. callback();
  115880. }
  115881. function writeUint8Array(array, callback) {
  115882. blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
  115883. type : contentType
  115884. });
  115885. callback();
  115886. }
  115887. function getData(callback) {
  115888. callback(blob);
  115889. }
  115890. that.init = init;
  115891. that.writeUint8Array = writeUint8Array;
  115892. that.getData = getData;
  115893. }
  115894. BlobWriter.prototype = new Writer();
  115895. BlobWriter.prototype.constructor = BlobWriter;
  115896. // inflate/deflate core functions
  115897. function launchWorkerProcess(worker, reader, writer, offset, size, onappend, onprogress, onend, onreaderror, onwriteerror) {
  115898. var chunkIndex = 0, index, outputSize;
  115899. function onflush() {
  115900. worker.removeEventListener(MESSAGE_EVENT, onmessage, false);
  115901. onend(outputSize);
  115902. }
  115903. function onmessage(event) {
  115904. var message = event.data, data = message.data;
  115905. if (message.onappend) {
  115906. outputSize += data.length;
  115907. writer.writeUint8Array(data, function() {
  115908. onappend(false, data);
  115909. step();
  115910. }, onwriteerror);
  115911. }
  115912. if (message.onflush)
  115913. if (data) {
  115914. outputSize += data.length;
  115915. writer.writeUint8Array(data, function() {
  115916. onappend(false, data);
  115917. onflush();
  115918. }, onwriteerror);
  115919. } else
  115920. onflush();
  115921. if (message.progress && onprogress)
  115922. onprogress(index + message.current, size);
  115923. }
  115924. function step() {
  115925. index = chunkIndex * CHUNK_SIZE;
  115926. if (index < size)
  115927. reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(array) {
  115928. worker.postMessage({
  115929. append : true,
  115930. data : array
  115931. });
  115932. chunkIndex++;
  115933. if (onprogress)
  115934. onprogress(index, size);
  115935. onappend(true, array);
  115936. }, onreaderror);
  115937. else
  115938. worker.postMessage({
  115939. flush : true
  115940. });
  115941. }
  115942. outputSize = 0;
  115943. worker.addEventListener(MESSAGE_EVENT, onmessage, false);
  115944. step();
  115945. }
  115946. function launchProcess(process, reader, writer, offset, size, onappend, onprogress, onend, onreaderror, onwriteerror) {
  115947. var chunkIndex = 0, index, outputSize = 0;
  115948. function step() {
  115949. var outputData;
  115950. index = chunkIndex * CHUNK_SIZE;
  115951. if (index < size)
  115952. reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(inputData) {
  115953. var outputData = process.append(inputData, function() {
  115954. if (onprogress)
  115955. onprogress(offset + index, size);
  115956. });
  115957. outputSize += outputData.length;
  115958. onappend(true, inputData);
  115959. writer.writeUint8Array(outputData, function() {
  115960. onappend(false, outputData);
  115961. chunkIndex++;
  115962. setTimeout(step, 1);
  115963. }, onwriteerror);
  115964. if (onprogress)
  115965. onprogress(index, size);
  115966. }, onreaderror);
  115967. else {
  115968. outputData = process.flush();
  115969. if (outputData) {
  115970. outputSize += outputData.length;
  115971. writer.writeUint8Array(outputData, function() {
  115972. onappend(false, outputData);
  115973. onend(outputSize);
  115974. }, onwriteerror);
  115975. } else
  115976. onend(outputSize);
  115977. }
  115978. }
  115979. step();
  115980. }
  115981. function inflate(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
  115982. var worker, crc32 = new Crc32();
  115983. function oninflateappend(sending, array) {
  115984. if (computeCrc32 && !sending)
  115985. crc32.append(array);
  115986. }
  115987. function oninflateend(outputSize) {
  115988. onend(outputSize, crc32.get());
  115989. }
  115990. if (obj.zip.useWebWorkers) {
  115991. worker = new Worker(obj.zip.workerScriptsPath + INFLATE_JS);
  115992. launchWorkerProcess(worker, reader, writer, offset, size, oninflateappend, onprogress, oninflateend, onreaderror, onwriteerror);
  115993. } else
  115994. launchProcess(new obj.zip.Inflater(), reader, writer, offset, size, oninflateappend, onprogress, oninflateend, onreaderror, onwriteerror);
  115995. return worker;
  115996. }
  115997. function deflate(reader, writer, level, onend, onprogress, onreaderror, onwriteerror) {
  115998. var worker, crc32 = new Crc32();
  115999. function ondeflateappend(sending, array) {
  116000. if (sending)
  116001. crc32.append(array);
  116002. }
  116003. function ondeflateend(outputSize) {
  116004. onend(outputSize, crc32.get());
  116005. }
  116006. function onmessage() {
  116007. worker.removeEventListener(MESSAGE_EVENT, onmessage, false);
  116008. launchWorkerProcess(worker, reader, writer, 0, reader.size, ondeflateappend, onprogress, ondeflateend, onreaderror, onwriteerror);
  116009. }
  116010. if (obj.zip.useWebWorkers) {
  116011. worker = new Worker(obj.zip.workerScriptsPath + DEFLATE_JS);
  116012. worker.addEventListener(MESSAGE_EVENT, onmessage, false);
  116013. worker.postMessage({
  116014. init : true,
  116015. level : level
  116016. });
  116017. } else
  116018. launchProcess(new obj.zip.Deflater(), reader, writer, 0, reader.size, ondeflateappend, onprogress, ondeflateend, onreaderror, onwriteerror);
  116019. return worker;
  116020. }
  116021. function copy(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
  116022. var chunkIndex = 0, crc32 = new Crc32();
  116023. function step() {
  116024. var index = chunkIndex * CHUNK_SIZE;
  116025. if (index < size)
  116026. reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(array) {
  116027. if (computeCrc32)
  116028. crc32.append(array);
  116029. if (onprogress)
  116030. onprogress(index, size, array);
  116031. writer.writeUint8Array(array, function() {
  116032. chunkIndex++;
  116033. step();
  116034. }, onwriteerror);
  116035. }, onreaderror);
  116036. else
  116037. onend(size, crc32.get());
  116038. }
  116039. step();
  116040. }
  116041. // ZipReader
  116042. function decodeASCII(str) {
  116043. var i, out = "", charCode, extendedASCII = [ '\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB',
  116044. '\u00E8', '\u00EF', '\u00EE', '\u00EC', '\u00C4', '\u00C5', '\u00C9', '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9',
  116045. '\u00FF', '\u00D6', '\u00DC', '\u00F8', '\u00A3', '\u00D8', '\u00D7', '\u0192', '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1',
  116046. '\u00AA', '\u00BA', '\u00BF', '\u00AE', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB', '\u00BB', '_', '_', '_', '\u00A6', '\u00A6',
  116047. '\u00C1', '\u00C2', '\u00C0', '\u00A9', '\u00A6', '\u00A6', '+', '+', '\u00A2', '\u00A5', '+', '+', '-', '-', '+', '-', '+', '\u00E3',
  116048. '\u00C3', '+', '+', '-', '-', '\u00A6', '-', '+', '\u00A4', '\u00F0', '\u00D0', '\u00CA', '\u00CB', '\u00C8', 'i', '\u00CD', '\u00CE',
  116049. '\u00CF', '+', '+', '_', '_', '\u00A6', '\u00CC', '_', '\u00D3', '\u00DF', '\u00D4', '\u00D2', '\u00F5', '\u00D5', '\u00B5', '\u00FE',
  116050. '\u00DE', '\u00DA', '\u00DB', '\u00D9', '\u00FD', '\u00DD', '\u00AF', '\u00B4', '\u00AD', '\u00B1', '_', '\u00BE', '\u00B6', '\u00A7',
  116051. '\u00F7', '\u00B8', '\u00B0', '\u00A8', '\u00B7', '\u00B9', '\u00B3', '\u00B2', '_', ' ' ];
  116052. for (i = 0; i < str.length; i++) {
  116053. charCode = str.charCodeAt(i) & 0xFF;
  116054. if (charCode > 127)
  116055. out += extendedASCII[charCode - 128];
  116056. else
  116057. out += String.fromCharCode(charCode);
  116058. }
  116059. return out;
  116060. }
  116061. function decodeUTF8(string) {
  116062. return decodeURIComponent(escape(string));
  116063. }
  116064. function getString(bytes) {
  116065. var i, str = "";
  116066. for (i = 0; i < bytes.length; i++)
  116067. str += String.fromCharCode(bytes[i]);
  116068. return str;
  116069. }
  116070. function getDate(timeRaw) {
  116071. var date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & 0x0000ffff;
  116072. try {
  116073. return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5,
  116074. (time & 0x001F) * 2, 0);
  116075. } catch (e) {
  116076. }
  116077. }
  116078. function readCommonHeader(entry, data, index, centralDirectory, onerror) {
  116079. entry.version = data.view.getUint16(index, true);
  116080. entry.bitFlag = data.view.getUint16(index + 2, true);
  116081. entry.compressionMethod = data.view.getUint16(index + 4, true);
  116082. entry.lastModDateRaw = data.view.getUint32(index + 6, true);
  116083. entry.lastModDate = getDate(entry.lastModDateRaw);
  116084. if ((entry.bitFlag & 0x01) === 0x01) {
  116085. onerror(ERR_ENCRYPTED);
  116086. return;
  116087. }
  116088. if (centralDirectory || (entry.bitFlag & 0x0008) != 0x0008) {
  116089. entry.crc32 = data.view.getUint32(index + 10, true);
  116090. entry.compressedSize = data.view.getUint32(index + 14, true);
  116091. entry.uncompressedSize = data.view.getUint32(index + 18, true);
  116092. }
  116093. if (entry.compressedSize === 0xFFFFFFFF || entry.uncompressedSize === 0xFFFFFFFF) {
  116094. onerror(ERR_ZIP64);
  116095. return;
  116096. }
  116097. entry.filenameLength = data.view.getUint16(index + 22, true);
  116098. entry.extraFieldLength = data.view.getUint16(index + 24, true);
  116099. }
  116100. function createZipReader(reader, onerror) {
  116101. function Entry() {
  116102. }
  116103. Entry.prototype.getData = function(writer, onend, onprogress, checkCrc32) {
  116104. var that = this, worker;
  116105. function terminate(callback, param) {
  116106. if (worker)
  116107. worker.terminate();
  116108. worker = null;
  116109. if (callback)
  116110. callback(param);
  116111. }
  116112. function testCrc32(crc32) {
  116113. var dataCrc32 = getDataHelper(4);
  116114. dataCrc32.view.setUint32(0, crc32);
  116115. return that.crc32 == dataCrc32.view.getUint32(0);
  116116. }
  116117. function getWriterData(uncompressedSize, crc32) {
  116118. if (checkCrc32 && !testCrc32(crc32))
  116119. onreaderror();
  116120. else
  116121. writer.getData(function(data) {
  116122. terminate(onend, data);
  116123. });
  116124. }
  116125. function onreaderror() {
  116126. terminate(onerror, ERR_READ_DATA);
  116127. }
  116128. function onwriteerror() {
  116129. terminate(onerror, ERR_WRITE_DATA);
  116130. }
  116131. reader.readUint8Array(that.offset, 30, function(bytes) {
  116132. var data = getDataHelper(bytes.length, bytes), dataOffset;
  116133. if (data.view.getUint32(0) != 0x504b0304) {
  116134. onerror(ERR_BAD_FORMAT);
  116135. return;
  116136. }
  116137. readCommonHeader(that, data, 4, false, onerror);
  116138. dataOffset = that.offset + 30 + that.filenameLength + that.extraFieldLength;
  116139. writer.init(function() {
  116140. if (that.compressionMethod === 0)
  116141. copy(reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
  116142. else
  116143. worker = inflate(reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
  116144. }, onwriteerror);
  116145. }, onreaderror);
  116146. };
  116147. function seekEOCDR(offset, entriesCallback) {
  116148. reader.readUint8Array(reader.size - offset, offset, function(bytes) {
  116149. var dataView = getDataHelper(bytes.length, bytes).view;
  116150. if (dataView.getUint32(0) != 0x504b0506) {
  116151. seekEOCDR(offset + 1, entriesCallback);
  116152. } else {
  116153. entriesCallback(dataView);
  116154. }
  116155. }, function() {
  116156. onerror(ERR_READ);
  116157. });
  116158. }
  116159. return {
  116160. getEntries : function(callback) {
  116161. if (reader.size < 22) {
  116162. onerror(ERR_BAD_FORMAT);
  116163. return;
  116164. }
  116165. // look for End of central directory record
  116166. seekEOCDR(22, function(dataView) {
  116167. var datalength, fileslength;
  116168. datalength = dataView.getUint32(16, true);
  116169. fileslength = dataView.getUint16(8, true);
  116170. reader.readUint8Array(datalength, reader.size - datalength, function(bytes) {
  116171. var i, index = 0, entries = [], entry, filename, comment, data = getDataHelper(bytes.length, bytes);
  116172. for (i = 0; i < fileslength; i++) {
  116173. entry = new Entry();
  116174. if (data.view.getUint32(index) != 0x504b0102) {
  116175. onerror(ERR_BAD_FORMAT);
  116176. return;
  116177. }
  116178. readCommonHeader(entry, data, index + 6, true, onerror);
  116179. entry.commentLength = data.view.getUint16(index + 32, true);
  116180. entry.directory = ((data.view.getUint8(index + 38) & 0x10) == 0x10);
  116181. entry.offset = data.view.getUint32(index + 42, true);
  116182. filename = getString(data.array.subarray(index + 46, index + 46 + entry.filenameLength));
  116183. entry.filename = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(filename) : decodeASCII(filename);
  116184. if (!entry.directory && entry.filename.charAt(entry.filename.length - 1) == "/")
  116185. entry.directory = true;
  116186. comment = getString(data.array.subarray(index + 46 + entry.filenameLength + entry.extraFieldLength, index + 46
  116187. + entry.filenameLength + entry.extraFieldLength + entry.commentLength));
  116188. entry.comment = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(comment) : decodeASCII(comment);
  116189. entries.push(entry);
  116190. index += 46 + entry.filenameLength + entry.extraFieldLength + entry.commentLength;
  116191. }
  116192. callback(entries);
  116193. }, function() {
  116194. onerror(ERR_READ);
  116195. });
  116196. });
  116197. },
  116198. close : function(callback) {
  116199. if (callback)
  116200. callback();
  116201. }
  116202. };
  116203. }
  116204. // ZipWriter
  116205. function encodeUTF8(string) {
  116206. return unescape(encodeURIComponent(string));
  116207. }
  116208. function getBytes(str) {
  116209. var i, array = [];
  116210. for (i = 0; i < str.length; i++)
  116211. array.push(str.charCodeAt(i));
  116212. return array;
  116213. }
  116214. function createZipWriter(writer, onerror, dontDeflate) {
  116215. var worker, files = {}, filenames = [], datalength = 0;
  116216. function terminate(callback, message) {
  116217. if (worker)
  116218. worker.terminate();
  116219. worker = null;
  116220. if (callback)
  116221. callback(message);
  116222. }
  116223. function onwriteerror() {
  116224. terminate(onerror, ERR_WRITE);
  116225. }
  116226. function onreaderror() {
  116227. terminate(onerror, ERR_READ_DATA);
  116228. }
  116229. return {
  116230. add : function(name, reader, onend, onprogress, options) {
  116231. var header, filename, date;
  116232. function writeHeader(callback) {
  116233. var data;
  116234. date = options.lastModDate || new Date();
  116235. header = getDataHelper(26);
  116236. files[name] = {
  116237. headerArray : header.array,
  116238. directory : options.directory,
  116239. filename : filename,
  116240. offset : datalength,
  116241. comment : getBytes(encodeUTF8(options.comment || ""))
  116242. };
  116243. header.view.setUint32(0, 0x14000808);
  116244. if (options.version)
  116245. header.view.setUint8(0, options.version);
  116246. if (!dontDeflate && options.level !== 0 && !options.directory)
  116247. header.view.setUint16(4, 0x0800);
  116248. header.view.setUint16(6, (((date.getHours() << 6) | date.getMinutes()) << 5) | date.getSeconds() / 2, true);
  116249. header.view.setUint16(8, ((((date.getFullYear() - 1980) << 4) | (date.getMonth() + 1)) << 5) | date.getDate(), true);
  116250. header.view.setUint16(22, filename.length, true);
  116251. data = getDataHelper(30 + filename.length);
  116252. data.view.setUint32(0, 0x504b0304);
  116253. data.array.set(header.array, 4);
  116254. data.array.set(filename, 30);
  116255. datalength += data.array.length;
  116256. writer.writeUint8Array(data.array, callback, onwriteerror);
  116257. }
  116258. function writeFooter(compressedLength, crc32) {
  116259. var footer = getDataHelper(16);
  116260. datalength += compressedLength || 0;
  116261. footer.view.setUint32(0, 0x504b0708);
  116262. if (typeof crc32 != "undefined") {
  116263. header.view.setUint32(10, crc32, true);
  116264. footer.view.setUint32(4, crc32, true);
  116265. }
  116266. if (reader) {
  116267. footer.view.setUint32(8, compressedLength, true);
  116268. header.view.setUint32(14, compressedLength, true);
  116269. footer.view.setUint32(12, reader.size, true);
  116270. header.view.setUint32(18, reader.size, true);
  116271. }
  116272. writer.writeUint8Array(footer.array, function() {
  116273. datalength += 16;
  116274. terminate(onend);
  116275. }, onwriteerror);
  116276. }
  116277. function writeFile() {
  116278. options = options || {};
  116279. name = name.trim();
  116280. if (options.directory && name.charAt(name.length - 1) != "/")
  116281. name += "/";
  116282. if (files.hasOwnProperty(name)) {
  116283. onerror(ERR_DUPLICATED_NAME);
  116284. return;
  116285. }
  116286. filename = getBytes(encodeUTF8(name));
  116287. filenames.push(name);
  116288. writeHeader(function() {
  116289. if (reader)
  116290. if (dontDeflate || options.level === 0)
  116291. copy(reader, writer, 0, reader.size, true, writeFooter, onprogress, onreaderror, onwriteerror);
  116292. else
  116293. worker = deflate(reader, writer, options.level, writeFooter, onprogress, onreaderror, onwriteerror);
  116294. else
  116295. writeFooter();
  116296. }, onwriteerror);
  116297. }
  116298. if (reader)
  116299. reader.init(writeFile, onreaderror);
  116300. else
  116301. writeFile();
  116302. },
  116303. close : function(callback) {
  116304. var data, length = 0, index = 0, indexFilename, file;
  116305. for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) {
  116306. file = files[filenames[indexFilename]];
  116307. length += 46 + file.filename.length + file.comment.length;
  116308. }
  116309. data = getDataHelper(length + 22);
  116310. for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) {
  116311. file = files[filenames[indexFilename]];
  116312. data.view.setUint32(index, 0x504b0102);
  116313. data.view.setUint16(index + 4, 0x1400);
  116314. data.array.set(file.headerArray, index + 6);
  116315. data.view.setUint16(index + 32, file.comment.length, true);
  116316. if (file.directory)
  116317. data.view.setUint8(index + 38, 0x10);
  116318. data.view.setUint32(index + 42, file.offset, true);
  116319. data.array.set(file.filename, index + 46);
  116320. data.array.set(file.comment, index + 46 + file.filename.length);
  116321. index += 46 + file.filename.length + file.comment.length;
  116322. }
  116323. data.view.setUint32(index, 0x504b0506);
  116324. data.view.setUint16(index + 8, filenames.length, true);
  116325. data.view.setUint16(index + 10, filenames.length, true);
  116326. data.view.setUint32(index + 12, length, true);
  116327. data.view.setUint32(index + 16, datalength, true);
  116328. writer.writeUint8Array(data.array, function() {
  116329. terminate(function() {
  116330. writer.getData(callback);
  116331. });
  116332. }, onwriteerror);
  116333. }
  116334. };
  116335. }
  116336. obj.zip = {
  116337. Reader : Reader,
  116338. Writer : Writer,
  116339. BlobReader : BlobReader,
  116340. Data64URIReader : Data64URIReader,
  116341. TextReader : TextReader,
  116342. BlobWriter : BlobWriter,
  116343. Data64URIWriter : Data64URIWriter,
  116344. TextWriter : TextWriter,
  116345. createReader : function(reader, callback, onerror) {
  116346. reader.init(function() {
  116347. callback(createZipReader(reader, onerror));
  116348. }, onerror);
  116349. },
  116350. createWriter : function(writer, callback, onerror, dontDeflate) {
  116351. writer.init(function() {
  116352. callback(createZipWriter(writer, onerror, dontDeflate));
  116353. }, onerror);
  116354. },
  116355. useWebWorkers : true
  116356. };
  116357. var workerScriptsPath;
  116358. defineProperties(obj.zip, {
  116359. 'workerScriptsPath' : {
  116360. get : function() {
  116361. if (typeof workerScriptsPath === 'undefined') {
  116362. workerScriptsPath = buildModuleUrl('ThirdParty/Workers/');
  116363. }
  116364. return workerScriptsPath;
  116365. }
  116366. }
  116367. });
  116368. })(tmp);
  116369. return tmp.zip;
  116370. });
  116371. /*global define*/
  116372. define('DataSources/KmlDataSource',[
  116373. '../Core/AssociativeArray',
  116374. '../Core/BoundingRectangle',
  116375. '../Core/Cartesian2',
  116376. '../Core/Cartesian3',
  116377. '../Core/Cartographic',
  116378. '../Core/ClockRange',
  116379. '../Core/ClockStep',
  116380. '../Core/Color',
  116381. '../Core/createGuid',
  116382. '../Core/defaultValue',
  116383. '../Core/defined',
  116384. '../Core/defineProperties',
  116385. '../Core/DeveloperError',
  116386. '../Core/Ellipsoid',
  116387. '../Core/Event',
  116388. '../Core/getAbsoluteUri',
  116389. '../Core/getExtensionFromUri',
  116390. '../Core/getFilenameFromUri',
  116391. '../Core/Iso8601',
  116392. '../Core/joinUrls',
  116393. '../Core/JulianDate',
  116394. '../Core/loadBlob',
  116395. '../Core/loadXML',
  116396. '../Core/Math',
  116397. '../Core/NearFarScalar',
  116398. '../Core/PinBuilder',
  116399. '../Core/PolygonHierarchy',
  116400. '../Core/Rectangle',
  116401. '../Core/RuntimeError',
  116402. '../Core/TimeInterval',
  116403. '../Core/TimeIntervalCollection',
  116404. '../Scene/HeightReference',
  116405. '../Scene/HorizontalOrigin',
  116406. '../Scene/LabelStyle',
  116407. '../Scene/SceneMode',
  116408. '../ThirdParty/Autolinker',
  116409. '../ThirdParty/Uri',
  116410. '../ThirdParty/when',
  116411. '../ThirdParty/zip',
  116412. './BillboardGraphics',
  116413. './CompositePositionProperty',
  116414. './CorridorGraphics',
  116415. './DataSource',
  116416. './DataSourceClock',
  116417. './Entity',
  116418. './EntityCluster',
  116419. './EntityCollection',
  116420. './LabelGraphics',
  116421. './PathGraphics',
  116422. './PolygonGraphics',
  116423. './PolylineGraphics',
  116424. './PositionPropertyArray',
  116425. './RectangleGraphics',
  116426. './ReferenceProperty',
  116427. './SampledPositionProperty',
  116428. './ScaledPositionProperty',
  116429. './TimeIntervalCollectionProperty',
  116430. './WallGraphics'
  116431. ], function(
  116432. AssociativeArray,
  116433. BoundingRectangle,
  116434. Cartesian2,
  116435. Cartesian3,
  116436. Cartographic,
  116437. ClockRange,
  116438. ClockStep,
  116439. Color,
  116440. createGuid,
  116441. defaultValue,
  116442. defined,
  116443. defineProperties,
  116444. DeveloperError,
  116445. Ellipsoid,
  116446. Event,
  116447. getAbsoluteUri,
  116448. getExtensionFromUri,
  116449. getFilenameFromUri,
  116450. Iso8601,
  116451. joinUrls,
  116452. JulianDate,
  116453. loadBlob,
  116454. loadXML,
  116455. CesiumMath,
  116456. NearFarScalar,
  116457. PinBuilder,
  116458. PolygonHierarchy,
  116459. Rectangle,
  116460. RuntimeError,
  116461. TimeInterval,
  116462. TimeIntervalCollection,
  116463. HeightReference,
  116464. HorizontalOrigin,
  116465. LabelStyle,
  116466. SceneMode,
  116467. Autolinker,
  116468. Uri,
  116469. when,
  116470. zip,
  116471. BillboardGraphics,
  116472. CompositePositionProperty,
  116473. CorridorGraphics,
  116474. DataSource,
  116475. DataSourceClock,
  116476. Entity,
  116477. EntityCluster,
  116478. EntityCollection,
  116479. LabelGraphics,
  116480. PathGraphics,
  116481. PolygonGraphics,
  116482. PolylineGraphics,
  116483. PositionPropertyArray,
  116484. RectangleGraphics,
  116485. ReferenceProperty,
  116486. SampledPositionProperty,
  116487. ScaledPositionProperty,
  116488. TimeIntervalCollectionProperty,
  116489. WallGraphics) {
  116490. 'use strict';
  116491. // IE 8 doesn't have a DOM parser and can't run Cesium anyway, so just bail.
  116492. if (typeof DOMParser === 'undefined') {
  116493. return {};
  116494. }
  116495. //This is by no means an exhaustive list of MIME types.
  116496. //The purpose of this list is to be able to accurately identify content embedded
  116497. //in KMZ files. Eventually, we can make this configurable by the end user so they can add
  116498. //there own content types if they have KMZ files that require it.
  116499. var MimeTypes = {
  116500. avi : "video/x-msvideo",
  116501. bmp : "image/bmp",
  116502. bz2 : "application/x-bzip2",
  116503. chm : "application/vnd.ms-htmlhelp",
  116504. css : "text/css",
  116505. csv : "text/csv",
  116506. doc : "application/msword",
  116507. dvi : "application/x-dvi",
  116508. eps : "application/postscript",
  116509. flv : "video/x-flv",
  116510. gif : "image/gif",
  116511. gz : "application/x-gzip",
  116512. htm : "text/html",
  116513. html : "text/html",
  116514. ico : "image/vnd.microsoft.icon",
  116515. jnlp : "application/x-java-jnlp-file",
  116516. jpeg : "image/jpeg",
  116517. jpg : "image/jpeg",
  116518. m3u : "audio/x-mpegurl",
  116519. m4v : "video/mp4",
  116520. mathml : "application/mathml+xml",
  116521. mid : "audio/midi",
  116522. midi : "audio/midi",
  116523. mov : "video/quicktime",
  116524. mp3 : "audio/mpeg",
  116525. mp4 : "video/mp4",
  116526. mp4v : "video/mp4",
  116527. mpeg : "video/mpeg",
  116528. mpg : "video/mpeg",
  116529. odp : "application/vnd.oasis.opendocument.presentation",
  116530. ods : "application/vnd.oasis.opendocument.spreadsheet",
  116531. odt : "application/vnd.oasis.opendocument.text",
  116532. ogg : "application/ogg",
  116533. pdf : "application/pdf",
  116534. png : "image/png",
  116535. pps : "application/vnd.ms-powerpoint",
  116536. ppt : "application/vnd.ms-powerpoint",
  116537. ps : "application/postscript",
  116538. qt : "video/quicktime",
  116539. rdf : "application/rdf+xml",
  116540. rss : "application/rss+xml",
  116541. rtf : "application/rtf",
  116542. svg : "image/svg+xml",
  116543. swf : "application/x-shockwave-flash",
  116544. text : "text/plain",
  116545. tif : "image/tiff",
  116546. tiff : "image/tiff",
  116547. txt : "text/plain",
  116548. wav : "audio/x-wav",
  116549. wma : "audio/x-ms-wma",
  116550. wmv : "video/x-ms-wmv",
  116551. xml : "application/xml",
  116552. zip : "application/zip",
  116553. detectFromFilename : function(filename) {
  116554. var ext = filename.toLowerCase();
  116555. ext = getExtensionFromUri(ext);
  116556. return MimeTypes[ext];
  116557. }
  116558. };
  116559. var parser = new DOMParser();
  116560. var autolinker = new Autolinker({
  116561. stripPrefix : false,
  116562. twitter : false,
  116563. email : false,
  116564. replaceFn : function(linker, match) {
  116565. if (!match.protocolUrlMatch) {
  116566. //Prevent matching of non-explicit urls.
  116567. //i.e. foo.id won't match but http://foo.id will
  116568. return false;
  116569. }
  116570. }
  116571. });
  116572. var BILLBOARD_SIZE = 32;
  116573. var BILLBOARD_NEAR_DISTANCE = 2414016;
  116574. var BILLBOARD_NEAR_RATIO = 1.0;
  116575. var BILLBOARD_FAR_DISTANCE = 1.6093e+7;
  116576. var BILLBOARD_FAR_RATIO = 0.1;
  116577. function isZipFile(blob) {
  116578. var magicBlob = blob.slice(0, Math.min(4, blob.size));
  116579. var deferred = when.defer();
  116580. var reader = new FileReader();
  116581. reader.addEventListener('load', function() {
  116582. deferred.resolve(new DataView(reader.result).getUint32(0, false) === 0x504b0304);
  116583. });
  116584. reader.addEventListener('error', function() {
  116585. deferred.reject(reader.error);
  116586. });
  116587. reader.readAsArrayBuffer(magicBlob);
  116588. return deferred.promise;
  116589. }
  116590. function readBlobAsText(blob) {
  116591. var deferred = when.defer();
  116592. var reader = new FileReader();
  116593. reader.addEventListener('load', function() {
  116594. deferred.resolve(reader.result);
  116595. });
  116596. reader.addEventListener('error', function() {
  116597. deferred.reject(reader.error);
  116598. });
  116599. reader.readAsText(blob);
  116600. return deferred.promise;
  116601. }
  116602. function loadXmlFromZip(reader, entry, uriResolver, deferred) {
  116603. entry.getData(new zip.TextWriter(), function(text) {
  116604. uriResolver.kml = parser.parseFromString(text, 'application/xml');
  116605. deferred.resolve();
  116606. });
  116607. }
  116608. function loadDataUriFromZip(reader, entry, uriResolver, deferred) {
  116609. var mimeType = defaultValue(MimeTypes.detectFromFilename(entry.filename), 'application/octet-stream');
  116610. entry.getData(new zip.Data64URIWriter(mimeType), function(dataUri) {
  116611. uriResolver[entry.filename] = dataUri;
  116612. deferred.resolve();
  116613. });
  116614. }
  116615. function replaceAttributes(div, elementType, attributeName, uriResolver) {
  116616. var keys = uriResolver.keys;
  116617. var baseUri = new Uri('.');
  116618. var elements = div.querySelectorAll(elementType);
  116619. for (var i = 0; i < elements.length; i++) {
  116620. var element = elements[i];
  116621. var value = element.getAttribute(attributeName);
  116622. var uri = new Uri(value).resolve(baseUri).toString();
  116623. var index = keys.indexOf(uri);
  116624. if (index !== -1) {
  116625. var key = keys[index];
  116626. element.setAttribute(attributeName, uriResolver[key]);
  116627. if (elementType === 'a' && element.getAttribute('download') === null) {
  116628. element.setAttribute('download', key);
  116629. }
  116630. }
  116631. }
  116632. }
  116633. function proxyUrl(url, proxy) {
  116634. if (defined(proxy)) {
  116635. if (new Uri(url).isAbsolute()) {
  116636. url = proxy.getURL(url);
  116637. }
  116638. }
  116639. return url;
  116640. }
  116641. // an optional context is passed to allow for some malformed kmls (those with multiple geometries with same ids) to still parse
  116642. // correctly, as they do in Google Earth.
  116643. function createEntity(node, entityCollection, context) {
  116644. var id = queryStringAttribute(node, 'id');
  116645. id = defined(id) && id.length !== 0 ? id : createGuid();
  116646. if(defined(context)){
  116647. id = context + id;
  116648. }
  116649. // If we have a duplicate ID just generate one.
  116650. // This isn't valid KML but Google Earth handles this case.
  116651. var entity = entityCollection.getById(id);
  116652. if (defined(entity)) {
  116653. id = createGuid();
  116654. if(defined(context)){
  116655. id = context + id;
  116656. }
  116657. }
  116658. entity = entityCollection.add(new Entity({id : id}));
  116659. if (!defined(entity.kml)) {
  116660. entity.addProperty('kml');
  116661. entity.kml = new KmlFeatureData();
  116662. }
  116663. return entity;
  116664. }
  116665. function isExtrudable(altitudeMode, gxAltitudeMode) {
  116666. return altitudeMode === 'absolute' || altitudeMode === 'relativeToGround' || gxAltitudeMode === 'relativeToSeaFloor';
  116667. }
  116668. function readCoordinate(value) {
  116669. //Google Earth treats empty or missing coordinates as 0.
  116670. if (!defined(value)) {
  116671. return Cartesian3.fromDegrees(0, 0, 0);
  116672. }
  116673. var digits = value.match(/[^\s,\n]+/g);
  116674. if (!defined(digits)) {
  116675. return Cartesian3.fromDegrees(0, 0, 0);
  116676. }
  116677. var longitude = parseFloat(digits[0]);
  116678. var latitude = parseFloat(digits[1]);
  116679. var height = parseFloat(digits[2]);
  116680. longitude = isNaN(longitude) ? 0.0 : longitude;
  116681. latitude = isNaN(latitude) ? 0.0 : latitude;
  116682. height = isNaN(height) ? 0.0 : height;
  116683. return Cartesian3.fromDegrees(longitude, latitude, height);
  116684. }
  116685. function readCoordinates(element) {
  116686. if (!defined(element)) {
  116687. return undefined;
  116688. }
  116689. var tuples = element.textContent.match(/[^\s\n]+/g);
  116690. if (!defined(tuples)) {
  116691. return undefined;
  116692. }
  116693. var length = tuples.length;
  116694. var result = new Array(length);
  116695. var resultIndex = 0;
  116696. for (var i = 0; i < length; i++) {
  116697. result[resultIndex++] = readCoordinate(tuples[i]);
  116698. }
  116699. return result;
  116700. }
  116701. var kmlNamespaces = [null, undefined, 'http://www.opengis.net/kml/2.2', 'http://earth.google.com/kml/2.2', 'http://earth.google.com/kml/2.1', 'http://earth.google.com/kml/2.0'];
  116702. var gxNamespaces = ['http://www.google.com/kml/ext/2.2'];
  116703. var atomNamespaces = ['http://www.w3.org/2005/Atom'];
  116704. var namespaces = {
  116705. kml : kmlNamespaces,
  116706. gx : gxNamespaces,
  116707. atom : atomNamespaces,
  116708. kmlgx : kmlNamespaces.concat(gxNamespaces)
  116709. };
  116710. function queryNumericAttribute(node, attributeName) {
  116711. if (!defined(node)) {
  116712. return undefined;
  116713. }
  116714. var value = node.getAttribute(attributeName);
  116715. if (value !== null) {
  116716. var result = parseFloat(value);
  116717. return !isNaN(result) ? result : undefined;
  116718. }
  116719. return undefined;
  116720. }
  116721. function queryStringAttribute(node, attributeName) {
  116722. if (!defined(node)) {
  116723. return undefined;
  116724. }
  116725. var value = node.getAttribute(attributeName);
  116726. return value !== null ? value : undefined;
  116727. }
  116728. function queryFirstNode(node, tagName, namespace) {
  116729. if (!defined(node)) {
  116730. return undefined;
  116731. }
  116732. var childNodes = node.childNodes;
  116733. var length = childNodes.length;
  116734. for (var q = 0; q < length; q++) {
  116735. var child = childNodes[q];
  116736. if (child.localName === tagName && namespace.indexOf(child.namespaceURI) !== -1) {
  116737. return child;
  116738. }
  116739. }
  116740. return undefined;
  116741. }
  116742. function queryNodes(node, tagName, namespace) {
  116743. if (!defined(node)) {
  116744. return undefined;
  116745. }
  116746. var result = [];
  116747. var childNodes = node.getElementsByTagNameNS('*', tagName);
  116748. var length = childNodes.length;
  116749. for (var q = 0; q < length; q++) {
  116750. var child = childNodes[q];
  116751. if (child.localName === tagName && namespace.indexOf(child.namespaceURI) !== -1) {
  116752. result.push(child);
  116753. }
  116754. }
  116755. return result;
  116756. }
  116757. function queryChildNodes(node, tagName, namespace) {
  116758. if (!defined(node)) {
  116759. return [];
  116760. }
  116761. var result = [];
  116762. var childNodes = node.childNodes;
  116763. var length = childNodes.length;
  116764. for (var q = 0; q < length; q++) {
  116765. var child = childNodes[q];
  116766. if (child.localName === tagName && namespace.indexOf(child.namespaceURI) !== -1) {
  116767. result.push(child);
  116768. }
  116769. }
  116770. return result;
  116771. }
  116772. function queryNumericValue(node, tagName, namespace) {
  116773. var resultNode = queryFirstNode(node, tagName, namespace);
  116774. if (defined(resultNode)) {
  116775. var result = parseFloat(resultNode.textContent);
  116776. return !isNaN(result) ? result : undefined;
  116777. }
  116778. return undefined;
  116779. }
  116780. function queryStringValue(node, tagName, namespace) {
  116781. var result = queryFirstNode(node, tagName, namespace);
  116782. if (defined(result)) {
  116783. return result.textContent.trim();
  116784. }
  116785. return undefined;
  116786. }
  116787. function queryBooleanValue(node, tagName, namespace) {
  116788. var result = queryFirstNode(node, tagName, namespace);
  116789. if (defined(result)) {
  116790. var value = result.textContent.trim();
  116791. return value === '1' || /^true$/i.test(value);
  116792. }
  116793. return undefined;
  116794. }
  116795. function resolveHref(href, proxy, sourceUri, uriResolver) {
  116796. if (!defined(href)) {
  116797. return undefined;
  116798. }
  116799. var hrefResolved = false;
  116800. if (defined(uriResolver)) {
  116801. var blob = uriResolver[href];
  116802. if (defined(blob)) {
  116803. hrefResolved = true;
  116804. href = blob;
  116805. } else {
  116806. // Needed for multiple levels of KML files in a KMZ
  116807. var tmpHref = getAbsoluteUri(href, sourceUri);
  116808. blob = uriResolver[tmpHref];
  116809. if (defined(blob)) {
  116810. hrefResolved = true;
  116811. href = blob;
  116812. }
  116813. }
  116814. }
  116815. if (!hrefResolved && defined(sourceUri)) {
  116816. href = getAbsoluteUri(href, getAbsoluteUri(sourceUri));
  116817. href = proxyUrl(href, proxy);
  116818. }
  116819. return href;
  116820. }
  116821. var colorOptions = {};
  116822. function parseColorString(value, isRandom) {
  116823. if (!defined(value)) {
  116824. return undefined;
  116825. }
  116826. if (value[0] === '#') {
  116827. value = value.substring(1);
  116828. }
  116829. var alpha = parseInt(value.substring(0, 2), 16) / 255.0;
  116830. var blue = parseInt(value.substring(2, 4), 16) / 255.0;
  116831. var green = parseInt(value.substring(4, 6), 16) / 255.0;
  116832. var red = parseInt(value.substring(6, 8), 16) / 255.0;
  116833. if (!isRandom) {
  116834. return new Color(red, green, blue, alpha);
  116835. }
  116836. if (red > 0) {
  116837. colorOptions.maximumRed = red;
  116838. } else {
  116839. colorOptions.red = 0;
  116840. }
  116841. if (green > 0) {
  116842. colorOptions.maximumGreen = green;
  116843. } else {
  116844. colorOptions.green = 0;
  116845. }
  116846. if (blue > 0) {
  116847. colorOptions.maximumBlue = blue;
  116848. } else {
  116849. colorOptions.blue = 0;
  116850. }
  116851. colorOptions.alpha = alpha;
  116852. return Color.fromRandom(colorOptions);
  116853. }
  116854. function queryColorValue(node, tagName, namespace) {
  116855. var value = queryStringValue(node, tagName, namespace);
  116856. if (!defined(value)) {
  116857. return undefined;
  116858. }
  116859. return parseColorString(value, queryStringValue(node, 'colorMode', namespace) === 'random');
  116860. }
  116861. function processTimeStamp(featureNode) {
  116862. var node = queryFirstNode(featureNode, 'TimeStamp', namespaces.kmlgx);
  116863. var whenString = queryStringValue(node, 'when', namespaces.kmlgx);
  116864. if (!defined(node) || !defined(whenString) || whenString.length === 0) {
  116865. return undefined;
  116866. }
  116867. //According to the KML spec, a TimeStamp represents a "single moment in time"
  116868. //However, since Cesium animates much differently than Google Earth, that doesn't
  116869. //Make much sense here. Instead, we use the TimeStamp as the moment the feature
  116870. //comes into existence. This works much better and gives a similar feel to
  116871. //GE's experience.
  116872. var when = JulianDate.fromIso8601(whenString);
  116873. var result = new TimeIntervalCollection();
  116874. result.addInterval(new TimeInterval({
  116875. start : when,
  116876. stop : Iso8601.MAXIMUM_VALUE
  116877. }));
  116878. return result;
  116879. }
  116880. function processTimeSpan(featureNode) {
  116881. var node = queryFirstNode(featureNode, 'TimeSpan', namespaces.kmlgx);
  116882. if (!defined(node)) {
  116883. return undefined;
  116884. }
  116885. var result;
  116886. var beginNode = queryFirstNode(node, 'begin', namespaces.kmlgx);
  116887. var beginDate = defined(beginNode) ? JulianDate.fromIso8601(beginNode.textContent) : undefined;
  116888. var endNode = queryFirstNode(node, 'end', namespaces.kmlgx);
  116889. var endDate = defined(endNode) ? JulianDate.fromIso8601(endNode.textContent) : undefined;
  116890. if (defined(beginDate) && defined(endDate)) {
  116891. if (JulianDate.lessThan(endDate, beginDate)) {
  116892. var tmp = beginDate;
  116893. beginDate = endDate;
  116894. endDate = tmp;
  116895. }
  116896. result = new TimeIntervalCollection();
  116897. result.addInterval(new TimeInterval({
  116898. start : beginDate,
  116899. stop : endDate
  116900. }));
  116901. } else if (defined(beginDate)) {
  116902. result = new TimeIntervalCollection();
  116903. result.addInterval(new TimeInterval({
  116904. start : beginDate,
  116905. stop : Iso8601.MAXIMUM_VALUE
  116906. }));
  116907. } else if (defined(endDate)) {
  116908. result = new TimeIntervalCollection();
  116909. result.addInterval(new TimeInterval({
  116910. start : Iso8601.MINIMUM_VALUE,
  116911. stop : endDate
  116912. }));
  116913. }
  116914. return result;
  116915. }
  116916. function createDefaultBillboard() {
  116917. var billboard = new BillboardGraphics();
  116918. billboard.width = BILLBOARD_SIZE;
  116919. billboard.height = BILLBOARD_SIZE;
  116920. billboard.scaleByDistance = new NearFarScalar(BILLBOARD_NEAR_DISTANCE, BILLBOARD_NEAR_RATIO, BILLBOARD_FAR_DISTANCE, BILLBOARD_FAR_RATIO);
  116921. billboard.pixelOffsetScaleByDistance = new NearFarScalar(BILLBOARD_NEAR_DISTANCE, BILLBOARD_NEAR_RATIO, BILLBOARD_FAR_DISTANCE, BILLBOARD_FAR_RATIO);
  116922. return billboard;
  116923. }
  116924. function createDefaultPolygon() {
  116925. var polygon = new PolygonGraphics();
  116926. polygon.outline = true;
  116927. polygon.outlineColor = Color.WHITE;
  116928. return polygon;
  116929. }
  116930. function createDefaultLabel() {
  116931. var label = new LabelGraphics();
  116932. label.translucencyByDistance = new NearFarScalar(3000000, 1.0, 5000000, 0.0);
  116933. label.pixelOffset = new Cartesian2(17, 0);
  116934. label.horizontalOrigin = HorizontalOrigin.LEFT;
  116935. label.font = '16px sans-serif';
  116936. label.style = LabelStyle.FILL_AND_OUTLINE;
  116937. return label;
  116938. }
  116939. function getIconHref(iconNode, dataSource, sourceUri, uriResolver, canRefresh) {
  116940. var href = queryStringValue(iconNode, 'href', namespaces.kml);
  116941. if (!defined(href) || (href.length === 0)) {
  116942. return undefined;
  116943. }
  116944. if (href.indexOf('root://icons/palette-') === 0) {
  116945. var palette = href.charAt(21);
  116946. // Get the icon number
  116947. var x = defaultValue(queryNumericValue(iconNode, 'x', namespaces.gx), 0);
  116948. var y = defaultValue(queryNumericValue(iconNode, 'y', namespaces.gx), 0);
  116949. x = Math.min(x / 32, 7);
  116950. y = 7 - Math.min(y / 32, 7);
  116951. var iconNum = (8 * y) + x;
  116952. href = 'https://maps.google.com/mapfiles/kml/pal' + palette + '/icon' + iconNum + '.png';
  116953. }
  116954. href = resolveHref(href, dataSource._proxy, sourceUri, uriResolver);
  116955. if (canRefresh) {
  116956. var refreshMode = queryStringValue(iconNode, 'refreshMode', namespaces.kml);
  116957. var viewRefreshMode = queryStringValue(iconNode, 'viewRefreshMode', namespaces.kml);
  116958. if (refreshMode === 'onInterval' || refreshMode === 'onExpire') {
  116959. console.log('KML - Unsupported Icon refreshMode: ' + refreshMode);
  116960. } else if (viewRefreshMode === 'onStop' || viewRefreshMode === 'onRegion') {
  116961. console.log('KML - Unsupported Icon viewRefreshMode: ' + viewRefreshMode);
  116962. }
  116963. var viewBoundScale = defaultValue(queryStringValue(iconNode, 'viewBoundScale', namespaces.kml), 1.0);
  116964. var defaultViewFormat = (viewRefreshMode === 'onStop') ? 'BBOX=[bboxWest],[bboxSouth],[bboxEast],[bboxNorth]' : '';
  116965. var viewFormat = defaultValue(queryStringValue(iconNode, 'viewFormat', namespaces.kml), defaultViewFormat);
  116966. var httpQuery = queryStringValue(iconNode, 'httpQuery', namespaces.kml);
  116967. var queryString = makeQueryString(viewFormat, httpQuery);
  116968. var icon = joinUrls(href, queryString, false);
  116969. return processNetworkLinkQueryString(dataSource._camera, dataSource._canvas, icon, viewBoundScale, dataSource._lastCameraView.bbox);
  116970. }
  116971. return href;
  116972. }
  116973. function processBillboardIcon(dataSource, node, targetEntity, sourceUri, uriResolver) {
  116974. var scale = queryNumericValue(node, 'scale', namespaces.kml);
  116975. var heading = queryNumericValue(node, 'heading', namespaces.kml);
  116976. var color = queryColorValue(node, 'color', namespaces.kml);
  116977. var iconNode = queryFirstNode(node, 'Icon', namespaces.kml);
  116978. var icon = getIconHref(iconNode, dataSource, sourceUri, uriResolver, false);
  116979. var x = queryNumericValue(iconNode, 'x', namespaces.gx);
  116980. var y = queryNumericValue(iconNode, 'y', namespaces.gx);
  116981. var w = queryNumericValue(iconNode, 'w', namespaces.gx);
  116982. var h = queryNumericValue(iconNode, 'h', namespaces.gx);
  116983. var hotSpotNode = queryFirstNode(node, 'hotSpot', namespaces.kml);
  116984. var hotSpotX = queryNumericAttribute(hotSpotNode, 'x');
  116985. var hotSpotY = queryNumericAttribute(hotSpotNode, 'y');
  116986. var hotSpotXUnit = queryStringAttribute(hotSpotNode, 'xunits');
  116987. var hotSpotYUnit = queryStringAttribute(hotSpotNode, 'yunits');
  116988. var billboard = targetEntity.billboard;
  116989. if (!defined(billboard)) {
  116990. billboard = createDefaultBillboard();
  116991. targetEntity.billboard = billboard;
  116992. }
  116993. billboard.image = icon;
  116994. billboard.scale = scale;
  116995. billboard.color = color;
  116996. if (defined(x) || defined(y) || defined(w) || defined(h)) {
  116997. billboard.imageSubRegion = new BoundingRectangle(x, y, w, h);
  116998. }
  116999. //GE treats a heading of zero as no heading
  117000. //You can still point north using a 360 degree angle (or any multiple of 360)
  117001. if (defined(heading) && heading !== 0) {
  117002. billboard.rotation = CesiumMath.toRadians(-heading);
  117003. billboard.alignedAxis = Cartesian3.UNIT_Z;
  117004. }
  117005. //Hotpot is the KML equivalent of pixel offset
  117006. //The hotspot origin is the lower left, but we leave
  117007. //our billboard origin at the center and simply
  117008. //modify the pixel offset to take this into account
  117009. scale = defaultValue(scale, 1.0);
  117010. var xOffset;
  117011. var yOffset;
  117012. if (defined(hotSpotX)) {
  117013. if (hotSpotXUnit === 'pixels') {
  117014. xOffset = -hotSpotX * scale;
  117015. } else if (hotSpotXUnit === 'insetPixels') {
  117016. xOffset = (hotSpotX - BILLBOARD_SIZE) * scale;
  117017. } else if (hotSpotXUnit === 'fraction') {
  117018. xOffset = -hotSpotX * BILLBOARD_SIZE * scale;
  117019. }
  117020. xOffset += BILLBOARD_SIZE * 0.5 * scale;
  117021. }
  117022. if (defined(hotSpotY)) {
  117023. if (hotSpotYUnit === 'pixels') {
  117024. yOffset = hotSpotY * scale;
  117025. } else if (hotSpotYUnit === 'insetPixels') {
  117026. yOffset = (-hotSpotY + BILLBOARD_SIZE) * scale;
  117027. } else if (hotSpotYUnit === 'fraction') {
  117028. yOffset = hotSpotY * BILLBOARD_SIZE * scale;
  117029. }
  117030. yOffset -= BILLBOARD_SIZE * 0.5 * scale;
  117031. }
  117032. if (defined(xOffset) || defined(yOffset)) {
  117033. billboard.pixelOffset = new Cartesian2(xOffset, yOffset);
  117034. }
  117035. }
  117036. function applyStyle(dataSource, styleNode, targetEntity, sourceUri, uriResolver) {
  117037. for (var i = 0, len = styleNode.childNodes.length; i < len; i++) {
  117038. var node = styleNode.childNodes.item(i);
  117039. if (node.localName === 'IconStyle') {
  117040. processBillboardIcon(dataSource, node, targetEntity, sourceUri, uriResolver);
  117041. } else if (node.localName === 'LabelStyle') {
  117042. var label = targetEntity.label;
  117043. if (!defined(label)) {
  117044. label = createDefaultLabel();
  117045. targetEntity.label = label;
  117046. }
  117047. label.scale = defaultValue(queryNumericValue(node, 'scale', namespaces.kml), label.scale);
  117048. label.fillColor = defaultValue(queryColorValue(node, 'color', namespaces.kml), label.fillColor);
  117049. label.text = targetEntity.name;
  117050. } else if (node.localName === 'LineStyle') {
  117051. var polyline = targetEntity.polyline;
  117052. if (!defined(polyline)) {
  117053. polyline = new PolylineGraphics();
  117054. targetEntity.polyline = polyline;
  117055. }
  117056. polyline.width = queryNumericValue(node, 'width', namespaces.kml);
  117057. polyline.material = queryColorValue(node, 'color', namespaces.kml);
  117058. if (defined(queryColorValue(node, 'outerColor', namespaces.gx))) {
  117059. console.log('KML - gx:outerColor is not supported in a LineStyle');
  117060. }
  117061. if (defined(queryNumericValue(node, 'outerWidth', namespaces.gx))) {
  117062. console.log('KML - gx:outerWidth is not supported in a LineStyle');
  117063. }
  117064. if (defined(queryNumericValue(node, 'physicalWidth', namespaces.gx))) {
  117065. console.log('KML - gx:physicalWidth is not supported in a LineStyle');
  117066. }
  117067. if (defined(queryBooleanValue(node, 'labelVisibility', namespaces.gx))) {
  117068. console.log('KML - gx:labelVisibility is not supported in a LineStyle');
  117069. }
  117070. } else if (node.localName === 'PolyStyle') {
  117071. var polygon = targetEntity.polygon;
  117072. if (!defined(polygon)) {
  117073. polygon = createDefaultPolygon();
  117074. targetEntity.polygon = polygon;
  117075. }
  117076. polygon.material = defaultValue(queryColorValue(node, 'color', namespaces.kml), polygon.material);
  117077. polygon.fill = defaultValue(queryBooleanValue(node, 'fill', namespaces.kml), polygon.fill);
  117078. polygon.outline = defaultValue(queryBooleanValue(node, 'outline', namespaces.kml), polygon.outline);
  117079. } else if (node.localName === 'BalloonStyle') {
  117080. var bgColor = defaultValue(parseColorString(queryStringValue(node, 'bgColor', namespaces.kml)), Color.WHITE);
  117081. var textColor = defaultValue(parseColorString(queryStringValue(node, 'textColor', namespaces.kml)), Color.BLACK);
  117082. var text = queryStringValue(node, 'text', namespaces.kml);
  117083. //This is purely an internal property used in style processing,
  117084. //it never ends up on the final entity.
  117085. targetEntity.addProperty('balloonStyle');
  117086. targetEntity.balloonStyle = {
  117087. bgColor : bgColor,
  117088. textColor : textColor,
  117089. text : text
  117090. };
  117091. } else if (node.localName === 'ListStyle') {
  117092. var listItemType = queryStringValue(node, 'listItemType', namespaces.kml);
  117093. if (listItemType === 'radioFolder' || listItemType === 'checkOffOnly') {
  117094. console.log('KML - Unsupported ListStyle with listItemType: ' + listItemType);
  117095. }
  117096. }
  117097. }
  117098. }
  117099. //Processes and merges any inline styles for the provided node into the provided entity.
  117100. function computeFinalStyle(entity, dataSource, placeMark, styleCollection, sourceUri, uriResolver) {
  117101. var result = new Entity();
  117102. var styleEntity;
  117103. //Google earth seems to always use the last inline Style/StyleMap only
  117104. var styleIndex = -1;
  117105. var childNodes = placeMark.childNodes;
  117106. var length = childNodes.length;
  117107. for (var q = 0; q < length; q++) {
  117108. var child = childNodes[q];
  117109. if (child.localName === 'Style' || child.localName === 'StyleMap') {
  117110. styleIndex = q;
  117111. }
  117112. }
  117113. if (styleIndex !== -1) {
  117114. var inlineStyleNode = childNodes[styleIndex];
  117115. if (inlineStyleNode.localName === 'Style') {
  117116. applyStyle(dataSource, inlineStyleNode, result, sourceUri, uriResolver);
  117117. } else { // StyleMap
  117118. var pairs = queryChildNodes(inlineStyleNode, 'Pair', namespaces.kml);
  117119. for (var p = 0; p < pairs.length; p++) {
  117120. var pair = pairs[p];
  117121. var key = queryStringValue(pair, 'key', namespaces.kml);
  117122. if (key === 'normal') {
  117123. var styleUrl = queryStringValue(pair, 'styleUrl', namespaces.kml);
  117124. if (defined(styleUrl)) {
  117125. styleEntity = styleCollection.getById(styleUrl);
  117126. if (!defined(styleEntity)) {
  117127. styleEntity = styleCollection.getById('#' + styleUrl);
  117128. }
  117129. if (defined(styleEntity)) {
  117130. result.merge(styleEntity);
  117131. }
  117132. } else {
  117133. var node = queryFirstNode(pair, 'Style', namespaces.kml);
  117134. applyStyle(dataSource, node, result, sourceUri, uriResolver);
  117135. }
  117136. } else {
  117137. console.log('KML - Unsupported StyleMap key: ' + key);
  117138. }
  117139. }
  117140. }
  117141. }
  117142. //Google earth seems to always use the first external style only.
  117143. var externalStyle = queryStringValue(placeMark, 'styleUrl', namespaces.kml);
  117144. if (defined(externalStyle)) {
  117145. var id = externalStyle;
  117146. if (externalStyle[0] !== '#' && externalStyle.indexOf('#') !== -1) {
  117147. var tokens = externalStyle.split('#');
  117148. var uri = tokens[0];
  117149. if (defined(sourceUri)) {
  117150. uri = getAbsoluteUri(uri, getAbsoluteUri(sourceUri));
  117151. }
  117152. id = uri + '#' + tokens[1];
  117153. }
  117154. styleEntity = styleCollection.getById(id);
  117155. if (!defined(styleEntity)) {
  117156. styleEntity = styleCollection.getById('#' + id);
  117157. }
  117158. if (defined(styleEntity)) {
  117159. result.merge(styleEntity);
  117160. }
  117161. }
  117162. return result;
  117163. }
  117164. //Asynchronously processes an external style file.
  117165. function processExternalStyles(dataSource, uri, styleCollection) {
  117166. return loadXML(proxyUrl(uri, dataSource._proxy)).then(function(styleKml) {
  117167. return processStyles(dataSource, styleKml, styleCollection, uri, true);
  117168. });
  117169. }
  117170. //Processes all shared and external styles and stores
  117171. //their id into the provided styleCollection.
  117172. //Returns an array of promises that will resolve when
  117173. //each style is loaded.
  117174. function processStyles(dataSource, kml, styleCollection, sourceUri, isExternal, uriResolver) {
  117175. var i;
  117176. var id;
  117177. var styleEntity;
  117178. var node;
  117179. var styleNodes = queryNodes(kml, 'Style', namespaces.kml);
  117180. if (defined(styleNodes)) {
  117181. var styleNodesLength = styleNodes.length;
  117182. for (i = 0; i < styleNodesLength; i++) {
  117183. node = styleNodes[i];
  117184. id = queryStringAttribute(node, 'id');
  117185. if (defined(id)) {
  117186. id = '#' + id;
  117187. if (isExternal && defined(sourceUri)) {
  117188. id = sourceUri + id;
  117189. }
  117190. if (!defined(styleCollection.getById(id))) {
  117191. styleEntity = new Entity({
  117192. id : id
  117193. });
  117194. styleCollection.add(styleEntity);
  117195. applyStyle(dataSource, node, styleEntity, sourceUri, uriResolver);
  117196. }
  117197. }
  117198. }
  117199. }
  117200. var styleMaps = queryNodes(kml, 'StyleMap', namespaces.kml);
  117201. if (defined(styleMaps)) {
  117202. var styleMapsLength = styleMaps.length;
  117203. for (i = 0; i < styleMapsLength; i++) {
  117204. var styleMap = styleMaps[i];
  117205. id = queryStringAttribute(styleMap, 'id');
  117206. if (defined(id)) {
  117207. var pairs = queryChildNodes(styleMap, 'Pair', namespaces.kml);
  117208. for (var p = 0; p < pairs.length; p++) {
  117209. var pair = pairs[p];
  117210. var key = queryStringValue(pair, 'key', namespaces.kml);
  117211. if (key === 'normal') {
  117212. id = '#' + id;
  117213. if (isExternal && defined(sourceUri)) {
  117214. id = sourceUri + id;
  117215. }
  117216. if (!defined(styleCollection.getById(id))) {
  117217. styleEntity = styleCollection.getOrCreateEntity(id);
  117218. var styleUrl = queryStringValue(pair, 'styleUrl', namespaces.kml);
  117219. if (defined(styleUrl)) {
  117220. if (styleUrl[0] !== '#') {
  117221. styleUrl = '#' + styleUrl;
  117222. }
  117223. if (isExternal && defined(sourceUri)) {
  117224. styleUrl = sourceUri + styleUrl;
  117225. }
  117226. var base = styleCollection.getById(styleUrl);
  117227. if (defined(base)) {
  117228. styleEntity.merge(base);
  117229. }
  117230. } else {
  117231. node = queryFirstNode(pair, 'Style', namespaces.kml);
  117232. applyStyle(dataSource, node, styleEntity, sourceUri, uriResolver);
  117233. }
  117234. }
  117235. } else {
  117236. console.log('KML - Unsupported StyleMap key: ' + key);
  117237. }
  117238. }
  117239. }
  117240. }
  117241. }
  117242. var externalStyleHash = {};
  117243. var promises = [];
  117244. var styleUrlNodes = kml.getElementsByTagName('styleUrl');
  117245. var styleUrlNodesLength = styleUrlNodes.length;
  117246. for (i = 0; i < styleUrlNodesLength; i++) {
  117247. var styleReference = styleUrlNodes[i].textContent;
  117248. if (styleReference[0] !== '#') {
  117249. //According to the spec, all local styles should start with a #
  117250. //and everything else is an external style that has a # seperating
  117251. //the URL of the document and the style. However, Google Earth
  117252. //also accepts styleUrls without a # as meaning a local style.
  117253. var tokens = styleReference.split('#');
  117254. if (tokens.length === 2) {
  117255. var uri = tokens[0];
  117256. if (!defined(externalStyleHash[uri])) {
  117257. if (defined(sourceUri)) {
  117258. uri = getAbsoluteUri(uri, getAbsoluteUri(sourceUri));
  117259. }
  117260. promises.push(processExternalStyles(dataSource, uri, styleCollection, sourceUri));
  117261. }
  117262. }
  117263. }
  117264. }
  117265. return promises;
  117266. }
  117267. function createDropLine(entityCollection, entity, styleEntity) {
  117268. var entityPosition = new ReferenceProperty(entityCollection, entity.id, ['position']);
  117269. var surfacePosition = new ScaledPositionProperty(entity.position);
  117270. entity.polyline = defined(styleEntity.polyline) ? styleEntity.polyline.clone() : new PolylineGraphics();
  117271. entity.polyline.positions = new PositionPropertyArray([entityPosition, surfacePosition]);
  117272. }
  117273. function heightReferenceFromAltitudeMode(altitudeMode, gxAltitudeMode) {
  117274. if (!defined(altitudeMode) && !defined(gxAltitudeMode) || altitudeMode === 'clampToGround') {
  117275. return HeightReference.CLAMP_TO_GROUND;
  117276. }
  117277. if (altitudeMode === 'relativeToGround') {
  117278. return HeightReference.RELATIVE_TO_GROUND;
  117279. }
  117280. if (altitudeMode === 'absolute') {
  117281. return HeightReference.NONE;
  117282. }
  117283. if (gxAltitudeMode === 'clampToSeaFloor') {
  117284. console.log('KML - <gx:altitudeMode>:clampToSeaFloor is currently not supported, using <kml:altitudeMode>:clampToGround.');
  117285. return HeightReference.CLAMP_TO_GROUND;
  117286. }
  117287. if (gxAltitudeMode === 'relativeToSeaFloor') {
  117288. console.log('KML - <gx:altitudeMode>:relativeToSeaFloor is currently not supported, using <kml:altitudeMode>:relativeToGround.');
  117289. return HeightReference.RELATIVE_TO_GROUND;
  117290. }
  117291. if (defined(altitudeMode)) {
  117292. console.log('KML - Unknown <kml:altitudeMode>:' + altitudeMode + ', using <kml:altitudeMode>:CLAMP_TO_GROUND.');
  117293. } else {
  117294. console.log('KML - Unknown <gx:altitudeMode>:' + gxAltitudeMode + ', using <kml:altitudeMode>:CLAMP_TO_GROUND.');
  117295. }
  117296. // Clamp to ground is the default
  117297. return HeightReference.CLAMP_TO_GROUND;
  117298. }
  117299. function createPositionPropertyFromAltitudeMode(property, altitudeMode, gxAltitudeMode) {
  117300. if (gxAltitudeMode === 'relativeToSeaFloor' || altitudeMode === 'absolute' || altitudeMode === 'relativeToGround') {
  117301. //Just return the ellipsoid referenced property until we support MSL
  117302. return property;
  117303. }
  117304. if ((defined(altitudeMode) && altitudeMode !== 'clampToGround') || //
  117305. (defined(gxAltitudeMode) && gxAltitudeMode !== 'clampToSeaFloor')) {
  117306. console.log('KML - Unknown altitudeMode: ' + defaultValue(altitudeMode, gxAltitudeMode));
  117307. }
  117308. // Clamp to ground is the default
  117309. return new ScaledPositionProperty(property);
  117310. }
  117311. function createPositionPropertyArrayFromAltitudeMode(properties, altitudeMode, gxAltitudeMode) {
  117312. if (!defined(properties)) {
  117313. return undefined;
  117314. }
  117315. if (gxAltitudeMode === 'relativeToSeaFloor' || altitudeMode === 'absolute' || altitudeMode === 'relativeToGround') {
  117316. //Just return the ellipsoid referenced property until we support MSL
  117317. return properties;
  117318. }
  117319. if ((defined(altitudeMode) && altitudeMode !== 'clampToGround') || //
  117320. (defined(gxAltitudeMode) && gxAltitudeMode !== 'clampToSeaFloor')) {
  117321. console.log('KML - Unknown altitudeMode: ' + defaultValue(altitudeMode, gxAltitudeMode));
  117322. }
  117323. // Clamp to ground is the default
  117324. var propertiesLength = properties.length;
  117325. for (var i = 0; i < propertiesLength; i++) {
  117326. var property = properties[i];
  117327. Ellipsoid.WGS84.scaleToGeodeticSurface(property, property);
  117328. }
  117329. return properties;
  117330. }
  117331. function processPositionGraphics(dataSource, entity, styleEntity, heightReference) {
  117332. var label = entity.label;
  117333. if (!defined(label)) {
  117334. label = defined(styleEntity.label) ? styleEntity.label.clone() : createDefaultLabel();
  117335. entity.label = label;
  117336. }
  117337. label.text = entity.name;
  117338. var billboard = entity.billboard;
  117339. if (!defined(billboard)) {
  117340. billboard = defined(styleEntity.billboard) ? styleEntity.billboard.clone() : createDefaultBillboard();
  117341. entity.billboard = billboard;
  117342. }
  117343. if (!defined(billboard.image)) {
  117344. billboard.image = dataSource._pinBuilder.fromColor(Color.YELLOW, 64);
  117345. }
  117346. var scale = 1.0;
  117347. if (defined(billboard.scale)) {
  117348. scale = billboard.scale.getValue();
  117349. if (scale !== 0) {
  117350. label.pixelOffset = new Cartesian2((scale * 16) + 1, 0);
  117351. } else {
  117352. //Minor tweaks to better match Google Earth.
  117353. label.pixelOffset = undefined;
  117354. label.horizontalOrigin = undefined;
  117355. }
  117356. }
  117357. if (defined(heightReference) && dataSource._clampToGround) {
  117358. billboard.heightReference = heightReference;
  117359. label.heightReference = heightReference;
  117360. }
  117361. }
  117362. function processPathGraphics(dataSource, entity, styleEntity) {
  117363. var path = entity.path;
  117364. if (!defined(path)) {
  117365. path = new PathGraphics();
  117366. path.leadTime = 0;
  117367. entity.path = path;
  117368. }
  117369. var polyline = styleEntity.polyline;
  117370. if (defined(polyline)) {
  117371. path.material = polyline.material;
  117372. path.width = polyline.width;
  117373. }
  117374. }
  117375. function processPoint(dataSource, entityCollection, geometryNode, entity, styleEntity) {
  117376. var coordinatesString = queryStringValue(geometryNode, 'coordinates', namespaces.kml);
  117377. var altitudeMode = queryStringValue(geometryNode, 'altitudeMode', namespaces.kml);
  117378. var gxAltitudeMode = queryStringValue(geometryNode, 'altitudeMode', namespaces.gx);
  117379. var extrude = queryBooleanValue(geometryNode, 'extrude', namespaces.kml);
  117380. var position = readCoordinate(coordinatesString);
  117381. entity.position = position;
  117382. processPositionGraphics(dataSource, entity, styleEntity, heightReferenceFromAltitudeMode(altitudeMode, gxAltitudeMode));
  117383. if (extrude && isExtrudable(altitudeMode, gxAltitudeMode)) {
  117384. createDropLine(entityCollection, entity, styleEntity);
  117385. }
  117386. return true;
  117387. }
  117388. function processLineStringOrLinearRing(dataSource, entityCollection, geometryNode, entity, styleEntity) {
  117389. var coordinatesNode = queryFirstNode(geometryNode, 'coordinates', namespaces.kml);
  117390. var altitudeMode = queryStringValue(geometryNode, 'altitudeMode', namespaces.kml);
  117391. var gxAltitudeMode = queryStringValue(geometryNode, 'altitudeMode', namespaces.gx);
  117392. var extrude = queryBooleanValue(geometryNode, 'extrude', namespaces.kml);
  117393. var tessellate = queryBooleanValue(geometryNode, 'tessellate', namespaces.kml);
  117394. var canExtrude = isExtrudable(altitudeMode, gxAltitudeMode);
  117395. if (defined(queryNumericValue(geometryNode, 'drawOrder', namespaces.gx))) {
  117396. console.log('KML - gx:drawOrder is not supported in LineStrings');
  117397. }
  117398. var coordinates = readCoordinates(coordinatesNode);
  117399. var polyline = styleEntity.polyline;
  117400. if (canExtrude && extrude) {
  117401. var wall = new WallGraphics();
  117402. entity.wall = wall;
  117403. wall.positions = coordinates;
  117404. var polygon = styleEntity.polygon;
  117405. if (defined(polygon)) {
  117406. wall.fill = polygon.fill;
  117407. wall.outline = polygon.outline;
  117408. wall.material = polygon.material;
  117409. }
  117410. if (defined(polyline)) {
  117411. wall.outlineColor = defined(polyline.material) ? polyline.material.color : Color.WHITE;
  117412. wall.outlineWidth = polyline.width;
  117413. }
  117414. } else {
  117415. if (dataSource._clampToGround && !canExtrude && tessellate) {
  117416. var corridor = new CorridorGraphics();
  117417. entity.corridor = corridor;
  117418. corridor.positions = coordinates;
  117419. if (defined(polyline)) {
  117420. corridor.material = defined(polyline.material) ? polyline.material.color.getValue(Iso8601.MINIMUM_VALUE) : Color.WHITE;
  117421. corridor.width = defaultValue(polyline.width, 1.0);
  117422. } else {
  117423. corridor.material = Color.WHITE;
  117424. corridor.width = 1.0;
  117425. }
  117426. } else {
  117427. polyline = defined(polyline) ? polyline.clone() : new PolylineGraphics();
  117428. entity.polyline = polyline;
  117429. polyline.positions = createPositionPropertyArrayFromAltitudeMode(coordinates, altitudeMode, gxAltitudeMode);
  117430. if (!tessellate || canExtrude) {
  117431. polyline.followSurface = false;
  117432. }
  117433. }
  117434. }
  117435. return true;
  117436. }
  117437. function processPolygon(dataSource, entityCollection, geometryNode, entity, styleEntity) {
  117438. var outerBoundaryIsNode = queryFirstNode(geometryNode, 'outerBoundaryIs', namespaces.kml);
  117439. var linearRingNode = queryFirstNode(outerBoundaryIsNode, 'LinearRing', namespaces.kml);
  117440. var coordinatesNode = queryFirstNode(linearRingNode, 'coordinates', namespaces.kml);
  117441. var coordinates = readCoordinates(coordinatesNode);
  117442. var extrude = queryBooleanValue(geometryNode, 'extrude', namespaces.kml);
  117443. var altitudeMode = queryStringValue(geometryNode, 'altitudeMode', namespaces.kml);
  117444. var gxAltitudeMode = queryStringValue(geometryNode, 'altitudeMode', namespaces.gx);
  117445. var canExtrude = isExtrudable(altitudeMode, gxAltitudeMode);
  117446. var polygon = defined(styleEntity.polygon) ? styleEntity.polygon.clone() : createDefaultPolygon();
  117447. var polyline = styleEntity.polyline;
  117448. if (defined(polyline)) {
  117449. polygon.outlineColor = defined(polyline.material) ? polyline.material.color : Color.WHITE;
  117450. polygon.outlineWidth = polyline.width;
  117451. }
  117452. entity.polygon = polygon;
  117453. if (canExtrude) {
  117454. polygon.perPositionHeight = true;
  117455. polygon.extrudedHeight = extrude ? 0 : undefined;
  117456. } else if (!dataSource._clampToGround) {
  117457. polygon.height = 0;
  117458. }
  117459. if (defined(coordinates)) {
  117460. var hierarchy = new PolygonHierarchy(coordinates);
  117461. var innerBoundaryIsNodes = queryChildNodes(geometryNode, 'innerBoundaryIs', namespaces.kml);
  117462. for (var j = 0; j < innerBoundaryIsNodes.length; j++) {
  117463. linearRingNode = queryChildNodes(innerBoundaryIsNodes[j], 'LinearRing', namespaces.kml);
  117464. for (var k = 0; k < linearRingNode.length; k++) {
  117465. coordinatesNode = queryFirstNode(linearRingNode[k], 'coordinates', namespaces.kml);
  117466. coordinates = readCoordinates(coordinatesNode);
  117467. if (defined(coordinates)) {
  117468. hierarchy.holes.push(new PolygonHierarchy(coordinates));
  117469. }
  117470. }
  117471. }
  117472. polygon.hierarchy = hierarchy;
  117473. }
  117474. return true;
  117475. }
  117476. function processTrack(dataSource, entityCollection, geometryNode, entity, styleEntity) {
  117477. var altitudeMode = queryStringValue(geometryNode, 'altitudeMode', namespaces.kml);
  117478. var gxAltitudeMode = queryStringValue(geometryNode, 'altitudeMode', namespaces.gx);
  117479. var coordNodes = queryChildNodes(geometryNode, 'coord', namespaces.gx);
  117480. var angleNodes = queryChildNodes(geometryNode, 'angles', namespaces.gx);
  117481. var timeNodes = queryChildNodes(geometryNode, 'when', namespaces.kml);
  117482. var extrude = queryBooleanValue(geometryNode, 'extrude', namespaces.kml);
  117483. var canExtrude = isExtrudable(altitudeMode, gxAltitudeMode);
  117484. if (angleNodes.length > 0) {
  117485. console.log('KML - gx:angles are not supported in gx:Tracks');
  117486. }
  117487. var length = Math.min(coordNodes.length, timeNodes.length);
  117488. var coordinates = [];
  117489. var times = [];
  117490. for (var i = 0; i < length; i++) {
  117491. var position = readCoordinate(coordNodes[i].textContent);
  117492. coordinates.push(position);
  117493. times.push(JulianDate.fromIso8601(timeNodes[i].textContent));
  117494. }
  117495. var property = new SampledPositionProperty();
  117496. property.addSamples(times, coordinates);
  117497. entity.position = property;
  117498. processPositionGraphics(dataSource, entity, styleEntity, heightReferenceFromAltitudeMode(altitudeMode, gxAltitudeMode));
  117499. processPathGraphics(dataSource, entity, styleEntity);
  117500. entity.availability = new TimeIntervalCollection();
  117501. if (timeNodes.length > 0) {
  117502. entity.availability.addInterval(new TimeInterval({
  117503. start : times[0],
  117504. stop : times[times.length - 1]
  117505. }));
  117506. }
  117507. if (canExtrude && extrude) {
  117508. createDropLine(entityCollection, entity, styleEntity);
  117509. }
  117510. return true;
  117511. }
  117512. function addToMultiTrack(times, positions, composite, availability, dropShowProperty, extrude, altitudeMode, gxAltitudeMode, includeEndPoints) {
  117513. var start = times[0];
  117514. var stop = times[times.length - 1];
  117515. var data = new SampledPositionProperty();
  117516. data.addSamples(times, positions);
  117517. composite.intervals.addInterval(new TimeInterval({
  117518. start : start,
  117519. stop : stop,
  117520. isStartIncluded : includeEndPoints,
  117521. isStopIncluded : includeEndPoints,
  117522. data : createPositionPropertyFromAltitudeMode(data, altitudeMode, gxAltitudeMode)
  117523. }));
  117524. availability.addInterval(new TimeInterval({
  117525. start : start,
  117526. stop : stop,
  117527. isStartIncluded : includeEndPoints,
  117528. isStopIncluded : includeEndPoints
  117529. }));
  117530. dropShowProperty.intervals.addInterval(new TimeInterval({
  117531. start : start,
  117532. stop : stop,
  117533. isStartIncluded : includeEndPoints,
  117534. isStopIncluded : includeEndPoints,
  117535. data : extrude
  117536. }));
  117537. }
  117538. function processMultiTrack(dataSource, entityCollection, geometryNode, entity, styleEntity) {
  117539. // Multitrack options do not work in GE as detailed in the spec,
  117540. // rather than altitudeMode being at the MultiTrack level,
  117541. // GE just defers all settings to the underlying track.
  117542. var interpolate = queryBooleanValue(geometryNode, 'interpolate', namespaces.gx);
  117543. var trackNodes = queryChildNodes(geometryNode, 'Track', namespaces.gx);
  117544. var times;
  117545. var lastStop;
  117546. var lastStopPosition;
  117547. var needDropLine = false;
  117548. var dropShowProperty = new TimeIntervalCollectionProperty();
  117549. var availability = new TimeIntervalCollection();
  117550. var composite = new CompositePositionProperty();
  117551. for (var i = 0, len = trackNodes.length; i < len; i++) {
  117552. var trackNode = trackNodes[i];
  117553. var timeNodes = queryChildNodes(trackNode, 'when', namespaces.kml);
  117554. var coordNodes = queryChildNodes(trackNode, 'coord', namespaces.gx);
  117555. var altitudeMode = queryStringValue(trackNode, 'altitudeMode', namespaces.kml);
  117556. var gxAltitudeMode = queryStringValue(trackNode, 'altitudeMode', namespaces.gx);
  117557. var canExtrude = isExtrudable(altitudeMode, gxAltitudeMode);
  117558. var extrude = queryBooleanValue(trackNode, 'extrude', namespaces.kml);
  117559. var length = Math.min(coordNodes.length, timeNodes.length);
  117560. var positions = [];
  117561. times = [];
  117562. for (var x = 0; x < length; x++) {
  117563. var position = readCoordinate(coordNodes[x].textContent);
  117564. positions.push(position);
  117565. times.push(JulianDate.fromIso8601(timeNodes[x].textContent));
  117566. }
  117567. if (interpolate) {
  117568. //If we are interpolating, then we need to fill in the end of
  117569. //the last track and the beginning of this one with a sampled
  117570. //property. From testing in Google Earth, this property
  117571. //is never extruded and always absolute.
  117572. if (defined(lastStop)) {
  117573. addToMultiTrack([lastStop, times[0]], [lastStopPosition, positions[0]], composite, availability, dropShowProperty, false, 'absolute', undefined, false);
  117574. }
  117575. lastStop = times[length - 1];
  117576. lastStopPosition = positions[positions.length - 1];
  117577. }
  117578. addToMultiTrack(times, positions, composite, availability, dropShowProperty, canExtrude && extrude, altitudeMode, gxAltitudeMode, true);
  117579. needDropLine = needDropLine || (canExtrude && extrude);
  117580. }
  117581. entity.availability = availability;
  117582. entity.position = composite;
  117583. processPositionGraphics(dataSource, entity, styleEntity);
  117584. processPathGraphics(dataSource, entity, styleEntity);
  117585. if (needDropLine) {
  117586. createDropLine(entityCollection, entity, styleEntity);
  117587. entity.polyline.show = dropShowProperty;
  117588. }
  117589. return true;
  117590. }
  117591. function processMultiGeometry(dataSource, entityCollection, geometryNode, entity, styleEntity, context) {
  117592. var childNodes = geometryNode.childNodes;
  117593. var hasGeometry = false;
  117594. for (var i = 0, len = childNodes.length; i < len; i++) {
  117595. var childNode = childNodes.item(i);
  117596. var geometryProcessor = geometryTypes[childNode.localName];
  117597. if (defined(geometryProcessor)) {
  117598. var childEntity = createEntity(childNode, entityCollection, context);
  117599. childEntity.parent = entity;
  117600. childEntity.name = entity.name;
  117601. childEntity.availability = entity.availability;
  117602. childEntity.description = entity.description;
  117603. childEntity.kml = entity.kml;
  117604. if (geometryProcessor(dataSource, entityCollection, childNode, childEntity, styleEntity)) {
  117605. hasGeometry = true;
  117606. }
  117607. }
  117608. }
  117609. return hasGeometry;
  117610. }
  117611. function processUnsupportedGeometry(dataSource, entityCollection, geometryNode, entity, styleEntity) {
  117612. console.log('KML - Unsupported geometry: ' + geometryNode.localName);
  117613. return false;
  117614. }
  117615. function processExtendedData(node, entity) {
  117616. var extendedDataNode = queryFirstNode(node, 'ExtendedData', namespaces.kml);
  117617. if (!defined(extendedDataNode)) {
  117618. return undefined;
  117619. }
  117620. if (defined(queryFirstNode(extendedDataNode, 'SchemaData', namespaces.kml))) {
  117621. console.log('KML - SchemaData is unsupported');
  117622. }
  117623. if (defined(queryStringAttribute(extendedDataNode, 'xmlns:prefix'))) {
  117624. console.log('KML - ExtendedData with xmlns:prefix is unsupported');
  117625. }
  117626. var result = {};
  117627. var dataNodes = queryChildNodes(extendedDataNode, 'Data', namespaces.kml);
  117628. if (defined(dataNodes)) {
  117629. var length = dataNodes.length;
  117630. for (var i = 0; i < length; i++) {
  117631. var dataNode = dataNodes[i];
  117632. var name = queryStringAttribute(dataNode, 'name');
  117633. if (defined(name)) {
  117634. result[name] = {
  117635. displayName : queryStringValue(dataNode, 'displayName', namespaces.kml),
  117636. value : queryStringValue(dataNode, 'value', namespaces.kml)
  117637. };
  117638. }
  117639. }
  117640. }
  117641. entity.kml.extendedData = result;
  117642. }
  117643. var scratchDiv = document.createElement('div');
  117644. function processDescription(node, entity, styleEntity, uriResolver) {
  117645. var i;
  117646. var key;
  117647. var keys;
  117648. var kmlData = entity.kml;
  117649. var extendedData = kmlData.extendedData;
  117650. var description = queryStringValue(node, 'description', namespaces.kml);
  117651. var balloonStyle = defaultValue(entity.balloonStyle, styleEntity.balloonStyle);
  117652. var background = Color.WHITE;
  117653. var foreground = Color.BLACK;
  117654. var text = description;
  117655. if (defined(balloonStyle)) {
  117656. background = defaultValue(balloonStyle.bgColor, Color.WHITE);
  117657. foreground = defaultValue(balloonStyle.textColor, Color.BLACK);
  117658. text = defaultValue(balloonStyle.text, description);
  117659. }
  117660. var value;
  117661. if (defined(text)) {
  117662. text = text.replace('$[name]', defaultValue(entity.name, ''));
  117663. text = text.replace('$[description]', defaultValue(description, ''));
  117664. text = text.replace('$[address]', defaultValue(kmlData.address, ''));
  117665. text = text.replace('$[Snippet]', defaultValue(kmlData.snippet, ''));
  117666. text = text.replace('$[id]', entity.id);
  117667. //While not explicitly defined by the OGC spec, in Google Earth
  117668. //The appearance of geDirections adds the directions to/from links
  117669. //We simply replace this string with nothing.
  117670. text = text.replace('$[geDirections]', '');
  117671. if (defined(extendedData)) {
  117672. var matches = text.match(/\$\[.+?\]/g);
  117673. if (matches !== null) {
  117674. for (i = 0; i < matches.length; i++) {
  117675. var token = matches[i];
  117676. var propertyName = token.substr(2, token.length - 3);
  117677. var isDisplayName = /\/displayName$/.test(propertyName);
  117678. propertyName = propertyName.replace(/\/displayName$/, '');
  117679. value = extendedData[propertyName];
  117680. if (defined(value)) {
  117681. value = isDisplayName ? value.displayName : value.value;
  117682. }
  117683. if (defined(value)) {
  117684. text = text.replace(token, defaultValue(value, ''));
  117685. }
  117686. }
  117687. }
  117688. }
  117689. } else if (defined(extendedData)) {
  117690. //If no description exists, build a table out of the extended data
  117691. keys = Object.keys(extendedData);
  117692. if (keys.length > 0) {
  117693. text = '<table class="cesium-infoBox-defaultTable cesium-infoBox-defaultTable-lighter"><tbody>';
  117694. for (i = 0; i < keys.length; i++) {
  117695. key = keys[i];
  117696. value = extendedData[key];
  117697. text += '<tr><th>' + defaultValue(value.displayName, key) + '</th><td>' + defaultValue(value.value, '') + '</td></tr>';
  117698. }
  117699. text += '</tbody></table>';
  117700. }
  117701. }
  117702. if (!defined(text)) {
  117703. //No description
  117704. return;
  117705. }
  117706. //Turns non-explicit links into clickable links.
  117707. text = autolinker.link(text);
  117708. //Use a temporary div to manipulate the links
  117709. //so that they open in a new window.
  117710. scratchDiv.innerHTML = text;
  117711. var links = scratchDiv.querySelectorAll('a');
  117712. for (i = 0; i < links.length; i++) {
  117713. links[i].setAttribute('target', '_blank');
  117714. }
  117715. //Rewrite any KMZ embedded urls
  117716. if (defined(uriResolver) && uriResolver.keys.length > 1) {
  117717. replaceAttributes(scratchDiv, 'a', 'href', uriResolver);
  117718. replaceAttributes(scratchDiv, 'img', 'src', uriResolver);
  117719. }
  117720. var tmp = '<div class="cesium-infoBox-description-lighter" style="';
  117721. tmp += 'overflow:auto;';
  117722. tmp += 'word-wrap:break-word;';
  117723. tmp += 'background-color:' + background.toCssColorString() + ';';
  117724. tmp += 'color:' + foreground.toCssColorString() + ';';
  117725. tmp += '">';
  117726. tmp += scratchDiv.innerHTML + '</div>';
  117727. scratchDiv.innerHTML = '';
  117728. //Set the final HTML as the description.
  117729. entity.description = tmp;
  117730. }
  117731. function processFeature(dataSource, parent, featureNode, entityCollection, styleCollection, sourceUri, uriResolver, promises, context) {
  117732. var entity = createEntity(featureNode, entityCollection, context);
  117733. var kmlData = entity.kml;
  117734. var styleEntity = computeFinalStyle(entity, dataSource, featureNode, styleCollection, sourceUri, uriResolver);
  117735. var name = queryStringValue(featureNode, 'name', namespaces.kml);
  117736. entity.name = name;
  117737. entity.parent = parent;
  117738. var availability = processTimeSpan(featureNode);
  117739. if (!defined(availability)) {
  117740. availability = processTimeStamp(featureNode);
  117741. }
  117742. entity.availability = availability;
  117743. mergeAvailabilityWithParent(entity);
  117744. // Per KML spec "A Feature is visible only if it and all its ancestors are visible."
  117745. function ancestryIsVisible(parentEntity) {
  117746. if (!parentEntity) {
  117747. return true;
  117748. }
  117749. return parentEntity.show && ancestryIsVisible(parentEntity.parent);
  117750. }
  117751. var visibility = queryBooleanValue(featureNode, 'visibility', namespaces.kml);
  117752. entity.show = ancestryIsVisible(parent) && defaultValue(visibility, true);
  117753. //var open = queryBooleanValue(featureNode, 'open', namespaces.kml);
  117754. var authorNode = queryFirstNode(featureNode, 'author', namespaces.atom);
  117755. var author = kmlData.author;
  117756. author.name = queryStringValue(authorNode, 'name', namespaces.atom);
  117757. author.uri = queryStringValue(authorNode, 'uri', namespaces.atom);
  117758. author.email = queryStringValue(authorNode, 'email', namespaces.atom);
  117759. var linkNode = queryFirstNode(featureNode, 'link', namespaces.atom);
  117760. var link = kmlData.link;
  117761. link.href = queryStringAttribute(linkNode, 'href');
  117762. link.hreflang = queryStringAttribute(linkNode, 'hreflang');
  117763. link.rel = queryStringAttribute(linkNode, 'rel');
  117764. link.type = queryStringAttribute(linkNode, 'type');
  117765. link.title = queryStringAttribute(linkNode, 'title');
  117766. link.length = queryStringAttribute(linkNode, 'length');
  117767. kmlData.address = queryStringValue(featureNode, 'address', namespaces.kml);
  117768. kmlData.phoneNumber = queryStringValue(featureNode, 'phoneNumber', namespaces.kml);
  117769. kmlData.snippet = queryStringValue(featureNode, 'Snippet', namespaces.kml);
  117770. processExtendedData(featureNode, entity);
  117771. processDescription(featureNode, entity, styleEntity, uriResolver);
  117772. if (defined(queryFirstNode(featureNode, 'Camera', namespaces.kml))) {
  117773. console.log('KML - Unsupported view: Camera');
  117774. }
  117775. if (defined(queryFirstNode(featureNode, 'LookAt', namespaces.kml))) {
  117776. console.log('KML - Unsupported view: LookAt');
  117777. }
  117778. if (defined(queryFirstNode(featureNode, 'Region', namespaces.kml))) {
  117779. console.log('KML - Placemark Regions are unsupported');
  117780. }
  117781. return {
  117782. entity : entity,
  117783. styleEntity : styleEntity
  117784. };
  117785. }
  117786. var geometryTypes = {
  117787. Point : processPoint,
  117788. LineString : processLineStringOrLinearRing,
  117789. LinearRing : processLineStringOrLinearRing,
  117790. Polygon : processPolygon,
  117791. Track : processTrack,
  117792. MultiTrack : processMultiTrack,
  117793. MultiGeometry : processMultiGeometry,
  117794. Model : processUnsupportedGeometry
  117795. };
  117796. function processDocument(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context) {
  117797. var featureTypeNames = Object.keys(featureTypes);
  117798. var featureTypeNamesLength = featureTypeNames.length;
  117799. for (var i = 0; i < featureTypeNamesLength; i++) {
  117800. var featureName = featureTypeNames[i];
  117801. var processFeatureNode = featureTypes[featureName];
  117802. var childNodes = node.childNodes;
  117803. var length = childNodes.length;
  117804. for (var q = 0; q < length; q++) {
  117805. var child = childNodes[q];
  117806. if (child.localName === featureName &&
  117807. ((namespaces.kml.indexOf(child.namespaceURI) !== -1) || (namespaces.gx.indexOf(child.namespaceURI) !== -1))) {
  117808. processFeatureNode(dataSource, parent, child, entityCollection, styleCollection, sourceUri, uriResolver, promises, context);
  117809. }
  117810. }
  117811. }
  117812. }
  117813. function processFolder(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context) {
  117814. var r = processFeature(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context);
  117815. processDocument(dataSource, r.entity, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context);
  117816. }
  117817. function processPlacemark(dataSource, parent, placemark, entityCollection, styleCollection, sourceUri, uriResolver, promises, context) {
  117818. var r = processFeature(dataSource, parent, placemark, entityCollection, styleCollection, sourceUri, uriResolver, promises, context);
  117819. var entity = r.entity;
  117820. var styleEntity = r.styleEntity;
  117821. var hasGeometry = false;
  117822. var childNodes = placemark.childNodes;
  117823. for (var i = 0, len = childNodes.length; i < len && !hasGeometry; i++) {
  117824. var childNode = childNodes.item(i);
  117825. var geometryProcessor = geometryTypes[childNode.localName];
  117826. if (defined(geometryProcessor)) {
  117827. // pass the placemark entity id as a context for case of defining multiple child entities together to handle case
  117828. // where some malformed kmls reuse the same id across placemarks, which works in GE, but is not technically to spec.
  117829. geometryProcessor(dataSource, entityCollection, childNode, entity, styleEntity, entity.id);
  117830. hasGeometry = true;
  117831. }
  117832. }
  117833. if (!hasGeometry) {
  117834. entity.merge(styleEntity);
  117835. processPositionGraphics(dataSource, entity, styleEntity);
  117836. }
  117837. }
  117838. function processGroundOverlay(dataSource, parent, groundOverlay, entityCollection, styleCollection, sourceUri, uriResolver, promises, context) {
  117839. var r = processFeature(dataSource, parent, groundOverlay, entityCollection, styleCollection, sourceUri, uriResolver, promises, context);
  117840. var entity = r.entity;
  117841. var geometry;
  117842. var isLatLonQuad = false;
  117843. var positions = readCoordinates(queryFirstNode(groundOverlay, 'LatLonQuad', namespaces.gx));
  117844. if (defined(positions)) {
  117845. geometry = createDefaultPolygon();
  117846. geometry.hierarchy = new PolygonHierarchy(positions);
  117847. entity.polygon = geometry;
  117848. isLatLonQuad = true;
  117849. } else {
  117850. geometry = new RectangleGraphics();
  117851. entity.rectangle = geometry;
  117852. var latLonBox = queryFirstNode(groundOverlay, 'LatLonBox', namespaces.kml);
  117853. if (defined(latLonBox)) {
  117854. var west = queryNumericValue(latLonBox, 'west', namespaces.kml);
  117855. var south = queryNumericValue(latLonBox, 'south', namespaces.kml);
  117856. var east = queryNumericValue(latLonBox, 'east', namespaces.kml);
  117857. var north = queryNumericValue(latLonBox, 'north', namespaces.kml);
  117858. if (defined(west)) {
  117859. west = CesiumMath.negativePiToPi(CesiumMath.toRadians(west));
  117860. }
  117861. if (defined(south)) {
  117862. south = CesiumMath.clampToLatitudeRange(CesiumMath.toRadians(south));
  117863. }
  117864. if (defined(east)) {
  117865. east = CesiumMath.negativePiToPi(CesiumMath.toRadians(east));
  117866. }
  117867. if (defined(north)) {
  117868. north = CesiumMath.clampToLatitudeRange(CesiumMath.toRadians(north));
  117869. }
  117870. geometry.coordinates = new Rectangle(west, south, east, north);
  117871. var rotation = queryNumericValue(latLonBox, 'rotation', namespaces.kml);
  117872. if (defined(rotation)) {
  117873. geometry.rotation = CesiumMath.toRadians(rotation);
  117874. }
  117875. }
  117876. }
  117877. var iconNode = queryFirstNode(groundOverlay, 'Icon', namespaces.kml);
  117878. var href = getIconHref(iconNode, dataSource, sourceUri, uriResolver, true);
  117879. if (defined(href)) {
  117880. if (isLatLonQuad) {
  117881. console.log('KML - gx:LatLonQuad Icon does not support texture projection.');
  117882. }
  117883. var x = queryNumericValue(iconNode, 'x', namespaces.gx);
  117884. var y = queryNumericValue(iconNode, 'y', namespaces.gx);
  117885. var w = queryNumericValue(iconNode, 'w', namespaces.gx);
  117886. var h = queryNumericValue(iconNode, 'h', namespaces.gx);
  117887. if (defined(x) || defined(y) || defined(w) || defined(h)) {
  117888. console.log('KML - gx:x, gx:y, gx:w, gx:h aren\'t supported for GroundOverlays');
  117889. }
  117890. geometry.material = href;
  117891. geometry.material.color = queryColorValue(groundOverlay, 'color', namespaces.kml);
  117892. geometry.material.transparent = true;
  117893. } else {
  117894. geometry.material = queryColorValue(groundOverlay, 'color', namespaces.kml);
  117895. }
  117896. var altitudeMode = queryStringValue(groundOverlay, 'altitudeMode', namespaces.kml);
  117897. if (defined(altitudeMode)) {
  117898. if (altitudeMode === 'absolute') {
  117899. //Use height above ellipsoid until we support MSL.
  117900. geometry.height = queryNumericValue(groundOverlay, 'altitude', namespaces.kml);
  117901. } else if (altitudeMode !== 'clampToGround'){
  117902. console.log('KML - Unknown altitudeMode: ' + altitudeMode);
  117903. }
  117904. // else just use the default of 0 until we support 'clampToGround'
  117905. } else {
  117906. altitudeMode = queryStringValue(groundOverlay, 'altitudeMode', namespaces.gx);
  117907. if (altitudeMode === 'relativeToSeaFloor') {
  117908. console.log('KML - altitudeMode relativeToSeaFloor is currently not supported, treating as absolute.');
  117909. geometry.height = queryNumericValue(groundOverlay, 'altitude', namespaces.kml);
  117910. } else if (altitudeMode === 'clampToSeaFloor') {
  117911. console.log('KML - altitudeMode clampToSeaFloor is currently not supported, treating as clampToGround.');
  117912. } else if (defined(altitudeMode)) {
  117913. console.log('KML - Unknown altitudeMode: ' + altitudeMode);
  117914. }
  117915. }
  117916. }
  117917. function processUnsupportedFeature(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context) {
  117918. dataSource._unsupportedNode.raiseEvent(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver);
  117919. console.log('KML - Unsupported feature: ' + node.localName);
  117920. }
  117921. var RefreshMode = {
  117922. INTERVAL : 0,
  117923. EXPIRE : 1,
  117924. STOP : 2
  117925. };
  117926. function cleanupString(s) {
  117927. if (!defined(s) || s.length === 0) {
  117928. return '';
  117929. }
  117930. var sFirst = s[0];
  117931. if (sFirst === '&') {
  117932. s.splice(0, 1);
  117933. }
  117934. if(sFirst !== '?') {
  117935. s = '?' + s;
  117936. }
  117937. return s;
  117938. }
  117939. function makeQueryString(string1, string2) {
  117940. var result = '';
  117941. if ((defined(string1) && string1.length > 0) || (defined(string2) && string2.length > 0)) {
  117942. result += joinUrls(cleanupString(string1), cleanupString(string2), false);
  117943. }
  117944. return result;
  117945. }
  117946. var zeroRectangle = new Rectangle();
  117947. var scratchCartographic = new Cartographic();
  117948. var scratchCartesian2 = new Cartesian2();
  117949. var scratchCartesian3 = new Cartesian3();
  117950. function processNetworkLinkQueryString(camera, canvas, queryString, viewBoundScale, bbox) {
  117951. function fixLatitude(value) {
  117952. if (value < -CesiumMath.PI_OVER_TWO) {
  117953. return -CesiumMath.PI_OVER_TWO;
  117954. } else if (value > CesiumMath.PI_OVER_TWO) {
  117955. return CesiumMath.PI_OVER_TWO;
  117956. }
  117957. return value;
  117958. }
  117959. function fixLongitude(value) {
  117960. if (value > CesiumMath.PI) {
  117961. return value - CesiumMath.TWO_PI;
  117962. } else if (value < -CesiumMath.PI) {
  117963. return value + CesiumMath.TWO_PI;
  117964. }
  117965. return value;
  117966. }
  117967. if (defined(camera) && camera._mode !== SceneMode.MORPHING) {
  117968. var wgs84 = Ellipsoid.WGS84;
  117969. var centerCartesian;
  117970. var centerCartographic;
  117971. bbox = defaultValue(bbox, zeroRectangle);
  117972. if (defined(canvas)) {
  117973. scratchCartesian2.x = canvas.clientWidth * 0.5;
  117974. scratchCartesian2.y = canvas.clientHeight * 0.5;
  117975. centerCartesian = camera.pickEllipsoid(scratchCartesian2, wgs84, scratchCartesian3);
  117976. }
  117977. if (defined(centerCartesian)) {
  117978. centerCartographic = wgs84.cartesianToCartographic(centerCartesian, scratchCartographic);
  117979. } else {
  117980. centerCartographic = Rectangle.center(bbox, scratchCartographic);
  117981. centerCartesian = wgs84.cartographicToCartesian(centerCartographic);
  117982. }
  117983. if (defined(viewBoundScale) && !CesiumMath.equalsEpsilon(viewBoundScale, 1.0, CesiumMath.EPSILON9)) {
  117984. var newHalfWidth = bbox.width * viewBoundScale * 0.5;
  117985. var newHalfHeight = bbox.height * viewBoundScale * 0.5;
  117986. bbox = new Rectangle(fixLongitude(centerCartographic.longitude - newHalfWidth),
  117987. fixLatitude(centerCartographic.latitude - newHalfHeight),
  117988. fixLongitude(centerCartographic.longitude + newHalfWidth),
  117989. fixLatitude(centerCartographic.latitude + newHalfHeight)
  117990. );
  117991. }
  117992. queryString = queryString.replace('[bboxWest]', CesiumMath.toDegrees(bbox.west).toString());
  117993. queryString = queryString.replace('[bboxSouth]', CesiumMath.toDegrees(bbox.south).toString());
  117994. queryString = queryString.replace('[bboxEast]', CesiumMath.toDegrees(bbox.east).toString());
  117995. queryString = queryString.replace('[bboxNorth]', CesiumMath.toDegrees(bbox.north).toString());
  117996. var lon = CesiumMath.toDegrees(centerCartographic.longitude).toString();
  117997. var lat = CesiumMath.toDegrees(centerCartographic.latitude).toString();
  117998. queryString = queryString.replace('[lookatLon]', lon);
  117999. queryString = queryString.replace('[lookatLat]', lat);
  118000. queryString = queryString.replace('[lookatTilt]', CesiumMath.toDegrees(camera.pitch).toString());
  118001. queryString = queryString.replace('[lookatHeading]', CesiumMath.toDegrees(camera.heading).toString());
  118002. queryString = queryString.replace('[lookatRange]', Cartesian3.distance(camera.positionWC, centerCartesian));
  118003. queryString = queryString.replace('[lookatTerrainLon]', lon);
  118004. queryString = queryString.replace('[lookatTerrainLat]', lat);
  118005. queryString = queryString.replace('[lookatTerrainAlt]', centerCartographic.height.toString());
  118006. wgs84.cartesianToCartographic(camera.positionWC, scratchCartographic);
  118007. queryString = queryString.replace('[cameraLon]', CesiumMath.toDegrees(scratchCartographic.longitude).toString());
  118008. queryString = queryString.replace('[cameraLat]', CesiumMath.toDegrees(scratchCartographic.latitude).toString());
  118009. queryString = queryString.replace('[cameraAlt]', CesiumMath.toDegrees(scratchCartographic.height).toString());
  118010. var frustum = camera.frustum;
  118011. var aspectRatio = frustum.aspectRatio;
  118012. var horizFov = '';
  118013. var vertFov = '';
  118014. if (defined(aspectRatio)) {
  118015. var fov = CesiumMath.toDegrees(frustum.fov);
  118016. if (aspectRatio > 1.0) {
  118017. horizFov = fov;
  118018. vertFov = fov / aspectRatio;
  118019. } else {
  118020. vertFov = fov;
  118021. horizFov = fov * aspectRatio;
  118022. }
  118023. }
  118024. queryString = queryString.replace('[horizFov]', horizFov.toString());
  118025. queryString = queryString.replace('[vertFov]', vertFov.toString());
  118026. } else {
  118027. queryString = queryString.replace('[bboxWest]', '-180');
  118028. queryString = queryString.replace('[bboxSouth]', '-90');
  118029. queryString = queryString.replace('[bboxEast]', '180');
  118030. queryString = queryString.replace('[bboxNorth]', '90');
  118031. queryString = queryString.replace('[lookatLon]', '');
  118032. queryString = queryString.replace('[lookatLat]', '');
  118033. queryString = queryString.replace('[lookatRange]', '');
  118034. queryString = queryString.replace('[lookatTilt]', '');
  118035. queryString = queryString.replace('[lookatHeading]', '');
  118036. queryString = queryString.replace('[lookatTerrainLon]', '');
  118037. queryString = queryString.replace('[lookatTerrainLat]', '');
  118038. queryString = queryString.replace('[lookatTerrainAlt]', '');
  118039. queryString = queryString.replace('[cameraLon]', '');
  118040. queryString = queryString.replace('[cameraLat]', '');
  118041. queryString = queryString.replace('[cameraAlt]', '');
  118042. queryString = queryString.replace('[horizFov]', '');
  118043. queryString = queryString.replace('[vertFov]', '');
  118044. }
  118045. if (defined(canvas)) {
  118046. queryString = queryString.replace('[horizPixels]', canvas.clientWidth);
  118047. queryString = queryString.replace('[vertPixels]', canvas.clientHeight);
  118048. } else {
  118049. queryString = queryString.replace('[horizPixels]', '');
  118050. queryString = queryString.replace('[vertPixels]', '');
  118051. }
  118052. queryString = queryString.replace('[terrainEnabled]', '1');
  118053. queryString = queryString.replace('[clientVersion]', '1');
  118054. queryString = queryString.replace('[kmlVersion]', '2.2');
  118055. queryString = queryString.replace('[clientName]', 'Cesium');
  118056. queryString = queryString.replace('[language]', 'English');
  118057. return queryString;
  118058. }
  118059. function processNetworkLink(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context) {
  118060. var r = processFeature(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context);
  118061. var networkEntity = r.entity;
  118062. var link = queryFirstNode(node, 'Link', namespaces.kml);
  118063. if(!defined(link)){
  118064. link = queryFirstNode(node, 'Url', namespaces.kml);
  118065. }
  118066. if (defined(link)) {
  118067. var href = queryStringValue(link, 'href', namespaces.kml);
  118068. if (defined(href)) {
  118069. var newSourceUri = href;
  118070. href = resolveHref(href, undefined, sourceUri, uriResolver);
  118071. var linkUrl;
  118072. // We need to pass in the original path if resolveHref returns a data uri because the network link
  118073. // references a document in a KMZ archive
  118074. if (/^data:/.test(href)) {
  118075. // No need to build a query string for a data uri, just use as is
  118076. linkUrl = href;
  118077. // So if sourceUri isn't the kmz file, then its another kml in the archive, so resolve it
  118078. if (!/\.kmz/i.test(sourceUri)) {
  118079. newSourceUri = getAbsoluteUri(newSourceUri, sourceUri);
  118080. }
  118081. } else {
  118082. newSourceUri = href; // Not a data uri so use the fully qualified uri
  118083. var viewRefreshMode = queryStringValue(link, 'viewRefreshMode', namespaces.kml);
  118084. var viewBoundScale = defaultValue(queryStringValue(link, 'viewBoundScale', namespaces.kml), 1.0);
  118085. var defaultViewFormat = (viewRefreshMode === 'onStop') ? 'BBOX=[bboxWest],[bboxSouth],[bboxEast],[bboxNorth]' : '';
  118086. var viewFormat = defaultValue(queryStringValue(link, 'viewFormat', namespaces.kml), defaultViewFormat);
  118087. var httpQuery = queryStringValue(link, 'httpQuery', namespaces.kml);
  118088. var queryString = makeQueryString(viewFormat, httpQuery);
  118089. linkUrl = processNetworkLinkQueryString(dataSource._camera, dataSource._canvas, joinUrls(href, queryString, false),
  118090. viewBoundScale, dataSource._lastCameraView.bbox);
  118091. }
  118092. var options = {
  118093. sourceUri : newSourceUri,
  118094. uriResolver : uriResolver,
  118095. context : networkEntity.id
  118096. };
  118097. var networkLinkCollection = new EntityCollection();
  118098. var promise = load(dataSource, networkLinkCollection, linkUrl, options).then(function(rootElement) {
  118099. var entities = dataSource._entityCollection;
  118100. var newEntities = networkLinkCollection.values;
  118101. entities.suspendEvents();
  118102. for (var i = 0; i < newEntities.length; i++) {
  118103. var newEntity = newEntities[i];
  118104. if (!defined(newEntity.parent)) {
  118105. newEntity.parent = networkEntity;
  118106. mergeAvailabilityWithParent(newEntity);
  118107. }
  118108. entities.add(newEntity);
  118109. }
  118110. entities.resumeEvents();
  118111. // Add network links to a list if we need they will need to be updated
  118112. var refreshMode = queryStringValue(link, 'refreshMode', namespaces.kml);
  118113. var refreshInterval = defaultValue(queryNumericValue(link, 'refreshInterval', namespaces.kml), 0);
  118114. if ((refreshMode === 'onInterval' && refreshInterval > 0 ) || (refreshMode === 'onExpire') || (viewRefreshMode === 'onStop')) {
  118115. var networkLinkControl = queryFirstNode(rootElement, 'NetworkLinkControl', namespaces.kml);
  118116. var hasNetworkLinkControl = defined(networkLinkControl);
  118117. var now = JulianDate.now();
  118118. var networkLinkInfo = {
  118119. id : createGuid(),
  118120. href : href,
  118121. cookie : '',
  118122. queryString : queryString,
  118123. lastUpdated : now,
  118124. updating : false,
  118125. entity : networkEntity,
  118126. viewBoundScale : viewBoundScale,
  118127. needsUpdate : false,
  118128. cameraUpdateTime : now
  118129. };
  118130. var minRefreshPeriod = 0;
  118131. if (hasNetworkLinkControl) {
  118132. networkLinkInfo.cookie = defaultValue(queryStringValue(networkLinkControl, 'cookie', namespaces.kml), '');
  118133. minRefreshPeriod = defaultValue(queryNumericValue(networkLinkControl, 'minRefreshPeriod', namespaces.kml), 0);
  118134. }
  118135. if (refreshMode === 'onInterval') {
  118136. if (hasNetworkLinkControl) {
  118137. refreshInterval = Math.max(minRefreshPeriod, refreshInterval);
  118138. }
  118139. networkLinkInfo.refreshMode = RefreshMode.INTERVAL;
  118140. networkLinkInfo.time = refreshInterval;
  118141. } else if (refreshMode === 'onExpire') {
  118142. var expires;
  118143. if (hasNetworkLinkControl) {
  118144. expires = queryStringValue(networkLinkControl, 'expires', namespaces.kml);
  118145. }
  118146. if (defined(expires)) {
  118147. try {
  118148. var date = JulianDate.fromIso8601(expires);
  118149. var diff = JulianDate.secondsDifference(date, now);
  118150. if (diff > 0 && diff < minRefreshPeriod) {
  118151. JulianDate.addSeconds(now, minRefreshPeriod, date);
  118152. }
  118153. networkLinkInfo.refreshMode = RefreshMode.EXPIRE;
  118154. networkLinkInfo.time = date;
  118155. } catch (e) {
  118156. console.log('KML - NetworkLinkControl expires is not a valid date');
  118157. }
  118158. } else {
  118159. console.log('KML - refreshMode of onExpire requires the NetworkLinkControl to have an expires element');
  118160. }
  118161. } else {
  118162. if (dataSource._camera) { // Only allow onStop refreshes if we have a camera
  118163. networkLinkInfo.refreshMode = RefreshMode.STOP;
  118164. networkLinkInfo.time = defaultValue(queryNumericValue(link, 'viewRefreshTime', namespaces.kml), 0);
  118165. } else {
  118166. console.log('A NetworkLink with viewRefreshMode=onStop requires a camera be passed in when creating the KmlDataSource');
  118167. }
  118168. }
  118169. if (defined(networkLinkInfo.refreshMode)) {
  118170. dataSource._networkLinks.set(networkLinkInfo.id, networkLinkInfo);
  118171. }
  118172. } else if (viewRefreshMode === 'onRegion'){
  118173. console.log('KML - Unsupported viewRefreshMode: onRegion');
  118174. }
  118175. });
  118176. promises.push(promise);
  118177. }
  118178. }
  118179. }
  118180. // Ensure Specs/Data/KML/unsupported.kml is kept up to date with these supported types
  118181. var featureTypes = {
  118182. Document : processDocument,
  118183. Folder : processFolder,
  118184. Placemark : processPlacemark,
  118185. NetworkLink : processNetworkLink,
  118186. GroundOverlay : processGroundOverlay,
  118187. PhotoOverlay : processUnsupportedFeature,
  118188. ScreenOverlay : processUnsupportedFeature,
  118189. Tour : processUnsupportedFeature
  118190. };
  118191. function processFeatureNode(dataSource, node, parent, entityCollection, styleCollection, sourceUri, uriResolver, promises, context) {
  118192. var featureProcessor = featureTypes[node.localName];
  118193. if (defined(featureProcessor)) {
  118194. featureProcessor(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context);
  118195. } else {
  118196. processUnsupportedFeature(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context);
  118197. }
  118198. }
  118199. function loadKml(dataSource, entityCollection, kml, sourceUri, uriResolver, context) {
  118200. entityCollection.removeAll();
  118201. var promises = [];
  118202. var documentElement = kml.documentElement;
  118203. var document = documentElement.localName === 'Document' ? documentElement : queryFirstNode(documentElement, 'Document', namespaces.kml);
  118204. var name = queryStringValue(document, 'name', namespaces.kml);
  118205. if (!defined(name) && defined(sourceUri)) {
  118206. name = getFilenameFromUri(sourceUri);
  118207. }
  118208. // Only set the name from the root document
  118209. if (!defined(dataSource._name)) {
  118210. dataSource._name = name;
  118211. }
  118212. var styleCollection = new EntityCollection(dataSource);
  118213. return when.all(processStyles(dataSource, kml, styleCollection, sourceUri, false, uriResolver, context)).then(function() {
  118214. var element = kml.documentElement;
  118215. if (element.localName === 'kml') {
  118216. var childNodes = element.childNodes;
  118217. for (var i = 0; i < childNodes.length; i++) {
  118218. var tmp = childNodes[i];
  118219. if (defined(featureTypes[tmp.localName])) {
  118220. element = tmp;
  118221. break;
  118222. }
  118223. }
  118224. }
  118225. entityCollection.suspendEvents();
  118226. processFeatureNode(dataSource, element, undefined, entityCollection, styleCollection, sourceUri, uriResolver, promises, context);
  118227. entityCollection.resumeEvents();
  118228. return when.all(promises).then(function() {
  118229. return kml.documentElement;
  118230. });
  118231. });
  118232. }
  118233. function loadKmz(dataSource, entityCollection, blob, sourceUri) {
  118234. var deferred = when.defer();
  118235. zip.createReader(new zip.BlobReader(blob), function(reader) {
  118236. reader.getEntries(function(entries) {
  118237. var promises = [];
  118238. var uriResolver = {};
  118239. var docEntry;
  118240. var docDefer;
  118241. for (var i = 0; i < entries.length; i++) {
  118242. var entry = entries[i];
  118243. if (!entry.directory) {
  118244. var innerDefer = when.defer();
  118245. promises.push(innerDefer.promise);
  118246. if (/\.kml$/i.test(entry.filename)) {
  118247. // We use the first KML document we come across
  118248. // https://developers.google.com/kml/documentation/kmzarchives
  118249. // Unless we come across a .kml file at the root of the archive because GE does this
  118250. if (!defined(docEntry) || !/\//i.test(entry.filename)) {
  118251. if (defined(docEntry)) {
  118252. // We found one at the root so load the initial kml as a data uri
  118253. loadDataUriFromZip(reader, docEntry, uriResolver, docDefer);
  118254. }
  118255. docEntry = entry;
  118256. docDefer = innerDefer;
  118257. } else {
  118258. // Wasn't the first kml and wasn't at the root
  118259. loadDataUriFromZip(reader, entry, uriResolver, innerDefer);
  118260. }
  118261. } else {
  118262. loadDataUriFromZip(reader, entry, uriResolver, innerDefer);
  118263. }
  118264. }
  118265. }
  118266. // Now load the root KML document
  118267. if (defined(docEntry)) {
  118268. loadXmlFromZip(reader, docEntry, uriResolver, docDefer);
  118269. }
  118270. when.all(promises).then(function() {
  118271. reader.close();
  118272. if (!defined(uriResolver.kml)) {
  118273. deferred.reject(new RuntimeError('KMZ file does not contain a KML document.'));
  118274. return;
  118275. }
  118276. uriResolver.keys = Object.keys(uriResolver);
  118277. return loadKml(dataSource, entityCollection, uriResolver.kml, sourceUri, uriResolver);
  118278. }).then(deferred.resolve).otherwise(deferred.reject);
  118279. });
  118280. }, function(e) {
  118281. deferred.reject(e);
  118282. });
  118283. return deferred.promise;
  118284. }
  118285. function load(dataSource, entityCollection, data, options) {
  118286. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  118287. var sourceUri = options.sourceUri;
  118288. var uriResolver = options.uriResolver;
  118289. var context = options.context;
  118290. var promise = data;
  118291. if (typeof data === 'string') {
  118292. promise = loadBlob(proxyUrl(data, dataSource._proxy));
  118293. sourceUri = defaultValue(sourceUri, data);
  118294. }
  118295. return when(promise)
  118296. .then(function(dataToLoad) {
  118297. if (dataToLoad instanceof Blob) {
  118298. return isZipFile(dataToLoad).then(function(isZip) {
  118299. if (isZip) {
  118300. return loadKmz(dataSource, entityCollection, dataToLoad, sourceUri);
  118301. }
  118302. return readBlobAsText(dataToLoad).then(function(text) {
  118303. //There's no official way to validate if a parse was successful.
  118304. //The following check detects the error on various browsers.
  118305. //IE raises an exception
  118306. var kml;
  118307. var error;
  118308. try {
  118309. kml = parser.parseFromString(text, 'application/xml');
  118310. } catch (e) {
  118311. error = e.toString();
  118312. }
  118313. //The parse succeeds on Chrome and Firefox, but the error
  118314. //handling is different in each.
  118315. if (defined(error) || kml.body || kml.documentElement.tagName === 'parsererror') {
  118316. //Firefox has error information as the firstChild nodeValue.
  118317. var msg = defined(error) ? error : kml.documentElement.firstChild.nodeValue;
  118318. //Chrome has it in the body text.
  118319. if (!msg) {
  118320. msg = kml.body.innerText;
  118321. }
  118322. //Return the error
  118323. throw new RuntimeError(msg);
  118324. }
  118325. return loadKml(dataSource, entityCollection, kml, sourceUri, uriResolver, context);
  118326. });
  118327. });
  118328. } else {
  118329. return loadKml(dataSource, entityCollection, dataToLoad, sourceUri, uriResolver, context);
  118330. }
  118331. })
  118332. .otherwise(function(error) {
  118333. dataSource._error.raiseEvent(dataSource, error);
  118334. console.log(error);
  118335. return when.reject(error);
  118336. });
  118337. }
  118338. /**
  118339. * A {@link DataSource} which processes Keyhole Markup Language 2.2 (KML).
  118340. * <p>
  118341. * KML support in Cesium is incomplete, but a large amount of the standard,
  118342. * as well as Google's <code>gx</code> extension namespace, is supported. See Github issue
  118343. * {@link https://github.com/AnalyticalGraphicsInc/cesium/issues/873|#873} for a
  118344. * detailed list of what is and isn't support. Cesium will also write information to the
  118345. * console when it encounters most unsupported features.
  118346. * </p>
  118347. * <p>
  118348. * Non visual feature data, such as <code>atom:author</code> and <code>ExtendedData</code>
  118349. * is exposed via an instance of {@link KmlFeatureData}, which is added to each {@link Entity}
  118350. * under the <code>kml</code> property.
  118351. * </p>
  118352. *
  118353. * @alias KmlDataSource
  118354. * @constructor
  118355. *
  118356. * @param {Camera} options.camera The camera that is used for viewRefreshModes and sending camera properties to network links.
  118357. * @param {Canvas} options.canvas The canvas that is used for sending viewer properties to network links.
  118358. * @param {DefaultProxy} [options.proxy] A proxy to be used for loading external data.
  118359. *
  118360. * @see {@link http://www.opengeospatial.org/standards/kml/|Open Geospatial Consortium KML Standard}
  118361. * @see {@link https://developers.google.com/kml/|Google KML Documentation}
  118362. *
  118363. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=KML.html|Cesium Sandcastle KML Demo}
  118364. *
  118365. * @example
  118366. * var viewer = new Cesium.Viewer('cesiumContainer');
  118367. * viewer.dataSources.add(Cesium.KmlDataSource.load('../../SampleData/facilities.kmz'),
  118368. * {
  118369. * camera: viewer.scene.camera,
  118370. * canvas: viewer.scene.canvas
  118371. * });
  118372. */
  118373. function KmlDataSource(options) {
  118374. options = defaultValue(options, {});
  118375. var camera = options.camera;
  118376. var canvas = options.canvas;
  118377. if (!defined(camera)) {
  118378. throw new DeveloperError('options.camera is required.');
  118379. }
  118380. if (!defined(canvas)) {
  118381. throw new DeveloperError('options.canvas is required.');
  118382. }
  118383. this._changed = new Event();
  118384. this._error = new Event();
  118385. this._loading = new Event();
  118386. this._refresh = new Event();
  118387. this._unsupportedNode = new Event();
  118388. this._clock = undefined;
  118389. this._entityCollection = new EntityCollection(this);
  118390. this._name = undefined;
  118391. this._isLoading = false;
  118392. this._proxy = options.proxy;
  118393. this._pinBuilder = new PinBuilder();
  118394. this._networkLinks = new AssociativeArray();
  118395. this._entityCluster = new EntityCluster();
  118396. this._canvas = canvas;
  118397. this._camera = camera;
  118398. this._lastCameraView = {
  118399. position : defined(camera) ? Cartesian3.clone(camera.positionWC) : undefined,
  118400. direction : defined(camera) ? Cartesian3.clone(camera.directionWC) : undefined,
  118401. up : defined(camera) ? Cartesian3.clone(camera.upWC) : undefined,
  118402. bbox : defined(camera) ? camera.computeViewRectangle() : Rectangle.clone(Rectangle.MAX_VALUE)
  118403. };
  118404. }
  118405. /**
  118406. * Creates a Promise to a new instance loaded with the provided KML data.
  118407. *
  118408. * @param {String|Document|Blob} data A url, parsed KML document, or Blob containing binary KMZ data or a parsed KML document.
  118409. * @param {Object} [options] An object with the following properties:
  118410. * @param {Camera} options.camera The camera that is used for viewRefreshModes and sending camera properties to network links.
  118411. * @param {Canvas} options.canvas The canvas that is used for sending viewer properties to network links.
  118412. * @param {DefaultProxy} [options.proxy] A proxy to be used for loading external data.
  118413. * @param {String} [options.sourceUri] Overrides the url to use for resolving relative links and other KML network features.
  118414. * @param {Boolean} [options.clampToGround=false] true if we want the geometry features (Polygons, LineStrings and LinearRings) clamped to the ground. If true, lines will use corridors so use Entity.corridor instead of Entity.polyline.
  118415. *
  118416. * @returns {Promise.<KmlDataSource>} A promise that will resolve to a new KmlDataSource instance once the KML is loaded.
  118417. */
  118418. KmlDataSource.load = function(data, options) {
  118419. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  118420. var dataSource = new KmlDataSource(options);
  118421. return dataSource.load(data, options);
  118422. };
  118423. defineProperties(KmlDataSource.prototype, {
  118424. /**
  118425. * Gets a human-readable name for this instance.
  118426. * This will be automatically be set to the KML document name on load.
  118427. * @memberof KmlDataSource.prototype
  118428. * @type {String}
  118429. */
  118430. name : {
  118431. get : function() {
  118432. return this._name;
  118433. }
  118434. },
  118435. /**
  118436. * Gets the clock settings defined by the loaded KML. This represents the total
  118437. * availability interval for all time-dynamic data. If the KML does not contain
  118438. * time-dynamic data, this value is undefined.
  118439. * @memberof KmlDataSource.prototype
  118440. * @type {DataSourceClock}
  118441. */
  118442. clock : {
  118443. get : function() {
  118444. return this._clock;
  118445. }
  118446. },
  118447. /**
  118448. * Gets the collection of {@link Entity} instances.
  118449. * @memberof KmlDataSource.prototype
  118450. * @type {EntityCollection}
  118451. */
  118452. entities : {
  118453. get : function() {
  118454. return this._entityCollection;
  118455. }
  118456. },
  118457. /**
  118458. * Gets a value indicating if the data source is currently loading data.
  118459. * @memberof KmlDataSource.prototype
  118460. * @type {Boolean}
  118461. */
  118462. isLoading : {
  118463. get : function() {
  118464. return this._isLoading;
  118465. }
  118466. },
  118467. /**
  118468. * Gets an event that will be raised when the underlying data changes.
  118469. * @memberof KmlDataSource.prototype
  118470. * @type {Event}
  118471. */
  118472. changedEvent : {
  118473. get : function() {
  118474. return this._changed;
  118475. }
  118476. },
  118477. /**
  118478. * Gets an event that will be raised if an error is encountered during processing.
  118479. * @memberof KmlDataSource.prototype
  118480. * @type {Event}
  118481. */
  118482. errorEvent : {
  118483. get : function() {
  118484. return this._error;
  118485. }
  118486. },
  118487. /**
  118488. * Gets an event that will be raised when the data source either starts or stops loading.
  118489. * @memberof KmlDataSource.prototype
  118490. * @type {Event}
  118491. */
  118492. loadingEvent : {
  118493. get : function() {
  118494. return this._loading;
  118495. }
  118496. },
  118497. /**
  118498. * Gets an event that will be raised when the data source refreshes a network link.
  118499. * @memberof KmlDataSource.prototype
  118500. * @type {Event}
  118501. */
  118502. refreshEvent : {
  118503. get : function() {
  118504. return this._refresh;
  118505. }
  118506. },
  118507. /**
  118508. * Gets an event that will be raised when the data source finds an unsupported node type.
  118509. * @memberof KmlDataSource.prototype
  118510. * @type {Event}
  118511. */
  118512. unsupportedNodeEvent : {
  118513. get : function() {
  118514. return this._unsupportedNode;
  118515. }
  118516. },
  118517. /**
  118518. * Gets whether or not this data source should be displayed.
  118519. * @memberof KmlDataSource.prototype
  118520. * @type {Boolean}
  118521. */
  118522. show : {
  118523. get : function() {
  118524. return this._entityCollection.show;
  118525. },
  118526. set : function(value) {
  118527. this._entityCollection.show = value;
  118528. }
  118529. },
  118530. /**
  118531. * Gets or sets the clustering options for this data source. This object can be shared between multiple data sources.
  118532. *
  118533. * @memberof KmlDataSource.prototype
  118534. * @type {EntityCluster}
  118535. */
  118536. clustering : {
  118537. get : function() {
  118538. return this._entityCluster;
  118539. },
  118540. set : function(value) {
  118541. if (!defined(value)) {
  118542. throw new DeveloperError('value must be defined.');
  118543. }
  118544. this._entityCluster = value;
  118545. }
  118546. }
  118547. });
  118548. /**
  118549. * Asynchronously loads the provided KML data, replacing any existing data.
  118550. *
  118551. * @param {String|Document|Blob} data A url, parsed KML document, or Blob containing binary KMZ data or a parsed KML document.
  118552. * @param {Object} [options] An object with the following properties:
  118553. * @param {Number} [options.sourceUri] Overrides the url to use for resolving relative links and other KML network features.
  118554. * @returns {Promise.<KmlDataSource>} A promise that will resolve to this instances once the KML is loaded.
  118555. * @param {Boolean} [options.clampToGround=false] true if we want the geometry features (Polygons, LineStrings and LinearRings) clamped to the ground. If true, lines will use corridors so use Entity.corridor instead of Entity.polyline.
  118556. */
  118557. KmlDataSource.prototype.load = function(data, options) {
  118558. if (!defined(data)) {
  118559. throw new DeveloperError('data is required.');
  118560. }
  118561. options = defaultValue(options, {});
  118562. DataSource.setLoading(this, true);
  118563. var oldName = this._name;
  118564. this._name = undefined;
  118565. this._clampToGround = defaultValue(options.clampToGround, false);
  118566. var that = this;
  118567. return load(this, this._entityCollection, data, options).then(function() {
  118568. var clock;
  118569. var availability = that._entityCollection.computeAvailability();
  118570. var start = availability.start;
  118571. var stop = availability.stop;
  118572. var isMinStart = JulianDate.equals(start, Iso8601.MINIMUM_VALUE);
  118573. var isMaxStop = JulianDate.equals(stop, Iso8601.MAXIMUM_VALUE);
  118574. if (!isMinStart || !isMaxStop) {
  118575. var date;
  118576. //If start is min time just start at midnight this morning, local time
  118577. if (isMinStart) {
  118578. date = new Date();
  118579. date.setHours(0, 0, 0, 0);
  118580. start = JulianDate.fromDate(date);
  118581. }
  118582. //If stop is max value just stop at midnight tonight, local time
  118583. if (isMaxStop) {
  118584. date = new Date();
  118585. date.setHours(24, 0, 0, 0);
  118586. stop = JulianDate.fromDate(date);
  118587. }
  118588. clock = new DataSourceClock();
  118589. clock.startTime = start;
  118590. clock.stopTime = stop;
  118591. clock.currentTime = JulianDate.clone(start);
  118592. clock.clockRange = ClockRange.LOOP_STOP;
  118593. clock.clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER;
  118594. clock.multiplier = Math.round(Math.min(Math.max(JulianDate.secondsDifference(stop, start) / 60, 1), 3.15569e7));
  118595. }
  118596. var changed = false;
  118597. if (clock !== that._clock) {
  118598. that._clock = clock;
  118599. changed = true;
  118600. }
  118601. if (oldName !== that._name) {
  118602. changed = true;
  118603. }
  118604. if (changed) {
  118605. that._changed.raiseEvent(that);
  118606. }
  118607. DataSource.setLoading(that, false);
  118608. return that;
  118609. }).otherwise(function(error) {
  118610. DataSource.setLoading(that, false);
  118611. that._error.raiseEvent(that, error);
  118612. console.log(error);
  118613. return when.reject(error);
  118614. });
  118615. };
  118616. function mergeAvailabilityWithParent(child) {
  118617. var parent = child.parent;
  118618. if (defined(parent)) {
  118619. var parentAvailability = parent.availability;
  118620. if (defined(parentAvailability)) {
  118621. var childAvailability = child.availability;
  118622. if (defined(childAvailability)) {
  118623. childAvailability.intersect(parentAvailability);
  118624. } else {
  118625. child.availability = parentAvailability;
  118626. }
  118627. }
  118628. }
  118629. }
  118630. function getNetworkLinkUpdateCallback(dataSource, networkLink, newEntityCollection, networkLinks, processedHref) {
  118631. return function(rootElement) {
  118632. if (!networkLinks.contains(networkLink.id)) {
  118633. // Got into the odd case where a parent network link was updated while a child
  118634. // network link update was in flight, so just throw it away.
  118635. return;
  118636. }
  118637. var remove = false;
  118638. var networkLinkControl = queryFirstNode(rootElement, 'NetworkLinkControl', namespaces.kml);
  118639. var hasNetworkLinkControl = defined(networkLinkControl);
  118640. var minRefreshPeriod = 0;
  118641. if (hasNetworkLinkControl) {
  118642. if (defined(queryFirstNode(networkLinkControl, 'Update', namespaces.kml))) {
  118643. console.log('KML - NetworkLinkControl updates aren\'t supported.');
  118644. networkLink.updating = false;
  118645. networkLinks.remove(networkLink.id);
  118646. return;
  118647. }
  118648. networkLink.cookie = defaultValue(queryStringValue(networkLinkControl, 'cookie', namespaces.kml), '');
  118649. minRefreshPeriod = defaultValue(queryNumericValue(networkLinkControl, 'minRefreshPeriod', namespaces.kml), 0);
  118650. }
  118651. var now = JulianDate.now();
  118652. var refreshMode = networkLink.refreshMode;
  118653. if (refreshMode === RefreshMode.INTERVAL) {
  118654. if (defined(networkLinkControl)) {
  118655. networkLink.time = Math.max(minRefreshPeriod, networkLink.time);
  118656. }
  118657. } else if (refreshMode === RefreshMode.EXPIRE) {
  118658. var expires;
  118659. if (defined(networkLinkControl)) {
  118660. expires = queryStringValue(networkLinkControl, 'expires', namespaces.kml);
  118661. }
  118662. if (defined(expires)) {
  118663. try {
  118664. var date = JulianDate.fromIso8601(expires);
  118665. var diff = JulianDate.secondsDifference(date, now);
  118666. if (diff > 0 && diff < minRefreshPeriod) {
  118667. JulianDate.addSeconds(now, minRefreshPeriod, date);
  118668. }
  118669. networkLink.time = date;
  118670. } catch (e) {
  118671. console.log('KML - NetworkLinkControl expires is not a valid date');
  118672. remove = true;
  118673. }
  118674. } else {
  118675. console.log('KML - refreshMode of onExpire requires the NetworkLinkControl to have an expires element');
  118676. remove = true;
  118677. }
  118678. }
  118679. var networkLinkEntity = networkLink.entity;
  118680. var entityCollection = dataSource._entityCollection;
  118681. var newEntities = newEntityCollection.values;
  118682. function removeChildren(entity) {
  118683. entityCollection.remove(entity);
  118684. var children = entity._children;
  118685. var count = children.length;
  118686. for(var i=0;i<count;++i) {
  118687. removeChildren(children[i]);
  118688. }
  118689. }
  118690. // Remove old entities
  118691. entityCollection.suspendEvents();
  118692. var entitiesCopy = entityCollection.values.slice();
  118693. for (var i=0;i<entitiesCopy.length;++i) {
  118694. var entityToRemove = entitiesCopy[i];
  118695. if (entityToRemove.parent === networkLinkEntity) {
  118696. entityToRemove.parent = undefined;
  118697. removeChildren(entityToRemove);
  118698. }
  118699. }
  118700. entityCollection.resumeEvents();
  118701. // Add new entities
  118702. entityCollection.suspendEvents();
  118703. for (i = 0; i < newEntities.length; i++) {
  118704. var newEntity = newEntities[i];
  118705. if (!defined(newEntity.parent)) {
  118706. newEntity.parent = networkLinkEntity;
  118707. mergeAvailabilityWithParent(newEntity);
  118708. }
  118709. entityCollection.add(newEntity);
  118710. }
  118711. entityCollection.resumeEvents();
  118712. // No refresh information remove it, otherwise update lastUpdate time
  118713. if (remove) {
  118714. networkLinks.remove(networkLink.id);
  118715. } else {
  118716. networkLink.lastUpdated = now;
  118717. }
  118718. var availability = entityCollection.computeAvailability();
  118719. var start = availability.start;
  118720. var stop = availability.stop;
  118721. var isMinStart = JulianDate.equals(start, Iso8601.MINIMUM_VALUE);
  118722. var isMaxStop = JulianDate.equals(stop, Iso8601.MAXIMUM_VALUE);
  118723. if (!isMinStart || !isMaxStop) {
  118724. var clock = dataSource._clock;
  118725. if (clock.startTime !== start || clock.stopTime !== stop) {
  118726. clock.startTime = start;
  118727. clock.stopTime = stop;
  118728. dataSource._changed.raiseEvent(dataSource);
  118729. }
  118730. }
  118731. networkLink.updating = false;
  118732. networkLink.needsUpdate = false;
  118733. dataSource._refresh.raiseEvent(dataSource, processedHref);
  118734. };
  118735. }
  118736. var entitiesToIgnore = new AssociativeArray();
  118737. /**
  118738. * Updates any NetworkLink that require updating
  118739. * @function
  118740. *
  118741. * @param {JulianDate} time The simulation time.
  118742. * @returns {Boolean} True if this data source is ready to be displayed at the provided time, false otherwise.
  118743. */
  118744. KmlDataSource.prototype.update = function(time) {
  118745. var networkLinks = this._networkLinks;
  118746. if (networkLinks.length === 0) {
  118747. return true;
  118748. }
  118749. var now = JulianDate.now();
  118750. var that = this;
  118751. entitiesToIgnore.removeAll();
  118752. function recurseIgnoreEntities(entity) {
  118753. var children = entity._children;
  118754. var count = children.length;
  118755. for (var i=0;i<count;++i) {
  118756. var child = children[i];
  118757. entitiesToIgnore.set(child.id, child);
  118758. recurseIgnoreEntities(child);
  118759. }
  118760. }
  118761. var cameraViewUpdate = false;
  118762. var lastCameraView = this._lastCameraView;
  118763. var camera = this._camera;
  118764. if (defined(camera) &&
  118765. !(camera.positionWC.equalsEpsilon(lastCameraView.position, CesiumMath.EPSILON7) &&
  118766. camera.directionWC.equalsEpsilon(lastCameraView.direction, CesiumMath.EPSILON7) &&
  118767. camera.upWC.equalsEpsilon(lastCameraView.up, CesiumMath.EPSILON7))) {
  118768. // Camera has changed so update the last view
  118769. lastCameraView.position = Cartesian3.clone(camera.positionWC);
  118770. lastCameraView.direction = Cartesian3.clone(camera.directionWC);
  118771. lastCameraView.up = Cartesian3.clone(camera.upWC);
  118772. lastCameraView.bbox = camera.computeViewRectangle();
  118773. cameraViewUpdate = true;
  118774. }
  118775. var newNetworkLinks = new AssociativeArray();
  118776. var changed = false;
  118777. networkLinks.values.forEach(function(networkLink) {
  118778. var entity = networkLink.entity;
  118779. if (entitiesToIgnore.contains(entity.id)) {
  118780. return;
  118781. }
  118782. if (!networkLink.updating) {
  118783. var doUpdate = false;
  118784. if (networkLink.refreshMode === RefreshMode.INTERVAL) {
  118785. if (JulianDate.secondsDifference(now, networkLink.lastUpdated) > networkLink.time) {
  118786. doUpdate = true;
  118787. }
  118788. }
  118789. else if (networkLink.refreshMode === RefreshMode.EXPIRE) {
  118790. if (JulianDate.greaterThan(now, networkLink.time)) {
  118791. doUpdate = true;
  118792. }
  118793. } else if (networkLink.refreshMode === RefreshMode.STOP) {
  118794. if (cameraViewUpdate) {
  118795. networkLink.needsUpdate = true;
  118796. networkLink.cameraUpdateTime = now;
  118797. }
  118798. if (networkLink.needsUpdate && JulianDate.secondsDifference(now, networkLink.cameraUpdateTime) >= networkLink.time) {
  118799. doUpdate = true;
  118800. }
  118801. }
  118802. if (doUpdate) {
  118803. recurseIgnoreEntities(entity);
  118804. networkLink.updating = true;
  118805. var newEntityCollection = new EntityCollection();
  118806. var href = joinUrls(networkLink.href, makeQueryString(networkLink.cookie, networkLink.queryString), false);
  118807. href = processNetworkLinkQueryString(that._camera, that._canvas, href, networkLink.viewBoundScale, lastCameraView.bbox);
  118808. load(that, newEntityCollection, href, {context: entity.id})
  118809. .then(getNetworkLinkUpdateCallback(that, networkLink, newEntityCollection, newNetworkLinks, href))
  118810. .otherwise(function(error) {
  118811. var msg = 'NetworkLink ' + networkLink.href + ' refresh failed: ' + error;
  118812. console.log(msg);
  118813. that._error.raiseEvent(that, msg);
  118814. });
  118815. changed = true;
  118816. }
  118817. }
  118818. newNetworkLinks.set(networkLink.id, networkLink);
  118819. });
  118820. if (changed) {
  118821. this._networkLinks = newNetworkLinks;
  118822. this._changed.raiseEvent(this);
  118823. }
  118824. return true;
  118825. };
  118826. /**
  118827. * Contains KML Feature data loaded into the <code>Entity.kml</code> property by {@link KmlDataSource}.
  118828. * @alias KmlFeatureData
  118829. * @constructor
  118830. */
  118831. function KmlFeatureData() {
  118832. /**
  118833. * Gets the atom syndication format author field.
  118834. * @type Object
  118835. */
  118836. this.author = {
  118837. /**
  118838. * Gets the name.
  118839. * @type String
  118840. * @alias author.name
  118841. * @memberof! KmlFeatureData#
  118842. * @property author.name
  118843. */
  118844. name : undefined,
  118845. /**
  118846. * Gets the URI.
  118847. * @type String
  118848. * @alias author.uri
  118849. * @memberof! KmlFeatureData#
  118850. * @property author.uri
  118851. */
  118852. uri : undefined,
  118853. /**
  118854. * Gets the email.
  118855. * @type String
  118856. * @alias author.email
  118857. * @memberof! KmlFeatureData#
  118858. * @property author.email
  118859. */
  118860. email : undefined
  118861. };
  118862. /**
  118863. * Gets the link.
  118864. * @type Object
  118865. */
  118866. this.link = {
  118867. /**
  118868. * Gets the href.
  118869. * @type String
  118870. * @alias link.href
  118871. * @memberof! KmlFeatureData#
  118872. * @property link.href
  118873. */
  118874. href : undefined,
  118875. /**
  118876. * Gets the language of the linked resource.
  118877. * @type String
  118878. * @alias link.hreflang
  118879. * @memberof! KmlFeatureData#
  118880. * @property link.hreflang
  118881. */
  118882. hreflang : undefined,
  118883. /**
  118884. * Gets the link relation.
  118885. * @type String
  118886. * @alias link.rel
  118887. * @memberof! KmlFeatureData#
  118888. * @property link.rel
  118889. */
  118890. rel : undefined,
  118891. /**
  118892. * Gets the link type.
  118893. * @type String
  118894. * @alias link.type
  118895. * @memberof! KmlFeatureData#
  118896. * @property link.type
  118897. */
  118898. type : undefined,
  118899. /**
  118900. * Gets the link title.
  118901. * @type String
  118902. * @alias link.title
  118903. * @memberof! KmlFeatureData#
  118904. * @property link.title
  118905. */
  118906. title : undefined,
  118907. /**
  118908. * Gets the link length.
  118909. * @type String
  118910. * @alias link.length
  118911. * @memberof! KmlFeatureData#
  118912. * @property link.length
  118913. */
  118914. length : undefined
  118915. };
  118916. /**
  118917. * Gets the unstructured address field.
  118918. * @type String
  118919. */
  118920. this.address = undefined;
  118921. /**
  118922. * Gets the phone number.
  118923. * @type String
  118924. */
  118925. this.phoneNumber = undefined;
  118926. /**
  118927. * Gets the snippet.
  118928. * @type String
  118929. */
  118930. this.snippet = undefined;
  118931. /**
  118932. * Gets the extended data, parsed into a JSON object.
  118933. * Currently only the <code>Data</code> property is supported.
  118934. * <code>SchemaData</code> and custom data are ignored.
  118935. * @type String
  118936. */
  118937. this.extendedData = undefined;
  118938. }
  118939. return KmlDataSource;
  118940. });
  118941. /*global define*/
  118942. define('DataSources/VelocityOrientationProperty',[
  118943. '../Core/Cartesian3',
  118944. '../Core/defaultValue',
  118945. '../Core/defined',
  118946. '../Core/defineProperties',
  118947. '../Core/Ellipsoid',
  118948. '../Core/Event',
  118949. '../Core/Matrix3',
  118950. '../Core/Quaternion',
  118951. '../Core/Transforms',
  118952. './Property',
  118953. './VelocityVectorProperty'
  118954. ], function(
  118955. Cartesian3,
  118956. defaultValue,
  118957. defined,
  118958. defineProperties,
  118959. Ellipsoid,
  118960. Event,
  118961. Matrix3,
  118962. Quaternion,
  118963. Transforms,
  118964. Property,
  118965. VelocityVectorProperty) {
  118966. 'use strict';
  118967. /**
  118968. * A {@link Property} which evaluates to a {@link Quaternion} rotation
  118969. * based on the velocity of the provided {@link PositionProperty}.
  118970. *
  118971. * @alias VelocityOrientationProperty
  118972. * @constructor
  118973. *
  118974. * @param {Property} [position] The position property used to compute the orientation.
  118975. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid used to determine which way is up.
  118976. *
  118977. * @example
  118978. * //Create an entity with position and orientation.
  118979. * var position = new Cesium.SampledProperty();
  118980. * position.addSamples(...);
  118981. * var entity = viewer.entities.add({
  118982. * position : position,
  118983. * orientation : new Cesium.VelocityOrientationProperty(position)
  118984. * }));
  118985. */
  118986. function VelocityOrientationProperty(position, ellipsoid) {
  118987. this._velocityVectorProperty = new VelocityVectorProperty(position, true);
  118988. this._subscription = undefined;
  118989. this._ellipsoid = undefined;
  118990. this._definitionChanged = new Event();
  118991. this.ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  118992. var that = this;
  118993. this._velocityVectorProperty.definitionChanged.addEventListener(function() {
  118994. that._definitionChanged.raiseEvent(that);
  118995. });
  118996. }
  118997. defineProperties(VelocityOrientationProperty.prototype, {
  118998. /**
  118999. * Gets a value indicating if this property is constant.
  119000. * @memberof VelocityOrientationProperty.prototype
  119001. *
  119002. * @type {Boolean}
  119003. * @readonly
  119004. */
  119005. isConstant : {
  119006. get : function() {
  119007. return Property.isConstant(this._velocityVectorProperty);
  119008. }
  119009. },
  119010. /**
  119011. * Gets the event that is raised whenever the definition of this property changes.
  119012. * @memberof VelocityOrientationProperty.prototype
  119013. *
  119014. * @type {Event}
  119015. * @readonly
  119016. */
  119017. definitionChanged : {
  119018. get : function() {
  119019. return this._definitionChanged;
  119020. }
  119021. },
  119022. /**
  119023. * Gets or sets the position property used to compute orientation.
  119024. * @memberof VelocityOrientationProperty.prototype
  119025. *
  119026. * @type {Property}
  119027. */
  119028. position : {
  119029. get : function() {
  119030. return this._velocityVectorProperty.position;
  119031. },
  119032. set : function(value) {
  119033. this._velocityVectorProperty.position = value;
  119034. }
  119035. },
  119036. /**
  119037. * Gets or sets the ellipsoid used to determine which way is up.
  119038. * @memberof VelocityOrientationProperty.prototype
  119039. *
  119040. * @type {Property}
  119041. */
  119042. ellipsoid : {
  119043. get : function() {
  119044. return this._ellipsoid;
  119045. },
  119046. set : function(value) {
  119047. var oldValue = this._ellipsoid;
  119048. if (oldValue !== value) {
  119049. this._ellipsoid = value;
  119050. this._definitionChanged.raiseEvent(this);
  119051. }
  119052. }
  119053. }
  119054. });
  119055. var positionScratch = new Cartesian3();
  119056. var velocityScratch = new Cartesian3();
  119057. var rotationScratch = new Matrix3();
  119058. /**
  119059. * Gets the value of the property at the provided time.
  119060. *
  119061. * @param {JulianDate} [time] The time for which to retrieve the value.
  119062. * @param {Quaternion} [result] The object to store the value into, if omitted, a new instance is created and returned.
  119063. * @returns {Quaternion} The modified result parameter or a new instance if the result parameter was not supplied.
  119064. */
  119065. VelocityOrientationProperty.prototype.getValue = function(time, result) {
  119066. var velocity = this._velocityVectorProperty._getValue(time, velocityScratch, positionScratch);
  119067. if (!defined(velocity)) {
  119068. return undefined;
  119069. }
  119070. Transforms.rotationMatrixFromPositionVelocity(positionScratch, velocity, this._ellipsoid, rotationScratch);
  119071. return Quaternion.fromRotationMatrix(rotationScratch, result);
  119072. };
  119073. /**
  119074. * Compares this property to the provided property and returns
  119075. * <code>true</code> if they are equal, <code>false</code> otherwise.
  119076. *
  119077. * @param {Property} [other] The other property.
  119078. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  119079. */
  119080. VelocityOrientationProperty.prototype.equals = function(other) {
  119081. return this === other ||//
  119082. (other instanceof VelocityOrientationProperty &&
  119083. Property.equals(this._velocityVectorProperty, other._velocityVectorProperty) &&
  119084. (this._ellipsoid === other._ellipsoid ||
  119085. this._ellipsoid.equals(other._ellipsoid)));
  119086. };
  119087. return VelocityOrientationProperty;
  119088. });
  119089. /*global define*/
  119090. define('DataSources/Visualizer',[
  119091. '../Core/DeveloperError'
  119092. ], function(
  119093. DeveloperError) {
  119094. 'use strict';
  119095. /**
  119096. * Defines the interface for visualizers. Visualizers are plug-ins to
  119097. * {@link DataSourceDisplay} that render data associated with
  119098. * {@link DataSource} instances.
  119099. * This object is an interface for documentation purposes and is not intended
  119100. * to be instantiated directly.
  119101. * @alias Visualizer
  119102. * @constructor
  119103. *
  119104. * @see BillboardVisualizer
  119105. * @see LabelVisualizer
  119106. * @see ModelVisualizer
  119107. * @see PathVisualizer
  119108. * @see PointVisualizer
  119109. * @see GeometryVisualizer
  119110. */
  119111. function Visualizer() {
  119112. DeveloperError.throwInstantiationError();
  119113. }
  119114. /**
  119115. * Updates the visualization to the provided time.
  119116. * @function
  119117. *
  119118. * @param {JulianDate} time The time.
  119119. *
  119120. * @returns {Boolean} True if the display was updated to the provided time,
  119121. * false if the visualizer is waiting for an asynchronous operation to
  119122. * complete before data can be updated.
  119123. */
  119124. Visualizer.prototype.update = DeveloperError.throwInstantiationError;
  119125. /**
  119126. * Computes a bounding sphere which encloses the visualization produced for the specified entity.
  119127. * The bounding sphere is in the fixed frame of the scene's globe.
  119128. *
  119129. * @param {Entity} entity The entity whose bounding sphere to compute.
  119130. * @param {BoundingSphere} result The bounding sphere onto which to store the result.
  119131. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere,
  119132. * BoundingSphereState.PENDING if the result is still being computed, or
  119133. * BoundingSphereState.FAILED if the entity has no visualization in the current scene.
  119134. * @private
  119135. */
  119136. Visualizer.prototype.getBoundingSphere = DeveloperError.throwInstantiationError;
  119137. /**
  119138. * Returns true if this object was destroyed; otherwise, false.
  119139. * @function
  119140. *
  119141. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  119142. */
  119143. Visualizer.prototype.isDestroyed = DeveloperError.throwInstantiationError;
  119144. /**
  119145. * Removes all visualization and cleans up any resources associated with this instance.
  119146. * @function
  119147. */
  119148. Visualizer.prototype.destroy = DeveloperError.throwInstantiationError;
  119149. return Visualizer;
  119150. });
  119151. /*global define*/
  119152. define('Renderer/ClearCommand',[
  119153. '../Core/Color',
  119154. '../Core/defaultValue',
  119155. '../Core/freezeObject'
  119156. ], function(
  119157. Color,
  119158. defaultValue,
  119159. freezeObject) {
  119160. 'use strict';
  119161. /**
  119162. * Represents a command to the renderer for clearing a framebuffer.
  119163. *
  119164. * @private
  119165. */
  119166. function ClearCommand(options) {
  119167. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  119168. /**
  119169. * The value to clear the color buffer to. When <code>undefined</code>, the color buffer is not cleared.
  119170. *
  119171. * @type {Color}
  119172. *
  119173. * @default undefined
  119174. */
  119175. this.color = options.color;
  119176. /**
  119177. * The value to clear the depth buffer to. When <code>undefined</code>, the depth buffer is not cleared.
  119178. *
  119179. * @type {Number}
  119180. *
  119181. * @default undefined
  119182. */
  119183. this.depth = options.depth;
  119184. /**
  119185. * The value to clear the stencil buffer to. When <code>undefined</code>, the stencil buffer is not cleared.
  119186. *
  119187. * @type {Number}
  119188. *
  119189. * @default undefined
  119190. */
  119191. this.stencil = options.stencil;
  119192. /**
  119193. * The render state to apply when executing the clear command. The following states affect clearing:
  119194. * scissor test, color mask, depth mask, and stencil mask. When the render state is
  119195. * <code>undefined</code>, the default render state is used.
  119196. *
  119197. * @type {RenderState}
  119198. *
  119199. * @default undefined
  119200. */
  119201. this.renderState = options.renderState;
  119202. /**
  119203. * The framebuffer to clear.
  119204. *
  119205. * @type {Framebuffer}
  119206. *
  119207. * @default undefined
  119208. */
  119209. this.framebuffer = options.framebuffer;
  119210. /**
  119211. * The object who created this command. This is useful for debugging command
  119212. * execution; it allows you to see who created a command when you only have a
  119213. * reference to the command, and can be used to selectively execute commands
  119214. * with {@link Scene#debugCommandFilter}.
  119215. *
  119216. * @type {Object}
  119217. *
  119218. * @default undefined
  119219. *
  119220. * @see Scene#debugCommandFilter
  119221. */
  119222. this.owner = options.owner;
  119223. }
  119224. /**
  119225. * Clears color to (0.0, 0.0, 0.0, 0.0); depth to 1.0; and stencil to 0.
  119226. *
  119227. * @type {ClearCommand}
  119228. *
  119229. * @constant
  119230. */
  119231. ClearCommand.ALL = freezeObject(new ClearCommand({
  119232. color : new Color(0.0, 0.0, 0.0, 0.0),
  119233. depth : 1.0,
  119234. stencil : 0.0
  119235. }));
  119236. ClearCommand.prototype.execute = function(context, passState) {
  119237. context.clear(this, passState);
  119238. };
  119239. return ClearCommand;
  119240. });
  119241. /*global define*/
  119242. define('Renderer/ComputeCommand',[
  119243. '../Core/defaultValue',
  119244. './Pass'
  119245. ], function(
  119246. defaultValue,
  119247. Pass) {
  119248. 'use strict';
  119249. /**
  119250. * Represents a command to the renderer for GPU Compute (using old-school GPGPU).
  119251. *
  119252. * @private
  119253. */
  119254. function ComputeCommand(options) {
  119255. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  119256. /**
  119257. * The vertex array. If none is provided, a viewport quad will be used.
  119258. *
  119259. * @type {VertexArray}
  119260. * @default undefined
  119261. */
  119262. this.vertexArray = options.vertexArray;
  119263. /**
  119264. * The fragment shader source. The default vertex shader is ViewportQuadVS.
  119265. *
  119266. * @type {ShaderSource}
  119267. * @default undefined
  119268. */
  119269. this.fragmentShaderSource = options.fragmentShaderSource;
  119270. /**
  119271. * The shader program to apply.
  119272. *
  119273. * @type {ShaderProgram}
  119274. * @default undefined
  119275. */
  119276. this.shaderProgram = options.shaderProgram;
  119277. /**
  119278. * An object with functions whose names match the uniforms in the shader program
  119279. * and return values to set those uniforms.
  119280. *
  119281. * @type {Object}
  119282. * @default undefined
  119283. */
  119284. this.uniformMap = options.uniformMap;
  119285. /**
  119286. * Texture to use for offscreen rendering.
  119287. *
  119288. * @type {Texture}
  119289. * @default undefined
  119290. */
  119291. this.outputTexture = options.outputTexture;
  119292. /**
  119293. * Function that is called immediately before the ComputeCommand is executed. Used to
  119294. * update any renderer resources. Takes the ComputeCommand as its single argument.
  119295. *
  119296. * @type {Function}
  119297. * @default undefined
  119298. */
  119299. this.preExecute = options.preExecute;
  119300. /**
  119301. * Function that is called after the ComputeCommand is executed. Takes the output
  119302. * texture as its single argument.
  119303. *
  119304. * @type {Function}
  119305. * @default undefined
  119306. */
  119307. this.postExecute = options.postExecute;
  119308. /**
  119309. * Whether the renderer resources will persist beyond this call. If not, they
  119310. * will be destroyed after completion.
  119311. *
  119312. * @type {Boolean}
  119313. * @default false
  119314. */
  119315. this.persists = defaultValue(options.persists, false);
  119316. /**
  119317. * The pass when to render. Always compute pass.
  119318. *
  119319. * @type {Pass}
  119320. * @default Pass.COMPUTE;
  119321. */
  119322. this.pass = Pass.COMPUTE;
  119323. /**
  119324. * The object who created this command. This is useful for debugging command
  119325. * execution; it allows us to see who created a command when we only have a
  119326. * reference to the command, and can be used to selectively execute commands
  119327. * with {@link Scene#debugCommandFilter}.
  119328. *
  119329. * @type {Object}
  119330. * @default undefined
  119331. *
  119332. * @see Scene#debugCommandFilter
  119333. */
  119334. this.owner = options.owner;
  119335. }
  119336. /**
  119337. * Executes the compute command.
  119338. *
  119339. * @param {Context} context The context that processes the compute command.
  119340. */
  119341. ComputeCommand.prototype.execute = function(computeEngine) {
  119342. computeEngine.execute(this);
  119343. };
  119344. return ComputeCommand;
  119345. });
  119346. //This file is automatically rebuilt by the Cesium build process.
  119347. /*global define*/
  119348. define('Shaders/ViewportQuadVS',[],function() {
  119349. 'use strict';
  119350. return "attribute vec4 position;\n\
  119351. attribute vec2 textureCoordinates;\n\
  119352. varying vec2 v_textureCoordinates;\n\
  119353. void main()\n\
  119354. {\n\
  119355. gl_Position = position;\n\
  119356. v_textureCoordinates = textureCoordinates;\n\
  119357. }\n\
  119358. ";
  119359. });
  119360. /*global define*/
  119361. define('Renderer/ComputeEngine',[
  119362. '../Core/BoundingRectangle',
  119363. '../Core/Color',
  119364. '../Core/defined',
  119365. '../Core/destroyObject',
  119366. '../Core/DeveloperError',
  119367. '../Core/PrimitiveType',
  119368. '../Shaders/ViewportQuadVS',
  119369. './ClearCommand',
  119370. './DrawCommand',
  119371. './Framebuffer',
  119372. './RenderState',
  119373. './ShaderProgram'
  119374. ], function(
  119375. BoundingRectangle,
  119376. Color,
  119377. defined,
  119378. destroyObject,
  119379. DeveloperError,
  119380. PrimitiveType,
  119381. ViewportQuadVS,
  119382. ClearCommand,
  119383. DrawCommand,
  119384. Framebuffer,
  119385. RenderState,
  119386. ShaderProgram) {
  119387. 'use strict';
  119388. /**
  119389. * @private
  119390. */
  119391. function ComputeEngine(context) {
  119392. this._context = context;
  119393. }
  119394. var renderStateScratch;
  119395. var drawCommandScratch = new DrawCommand({
  119396. primitiveType : PrimitiveType.TRIANGLES
  119397. });
  119398. var clearCommandScratch = new ClearCommand({
  119399. color : new Color(0.0, 0.0, 0.0, 0.0)
  119400. });
  119401. function createFramebuffer(context, outputTexture) {
  119402. return new Framebuffer({
  119403. context : context,
  119404. colorTextures : [outputTexture],
  119405. destroyAttachments : false
  119406. });
  119407. }
  119408. function createViewportQuadShader(context, fragmentShaderSource) {
  119409. return ShaderProgram.fromCache({
  119410. context : context,
  119411. vertexShaderSource : ViewportQuadVS,
  119412. fragmentShaderSource : fragmentShaderSource,
  119413. attributeLocations : {
  119414. position : 0,
  119415. textureCoordinates : 1
  119416. }
  119417. });
  119418. }
  119419. function createRenderState(width, height) {
  119420. if ((!defined(renderStateScratch)) ||
  119421. (renderStateScratch.viewport.width !== width) ||
  119422. (renderStateScratch.viewport.height !== height)) {
  119423. renderStateScratch = RenderState.fromCache({
  119424. viewport : new BoundingRectangle(0, 0, width, height)
  119425. });
  119426. }
  119427. return renderStateScratch;
  119428. }
  119429. ComputeEngine.prototype.execute = function(computeCommand) {
  119430. if (!defined(computeCommand)) {
  119431. throw new DeveloperError('computeCommand is required.');
  119432. }
  119433. // This may modify the command's resources, so do error checking afterwards
  119434. if (defined(computeCommand.preExecute)) {
  119435. computeCommand.preExecute(computeCommand);
  119436. }
  119437. if (!defined(computeCommand.fragmentShaderSource) && !defined(computeCommand.shaderProgram)) {
  119438. throw new DeveloperError('computeCommand.fragmentShaderSource or computeCommand.shaderProgram is required.');
  119439. }
  119440. if (!defined(computeCommand.outputTexture)) {
  119441. throw new DeveloperError('computeCommand.outputTexture is required.');
  119442. }
  119443. var outputTexture = computeCommand.outputTexture;
  119444. var width = outputTexture.width;
  119445. var height = outputTexture.height;
  119446. var context = this._context;
  119447. var vertexArray = defined(computeCommand.vertexArray) ? computeCommand.vertexArray : context.getViewportQuadVertexArray();
  119448. var shaderProgram = defined(computeCommand.shaderProgram) ? computeCommand.shaderProgram : createViewportQuadShader(context, computeCommand.fragmentShaderSource);
  119449. var framebuffer = createFramebuffer(context, outputTexture);
  119450. var renderState = createRenderState(width, height);
  119451. var uniformMap = computeCommand.uniformMap;
  119452. var clearCommand = clearCommandScratch;
  119453. clearCommand.framebuffer = framebuffer;
  119454. clearCommand.renderState = renderState;
  119455. clearCommand.execute(context);
  119456. var drawCommand = drawCommandScratch;
  119457. drawCommand.vertexArray = vertexArray;
  119458. drawCommand.renderState = renderState;
  119459. drawCommand.shaderProgram = shaderProgram;
  119460. drawCommand.uniformMap = uniformMap;
  119461. drawCommand.framebuffer = framebuffer;
  119462. drawCommand.execute(context);
  119463. framebuffer.destroy();
  119464. if (!computeCommand.persists) {
  119465. shaderProgram.destroy();
  119466. if (defined(computeCommand.vertexArray)) {
  119467. vertexArray.destroy();
  119468. }
  119469. }
  119470. if (defined(computeCommand.postExecute)) {
  119471. computeCommand.postExecute(outputTexture);
  119472. }
  119473. };
  119474. ComputeEngine.prototype.isDestroyed = function() {
  119475. return false;
  119476. };
  119477. ComputeEngine.prototype.destroy = function() {
  119478. return destroyObject(this);
  119479. };
  119480. return ComputeEngine;
  119481. });
  119482. /*global define*/
  119483. define('Renderer/PassState',[], function() {
  119484. 'use strict';
  119485. /**
  119486. * The state for a particular rendering pass. This is used to supplement the state
  119487. * in a command being executed.
  119488. *
  119489. * @private
  119490. */
  119491. function PassState(context) {
  119492. /**
  119493. * The context used to execute commands for this pass.
  119494. *
  119495. * @type {Context}
  119496. */
  119497. this.context = context;
  119498. /**
  119499. * The framebuffer to render to. This framebuffer is used unless a {@link DrawCommand}
  119500. * or {@link ClearCommand} explicitly define a framebuffer, which is used for off-screen
  119501. * rendering.
  119502. *
  119503. * @type {Framebuffer}
  119504. * @default undefined
  119505. */
  119506. this.framebuffer = undefined;
  119507. /**
  119508. * When defined, this overrides the blending property of a {@link DrawCommand}'s render state.
  119509. * This is used to, for example, to allow the renderer to turn off blending during the picking pass.
  119510. * <p>
  119511. * When this is <code>undefined</code>, the {@link DrawCommand}'s property is used.
  119512. * </p>
  119513. *
  119514. * @type {Boolean}
  119515. * @default undefined
  119516. */
  119517. this.blendingEnabled = undefined;
  119518. /**
  119519. * When defined, this overrides the scissor test property of a {@link DrawCommand}'s render state.
  119520. * This is used to, for example, to allow the renderer to scissor out the pick region during the picking pass.
  119521. * <p>
  119522. * When this is <code>undefined</code>, the {@link DrawCommand}'s property is used.
  119523. * </p>
  119524. *
  119525. * @type {Object}
  119526. * @default undefined
  119527. */
  119528. this.scissorTest = undefined;
  119529. /**
  119530. * The viewport used when one is not defined by a {@link DrawCommand}'s render state.
  119531. * @type {BoundingRectangle}
  119532. * @default undefined
  119533. */
  119534. this.viewport = undefined;
  119535. }
  119536. return PassState;
  119537. });
  119538. /*global define*/
  119539. define('Renderer/RenderbufferFormat',[
  119540. '../Core/freezeObject',
  119541. '../Core/WebGLConstants'
  119542. ], function(
  119543. freezeObject,
  119544. WebGLConstants) {
  119545. 'use strict';
  119546. /**
  119547. * @private
  119548. */
  119549. var RenderbufferFormat = {
  119550. RGBA4 : WebGLConstants.RGBA4,
  119551. RGB5_A1 : WebGLConstants.RGB5_A1,
  119552. RGB565 : WebGLConstants.RGB565,
  119553. DEPTH_COMPONENT16 : WebGLConstants.DEPTH_COMPONENT16,
  119554. STENCIL_INDEX8 : WebGLConstants.STENCIL_INDEX8,
  119555. DEPTH_STENCIL : WebGLConstants.DEPTH_STENCIL,
  119556. validate : function(renderbufferFormat) {
  119557. return ((renderbufferFormat === RenderbufferFormat.RGBA4) ||
  119558. (renderbufferFormat === RenderbufferFormat.RGB5_A1) ||
  119559. (renderbufferFormat === RenderbufferFormat.RGB565) ||
  119560. (renderbufferFormat === RenderbufferFormat.DEPTH_COMPONENT16) ||
  119561. (renderbufferFormat === RenderbufferFormat.STENCIL_INDEX8) ||
  119562. (renderbufferFormat === RenderbufferFormat.DEPTH_STENCIL));
  119563. }
  119564. };
  119565. return freezeObject(RenderbufferFormat);
  119566. });
  119567. /*global define*/
  119568. define('Renderer/Renderbuffer',[
  119569. '../Core/defaultValue',
  119570. '../Core/defined',
  119571. '../Core/defineProperties',
  119572. '../Core/destroyObject',
  119573. '../Core/DeveloperError',
  119574. './ContextLimits',
  119575. './RenderbufferFormat'
  119576. ], function(
  119577. defaultValue,
  119578. defined,
  119579. defineProperties,
  119580. destroyObject,
  119581. DeveloperError,
  119582. ContextLimits,
  119583. RenderbufferFormat) {
  119584. 'use strict';
  119585. /**
  119586. * @private
  119587. */
  119588. function Renderbuffer(options) {
  119589. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  119590. if (!defined(options.context)) {
  119591. throw new DeveloperError('options.context is required.');
  119592. }
  119593. var context = options.context;
  119594. var gl = context._gl;
  119595. var maximumRenderbufferSize = ContextLimits.maximumRenderbufferSize;
  119596. var format = defaultValue(options.format, RenderbufferFormat.RGBA4);
  119597. var width = defined(options.width) ? options.width : gl.drawingBufferWidth;
  119598. var height = defined(options.height) ? options.height : gl.drawingBufferHeight;
  119599. if (!RenderbufferFormat.validate(format)) {
  119600. throw new DeveloperError('Invalid format.');
  119601. }
  119602. if (width <= 0) {
  119603. throw new DeveloperError('Width must be greater than zero.');
  119604. }
  119605. if (width > maximumRenderbufferSize) {
  119606. throw new DeveloperError('Width must be less than or equal to the maximum renderbuffer size (' + maximumRenderbufferSize + '). Check maximumRenderbufferSize.');
  119607. }
  119608. if (height <= 0) {
  119609. throw new DeveloperError('Height must be greater than zero.');
  119610. }
  119611. if (height > maximumRenderbufferSize) {
  119612. throw new DeveloperError('Height must be less than or equal to the maximum renderbuffer size (' + maximumRenderbufferSize + '). Check maximumRenderbufferSize.');
  119613. }
  119614. this._gl = gl;
  119615. this._format = format;
  119616. this._width = width;
  119617. this._height = height;
  119618. this._renderbuffer = this._gl.createRenderbuffer();
  119619. gl.bindRenderbuffer(gl.RENDERBUFFER, this._renderbuffer);
  119620. gl.renderbufferStorage(gl.RENDERBUFFER, format, width, height);
  119621. gl.bindRenderbuffer(gl.RENDERBUFFER, null);
  119622. }
  119623. defineProperties(Renderbuffer.prototype, {
  119624. format: {
  119625. get : function() {
  119626. return this._format;
  119627. }
  119628. },
  119629. width: {
  119630. get : function() {
  119631. return this._width;
  119632. }
  119633. },
  119634. height: {
  119635. get : function() {
  119636. return this._height;
  119637. }
  119638. }
  119639. });
  119640. Renderbuffer.prototype._getRenderbuffer = function() {
  119641. return this._renderbuffer;
  119642. };
  119643. Renderbuffer.prototype.isDestroyed = function() {
  119644. return false;
  119645. };
  119646. Renderbuffer.prototype.destroy = function() {
  119647. this._gl.deleteRenderbuffer(this._renderbuffer);
  119648. return destroyObject(this);
  119649. };
  119650. return Renderbuffer;
  119651. });
  119652. /*global define*/
  119653. define('Renderer/PickFramebuffer',[
  119654. '../Core/BoundingRectangle',
  119655. '../Core/Color',
  119656. '../Core/defaultValue',
  119657. '../Core/defined',
  119658. '../Core/destroyObject',
  119659. './Framebuffer',
  119660. './PassState',
  119661. './Renderbuffer',
  119662. './RenderbufferFormat',
  119663. './Texture'
  119664. ], function(
  119665. BoundingRectangle,
  119666. Color,
  119667. defaultValue,
  119668. defined,
  119669. destroyObject,
  119670. Framebuffer,
  119671. PassState,
  119672. Renderbuffer,
  119673. RenderbufferFormat,
  119674. Texture) {
  119675. 'use strict';
  119676. /**
  119677. * @private
  119678. */
  119679. function PickFramebuffer(context) {
  119680. // Override per-command states
  119681. var passState = new PassState(context);
  119682. passState.blendingEnabled = false;
  119683. passState.scissorTest = {
  119684. enabled : true,
  119685. rectangle : new BoundingRectangle()
  119686. };
  119687. passState.viewport = new BoundingRectangle();
  119688. this._context = context;
  119689. this._fb = undefined;
  119690. this._passState = passState;
  119691. this._width = 0;
  119692. this._height = 0;
  119693. }
  119694. PickFramebuffer.prototype.begin = function(screenSpaceRectangle) {
  119695. var context = this._context;
  119696. var width = context.drawingBufferWidth;
  119697. var height = context.drawingBufferHeight;
  119698. BoundingRectangle.clone(screenSpaceRectangle, this._passState.scissorTest.rectangle);
  119699. // Initially create or recreate renderbuffers and framebuffer used for picking
  119700. if ((!defined(this._fb)) || (this._width !== width) || (this._height !== height)) {
  119701. this._width = width;
  119702. this._height = height;
  119703. this._fb = this._fb && this._fb.destroy();
  119704. this._fb = new Framebuffer({
  119705. context : context,
  119706. colorTextures : [new Texture({
  119707. context : context,
  119708. width : width,
  119709. height : height
  119710. })],
  119711. depthStencilRenderbuffer : new Renderbuffer({
  119712. context : context,
  119713. format : RenderbufferFormat.DEPTH_STENCIL
  119714. })
  119715. });
  119716. this._passState.framebuffer = this._fb;
  119717. }
  119718. this._passState.viewport.width = width;
  119719. this._passState.viewport.height = height;
  119720. return this._passState;
  119721. };
  119722. var colorScratch = new Color();
  119723. PickFramebuffer.prototype.end = function(screenSpaceRectangle) {
  119724. var width = defaultValue(screenSpaceRectangle.width, 1.0);
  119725. var height = defaultValue(screenSpaceRectangle.height, 1.0);
  119726. var context = this._context;
  119727. var pixels = context.readPixels({
  119728. x : screenSpaceRectangle.x,
  119729. y : screenSpaceRectangle.y,
  119730. width : width,
  119731. height : height,
  119732. framebuffer : this._fb
  119733. });
  119734. var max = Math.max(width, height);
  119735. var length = max * max;
  119736. var halfWidth = Math.floor(width * 0.5);
  119737. var halfHeight = Math.floor(height * 0.5);
  119738. var x = 0;
  119739. var y = 0;
  119740. var dx = 0;
  119741. var dy = -1;
  119742. // Spiral around the center pixel, this is a workaround until
  119743. // we can access the depth buffer on all browsers.
  119744. // The region does not have to square and the dimensions do not have to be odd, but
  119745. // loop iterations would be wasted. Prefer square regions where the size is odd.
  119746. for (var i = 0; i < length; ++i) {
  119747. if (-halfWidth <= x && x <= halfWidth && -halfHeight <= y && y <= halfHeight) {
  119748. var index = 4 * ((halfHeight - y) * width + x + halfWidth);
  119749. colorScratch.red = Color.byteToFloat(pixels[index]);
  119750. colorScratch.green = Color.byteToFloat(pixels[index + 1]);
  119751. colorScratch.blue = Color.byteToFloat(pixels[index + 2]);
  119752. colorScratch.alpha = Color.byteToFloat(pixels[index + 3]);
  119753. var object = context.getObjectByPickColor(colorScratch);
  119754. if (defined(object)) {
  119755. return object;
  119756. }
  119757. }
  119758. // if (top right || bottom left corners) || (top left corner) || (bottom right corner + (1, 0))
  119759. // change spiral direction
  119760. if (x === y || (x < 0 && -x === y) || (x > 0 && x === 1 - y)) {
  119761. var temp = dx;
  119762. dx = -dy;
  119763. dy = temp;
  119764. }
  119765. x += dx;
  119766. y += dy;
  119767. }
  119768. return undefined;
  119769. };
  119770. PickFramebuffer.prototype.isDestroyed = function() {
  119771. return false;
  119772. };
  119773. PickFramebuffer.prototype.destroy = function() {
  119774. this._fb = this._fb && this._fb.destroy();
  119775. return destroyObject(this);
  119776. };
  119777. return PickFramebuffer;
  119778. });
  119779. /*global define*/
  119780. define('Renderer/ShaderCache',[
  119781. '../Core/defined',
  119782. '../Core/defineProperties',
  119783. '../Core/destroyObject',
  119784. './ShaderProgram',
  119785. './ShaderSource'
  119786. ], function(
  119787. defined,
  119788. defineProperties,
  119789. destroyObject,
  119790. ShaderProgram,
  119791. ShaderSource) {
  119792. 'use strict';
  119793. /**
  119794. * @private
  119795. */
  119796. function ShaderCache(context) {
  119797. this._context = context;
  119798. this._shaders = {};
  119799. this._numberOfShaders = 0;
  119800. this._shadersToRelease = {};
  119801. }
  119802. defineProperties(ShaderCache.prototype, {
  119803. numberOfShaders : {
  119804. get : function() {
  119805. return this._numberOfShaders;
  119806. }
  119807. }
  119808. });
  119809. /**
  119810. * Returns a shader program from the cache, or creates and caches a new shader program,
  119811. * given the GLSL vertex and fragment shader source and attribute locations.
  119812. * <p>
  119813. * The difference between this and {@link ShaderCache#getShaderProgram}, is this is used to
  119814. * replace an existing reference to a shader program, which is passed as the first argument.
  119815. * </p>
  119816. *
  119817. * @param {Object} options Object with the following properties:
  119818. * @param {ShaderProgram} [options.shaderProgram] The shader program that is being reassigned.
  119819. * @param {String|ShaderSource} options.vertexShaderSource The GLSL source for the vertex shader.
  119820. * @param {String|ShaderSource} options.fragmentShaderSource The GLSL source for the fragment shader.
  119821. * @param {Object} options.attributeLocations Indices for the attribute inputs to the vertex shader.
  119822. * @returns {ShaderProgram} The cached or newly created shader program.
  119823. *
  119824. *
  119825. * @example
  119826. * this._shaderProgram = context.shaderCache.replaceShaderProgram({
  119827. * shaderProgram : this._shaderProgram,
  119828. * vertexShaderSource : vs,
  119829. * fragmentShaderSource : fs,
  119830. * attributeLocations : attributeLocations
  119831. * });
  119832. *
  119833. * @see ShaderCache#getShaderProgram
  119834. */
  119835. ShaderCache.prototype.replaceShaderProgram = function(options) {
  119836. if (defined(options.shaderProgram)) {
  119837. options.shaderProgram.destroy();
  119838. }
  119839. return this.getShaderProgram(options);
  119840. };
  119841. /**
  119842. * Returns a shader program from the cache, or creates and caches a new shader program,
  119843. * given the GLSL vertex and fragment shader source and attribute locations.
  119844. *
  119845. * @param {Object} options Object with the following properties:
  119846. * @param {String|ShaderSource} options.vertexShaderSource The GLSL source for the vertex shader.
  119847. * @param {String|ShaderSource} options.fragmentShaderSource The GLSL source for the fragment shader.
  119848. * @param {Object} options.attributeLocations Indices for the attribute inputs to the vertex shader.
  119849. *
  119850. * @returns {ShaderProgram} The cached or newly created shader program.
  119851. */
  119852. ShaderCache.prototype.getShaderProgram = function(options) {
  119853. // convert shaders which are provided as strings into ShaderSource objects
  119854. // because ShaderSource handles all the automatic including of built-in functions, etc.
  119855. var vertexShaderSource = options.vertexShaderSource;
  119856. var fragmentShaderSource = options.fragmentShaderSource;
  119857. var attributeLocations = options.attributeLocations;
  119858. if (typeof vertexShaderSource === 'string') {
  119859. vertexShaderSource = new ShaderSource({
  119860. sources : [vertexShaderSource]
  119861. });
  119862. }
  119863. if (typeof fragmentShaderSource === 'string') {
  119864. fragmentShaderSource = new ShaderSource({
  119865. sources : [fragmentShaderSource]
  119866. });
  119867. }
  119868. var vertexShaderText = vertexShaderSource.createCombinedVertexShader();
  119869. var fragmentShaderText = fragmentShaderSource.createCombinedFragmentShader();
  119870. var keyword = vertexShaderText + fragmentShaderText + JSON.stringify(attributeLocations);
  119871. var cachedShader;
  119872. if (this._shaders[keyword]) {
  119873. cachedShader = this._shaders[keyword];
  119874. // No longer want to release this if it was previously released.
  119875. delete this._shadersToRelease[keyword];
  119876. } else {
  119877. var context = this._context;
  119878. var shaderProgram = new ShaderProgram({
  119879. gl : context._gl,
  119880. logShaderCompilation : context.logShaderCompilation,
  119881. debugShaders : context.debugShaders,
  119882. vertexShaderSource : vertexShaderSource,
  119883. vertexShaderText : vertexShaderText,
  119884. fragmentShaderSource : fragmentShaderSource,
  119885. fragmentShaderText : fragmentShaderText,
  119886. attributeLocations : attributeLocations
  119887. });
  119888. cachedShader = {
  119889. cache : this,
  119890. shaderProgram : shaderProgram,
  119891. keyword : keyword,
  119892. count : 0
  119893. };
  119894. // A shader can't be in more than one cache.
  119895. shaderProgram._cachedShader = cachedShader;
  119896. this._shaders[keyword] = cachedShader;
  119897. ++this._numberOfShaders;
  119898. }
  119899. ++cachedShader.count;
  119900. return cachedShader.shaderProgram;
  119901. };
  119902. ShaderCache.prototype.destroyReleasedShaderPrograms = function() {
  119903. var shadersToRelease = this._shadersToRelease;
  119904. for ( var keyword in shadersToRelease) {
  119905. if (shadersToRelease.hasOwnProperty(keyword)) {
  119906. var cachedShader = shadersToRelease[keyword];
  119907. delete this._shaders[cachedShader.keyword];
  119908. cachedShader.shaderProgram.finalDestroy();
  119909. --this._numberOfShaders;
  119910. }
  119911. }
  119912. this._shadersToRelease = {};
  119913. };
  119914. ShaderCache.prototype.releaseShaderProgram = function(shaderProgram) {
  119915. if (defined(shaderProgram)) {
  119916. var cachedShader = shaderProgram._cachedShader;
  119917. if (cachedShader && (--cachedShader.count === 0)) {
  119918. this._shadersToRelease[cachedShader.keyword] = cachedShader;
  119919. }
  119920. }
  119921. };
  119922. ShaderCache.prototype.isDestroyed = function() {
  119923. return false;
  119924. };
  119925. ShaderCache.prototype.destroy = function() {
  119926. var shaders = this._shaders;
  119927. for ( var keyword in shaders) {
  119928. if (shaders.hasOwnProperty(keyword)) {
  119929. shaders[keyword].shaderProgram.finalDestroy();
  119930. }
  119931. }
  119932. return destroyObject(this);
  119933. };
  119934. return ShaderCache;
  119935. });
  119936. /*global define*/
  119937. define('Renderer/UniformState',[
  119938. '../Core/BoundingRectangle',
  119939. '../Core/Cartesian2',
  119940. '../Core/Cartesian3',
  119941. '../Core/Cartesian4',
  119942. '../Core/Cartographic',
  119943. '../Core/defined',
  119944. '../Core/defineProperties',
  119945. '../Core/EncodedCartesian3',
  119946. '../Core/Math',
  119947. '../Core/Matrix3',
  119948. '../Core/Matrix4',
  119949. '../Core/Simon1994PlanetaryPositions',
  119950. '../Core/Transforms',
  119951. '../Scene/SceneMode'
  119952. ], function(
  119953. BoundingRectangle,
  119954. Cartesian2,
  119955. Cartesian3,
  119956. Cartesian4,
  119957. Cartographic,
  119958. defined,
  119959. defineProperties,
  119960. EncodedCartesian3,
  119961. CesiumMath,
  119962. Matrix3,
  119963. Matrix4,
  119964. Simon1994PlanetaryPositions,
  119965. Transforms,
  119966. SceneMode) {
  119967. 'use strict';
  119968. /**
  119969. * @private
  119970. */
  119971. function UniformState() {
  119972. /**
  119973. * @type {Texture}
  119974. */
  119975. this.globeDepthTexture = undefined;
  119976. this._viewport = new BoundingRectangle();
  119977. this._viewportCartesian4 = new Cartesian4();
  119978. this._viewportDirty = false;
  119979. this._viewportOrthographicMatrix = Matrix4.clone(Matrix4.IDENTITY);
  119980. this._viewportTransformation = Matrix4.clone(Matrix4.IDENTITY);
  119981. this._model = Matrix4.clone(Matrix4.IDENTITY);
  119982. this._view = Matrix4.clone(Matrix4.IDENTITY);
  119983. this._inverseView = Matrix4.clone(Matrix4.IDENTITY);
  119984. this._projection = Matrix4.clone(Matrix4.IDENTITY);
  119985. this._infiniteProjection = Matrix4.clone(Matrix4.IDENTITY);
  119986. this._entireFrustum = new Cartesian2();
  119987. this._currentFrustum = new Cartesian2();
  119988. this._frustumPlanes = new Cartesian4();
  119989. this._frameState = undefined;
  119990. this._temeToPseudoFixed = Matrix3.clone(Matrix4.IDENTITY);
  119991. // Derived members
  119992. this._view3DDirty = true;
  119993. this._view3D = new Matrix4();
  119994. this._inverseView3DDirty = true;
  119995. this._inverseView3D = new Matrix4();
  119996. this._inverseModelDirty = true;
  119997. this._inverseModel = new Matrix4();
  119998. this._inverseTransposeModelDirty = true;
  119999. this._inverseTransposeModel = new Matrix3();
  120000. this._viewRotation = new Matrix3();
  120001. this._inverseViewRotation = new Matrix3();
  120002. this._viewRotation3D = new Matrix3();
  120003. this._inverseViewRotation3D = new Matrix3();
  120004. this._inverseProjectionDirty = true;
  120005. this._inverseProjection = new Matrix4();
  120006. this._inverseProjectionOITDirty = true;
  120007. this._inverseProjectionOIT = new Matrix4();
  120008. this._modelViewDirty = true;
  120009. this._modelView = new Matrix4();
  120010. this._modelView3DDirty = true;
  120011. this._modelView3D = new Matrix4();
  120012. this._modelViewRelativeToEyeDirty = true;
  120013. this._modelViewRelativeToEye = new Matrix4();
  120014. this._inverseModelViewDirty = true;
  120015. this._inverseModelView = new Matrix4();
  120016. this._inverseModelView3DDirty = true;
  120017. this._inverseModelView3D = new Matrix4();
  120018. this._viewProjectionDirty = true;
  120019. this._viewProjection = new Matrix4();
  120020. this._inverseViewProjectionDirty = true;
  120021. this._inverseViewProjection = new Matrix4();
  120022. this._modelViewProjectionDirty = true;
  120023. this._modelViewProjection = new Matrix4();
  120024. this._inverseModelViewProjectionDirty = true;
  120025. this._inverseModelViewProjection = new Matrix4();
  120026. this._modelViewProjectionRelativeToEyeDirty = true;
  120027. this._modelViewProjectionRelativeToEye = new Matrix4();
  120028. this._modelViewInfiniteProjectionDirty = true;
  120029. this._modelViewInfiniteProjection = new Matrix4();
  120030. this._normalDirty = true;
  120031. this._normal = new Matrix3();
  120032. this._normal3DDirty = true;
  120033. this._normal3D = new Matrix3();
  120034. this._inverseNormalDirty = true;
  120035. this._inverseNormal = new Matrix3();
  120036. this._inverseNormal3DDirty = true;
  120037. this._inverseNormal3D = new Matrix3();
  120038. this._encodedCameraPositionMCDirty = true;
  120039. this._encodedCameraPositionMC = new EncodedCartesian3();
  120040. this._cameraPosition = new Cartesian3();
  120041. this._sunPositionWC = new Cartesian3();
  120042. this._sunPositionColumbusView = new Cartesian3();
  120043. this._sunDirectionWC = new Cartesian3();
  120044. this._sunDirectionEC = new Cartesian3();
  120045. this._moonDirectionEC = new Cartesian3();
  120046. this._pass = undefined;
  120047. this._mode = undefined;
  120048. this._mapProjection = undefined;
  120049. this._cameraDirection = new Cartesian3();
  120050. this._cameraRight = new Cartesian3();
  120051. this._cameraUp = new Cartesian3();
  120052. this._frustum2DWidth = 0.0;
  120053. this._eyeHeight2D = new Cartesian2();
  120054. this._resolutionScale = 1.0;
  120055. this._fogDensity = undefined;
  120056. }
  120057. defineProperties(UniformState.prototype, {
  120058. /**
  120059. * @memberof UniformState.prototype
  120060. * @type {FrameState}
  120061. * @readonly
  120062. */
  120063. frameState : {
  120064. get : function() {
  120065. return this._frameState;
  120066. }
  120067. },
  120068. /**
  120069. * @memberof UniformState.prototype
  120070. * @type {BoundingRectangle}
  120071. */
  120072. viewport : {
  120073. get : function() {
  120074. return this._viewport;
  120075. },
  120076. set : function(viewport) {
  120077. if (!BoundingRectangle.equals(viewport, this._viewport)) {
  120078. BoundingRectangle.clone(viewport, this._viewport);
  120079. var v = this._viewport;
  120080. var vc = this._viewportCartesian4;
  120081. vc.x = v.x;
  120082. vc.y = v.y;
  120083. vc.z = v.width;
  120084. vc.w = v.height;
  120085. this._viewportDirty = true;
  120086. }
  120087. }
  120088. },
  120089. /**
  120090. * @memberof UniformState.prototype
  120091. * @private
  120092. */
  120093. viewportCartesian4 : {
  120094. get : function() {
  120095. return this._viewportCartesian4;
  120096. }
  120097. },
  120098. viewportOrthographic : {
  120099. get : function() {
  120100. cleanViewport(this);
  120101. return this._viewportOrthographicMatrix;
  120102. }
  120103. },
  120104. viewportTransformation : {
  120105. get : function() {
  120106. cleanViewport(this);
  120107. return this._viewportTransformation;
  120108. }
  120109. },
  120110. /**
  120111. * @memberof UniformState.prototype
  120112. * @type {Matrix4}
  120113. */
  120114. model : {
  120115. get : function() {
  120116. return this._model;
  120117. },
  120118. set : function(matrix) {
  120119. Matrix4.clone(matrix, this._model);
  120120. this._modelView3DDirty = true;
  120121. this._inverseModelView3DDirty = true;
  120122. this._inverseModelDirty = true;
  120123. this._inverseTransposeModelDirty = true;
  120124. this._modelViewDirty = true;
  120125. this._inverseModelViewDirty = true;
  120126. this._modelViewRelativeToEyeDirty = true;
  120127. this._inverseModelViewDirty = true;
  120128. this._modelViewProjectionDirty = true;
  120129. this._inverseModelViewProjectionDirty = true;
  120130. this._modelViewProjectionRelativeToEyeDirty = true;
  120131. this._modelViewInfiniteProjectionDirty = true;
  120132. this._normalDirty = true;
  120133. this._inverseNormalDirty = true;
  120134. this._normal3DDirty = true;
  120135. this._inverseNormal3DDirty = true;
  120136. this._encodedCameraPositionMCDirty = true;
  120137. }
  120138. },
  120139. /**
  120140. * @memberof UniformState.prototype
  120141. * @type {Matrix4}
  120142. */
  120143. inverseModel : {
  120144. get : function() {
  120145. if (this._inverseModelDirty) {
  120146. this._inverseModelDirty = false;
  120147. Matrix4.inverse(this._model, this._inverseModel);
  120148. }
  120149. return this._inverseModel;
  120150. }
  120151. },
  120152. /**
  120153. * @memberof UniformState.prototype
  120154. * @private
  120155. */
  120156. inverseTransposeModel : {
  120157. get : function() {
  120158. var m = this._inverseTransposeModel;
  120159. if (this._inverseTransposeModelDirty) {
  120160. this._inverseTransposeModelDirty = false;
  120161. Matrix4.getRotation(this.inverseModel, m);
  120162. Matrix3.transpose(m, m);
  120163. }
  120164. return m;
  120165. }
  120166. },
  120167. /**
  120168. * @memberof UniformState.prototype
  120169. * @type {Matrix4}
  120170. */
  120171. view : {
  120172. get : function() {
  120173. return this._view;
  120174. }
  120175. },
  120176. /**
  120177. * The 3D view matrix. In 3D mode, this is identical to {@link UniformState#view},
  120178. * but in 2D and Columbus View it is a synthetic matrix based on the equivalent position
  120179. * of the camera in the 3D world.
  120180. * @memberof UniformState.prototype
  120181. * @type {Matrix4}
  120182. */
  120183. view3D : {
  120184. get : function() {
  120185. updateView3D(this);
  120186. return this._view3D;
  120187. }
  120188. },
  120189. /**
  120190. * The 3x3 rotation matrix of the current view matrix ({@link UniformState#view}).
  120191. * @memberof UniformState.prototype
  120192. * @type {Matrix3}
  120193. */
  120194. viewRotation : {
  120195. get : function() {
  120196. updateView3D(this);
  120197. return this._viewRotation;
  120198. }
  120199. },
  120200. /**
  120201. * @memberof UniformState.prototype
  120202. * @type {Matrix3}
  120203. */
  120204. viewRotation3D : {
  120205. get : function() {
  120206. updateView3D(this);
  120207. return this._viewRotation3D;
  120208. }
  120209. },
  120210. /**
  120211. * @memberof UniformState.prototype
  120212. * @type {Matrix4}
  120213. */
  120214. inverseView : {
  120215. get : function() {
  120216. return this._inverseView;
  120217. }
  120218. },
  120219. /**
  120220. * the 4x4 inverse-view matrix that transforms from eye to 3D world coordinates. In 3D mode, this is
  120221. * identical to {@link UniformState#inverseView}, but in 2D and Columbus View it is a synthetic matrix
  120222. * based on the equivalent position of the camera in the 3D world.
  120223. * @memberof UniformState.prototype
  120224. * @type {Matrix4}
  120225. */
  120226. inverseView3D : {
  120227. get : function() {
  120228. updateInverseView3D(this);
  120229. return this._inverseView3D;
  120230. }
  120231. },
  120232. /**
  120233. * @memberof UniformState.prototype
  120234. * @type {Matrix3}
  120235. */
  120236. inverseViewRotation : {
  120237. get : function() {
  120238. return this._inverseViewRotation;
  120239. }
  120240. },
  120241. /**
  120242. * The 3x3 rotation matrix of the current 3D inverse-view matrix ({@link UniformState#inverseView3D}).
  120243. * @memberof UniformState.prototype
  120244. * @type {Matrix3}
  120245. */
  120246. inverseViewRotation3D : {
  120247. get : function() {
  120248. updateInverseView3D(this);
  120249. return this._inverseViewRotation3D;
  120250. }
  120251. },
  120252. /**
  120253. * @memberof UniformState.prototype
  120254. * @type {Matrix4}
  120255. */
  120256. projection : {
  120257. get : function() {
  120258. return this._projection;
  120259. }
  120260. },
  120261. /**
  120262. * @memberof UniformState.prototype
  120263. * @type {Matrix4}
  120264. */
  120265. inverseProjection : {
  120266. get : function() {
  120267. cleanInverseProjection(this);
  120268. return this._inverseProjection;
  120269. }
  120270. },
  120271. /**
  120272. * @memberof UniformState.prototype
  120273. * @private
  120274. */
  120275. inverseProjectionOIT : {
  120276. get : function() {
  120277. cleanInverseProjectionOIT(this);
  120278. return this._inverseProjectionOIT;
  120279. }
  120280. },
  120281. /**
  120282. * @memberof UniformState.prototype
  120283. * @type {Matrix4}
  120284. */
  120285. infiniteProjection : {
  120286. get : function() {
  120287. return this._infiniteProjection;
  120288. }
  120289. },
  120290. /**
  120291. * @memberof UniformState.prototype
  120292. * @type {Matrix4}
  120293. */
  120294. modelView : {
  120295. get : function() {
  120296. cleanModelView(this);
  120297. return this._modelView;
  120298. }
  120299. },
  120300. /**
  120301. * The 3D model-view matrix. In 3D mode, this is equivalent to {@link UniformState#modelView}. In 2D and
  120302. * Columbus View, however, it is a synthetic matrix based on the equivalent position of the camera in the 3D world.
  120303. * @memberof UniformState.prototype
  120304. * @type {Matrix4}
  120305. */
  120306. modelView3D : {
  120307. get : function() {
  120308. cleanModelView3D(this);
  120309. return this._modelView3D;
  120310. }
  120311. },
  120312. /**
  120313. * Model-view relative to eye matrix.
  120314. *
  120315. * @memberof UniformState.prototype
  120316. * @type {Matrix4}
  120317. */
  120318. modelViewRelativeToEye : {
  120319. get : function() {
  120320. cleanModelViewRelativeToEye(this);
  120321. return this._modelViewRelativeToEye;
  120322. }
  120323. },
  120324. /**
  120325. * @memberof UniformState.prototype
  120326. * @type {Matrix4}
  120327. */
  120328. inverseModelView : {
  120329. get : function() {
  120330. cleanInverseModelView(this);
  120331. return this._inverseModelView;
  120332. }
  120333. },
  120334. /**
  120335. * The inverse of the 3D model-view matrix. In 3D mode, this is equivalent to {@link UniformState#inverseModelView}.
  120336. * In 2D and Columbus View, however, it is a synthetic matrix based on the equivalent position of the camera in the 3D world.
  120337. * @memberof UniformState.prototype
  120338. * @type {Matrix4}
  120339. */
  120340. inverseModelView3D : {
  120341. get : function() {
  120342. cleanInverseModelView3D(this);
  120343. return this._inverseModelView3D;
  120344. }
  120345. },
  120346. /**
  120347. * @memberof UniformState.prototype
  120348. * @type {Matrix4}
  120349. */
  120350. viewProjection : {
  120351. get : function() {
  120352. cleanViewProjection(this);
  120353. return this._viewProjection;
  120354. }
  120355. },
  120356. /**
  120357. * @memberof UniformState.prototype
  120358. * @type {Matrix4}
  120359. */
  120360. inverseViewProjection : {
  120361. get : function() {
  120362. cleanInverseViewProjection(this);
  120363. return this._inverseViewProjection;
  120364. }
  120365. },
  120366. /**
  120367. * @memberof UniformState.prototype
  120368. * @type {Matrix4}
  120369. */
  120370. modelViewProjection : {
  120371. get : function() {
  120372. cleanModelViewProjection(this);
  120373. return this._modelViewProjection;
  120374. }
  120375. },
  120376. /**
  120377. * @memberof UniformState.prototype
  120378. * @type {Matrix4}
  120379. */
  120380. inverseModelViewProjection : {
  120381. get : function() {
  120382. cleanInverseModelViewProjection(this);
  120383. return this._inverseModelViewProjection;
  120384. }
  120385. },
  120386. /**
  120387. * Model-view-projection relative to eye matrix.
  120388. *
  120389. * @memberof UniformState.prototype
  120390. * @type {Matrix4}
  120391. */
  120392. modelViewProjectionRelativeToEye : {
  120393. get : function() {
  120394. cleanModelViewProjectionRelativeToEye(this);
  120395. return this._modelViewProjectionRelativeToEye;
  120396. }
  120397. },
  120398. /**
  120399. * @memberof UniformState.prototype
  120400. * @type {Matrix4}
  120401. */
  120402. modelViewInfiniteProjection : {
  120403. get : function() {
  120404. cleanModelViewInfiniteProjection(this);
  120405. return this._modelViewInfiniteProjection;
  120406. }
  120407. },
  120408. /**
  120409. * A 3x3 normal transformation matrix that transforms normal vectors in model coordinates to
  120410. * eye coordinates.
  120411. * @memberof UniformState.prototype
  120412. * @type {Matrix3}
  120413. */
  120414. normal : {
  120415. get : function() {
  120416. cleanNormal(this);
  120417. return this._normal;
  120418. }
  120419. },
  120420. /**
  120421. * A 3x3 normal transformation matrix that transforms normal vectors in 3D model
  120422. * coordinates to eye coordinates. In 3D mode, this is identical to
  120423. * {@link UniformState#normal}, but in 2D and Columbus View it represents the normal transformation
  120424. * matrix as if the camera were at an equivalent location in 3D mode.
  120425. * @memberof UniformState.prototype
  120426. * @type {Matrix3}
  120427. */
  120428. normal3D : {
  120429. get : function() {
  120430. cleanNormal3D(this);
  120431. return this._normal3D;
  120432. }
  120433. },
  120434. /**
  120435. * An inverse 3x3 normal transformation matrix that transforms normal vectors in model coordinates
  120436. * to eye coordinates.
  120437. * @memberof UniformState.prototype
  120438. * @type {Matrix3}
  120439. */
  120440. inverseNormal : {
  120441. get : function() {
  120442. cleanInverseNormal(this);
  120443. return this._inverseNormal;
  120444. }
  120445. },
  120446. /**
  120447. * An inverse 3x3 normal transformation matrix that transforms normal vectors in eye coordinates
  120448. * to 3D model coordinates. In 3D mode, this is identical to
  120449. * {@link UniformState#inverseNormal}, but in 2D and Columbus View it represents the normal transformation
  120450. * matrix as if the camera were at an equivalent location in 3D mode.
  120451. * @memberof UniformState.prototype
  120452. * @type {Matrix3}
  120453. */
  120454. inverseNormal3D : {
  120455. get : function() {
  120456. cleanInverseNormal3D(this);
  120457. return this._inverseNormal3D;
  120458. }
  120459. },
  120460. /**
  120461. * The near distance (<code>x</code>) and the far distance (<code>y</code>) of the frustum defined by the camera.
  120462. * This is the largest possible frustum, not an individual frustum used for multi-frustum rendering.
  120463. * @memberof UniformState.prototype
  120464. * @type {Cartesian2}
  120465. */
  120466. entireFrustum : {
  120467. get : function() {
  120468. return this._entireFrustum;
  120469. }
  120470. },
  120471. /**
  120472. * The near distance (<code>x</code>) and the far distance (<code>y</code>) of the frustum defined by the camera.
  120473. * This is the individual frustum used for multi-frustum rendering.
  120474. * @memberof UniformState.prototype
  120475. * @type {Cartesian2}
  120476. */
  120477. currentFrustum : {
  120478. get : function() {
  120479. return this._currentFrustum;
  120480. }
  120481. },
  120482. /**
  120483. * The distances to the frustum planes. The top, bottom, left and right distances are
  120484. * the x, y, z, and w components, respectively.
  120485. * @memberof UniformState.prototype
  120486. * @type {Cartesian4}
  120487. */
  120488. frustumPlanes : {
  120489. get : function() {
  120490. return this._frustumPlanes;
  120491. }
  120492. },
  120493. /**
  120494. * The the height (<code>x</code>) and the height squared (<code>y</code>)
  120495. * in meters of the camera above the 2D world plane. This uniform is only valid
  120496. * when the {@link SceneMode} equal to <code>SCENE2D</code>.
  120497. * @memberof UniformState.prototype
  120498. * @type {Cartesian2}
  120499. */
  120500. eyeHeight2D : {
  120501. get : function() {
  120502. return this._eyeHeight2D;
  120503. }
  120504. },
  120505. /**
  120506. * The sun position in 3D world coordinates at the current scene time.
  120507. * @memberof UniformState.prototype
  120508. * @type {Cartesian3}
  120509. */
  120510. sunPositionWC : {
  120511. get : function() {
  120512. return this._sunPositionWC;
  120513. }
  120514. },
  120515. /**
  120516. * The sun position in 2D world coordinates at the current scene time.
  120517. * @memberof UniformState.prototype
  120518. * @type {Cartesian3}
  120519. */
  120520. sunPositionColumbusView : {
  120521. get : function(){
  120522. return this._sunPositionColumbusView;
  120523. }
  120524. },
  120525. /**
  120526. * A normalized vector to the sun in 3D world coordinates at the current scene time. Even in 2D or
  120527. * Columbus View mode, this returns the position of the sun in the 3D scene.
  120528. * @memberof UniformState.prototype
  120529. * @type {Cartesian3}
  120530. */
  120531. sunDirectionWC : {
  120532. get : function() {
  120533. return this._sunDirectionWC;
  120534. }
  120535. },
  120536. /**
  120537. * A normalized vector to the sun in eye coordinates at the current scene time. In 3D mode, this
  120538. * returns the actual vector from the camera position to the sun position. In 2D and Columbus View, it returns
  120539. * the vector from the equivalent 3D camera position to the position of the sun in the 3D scene.
  120540. * @memberof UniformState.prototype
  120541. * @type {Cartesian3}
  120542. */
  120543. sunDirectionEC : {
  120544. get : function() {
  120545. return this._sunDirectionEC;
  120546. }
  120547. },
  120548. /**
  120549. * A normalized vector to the moon in eye coordinates at the current scene time. In 3D mode, this
  120550. * returns the actual vector from the camera position to the moon position. In 2D and Columbus View, it returns
  120551. * the vector from the equivalent 3D camera position to the position of the moon in the 3D scene.
  120552. * @memberof UniformState.prototype
  120553. * @type {Cartesian3}
  120554. */
  120555. moonDirectionEC : {
  120556. get : function() {
  120557. return this._moonDirectionEC;
  120558. }
  120559. },
  120560. /**
  120561. * The high bits of the camera position.
  120562. * @memberof UniformState.prototype
  120563. * @type {Cartesian3}
  120564. */
  120565. encodedCameraPositionMCHigh : {
  120566. get : function() {
  120567. cleanEncodedCameraPositionMC(this);
  120568. return this._encodedCameraPositionMC.high;
  120569. }
  120570. },
  120571. /**
  120572. * The low bits of the camera position.
  120573. * @memberof UniformState.prototype
  120574. * @type {Cartesian3}
  120575. */
  120576. encodedCameraPositionMCLow : {
  120577. get : function() {
  120578. cleanEncodedCameraPositionMC(this);
  120579. return this._encodedCameraPositionMC.low;
  120580. }
  120581. },
  120582. /**
  120583. * A 3x3 matrix that transforms from True Equator Mean Equinox (TEME) axes to the
  120584. * pseudo-fixed axes at the Scene's current time.
  120585. * @memberof UniformState.prototype
  120586. * @type {Matrix3}
  120587. */
  120588. temeToPseudoFixedMatrix : {
  120589. get : function() {
  120590. return this._temeToPseudoFixed;
  120591. }
  120592. },
  120593. /**
  120594. * Gets the scaling factor for transforming from the canvas
  120595. * pixel space to canvas coordinate space.
  120596. * @memberof UniformState.prototype
  120597. * @type {Number}
  120598. */
  120599. resolutionScale : {
  120600. get : function() {
  120601. return this._resolutionScale;
  120602. }
  120603. },
  120604. /**
  120605. * A scalar used to mix a color with the fog color based on the distance to the camera.
  120606. * @memberof UniformState.prototype
  120607. * @type {Number}
  120608. */
  120609. fogDensity : {
  120610. get : function() {
  120611. return this._fogDensity;
  120612. }
  120613. },
  120614. /**
  120615. * @memberof UniformState.prototype
  120616. * @type {Pass}
  120617. */
  120618. pass : {
  120619. get : function() {
  120620. return this._pass;
  120621. }
  120622. }
  120623. });
  120624. function setView(uniformState, matrix) {
  120625. Matrix4.clone(matrix, uniformState._view);
  120626. Matrix4.getRotation(matrix, uniformState._viewRotation);
  120627. uniformState._view3DDirty = true;
  120628. uniformState._inverseView3DDirty = true;
  120629. uniformState._modelViewDirty = true;
  120630. uniformState._modelView3DDirty = true;
  120631. uniformState._modelViewRelativeToEyeDirty = true;
  120632. uniformState._inverseModelViewDirty = true;
  120633. uniformState._inverseModelView3DDirty = true;
  120634. uniformState._viewProjectionDirty = true;
  120635. uniformState._inverseViewProjectionDirty = true;
  120636. uniformState._modelViewProjectionDirty = true;
  120637. uniformState._modelViewProjectionRelativeToEyeDirty = true;
  120638. uniformState._modelViewInfiniteProjectionDirty = true;
  120639. uniformState._normalDirty = true;
  120640. uniformState._inverseNormalDirty = true;
  120641. uniformState._normal3DDirty = true;
  120642. uniformState._inverseNormal3DDirty = true;
  120643. }
  120644. function setInverseView(uniformState, matrix) {
  120645. Matrix4.clone(matrix, uniformState._inverseView);
  120646. Matrix4.getRotation(matrix, uniformState._inverseViewRotation);
  120647. }
  120648. function setProjection(uniformState, matrix) {
  120649. Matrix4.clone(matrix, uniformState._projection);
  120650. uniformState._inverseProjectionDirty = true;
  120651. uniformState._inverseProjectionOITDirty = true;
  120652. uniformState._viewProjectionDirty = true;
  120653. uniformState._inverseViewProjectionDirty = true;
  120654. uniformState._modelViewProjectionDirty = true;
  120655. uniformState._modelViewProjectionRelativeToEyeDirty = true;
  120656. }
  120657. function setInfiniteProjection(uniformState, matrix) {
  120658. Matrix4.clone(matrix, uniformState._infiniteProjection);
  120659. uniformState._modelViewInfiniteProjectionDirty = true;
  120660. }
  120661. function setCamera(uniformState, camera) {
  120662. Cartesian3.clone(camera.positionWC, uniformState._cameraPosition);
  120663. Cartesian3.clone(camera.directionWC, uniformState._cameraDirection);
  120664. Cartesian3.clone(camera.rightWC, uniformState._cameraRight);
  120665. Cartesian3.clone(camera.upWC, uniformState._cameraUp);
  120666. uniformState._encodedCameraPositionMCDirty = true;
  120667. }
  120668. var transformMatrix = new Matrix3();
  120669. var sunCartographicScratch = new Cartographic();
  120670. function setSunAndMoonDirections(uniformState, frameState) {
  120671. if (!defined(Transforms.computeIcrfToFixedMatrix(frameState.time, transformMatrix))) {
  120672. transformMatrix = Transforms.computeTemeToPseudoFixedMatrix(frameState.time, transformMatrix);
  120673. }
  120674. var position = Simon1994PlanetaryPositions.computeSunPositionInEarthInertialFrame(frameState.time, uniformState._sunPositionWC);
  120675. Matrix3.multiplyByVector(transformMatrix, position, position);
  120676. Cartesian3.normalize(position, uniformState._sunDirectionWC);
  120677. position = Matrix3.multiplyByVector(uniformState.viewRotation3D, position, uniformState._sunDirectionEC);
  120678. Cartesian3.normalize(position, position);
  120679. position = Simon1994PlanetaryPositions.computeMoonPositionInEarthInertialFrame(frameState.time, uniformState._moonDirectionEC);
  120680. Matrix3.multiplyByVector(transformMatrix, position, position);
  120681. Matrix3.multiplyByVector(uniformState.viewRotation3D, position, position);
  120682. Cartesian3.normalize(position, position);
  120683. var projection = frameState.mapProjection;
  120684. var ellipsoid = projection.ellipsoid;
  120685. var sunCartographic = ellipsoid.cartesianToCartographic(uniformState._sunPositionWC, sunCartographicScratch);
  120686. projection.project(sunCartographic, uniformState._sunPositionColumbusView);
  120687. }
  120688. /**
  120689. * Synchronizes the frustum's state with the camera state. This is called
  120690. * by the {@link Scene} when rendering to ensure that automatic GLSL uniforms
  120691. * are set to the right value.
  120692. *
  120693. * @param {Object} camera The camera to synchronize with.
  120694. */
  120695. UniformState.prototype.updateCamera = function(camera) {
  120696. setView(this, camera.viewMatrix);
  120697. setInverseView(this, camera.inverseViewMatrix);
  120698. setCamera(this, camera);
  120699. this._entireFrustum.x = camera.frustum.near;
  120700. this._entireFrustum.y = camera.frustum.far;
  120701. this.updateFrustum(camera.frustum);
  120702. };
  120703. /**
  120704. * Synchronizes the frustum's state with the uniform state. This is called
  120705. * by the {@link Scene} when rendering to ensure that automatic GLSL uniforms
  120706. * are set to the right value.
  120707. *
  120708. * @param {Object} frustum The frustum to synchronize with.
  120709. */
  120710. UniformState.prototype.updateFrustum = function(frustum) {
  120711. setProjection(this, frustum.projectionMatrix);
  120712. if (defined(frustum.infiniteProjectionMatrix)) {
  120713. setInfiniteProjection(this, frustum.infiniteProjectionMatrix);
  120714. }
  120715. this._currentFrustum.x = frustum.near;
  120716. this._currentFrustum.y = frustum.far;
  120717. if (!defined(frustum.top)) {
  120718. frustum = frustum._offCenterFrustum;
  120719. }
  120720. this._frustumPlanes.x = frustum.top;
  120721. this._frustumPlanes.y = frustum.bottom;
  120722. this._frustumPlanes.z = frustum.left;
  120723. this._frustumPlanes.w = frustum.right;
  120724. };
  120725. UniformState.prototype.updatePass = function(pass) {
  120726. this._pass = pass;
  120727. };
  120728. /**
  120729. * Synchronizes frame state with the uniform state. This is called
  120730. * by the {@link Scene} when rendering to ensure that automatic GLSL uniforms
  120731. * are set to the right value.
  120732. *
  120733. * @param {FrameState} frameState The frameState to synchronize with.
  120734. */
  120735. UniformState.prototype.update = function(frameState) {
  120736. this._mode = frameState.mode;
  120737. this._mapProjection = frameState.mapProjection;
  120738. var canvas = frameState.context._canvas;
  120739. this._resolutionScale = canvas.width / canvas.clientWidth;
  120740. var camera = frameState.camera;
  120741. this.updateCamera(camera);
  120742. if (frameState.mode === SceneMode.SCENE2D) {
  120743. this._frustum2DWidth = camera.frustum.right - camera.frustum.left;
  120744. this._eyeHeight2D.x = this._frustum2DWidth * 0.5;
  120745. this._eyeHeight2D.y = this._eyeHeight2D.x * this._eyeHeight2D.x;
  120746. } else {
  120747. this._frustum2DWidth = 0.0;
  120748. this._eyeHeight2D.x = 0.0;
  120749. this._eyeHeight2D.y = 0.0;
  120750. }
  120751. setSunAndMoonDirections(this, frameState);
  120752. this._fogDensity = frameState.fog.density;
  120753. this._frameState = frameState;
  120754. this._temeToPseudoFixed = Transforms.computeTemeToPseudoFixedMatrix(frameState.time, this._temeToPseudoFixed);
  120755. };
  120756. function cleanViewport(uniformState) {
  120757. if (uniformState._viewportDirty) {
  120758. var v = uniformState._viewport;
  120759. Matrix4.computeOrthographicOffCenter(v.x, v.x + v.width, v.y, v.y + v.height, 0.0, 1.0, uniformState._viewportOrthographicMatrix);
  120760. Matrix4.computeViewportTransformation(v, 0.0, 1.0, uniformState._viewportTransformation);
  120761. uniformState._viewportDirty = false;
  120762. }
  120763. }
  120764. function cleanInverseProjection(uniformState) {
  120765. if (uniformState._inverseProjectionDirty) {
  120766. uniformState._inverseProjectionDirty = false;
  120767. Matrix4.inverse(uniformState._projection, uniformState._inverseProjection);
  120768. }
  120769. }
  120770. function cleanInverseProjectionOIT(uniformState) {
  120771. if (uniformState._inverseProjectionOITDirty) {
  120772. uniformState._inverseProjectionOITDirty = false;
  120773. if (uniformState._mode !== SceneMode.SCENE2D && uniformState._mode !== SceneMode.MORPHING) {
  120774. Matrix4.inverse(uniformState._projection, uniformState._inverseProjectionOIT);
  120775. } else {
  120776. Matrix4.clone(Matrix4.IDENTITY, uniformState._inverseProjectionOIT);
  120777. }
  120778. }
  120779. }
  120780. // Derived
  120781. function cleanModelView(uniformState) {
  120782. if (uniformState._modelViewDirty) {
  120783. uniformState._modelViewDirty = false;
  120784. Matrix4.multiplyTransformation(uniformState._view, uniformState._model, uniformState._modelView);
  120785. }
  120786. }
  120787. function cleanModelView3D(uniformState) {
  120788. if (uniformState._modelView3DDirty) {
  120789. uniformState._modelView3DDirty = false;
  120790. Matrix4.multiplyTransformation(uniformState.view3D, uniformState._model, uniformState._modelView3D);
  120791. }
  120792. }
  120793. function cleanInverseModelView(uniformState) {
  120794. if (uniformState._inverseModelViewDirty) {
  120795. uniformState._inverseModelViewDirty = false;
  120796. Matrix4.inverse(uniformState.modelView, uniformState._inverseModelView);
  120797. }
  120798. }
  120799. function cleanInverseModelView3D(uniformState) {
  120800. if (uniformState._inverseModelView3DDirty) {
  120801. uniformState._inverseModelView3DDirty = false;
  120802. Matrix4.inverse(uniformState.modelView3D, uniformState._inverseModelView3D);
  120803. }
  120804. }
  120805. function cleanViewProjection(uniformState) {
  120806. if (uniformState._viewProjectionDirty) {
  120807. uniformState._viewProjectionDirty = false;
  120808. Matrix4.multiply(uniformState._projection, uniformState._view, uniformState._viewProjection);
  120809. }
  120810. }
  120811. function cleanInverseViewProjection(uniformState) {
  120812. if (uniformState._inverseViewProjectionDirty) {
  120813. uniformState._inverseViewProjectionDirty = false;
  120814. Matrix4.inverse(uniformState.viewProjection, uniformState._inverseViewProjection);
  120815. }
  120816. }
  120817. function cleanModelViewProjection(uniformState) {
  120818. if (uniformState._modelViewProjectionDirty) {
  120819. uniformState._modelViewProjectionDirty = false;
  120820. Matrix4.multiply(uniformState._projection, uniformState.modelView, uniformState._modelViewProjection);
  120821. }
  120822. }
  120823. function cleanModelViewRelativeToEye(uniformState) {
  120824. if (uniformState._modelViewRelativeToEyeDirty) {
  120825. uniformState._modelViewRelativeToEyeDirty = false;
  120826. var mv = uniformState.modelView;
  120827. var mvRte = uniformState._modelViewRelativeToEye;
  120828. mvRte[0] = mv[0];
  120829. mvRte[1] = mv[1];
  120830. mvRte[2] = mv[2];
  120831. mvRte[3] = mv[3];
  120832. mvRte[4] = mv[4];
  120833. mvRte[5] = mv[5];
  120834. mvRte[6] = mv[6];
  120835. mvRte[7] = mv[7];
  120836. mvRte[8] = mv[8];
  120837. mvRte[9] = mv[9];
  120838. mvRte[10] = mv[10];
  120839. mvRte[11] = mv[11];
  120840. mvRte[12] = 0.0;
  120841. mvRte[13] = 0.0;
  120842. mvRte[14] = 0.0;
  120843. mvRte[15] = mv[15];
  120844. }
  120845. }
  120846. function cleanInverseModelViewProjection(uniformState) {
  120847. if (uniformState._inverseModelViewProjectionDirty) {
  120848. uniformState._inverseModelViewProjectionDirty = false;
  120849. Matrix4.inverse(uniformState.modelViewProjection, uniformState._inverseModelViewProjection);
  120850. }
  120851. }
  120852. function cleanModelViewProjectionRelativeToEye(uniformState) {
  120853. if (uniformState._modelViewProjectionRelativeToEyeDirty) {
  120854. uniformState._modelViewProjectionRelativeToEyeDirty = false;
  120855. Matrix4.multiply(uniformState._projection, uniformState.modelViewRelativeToEye, uniformState._modelViewProjectionRelativeToEye);
  120856. }
  120857. }
  120858. function cleanModelViewInfiniteProjection(uniformState) {
  120859. if (uniformState._modelViewInfiniteProjectionDirty) {
  120860. uniformState._modelViewInfiniteProjectionDirty = false;
  120861. Matrix4.multiply(uniformState._infiniteProjection, uniformState.modelView, uniformState._modelViewInfiniteProjection);
  120862. }
  120863. }
  120864. function cleanNormal(uniformState) {
  120865. if (uniformState._normalDirty) {
  120866. uniformState._normalDirty = false;
  120867. var m = uniformState._normal;
  120868. Matrix4.getRotation(uniformState.inverseModelView, m);
  120869. Matrix3.transpose(m, m);
  120870. }
  120871. }
  120872. function cleanNormal3D(uniformState) {
  120873. if (uniformState._normal3DDirty) {
  120874. uniformState._normal3DDirty = false;
  120875. var m = uniformState._normal3D;
  120876. Matrix4.getRotation(uniformState.inverseModelView3D, m);
  120877. Matrix3.transpose(m, m);
  120878. }
  120879. }
  120880. function cleanInverseNormal(uniformState) {
  120881. if (uniformState._inverseNormalDirty) {
  120882. uniformState._inverseNormalDirty = false;
  120883. Matrix4.getRotation(uniformState.inverseModelView, uniformState._inverseNormal);
  120884. }
  120885. }
  120886. function cleanInverseNormal3D(uniformState) {
  120887. if (uniformState._inverseNormal3DDirty) {
  120888. uniformState._inverseNormal3DDirty = false;
  120889. Matrix4.getRotation(uniformState.inverseModelView3D, uniformState._inverseNormal3D);
  120890. }
  120891. }
  120892. var cameraPositionMC = new Cartesian3();
  120893. function cleanEncodedCameraPositionMC(uniformState) {
  120894. if (uniformState._encodedCameraPositionMCDirty) {
  120895. uniformState._encodedCameraPositionMCDirty = false;
  120896. Matrix4.multiplyByPoint(uniformState.inverseModel, uniformState._cameraPosition, cameraPositionMC);
  120897. EncodedCartesian3.fromCartesian(cameraPositionMC, uniformState._encodedCameraPositionMC);
  120898. }
  120899. }
  120900. var view2Dto3DPScratch = new Cartesian3();
  120901. var view2Dto3DRScratch = new Cartesian3();
  120902. var view2Dto3DUScratch = new Cartesian3();
  120903. var view2Dto3DDScratch = new Cartesian3();
  120904. var view2Dto3DCartographicScratch = new Cartographic();
  120905. var view2Dto3DCartesian3Scratch = new Cartesian3();
  120906. var view2Dto3DMatrix4Scratch = new Matrix4();
  120907. function view2Dto3D(position2D, direction2D, right2D, up2D, frustum2DWidth, mode, projection, result) {
  120908. // The camera position and directions are expressed in the 2D coordinate system where the Y axis is to the East,
  120909. // the Z axis is to the North, and the X axis is out of the map. Express them instead in the ENU axes where
  120910. // X is to the East, Y is to the North, and Z is out of the local horizontal plane.
  120911. var p = view2Dto3DPScratch;
  120912. p.x = position2D.y;
  120913. p.y = position2D.z;
  120914. p.z = position2D.x;
  120915. var r = view2Dto3DRScratch;
  120916. r.x = right2D.y;
  120917. r.y = right2D.z;
  120918. r.z = right2D.x;
  120919. var u = view2Dto3DUScratch;
  120920. u.x = up2D.y;
  120921. u.y = up2D.z;
  120922. u.z = up2D.x;
  120923. var d = view2Dto3DDScratch;
  120924. d.x = direction2D.y;
  120925. d.y = direction2D.z;
  120926. d.z = direction2D.x;
  120927. // In 2D, the camera height is always 12.7 million meters.
  120928. // The apparent height is equal to half the frustum width.
  120929. if (mode === SceneMode.SCENE2D) {
  120930. p.z = frustum2DWidth * 0.5;
  120931. }
  120932. // Compute the equivalent camera position in the real (3D) world.
  120933. // In 2D and Columbus View, the camera can travel outside the projection, and when it does so
  120934. // there's not really any corresponding location in the real world. So clamp the unprojected
  120935. // longitude and latitude to their valid ranges.
  120936. var cartographic = projection.unproject(p, view2Dto3DCartographicScratch);
  120937. cartographic.longitude = CesiumMath.clamp(cartographic.longitude, -Math.PI, Math.PI);
  120938. cartographic.latitude = CesiumMath.clamp(cartographic.latitude, -CesiumMath.PI_OVER_TWO, CesiumMath.PI_OVER_TWO);
  120939. var ellipsoid = projection.ellipsoid;
  120940. var position3D = ellipsoid.cartographicToCartesian(cartographic, view2Dto3DCartesian3Scratch);
  120941. // Compute the rotation from the local ENU at the real world camera position to the fixed axes.
  120942. var enuToFixed = Transforms.eastNorthUpToFixedFrame(position3D, ellipsoid, view2Dto3DMatrix4Scratch);
  120943. // Transform each camera direction to the fixed axes.
  120944. Matrix4.multiplyByPointAsVector(enuToFixed, r, r);
  120945. Matrix4.multiplyByPointAsVector(enuToFixed, u, u);
  120946. Matrix4.multiplyByPointAsVector(enuToFixed, d, d);
  120947. // Compute the view matrix based on the new fixed-frame camera position and directions.
  120948. if (!defined(result)) {
  120949. result = new Matrix4();
  120950. }
  120951. result[0] = r.x;
  120952. result[1] = u.x;
  120953. result[2] = -d.x;
  120954. result[3] = 0.0;
  120955. result[4] = r.y;
  120956. result[5] = u.y;
  120957. result[6] = -d.y;
  120958. result[7] = 0.0;
  120959. result[8] = r.z;
  120960. result[9] = u.z;
  120961. result[10] = -d.z;
  120962. result[11] = 0.0;
  120963. result[12] = -Cartesian3.dot(r, position3D);
  120964. result[13] = -Cartesian3.dot(u, position3D);
  120965. result[14] = Cartesian3.dot(d, position3D);
  120966. result[15] = 1.0;
  120967. return result;
  120968. }
  120969. function updateView3D(that) {
  120970. if (that._view3DDirty) {
  120971. if (that._mode === SceneMode.SCENE3D) {
  120972. Matrix4.clone(that._view, that._view3D);
  120973. } else {
  120974. view2Dto3D(that._cameraPosition, that._cameraDirection, that._cameraRight, that._cameraUp, that._frustum2DWidth, that._mode, that._mapProjection, that._view3D);
  120975. }
  120976. Matrix4.getRotation(that._view3D, that._viewRotation3D);
  120977. that._view3DDirty = false;
  120978. }
  120979. }
  120980. function updateInverseView3D(that){
  120981. if (that._inverseView3DDirty) {
  120982. Matrix4.inverseTransformation(that.view3D, that._inverseView3D);
  120983. Matrix4.getRotation(that._inverseView3D, that._inverseViewRotation3D);
  120984. that._inverseView3DDirty = false;
  120985. }
  120986. }
  120987. return UniformState;
  120988. });
  120989. /*global define*/
  120990. define('Renderer/Context',[
  120991. '../Core/clone',
  120992. '../Core/Color',
  120993. '../Core/ComponentDatatype',
  120994. '../Core/createGuid',
  120995. '../Core/defaultValue',
  120996. '../Core/defined',
  120997. '../Core/defineProperties',
  120998. '../Core/destroyObject',
  120999. '../Core/DeveloperError',
  121000. '../Core/Geometry',
  121001. '../Core/GeometryAttribute',
  121002. '../Core/Matrix4',
  121003. '../Core/PrimitiveType',
  121004. '../Core/RuntimeError',
  121005. '../Core/WebGLConstants',
  121006. '../Shaders/ViewportQuadVS',
  121007. './BufferUsage',
  121008. './ClearCommand',
  121009. './ContextLimits',
  121010. './CubeMap',
  121011. './DrawCommand',
  121012. './PassState',
  121013. './PickFramebuffer',
  121014. './RenderState',
  121015. './ShaderCache',
  121016. './ShaderProgram',
  121017. './Texture',
  121018. './UniformState',
  121019. './VertexArray'
  121020. ], function(
  121021. clone,
  121022. Color,
  121023. ComponentDatatype,
  121024. createGuid,
  121025. defaultValue,
  121026. defined,
  121027. defineProperties,
  121028. destroyObject,
  121029. DeveloperError,
  121030. Geometry,
  121031. GeometryAttribute,
  121032. Matrix4,
  121033. PrimitiveType,
  121034. RuntimeError,
  121035. WebGLConstants,
  121036. ViewportQuadVS,
  121037. BufferUsage,
  121038. ClearCommand,
  121039. ContextLimits,
  121040. CubeMap,
  121041. DrawCommand,
  121042. PassState,
  121043. PickFramebuffer,
  121044. RenderState,
  121045. ShaderCache,
  121046. ShaderProgram,
  121047. Texture,
  121048. UniformState,
  121049. VertexArray) {
  121050. 'use strict';
  121051. /*global WebGLRenderingContext*/
  121052. /*global WebGL2RenderingContext*/
  121053. function errorToString(gl, error) {
  121054. var message = 'WebGL Error: ';
  121055. switch (error) {
  121056. case gl.INVALID_ENUM:
  121057. message += 'INVALID_ENUM';
  121058. break;
  121059. case gl.INVALID_VALUE:
  121060. message += 'INVALID_VALUE';
  121061. break;
  121062. case gl.INVALID_OPERATION:
  121063. message += 'INVALID_OPERATION';
  121064. break;
  121065. case gl.OUT_OF_MEMORY:
  121066. message += 'OUT_OF_MEMORY';
  121067. break;
  121068. case gl.CONTEXT_LOST_WEBGL:
  121069. message += 'CONTEXT_LOST_WEBGL lost';
  121070. break;
  121071. default:
  121072. message += 'Unknown (' + error + ')';
  121073. }
  121074. return message;
  121075. }
  121076. function createErrorMessage(gl, glFunc, glFuncArguments, error) {
  121077. var message = errorToString(gl, error) + ': ' + glFunc.name + '(';
  121078. for ( var i = 0; i < glFuncArguments.length; ++i) {
  121079. if (i !== 0) {
  121080. message += ', ';
  121081. }
  121082. message += glFuncArguments[i];
  121083. }
  121084. message += ');';
  121085. return message;
  121086. }
  121087. function throwOnError(gl, glFunc, glFuncArguments) {
  121088. var error = gl.getError();
  121089. if (error !== gl.NO_ERROR) {
  121090. throw new RuntimeError(createErrorMessage(gl, glFunc, glFuncArguments, error));
  121091. }
  121092. }
  121093. function makeGetterSetter(gl, propertyName, logFunc) {
  121094. return {
  121095. get : function() {
  121096. var value = gl[propertyName];
  121097. logFunc(gl, 'get: ' + propertyName, value);
  121098. return gl[propertyName];
  121099. },
  121100. set : function(value) {
  121101. gl[propertyName] = value;
  121102. logFunc(gl, 'set: ' + propertyName, value);
  121103. }
  121104. };
  121105. }
  121106. function wrapGL(gl, logFunc) {
  121107. if (!logFunc) {
  121108. return gl;
  121109. }
  121110. function wrapFunction(property) {
  121111. return function() {
  121112. var result = property.apply(gl, arguments);
  121113. logFunc(gl, property, arguments);
  121114. return result;
  121115. };
  121116. }
  121117. var glWrapper = {};
  121118. /*jslint forin: true*/
  121119. /*jshint forin: false*/
  121120. // JSLint normally demands that a for..in loop must directly contain an if,
  121121. // but in our loop below, we actually intend to iterate all properties, including
  121122. // those in the prototype.
  121123. for ( var propertyName in gl) {
  121124. var property = gl[propertyName];
  121125. // wrap any functions we encounter, otherwise just copy the property to the wrapper.
  121126. if (typeof property === 'function') {
  121127. glWrapper[propertyName] = wrapFunction(property);
  121128. } else {
  121129. Object.defineProperty(glWrapper, propertyName, makeGetterSetter(gl, propertyName, logFunc));
  121130. }
  121131. }
  121132. return glWrapper;
  121133. }
  121134. function getExtension(gl, names) {
  121135. var length = names.length;
  121136. for (var i = 0; i < length; ++i) {
  121137. var extension = gl.getExtension(names[i]);
  121138. if (extension) {
  121139. return extension;
  121140. }
  121141. }
  121142. return undefined;
  121143. }
  121144. /**
  121145. * @private
  121146. */
  121147. function Context(canvas, options) {
  121148. // this check must use typeof, not defined, because defined doesn't work with undeclared variables.
  121149. if (typeof WebGLRenderingContext === 'undefined') {
  121150. throw new RuntimeError('The browser does not support WebGL. Visit http://get.webgl.org.');
  121151. }
  121152. if (!defined(canvas)) {
  121153. throw new DeveloperError('canvas is required.');
  121154. }
  121155. this._canvas = canvas;
  121156. options = clone(options, true);
  121157. options = defaultValue(options, {});
  121158. options.allowTextureFilterAnisotropic = defaultValue(options.allowTextureFilterAnisotropic, true);
  121159. var webglOptions = defaultValue(options.webgl, {});
  121160. // Override select WebGL defaults
  121161. webglOptions.alpha = defaultValue(webglOptions.alpha, false); // WebGL default is true
  121162. webglOptions.stencil = defaultValue(webglOptions.stencil, true); // WebGL default is false
  121163. var defaultToWebgl2 = false;
  121164. var webgl2Supported = (typeof WebGL2RenderingContext !== 'undefined');
  121165. var webgl2 = false;
  121166. var glContext;
  121167. if (defaultToWebgl2 && webgl2Supported) {
  121168. glContext = canvas.getContext('webgl2', webglOptions) || canvas.getContext('experimental-webgl2', webglOptions) || undefined;
  121169. if (defined(glContext)) {
  121170. webgl2 = true;
  121171. }
  121172. }
  121173. if (!defined(glContext)) {
  121174. glContext = canvas.getContext('webgl', webglOptions) || canvas.getContext('experimental-webgl', webglOptions) || undefined;
  121175. }
  121176. if (!defined(glContext)) {
  121177. throw new RuntimeError('The browser supports WebGL, but initialization failed.');
  121178. }
  121179. this._originalGLContext = glContext;
  121180. this._webgl2 = webgl2;
  121181. this._id = createGuid();
  121182. // Validation and logging disabled by default for speed.
  121183. this.validateFramebuffer = false;
  121184. this.validateShaderProgram = false;
  121185. this.logShaderCompilation = false;
  121186. this._throwOnWebGLError = false;
  121187. this._shaderCache = new ShaderCache(this);
  121188. var gl = this._gl = this._originalGLContext;
  121189. this._redBits = gl.getParameter(gl.RED_BITS);
  121190. this._greenBits = gl.getParameter(gl.GREEN_BITS);
  121191. this._blueBits = gl.getParameter(gl.BLUE_BITS);
  121192. this._alphaBits = gl.getParameter(gl.ALPHA_BITS);
  121193. this._depthBits = gl.getParameter(gl.DEPTH_BITS);
  121194. this._stencilBits = gl.getParameter(gl.STENCIL_BITS);
  121195. ContextLimits._maximumCombinedTextureImageUnits = gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS); // min: 8
  121196. ContextLimits._maximumCubeMapSize = gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE); // min: 16
  121197. ContextLimits._maximumFragmentUniformVectors = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS); // min: 16
  121198. ContextLimits._maximumTextureImageUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS); // min: 8
  121199. ContextLimits._maximumRenderbufferSize = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE); // min: 1
  121200. ContextLimits._maximumTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE); // min: 64
  121201. ContextLimits._maximumVaryingVectors = gl.getParameter(gl.MAX_VARYING_VECTORS); // min: 8
  121202. ContextLimits._maximumVertexAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS); // min: 8
  121203. ContextLimits._maximumVertexTextureImageUnits = gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS); // min: 0
  121204. ContextLimits._maximumVertexUniformVectors = gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS); // min: 128
  121205. var aliasedLineWidthRange = gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE); // must include 1
  121206. ContextLimits._minimumAliasedLineWidth = aliasedLineWidthRange[0];
  121207. ContextLimits._maximumAliasedLineWidth = aliasedLineWidthRange[1];
  121208. var aliasedPointSizeRange = gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE); // must include 1
  121209. ContextLimits._minimumAliasedPointSize = aliasedPointSizeRange[0];
  121210. ContextLimits._maximumAliasedPointSize = aliasedPointSizeRange[1];
  121211. var maximumViewportDimensions = gl.getParameter(gl.MAX_VIEWPORT_DIMS);
  121212. ContextLimits._maximumViewportWidth = maximumViewportDimensions[0];
  121213. ContextLimits._maximumViewportHeight = maximumViewportDimensions[1];
  121214. var highpFloat = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
  121215. ContextLimits._highpFloatSupported = highpFloat.precision !== 0;
  121216. var highpInt = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_INT);
  121217. ContextLimits._highpIntSupported = highpInt.rangeMax !== 0;
  121218. this._antialias = gl.getContextAttributes().antialias;
  121219. // Query and initialize extensions
  121220. this._standardDerivatives = !!getExtension(gl, ['OES_standard_derivatives']);
  121221. this._elementIndexUint = !!getExtension(gl, ['OES_element_index_uint']);
  121222. this._depthTexture = !!getExtension(gl, ['WEBGL_depth_texture', 'WEBKIT_WEBGL_depth_texture']);
  121223. this._textureFloat = !!getExtension(gl, ['OES_texture_float']);
  121224. this._fragDepth = !!getExtension(gl, ['EXT_frag_depth']);
  121225. this._debugShaders = getExtension(gl, ['WEBGL_debug_shaders']);
  121226. var textureFilterAnisotropic = options.allowTextureFilterAnisotropic ? getExtension(gl, ['EXT_texture_filter_anisotropic', 'WEBKIT_EXT_texture_filter_anisotropic']) : undefined;
  121227. this._textureFilterAnisotropic = textureFilterAnisotropic;
  121228. ContextLimits._maximumTextureFilterAnisotropy = defined(textureFilterAnisotropic) ? gl.getParameter(textureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT) : 1.0;
  121229. var glCreateVertexArray;
  121230. var glBindVertexArray;
  121231. var glDeleteVertexArray;
  121232. var glDrawElementsInstanced;
  121233. var glDrawArraysInstanced;
  121234. var glVertexAttribDivisor;
  121235. var glDrawBuffers;
  121236. var vertexArrayObject;
  121237. var instancedArrays;
  121238. var drawBuffers;
  121239. if (webgl2) {
  121240. var that = this;
  121241. glCreateVertexArray = function () { return that._gl.createVertexArray(); };
  121242. glBindVertexArray = function(vao) { that._gl.bindVertexArray(vao); };
  121243. glDeleteVertexArray = function(vao) { that._gl.deleteVertexArray(vao); };
  121244. glDrawElementsInstanced = function(mode, count, type, offset, instanceCount) { gl.drawElementsInstanced(mode, count, type, offset, instanceCount); };
  121245. glDrawArraysInstanced = function(mode, first, count, instanceCount) { gl.drawArraysInstanced(mode, first, count, instanceCount); };
  121246. glVertexAttribDivisor = function(index, divisor) { gl.vertexAttribDivisor(index, divisor); };
  121247. glDrawBuffers = function(buffers) { gl.drawBuffers(buffers); };
  121248. } else {
  121249. vertexArrayObject = getExtension(gl, ['OES_vertex_array_object']);
  121250. if (defined(vertexArrayObject)) {
  121251. glCreateVertexArray = function() { return vertexArrayObject.createVertexArrayOES(); };
  121252. glBindVertexArray = function(vertexArray) { vertexArrayObject.bindVertexArrayOES(vertexArray); };
  121253. glDeleteVertexArray = function(vertexArray) { vertexArrayObject.deleteVertexArrayOES(vertexArray); };
  121254. }
  121255. instancedArrays = getExtension(gl, ['ANGLE_instanced_arrays']);
  121256. if (defined(instancedArrays)) {
  121257. glDrawElementsInstanced = function(mode, count, type, offset, instanceCount) { instancedArrays.drawElementsInstancedANGLE(mode, count, type, offset, instanceCount); };
  121258. glDrawArraysInstanced = function(mode, first, count, instanceCount) { instancedArrays.drawArraysInstancedANGLE(mode, first, count, instanceCount); };
  121259. glVertexAttribDivisor = function(index, divisor) { instancedArrays.vertexAttribDivisorANGLE(index, divisor); };
  121260. }
  121261. drawBuffers = getExtension(gl, ['WEBGL_draw_buffers']);
  121262. if (defined(drawBuffers)) {
  121263. glDrawBuffers = function(buffers) { drawBuffers.drawBuffersWEBGL(buffers); };
  121264. }
  121265. }
  121266. this.glCreateVertexArray = glCreateVertexArray;
  121267. this.glBindVertexArray = glBindVertexArray;
  121268. this.glDeleteVertexArray = glDeleteVertexArray;
  121269. this.glDrawElementsInstanced = glDrawElementsInstanced;
  121270. this.glDrawArraysInstanced = glDrawArraysInstanced;
  121271. this.glVertexAttribDivisor = glVertexAttribDivisor;
  121272. this.glDrawBuffers = glDrawBuffers;
  121273. this._vertexArrayObject = !!vertexArrayObject;
  121274. this._instancedArrays = !!instancedArrays;
  121275. this._drawBuffers = !!drawBuffers;
  121276. ContextLimits._maximumDrawBuffers = this.drawBuffers ? gl.getParameter(WebGLConstants.MAX_DRAW_BUFFERS) : 1;
  121277. ContextLimits._maximumColorAttachments = this.drawBuffers ? gl.getParameter(WebGLConstants.MAX_COLOR_ATTACHMENTS) : 1;
  121278. var cc = gl.getParameter(gl.COLOR_CLEAR_VALUE);
  121279. this._clearColor = new Color(cc[0], cc[1], cc[2], cc[3]);
  121280. this._clearDepth = gl.getParameter(gl.DEPTH_CLEAR_VALUE);
  121281. this._clearStencil = gl.getParameter(gl.STENCIL_CLEAR_VALUE);
  121282. var us = new UniformState();
  121283. var ps = new PassState(this);
  121284. var rs = RenderState.fromCache();
  121285. this._defaultPassState = ps;
  121286. this._defaultRenderState = rs;
  121287. this._defaultTexture = undefined;
  121288. this._defaultCubeMap = undefined;
  121289. this._us = us;
  121290. this._currentRenderState = rs;
  121291. this._currentPassState = ps;
  121292. this._currentFramebuffer = undefined;
  121293. this._maxFrameTextureUnitIndex = 0;
  121294. // Vertex attribute divisor state cache. Workaround for ANGLE (also look at VertexArray.setVertexAttribDivisor)
  121295. this._vertexAttribDivisors = [];
  121296. this._previousDrawInstanced = false;
  121297. for (var i = 0; i < ContextLimits._maximumVertexAttributes; i++) {
  121298. this._vertexAttribDivisors.push(0);
  121299. }
  121300. this._pickObjects = {};
  121301. this._nextPickColor = new Uint32Array(1);
  121302. /**
  121303. * @example
  121304. * {
  121305. * webgl : {
  121306. * alpha : false,
  121307. * depth : true,
  121308. * stencil : false,
  121309. * antialias : true,
  121310. * premultipliedAlpha : true,
  121311. * preserveDrawingBuffer : false,
  121312. * failIfMajorPerformanceCaveat : true
  121313. * },
  121314. * allowTextureFilterAnisotropic : true
  121315. * }
  121316. */
  121317. this.options = options;
  121318. /**
  121319. * A cache of objects tied to this context. Just before the Context is destroyed,
  121320. * <code>destroy</code> will be invoked on each object in this object literal that has
  121321. * such a method. This is useful for caching any objects that might otherwise
  121322. * be stored globally, except they're tied to a particular context, and to manage
  121323. * their lifetime.
  121324. *
  121325. * @type {Object}
  121326. */
  121327. this.cache = {};
  121328. RenderState.apply(gl, rs, ps);
  121329. }
  121330. var defaultFramebufferMarker = {};
  121331. defineProperties(Context.prototype, {
  121332. id : {
  121333. get : function() {
  121334. return this._id;
  121335. }
  121336. },
  121337. webgl2 : {
  121338. get : function() {
  121339. return this._webgl2;
  121340. }
  121341. },
  121342. canvas : {
  121343. get : function() {
  121344. return this._canvas;
  121345. }
  121346. },
  121347. shaderCache : {
  121348. get : function() {
  121349. return this._shaderCache;
  121350. }
  121351. },
  121352. uniformState : {
  121353. get : function() {
  121354. return this._us;
  121355. }
  121356. },
  121357. /**
  121358. * The number of red bits per component in the default framebuffer's color buffer. The minimum is eight.
  121359. * @memberof Context.prototype
  121360. * @type {Number}
  121361. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>RED_BITS</code>.
  121362. */
  121363. redBits : {
  121364. get : function() {
  121365. return this._redBits;
  121366. }
  121367. },
  121368. /**
  121369. * The number of green bits per component in the default framebuffer's color buffer. The minimum is eight.
  121370. * @memberof Context.prototype
  121371. * @type {Number}
  121372. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>GREEN_BITS</code>.
  121373. */
  121374. greenBits : {
  121375. get : function() {
  121376. return this._greenBits;
  121377. }
  121378. },
  121379. /**
  121380. * The number of blue bits per component in the default framebuffer's color buffer. The minimum is eight.
  121381. * @memberof Context.prototype
  121382. * @type {Number}
  121383. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>BLUE_BITS</code>.
  121384. */
  121385. blueBits : {
  121386. get : function() {
  121387. return this._blueBits;
  121388. }
  121389. },
  121390. /**
  121391. * The number of alpha bits per component in the default framebuffer's color buffer. The minimum is eight.
  121392. * <br /><br />
  121393. * The alpha channel is used for GL destination alpha operations and by the HTML compositor to combine the color buffer
  121394. * with the rest of the page.
  121395. * @memberof Context.prototype
  121396. * @type {Number}
  121397. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>ALPHA_BITS</code>.
  121398. */
  121399. alphaBits : {
  121400. get : function() {
  121401. return this._alphaBits;
  121402. }
  121403. },
  121404. /**
  121405. * The number of depth bits per pixel in the default bound framebuffer. The minimum is 16 bits; most
  121406. * implementations will have 24 bits.
  121407. * @memberof Context.prototype
  121408. * @type {Number}
  121409. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>DEPTH_BITS</code>.
  121410. */
  121411. depthBits : {
  121412. get : function() {
  121413. return this._depthBits;
  121414. }
  121415. },
  121416. /**
  121417. * The number of stencil bits per pixel in the default bound framebuffer. The minimum is eight bits.
  121418. * @memberof Context.prototype
  121419. * @type {Number}
  121420. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>STENCIL_BITS</code>.
  121421. */
  121422. stencilBits : {
  121423. get : function() {
  121424. return this._stencilBits;
  121425. }
  121426. },
  121427. /**
  121428. * <code>true</code> if the WebGL context supports stencil buffers.
  121429. * Stencil buffers are not supported by all systems.
  121430. * @memberof Context.prototype
  121431. * @type {Boolean}
  121432. */
  121433. stencilBuffer : {
  121434. get : function() {
  121435. return this._stencilBits >= 8;
  121436. }
  121437. },
  121438. /**
  121439. * <code>true</code> if the WebGL context supports antialiasing. By default
  121440. * antialiasing is requested, but it is not supported by all systems.
  121441. * @memberof Context.prototype
  121442. * @type {Boolean}
  121443. */
  121444. antialias : {
  121445. get : function() {
  121446. return this._antialias;
  121447. }
  121448. },
  121449. /**
  121450. * <code>true</code> if the OES_standard_derivatives extension is supported. This
  121451. * extension provides access to <code>dFdx</code>, <code>dFdy</code>, and <code>fwidth</code>
  121452. * functions from GLSL. A shader using these functions still needs to explicitly enable the
  121453. * extension with <code>#extension GL_OES_standard_derivatives : enable</code>.
  121454. * @memberof Context.prototype
  121455. * @type {Boolean}
  121456. * @see {@link http://www.khronos.org/registry/gles/extensions/OES/OES_standard_derivatives.txt|OES_standard_derivatives}
  121457. */
  121458. standardDerivatives : {
  121459. get : function() {
  121460. return this._standardDerivatives;
  121461. }
  121462. },
  121463. /**
  121464. * <code>true</code> if the OES_element_index_uint extension is supported. This
  121465. * extension allows the use of unsigned int indices, which can improve performance by
  121466. * eliminating batch breaking caused by unsigned short indices.
  121467. * @memberof Context.prototype
  121468. * @type {Boolean}
  121469. * @see {@link http://www.khronos.org/registry/webgl/extensions/OES_element_index_uint/|OES_element_index_uint}
  121470. */
  121471. elementIndexUint : {
  121472. get : function() {
  121473. return this._elementIndexUint || this._webgl2;
  121474. }
  121475. },
  121476. /**
  121477. * <code>true</code> if WEBGL_depth_texture is supported. This extension provides
  121478. * access to depth textures that, for example, can be attached to framebuffers for shadow mapping.
  121479. * @memberof Context.prototype
  121480. * @type {Boolean}
  121481. * @see {@link http://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/|WEBGL_depth_texture}
  121482. */
  121483. depthTexture : {
  121484. get : function() {
  121485. return this._depthTexture;
  121486. }
  121487. },
  121488. /**
  121489. * <code>true</code> if OES_texture_float is supported. This extension provides
  121490. * access to floating point textures that, for example, can be attached to framebuffers for high dynamic range.
  121491. * @memberof Context.prototype
  121492. * @type {Boolean}
  121493. * @see {@link http://www.khronos.org/registry/gles/extensions/OES/OES_texture_float.txt|OES_texture_float}
  121494. */
  121495. floatingPointTexture : {
  121496. get : function() {
  121497. return this._textureFloat;
  121498. }
  121499. },
  121500. textureFilterAnisotropic : {
  121501. get : function() {
  121502. return !!this._textureFilterAnisotropic;
  121503. }
  121504. },
  121505. /**
  121506. * <code>true</code> if the OES_vertex_array_object extension is supported. This
  121507. * extension can improve performance by reducing the overhead of switching vertex arrays.
  121508. * When enabled, this extension is automatically used by {@link VertexArray}.
  121509. * @memberof Context.prototype
  121510. * @type {Boolean}
  121511. * @see {@link http://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/|OES_vertex_array_object}
  121512. */
  121513. vertexArrayObject : {
  121514. get : function() {
  121515. return this._vertexArrayObject || this._webgl2;
  121516. }
  121517. },
  121518. /**
  121519. * <code>true</code> if the EXT_frag_depth extension is supported. This
  121520. * extension provides access to the <code>gl_FragDepthEXT</code> built-in output variable
  121521. * from GLSL fragment shaders. A shader using these functions still needs to explicitly enable the
  121522. * extension with <code>#extension GL_EXT_frag_depth : enable</code>.
  121523. * @memberof Context.prototype
  121524. * @type {Boolean}
  121525. * @see {@link http://www.khronos.org/registry/webgl/extensions/EXT_frag_depth/|EXT_frag_depth}
  121526. */
  121527. fragmentDepth : {
  121528. get : function() {
  121529. return this._fragDepth;
  121530. }
  121531. },
  121532. /**
  121533. * <code>true</code> if the ANGLE_instanced_arrays extension is supported. This
  121534. * extension provides access to instanced rendering.
  121535. * @memberof Context.prototype
  121536. * @type {Boolean}
  121537. * @see {@link https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays}
  121538. */
  121539. instancedArrays : {
  121540. get : function() {
  121541. return this._instancedArrays || this._webgl2;
  121542. }
  121543. },
  121544. /**
  121545. * <code>true</code> if the WEBGL_draw_buffers extension is supported. This
  121546. * extensions provides support for multiple render targets. The framebuffer object can have mutiple
  121547. * color attachments and the GLSL fragment shader can write to the built-in output array <code>gl_FragData</code>.
  121548. * A shader using this feature needs to explicitly enable the extension with
  121549. * <code>#extension GL_EXT_draw_buffers : enable</code>.
  121550. * @memberof Context.prototype
  121551. * @type {Boolean}
  121552. * @see {@link http://www.khronos.org/registry/webgl/extensions/WEBGL_draw_buffers/|WEBGL_draw_buffers}
  121553. */
  121554. drawBuffers : {
  121555. get : function() {
  121556. return this._drawBuffers || this._webgl2;
  121557. }
  121558. },
  121559. debugShaders : {
  121560. get : function() {
  121561. return this._debugShaders;
  121562. }
  121563. },
  121564. throwOnWebGLError : {
  121565. get : function() {
  121566. return this._throwOnWebGLError;
  121567. },
  121568. set : function(value) {
  121569. this._throwOnWebGLError = value;
  121570. this._gl = wrapGL(this._originalGLContext, value ? throwOnError : null);
  121571. }
  121572. },
  121573. /**
  121574. * A 1x1 RGBA texture initialized to [255, 255, 255, 255]. This can
  121575. * be used as a placeholder texture while other textures are downloaded.
  121576. * @memberof Context.prototype
  121577. * @type {Texture}
  121578. */
  121579. defaultTexture : {
  121580. get : function() {
  121581. if (this._defaultTexture === undefined) {
  121582. this._defaultTexture = new Texture({
  121583. context : this,
  121584. source : {
  121585. width : 1,
  121586. height : 1,
  121587. arrayBufferView : new Uint8Array([255, 255, 255, 255])
  121588. }
  121589. });
  121590. }
  121591. return this._defaultTexture;
  121592. }
  121593. },
  121594. /**
  121595. * A cube map, where each face is a 1x1 RGBA texture initialized to
  121596. * [255, 255, 255, 255]. This can be used as a placeholder cube map while
  121597. * other cube maps are downloaded.
  121598. * @memberof Context.prototype
  121599. * @type {CubeMap}
  121600. */
  121601. defaultCubeMap : {
  121602. get : function() {
  121603. if (this._defaultCubeMap === undefined) {
  121604. var face = {
  121605. width : 1,
  121606. height : 1,
  121607. arrayBufferView : new Uint8Array([255, 255, 255, 255])
  121608. };
  121609. this._defaultCubeMap = new CubeMap({
  121610. context : this,
  121611. source : {
  121612. positiveX : face,
  121613. negativeX : face,
  121614. positiveY : face,
  121615. negativeY : face,
  121616. positiveZ : face,
  121617. negativeZ : face
  121618. }
  121619. });
  121620. }
  121621. return this._defaultCubeMap;
  121622. }
  121623. },
  121624. /**
  121625. * The drawingBufferHeight of the underlying GL context.
  121626. * @memberof Context.prototype
  121627. * @type {Number}
  121628. * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferHeight|drawingBufferHeight}
  121629. */
  121630. drawingBufferHeight : {
  121631. get : function() {
  121632. return this._gl.drawingBufferHeight;
  121633. }
  121634. },
  121635. /**
  121636. * The drawingBufferWidth of the underlying GL context.
  121637. * @memberof Context.prototype
  121638. * @type {Number}
  121639. * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferWidth|drawingBufferWidth}
  121640. */
  121641. drawingBufferWidth : {
  121642. get : function() {
  121643. return this._gl.drawingBufferWidth;
  121644. }
  121645. },
  121646. /**
  121647. * Gets an object representing the currently bound framebuffer. While this instance is not an actual
  121648. * {@link Framebuffer}, it is used to represent the default framebuffer in calls to
  121649. * {@link Texture.FromFramebuffer}.
  121650. * @memberof Context.prototype
  121651. * @type {Object}
  121652. */
  121653. defaultFramebuffer : {
  121654. get : function() {
  121655. return defaultFramebufferMarker;
  121656. }
  121657. }
  121658. });
  121659. /**
  121660. * Validates a framebuffer.
  121661. * Available in debug builds only.
  121662. * @private
  121663. */
  121664. function validateFramebuffer(context) {
  121665. if (context.validateFramebuffer) {
  121666. var gl = context._gl;
  121667. var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
  121668. if (status !== gl.FRAMEBUFFER_COMPLETE) {
  121669. var message;
  121670. switch (status) {
  121671. case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
  121672. message = 'Framebuffer is not complete. Incomplete attachment: at least one attachment point with a renderbuffer or texture attached has its attached object no longer in existence or has an attached image with a width or height of zero, or the color attachment point has a non-color-renderable image attached, or the depth attachment point has a non-depth-renderable image attached, or the stencil attachment point has a non-stencil-renderable image attached. Color-renderable formats include GL_RGBA4, GL_RGB5_A1, and GL_RGB565. GL_DEPTH_COMPONENT16 is the only depth-renderable format. GL_STENCIL_INDEX8 is the only stencil-renderable format.';
  121673. break;
  121674. case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
  121675. message = 'Framebuffer is not complete. Incomplete dimensions: not all attached images have the same width and height.';
  121676. break;
  121677. case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
  121678. message = 'Framebuffer is not complete. Missing attachment: no images are attached to the framebuffer.';
  121679. break;
  121680. case gl.FRAMEBUFFER_UNSUPPORTED:
  121681. message = 'Framebuffer is not complete. Unsupported: the combination of internal formats of the attached images violates an implementation-dependent set of restrictions.';
  121682. break;
  121683. }
  121684. throw new DeveloperError(message);
  121685. }
  121686. }
  121687. }
  121688. function applyRenderState(context, renderState, passState, clear) {
  121689. var previousRenderState = context._currentRenderState;
  121690. var previousPassState = context._currentPassState;
  121691. context._currentRenderState = renderState;
  121692. context._currentPassState = passState;
  121693. RenderState.partialApply(context._gl, previousRenderState, renderState, previousPassState, passState, clear);
  121694. }
  121695. var scratchBackBufferArray;
  121696. // this check must use typeof, not defined, because defined doesn't work with undeclared variables.
  121697. if (typeof WebGLRenderingContext !== 'undefined') {
  121698. scratchBackBufferArray = [WebGLConstants.BACK];
  121699. }
  121700. function bindFramebuffer(context, framebuffer) {
  121701. if (framebuffer !== context._currentFramebuffer) {
  121702. context._currentFramebuffer = framebuffer;
  121703. var buffers = scratchBackBufferArray;
  121704. if (defined(framebuffer)) {
  121705. framebuffer._bind();
  121706. validateFramebuffer(context);
  121707. // TODO: Need a way for a command to give what draw buffers are active.
  121708. buffers = framebuffer._getActiveColorAttachments();
  121709. } else {
  121710. var gl = context._gl;
  121711. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  121712. }
  121713. if (context.drawBuffers) {
  121714. context.glDrawBuffers(buffers);
  121715. }
  121716. }
  121717. }
  121718. var defaultClearCommand = new ClearCommand();
  121719. Context.prototype.clear = function(clearCommand, passState) {
  121720. clearCommand = defaultValue(clearCommand, defaultClearCommand);
  121721. passState = defaultValue(passState, this._defaultPassState);
  121722. var gl = this._gl;
  121723. var bitmask = 0;
  121724. var c = clearCommand.color;
  121725. var d = clearCommand.depth;
  121726. var s = clearCommand.stencil;
  121727. if (defined(c)) {
  121728. if (!Color.equals(this._clearColor, c)) {
  121729. Color.clone(c, this._clearColor);
  121730. gl.clearColor(c.red, c.green, c.blue, c.alpha);
  121731. }
  121732. bitmask |= gl.COLOR_BUFFER_BIT;
  121733. }
  121734. if (defined(d)) {
  121735. if (d !== this._clearDepth) {
  121736. this._clearDepth = d;
  121737. gl.clearDepth(d);
  121738. }
  121739. bitmask |= gl.DEPTH_BUFFER_BIT;
  121740. }
  121741. if (defined(s)) {
  121742. if (s !== this._clearStencil) {
  121743. this._clearStencil = s;
  121744. gl.clearStencil(s);
  121745. }
  121746. bitmask |= gl.STENCIL_BUFFER_BIT;
  121747. }
  121748. var rs = defaultValue(clearCommand.renderState, this._defaultRenderState);
  121749. applyRenderState(this, rs, passState, true);
  121750. // The command's framebuffer takes presidence over the pass' framebuffer, e.g., for off-screen rendering.
  121751. var framebuffer = defaultValue(clearCommand.framebuffer, passState.framebuffer);
  121752. bindFramebuffer(this, framebuffer);
  121753. gl.clear(bitmask);
  121754. };
  121755. function beginDraw(context, framebuffer, drawCommand, passState) {
  121756. var rs = defaultValue(drawCommand._renderState, context._defaultRenderState);
  121757. if (defined(framebuffer) && rs.depthTest) {
  121758. if (rs.depthTest.enabled && !framebuffer.hasDepthAttachment) {
  121759. throw new DeveloperError('The depth test can not be enabled (drawCommand.renderState.depthTest.enabled) because the framebuffer (drawCommand.framebuffer) does not have a depth or depth-stencil renderbuffer.');
  121760. }
  121761. }
  121762. bindFramebuffer(context, framebuffer);
  121763. applyRenderState(context, rs, passState, false);
  121764. var sp = drawCommand._shaderProgram;
  121765. sp._bind();
  121766. context._maxFrameTextureUnitIndex = Math.max(context._maxFrameTextureUnitIndex, sp.maximumTextureUnitIndex);
  121767. }
  121768. function continueDraw(context, drawCommand) {
  121769. var primitiveType = drawCommand._primitiveType;
  121770. var va = drawCommand._vertexArray;
  121771. var offset = drawCommand._offset;
  121772. var count = drawCommand._count;
  121773. var instanceCount = drawCommand.instanceCount;
  121774. if (!PrimitiveType.validate(primitiveType)) {
  121775. throw new DeveloperError('drawCommand.primitiveType is required and must be valid.');
  121776. }
  121777. if (!defined(va)) {
  121778. throw new DeveloperError('drawCommand.vertexArray is required.');
  121779. }
  121780. if (offset < 0) {
  121781. throw new DeveloperError('drawCommand.offset must be greater than or equal to zero.');
  121782. }
  121783. if (count < 0) {
  121784. throw new DeveloperError('drawCommand.count must be greater than or equal to zero.');
  121785. }
  121786. if (instanceCount < 0) {
  121787. throw new DeveloperError('drawCommand.instanceCount must be greater than or equal to zero.');
  121788. }
  121789. if (instanceCount > 0 && !context.instancedArrays) {
  121790. throw new DeveloperError('Instanced arrays extension is not supported');
  121791. }
  121792. context._us.model = defaultValue(drawCommand._modelMatrix, Matrix4.IDENTITY);
  121793. drawCommand._shaderProgram._setUniforms(drawCommand._uniformMap, context._us, context.validateShaderProgram);
  121794. va._bind();
  121795. var indexBuffer = va.indexBuffer;
  121796. if (defined(indexBuffer)) {
  121797. offset = offset * indexBuffer.bytesPerIndex; // offset in vertices to offset in bytes
  121798. count = defaultValue(count, indexBuffer.numberOfIndices);
  121799. if (instanceCount === 0) {
  121800. context._gl.drawElements(primitiveType, count, indexBuffer.indexDatatype, offset);
  121801. } else {
  121802. context.glDrawElementsInstanced(primitiveType, count, indexBuffer.indexDatatype, offset, instanceCount);
  121803. }
  121804. } else {
  121805. count = defaultValue(count, va.numberOfVertices);
  121806. if (instanceCount === 0) {
  121807. context._gl.drawArrays(primitiveType, offset, count);
  121808. } else {
  121809. context.glDrawArraysInstanced(primitiveType, offset, count, instanceCount);
  121810. }
  121811. }
  121812. va._unBind();
  121813. }
  121814. Context.prototype.draw = function(drawCommand, passState) {
  121815. if (!defined(drawCommand)) {
  121816. throw new DeveloperError('drawCommand is required.');
  121817. }
  121818. if (!defined(drawCommand._shaderProgram)) {
  121819. throw new DeveloperError('drawCommand.shaderProgram is required.');
  121820. }
  121821. passState = defaultValue(passState, this._defaultPassState);
  121822. // The command's framebuffer takes presidence over the pass' framebuffer, e.g., for off-screen rendering.
  121823. var framebuffer = defaultValue(drawCommand._framebuffer, passState.framebuffer);
  121824. beginDraw(this, framebuffer, drawCommand, passState);
  121825. continueDraw(this, drawCommand);
  121826. };
  121827. Context.prototype.endFrame = function() {
  121828. var gl = this._gl;
  121829. gl.useProgram(null);
  121830. this._currentFramebuffer = undefined;
  121831. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  121832. var buffers = scratchBackBufferArray;
  121833. if (this.drawBuffers) {
  121834. this.glDrawBuffers(buffers);
  121835. }
  121836. var length = this._maxFrameTextureUnitIndex;
  121837. this._maxFrameTextureUnitIndex = 0;
  121838. for (var i = 0; i < length; ++i) {
  121839. gl.activeTexture(gl.TEXTURE0 + i);
  121840. gl.bindTexture(gl.TEXTURE_2D, null);
  121841. gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
  121842. }
  121843. };
  121844. Context.prototype.readPixels = function(readState) {
  121845. var gl = this._gl;
  121846. readState = readState || {};
  121847. var x = Math.max(readState.x || 0, 0);
  121848. var y = Math.max(readState.y || 0, 0);
  121849. var width = readState.width || gl.drawingBufferWidth;
  121850. var height = readState.height || gl.drawingBufferHeight;
  121851. var framebuffer = readState.framebuffer;
  121852. if (width <= 0) {
  121853. throw new DeveloperError('readState.width must be greater than zero.');
  121854. }
  121855. if (height <= 0) {
  121856. throw new DeveloperError('readState.height must be greater than zero.');
  121857. }
  121858. var pixels = new Uint8Array(4 * width * height);
  121859. bindFramebuffer(this, framebuffer);
  121860. gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
  121861. return pixels;
  121862. };
  121863. var viewportQuadAttributeLocations = {
  121864. position : 0,
  121865. textureCoordinates : 1
  121866. };
  121867. Context.prototype.getViewportQuadVertexArray = function() {
  121868. // Per-context cache for viewport quads
  121869. var vertexArray = this.cache.viewportQuad_vertexArray;
  121870. if (!defined(vertexArray)) {
  121871. var geometry = new Geometry({
  121872. attributes : {
  121873. position : new GeometryAttribute({
  121874. componentDatatype : ComponentDatatype.FLOAT,
  121875. componentsPerAttribute : 2,
  121876. values : [
  121877. -1.0, -1.0,
  121878. 1.0, -1.0,
  121879. 1.0, 1.0,
  121880. -1.0, 1.0
  121881. ]
  121882. }),
  121883. textureCoordinates : new GeometryAttribute({
  121884. componentDatatype : ComponentDatatype.FLOAT,
  121885. componentsPerAttribute : 2,
  121886. values : [
  121887. 0.0, 0.0,
  121888. 1.0, 0.0,
  121889. 1.0, 1.0,
  121890. 0.0, 1.0
  121891. ]
  121892. })
  121893. },
  121894. // Workaround Internet Explorer 11.0.8 lack of TRIANGLE_FAN
  121895. indices : new Uint16Array([0, 1, 2, 0, 2, 3]),
  121896. primitiveType : PrimitiveType.TRIANGLES
  121897. });
  121898. vertexArray = VertexArray.fromGeometry({
  121899. context : this,
  121900. geometry : geometry,
  121901. attributeLocations : viewportQuadAttributeLocations,
  121902. bufferUsage : BufferUsage.STATIC_DRAW,
  121903. interleave : true
  121904. });
  121905. this.cache.viewportQuad_vertexArray = vertexArray;
  121906. }
  121907. return vertexArray;
  121908. };
  121909. Context.prototype.createViewportQuadCommand = function(fragmentShaderSource, overrides) {
  121910. overrides = defaultValue(overrides, defaultValue.EMPTY_OBJECT);
  121911. return new DrawCommand({
  121912. vertexArray : this.getViewportQuadVertexArray(),
  121913. primitiveType : PrimitiveType.TRIANGLES,
  121914. renderState : overrides.renderState,
  121915. shaderProgram : ShaderProgram.fromCache({
  121916. context : this,
  121917. vertexShaderSource : ViewportQuadVS,
  121918. fragmentShaderSource : fragmentShaderSource,
  121919. attributeLocations : viewportQuadAttributeLocations
  121920. }),
  121921. uniformMap : overrides.uniformMap,
  121922. owner : overrides.owner,
  121923. framebuffer : overrides.framebuffer
  121924. });
  121925. };
  121926. Context.prototype.createPickFramebuffer = function() {
  121927. return new PickFramebuffer(this);
  121928. };
  121929. /**
  121930. * Gets the object associated with a pick color.
  121931. *
  121932. * @param {Color} pickColor The pick color.
  121933. * @returns {Object} The object associated with the pick color, or undefined if no object is associated with that color.
  121934. *
  121935. * @example
  121936. * var object = context.getObjectByPickColor(pickColor);
  121937. *
  121938. * @see Context#createPickId
  121939. */
  121940. Context.prototype.getObjectByPickColor = function(pickColor) {
  121941. if (!defined(pickColor)) {
  121942. throw new DeveloperError('pickColor is required.');
  121943. }
  121944. return this._pickObjects[pickColor.toRgba()];
  121945. };
  121946. function PickId(pickObjects, key, color) {
  121947. this._pickObjects = pickObjects;
  121948. this.key = key;
  121949. this.color = color;
  121950. }
  121951. defineProperties(PickId.prototype, {
  121952. object : {
  121953. get : function() {
  121954. return this._pickObjects[this.key];
  121955. },
  121956. set : function(value) {
  121957. this._pickObjects[this.key] = value;
  121958. }
  121959. }
  121960. });
  121961. PickId.prototype.destroy = function() {
  121962. delete this._pickObjects[this.key];
  121963. return undefined;
  121964. };
  121965. /**
  121966. * Creates a unique ID associated with the input object for use with color-buffer picking.
  121967. * The ID has an RGBA color value unique to this context. You must call destroy()
  121968. * on the pick ID when destroying the input object.
  121969. *
  121970. * @param {Object} object The object to associate with the pick ID.
  121971. * @returns {Object} A PickId object with a <code>color</code> property.
  121972. *
  121973. * @exception {RuntimeError} Out of unique Pick IDs.
  121974. *
  121975. *
  121976. * @example
  121977. * this._pickId = context.createPickId({
  121978. * primitive : this,
  121979. * id : this.id
  121980. * });
  121981. *
  121982. * @see Context#getObjectByPickColor
  121983. */
  121984. Context.prototype.createPickId = function(object) {
  121985. if (!defined(object)) {
  121986. throw new DeveloperError('object is required.');
  121987. }
  121988. // the increment and assignment have to be separate statements to
  121989. // actually detect overflow in the Uint32 value
  121990. ++this._nextPickColor[0];
  121991. var key = this._nextPickColor[0];
  121992. if (key === 0) {
  121993. // In case of overflow
  121994. throw new RuntimeError('Out of unique Pick IDs.');
  121995. }
  121996. this._pickObjects[key] = object;
  121997. return new PickId(this._pickObjects, key, Color.fromRgba(key));
  121998. };
  121999. Context.prototype.isDestroyed = function() {
  122000. return false;
  122001. };
  122002. Context.prototype.destroy = function() {
  122003. // Destroy all objects in the cache that have a destroy method.
  122004. var cache = this.cache;
  122005. for (var property in cache) {
  122006. if (cache.hasOwnProperty(property)) {
  122007. var propertyValue = cache[property];
  122008. if (defined(propertyValue.destroy)) {
  122009. propertyValue.destroy();
  122010. }
  122011. }
  122012. }
  122013. this._shaderCache = this._shaderCache.destroy();
  122014. this._defaultTexture = this._defaultTexture && this._defaultTexture.destroy();
  122015. this._defaultCubeMap = this._defaultCubeMap && this._defaultCubeMap.destroy();
  122016. return destroyObject(this);
  122017. };
  122018. return Context;
  122019. });
  122020. /*global define*/
  122021. define('Renderer/loadCubeMap',[
  122022. '../Core/defined',
  122023. '../Core/DeveloperError',
  122024. '../Core/loadImage',
  122025. '../ThirdParty/when',
  122026. './CubeMap'
  122027. ], function(
  122028. defined,
  122029. DeveloperError,
  122030. loadImage,
  122031. when,
  122032. CubeMap) {
  122033. 'use strict';
  122034. /**
  122035. * Asynchronously loads six images and creates a cube map. Returns a promise that
  122036. * will resolve to a {@link CubeMap} once loaded, or reject if any image fails to load.
  122037. *
  122038. * @exports loadCubeMap
  122039. *
  122040. * @param {Context} context The context to use to create the cube map.
  122041. * @param {Object} urls The source of each image, or a promise for each URL. See the example below.
  122042. * @param {Boolean} [allowCrossOrigin=true] Whether to request the image using Cross-Origin
  122043. * Resource Sharing (CORS). CORS is only actually used if the image URL is actually cross-origin.
  122044. * Data URIs are never requested using CORS.
  122045. * @returns {Promise.<CubeMap>} a promise that will resolve to the requested {@link CubeMap} when loaded.
  122046. *
  122047. * @exception {DeveloperError} context is required.
  122048. * @exception {DeveloperError} urls is required and must have positiveX, negativeX, positiveY, negativeY, positiveZ, and negativeZ properties.
  122049. *
  122050. *
  122051. * @example
  122052. * Cesium.loadCubeMap(context, {
  122053. * positiveX : 'skybox_px.png',
  122054. * negativeX : 'skybox_nx.png',
  122055. * positiveY : 'skybox_py.png',
  122056. * negativeY : 'skybox_ny.png',
  122057. * positiveZ : 'skybox_pz.png',
  122058. * negativeZ : 'skybox_nz.png'
  122059. * }).then(function(cubeMap) {
  122060. * // use the cubemap
  122061. * }).otherwise(function(error) {
  122062. * // an error occurred
  122063. * });
  122064. *
  122065. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  122066. * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
  122067. *
  122068. * @private
  122069. */
  122070. function loadCubeMap(context, urls, allowCrossOrigin) {
  122071. if (!defined(context)) {
  122072. throw new DeveloperError('context is required.');
  122073. }
  122074. if ((!defined(urls)) ||
  122075. (!defined(urls.positiveX)) ||
  122076. (!defined(urls.negativeX)) ||
  122077. (!defined(urls.positiveY)) ||
  122078. (!defined(urls.negativeY)) ||
  122079. (!defined(urls.positiveZ)) ||
  122080. (!defined(urls.negativeZ))) {
  122081. throw new DeveloperError('urls is required and must have positiveX, negativeX, positiveY, negativeY, positiveZ, and negativeZ properties.');
  122082. }
  122083. // PERFORMANCE_IDEA: Given the size of some cube maps, we should consider tiling them, which
  122084. // would prevent hiccups when uploading, for example, six 4096x4096 textures to the GPU.
  122085. //
  122086. // Also, it is perhaps acceptable to use the context here in the callbacks, but
  122087. // ideally, we would do it in the primitive's update function.
  122088. var facePromises = [
  122089. loadImage(urls.positiveX, allowCrossOrigin),
  122090. loadImage(urls.negativeX, allowCrossOrigin),
  122091. loadImage(urls.positiveY, allowCrossOrigin),
  122092. loadImage(urls.negativeY, allowCrossOrigin),
  122093. loadImage(urls.positiveZ, allowCrossOrigin),
  122094. loadImage(urls.negativeZ, allowCrossOrigin)
  122095. ];
  122096. return when.all(facePromises, function(images) {
  122097. return new CubeMap({
  122098. context : context,
  122099. source : {
  122100. positiveX : images[0],
  122101. negativeX : images[1],
  122102. positiveY : images[2],
  122103. negativeY : images[3],
  122104. positiveZ : images[4],
  122105. negativeZ : images[5]
  122106. }
  122107. });
  122108. });
  122109. }
  122110. return loadCubeMap;
  122111. });
  122112. /*global define*/
  122113. define('Scene/DiscardMissingTileImagePolicy',[
  122114. '../Core/defaultValue',
  122115. '../Core/defined',
  122116. '../Core/DeveloperError',
  122117. '../Core/getImagePixels',
  122118. '../Core/loadImageViaBlob',
  122119. '../ThirdParty/when'
  122120. ], function(
  122121. defaultValue,
  122122. defined,
  122123. DeveloperError,
  122124. getImagePixels,
  122125. loadImageViaBlob,
  122126. when) {
  122127. 'use strict';
  122128. /**
  122129. * A policy for discarding tile images that match a known image containing a
  122130. * "missing" image.
  122131. *
  122132. * @alias DiscardMissingTileImagePolicy
  122133. * @constructor
  122134. *
  122135. * @param {Object} options Object with the following properties:
  122136. * @param {String} options.missingImageUrl The URL of the known missing image.
  122137. * @param {Cartesian2[]} options.pixelsToCheck An array of {@link Cartesian2} pixel positions to
  122138. * compare against the missing image.
  122139. * @param {Boolean} [options.disableCheckIfAllPixelsAreTransparent=false] If true, the discard check will be disabled
  122140. * if all of the pixelsToCheck in the missingImageUrl have an alpha value of 0. If false, the
  122141. * discard check will proceed no matter the values of the pixelsToCheck.
  122142. */
  122143. function DiscardMissingTileImagePolicy(options) {
  122144. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  122145. if (!defined(options.missingImageUrl)) {
  122146. throw new DeveloperError('options.missingImageUrl is required.');
  122147. }
  122148. if (!defined(options.pixelsToCheck)) {
  122149. throw new DeveloperError('options.pixelsToCheck is required.');
  122150. }
  122151. this._pixelsToCheck = options.pixelsToCheck;
  122152. this._missingImagePixels = undefined;
  122153. this._missingImageByteLength = undefined;
  122154. this._isReady = false;
  122155. var that = this;
  122156. function success(image) {
  122157. if (defined(image.blob)) {
  122158. that._missingImageByteLength = image.blob.size;
  122159. }
  122160. var pixels = getImagePixels(image);
  122161. if (options.disableCheckIfAllPixelsAreTransparent) {
  122162. var allAreTransparent = true;
  122163. var width = image.width;
  122164. var pixelsToCheck = options.pixelsToCheck;
  122165. for (var i = 0, len = pixelsToCheck.length; allAreTransparent && i < len; ++i) {
  122166. var pos = pixelsToCheck[i];
  122167. var index = pos.x * 4 + pos.y * width;
  122168. var alpha = pixels[index + 3];
  122169. if (alpha > 0) {
  122170. allAreTransparent = false;
  122171. }
  122172. }
  122173. if (allAreTransparent) {
  122174. pixels = undefined;
  122175. }
  122176. }
  122177. that._missingImagePixels = pixels;
  122178. that._isReady = true;
  122179. }
  122180. function failure() {
  122181. // Failed to download "missing" image, so assume that any truly missing tiles
  122182. // will also fail to download and disable the discard check.
  122183. that._missingImagePixels = undefined;
  122184. that._isReady = true;
  122185. }
  122186. when(loadImageViaBlob(options.missingImageUrl), success, failure);
  122187. }
  122188. /**
  122189. * Determines if the discard policy is ready to process images.
  122190. * @returns {Boolean} True if the discard policy is ready to process images; otherwise, false.
  122191. */
  122192. DiscardMissingTileImagePolicy.prototype.isReady = function() {
  122193. return this._isReady;
  122194. };
  122195. /**
  122196. * Given a tile image, decide whether to discard that image.
  122197. *
  122198. * @param {Image} image An image to test.
  122199. * @returns {Boolean} True if the image should be discarded; otherwise, false.
  122200. *
  122201. * @exception {DeveloperError} <code>shouldDiscardImage</code> must not be called before the discard policy is ready.
  122202. */
  122203. DiscardMissingTileImagePolicy.prototype.shouldDiscardImage = function(image) {
  122204. if (!this._isReady) {
  122205. throw new DeveloperError('shouldDiscardImage must not be called before the discard policy is ready.');
  122206. }
  122207. var pixelsToCheck = this._pixelsToCheck;
  122208. var missingImagePixels = this._missingImagePixels;
  122209. // If missingImagePixels is undefined, it indicates that the discard check has been disabled.
  122210. if (!defined(missingImagePixels)) {
  122211. return false;
  122212. }
  122213. if (defined(image.blob) && image.blob.size !== this._missingImageByteLength) {
  122214. return false;
  122215. }
  122216. var pixels = getImagePixels(image);
  122217. var width = image.width;
  122218. for (var i = 0, len = pixelsToCheck.length; i < len; ++i) {
  122219. var pos = pixelsToCheck[i];
  122220. var index = pos.x * 4 + pos.y * width;
  122221. for (var offset = 0; offset < 4; ++offset) {
  122222. var pixel = index + offset;
  122223. if (pixels[pixel] !== missingImagePixels[pixel]) {
  122224. return false;
  122225. }
  122226. }
  122227. }
  122228. return true;
  122229. };
  122230. return DiscardMissingTileImagePolicy;
  122231. });
  122232. /*global define*/
  122233. define('Scene/ImageryLayerFeatureInfo',[
  122234. '../Core/defined'
  122235. ], function(
  122236. defined) {
  122237. 'use strict';
  122238. /**
  122239. * Describes a rasterized feature, such as a point, polygon, polyline, etc., in an imagery layer.
  122240. *
  122241. * @alias ImageryLayerFeatureInfo
  122242. * @constructor
  122243. */
  122244. function ImageryLayerFeatureInfo() {
  122245. /**
  122246. * Gets or sets the name of the feature.
  122247. * @type {String}
  122248. */
  122249. this.name = undefined;
  122250. /**
  122251. * Gets or sets an HTML description of the feature. The HTML is not trusted and should
  122252. * be sanitized before display to the user.
  122253. * @type {String}
  122254. */
  122255. this.description = undefined;
  122256. /**
  122257. * Gets or sets the position of the feature, or undefined if the position is not known.
  122258. *
  122259. * @type {Cartographic}
  122260. */
  122261. this.position = undefined;
  122262. /**
  122263. * Gets or sets the raw data describing the feature. The raw data may be in any
  122264. * number of formats, such as GeoJSON, KML, etc.
  122265. * @type {Object}
  122266. */
  122267. this.data = undefined;
  122268. /**
  122269. * Gets or sets the image layer of the feature.
  122270. * @type {Object}
  122271. */
  122272. this.imageryLayer = undefined;
  122273. }
  122274. /**
  122275. * Configures the name of this feature by selecting an appropriate property. The name will be obtained from
  122276. * one of the following sources, in this order: 1) the property with the name 'name', 2) the property with the name 'title',
  122277. * 3) the first property containing the word 'name', 4) the first property containing the word 'title'. If
  122278. * the name cannot be obtained from any of these sources, the existing name will be left unchanged.
  122279. *
  122280. * @param {Object} properties An object literal containing the properties of the feature.
  122281. */
  122282. ImageryLayerFeatureInfo.prototype.configureNameFromProperties = function(properties) {
  122283. var namePropertyPrecedence = 10;
  122284. var nameProperty;
  122285. for (var key in properties) {
  122286. if (properties.hasOwnProperty(key) && properties[key]) {
  122287. var lowerKey = key.toLowerCase();
  122288. if (namePropertyPrecedence > 1 && lowerKey === 'name') {
  122289. namePropertyPrecedence = 1;
  122290. nameProperty = key;
  122291. } else if (namePropertyPrecedence > 2 && lowerKey === 'title') {
  122292. namePropertyPrecedence = 2;
  122293. nameProperty = key;
  122294. } else if (namePropertyPrecedence > 3 && /name/i.test(key)) {
  122295. namePropertyPrecedence = 3;
  122296. nameProperty = key;
  122297. } else if (namePropertyPrecedence > 4 && /title/i.test(key)) {
  122298. namePropertyPrecedence = 4;
  122299. nameProperty = key;
  122300. }
  122301. }
  122302. }
  122303. if (defined(nameProperty)) {
  122304. this.name = properties[nameProperty];
  122305. }
  122306. };
  122307. /**
  122308. * Configures the description of this feature by creating an HTML table of properties and their values.
  122309. *
  122310. * @param {Object} properties An object literal containing the properties of the feature.
  122311. */
  122312. ImageryLayerFeatureInfo.prototype.configureDescriptionFromProperties = function(properties) {
  122313. function describe(properties) {
  122314. var html = '<table class="cesium-infoBox-defaultTable">';
  122315. for (var key in properties) {
  122316. if (properties.hasOwnProperty(key)) {
  122317. var value = properties[key];
  122318. if (defined(value)) {
  122319. if (typeof value === 'object') {
  122320. html += '<tr><td>' + key + '</td><td>' + describe(value) + '</td></tr>';
  122321. } else {
  122322. html += '<tr><td>' + key + '</td><td>' + value + '</td></tr>';
  122323. }
  122324. }
  122325. }
  122326. }
  122327. html += '</table>';
  122328. return html;
  122329. }
  122330. this.description = describe(properties);
  122331. };
  122332. return ImageryLayerFeatureInfo;
  122333. });
  122334. /*global define*/
  122335. define('Scene/ImageryProvider',[
  122336. '../Core/defined',
  122337. '../Core/defineProperties',
  122338. '../Core/DeveloperError',
  122339. '../Core/loadImage',
  122340. '../Core/loadImageViaBlob',
  122341. '../Core/throttleRequestByServer'
  122342. ], function(
  122343. defined,
  122344. defineProperties,
  122345. DeveloperError,
  122346. loadImage,
  122347. loadImageViaBlob,
  122348. throttleRequestByServer) {
  122349. 'use strict';
  122350. /**
  122351. * Provides imagery to be displayed on the surface of an ellipsoid. This type describes an
  122352. * interface and is not intended to be instantiated directly.
  122353. *
  122354. * @alias ImageryProvider
  122355. * @constructor
  122356. *
  122357. * @see ArcGisMapServerImageryProvider
  122358. * @see SingleTileImageryProvider
  122359. * @see BingMapsImageryProvider
  122360. * @see GoogleEarthImageryProvider
  122361. * @see MapboxImageryProvider
  122362. * @see createOpenStreetMapImageryProvider
  122363. * @see WebMapTileServiceImageryProvider
  122364. * @see WebMapServiceImageryProvider
  122365. *
  122366. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Imagery%20Layers.html|Cesium Sandcastle Imagery Layers Demo}
  122367. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Imagery%20Layers%20Manipulation.html|Cesium Sandcastle Imagery Manipulation Demo}
  122368. */
  122369. function ImageryProvider() {
  122370. /**
  122371. * The default alpha blending value of this provider, with 0.0 representing fully transparent and
  122372. * 1.0 representing fully opaque.
  122373. *
  122374. * @type {Number}
  122375. * @default undefined
  122376. */
  122377. this.defaultAlpha = undefined;
  122378. /**
  122379. * The default brightness of this provider. 1.0 uses the unmodified imagery color. Less than 1.0
  122380. * makes the imagery darker while greater than 1.0 makes it brighter.
  122381. *
  122382. * @type {Number}
  122383. * @default undefined
  122384. */
  122385. this.defaultBrightness = undefined;
  122386. /**
  122387. * The default contrast of this provider. 1.0 uses the unmodified imagery color. Less than 1.0 reduces
  122388. * the contrast while greater than 1.0 increases it.
  122389. *
  122390. * @type {Number}
  122391. * @default undefined
  122392. */
  122393. this.defaultContrast = undefined;
  122394. /**
  122395. * The default hue of this provider in radians. 0.0 uses the unmodified imagery color.
  122396. *
  122397. * @type {Number}
  122398. * @default undefined
  122399. */
  122400. this.defaultHue = undefined;
  122401. /**
  122402. * The default saturation of this provider. 1.0 uses the unmodified imagery color. Less than 1.0 reduces the
  122403. * saturation while greater than 1.0 increases it.
  122404. *
  122405. * @type {Number}
  122406. * @default undefined
  122407. */
  122408. this.defaultSaturation = undefined;
  122409. /**
  122410. * The default gamma correction to apply to this provider. 1.0 uses the unmodified imagery color.
  122411. *
  122412. * @type {Number}
  122413. * @default undefined
  122414. */
  122415. this.defaultGamma = undefined;
  122416. DeveloperError.throwInstantiationError();
  122417. }
  122418. defineProperties(ImageryProvider.prototype, {
  122419. /**
  122420. * Gets a value indicating whether or not the provider is ready for use.
  122421. * @memberof ImageryProvider.prototype
  122422. * @type {Boolean}
  122423. * @readonly
  122424. */
  122425. ready : {
  122426. get : DeveloperError.throwInstantiationError
  122427. },
  122428. /**
  122429. * Gets a promise that resolves to true when the provider is ready for use.
  122430. * @memberof ImageryProvider.prototype
  122431. * @type {Promise.<Boolean>}
  122432. * @readonly
  122433. */
  122434. readyPromise : {
  122435. get : DeveloperError.throwInstantiationError
  122436. },
  122437. /**
  122438. * Gets the rectangle, in radians, of the imagery provided by the instance. This function should
  122439. * not be called before {@link ImageryProvider#ready} returns true.
  122440. * @memberof ImageryProvider.prototype
  122441. * @type {Rectangle}
  122442. * @readonly
  122443. */
  122444. rectangle: {
  122445. get : DeveloperError.throwInstantiationError
  122446. },
  122447. /**
  122448. * Gets the width of each tile, in pixels. This function should
  122449. * not be called before {@link ImageryProvider#ready} returns true.
  122450. * @memberof ImageryProvider.prototype
  122451. * @type {Number}
  122452. * @readonly
  122453. */
  122454. tileWidth : {
  122455. get : DeveloperError.throwInstantiationError
  122456. },
  122457. /**
  122458. * Gets the height of each tile, in pixels. This function should
  122459. * not be called before {@link ImageryProvider#ready} returns true.
  122460. * @memberof ImageryProvider.prototype
  122461. * @type {Number}
  122462. * @readonly
  122463. */
  122464. tileHeight : {
  122465. get : DeveloperError.throwInstantiationError
  122466. },
  122467. /**
  122468. * Gets the maximum level-of-detail that can be requested. This function should
  122469. * not be called before {@link ImageryProvider#ready} returns true.
  122470. * @memberof ImageryProvider.prototype
  122471. * @type {Number}
  122472. * @readonly
  122473. */
  122474. maximumLevel : {
  122475. get : DeveloperError.throwInstantiationError
  122476. },
  122477. /**
  122478. * Gets the minimum level-of-detail that can be requested. This function should
  122479. * not be called before {@link ImageryProvider#ready} returns true. Generally,
  122480. * a minimum level should only be used when the rectangle of the imagery is small
  122481. * enough that the number of tiles at the minimum level is small. An imagery
  122482. * provider with more than a few tiles at the minimum level will lead to
  122483. * rendering problems.
  122484. * @memberof ImageryProvider.prototype
  122485. * @type {Number}
  122486. * @readonly
  122487. */
  122488. minimumLevel : {
  122489. get : DeveloperError.throwInstantiationError
  122490. },
  122491. /**
  122492. * Gets the tiling scheme used by the provider. This function should
  122493. * not be called before {@link ImageryProvider#ready} returns true.
  122494. * @memberof ImageryProvider.prototype
  122495. * @type {TilingScheme}
  122496. * @readonly
  122497. */
  122498. tilingScheme : {
  122499. get : DeveloperError.throwInstantiationError
  122500. },
  122501. /**
  122502. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  122503. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  122504. * returns undefined, no tiles are filtered. This function should
  122505. * not be called before {@link ImageryProvider#ready} returns true.
  122506. * @memberof ImageryProvider.prototype
  122507. * @type {TileDiscardPolicy}
  122508. * @readonly
  122509. */
  122510. tileDiscardPolicy : {
  122511. get : DeveloperError.throwInstantiationError
  122512. },
  122513. /**
  122514. * Gets an event that is raised when the imagery provider encounters an asynchronous error.. By subscribing
  122515. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  122516. * are passed an instance of {@link TileProviderError}.
  122517. * @memberof ImageryProvider.prototype
  122518. * @type {Event}
  122519. * @readonly
  122520. */
  122521. errorEvent : {
  122522. get : DeveloperError.throwInstantiationError
  122523. },
  122524. /**
  122525. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  122526. * the source of the imagery. This function should
  122527. * not be called before {@link ImageryProvider#ready} returns true.
  122528. * @memberof ImageryProvider.prototype
  122529. * @type {Credit}
  122530. * @readonly
  122531. */
  122532. credit : {
  122533. get : DeveloperError.throwInstantiationError
  122534. },
  122535. /**
  122536. * Gets the proxy used by this provider.
  122537. * @memberof ImageryProvider.prototype
  122538. * @type {Proxy}
  122539. * @readonly
  122540. */
  122541. proxy : {
  122542. get : DeveloperError.throwInstantiationError
  122543. },
  122544. /**
  122545. * Gets a value indicating whether or not the images provided by this imagery provider
  122546. * include an alpha channel. If this property is false, an alpha channel, if present, will
  122547. * be ignored. If this property is true, any images without an alpha channel will be treated
  122548. * as if their alpha is 1.0 everywhere. When this property is false, memory usage
  122549. * and texture upload time are reduced.
  122550. * @memberof ImageryProvider.prototype
  122551. * @type {Boolean}
  122552. * @readonly
  122553. */
  122554. hasAlphaChannel : {
  122555. get : DeveloperError.throwInstantiationError
  122556. }
  122557. });
  122558. /**
  122559. * Gets the credits to be displayed when a given tile is displayed.
  122560. * @function
  122561. *
  122562. * @param {Number} x The tile X coordinate.
  122563. * @param {Number} y The tile Y coordinate.
  122564. * @param {Number} level The tile level;
  122565. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  122566. *
  122567. * @exception {DeveloperError} <code>getTileCredits</code> must not be called before the imagery provider is ready.
  122568. */
  122569. ImageryProvider.prototype.getTileCredits = DeveloperError.throwInstantiationError;
  122570. /**
  122571. * Requests the image for a given tile. This function should
  122572. * not be called before {@link ImageryProvider#ready} returns true.
  122573. * @function
  122574. *
  122575. * @param {Number} x The tile X coordinate.
  122576. * @param {Number} y The tile Y coordinate.
  122577. * @param {Number} level The tile level.
  122578. * @returns {Promise.<Image|Canvas>|undefined} A promise for the image that will resolve when the image is available, or
  122579. * undefined if there are too many active requests to the server, and the request
  122580. * should be retried later. The resolved image may be either an
  122581. * Image or a Canvas DOM object.
  122582. *
  122583. * @exception {DeveloperError} <code>requestImage</code> must not be called before the imagery provider is ready.
  122584. */
  122585. ImageryProvider.prototype.requestImage = DeveloperError.throwInstantiationError;
  122586. /**
  122587. * Asynchronously determines what features, if any, are located at a given longitude and latitude within
  122588. * a tile. This function should not be called before {@link ImageryProvider#ready} returns true.
  122589. * This function is optional, so it may not exist on all ImageryProviders.
  122590. *
  122591. * @function
  122592. *
  122593. * @param {Number} x The tile X coordinate.
  122594. * @param {Number} y The tile Y coordinate.
  122595. * @param {Number} level The tile level.
  122596. * @param {Number} longitude The longitude at which to pick features.
  122597. * @param {Number} latitude The latitude at which to pick features.
  122598. * @return {Promise.<ImageryLayerFeatureInfo[]>|undefined} A promise for the picked features that will resolve when the asynchronous
  122599. * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
  122600. * instances. The array may be empty if no features are found at the given location.
  122601. * It may also be undefined if picking is not supported.
  122602. *
  122603. * @exception {DeveloperError} <code>pickFeatures</code> must not be called before the imagery provider is ready.
  122604. */
  122605. ImageryProvider.prototype.pickFeatures = DeveloperError.throwInstantiationError;
  122606. /**
  122607. * Loads an image from a given URL. If the server referenced by the URL already has
  122608. * too many requests pending, this function will instead return undefined, indicating
  122609. * that the request should be retried later.
  122610. *
  122611. * @param {String} url The URL of the image.
  122612. * @returns {Promise.<Image|Canvas>|undefined} A promise for the image that will resolve when the image is available, or
  122613. * undefined if there are too many active requests to the server, and the request
  122614. * should be retried later. The resolved image may be either an
  122615. * Image or a Canvas DOM object.
  122616. */
  122617. ImageryProvider.loadImage = function(imageryProvider, url) {
  122618. if (defined(imageryProvider.tileDiscardPolicy)) {
  122619. return throttleRequestByServer(url, loadImageViaBlob);
  122620. }
  122621. return throttleRequestByServer(url, loadImage);
  122622. };
  122623. return ImageryProvider;
  122624. });
  122625. /*global define*/
  122626. define('Scene/ArcGisMapServerImageryProvider',[
  122627. '../Core/Cartesian2',
  122628. '../Core/Cartesian3',
  122629. '../Core/Cartographic',
  122630. '../Core/Credit',
  122631. '../Core/defaultValue',
  122632. '../Core/defined',
  122633. '../Core/defineProperties',
  122634. '../Core/DeveloperError',
  122635. '../Core/Event',
  122636. '../Core/GeographicTilingScheme',
  122637. '../Core/loadJson',
  122638. '../Core/loadJsonp',
  122639. '../Core/Math',
  122640. '../Core/Rectangle',
  122641. '../Core/RuntimeError',
  122642. '../Core/TileProviderError',
  122643. '../Core/WebMercatorProjection',
  122644. '../Core/WebMercatorTilingScheme',
  122645. '../ThirdParty/when',
  122646. './DiscardMissingTileImagePolicy',
  122647. './ImageryLayerFeatureInfo',
  122648. './ImageryProvider'
  122649. ], function(
  122650. Cartesian2,
  122651. Cartesian3,
  122652. Cartographic,
  122653. Credit,
  122654. defaultValue,
  122655. defined,
  122656. defineProperties,
  122657. DeveloperError,
  122658. Event,
  122659. GeographicTilingScheme,
  122660. loadJson,
  122661. loadJsonp,
  122662. CesiumMath,
  122663. Rectangle,
  122664. RuntimeError,
  122665. TileProviderError,
  122666. WebMercatorProjection,
  122667. WebMercatorTilingScheme,
  122668. when,
  122669. DiscardMissingTileImagePolicy,
  122670. ImageryLayerFeatureInfo,
  122671. ImageryProvider) {
  122672. 'use strict';
  122673. /**
  122674. * Provides tiled imagery hosted by an ArcGIS MapServer. By default, the server's pre-cached tiles are
  122675. * used, if available.
  122676. *
  122677. * @alias ArcGisMapServerImageryProvider
  122678. * @constructor
  122679. *
  122680. * @param {Object} options Object with the following properties:
  122681. * @param {String} options.url The URL of the ArcGIS MapServer service.
  122682. * @param {String} [options.token] The ArcGIS token used to authenticate with the ArcGIS MapServer service.
  122683. * @param {TileDiscardPolicy} [options.tileDiscardPolicy] The policy that determines if a tile
  122684. * is invalid and should be discarded. If this value is not specified, a default
  122685. * {@link DiscardMissingTileImagePolicy} is used for tiled map servers, and a
  122686. * {@link NeverTileDiscardPolicy} is used for non-tiled map servers. In the former case,
  122687. * we request tile 0,0 at the maximum tile level and check pixels (0,0), (200,20), (20,200),
  122688. * (80,110), and (160, 130). If all of these pixels are transparent, the discard check is
  122689. * disabled and no tiles are discarded. If any of them have a non-transparent color, any
  122690. * tile that has the same values in these pixel locations is discarded. The end result of
  122691. * these defaults should be correct tile discarding for a standard ArcGIS Server. To ensure
  122692. * that no tiles are discarded, construct and pass a {@link NeverTileDiscardPolicy} for this
  122693. * parameter.
  122694. * @param {Proxy} [options.proxy] A proxy to use for requests. This object is
  122695. * expected to have a getURL function which returns the proxied URL, if needed.
  122696. * @param {Boolean} [options.usePreCachedTilesIfAvailable=true] If true, the server's pre-cached
  122697. * tiles are used if they are available. If false, any pre-cached tiles are ignored and the
  122698. * 'export' service is used.
  122699. * @param {String} [options.layers] A comma-separated list of the layers to show, or undefined if all layers should be shown.
  122700. * @param {Boolean} [options.enablePickFeatures=true] If true, {@link ArcGisMapServerImageryProvider#pickFeatures} will invoke
  122701. * the Identify service on the MapServer and return the features included in the response. If false,
  122702. * {@link ArcGisMapServerImageryProvider#pickFeatures} will immediately return undefined (indicating no pickable features)
  122703. * without communicating with the server. Set this property to false if you don't want this provider's features to
  122704. * be pickable. Can be overridden by setting the {@link ArcGisMapServerImageryProvider#enablePickFeatures} property on the object.
  122705. * @param {Rectangle} [options.rectangle=Rectangle.MAX_VALUE] The rectangle of the layer. This parameter is ignored when accessing
  122706. * a tiled layer.
  122707. * @param {TilingScheme} [options.tilingScheme=new GeographicTilingScheme()] The tiling scheme to use to divide the world into tiles.
  122708. * This parameter is ignored when accessing a tiled server.
  122709. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If the tilingScheme is specified and used,
  122710. * this parameter is ignored and the tiling scheme's ellipsoid is used instead. If neither
  122711. * parameter is specified, the WGS84 ellipsoid is used.
  122712. * @param {Number} [options.tileWidth=256] The width of each tile in pixels. This parameter is ignored when accessing a tiled server.
  122713. * @param {Number} [options.tileHeight=256] The height of each tile in pixels. This parameter is ignored when accessing a tiled server.
  122714. * @param {Number} [options.maximumLevel] The maximum tile level to request, or undefined if there is no maximum. This parameter is ignored when accessing
  122715. * a tiled server.
  122716. *
  122717. * @see BingMapsImageryProvider
  122718. * @see GoogleEarthImageryProvider
  122719. * @see createOpenStreetMapImageryProvider
  122720. * @see SingleTileImageryProvider
  122721. * @see createTileMapServiceImageryProvider
  122722. * @see WebMapServiceImageryProvider
  122723. * @see WebMapTileServiceImageryProvider
  122724. * @see UrlTemplateImageryProvider
  122725. *
  122726. *
  122727. * @example
  122728. * var esri = new Cesium.ArcGisMapServerImageryProvider({
  122729. * url : 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer'
  122730. * });
  122731. *
  122732. * @see {@link http://resources.esri.com/help/9.3/arcgisserver/apis/rest/|ArcGIS Server REST API}
  122733. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  122734. */
  122735. function ArcGisMapServerImageryProvider(options) {
  122736. options = defaultValue(options, {});
  122737. if (!defined(options.url)) {
  122738. throw new DeveloperError('options.url is required.');
  122739. }
  122740. this._url = options.url;
  122741. this._token = options.token;
  122742. this._tileDiscardPolicy = options.tileDiscardPolicy;
  122743. this._proxy = options.proxy;
  122744. this._tileWidth = defaultValue(options.tileWidth, 256);
  122745. this._tileHeight = defaultValue(options.tileHeight, 256);
  122746. this._maximumLevel = options.maximumLevel;
  122747. this._tilingScheme = defaultValue(options.tilingScheme, new GeographicTilingScheme({ ellipsoid : options.ellipsoid }));
  122748. this._credit = undefined;
  122749. this._useTiles = defaultValue(options.usePreCachedTilesIfAvailable, true);
  122750. this._rectangle = defaultValue(options.rectangle, this._tilingScheme.rectangle);
  122751. this._layers = options.layers;
  122752. /**
  122753. * Gets or sets a value indicating whether feature picking is enabled. If true, {@link ArcGisMapServerImageryProvider#pickFeatures} will
  122754. * invoke the "identify" operation on the ArcGIS server and return the features included in the response. If false,
  122755. * {@link ArcGisMapServerImageryProvider#pickFeatures} will immediately return undefined (indicating no pickable features)
  122756. * without communicating with the server.
  122757. * @type {Boolean}
  122758. * @default true
  122759. */
  122760. this.enablePickFeatures = defaultValue(options.enablePickFeatures, true);
  122761. this._errorEvent = new Event();
  122762. this._ready = false;
  122763. this._readyPromise = when.defer();
  122764. // Grab the details of this MapServer.
  122765. var that = this;
  122766. var metadataError;
  122767. function metadataSuccess(data) {
  122768. var tileInfo = data.tileInfo;
  122769. if (!defined(tileInfo)) {
  122770. that._useTiles = false;
  122771. } else {
  122772. that._tileWidth = tileInfo.rows;
  122773. that._tileHeight = tileInfo.cols;
  122774. if (tileInfo.spatialReference.wkid === 102100 ||
  122775. tileInfo.spatialReference.wkid === 102113) {
  122776. that._tilingScheme = new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid });
  122777. } else if (data.tileInfo.spatialReference.wkid === 4326) {
  122778. that._tilingScheme = new GeographicTilingScheme({ ellipsoid : options.ellipsoid });
  122779. } else {
  122780. var message = 'Tile spatial reference WKID ' + data.tileInfo.spatialReference.wkid + ' is not supported.';
  122781. metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
  122782. return;
  122783. }
  122784. that._maximumLevel = data.tileInfo.lods.length - 1;
  122785. if (defined(data.fullExtent)) {
  122786. if (defined(data.fullExtent.spatialReference) && defined(data.fullExtent.spatialReference.wkid)) {
  122787. if (data.fullExtent.spatialReference.wkid === 102100 ||
  122788. data.fullExtent.spatialReference.wkid === 102113) {
  122789. var projection = new WebMercatorProjection();
  122790. var extent = data.fullExtent;
  122791. var sw = projection.unproject(new Cartesian3(Math.max(extent.xmin, -that._tilingScheme.ellipsoid.maximumRadius * Math.PI), Math.max(extent.ymin, -that._tilingScheme.ellipsoid.maximumRadius * Math.PI), 0.0));
  122792. var ne = projection.unproject(new Cartesian3(Math.min(extent.xmax, that._tilingScheme.ellipsoid.maximumRadius * Math.PI), Math.min(extent.ymax, that._tilingScheme.ellipsoid.maximumRadius * Math.PI), 0.0));
  122793. that._rectangle = new Rectangle(sw.longitude, sw.latitude, ne.longitude, ne.latitude);
  122794. } else if (data.fullExtent.spatialReference.wkid === 4326) {
  122795. that._rectangle = Rectangle.fromDegrees(data.fullExtent.xmin, data.fullExtent.ymin, data.fullExtent.xmax, data.fullExtent.ymax);
  122796. } else {
  122797. var extentMessage = 'fullExtent.spatialReference WKID ' + data.fullExtent.spatialReference.wkid + ' is not supported.';
  122798. metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, extentMessage, undefined, undefined, undefined, requestMetadata);
  122799. return;
  122800. }
  122801. }
  122802. } else {
  122803. that._rectangle = that._tilingScheme.rectangle;
  122804. }
  122805. // Install the default tile discard policy if none has been supplied.
  122806. if (!defined(that._tileDiscardPolicy)) {
  122807. that._tileDiscardPolicy = new DiscardMissingTileImagePolicy({
  122808. missingImageUrl : buildImageUrl(that, 0, 0, that._maximumLevel),
  122809. pixelsToCheck : [new Cartesian2(0, 0), new Cartesian2(200, 20), new Cartesian2(20, 200), new Cartesian2(80, 110), new Cartesian2(160, 130)],
  122810. disableCheckIfAllPixelsAreTransparent : true
  122811. });
  122812. }
  122813. that._useTiles = true;
  122814. }
  122815. if (defined(data.copyrightText) && data.copyrightText.length > 0) {
  122816. that._credit = new Credit(data.copyrightText);
  122817. }
  122818. that._ready = true;
  122819. that._readyPromise.resolve(true);
  122820. TileProviderError.handleSuccess(metadataError);
  122821. }
  122822. function metadataFailure(e) {
  122823. var message = 'An error occurred while accessing ' + that._url + '.';
  122824. metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
  122825. that._readyPromise.reject(new RuntimeError(message));
  122826. }
  122827. function requestMetadata() {
  122828. var parameters = {
  122829. f: 'json'
  122830. };
  122831. if (defined(that._token)) {
  122832. parameters.token = that._token;
  122833. }
  122834. var metadata = loadJsonp(that._url, {
  122835. parameters : parameters,
  122836. proxy : that._proxy
  122837. });
  122838. when(metadata, metadataSuccess, metadataFailure);
  122839. }
  122840. if (this._useTiles) {
  122841. requestMetadata();
  122842. } else {
  122843. this._ready = true;
  122844. this._readyPromise.resolve(true);
  122845. }
  122846. }
  122847. function buildImageUrl(imageryProvider, x, y, level) {
  122848. var url;
  122849. if (imageryProvider._useTiles) {
  122850. url = imageryProvider._url + '/tile/' + level + '/' + y + '/' + x;
  122851. } else {
  122852. var nativeRectangle = imageryProvider._tilingScheme.tileXYToNativeRectangle(x, y, level);
  122853. var bbox = nativeRectangle.west + '%2C' + nativeRectangle.south + '%2C' + nativeRectangle.east + '%2C' + nativeRectangle.north;
  122854. url = imageryProvider._url + '/export?';
  122855. url += 'bbox=' + bbox;
  122856. if (imageryProvider._tilingScheme instanceof GeographicTilingScheme) {
  122857. url += '&bboxSR=4326&imageSR=4326';
  122858. } else {
  122859. url += '&bboxSR=3857&imageSR=3857';
  122860. }
  122861. url += '&size=' + imageryProvider._tileWidth + '%2C' + imageryProvider._tileHeight;
  122862. url += '&format=png&transparent=true&f=image';
  122863. if (imageryProvider.layers) {
  122864. url += '&layers=show:' + imageryProvider.layers;
  122865. }
  122866. }
  122867. var token = imageryProvider._token;
  122868. if (defined(token)) {
  122869. if (url.indexOf('?') === -1) {
  122870. url += '?';
  122871. }
  122872. if (url[url.length - 1] !== '?'){
  122873. url += '&';
  122874. }
  122875. url += 'token=' + token;
  122876. }
  122877. var proxy = imageryProvider._proxy;
  122878. if (defined(proxy)) {
  122879. url = proxy.getURL(url);
  122880. }
  122881. return url;
  122882. }
  122883. defineProperties(ArcGisMapServerImageryProvider.prototype, {
  122884. /**
  122885. * Gets the URL of the ArcGIS MapServer.
  122886. * @memberof ArcGisMapServerImageryProvider.prototype
  122887. * @type {String}
  122888. * @readonly
  122889. */
  122890. url : {
  122891. get : function() {
  122892. return this._url;
  122893. }
  122894. },
  122895. /**
  122896. * Gets the ArcGIS token used to authenticate with the ArcGis MapServer service.
  122897. * @memberof ArcGisMapServerImageryProvider.prototype
  122898. * @type {String}
  122899. * @readonly
  122900. */
  122901. token : {
  122902. get : function() {
  122903. return this._token;
  122904. }
  122905. },
  122906. /**
  122907. * Gets the proxy used by this provider.
  122908. * @memberof ArcGisMapServerImageryProvider.prototype
  122909. * @type {Proxy}
  122910. * @readonly
  122911. */
  122912. proxy : {
  122913. get : function() {
  122914. return this._proxy;
  122915. }
  122916. },
  122917. /**
  122918. * Gets the width of each tile, in pixels. This function should
  122919. * not be called before {@link ArcGisMapServerImageryProvider#ready} returns true.
  122920. * @memberof ArcGisMapServerImageryProvider.prototype
  122921. * @type {Number}
  122922. * @readonly
  122923. */
  122924. tileWidth : {
  122925. get : function() {
  122926. if (!this._ready) {
  122927. throw new DeveloperError('tileWidth must not be called before the imagery provider is ready.');
  122928. }
  122929. return this._tileWidth;
  122930. }
  122931. },
  122932. /**
  122933. * Gets the height of each tile, in pixels. This function should
  122934. * not be called before {@link ArcGisMapServerImageryProvider#ready} returns true.
  122935. * @memberof ArcGisMapServerImageryProvider.prototype
  122936. * @type {Number}
  122937. * @readonly
  122938. */
  122939. tileHeight: {
  122940. get : function() {
  122941. if (!this._ready) {
  122942. throw new DeveloperError('tileHeight must not be called before the imagery provider is ready.');
  122943. }
  122944. return this._tileHeight;
  122945. }
  122946. },
  122947. /**
  122948. * Gets the maximum level-of-detail that can be requested. This function should
  122949. * not be called before {@link ArcGisMapServerImageryProvider#ready} returns true.
  122950. * @memberof ArcGisMapServerImageryProvider.prototype
  122951. * @type {Number}
  122952. * @readonly
  122953. */
  122954. maximumLevel : {
  122955. get : function() {
  122956. if (!this._ready) {
  122957. throw new DeveloperError('maximumLevel must not be called before the imagery provider is ready.');
  122958. }
  122959. return this._maximumLevel;
  122960. }
  122961. },
  122962. /**
  122963. * Gets the minimum level-of-detail that can be requested. This function should
  122964. * not be called before {@link ArcGisMapServerImageryProvider#ready} returns true.
  122965. * @memberof ArcGisMapServerImageryProvider.prototype
  122966. * @type {Number}
  122967. * @readonly
  122968. */
  122969. minimumLevel : {
  122970. get : function() {
  122971. if (!this._ready) {
  122972. throw new DeveloperError('minimumLevel must not be called before the imagery provider is ready.');
  122973. }
  122974. return 0;
  122975. }
  122976. },
  122977. /**
  122978. * Gets the tiling scheme used by this provider. This function should
  122979. * not be called before {@link ArcGisMapServerImageryProvider#ready} returns true.
  122980. * @memberof ArcGisMapServerImageryProvider.prototype
  122981. * @type {TilingScheme}
  122982. * @readonly
  122983. */
  122984. tilingScheme : {
  122985. get : function() {
  122986. if (!this._ready) {
  122987. throw new DeveloperError('tilingScheme must not be called before the imagery provider is ready.');
  122988. }
  122989. return this._tilingScheme;
  122990. }
  122991. },
  122992. /**
  122993. * Gets the rectangle, in radians, of the imagery provided by this instance. This function should
  122994. * not be called before {@link ArcGisMapServerImageryProvider#ready} returns true.
  122995. * @memberof ArcGisMapServerImageryProvider.prototype
  122996. * @type {Rectangle}
  122997. * @readonly
  122998. */
  122999. rectangle : {
  123000. get : function() {
  123001. if (!this._ready) {
  123002. throw new DeveloperError('rectangle must not be called before the imagery provider is ready.');
  123003. }
  123004. return this._rectangle;
  123005. }
  123006. },
  123007. /**
  123008. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  123009. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  123010. * returns undefined, no tiles are filtered. This function should
  123011. * not be called before {@link ArcGisMapServerImageryProvider#ready} returns true.
  123012. * @memberof ArcGisMapServerImageryProvider.prototype
  123013. * @type {TileDiscardPolicy}
  123014. * @readonly
  123015. */
  123016. tileDiscardPolicy : {
  123017. get : function() {
  123018. if (!this._ready) {
  123019. throw new DeveloperError('tileDiscardPolicy must not be called before the imagery provider is ready.');
  123020. }
  123021. return this._tileDiscardPolicy;
  123022. }
  123023. },
  123024. /**
  123025. * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
  123026. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  123027. * are passed an instance of {@link TileProviderError}.
  123028. * @memberof ArcGisMapServerImageryProvider.prototype
  123029. * @type {Event}
  123030. * @readonly
  123031. */
  123032. errorEvent : {
  123033. get : function() {
  123034. return this._errorEvent;
  123035. }
  123036. },
  123037. /**
  123038. * Gets a value indicating whether or not the provider is ready for use.
  123039. * @memberof ArcGisMapServerImageryProvider.prototype
  123040. * @type {Boolean}
  123041. * @readonly
  123042. */
  123043. ready : {
  123044. get : function() {
  123045. return this._ready;
  123046. }
  123047. },
  123048. /**
  123049. * Gets a promise that resolves to true when the provider is ready for use.
  123050. * @memberof ArcGisMapServerImageryProvider.prototype
  123051. * @type {Promise.<Boolean>}
  123052. * @readonly
  123053. */
  123054. readyPromise : {
  123055. get : function() {
  123056. return this._readyPromise.promise;
  123057. }
  123058. },
  123059. /**
  123060. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  123061. * the source of the imagery. This function should not be called before {@link ArcGisMapServerImageryProvider#ready} returns true.
  123062. * @memberof ArcGisMapServerImageryProvider.prototype
  123063. * @type {Credit}
  123064. * @readonly
  123065. */
  123066. credit : {
  123067. get : function() {
  123068. return this._credit;
  123069. }
  123070. },
  123071. /**
  123072. * Gets a value indicating whether this imagery provider is using pre-cached tiles from the
  123073. * ArcGIS MapServer. If the imagery provider is not yet ready ({@link ArcGisMapServerImageryProvider#ready}), this function
  123074. * will return the value of `options.usePreCachedTilesIfAvailable`, even if the MapServer does
  123075. * not have pre-cached tiles.
  123076. * @memberof ArcGisMapServerImageryProvider.prototype
  123077. *
  123078. * @type {Boolean}
  123079. * @readonly
  123080. * @default true
  123081. */
  123082. usingPrecachedTiles : {
  123083. get : function() {
  123084. return this._useTiles;
  123085. }
  123086. },
  123087. /**
  123088. * Gets a value indicating whether or not the images provided by this imagery provider
  123089. * include an alpha channel. If this property is false, an alpha channel, if present, will
  123090. * be ignored. If this property is true, any images without an alpha channel will be treated
  123091. * as if their alpha is 1.0 everywhere. When this property is false, memory usage
  123092. * and texture upload time are reduced.
  123093. * @memberof ArcGisMapServerImageryProvider.prototype
  123094. *
  123095. * @type {Boolean}
  123096. * @readonly
  123097. * @default true
  123098. */
  123099. hasAlphaChannel : {
  123100. get : function() {
  123101. return true;
  123102. }
  123103. },
  123104. /**
  123105. * Gets the comma-separated list of layer IDs to show.
  123106. * @memberof ArcGisMapServerImageryProvider.prototype
  123107. *
  123108. * @type {String}
  123109. */
  123110. layers : {
  123111. get : function() {
  123112. return this._layers;
  123113. }
  123114. }
  123115. });
  123116. /**
  123117. * Gets the credits to be displayed when a given tile is displayed.
  123118. *
  123119. * @param {Number} x The tile X coordinate.
  123120. * @param {Number} y The tile Y coordinate.
  123121. * @param {Number} level The tile level;
  123122. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  123123. *
  123124. * @exception {DeveloperError} <code>getTileCredits</code> must not be called before the imagery provider is ready.
  123125. */
  123126. ArcGisMapServerImageryProvider.prototype.getTileCredits = function(x, y, level) {
  123127. return undefined;
  123128. };
  123129. /**
  123130. * Requests the image for a given tile. This function should
  123131. * not be called before {@link ArcGisMapServerImageryProvider#ready} returns true.
  123132. *
  123133. * @param {Number} x The tile X coordinate.
  123134. * @param {Number} y The tile Y coordinate.
  123135. * @param {Number} level The tile level.
  123136. * @returns {Promise.<Image|Canvas>|undefined} A promise for the image that will resolve when the image is available, or
  123137. * undefined if there are too many active requests to the server, and the request
  123138. * should be retried later. The resolved image may be either an
  123139. * Image or a Canvas DOM object.
  123140. *
  123141. * @exception {DeveloperError} <code>requestImage</code> must not be called before the imagery provider is ready.
  123142. */
  123143. ArcGisMapServerImageryProvider.prototype.requestImage = function(x, y, level) {
  123144. if (!this._ready) {
  123145. throw new DeveloperError('requestImage must not be called before the imagery provider is ready.');
  123146. }
  123147. var url = buildImageUrl(this, x, y, level);
  123148. return ImageryProvider.loadImage(this, url);
  123149. };
  123150. /**
  123151. /**
  123152. * Asynchronously determines what features, if any, are located at a given longitude and latitude within
  123153. * a tile. This function should not be called before {@link ImageryProvider#ready} returns true.
  123154. *
  123155. * @param {Number} x The tile X coordinate.
  123156. * @param {Number} y The tile Y coordinate.
  123157. * @param {Number} level The tile level.
  123158. * @param {Number} longitude The longitude at which to pick features.
  123159. * @param {Number} latitude The latitude at which to pick features.
  123160. * @return {Promise.<ImageryLayerFeatureInfo[]>|undefined} A promise for the picked features that will resolve when the asynchronous
  123161. * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
  123162. * instances. The array may be empty if no features are found at the given location.
  123163. *
  123164. * @exception {DeveloperError} <code>pickFeatures</code> must not be called before the imagery provider is ready.
  123165. */
  123166. ArcGisMapServerImageryProvider.prototype.pickFeatures = function(x, y, level, longitude, latitude) {
  123167. if (!this._ready) {
  123168. throw new DeveloperError('pickFeatures must not be called before the imagery provider is ready.');
  123169. }
  123170. if (!this.enablePickFeatures) {
  123171. return undefined;
  123172. }
  123173. var rectangle = this._tilingScheme.tileXYToNativeRectangle(x, y, level);
  123174. var horizontal;
  123175. var vertical;
  123176. var sr;
  123177. if (this._tilingScheme instanceof GeographicTilingScheme) {
  123178. horizontal = CesiumMath.toDegrees(longitude);
  123179. vertical = CesiumMath.toDegrees(latitude);
  123180. sr = '4326';
  123181. } else {
  123182. var projected = this._tilingScheme.projection.project(new Cartographic(longitude, latitude, 0.0));
  123183. horizontal = projected.x;
  123184. vertical = projected.y;
  123185. sr = '3857';
  123186. }
  123187. var url = this._url + '/identify?f=json&tolerance=2&geometryType=esriGeometryPoint';
  123188. url += '&geometry=' + horizontal + ',' + vertical;
  123189. url += '&mapExtent=' + rectangle.west + ',' + rectangle.south + ',' + rectangle.east + ',' + rectangle.north;
  123190. url += '&imageDisplay=' + this._tileWidth + ',' + this._tileHeight + ',96';
  123191. url += '&sr=' + sr;
  123192. url += '&layers=visible';
  123193. if (defined(this._layers)) {
  123194. url += ':' + this._layers;
  123195. }
  123196. if (defined(this._token)) {
  123197. url += '&token=' + this._token;
  123198. }
  123199. if (defined(this._proxy)) {
  123200. url = this._proxy.getURL(url);
  123201. }
  123202. return loadJson(url).then(function(json) {
  123203. var result = [];
  123204. var features = json.results;
  123205. if (!defined(features)) {
  123206. return result;
  123207. }
  123208. for (var i = 0; i < features.length; ++i) {
  123209. var feature = features[i];
  123210. var featureInfo = new ImageryLayerFeatureInfo();
  123211. featureInfo.data = feature;
  123212. featureInfo.name = feature.value;
  123213. featureInfo.properties = feature.attributes;
  123214. featureInfo.configureDescriptionFromProperties(feature.attributes);
  123215. // If this is a point feature, use the coordinates of the point.
  123216. if (feature.geometryType === 'esriGeometryPoint' && feature.geometry) {
  123217. var wkid = feature.geometry.spatialReference && feature.geometry.spatialReference.wkid ? feature.geometry.spatialReference.wkid : 4326;
  123218. if (wkid === 4326 || wkid === 4283) {
  123219. featureInfo.position = Cartographic.fromDegrees(feature.geometry.x, feature.geometry.y, feature.geometry.z);
  123220. } else if (wkid === 102100 || wkid === 900913 || wkid === 3857) {
  123221. var projection = new WebMercatorProjection();
  123222. featureInfo.position = projection.unproject(new Cartesian3(feature.geometry.x, feature.geometry.y, feature.geometry.z));
  123223. }
  123224. }
  123225. result.push(featureInfo);
  123226. }
  123227. return result;
  123228. });
  123229. };
  123230. return ArcGisMapServerImageryProvider;
  123231. });
  123232. /*global define*/
  123233. define('Scene/BingMapsStyle',[
  123234. '../Core/freezeObject'
  123235. ], function(
  123236. freezeObject) {
  123237. 'use strict';
  123238. /**
  123239. * The types of imagery provided by Bing Maps.
  123240. *
  123241. * @exports BingMapsStyle
  123242. *
  123243. * @see BingMapsImageryProvider
  123244. */
  123245. var BingMapsStyle = {
  123246. /**
  123247. * Aerial imagery.
  123248. *
  123249. * @type {String}
  123250. * @constant
  123251. */
  123252. AERIAL : 'Aerial',
  123253. /**
  123254. * Aerial imagery with a road overlay.
  123255. *
  123256. * @type {String}
  123257. * @constant
  123258. */
  123259. AERIAL_WITH_LABELS : 'AerialWithLabels',
  123260. /**
  123261. * Roads without additional imagery.
  123262. *
  123263. * @type {String}
  123264. * @constant
  123265. */
  123266. ROAD : 'Road',
  123267. /**
  123268. * Ordnance Survey imagery
  123269. *
  123270. * @type {String}
  123271. * @constant
  123272. */
  123273. ORDNANCE_SURVEY : 'OrdnanceSurvey',
  123274. /**
  123275. * Collins Bart imagery.
  123276. *
  123277. * @type {String}
  123278. * @constant
  123279. */
  123280. COLLINS_BART : 'CollinsBart'
  123281. };
  123282. return freezeObject(BingMapsStyle);
  123283. });
  123284. /*global define*/
  123285. define('Scene/BingMapsImageryProvider',[
  123286. '../Core/BingMapsApi',
  123287. '../Core/Cartesian2',
  123288. '../Core/Credit',
  123289. '../Core/defaultValue',
  123290. '../Core/defined',
  123291. '../Core/defineProperties',
  123292. '../Core/DeveloperError',
  123293. '../Core/Event',
  123294. '../Core/loadJsonp',
  123295. '../Core/Math',
  123296. '../Core/Rectangle',
  123297. '../Core/RuntimeError',
  123298. '../Core/TileProviderError',
  123299. '../Core/WebMercatorTilingScheme',
  123300. '../ThirdParty/when',
  123301. './BingMapsStyle',
  123302. './DiscardMissingTileImagePolicy',
  123303. './ImageryProvider'
  123304. ], function(
  123305. BingMapsApi,
  123306. Cartesian2,
  123307. Credit,
  123308. defaultValue,
  123309. defined,
  123310. defineProperties,
  123311. DeveloperError,
  123312. Event,
  123313. loadJsonp,
  123314. CesiumMath,
  123315. Rectangle,
  123316. RuntimeError,
  123317. TileProviderError,
  123318. WebMercatorTilingScheme,
  123319. when,
  123320. BingMapsStyle,
  123321. DiscardMissingTileImagePolicy,
  123322. ImageryProvider) {
  123323. 'use strict';
  123324. /**
  123325. * Provides tiled imagery using the Bing Maps Imagery REST API.
  123326. *
  123327. * @alias BingMapsImageryProvider
  123328. * @constructor
  123329. *
  123330. * @param {Object} options Object with the following properties:
  123331. * @param {String} options.url The url of the Bing Maps server hosting the imagery.
  123332. * @param {String} [options.key] The Bing Maps key for your application, which can be
  123333. * created at {@link https://www.bingmapsportal.com/}.
  123334. * If this parameter is not provided, {@link BingMapsApi.defaultKey} is used.
  123335. * If {@link BingMapsApi.defaultKey} is undefined as well, a message is
  123336. * written to the console reminding you that you must create and supply a Bing Maps
  123337. * key as soon as possible. Please do not deploy an application that uses
  123338. * Bing Maps imagery without creating a separate key for your application.
  123339. * @param {String} [options.tileProtocol] The protocol to use when loading tiles, e.g. 'http:' or 'https:'.
  123340. * By default, tiles are loaded using the same protocol as the page.
  123341. * @param {String} [options.mapStyle=BingMapsStyle.AERIAL] The type of Bing Maps
  123342. * imagery to load.
  123343. * @param {String} [options.culture=''] The culture to use when requesting Bing Maps imagery. Not
  123344. * all cultures are supported. See {@link http://msdn.microsoft.com/en-us/library/hh441729.aspx}
  123345. * for information on the supported cultures.
  123346. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If not specified, the WGS84 ellipsoid is used.
  123347. * @param {TileDiscardPolicy} [options.tileDiscardPolicy] The policy that determines if a tile
  123348. * is invalid and should be discarded. If this value is not specified, a default
  123349. * {@link DiscardMissingTileImagePolicy} is used which requests
  123350. * tile 0,0 at the maximum tile level and checks pixels (0,0), (120,140), (130,160),
  123351. * (200,50), and (200,200). If all of these pixels are transparent, the discard check is
  123352. * disabled and no tiles are discarded. If any of them have a non-transparent color, any
  123353. * tile that has the same values in these pixel locations is discarded. The end result of
  123354. * these defaults should be correct tile discarding for a standard Bing Maps server. To ensure
  123355. * that no tiles are discarded, construct and pass a {@link NeverTileDiscardPolicy} for this
  123356. * parameter.
  123357. * @param {Proxy} [options.proxy] A proxy to use for requests. This object is
  123358. * expected to have a getURL function which returns the proxied URL, if needed.
  123359. *
  123360. * @see ArcGisMapServerImageryProvider
  123361. * @see GoogleEarthImageryProvider
  123362. * @see createOpenStreetMapImageryProvider
  123363. * @see SingleTileImageryProvider
  123364. * @see createTileMapServiceImageryProvider
  123365. * @see WebMapServiceImageryProvider
  123366. * @see WebMapTileServiceImageryProvider
  123367. * @see UrlTemplateImageryProvider
  123368. *
  123369. *
  123370. * @example
  123371. * var bing = new Cesium.BingMapsImageryProvider({
  123372. * url : 'https://dev.virtualearth.net',
  123373. * key : 'get-yours-at-https://www.bingmapsportal.com/',
  123374. * mapStyle : Cesium.BingMapsStyle.AERIAL
  123375. * });
  123376. *
  123377. * @see {@link http://msdn.microsoft.com/en-us/library/ff701713.aspx|Bing Maps REST Services}
  123378. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  123379. */
  123380. function BingMapsImageryProvider(options) {
  123381. options = defaultValue(options, {});
  123382. if (!defined(options.url)) {
  123383. throw new DeveloperError('options.url is required.');
  123384. }
  123385. this._key = BingMapsApi.getKey(options.key);
  123386. this._keyErrorCredit = BingMapsApi.getErrorCredit(options.key);
  123387. this._url = options.url;
  123388. this._tileProtocol = options.tileProtocol;
  123389. this._mapStyle = defaultValue(options.mapStyle, BingMapsStyle.AERIAL);
  123390. this._culture = defaultValue(options.culture, '');
  123391. this._tileDiscardPolicy = options.tileDiscardPolicy;
  123392. this._proxy = options.proxy;
  123393. this._credit = new Credit('Bing Imagery', BingMapsImageryProvider._logoData, 'http://www.bing.com');
  123394. /**
  123395. * The default {@link ImageryLayer#gamma} to use for imagery layers created for this provider.
  123396. * Changing this value after creating an {@link ImageryLayer} for this provider will have
  123397. * no effect. Instead, set the layer's {@link ImageryLayer#gamma} property.
  123398. *
  123399. * @type {Number}
  123400. * @default 1.0
  123401. */
  123402. this.defaultGamma = 1.0;
  123403. this._tilingScheme = new WebMercatorTilingScheme({
  123404. numberOfLevelZeroTilesX : 2,
  123405. numberOfLevelZeroTilesY : 2,
  123406. ellipsoid : options.ellipsoid
  123407. });
  123408. this._tileWidth = undefined;
  123409. this._tileHeight = undefined;
  123410. this._maximumLevel = undefined;
  123411. this._imageUrlTemplate = undefined;
  123412. this._imageUrlSubdomains = undefined;
  123413. this._errorEvent = new Event();
  123414. this._ready = false;
  123415. this._readyPromise = when.defer();
  123416. var metadataUrl = this._url + '/REST/v1/Imagery/Metadata/' + this._mapStyle + '?incl=ImageryProviders&key=' + this._key;
  123417. var that = this;
  123418. var metadataError;
  123419. function metadataSuccess(data) {
  123420. var resource = data.resourceSets[0].resources[0];
  123421. that._tileWidth = resource.imageWidth;
  123422. that._tileHeight = resource.imageHeight;
  123423. that._maximumLevel = resource.zoomMax - 1;
  123424. that._imageUrlSubdomains = resource.imageUrlSubdomains;
  123425. that._imageUrlTemplate = resource.imageUrl.replace('{culture}', that._culture);
  123426. var tileProtocol = that._tileProtocol;
  123427. if (!defined(tileProtocol)) {
  123428. // use the document's protocol, unless it's not http or https
  123429. var documentProtocol = document.location.protocol;
  123430. tileProtocol = /^http/.test(documentProtocol) ? documentProtocol : 'http:';
  123431. }
  123432. that._imageUrlTemplate = that._imageUrlTemplate.replace(/^http:/, tileProtocol);
  123433. // Install the default tile discard policy if none has been supplied.
  123434. if (!defined(that._tileDiscardPolicy)) {
  123435. that._tileDiscardPolicy = new DiscardMissingTileImagePolicy({
  123436. missingImageUrl : buildImageUrl(that, 0, 0, that._maximumLevel),
  123437. pixelsToCheck : [new Cartesian2(0, 0), new Cartesian2(120, 140), new Cartesian2(130, 160), new Cartesian2(200, 50), new Cartesian2(200, 200)],
  123438. disableCheckIfAllPixelsAreTransparent : true
  123439. });
  123440. }
  123441. var attributionList = that._attributionList = resource.imageryProviders;
  123442. if (!attributionList) {
  123443. attributionList = that._attributionList = [];
  123444. }
  123445. for (var attributionIndex = 0, attributionLength = attributionList.length; attributionIndex < attributionLength; ++attributionIndex) {
  123446. var attribution = attributionList[attributionIndex];
  123447. attribution.credit = new Credit(attribution.attribution);
  123448. var coverageAreas = attribution.coverageAreas;
  123449. for (var areaIndex = 0, areaLength = attribution.coverageAreas.length; areaIndex < areaLength; ++areaIndex) {
  123450. var area = coverageAreas[areaIndex];
  123451. var bbox = area.bbox;
  123452. area.bbox = new Rectangle(
  123453. CesiumMath.toRadians(bbox[1]),
  123454. CesiumMath.toRadians(bbox[0]),
  123455. CesiumMath.toRadians(bbox[3]),
  123456. CesiumMath.toRadians(bbox[2]));
  123457. }
  123458. }
  123459. that._ready = true;
  123460. that._readyPromise.resolve(true);
  123461. TileProviderError.handleSuccess(metadataError);
  123462. }
  123463. function metadataFailure(e) {
  123464. var message = 'An error occurred while accessing ' + metadataUrl + '.';
  123465. metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
  123466. that._readyPromise.reject(new RuntimeError(message));
  123467. }
  123468. function requestMetadata() {
  123469. var metadata = loadJsonp(metadataUrl, {
  123470. callbackParameterName : 'jsonp',
  123471. proxy : that._proxy
  123472. });
  123473. when(metadata, metadataSuccess, metadataFailure);
  123474. }
  123475. requestMetadata();
  123476. }
  123477. defineProperties(BingMapsImageryProvider.prototype, {
  123478. /**
  123479. * Gets the name of the BingMaps server url hosting the imagery.
  123480. * @memberof BingMapsImageryProvider.prototype
  123481. * @type {String}
  123482. * @readonly
  123483. */
  123484. url : {
  123485. get : function() {
  123486. return this._url;
  123487. }
  123488. },
  123489. /**
  123490. * Gets the proxy used by this provider.
  123491. * @memberof BingMapsImageryProvider.prototype
  123492. * @type {Proxy}
  123493. * @readonly
  123494. */
  123495. proxy : {
  123496. get : function() {
  123497. return this._proxy;
  123498. }
  123499. },
  123500. /**
  123501. * Gets the Bing Maps key.
  123502. * @memberof BingMapsImageryProvider.prototype
  123503. * @type {String}
  123504. * @readonly
  123505. */
  123506. key : {
  123507. get : function() {
  123508. return this._key;
  123509. }
  123510. },
  123511. /**
  123512. * Gets the type of Bing Maps imagery to load.
  123513. * @memberof BingMapsImageryProvider.prototype
  123514. * @type {BingMapsStyle}
  123515. * @readonly
  123516. */
  123517. mapStyle : {
  123518. get : function() {
  123519. return this._mapStyle;
  123520. }
  123521. },
  123522. /**
  123523. * The culture to use when requesting Bing Maps imagery. Not
  123524. * all cultures are supported. See {@link http://msdn.microsoft.com/en-us/library/hh441729.aspx}
  123525. * for information on the supported cultures.
  123526. * @memberof BingMapsImageryProvider.prototype
  123527. * @type {String}
  123528. * @readonly
  123529. */
  123530. culture : {
  123531. get : function() {
  123532. return this._culture;
  123533. }
  123534. },
  123535. /**
  123536. * Gets the width of each tile, in pixels. This function should
  123537. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  123538. * @memberof BingMapsImageryProvider.prototype
  123539. * @type {Number}
  123540. * @readonly
  123541. */
  123542. tileWidth : {
  123543. get : function() {
  123544. if (!this._ready) {
  123545. throw new DeveloperError('tileWidth must not be called before the imagery provider is ready.');
  123546. }
  123547. return this._tileWidth;
  123548. }
  123549. },
  123550. /**
  123551. * Gets the height of each tile, in pixels. This function should
  123552. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  123553. * @memberof BingMapsImageryProvider.prototype
  123554. * @type {Number}
  123555. * @readonly
  123556. */
  123557. tileHeight: {
  123558. get : function() {
  123559. if (!this._ready) {
  123560. throw new DeveloperError('tileHeight must not be called before the imagery provider is ready.');
  123561. }
  123562. return this._tileHeight;
  123563. }
  123564. },
  123565. /**
  123566. * Gets the maximum level-of-detail that can be requested. This function should
  123567. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  123568. * @memberof BingMapsImageryProvider.prototype
  123569. * @type {Number}
  123570. * @readonly
  123571. */
  123572. maximumLevel : {
  123573. get : function() {
  123574. if (!this._ready) {
  123575. throw new DeveloperError('maximumLevel must not be called before the imagery provider is ready.');
  123576. }
  123577. return this._maximumLevel;
  123578. }
  123579. },
  123580. /**
  123581. * Gets the minimum level-of-detail that can be requested. This function should
  123582. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  123583. * @memberof BingMapsImageryProvider.prototype
  123584. * @type {Number}
  123585. * @readonly
  123586. */
  123587. minimumLevel : {
  123588. get : function() {
  123589. if (!this._ready) {
  123590. throw new DeveloperError('minimumLevel must not be called before the imagery provider is ready.');
  123591. }
  123592. return 0;
  123593. }
  123594. },
  123595. /**
  123596. * Gets the tiling scheme used by this provider. This function should
  123597. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  123598. * @memberof BingMapsImageryProvider.prototype
  123599. * @type {TilingScheme}
  123600. * @readonly
  123601. */
  123602. tilingScheme : {
  123603. get : function() {
  123604. if (!this._ready) {
  123605. throw new DeveloperError('tilingScheme must not be called before the imagery provider is ready.');
  123606. }
  123607. return this._tilingScheme;
  123608. }
  123609. },
  123610. /**
  123611. * Gets the rectangle, in radians, of the imagery provided by this instance. This function should
  123612. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  123613. * @memberof BingMapsImageryProvider.prototype
  123614. * @type {Rectangle}
  123615. * @readonly
  123616. */
  123617. rectangle : {
  123618. get : function() {
  123619. if (!this._ready) {
  123620. throw new DeveloperError('rectangle must not be called before the imagery provider is ready.');
  123621. }
  123622. return this._tilingScheme.rectangle;
  123623. }
  123624. },
  123625. /**
  123626. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  123627. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  123628. * returns undefined, no tiles are filtered. This function should
  123629. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  123630. * @memberof BingMapsImageryProvider.prototype
  123631. * @type {TileDiscardPolicy}
  123632. * @readonly
  123633. */
  123634. tileDiscardPolicy : {
  123635. get : function() {
  123636. if (!this._ready) {
  123637. throw new DeveloperError('tileDiscardPolicy must not be called before the imagery provider is ready.');
  123638. }
  123639. return this._tileDiscardPolicy;
  123640. }
  123641. },
  123642. /**
  123643. * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
  123644. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  123645. * are passed an instance of {@link TileProviderError}.
  123646. * @memberof BingMapsImageryProvider.prototype
  123647. * @type {Event}
  123648. * @readonly
  123649. */
  123650. errorEvent : {
  123651. get : function() {
  123652. return this._errorEvent;
  123653. }
  123654. },
  123655. /**
  123656. * Gets a value indicating whether or not the provider is ready for use.
  123657. * @memberof BingMapsImageryProvider.prototype
  123658. * @type {Boolean}
  123659. * @readonly
  123660. */
  123661. ready : {
  123662. get : function() {
  123663. return this._ready;
  123664. }
  123665. },
  123666. /**
  123667. * Gets a promise that resolves to true when the provider is ready for use.
  123668. * @memberof BingMapsImageryProvider.prototype
  123669. * @type {Promise.<Boolean>}
  123670. * @readonly
  123671. */
  123672. readyPromise : {
  123673. get : function() {
  123674. return this._readyPromise.promise;
  123675. }
  123676. },
  123677. /**
  123678. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  123679. * the source of the imagery. This function should not be called before {@link BingMapsImageryProvider#ready} returns true.
  123680. * @memberof BingMapsImageryProvider.prototype
  123681. * @type {Credit}
  123682. * @readonly
  123683. */
  123684. credit : {
  123685. get : function() {
  123686. return this._credit;
  123687. }
  123688. },
  123689. /**
  123690. * Gets a value indicating whether or not the images provided by this imagery provider
  123691. * include an alpha channel. If this property is false, an alpha channel, if present, will
  123692. * be ignored. If this property is true, any images without an alpha channel will be treated
  123693. * as if their alpha is 1.0 everywhere. Setting this property to false reduces memory usage
  123694. * and texture upload time.
  123695. * @memberof BingMapsImageryProvider.prototype
  123696. * @type {Boolean}
  123697. * @readonly
  123698. */
  123699. hasAlphaChannel : {
  123700. get : function() {
  123701. return false;
  123702. }
  123703. }
  123704. });
  123705. var rectangleScratch = new Rectangle();
  123706. /**
  123707. * Gets the credits to be displayed when a given tile is displayed.
  123708. *
  123709. * @param {Number} x The tile X coordinate.
  123710. * @param {Number} y The tile Y coordinate.
  123711. * @param {Number} level The tile level;
  123712. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  123713. *
  123714. * @exception {DeveloperError} <code>getTileCredits</code> must not be called before the imagery provider is ready.
  123715. */
  123716. BingMapsImageryProvider.prototype.getTileCredits = function(x, y, level) {
  123717. if (!this._ready) {
  123718. throw new DeveloperError('getTileCredits must not be called before the imagery provider is ready.');
  123719. }
  123720. var rectangle = this._tilingScheme.tileXYToRectangle(x, y, level, rectangleScratch);
  123721. var result = getRectangleAttribution(this._attributionList, level, rectangle);
  123722. if (defined(this._keyErrorCredit)) {
  123723. result.push(this._keyErrorCredit);
  123724. }
  123725. return result;
  123726. };
  123727. /**
  123728. * Requests the image for a given tile. This function should
  123729. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  123730. *
  123731. * @param {Number} x The tile X coordinate.
  123732. * @param {Number} y The tile Y coordinate.
  123733. * @param {Number} level The tile level.
  123734. * @returns {Promise.<Image|Canvas>|undefined} A promise for the image that will resolve when the image is available, or
  123735. * undefined if there are too many active requests to the server, and the request
  123736. * should be retried later. The resolved image may be either an
  123737. * Image or a Canvas DOM object.
  123738. *
  123739. * @exception {DeveloperError} <code>requestImage</code> must not be called before the imagery provider is ready.
  123740. */
  123741. BingMapsImageryProvider.prototype.requestImage = function(x, y, level) {
  123742. if (!this._ready) {
  123743. throw new DeveloperError('requestImage must not be called before the imagery provider is ready.');
  123744. }
  123745. var url = buildImageUrl(this, x, y, level);
  123746. return ImageryProvider.loadImage(this, url);
  123747. };
  123748. /**
  123749. * Picking features is not currently supported by this imagery provider, so this function simply returns
  123750. * undefined.
  123751. *
  123752. * @param {Number} x The tile X coordinate.
  123753. * @param {Number} y The tile Y coordinate.
  123754. * @param {Number} level The tile level.
  123755. * @param {Number} longitude The longitude at which to pick features.
  123756. * @param {Number} latitude The latitude at which to pick features.
  123757. * @return {Promise.<ImageryLayerFeatureInfo[]>|undefined} A promise for the picked features that will resolve when the asynchronous
  123758. * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
  123759. * instances. The array may be empty if no features are found at the given location.
  123760. * It may also be undefined if picking is not supported.
  123761. */
  123762. BingMapsImageryProvider.prototype.pickFeatures = function() {
  123763. return undefined;
  123764. };
  123765. BingMapsImageryProvider._logoData = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD0AAAAaCAYAAAAEy1RnAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAB3RJTUUH3gIDEgcPTMnXOQAAClZJREFUWMPdWGtsFNcV/u689uH1+sXaONhlWQzBENtxiUFBpBSLd60IpXHSNig4URtSYQUkRJNSi0igViVVVBJBaBsiAgKRQJSG8AgEHCCWU4iBCprY2MSgXfOI16y9D3s9Mzsztz9yB12WNU2i9Ecy0tHOzN4793zn3POdcy7BnRfJ8I7iB3SRDPeEExswLz8Y0DZIAYDIRGAgLQAm+7Xle31J3L3Anp1MZPY+BUBjorN332vgYhpgV1FRUd6TTz45ubq6OtDV1SXpuu5g//Oept9wNwlMyAi8IXDjyF245TsDTdivDMATCATGNDU1/WbhwoWPTZs2bWx1dXWhx+Oxrl+/PqTrus5t9W8KWEzjinTAYhro/xuBStwiIgBnJBLxKIoy1u/3V/r9/krDMMz3339/Z3t7e38ikUgCMDLEt8W+Q0cAI3McYTDDmZxh7DESG5Ni43jg9Gsa+X+OsxWxPSJTSj3JZFK5ZRVJErOzs8e6XC4fgGwALhbzDgAKU1hK28KEA6PMmTMn56233qpevnz5PQDcbJ7EzVUAuMrLy3MBeABkcWOEDELSyFe4y7iMoHkriZZlKYZh8ASHZDKpJJPJHAC5APIA5APIAeBlCjo5TwlpXnbOmTPHP3fu3KZVq1atZKBcDJQ9x7V48WJfc3Pzhp6enj+tXLnyR8w4MjdG4gyVDk7KICMClzKlLUrpbQMNw5AkScppbGz8cWdn57WjR4/2caw+DEBlYjO8wX1foZQWuN3uKZIklQD4G+fhlG0Yl8uVm5WVVW6app6dne0D0G8vnxbjJntHubCUOK/badZICyWanrJuAaeUknTQpmlKkUhEWbx48U8LCwtHhUKha+fPn+85fPhwV0tLyzUACSZx9jvMFhIByNFoVDEMw/qKB5HPvJfkUqBr9+7deklJyZ/j8bi5ffv2OAslieMLsG+m2DybT2QuzEQOsF5SUqJfvXo1yc2l6Xn6rgSRSCSEc+fOhVeuXLmwoqJixvTp0wcWLFgQ7unpudHR0dF97ty5z/fu3XseQJh5adjeerquy5ZlCalUivh8Pt8HH3ywzOPxyD09PZ81NjZ+2NnZaQEQx40b54vFYqaqquEVK1b4a2tr/WvWrDn18ssv144fP36SqqoD69ev371nz57rDLwAwHHkyJGfjRs3rtowDOv06dOnu7q6rs6bN2/s7Nmz9zIjDKenWoFZKg/AlMLCwl82Nzf/m3LX22+/fXb06NF/ALC8u7u7m6ZdkUhksL29/UpLS0vzunXrVgAoBzAaQBGAiY2NjUui0ei1RCLRFwwG/9PX19cVi8WCqqoOdHd3HysrK6sDMCccDl8IBoOtiqIsOnbs2D+i0eiV3t7ez8Ph8GeRSKRT07TB/v7+i1OnTp0HYBqABzs7O/+paVo0Fot1RyKRi/F4/Gp/f39XIpHoZnoUMn6wU+ZtRDaymwmxZFk2AWjvvvvuJ/F4PMn/n5+fn1VeXu6fOXNmbU1NzUOM4Bz8QqIoyg6HwxuLxfq3bdu2a+vWrW/09/dfKy0tffDVV199BEC20+n0ud3uQgBup9Pp83g8JYqieE+ePPnxxo0bt33xxRen8/Ly7n3hhRcWASh47bXX5pWVldWFw+GuXbt27XjzzTd3BoPBDq/XG1AUZRRHmAKPVfqaoKkgCCkA+oYNG84Eg0FHTU1N5ezZs8eWlJQ4CSF8/LvZYhJPQoQQpFKpwcrKyo1su9HBwUF99erVv588eXINgOOmacIwDEopdaZSKUIpxYkTJz6sr68/BMBav379RcMwZk2aNOl+AP+qq6t7xDTNVEVFxR+j0WgSAJk4ceKlTz/9tNzpdHpZvIvpjVW6pykhhBJCbkvwgiAQQogEQL558ybdtGlTsLm5OWJZdxZmlmWll5OUEEJN0zSGhob6GcOrALSzZ8/2apqWcLlc2axGACNRkRAimqaph0Kh68xIwwB0y7IMSZKcABz5+fkl8Xj8y2g0apOb5na7rYGBgS/JV54Q0qpAAoBKaS0jBWClg1ZVFeFw2AlgVF1dXeDpp5+eWVFRUVpcXOzgvQwAbrcbDJhdudlGpKZpGtx6JCcnRxIEQbQsS2PjbjM+AMvlchnMSBaXkr7ymCCIhmEYfMoVRVESBEHI0CaTTNubssUsQRBuubCtra33pZdeCk6YMCGwZs2aipqaGn9paWmuJEl3JP0bN258eeTIkRMABrm0YomiaImiKGVlZeWxLecAgBkzZvgdDkfWjRs3ggA0bpfpoiiahBCqKEqKAy2yULMA6MlkMp6Xl3cP1x2SWCwmFhQU+CmlFhfHNFOevpX4LcvSJUkyAeDQoUOh119//fpTTz01Zf78+UWBQCBHUZQ7yE/TNGPfvn0n33vvvSP79+//BECMeZsCMGRZNgRBgNPpHHXx4sVVDQ0Nf1+wYMGYJ554YikAevDgwUMA4oIgQJZlSggZdDqdBiGEZGdn6ww0tQlJURTT4/EMHz9+/MCjjz7622AwuHbZsmVbiouLvWvXrm1wOp3ZqVRqaKQTIInf1gAMl8ulU0q1CxcuBGOxmL5u3bryQCDgycrKEjORXGtra8eOHTsOHz169OyVK1cuA+hlRYrGlNRkWR7UNO2mYRiaz+cb3dLS8gYhhOi6Hj116tSOVatWHQNALcsaME0zLghClBDSZ9+zQsZ2SoJS2udwOKLPPffcvsrKyrJAIPDQ/v37txiGofX19V3r7e29UlBQMHqEVpjwnrYA6PF4PK6q6s2qqqqpZWVlitvtljOB7enpiWzbtu3wgQMHTre1tV0E0MeKkkGuIhMAqHv37u30er3Px+NxlyiKygMPPOAnhFiXLl0Kbd68uYPNsXbu3Lk6mUwaqqr2btmyZUdtbe3hd955pwvAEFNcO3jw4K/b2tqiqqpGIpGI4/HHH/9rQ0PDCa/XOyoSidDLly8PNTU1PcZ4QuNK1ju6NYHFRAGASXPnzv1Fa2vrxzTDpapqateuXR/Nnz+/SVGUhwFMBzCBFSLZLF75DsrJGpXRAH4EIABgPIBxAEoBFAPwARjFif1sNzZ25+VlOhaxufcCqAFQC+BhAPVLliz5XSqVUkOhUAuAKWnFyR3dlsw+fg+A+8eMGfPzTZs2bY9GozEb8JkzZ9qXLl36l+Li4l8B+AmAyQDGsGrOzfXNPGPawG2l85jksmcPm+vihH+2W1iF3bvZPN+sWbPuGx4eDrW3t+85fvz41o6OjmZN04Y0TYvV19cvYIbN5QqUjG2mwj5YAqDK4XDMe+aZZ55vbW09+sorr2yuqqpqYFatAuBn3uB7XzJCY297XeaUd2RoGzOJmHb6IjFj5D777LP3DQwMfDw8PBxSVbUvkUj0hEKhj1588cXH2O7zMSPdplumoxveMx5Zlj3jx4/39vb26gMDA4MsvgYZo+p8Pr7LqQX5Ds/U7d0jFxUVZS1atKg4Nzc317Isp67rZldXV6y5ufkmI78hFtcmrx8ZweMit6XsUs4+6kmlgbW+peLf9gyMZNCR374G0y/FxEzX8b/8+bkXEBxKFwAAAABJRU5ErkJggg==';
  123766. /**
  123767. * Converts a tiles (x, y, level) position into a quadkey used to request an image
  123768. * from a Bing Maps server.
  123769. *
  123770. * @param {Number} x The tile's x coordinate.
  123771. * @param {Number} y The tile's y coordinate.
  123772. * @param {Number} level The tile's zoom level.
  123773. *
  123774. * @see {@link http://msdn.microsoft.com/en-us/library/bb259689.aspx|Bing Maps Tile System}
  123775. * @see BingMapsImageryProvider#quadKeyToTileXY
  123776. */
  123777. BingMapsImageryProvider.tileXYToQuadKey = function(x, y, level) {
  123778. var quadkey = '';
  123779. for ( var i = level; i >= 0; --i) {
  123780. var bitmask = 1 << i;
  123781. var digit = 0;
  123782. if ((x & bitmask) !== 0) {
  123783. digit |= 1;
  123784. }
  123785. if ((y & bitmask) !== 0) {
  123786. digit |= 2;
  123787. }
  123788. quadkey += digit;
  123789. }
  123790. return quadkey;
  123791. };
  123792. /**
  123793. * Converts a tile's quadkey used to request an image from a Bing Maps server into the
  123794. * (x, y, level) position.
  123795. *
  123796. * @param {String} quadkey The tile's quad key
  123797. *
  123798. * @see {@link http://msdn.microsoft.com/en-us/library/bb259689.aspx|Bing Maps Tile System}
  123799. * @see BingMapsImageryProvider#tileXYToQuadKey
  123800. */
  123801. BingMapsImageryProvider.quadKeyToTileXY = function(quadkey) {
  123802. var x = 0;
  123803. var y = 0;
  123804. var level = quadkey.length - 1;
  123805. for ( var i = level; i >= 0; --i) {
  123806. var bitmask = 1 << i;
  123807. var digit = +quadkey[level - i];
  123808. if ((digit & 1) !== 0) {
  123809. x |= bitmask;
  123810. }
  123811. if ((digit & 2) !== 0) {
  123812. y |= bitmask;
  123813. }
  123814. }
  123815. return {
  123816. x : x,
  123817. y : y,
  123818. level : level
  123819. };
  123820. };
  123821. function buildImageUrl(imageryProvider, x, y, level) {
  123822. var imageUrl = imageryProvider._imageUrlTemplate;
  123823. var quadkey = BingMapsImageryProvider.tileXYToQuadKey(x, y, level);
  123824. imageUrl = imageUrl.replace('{quadkey}', quadkey);
  123825. var subdomains = imageryProvider._imageUrlSubdomains;
  123826. var subdomainIndex = (x + y + level) % subdomains.length;
  123827. imageUrl = imageUrl.replace('{subdomain}', subdomains[subdomainIndex]);
  123828. var proxy = imageryProvider._proxy;
  123829. if (defined(proxy)) {
  123830. imageUrl = proxy.getURL(imageUrl);
  123831. }
  123832. return imageUrl;
  123833. }
  123834. var intersectionScratch = new Rectangle();
  123835. function getRectangleAttribution(attributionList, level, rectangle) {
  123836. // Bing levels start at 1, while ours start at 0.
  123837. ++level;
  123838. var result = [];
  123839. for (var attributionIndex = 0, attributionLength = attributionList.length; attributionIndex < attributionLength; ++attributionIndex) {
  123840. var attribution = attributionList[attributionIndex];
  123841. var coverageAreas = attribution.coverageAreas;
  123842. var included = false;
  123843. for (var areaIndex = 0, areaLength = attribution.coverageAreas.length; !included && areaIndex < areaLength; ++areaIndex) {
  123844. var area = coverageAreas[areaIndex];
  123845. if (level >= area.zoomMin && level <= area.zoomMax) {
  123846. var intersection = Rectangle.intersection(rectangle, area.bbox, intersectionScratch);
  123847. if (defined(intersection)) {
  123848. included = true;
  123849. }
  123850. }
  123851. }
  123852. if (included) {
  123853. result.push(attribution.credit);
  123854. }
  123855. }
  123856. return result;
  123857. }
  123858. return BingMapsImageryProvider;
  123859. });
  123860. /*global define*/
  123861. define('Scene/CullingVolume',[
  123862. '../Core/Cartesian3',
  123863. '../Core/Cartesian4',
  123864. '../Core/defaultValue',
  123865. '../Core/defined',
  123866. '../Core/DeveloperError',
  123867. '../Core/Intersect',
  123868. '../Core/Plane'
  123869. ], function(
  123870. Cartesian3,
  123871. Cartesian4,
  123872. defaultValue,
  123873. defined,
  123874. DeveloperError,
  123875. Intersect,
  123876. Plane) {
  123877. 'use strict';
  123878. /**
  123879. * The culling volume defined by planes.
  123880. *
  123881. * @alias CullingVolume
  123882. * @constructor
  123883. *
  123884. * @param {Cartesian4[]} [planes] An array of clipping planes.
  123885. */
  123886. function CullingVolume(planes) {
  123887. /**
  123888. * Each plane is represented by a Cartesian4 object, where the x, y, and z components
  123889. * define the unit vector normal to the plane, and the w component is the distance of the
  123890. * plane from the origin.
  123891. * @type {Cartesian4[]}
  123892. * @default []
  123893. */
  123894. this.planes = defaultValue(planes, []);
  123895. }
  123896. var faces = [new Cartesian3(), new Cartesian3(), new Cartesian3()];
  123897. Cartesian3.clone(Cartesian3.UNIT_X, faces[0]);
  123898. Cartesian3.clone(Cartesian3.UNIT_Y, faces[1]);
  123899. Cartesian3.clone(Cartesian3.UNIT_Z, faces[2]);
  123900. var scratchPlaneCenter = new Cartesian3();
  123901. var scratchPlaneNormal = new Cartesian3();
  123902. var scratchPlane = new Plane(new Cartesian3(), 0.0);
  123903. /**
  123904. * Constructs a culling volume from a bounding sphere. Creates six planes that create a box containing the sphere.
  123905. * The planes are aligned to the x, y, and z axes in world coordinates.
  123906. *
  123907. * @param {BoundingSphere} boundingSphere The bounding sphere used to create the culling volume.
  123908. * @param {CullingVolume} [result] The object onto which to store the result.
  123909. * @returns {CullingVolume} The culling volume created from the bounding sphere.
  123910. */
  123911. CullingVolume.fromBoundingSphere = function(boundingSphere, result) {
  123912. if (!defined(boundingSphere)) {
  123913. throw new DeveloperError('boundingSphere is required.');
  123914. }
  123915. if (!defined(result)) {
  123916. result = new CullingVolume();
  123917. }
  123918. var length = faces.length;
  123919. var planes = result.planes;
  123920. planes.length = 2 * length;
  123921. var center = boundingSphere.center;
  123922. var radius = boundingSphere.radius;
  123923. var planeIndex = 0;
  123924. for (var i = 0; i < length; ++i) {
  123925. var faceNormal = faces[i];
  123926. var plane0 = planes[planeIndex];
  123927. var plane1 = planes[planeIndex + 1];
  123928. if (!defined(plane0)) {
  123929. plane0 = planes[planeIndex] = new Cartesian4();
  123930. }
  123931. if (!defined(plane1)) {
  123932. plane1 = planes[planeIndex + 1] = new Cartesian4();
  123933. }
  123934. Cartesian3.multiplyByScalar(faceNormal, -radius, scratchPlaneCenter);
  123935. Cartesian3.add(center, scratchPlaneCenter, scratchPlaneCenter);
  123936. plane0.x = faceNormal.x;
  123937. plane0.y = faceNormal.y;
  123938. plane0.z = faceNormal.z;
  123939. plane0.w = -Cartesian3.dot(faceNormal, scratchPlaneCenter);
  123940. Cartesian3.multiplyByScalar(faceNormal, radius, scratchPlaneCenter);
  123941. Cartesian3.add(center, scratchPlaneCenter, scratchPlaneCenter);
  123942. plane1.x = -faceNormal.x;
  123943. plane1.y = -faceNormal.y;
  123944. plane1.z = -faceNormal.z;
  123945. plane1.w = -Cartesian3.dot(Cartesian3.negate(faceNormal, scratchPlaneNormal), scratchPlaneCenter);
  123946. planeIndex += 2;
  123947. }
  123948. return result;
  123949. };
  123950. /**
  123951. * Determines whether a bounding volume intersects the culling volume.
  123952. *
  123953. * @param {Object} boundingVolume The bounding volume whose intersection with the culling volume is to be tested.
  123954. * @returns {Intersect} Intersect.OUTSIDE, Intersect.INTERSECTING, or Intersect.INSIDE.
  123955. */
  123956. CullingVolume.prototype.computeVisibility = function(boundingVolume) {
  123957. if (!defined(boundingVolume)) {
  123958. throw new DeveloperError('boundingVolume is required.');
  123959. }
  123960. var planes = this.planes;
  123961. var intersecting = false;
  123962. for (var k = 0, len = planes.length; k < len; ++k) {
  123963. var result = boundingVolume.intersectPlane(Plane.fromCartesian4(planes[k], scratchPlane));
  123964. if (result === Intersect.OUTSIDE) {
  123965. return Intersect.OUTSIDE;
  123966. } else if (result === Intersect.INTERSECTING) {
  123967. intersecting = true;
  123968. }
  123969. }
  123970. return intersecting ? Intersect.INTERSECTING : Intersect.INSIDE;
  123971. };
  123972. /**
  123973. * Determines whether a bounding volume intersects the culling volume.
  123974. *
  123975. * @param {Object} boundingVolume The bounding volume whose intersection with the culling volume is to be tested.
  123976. * @param {Number} parentPlaneMask A bit mask from the boundingVolume's parent's check against the same culling
  123977. * volume, such that if (planeMask & (1 << planeIndex) === 0), for k < 31, then
  123978. * the parent (and therefore this) volume is completely inside plane[planeIndex]
  123979. * and that plane check can be skipped.
  123980. * @returns {Number} A plane mask as described above (which can be applied to this boundingVolume's children).
  123981. *
  123982. * @private
  123983. */
  123984. CullingVolume.prototype.computeVisibilityWithPlaneMask = function(boundingVolume, parentPlaneMask) {
  123985. if (!defined(boundingVolume)) {
  123986. throw new DeveloperError('boundingVolume is required.');
  123987. }
  123988. if (!defined(parentPlaneMask)) {
  123989. throw new DeveloperError('parentPlaneMask is required.');
  123990. }
  123991. if (parentPlaneMask === CullingVolume.MASK_OUTSIDE || parentPlaneMask === CullingVolume.MASK_INSIDE) {
  123992. // parent is completely outside or completely inside, so this child is as well.
  123993. return parentPlaneMask;
  123994. }
  123995. // Start with MASK_INSIDE (all zeros) so that after the loop, the return value can be compared with MASK_INSIDE.
  123996. // (Because if there are fewer than 31 planes, the upper bits wont be changed.)
  123997. var mask = CullingVolume.MASK_INSIDE;
  123998. var planes = this.planes;
  123999. for (var k = 0, len = planes.length; k < len; ++k) {
  124000. // For k greater than 31 (since 31 is the maximum number of INSIDE/INTERSECTING bits we can store), skip the optimization.
  124001. var flag = (k < 31) ? (1 << k) : 0;
  124002. if (k < 31 && (parentPlaneMask & flag) === 0) {
  124003. // boundingVolume is known to be INSIDE this plane.
  124004. continue;
  124005. }
  124006. var result = boundingVolume.intersectPlane(Plane.fromCartesian4(planes[k], scratchPlane));
  124007. if (result === Intersect.OUTSIDE) {
  124008. return CullingVolume.MASK_OUTSIDE;
  124009. } else if (result === Intersect.INTERSECTING) {
  124010. mask |= flag;
  124011. }
  124012. }
  124013. return mask;
  124014. };
  124015. /**
  124016. * For plane masks (as used in {@link CullingVolume#computeVisibilityWithPlaneMask}), this special value
  124017. * represents the case where the object bounding volume is entirely outside the culling volume.
  124018. *
  124019. * @type {Number}
  124020. * @private
  124021. */
  124022. CullingVolume.MASK_OUTSIDE = 0xffffffff;
  124023. /**
  124024. * For plane masks (as used in {@link CullingVolume.prototype.computeVisibilityWithPlaneMask}), this value
  124025. * represents the case where the object bounding volume is entirely inside the culling volume.
  124026. *
  124027. * @type {Number}
  124028. * @private
  124029. */
  124030. CullingVolume.MASK_INSIDE = 0x00000000;
  124031. /**
  124032. * For plane masks (as used in {@link CullingVolume.prototype.computeVisibilityWithPlaneMask}), this value
  124033. * represents the case where the object bounding volume (may) intersect all planes of the culling volume.
  124034. *
  124035. * @type {Number}
  124036. * @private
  124037. */
  124038. CullingVolume.MASK_INDETERMINATE = 0x7fffffff;
  124039. return CullingVolume;
  124040. });
  124041. /*global define*/
  124042. define('Scene/PerspectiveOffCenterFrustum',[
  124043. '../Core/Cartesian3',
  124044. '../Core/Cartesian4',
  124045. '../Core/defined',
  124046. '../Core/defineProperties',
  124047. '../Core/DeveloperError',
  124048. '../Core/Matrix4',
  124049. './CullingVolume'
  124050. ], function(
  124051. Cartesian3,
  124052. Cartesian4,
  124053. defined,
  124054. defineProperties,
  124055. DeveloperError,
  124056. Matrix4,
  124057. CullingVolume) {
  124058. 'use strict';
  124059. /**
  124060. * The viewing frustum is defined by 6 planes.
  124061. * Each plane is represented by a {@link Cartesian4} object, where the x, y, and z components
  124062. * define the unit vector normal to the plane, and the w component is the distance of the
  124063. * plane from the origin/camera position.
  124064. *
  124065. * @alias PerspectiveOffCenterFrustum
  124066. * @constructor
  124067. *
  124068. *
  124069. * @example
  124070. * var frustum = new Cesium.PerspectiveOffCenterFrustum();
  124071. * frustum.right = 1.0;
  124072. * frustum.left = -1.0;
  124073. * frustum.top = 1.0;
  124074. * frustum.bottom = -1.0;
  124075. * frustum.near = 1.0;
  124076. * frustum.far = 2.0;
  124077. *
  124078. * @see PerspectiveFrustum
  124079. */
  124080. function PerspectiveOffCenterFrustum() {
  124081. /**
  124082. * Defines the left clipping plane.
  124083. * @type {Number}
  124084. * @default undefined
  124085. */
  124086. this.left = undefined;
  124087. this._left = undefined;
  124088. /**
  124089. * Defines the right clipping plane.
  124090. * @type {Number}
  124091. * @default undefined
  124092. */
  124093. this.right = undefined;
  124094. this._right = undefined;
  124095. /**
  124096. * Defines the top clipping plane.
  124097. * @type {Number}
  124098. * @default undefined
  124099. */
  124100. this.top = undefined;
  124101. this._top = undefined;
  124102. /**
  124103. * Defines the bottom clipping plane.
  124104. * @type {Number}
  124105. * @default undefined
  124106. */
  124107. this.bottom = undefined;
  124108. this._bottom = undefined;
  124109. /**
  124110. * The distance of the near plane.
  124111. * @type {Number}
  124112. * @default 1.0
  124113. */
  124114. this.near = 1.0;
  124115. this._near = this.near;
  124116. /**
  124117. * The distance of the far plane.
  124118. * @type {Number}
  124119. * @default 500000000.0
  124120. */
  124121. this.far = 500000000.0;
  124122. this._far = this.far;
  124123. this._cullingVolume = new CullingVolume();
  124124. this._perspectiveMatrix = new Matrix4();
  124125. this._infinitePerspective = new Matrix4();
  124126. }
  124127. function update(frustum) {
  124128. if (!defined(frustum.right) || !defined(frustum.left) ||
  124129. !defined(frustum.top) || !defined(frustum.bottom) ||
  124130. !defined(frustum.near) || !defined(frustum.far)) {
  124131. throw new DeveloperError('right, left, top, bottom, near, or far parameters are not set.');
  124132. }
  124133. var t = frustum.top;
  124134. var b = frustum.bottom;
  124135. var r = frustum.right;
  124136. var l = frustum.left;
  124137. var n = frustum.near;
  124138. var f = frustum.far;
  124139. if (t !== frustum._top || b !== frustum._bottom ||
  124140. l !== frustum._left || r !== frustum._right ||
  124141. n !== frustum._near || f !== frustum._far) {
  124142. if (frustum.near <= 0 || frustum.near > frustum.far) {
  124143. throw new DeveloperError('near must be greater than zero and less than far.');
  124144. }
  124145. frustum._left = l;
  124146. frustum._right = r;
  124147. frustum._top = t;
  124148. frustum._bottom = b;
  124149. frustum._near = n;
  124150. frustum._far = f;
  124151. frustum._perspectiveMatrix = Matrix4.computePerspectiveOffCenter(l, r, b, t, n, f, frustum._perspectiveMatrix);
  124152. frustum._infinitePerspective = Matrix4.computeInfinitePerspectiveOffCenter(l, r, b, t, n, frustum._infinitePerspective);
  124153. }
  124154. }
  124155. defineProperties(PerspectiveOffCenterFrustum.prototype, {
  124156. /**
  124157. * Gets the perspective projection matrix computed from the view frustum.
  124158. * @memberof PerspectiveOffCenterFrustum.prototype
  124159. * @type {Matrix4}
  124160. * @readonly
  124161. *
  124162. * @see PerspectiveOffCenterFrustum#infiniteProjectionMatrix
  124163. */
  124164. projectionMatrix : {
  124165. get : function() {
  124166. update(this);
  124167. return this._perspectiveMatrix;
  124168. }
  124169. },
  124170. /**
  124171. * Gets the perspective projection matrix computed from the view frustum with an infinite far plane.
  124172. * @memberof PerspectiveOffCenterFrustum.prototype
  124173. * @type {Matrix4}
  124174. * @readonly
  124175. *
  124176. * @see PerspectiveOffCenterFrustum#projectionMatrix
  124177. */
  124178. infiniteProjectionMatrix : {
  124179. get : function() {
  124180. update(this);
  124181. return this._infinitePerspective;
  124182. }
  124183. }
  124184. });
  124185. var getPlanesRight = new Cartesian3();
  124186. var getPlanesNearCenter = new Cartesian3();
  124187. var getPlanesFarCenter = new Cartesian3();
  124188. var getPlanesNormal = new Cartesian3();
  124189. /**
  124190. * Creates a culling volume for this frustum.
  124191. *
  124192. * @param {Cartesian3} position The eye position.
  124193. * @param {Cartesian3} direction The view direction.
  124194. * @param {Cartesian3} up The up direction.
  124195. * @returns {CullingVolume} A culling volume at the given position and orientation.
  124196. *
  124197. * @example
  124198. * // Check if a bounding volume intersects the frustum.
  124199. * var cullingVolume = frustum.computeCullingVolume(cameraPosition, cameraDirection, cameraUp);
  124200. * var intersect = cullingVolume.computeVisibility(boundingVolume);
  124201. */
  124202. PerspectiveOffCenterFrustum.prototype.computeCullingVolume = function(position, direction, up) {
  124203. if (!defined(position)) {
  124204. throw new DeveloperError('position is required.');
  124205. }
  124206. if (!defined(direction)) {
  124207. throw new DeveloperError('direction is required.');
  124208. }
  124209. if (!defined(up)) {
  124210. throw new DeveloperError('up is required.');
  124211. }
  124212. var planes = this._cullingVolume.planes;
  124213. var t = this.top;
  124214. var b = this.bottom;
  124215. var r = this.right;
  124216. var l = this.left;
  124217. var n = this.near;
  124218. var f = this.far;
  124219. var right = Cartesian3.cross(direction, up, getPlanesRight);
  124220. var nearCenter = getPlanesNearCenter;
  124221. Cartesian3.multiplyByScalar(direction, n, nearCenter);
  124222. Cartesian3.add(position, nearCenter, nearCenter);
  124223. var farCenter = getPlanesFarCenter;
  124224. Cartesian3.multiplyByScalar(direction, f, farCenter);
  124225. Cartesian3.add(position, farCenter, farCenter);
  124226. var normal = getPlanesNormal;
  124227. //Left plane computation
  124228. Cartesian3.multiplyByScalar(right, l, normal);
  124229. Cartesian3.add(nearCenter, normal, normal);
  124230. Cartesian3.subtract(normal, position, normal);
  124231. Cartesian3.normalize(normal, normal);
  124232. Cartesian3.cross(normal, up, normal);
  124233. var plane = planes[0];
  124234. if (!defined(plane)) {
  124235. plane = planes[0] = new Cartesian4();
  124236. }
  124237. plane.x = normal.x;
  124238. plane.y = normal.y;
  124239. plane.z = normal.z;
  124240. plane.w = -Cartesian3.dot(normal, position);
  124241. //Right plane computation
  124242. Cartesian3.multiplyByScalar(right, r, normal);
  124243. Cartesian3.add(nearCenter, normal, normal);
  124244. Cartesian3.subtract(normal, position, normal);
  124245. Cartesian3.normalize(normal, normal);
  124246. Cartesian3.cross(up, normal, normal);
  124247. plane = planes[1];
  124248. if (!defined(plane)) {
  124249. plane = planes[1] = new Cartesian4();
  124250. }
  124251. plane.x = normal.x;
  124252. plane.y = normal.y;
  124253. plane.z = normal.z;
  124254. plane.w = -Cartesian3.dot(normal, position);
  124255. //Bottom plane computation
  124256. Cartesian3.multiplyByScalar(up, b, normal);
  124257. Cartesian3.add(nearCenter, normal, normal);
  124258. Cartesian3.subtract(normal, position, normal);
  124259. Cartesian3.normalize(normal, normal);
  124260. Cartesian3.cross(right, normal, normal);
  124261. plane = planes[2];
  124262. if (!defined(plane)) {
  124263. plane = planes[2] = new Cartesian4();
  124264. }
  124265. plane.x = normal.x;
  124266. plane.y = normal.y;
  124267. plane.z = normal.z;
  124268. plane.w = -Cartesian3.dot(normal, position);
  124269. //Top plane computation
  124270. Cartesian3.multiplyByScalar(up, t, normal);
  124271. Cartesian3.add(nearCenter, normal, normal);
  124272. Cartesian3.subtract(normal, position, normal);
  124273. Cartesian3.normalize(normal, normal);
  124274. Cartesian3.cross(normal, right, normal);
  124275. plane = planes[3];
  124276. if (!defined(plane)) {
  124277. plane = planes[3] = new Cartesian4();
  124278. }
  124279. plane.x = normal.x;
  124280. plane.y = normal.y;
  124281. plane.z = normal.z;
  124282. plane.w = -Cartesian3.dot(normal, position);
  124283. //Near plane computation
  124284. plane = planes[4];
  124285. if (!defined(plane)) {
  124286. plane = planes[4] = new Cartesian4();
  124287. }
  124288. plane.x = direction.x;
  124289. plane.y = direction.y;
  124290. plane.z = direction.z;
  124291. plane.w = -Cartesian3.dot(direction, nearCenter);
  124292. //Far plane computation
  124293. Cartesian3.negate(direction, normal);
  124294. plane = planes[5];
  124295. if (!defined(plane)) {
  124296. plane = planes[5] = new Cartesian4();
  124297. }
  124298. plane.x = normal.x;
  124299. plane.y = normal.y;
  124300. plane.z = normal.z;
  124301. plane.w = -Cartesian3.dot(normal, farCenter);
  124302. return this._cullingVolume;
  124303. };
  124304. /**
  124305. * Returns the pixel's width and height in meters.
  124306. *
  124307. * @param {Number} drawingBufferWidth The width of the drawing buffer.
  124308. * @param {Number} drawingBufferHeight The height of the drawing buffer.
  124309. * @param {Number} distance The distance to the near plane in meters.
  124310. * @param {Cartesian2} result The object onto which to store the result.
  124311. * @returns {Cartesian2} The modified result parameter or a new instance of {@link Cartesian2} with the pixel's width and height in the x and y properties, respectively.
  124312. *
  124313. * @exception {DeveloperError} drawingBufferWidth must be greater than zero.
  124314. * @exception {DeveloperError} drawingBufferHeight must be greater than zero.
  124315. *
  124316. * @example
  124317. * // Example 1
  124318. * // Get the width and height of a pixel.
  124319. * var pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, 1.0, new Cesium.Cartesian2());
  124320. *
  124321. * @example
  124322. * // Example 2
  124323. * // Get the width and height of a pixel if the near plane was set to 'distance'.
  124324. * // For example, get the size of a pixel of an image on a billboard.
  124325. * var position = camera.position;
  124326. * var direction = camera.direction;
  124327. * var toCenter = Cesium.Cartesian3.subtract(primitive.boundingVolume.center, position, new Cesium.Cartesian3()); // vector from camera to a primitive
  124328. * var toCenterProj = Cesium.Cartesian3.multiplyByScalar(direction, Cesium.Cartesian3.dot(direction, toCenter), new Cesium.Cartesian3()); // project vector onto camera direction vector
  124329. * var distance = Cesium.Cartesian3.magnitude(toCenterProj);
  124330. * var pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, distance, new Cesium.Cartesian2());
  124331. */
  124332. PerspectiveOffCenterFrustum.prototype.getPixelDimensions = function(drawingBufferWidth, drawingBufferHeight, distance, result) {
  124333. update(this);
  124334. if (!defined(drawingBufferWidth) || !defined(drawingBufferHeight)) {
  124335. throw new DeveloperError('Both drawingBufferWidth and drawingBufferHeight are required.');
  124336. }
  124337. if (drawingBufferWidth <= 0) {
  124338. throw new DeveloperError('drawingBufferWidth must be greater than zero.');
  124339. }
  124340. if (drawingBufferHeight <= 0) {
  124341. throw new DeveloperError('drawingBufferHeight must be greater than zero.');
  124342. }
  124343. if (!defined(distance)) {
  124344. throw new DeveloperError('distance is required.');
  124345. }
  124346. if (!defined(result)) {
  124347. throw new DeveloperError('A result object is required.');
  124348. }
  124349. var inverseNear = 1.0 / this.near;
  124350. var tanTheta = this.top * inverseNear;
  124351. var pixelHeight = 2.0 * distance * tanTheta / drawingBufferHeight;
  124352. tanTheta = this.right * inverseNear;
  124353. var pixelWidth = 2.0 * distance * tanTheta / drawingBufferWidth;
  124354. result.x = pixelWidth;
  124355. result.y = pixelHeight;
  124356. return result;
  124357. };
  124358. /**
  124359. * Returns a duplicate of a PerspectiveOffCenterFrustum instance.
  124360. *
  124361. * @param {PerspectiveOffCenterFrustum} [result] The object onto which to store the result.
  124362. * @returns {PerspectiveOffCenterFrustum} The modified result parameter or a new PerspectiveFrustum instance if one was not provided.
  124363. */
  124364. PerspectiveOffCenterFrustum.prototype.clone = function(result) {
  124365. if (!defined(result)) {
  124366. result = new PerspectiveOffCenterFrustum();
  124367. }
  124368. result.right = this.right;
  124369. result.left = this.left;
  124370. result.top = this.top;
  124371. result.bottom = this.bottom;
  124372. result.near = this.near;
  124373. result.far = this.far;
  124374. // force update of clone to compute matrices
  124375. result._left = undefined;
  124376. result._right = undefined;
  124377. result._top = undefined;
  124378. result._bottom = undefined;
  124379. result._near = undefined;
  124380. result._far = undefined;
  124381. return result;
  124382. };
  124383. /**
  124384. * Compares the provided PerspectiveOffCenterFrustum componentwise and returns
  124385. * <code>true</code> if they are equal, <code>false</code> otherwise.
  124386. *
  124387. * @param {PerspectiveOffCenterFrustum} [other] The right hand side PerspectiveOffCenterFrustum.
  124388. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  124389. */
  124390. PerspectiveOffCenterFrustum.prototype.equals = function(other) {
  124391. return (defined(other) &&
  124392. this.right === other.right &&
  124393. this.left === other.left &&
  124394. this.top === other.top &&
  124395. this.bottom === other.bottom &&
  124396. this.near === other.near &&
  124397. this.far === other.far);
  124398. };
  124399. return PerspectiveOffCenterFrustum;
  124400. });
  124401. /*global define*/
  124402. define('Scene/PerspectiveFrustum',[
  124403. '../Core/defined',
  124404. '../Core/defineProperties',
  124405. '../Core/DeveloperError',
  124406. './PerspectiveOffCenterFrustum'
  124407. ], function(
  124408. defined,
  124409. defineProperties,
  124410. DeveloperError,
  124411. PerspectiveOffCenterFrustum) {
  124412. 'use strict';
  124413. /**
  124414. * The viewing frustum is defined by 6 planes.
  124415. * Each plane is represented by a {@link Cartesian4} object, where the x, y, and z components
  124416. * define the unit vector normal to the plane, and the w component is the distance of the
  124417. * plane from the origin/camera position.
  124418. *
  124419. * @alias PerspectiveFrustum
  124420. * @constructor
  124421. *
  124422. *
  124423. * @example
  124424. * var frustum = new Cesium.PerspectiveFrustum();
  124425. * frustum.aspectRatio = canvas.clientWidth / canvas.clientHeight;
  124426. * frustum.fov = Cesium.Math.PI_OVER_THREE;
  124427. * frustum.near = 1.0;
  124428. * frustum.far = 2.0;
  124429. *
  124430. * @see PerspectiveOffCenterFrustum
  124431. */
  124432. function PerspectiveFrustum() {
  124433. this._offCenterFrustum = new PerspectiveOffCenterFrustum();
  124434. /**
  124435. * The angle of the field of view (FOV), in radians. This angle will be used
  124436. * as the horizontal FOV if the width is greater than the height, otherwise
  124437. * it will be the vertical FOV.
  124438. * @type {Number}
  124439. * @default undefined
  124440. */
  124441. this.fov = undefined;
  124442. this._fov = undefined;
  124443. this._fovy = undefined;
  124444. this._sseDenominator = undefined;
  124445. /**
  124446. * The aspect ratio of the frustum's width to it's height.
  124447. * @type {Number}
  124448. * @default undefined
  124449. */
  124450. this.aspectRatio = undefined;
  124451. this._aspectRatio = undefined;
  124452. /**
  124453. * The distance of the near plane.
  124454. * @type {Number}
  124455. * @default 1.0
  124456. */
  124457. this.near = 1.0;
  124458. this._near = this.near;
  124459. /**
  124460. * The distance of the far plane.
  124461. * @type {Number}
  124462. * @default 500000000.0
  124463. */
  124464. this.far = 500000000.0;
  124465. this._far = this.far;
  124466. /**
  124467. * Offsets the frustum in the x direction.
  124468. * @type {Number}
  124469. * @default 0.0
  124470. */
  124471. this.xOffset = 0.0;
  124472. this._xOffset = this.xOffset;
  124473. /**
  124474. * Offsets the frustum in the y direction.
  124475. * @type {Number}
  124476. * @default 0.0
  124477. */
  124478. this.yOffset = 0.0;
  124479. this._yOffset = this.yOffset;
  124480. }
  124481. function update(frustum) {
  124482. if (!defined(frustum.fov) || !defined(frustum.aspectRatio) || !defined(frustum.near) || !defined(frustum.far)) {
  124483. throw new DeveloperError('fov, aspectRatio, near, or far parameters are not set.');
  124484. }
  124485. var f = frustum._offCenterFrustum;
  124486. if (frustum.fov !== frustum._fov || frustum.aspectRatio !== frustum._aspectRatio ||
  124487. frustum.near !== frustum._near || frustum.far !== frustum._far ||
  124488. frustum.xOffset !== frustum._xOffset || frustum.yOffset !== frustum._yOffset) {
  124489. if (frustum.fov < 0 || frustum.fov >= Math.PI) {
  124490. throw new DeveloperError('fov must be in the range [0, PI).');
  124491. }
  124492. if (frustum.aspectRatio < 0) {
  124493. throw new DeveloperError('aspectRatio must be positive.');
  124494. }
  124495. if (frustum.near < 0 || frustum.near > frustum.far) {
  124496. throw new DeveloperError('near must be greater than zero and less than far.');
  124497. }
  124498. frustum._aspectRatio = frustum.aspectRatio;
  124499. frustum._fov = frustum.fov;
  124500. frustum._fovy = (frustum.aspectRatio <= 1) ? frustum.fov : Math.atan(Math.tan(frustum.fov * 0.5) / frustum.aspectRatio) * 2.0;
  124501. frustum._near = frustum.near;
  124502. frustum._far = frustum.far;
  124503. frustum._sseDenominator = 2.0 * Math.tan(0.5 * frustum._fovy);
  124504. frustum._xOffset = frustum.xOffset;
  124505. frustum._yOffset = frustum.yOffset;
  124506. f.top = frustum.near * Math.tan(0.5 * frustum._fovy);
  124507. f.bottom = -f.top;
  124508. f.right = frustum.aspectRatio * f.top;
  124509. f.left = -f.right;
  124510. f.near = frustum.near;
  124511. f.far = frustum.far;
  124512. f.right += frustum.xOffset;
  124513. f.left += frustum.xOffset;
  124514. f.top += frustum.yOffset;
  124515. f.bottom += frustum.yOffset;
  124516. }
  124517. }
  124518. defineProperties(PerspectiveFrustum.prototype, {
  124519. /**
  124520. * Gets the perspective projection matrix computed from the view frustum.
  124521. * @memberof PerspectiveFrustum.prototype
  124522. * @type {Matrix4}
  124523. * @readonly
  124524. *
  124525. * @see PerspectiveFrustum#infiniteProjectionMatrix
  124526. */
  124527. projectionMatrix : {
  124528. get : function() {
  124529. update(this);
  124530. return this._offCenterFrustum.projectionMatrix;
  124531. }
  124532. },
  124533. /**
  124534. * The perspective projection matrix computed from the view frustum with an infinite far plane.
  124535. * @memberof PerspectiveFrustum.prototype
  124536. * @type {Matrix4}
  124537. * @readonly
  124538. *
  124539. * @see PerspectiveFrustum#projectionMatrix
  124540. */
  124541. infiniteProjectionMatrix : {
  124542. get : function() {
  124543. update(this);
  124544. return this._offCenterFrustum.infiniteProjectionMatrix;
  124545. }
  124546. },
  124547. /**
  124548. * Gets the angle of the vertical field of view, in radians.
  124549. * @memberof PerspectiveFrustum.prototype
  124550. * @type {Number}
  124551. * @readonly
  124552. * @default undefined
  124553. */
  124554. fovy : {
  124555. get : function() {
  124556. update(this);
  124557. return this._fovy;
  124558. }
  124559. },
  124560. /**
  124561. * @readonly
  124562. * @private
  124563. */
  124564. sseDenominator : {
  124565. get : function () {
  124566. update(this);
  124567. return this._sseDenominator;
  124568. }
  124569. }
  124570. });
  124571. /**
  124572. * Creates a culling volume for this frustum.
  124573. *
  124574. * @param {Cartesian3} position The eye position.
  124575. * @param {Cartesian3} direction The view direction.
  124576. * @param {Cartesian3} up The up direction.
  124577. * @returns {CullingVolume} A culling volume at the given position and orientation.
  124578. *
  124579. * @example
  124580. * // Check if a bounding volume intersects the frustum.
  124581. * var cullingVolume = frustum.computeCullingVolume(cameraPosition, cameraDirection, cameraUp);
  124582. * var intersect = cullingVolume.computeVisibility(boundingVolume);
  124583. */
  124584. PerspectiveFrustum.prototype.computeCullingVolume = function(position, direction, up) {
  124585. update(this);
  124586. return this._offCenterFrustum.computeCullingVolume(position, direction, up);
  124587. };
  124588. /**
  124589. * Returns the pixel's width and height in meters.
  124590. *
  124591. * @param {Number} drawingBufferWidth The width of the drawing buffer.
  124592. * @param {Number} drawingBufferHeight The height of the drawing buffer.
  124593. * @param {Number} distance The distance to the near plane in meters.
  124594. * @param {Cartesian2} result The object onto which to store the result.
  124595. * @returns {Cartesian2} The modified result parameter or a new instance of {@link Cartesian2} with the pixel's width and height in the x and y properties, respectively.
  124596. *
  124597. * @exception {DeveloperError} drawingBufferWidth must be greater than zero.
  124598. * @exception {DeveloperError} drawingBufferHeight must be greater than zero.
  124599. *
  124600. * @example
  124601. * // Example 1
  124602. * // Get the width and height of a pixel.
  124603. * var pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, 1.0, new Cesium.Cartesian2());
  124604. *
  124605. * @example
  124606. * // Example 2
  124607. * // Get the width and height of a pixel if the near plane was set to 'distance'.
  124608. * // For example, get the size of a pixel of an image on a billboard.
  124609. * var position = camera.position;
  124610. * var direction = camera.direction;
  124611. * var toCenter = Cesium.Cartesian3.subtract(primitive.boundingVolume.center, position, new Cesium.Cartesian3()); // vector from camera to a primitive
  124612. * var toCenterProj = Cesium.Cartesian3.multiplyByScalar(direction, Cesium.Cartesian3.dot(direction, toCenter), new Cesium.Cartesian3()); // project vector onto camera direction vector
  124613. * var distance = Cesium.Cartesian3.magnitude(toCenterProj);
  124614. * var pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, distance, new Cesium.Cartesian2());
  124615. */
  124616. PerspectiveFrustum.prototype.getPixelDimensions = function(drawingBufferWidth, drawingBufferHeight, distance, result) {
  124617. update(this);
  124618. return this._offCenterFrustum.getPixelDimensions(drawingBufferWidth, drawingBufferHeight, distance, result);
  124619. };
  124620. /**
  124621. * Returns a duplicate of a PerspectiveFrustum instance.
  124622. *
  124623. * @param {PerspectiveFrustum} [result] The object onto which to store the result.
  124624. * @returns {PerspectiveFrustum} The modified result parameter or a new PerspectiveFrustum instance if one was not provided.
  124625. */
  124626. PerspectiveFrustum.prototype.clone = function(result) {
  124627. if (!defined(result)) {
  124628. result = new PerspectiveFrustum();
  124629. }
  124630. result.aspectRatio = this.aspectRatio;
  124631. result.fov = this.fov;
  124632. result.near = this.near;
  124633. result.far = this.far;
  124634. // force update of clone to compute matrices
  124635. result._aspectRatio = undefined;
  124636. result._fov = undefined;
  124637. result._near = undefined;
  124638. result._far = undefined;
  124639. this._offCenterFrustum.clone(result._offCenterFrustum);
  124640. return result;
  124641. };
  124642. /**
  124643. * Compares the provided PerspectiveFrustum componentwise and returns
  124644. * <code>true</code> if they are equal, <code>false</code> otherwise.
  124645. *
  124646. * @param {PerspectiveFrustum} [other] The right hand side PerspectiveFrustum.
  124647. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  124648. */
  124649. PerspectiveFrustum.prototype.equals = function(other) {
  124650. if (!defined(other)) {
  124651. return false;
  124652. }
  124653. update(this);
  124654. update(other);
  124655. return (this.fov === other.fov &&
  124656. this.aspectRatio === other.aspectRatio &&
  124657. this.near === other.near &&
  124658. this.far === other.far &&
  124659. this._offCenterFrustum.equals(other._offCenterFrustum));
  124660. };
  124661. return PerspectiveFrustum;
  124662. });
  124663. /*global define*/
  124664. define('Scene/CameraFlightPath',[
  124665. '../Core/Cartesian2',
  124666. '../Core/Cartesian3',
  124667. '../Core/Cartographic',
  124668. '../Core/defaultValue',
  124669. '../Core/defined',
  124670. '../Core/DeveloperError',
  124671. '../Core/EasingFunction',
  124672. '../Core/Math',
  124673. './PerspectiveFrustum',
  124674. './PerspectiveOffCenterFrustum',
  124675. './SceneMode'
  124676. ], function(
  124677. Cartesian2,
  124678. Cartesian3,
  124679. Cartographic,
  124680. defaultValue,
  124681. defined,
  124682. DeveloperError,
  124683. EasingFunction,
  124684. CesiumMath,
  124685. PerspectiveFrustum,
  124686. PerspectiveOffCenterFrustum,
  124687. SceneMode) {
  124688. 'use strict';
  124689. /**
  124690. * Creates tweens for camera flights.
  124691. * <br /><br />
  124692. * Mouse interaction is disabled during flights.
  124693. *
  124694. * @private
  124695. */
  124696. var CameraFlightPath = {
  124697. };
  124698. function getAltitude(frustum, dx, dy) {
  124699. var near;
  124700. var top;
  124701. var right;
  124702. if (frustum instanceof PerspectiveFrustum) {
  124703. var tanTheta = Math.tan(0.5 * frustum.fovy);
  124704. near = frustum.near;
  124705. top = frustum.near * tanTheta;
  124706. right = frustum.aspectRatio * top;
  124707. return Math.max(dx * near / right, dy * near / top);
  124708. } else if (frustum instanceof PerspectiveOffCenterFrustum) {
  124709. near = frustum.near;
  124710. top = frustum.top;
  124711. right = frustum.right;
  124712. return Math.max(dx * near / right, dy * near / top);
  124713. }
  124714. return Math.max(dx, dy);
  124715. }
  124716. var scratchCart = new Cartesian3();
  124717. var scratchCart2 = new Cartesian3();
  124718. function createHeightFunction(camera, destination, startHeight, endHeight, optionAltitude) {
  124719. var altitude = optionAltitude;
  124720. var maxHeight = Math.max(startHeight, endHeight);
  124721. if (!defined(altitude)) {
  124722. var start = camera.position;
  124723. var end = destination;
  124724. var up = camera.up;
  124725. var right = camera.right;
  124726. var frustum = camera.frustum;
  124727. var diff = Cartesian3.subtract(start, end, scratchCart);
  124728. var verticalDistance = Cartesian3.magnitude(Cartesian3.multiplyByScalar(up, Cartesian3.dot(diff, up), scratchCart2));
  124729. var horizontalDistance = Cartesian3.magnitude(Cartesian3.multiplyByScalar(right, Cartesian3.dot(diff, right), scratchCart2));
  124730. altitude = Math.min(getAltitude(frustum, verticalDistance, horizontalDistance) * 0.20, 1000000000.0);
  124731. }
  124732. if (maxHeight < altitude) {
  124733. var power = 8.0;
  124734. var factor = 1000000.0;
  124735. var s = -Math.pow((altitude - startHeight) * factor, 1.0 / power);
  124736. var e = Math.pow((altitude - endHeight) * factor, 1.0 / power);
  124737. return function(t) {
  124738. var x = t * (e - s) + s;
  124739. return -Math.pow(x, power) / factor + altitude;
  124740. };
  124741. }
  124742. return function(t) {
  124743. return CesiumMath.lerp(startHeight, endHeight, t);
  124744. };
  124745. }
  124746. function adjustAngleForLERP(startAngle, endAngle) {
  124747. if (CesiumMath.equalsEpsilon(startAngle, CesiumMath.TWO_PI, CesiumMath.EPSILON11)) {
  124748. startAngle = 0.0;
  124749. }
  124750. if (endAngle > startAngle + Math.PI) {
  124751. startAngle += CesiumMath.TWO_PI;
  124752. } else if (endAngle < startAngle - Math.PI) {
  124753. startAngle -= CesiumMath.TWO_PI;
  124754. }
  124755. return startAngle;
  124756. }
  124757. var scratchStart = new Cartesian3();
  124758. function createUpdateCV(scene, duration, destination, heading, pitch, roll, optionAltitude) {
  124759. var camera = scene.camera;
  124760. var start = Cartesian3.clone(camera.position, scratchStart);
  124761. var startPitch = camera.pitch;
  124762. var startHeading = adjustAngleForLERP(camera.heading, heading);
  124763. var startRoll = adjustAngleForLERP(camera.roll, roll);
  124764. var heightFunction = createHeightFunction(camera, destination, start.z, destination.z, optionAltitude);
  124765. function update(value) {
  124766. var time = value.time / duration;
  124767. camera.setView({
  124768. orientation: {
  124769. heading : CesiumMath.lerp(startHeading, heading, time),
  124770. pitch : CesiumMath.lerp(startPitch, pitch, time),
  124771. roll : CesiumMath.lerp(startRoll, roll, time)
  124772. }
  124773. });
  124774. Cartesian2.lerp(start, destination, time, camera.position);
  124775. camera.position.z = heightFunction(time);
  124776. }
  124777. return update;
  124778. }
  124779. var scratchStartCart = new Cartographic();
  124780. var scratchEndCart = new Cartographic();
  124781. function createUpdate3D(scene, duration, destination, heading, pitch, roll, optionAltitude) {
  124782. var camera = scene.camera;
  124783. var projection = scene.mapProjection;
  124784. var ellipsoid = projection.ellipsoid;
  124785. var startCart = Cartographic.clone(camera.positionCartographic, scratchStartCart);
  124786. var startPitch = camera.pitch;
  124787. var startHeading = adjustAngleForLERP(camera.heading, heading);
  124788. var startRoll = adjustAngleForLERP(camera.roll, roll);
  124789. var destCart = ellipsoid.cartesianToCartographic(destination, scratchEndCart);
  124790. startCart.longitude = CesiumMath.zeroToTwoPi(startCart.longitude);
  124791. destCart.longitude = CesiumMath.zeroToTwoPi(destCart.longitude);
  124792. var diff = startCart.longitude - destCart.longitude;
  124793. if (diff < -CesiumMath.PI) {
  124794. startCart.longitude += CesiumMath.TWO_PI;
  124795. } else if (diff > CesiumMath.PI) {
  124796. destCart.longitude += CesiumMath.TWO_PI;
  124797. }
  124798. var heightFunction = createHeightFunction(camera, destination, startCart.height, destCart.height, optionAltitude);
  124799. function update(value) {
  124800. var time = value.time / duration;
  124801. var position = Cartesian3.fromRadians(
  124802. CesiumMath.lerp(startCart.longitude, destCart.longitude, time),
  124803. CesiumMath.lerp(startCart.latitude, destCart.latitude, time),
  124804. heightFunction(time)
  124805. );
  124806. camera.setView({
  124807. destination : position,
  124808. orientation: {
  124809. heading : CesiumMath.lerp(startHeading, heading, time),
  124810. pitch : CesiumMath.lerp(startPitch, pitch, time),
  124811. roll : CesiumMath.lerp(startRoll, roll, time)
  124812. }
  124813. });
  124814. }
  124815. return update;
  124816. }
  124817. function createUpdate2D(scene, duration, destination, heading, pitch, roll, optionAltitude) {
  124818. var camera = scene.camera;
  124819. var start = Cartesian3.clone(camera.position, scratchStart);
  124820. var startHeading = adjustAngleForLERP(camera.heading, heading);
  124821. var startHeight = camera.frustum.right - camera.frustum.left;
  124822. var heightFunction = createHeightFunction(camera, destination, startHeight, destination.z, optionAltitude);
  124823. function update(value) {
  124824. var time = value.time / duration;
  124825. camera.setView({
  124826. orientation: {
  124827. heading : CesiumMath.lerp(startHeading, heading, time)
  124828. }
  124829. });
  124830. Cartesian2.lerp(start, destination, time, camera.position);
  124831. var zoom = heightFunction(time);
  124832. var frustum = camera.frustum;
  124833. var ratio = frustum.top / frustum.right;
  124834. var incrementAmount = (zoom - (frustum.right - frustum.left)) * 0.5;
  124835. frustum.right += incrementAmount;
  124836. frustum.left -= incrementAmount;
  124837. frustum.top = ratio * frustum.right;
  124838. frustum.bottom = -frustum.top;
  124839. }
  124840. return update;
  124841. }
  124842. var scratchCartographic = new Cartographic();
  124843. var scratchDestination = new Cartesian3();
  124844. function emptyFlight(complete, cancel) {
  124845. return {
  124846. startObject : {},
  124847. stopObject : {},
  124848. duration : 0.0,
  124849. complete : complete,
  124850. cancel : cancel
  124851. };
  124852. }
  124853. function wrapCallback(controller, cb) {
  124854. function wrapped() {
  124855. if (typeof cb === 'function') {
  124856. cb();
  124857. }
  124858. controller.enableInputs = true;
  124859. }
  124860. return wrapped;
  124861. }
  124862. CameraFlightPath.createTween = function(scene, options) {
  124863. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  124864. var destination = options.destination;
  124865. if (!defined(scene)) {
  124866. throw new DeveloperError('scene is required.');
  124867. }
  124868. if (!defined(destination)) {
  124869. throw new DeveloperError('destination is required.');
  124870. }
  124871. var mode = scene.mode;
  124872. if (mode === SceneMode.MORPHING) {
  124873. return emptyFlight();
  124874. }
  124875. var convert = defaultValue(options.convert, true);
  124876. var projection = scene.mapProjection;
  124877. var ellipsoid = projection.ellipsoid;
  124878. var maximumHeight = options.maximumHeight;
  124879. var easingFunction = options.easingFunction;
  124880. if (convert && mode !== SceneMode.SCENE3D) {
  124881. ellipsoid.cartesianToCartographic(destination, scratchCartographic);
  124882. destination = projection.project(scratchCartographic, scratchDestination);
  124883. }
  124884. var camera = scene.camera;
  124885. var transform = options.endTransform;
  124886. if (defined(transform)) {
  124887. camera._setTransform(transform);
  124888. }
  124889. var duration = options.duration;
  124890. if (!defined(duration)) {
  124891. duration = Math.ceil(Cartesian3.distance(camera.position, destination) / 1000000.0) + 2.0;
  124892. duration = Math.min(duration, 3.0);
  124893. }
  124894. var heading = defaultValue(options.heading, 0.0);
  124895. var pitch = defaultValue(options.pitch, -CesiumMath.PI_OVER_TWO);
  124896. var roll = defaultValue(options.roll, 0.0);
  124897. var controller = scene.screenSpaceCameraController;
  124898. controller.enableInputs = false;
  124899. var complete = wrapCallback(controller, options.complete);
  124900. var cancel = wrapCallback(controller, options.cancel);
  124901. var frustum = camera.frustum;
  124902. var empty = scene.mode === SceneMode.SCENE2D;
  124903. empty = empty && Cartesian2.equalsEpsilon(camera.position, destination, CesiumMath.EPSILON6);
  124904. empty = empty && CesiumMath.equalsEpsilon(Math.max(frustum.right - frustum.left, frustum.top - frustum.bottom), destination.z, CesiumMath.EPSILON6);
  124905. empty = empty || (scene.mode !== SceneMode.SCENE2D &&
  124906. Cartesian3.equalsEpsilon(destination, camera.position, CesiumMath.EPSILON10));
  124907. empty = empty &&
  124908. CesiumMath.equalsEpsilon(CesiumMath.negativePiToPi(heading), CesiumMath.negativePiToPi(camera.heading), CesiumMath.EPSILON10) &&
  124909. CesiumMath.equalsEpsilon(CesiumMath.negativePiToPi(pitch), CesiumMath.negativePiToPi(camera.pitch), CesiumMath.EPSILON10) &&
  124910. CesiumMath.equalsEpsilon(CesiumMath.negativePiToPi(roll), CesiumMath.negativePiToPi(camera.roll), CesiumMath.EPSILON10);
  124911. if (empty) {
  124912. return emptyFlight(complete, cancel);
  124913. }
  124914. var updateFunctions = new Array(4);
  124915. updateFunctions[SceneMode.SCENE2D] = createUpdate2D;
  124916. updateFunctions[SceneMode.SCENE3D] = createUpdate3D;
  124917. updateFunctions[SceneMode.COLUMBUS_VIEW] = createUpdateCV;
  124918. if (duration <= 0.0) {
  124919. var newOnComplete = function() {
  124920. var update = updateFunctions[mode](scene, 1.0, destination, heading, pitch, roll, maximumHeight);
  124921. update({ time: 1.0 });
  124922. if (typeof complete === 'function') {
  124923. complete();
  124924. }
  124925. };
  124926. return emptyFlight(newOnComplete, cancel);
  124927. }
  124928. var update = updateFunctions[mode](scene, duration, destination, heading, pitch, roll, maximumHeight);
  124929. if (!defined(easingFunction)) {
  124930. var startHeight = camera.positionCartographic.height;
  124931. var endHeight = mode === SceneMode.SCENE3D ? ellipsoid.cartesianToCartographic(destination).height : destination.z;
  124932. if (startHeight > endHeight && startHeight > 11500.0) {
  124933. easingFunction = EasingFunction.CUBIC_OUT;
  124934. } else {
  124935. easingFunction = EasingFunction.QUINTIC_IN_OUT;
  124936. }
  124937. }
  124938. return {
  124939. duration : duration,
  124940. easingFunction : easingFunction,
  124941. startObject : {
  124942. time : 0.0
  124943. },
  124944. stopObject : {
  124945. time : duration
  124946. },
  124947. update : update,
  124948. complete : complete,
  124949. cancel: cancel
  124950. };
  124951. };
  124952. return CameraFlightPath;
  124953. });
  124954. /*global define*/
  124955. define('Scene/MapMode2D',[
  124956. '../Core/freezeObject'
  124957. ], function(
  124958. freezeObject) {
  124959. 'use strict';
  124960. /**
  124961. * Describes how the map will operate in 2D.
  124962. *
  124963. * @exports MapMode2D
  124964. */
  124965. var MapMode2D = {
  124966. /**
  124967. * The 2D map can be rotated about the z axis.
  124968. *
  124969. * @type {Number}
  124970. * @constant
  124971. */
  124972. ROTATE : 0,
  124973. /**
  124974. * The 2D map can be scrolled infinitely in the horizontal direction.
  124975. *
  124976. * @type {Number}
  124977. * @constant
  124978. */
  124979. INFINITE_SCROLL : 1
  124980. };
  124981. return freezeObject(MapMode2D);
  124982. });
  124983. /*global define*/
  124984. define('Scene/Camera',[
  124985. '../Core/BoundingSphere',
  124986. '../Core/Cartesian2',
  124987. '../Core/Cartesian3',
  124988. '../Core/Cartesian4',
  124989. '../Core/Cartographic',
  124990. '../Core/defaultValue',
  124991. '../Core/defined',
  124992. '../Core/defineProperties',
  124993. '../Core/DeveloperError',
  124994. '../Core/EasingFunction',
  124995. '../Core/Ellipsoid',
  124996. '../Core/EllipsoidGeodesic',
  124997. '../Core/Event',
  124998. '../Core/HeadingPitchRange',
  124999. '../Core/Intersect',
  125000. '../Core/IntersectionTests',
  125001. '../Core/Math',
  125002. '../Core/Matrix3',
  125003. '../Core/Matrix4',
  125004. '../Core/Quaternion',
  125005. '../Core/Ray',
  125006. '../Core/Rectangle',
  125007. '../Core/Transforms',
  125008. './CameraFlightPath',
  125009. './MapMode2D',
  125010. './PerspectiveFrustum',
  125011. './SceneMode'
  125012. ], function(
  125013. BoundingSphere,
  125014. Cartesian2,
  125015. Cartesian3,
  125016. Cartesian4,
  125017. Cartographic,
  125018. defaultValue,
  125019. defined,
  125020. defineProperties,
  125021. DeveloperError,
  125022. EasingFunction,
  125023. Ellipsoid,
  125024. EllipsoidGeodesic,
  125025. Event,
  125026. HeadingPitchRange,
  125027. Intersect,
  125028. IntersectionTests,
  125029. CesiumMath,
  125030. Matrix3,
  125031. Matrix4,
  125032. Quaternion,
  125033. Ray,
  125034. Rectangle,
  125035. Transforms,
  125036. CameraFlightPath,
  125037. MapMode2D,
  125038. PerspectiveFrustum,
  125039. SceneMode) {
  125040. 'use strict';
  125041. /**
  125042. * The camera is defined by a position, orientation, and view frustum.
  125043. * <br /><br />
  125044. * The orientation forms an orthonormal basis with a view, up and right = view x up unit vectors.
  125045. * <br /><br />
  125046. * The viewing frustum is defined by 6 planes.
  125047. * Each plane is represented by a {@link Cartesian4} object, where the x, y, and z components
  125048. * define the unit vector normal to the plane, and the w component is the distance of the
  125049. * plane from the origin/camera position.
  125050. *
  125051. * @alias Camera
  125052. *
  125053. * @constructor
  125054. *
  125055. * @param {Scene} scene The scene.
  125056. *
  125057. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Camera.html|Cesium Sandcastle Camera Demo}
  125058. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Camera%20Tutorial.html">Sandcastle Example</a> from the <a href="http://cesiumjs.org/2013/02/13/Cesium-Camera-Tutorial/|Camera Tutorial}
  125059. *
  125060. * @example
  125061. * // Create a camera looking down the negative z-axis, positioned at the origin,
  125062. * // with a field of view of 60 degrees, and 1:1 aspect ratio.
  125063. * var camera = new Cesium.Camera(scene);
  125064. * camera.position = new Cesium.Cartesian3();
  125065. * camera.direction = Cesium.Cartesian3.negate(Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3());
  125066. * camera.up = Cesium.Cartesian3.clone(Cesium.Cartesian3.UNIT_Y);
  125067. * camera.frustum.fov = Cesium.Math.PI_OVER_THREE;
  125068. * camera.frustum.near = 1.0;
  125069. * camera.frustum.far = 2.0;
  125070. */
  125071. function Camera(scene) {
  125072. if (!defined(scene)) {
  125073. throw new DeveloperError('scene is required.');
  125074. }
  125075. this._scene = scene;
  125076. this._transform = Matrix4.clone(Matrix4.IDENTITY);
  125077. this._invTransform = Matrix4.clone(Matrix4.IDENTITY);
  125078. this._actualTransform = Matrix4.clone(Matrix4.IDENTITY);
  125079. this._actualInvTransform = Matrix4.clone(Matrix4.IDENTITY);
  125080. this._transformChanged = false;
  125081. /**
  125082. * The position of the camera.
  125083. *
  125084. * @type {Cartesian3}
  125085. */
  125086. this.position = new Cartesian3();
  125087. this._position = new Cartesian3();
  125088. this._positionWC = new Cartesian3();
  125089. this._positionCartographic = new Cartographic();
  125090. /**
  125091. * The view direction of the camera.
  125092. *
  125093. * @type {Cartesian3}
  125094. */
  125095. this.direction = new Cartesian3();
  125096. this._direction = new Cartesian3();
  125097. this._directionWC = new Cartesian3();
  125098. /**
  125099. * The up direction of the camera.
  125100. *
  125101. * @type {Cartesian3}
  125102. */
  125103. this.up = new Cartesian3();
  125104. this._up = new Cartesian3();
  125105. this._upWC = new Cartesian3();
  125106. /**
  125107. * The right direction of the camera.
  125108. *
  125109. * @type {Cartesian3}
  125110. */
  125111. this.right = new Cartesian3();
  125112. this._right = new Cartesian3();
  125113. this._rightWC = new Cartesian3();
  125114. /**
  125115. * The region of space in view.
  125116. *
  125117. * @type {Frustum}
  125118. * @default PerspectiveFrustum()
  125119. *
  125120. * @see PerspectiveFrustum
  125121. * @see PerspectiveOffCenterFrustum
  125122. * @see OrthographicFrustum
  125123. */
  125124. this.frustum = new PerspectiveFrustum();
  125125. this.frustum.aspectRatio = scene.drawingBufferWidth / scene.drawingBufferHeight;
  125126. this.frustum.fov = CesiumMath.toRadians(60.0);
  125127. /**
  125128. * The default amount to move the camera when an argument is not
  125129. * provided to the move methods.
  125130. * @type {Number}
  125131. * @default 100000.0;
  125132. */
  125133. this.defaultMoveAmount = 100000.0;
  125134. /**
  125135. * The default amount to rotate the camera when an argument is not
  125136. * provided to the look methods.
  125137. * @type {Number}
  125138. * @default Math.PI / 60.0
  125139. */
  125140. this.defaultLookAmount = Math.PI / 60.0;
  125141. /**
  125142. * The default amount to rotate the camera when an argument is not
  125143. * provided to the rotate methods.
  125144. * @type {Number}
  125145. * @default Math.PI / 3600.0
  125146. */
  125147. this.defaultRotateAmount = Math.PI / 3600.0;
  125148. /**
  125149. * The default amount to move the camera when an argument is not
  125150. * provided to the zoom methods.
  125151. * @type {Number}
  125152. * @default 100000.0;
  125153. */
  125154. this.defaultZoomAmount = 100000.0;
  125155. /**
  125156. * If set, the camera will not be able to rotate past this axis in either direction.
  125157. * @type {Cartesian3}
  125158. * @default undefined
  125159. */
  125160. this.constrainedAxis = undefined;
  125161. /**
  125162. * The factor multiplied by the the map size used to determine where to clamp the camera position
  125163. * when zooming out from the surface. The default is 1.5. Only valid for 2D and the map is rotatable.
  125164. * @type {Number}
  125165. * @default 1.5
  125166. */
  125167. this.maximumZoomFactor = 1.5;
  125168. this._moveStart = new Event();
  125169. this._moveEnd = new Event();
  125170. this._changed = new Event();
  125171. this._changedPosition = undefined;
  125172. this._changedDirection = undefined;
  125173. this._changedFrustum = undefined;
  125174. /**
  125175. * The amount the camera has to change before the <code>changed</code> event is raised. The value is a percentage in the [0, 1] range.
  125176. * @type {number}
  125177. * @default 0.5
  125178. */
  125179. this.percentageChanged = 0.5;
  125180. this._viewMatrix = new Matrix4();
  125181. this._invViewMatrix = new Matrix4();
  125182. updateViewMatrix(this);
  125183. this._mode = SceneMode.SCENE3D;
  125184. this._modeChanged = true;
  125185. var projection = scene.mapProjection;
  125186. this._projection = projection;
  125187. this._maxCoord = projection.project(new Cartographic(Math.PI, CesiumMath.PI_OVER_TWO));
  125188. this._max2Dfrustum = undefined;
  125189. this._suspendTerrainAdjustment = false;
  125190. // set default view
  125191. rectangleCameraPosition3D(this, Camera.DEFAULT_VIEW_RECTANGLE, this.position, true);
  125192. var mag = Cartesian3.magnitude(this.position);
  125193. mag += mag * Camera.DEFAULT_VIEW_FACTOR;
  125194. Cartesian3.normalize(this.position, this.position);
  125195. Cartesian3.multiplyByScalar(this.position, mag, this.position);
  125196. }
  125197. /**
  125198. * @private
  125199. */
  125200. Camera.TRANSFORM_2D = new Matrix4(
  125201. 0.0, 0.0, 1.0, 0.0,
  125202. 1.0, 0.0, 0.0, 0.0,
  125203. 0.0, 1.0, 0.0, 0.0,
  125204. 0.0, 0.0, 0.0, 1.0);
  125205. /**
  125206. * @private
  125207. */
  125208. Camera.TRANSFORM_2D_INVERSE = Matrix4.inverseTransformation(Camera.TRANSFORM_2D, new Matrix4());
  125209. /**
  125210. * The default rectangle the camera will view on creation.
  125211. * @type Rectangle
  125212. */
  125213. Camera.DEFAULT_VIEW_RECTANGLE = Rectangle.fromDegrees(-95.0, -20.0, -70.0, 90.0);
  125214. /**
  125215. * A scalar to multiply to the camera position and add it back after setting the camera to view the rectangle.
  125216. * A value of zero means the camera will view the entire {@link Camera#DEFAULT_VIEW_RECTANGLE}, a value greater than zero
  125217. * will move it further away from the extent, and a value less than zero will move it close to the extent.
  125218. * @type Number
  125219. */
  125220. Camera.DEFAULT_VIEW_FACTOR = 0.5;
  125221. function updateViewMatrix(camera) {
  125222. Matrix4.computeView(camera._position, camera._direction, camera._up, camera._right, camera._viewMatrix);
  125223. Matrix4.multiply(camera._viewMatrix, camera._actualInvTransform, camera._viewMatrix);
  125224. Matrix4.inverseTransformation(camera._viewMatrix, camera._invViewMatrix);
  125225. }
  125226. Camera.prototype._updateCameraChanged = function() {
  125227. var camera = this;
  125228. if (camera._changed.numberOfListeners === 0) {
  125229. return;
  125230. }
  125231. var percentageChanged = camera.percentageChanged;
  125232. if (camera._mode === SceneMode.SCENE2D) {
  125233. if (!defined(camera._changedFrustum)) {
  125234. camera._changedPosition = Cartesian3.clone(camera.position, camera._changedPosition);
  125235. camera._changedFrustum = camera.frustum.clone();
  125236. return;
  125237. }
  125238. var position = camera.position;
  125239. var lastPosition = camera._changedPosition;
  125240. var frustum = camera.frustum;
  125241. var lastFrustum = camera._changedFrustum;
  125242. var x0 = position.x + frustum.left;
  125243. var x1 = position.x + frustum.right;
  125244. var x2 = lastPosition.x + lastFrustum.left;
  125245. var x3 = lastPosition.x + lastFrustum.right;
  125246. var y0 = position.y + frustum.bottom;
  125247. var y1 = position.y + frustum.top;
  125248. var y2 = lastPosition.y + lastFrustum.bottom;
  125249. var y3 = lastPosition.y + lastFrustum.top;
  125250. var leftX = Math.max(x0, x2);
  125251. var rightX = Math.min(x1, x3);
  125252. var bottomY = Math.max(y0, y2);
  125253. var topY = Math.min(y1, y3);
  125254. var areaPercentage;
  125255. if (leftX >= rightX || bottomY >= y1) {
  125256. areaPercentage = 1.0;
  125257. } else {
  125258. var areaRef = lastFrustum;
  125259. if (x0 < x2 && x1 > x3 && y0 < y2 && y1 > y3) {
  125260. areaRef = frustum;
  125261. }
  125262. areaPercentage = 1.0 - ((rightX - leftX) * (topY - bottomY)) / ((areaRef.right - areaRef.left) * (areaRef.top - areaRef.bottom));
  125263. }
  125264. if (areaPercentage > percentageChanged) {
  125265. camera._changed.raiseEvent(areaPercentage);
  125266. camera._changedPosition = Cartesian3.clone(camera.position, camera._changedPosition);
  125267. camera._changedFrustum = camera.frustum.clone(camera._changedFrustum);
  125268. }
  125269. return;
  125270. }
  125271. if (!defined(camera._changedDirection)) {
  125272. camera._changedPosition = Cartesian3.clone(camera.positionWC, camera._changedPosition);
  125273. camera._changedDirection = Cartesian3.clone(camera.directionWC, camera._changedDirection);
  125274. return;
  125275. }
  125276. var dirAngle = CesiumMath.acosClamped(Cartesian3.dot(camera.directionWC, camera._changedDirection));
  125277. var dirPercentage = dirAngle / (camera.frustum.fovy * 0.5);
  125278. var distance = Cartesian3.distance(camera.positionWC, camera._changedPosition);
  125279. var heightPercentage = distance / camera.positionCartographic.height;
  125280. if (dirPercentage > percentageChanged || heightPercentage > percentageChanged) {
  125281. camera._changed.raiseEvent(Math.max(dirPercentage, heightPercentage));
  125282. camera._changedPosition = Cartesian3.clone(camera.positionWC, camera._changedPosition);
  125283. camera._changedDirection = Cartesian3.clone(camera.directionWC, camera._changedDirection);
  125284. }
  125285. };
  125286. var scratchAdjustHeightTransform = new Matrix4();
  125287. var scratchAdjustHeightCartographic = new Cartographic();
  125288. Camera.prototype._adjustHeightForTerrain = function() {
  125289. var scene = this._scene;
  125290. var screenSpaceCameraController = scene.screenSpaceCameraController;
  125291. var enableCollisionDetection = screenSpaceCameraController.enableCollisionDetection;
  125292. var minimumCollisionTerrainHeight = screenSpaceCameraController.minimumCollisionTerrainHeight;
  125293. var minimumZoomDistance = screenSpaceCameraController.minimumZoomDistance;
  125294. if (this._suspendTerrainAdjustment || !enableCollisionDetection) {
  125295. return;
  125296. }
  125297. var mode = this._mode;
  125298. var globe = scene.globe;
  125299. if (!defined(globe) || mode === SceneMode.SCENE2D || mode === SceneMode.MORPHING) {
  125300. return;
  125301. }
  125302. var ellipsoid = globe.ellipsoid;
  125303. var projection = scene.mapProjection;
  125304. var transform;
  125305. var mag;
  125306. if (!Matrix4.equals(this.transform, Matrix4.IDENTITY)) {
  125307. transform = Matrix4.clone(this.transform, scratchAdjustHeightTransform);
  125308. mag = Cartesian3.magnitude(this.position);
  125309. this._setTransform(Matrix4.IDENTITY);
  125310. }
  125311. var cartographic = scratchAdjustHeightCartographic;
  125312. if (mode === SceneMode.SCENE3D) {
  125313. ellipsoid.cartesianToCartographic(this.position, cartographic);
  125314. } else {
  125315. projection.unproject(this.position, cartographic);
  125316. }
  125317. var heightUpdated = false;
  125318. if (cartographic.height < minimumCollisionTerrainHeight) {
  125319. var height = globe.getHeight(cartographic);
  125320. if (defined(height)) {
  125321. height += minimumZoomDistance;
  125322. if (cartographic.height < height) {
  125323. cartographic.height = height;
  125324. if (mode === SceneMode.SCENE3D) {
  125325. ellipsoid.cartographicToCartesian(cartographic, this.position);
  125326. } else {
  125327. projection.project(cartographic, this.position);
  125328. }
  125329. heightUpdated = true;
  125330. }
  125331. }
  125332. }
  125333. if (defined(transform)) {
  125334. this._setTransform(transform);
  125335. if (heightUpdated) {
  125336. Cartesian3.normalize(this.position, this.position);
  125337. Cartesian3.negate(this.position, this.direction);
  125338. Cartesian3.multiplyByScalar(this.position, Math.max(mag, minimumZoomDistance), this.position);
  125339. Cartesian3.normalize(this.direction, this.direction);
  125340. Cartesian3.cross(this.direction, this.up, this.right);
  125341. Cartesian3.cross(this.right, this.direction, this.up);
  125342. }
  125343. }
  125344. };
  125345. function convertTransformForColumbusView(camera) {
  125346. Transforms.basisTo2D(camera._projection, camera._transform, camera._actualTransform);
  125347. }
  125348. var scratchCartographic = new Cartographic();
  125349. var scratchCartesian3Projection = new Cartesian3();
  125350. var scratchCartesian3 = new Cartesian3();
  125351. var scratchCartesian4Origin = new Cartesian4();
  125352. var scratchCartesian4NewOrigin = new Cartesian4();
  125353. var scratchCartesian4NewXAxis = new Cartesian4();
  125354. var scratchCartesian4NewYAxis = new Cartesian4();
  125355. var scratchCartesian4NewZAxis = new Cartesian4();
  125356. function convertTransformFor2D(camera) {
  125357. var projection = camera._projection;
  125358. var ellipsoid = projection.ellipsoid;
  125359. var origin = Matrix4.getColumn(camera._transform, 3, scratchCartesian4Origin);
  125360. var cartographic = ellipsoid.cartesianToCartographic(origin, scratchCartographic);
  125361. var projectedPosition = projection.project(cartographic, scratchCartesian3Projection);
  125362. var newOrigin = scratchCartesian4NewOrigin;
  125363. newOrigin.x = projectedPosition.z;
  125364. newOrigin.y = projectedPosition.x;
  125365. newOrigin.z = projectedPosition.y;
  125366. newOrigin.w = 1.0;
  125367. var newZAxis = Cartesian4.clone(Cartesian4.UNIT_X, scratchCartesian4NewZAxis);
  125368. var xAxis = Cartesian4.add(Matrix4.getColumn(camera._transform, 0, scratchCartesian3), origin, scratchCartesian3);
  125369. ellipsoid.cartesianToCartographic(xAxis, cartographic);
  125370. projection.project(cartographic, projectedPosition);
  125371. var newXAxis = scratchCartesian4NewXAxis;
  125372. newXAxis.x = projectedPosition.z;
  125373. newXAxis.y = projectedPosition.x;
  125374. newXAxis.z = projectedPosition.y;
  125375. newXAxis.w = 0.0;
  125376. Cartesian3.subtract(newXAxis, newOrigin, newXAxis);
  125377. newXAxis.x = 0.0;
  125378. var newYAxis = scratchCartesian4NewYAxis;
  125379. if (Cartesian3.magnitudeSquared(newXAxis) > CesiumMath.EPSILON10) {
  125380. Cartesian3.cross(newZAxis, newXAxis, newYAxis);
  125381. } else {
  125382. var yAxis = Cartesian4.add(Matrix4.getColumn(camera._transform, 1, scratchCartesian3), origin, scratchCartesian3);
  125383. ellipsoid.cartesianToCartographic(yAxis, cartographic);
  125384. projection.project(cartographic, projectedPosition);
  125385. newYAxis.x = projectedPosition.z;
  125386. newYAxis.y = projectedPosition.x;
  125387. newYAxis.z = projectedPosition.y;
  125388. newYAxis.w = 0.0;
  125389. Cartesian3.subtract(newYAxis, newOrigin, newYAxis);
  125390. newYAxis.x = 0.0;
  125391. if (Cartesian3.magnitudeSquared(newYAxis) < CesiumMath.EPSILON10) {
  125392. Cartesian4.clone(Cartesian4.UNIT_Y, newXAxis);
  125393. Cartesian4.clone(Cartesian4.UNIT_Z, newYAxis);
  125394. }
  125395. }
  125396. Cartesian3.cross(newYAxis, newZAxis, newXAxis);
  125397. Cartesian3.normalize(newXAxis, newXAxis);
  125398. Cartesian3.cross(newZAxis, newXAxis, newYAxis);
  125399. Cartesian3.normalize(newYAxis, newYAxis);
  125400. Matrix4.setColumn(camera._actualTransform, 0, newXAxis, camera._actualTransform);
  125401. Matrix4.setColumn(camera._actualTransform, 1, newYAxis, camera._actualTransform);
  125402. Matrix4.setColumn(camera._actualTransform, 2, newZAxis, camera._actualTransform);
  125403. Matrix4.setColumn(camera._actualTransform, 3, newOrigin, camera._actualTransform);
  125404. }
  125405. var scratchCartesian = new Cartesian3();
  125406. function updateMembers(camera) {
  125407. var mode = camera._mode;
  125408. var heightChanged = false;
  125409. var height = 0.0;
  125410. if (mode === SceneMode.SCENE2D) {
  125411. height = camera.frustum.right - camera.frustum.left;
  125412. heightChanged = height !== camera._positionCartographic.height;
  125413. }
  125414. var position = camera._position;
  125415. var positionChanged = !Cartesian3.equals(position, camera.position) || heightChanged;
  125416. if (positionChanged) {
  125417. position = Cartesian3.clone(camera.position, camera._position);
  125418. }
  125419. var direction = camera._direction;
  125420. var directionChanged = !Cartesian3.equals(direction, camera.direction);
  125421. if (directionChanged) {
  125422. Cartesian3.normalize(camera.direction, camera.direction);
  125423. direction = Cartesian3.clone(camera.direction, camera._direction);
  125424. }
  125425. var up = camera._up;
  125426. var upChanged = !Cartesian3.equals(up, camera.up);
  125427. if (upChanged) {
  125428. Cartesian3.normalize(camera.up, camera.up);
  125429. up = Cartesian3.clone(camera.up, camera._up);
  125430. }
  125431. var right = camera._right;
  125432. var rightChanged = !Cartesian3.equals(right, camera.right);
  125433. if (rightChanged) {
  125434. Cartesian3.normalize(camera.right, camera.right);
  125435. right = Cartesian3.clone(camera.right, camera._right);
  125436. }
  125437. var transformChanged = camera._transformChanged || camera._modeChanged;
  125438. camera._transformChanged = false;
  125439. if (transformChanged) {
  125440. Matrix4.inverseTransformation(camera._transform, camera._invTransform);
  125441. if (camera._mode === SceneMode.COLUMBUS_VIEW || camera._mode === SceneMode.SCENE2D) {
  125442. if (Matrix4.equals(Matrix4.IDENTITY, camera._transform)) {
  125443. Matrix4.clone(Camera.TRANSFORM_2D, camera._actualTransform);
  125444. } else if (camera._mode === SceneMode.COLUMBUS_VIEW) {
  125445. convertTransformForColumbusView(camera);
  125446. } else {
  125447. convertTransformFor2D(camera);
  125448. }
  125449. } else {
  125450. Matrix4.clone(camera._transform, camera._actualTransform);
  125451. }
  125452. Matrix4.inverseTransformation(camera._actualTransform, camera._actualInvTransform);
  125453. camera._modeChanged = false;
  125454. }
  125455. var transform = camera._actualTransform;
  125456. if (positionChanged || transformChanged) {
  125457. camera._positionWC = Matrix4.multiplyByPoint(transform, position, camera._positionWC);
  125458. // Compute the Cartographic position of the camera.
  125459. if (mode === SceneMode.SCENE3D || mode === SceneMode.MORPHING) {
  125460. camera._positionCartographic = camera._projection.ellipsoid.cartesianToCartographic(camera._positionWC, camera._positionCartographic);
  125461. } else {
  125462. // The camera position is expressed in the 2D coordinate system where the Y axis is to the East,
  125463. // the Z axis is to the North, and the X axis is out of the map. Express them instead in the ENU axes where
  125464. // X is to the East, Y is to the North, and Z is out of the local horizontal plane.
  125465. var positionENU = scratchCartesian;
  125466. positionENU.x = camera._positionWC.y;
  125467. positionENU.y = camera._positionWC.z;
  125468. positionENU.z = camera._positionWC.x;
  125469. // In 2D, the camera height is always 12.7 million meters.
  125470. // The apparent height is equal to half the frustum width.
  125471. if (mode === SceneMode.SCENE2D) {
  125472. positionENU.z = height;
  125473. }
  125474. camera._projection.unproject(positionENU, camera._positionCartographic);
  125475. }
  125476. }
  125477. if (directionChanged || upChanged || rightChanged) {
  125478. var det = Cartesian3.dot(direction, Cartesian3.cross(up, right, scratchCartesian));
  125479. if (Math.abs(1.0 - det) > CesiumMath.EPSILON2) {
  125480. //orthonormalize axes
  125481. var invUpMag = 1.0 / Cartesian3.magnitudeSquared(up);
  125482. var scalar = Cartesian3.dot(up, direction) * invUpMag;
  125483. var w0 = Cartesian3.multiplyByScalar(direction, scalar, scratchCartesian);
  125484. up = Cartesian3.normalize(Cartesian3.subtract(up, w0, camera._up), camera._up);
  125485. Cartesian3.clone(up, camera.up);
  125486. right = Cartesian3.cross(direction, up, camera._right);
  125487. Cartesian3.clone(right, camera.right);
  125488. }
  125489. }
  125490. if (directionChanged || transformChanged) {
  125491. camera._directionWC = Matrix4.multiplyByPointAsVector(transform, direction, camera._directionWC);
  125492. }
  125493. if (upChanged || transformChanged) {
  125494. camera._upWC = Matrix4.multiplyByPointAsVector(transform, up, camera._upWC);
  125495. }
  125496. if (rightChanged || transformChanged) {
  125497. camera._rightWC = Matrix4.multiplyByPointAsVector(transform, right, camera._rightWC);
  125498. }
  125499. if (positionChanged || directionChanged || upChanged || rightChanged || transformChanged) {
  125500. updateViewMatrix(camera);
  125501. }
  125502. }
  125503. function getHeading(direction, up) {
  125504. var heading;
  125505. if (!CesiumMath.equalsEpsilon(Math.abs(direction.z), 1.0, CesiumMath.EPSILON3)) {
  125506. heading = Math.atan2(direction.y, direction.x) - CesiumMath.PI_OVER_TWO;
  125507. } else {
  125508. heading = Math.atan2(up.y, up.x) - CesiumMath.PI_OVER_TWO;
  125509. }
  125510. return CesiumMath.TWO_PI - CesiumMath.zeroToTwoPi(heading);
  125511. }
  125512. function getPitch(direction) {
  125513. return CesiumMath.PI_OVER_TWO - CesiumMath.acosClamped(direction.z);
  125514. }
  125515. function getRoll(direction, up, right) {
  125516. var roll = 0.0;
  125517. if (!CesiumMath.equalsEpsilon(Math.abs(direction.z), 1.0, CesiumMath.EPSILON3)) {
  125518. roll = Math.atan2(-right.z, up.z);
  125519. roll = CesiumMath.zeroToTwoPi(roll + CesiumMath.TWO_PI);
  125520. }
  125521. return roll;
  125522. }
  125523. var scratchHPRMatrix1 = new Matrix4();
  125524. var scratchHPRMatrix2 = new Matrix4();
  125525. defineProperties(Camera.prototype, {
  125526. /**
  125527. * Gets the camera's reference frame. The inverse of this transformation is appended to the view matrix.
  125528. * @memberof Camera.prototype
  125529. *
  125530. * @type {Matrix4}
  125531. * @readonly
  125532. *
  125533. * @default {@link Matrix4.IDENTITY}
  125534. */
  125535. transform : {
  125536. get : function() {
  125537. return this._transform;
  125538. }
  125539. },
  125540. /**
  125541. * Gets the inverse camera transform.
  125542. * @memberof Camera.prototype
  125543. *
  125544. * @type {Matrix4}
  125545. * @readonly
  125546. *
  125547. * @default {@link Matrix4.IDENTITY}
  125548. */
  125549. inverseTransform : {
  125550. get : function() {
  125551. updateMembers(this);
  125552. return this._invTransform;
  125553. }
  125554. },
  125555. /**
  125556. * Gets the view matrix.
  125557. * @memberof Camera.prototype
  125558. *
  125559. * @type {Matrix4}
  125560. * @readonly
  125561. *
  125562. * @see Camera#inverseViewMatrix
  125563. */
  125564. viewMatrix : {
  125565. get : function() {
  125566. updateMembers(this);
  125567. return this._viewMatrix;
  125568. }
  125569. },
  125570. /**
  125571. * Gets the inverse view matrix.
  125572. * @memberof Camera.prototype
  125573. *
  125574. * @type {Matrix4}
  125575. * @readonly
  125576. *
  125577. * @see Camera#viewMatrix
  125578. */
  125579. inverseViewMatrix : {
  125580. get : function() {
  125581. updateMembers(this);
  125582. return this._invViewMatrix;
  125583. }
  125584. },
  125585. /**
  125586. * Gets the {@link Cartographic} position of the camera, with longitude and latitude
  125587. * expressed in radians and height in meters. In 2D and Columbus View, it is possible
  125588. * for the returned longitude and latitude to be outside the range of valid longitudes
  125589. * and latitudes when the camera is outside the map.
  125590. * @memberof Camera.prototype
  125591. *
  125592. * @type {Cartographic}
  125593. * @readonly
  125594. */
  125595. positionCartographic : {
  125596. get : function() {
  125597. updateMembers(this);
  125598. return this._positionCartographic;
  125599. }
  125600. },
  125601. /**
  125602. * Gets the position of the camera in world coordinates.
  125603. * @memberof Camera.prototype
  125604. *
  125605. * @type {Cartesian3}
  125606. * @readonly
  125607. */
  125608. positionWC : {
  125609. get : function() {
  125610. updateMembers(this);
  125611. return this._positionWC;
  125612. }
  125613. },
  125614. /**
  125615. * Gets the view direction of the camera in world coordinates.
  125616. * @memberof Camera.prototype
  125617. *
  125618. * @type {Cartesian3}
  125619. * @readonly
  125620. */
  125621. directionWC : {
  125622. get : function() {
  125623. updateMembers(this);
  125624. return this._directionWC;
  125625. }
  125626. },
  125627. /**
  125628. * Gets the up direction of the camera in world coordinates.
  125629. * @memberof Camera.prototype
  125630. *
  125631. * @type {Cartesian3}
  125632. * @readonly
  125633. */
  125634. upWC : {
  125635. get : function() {
  125636. updateMembers(this);
  125637. return this._upWC;
  125638. }
  125639. },
  125640. /**
  125641. * Gets the right direction of the camera in world coordinates.
  125642. * @memberof Camera.prototype
  125643. *
  125644. * @type {Cartesian3}
  125645. * @readonly
  125646. */
  125647. rightWC : {
  125648. get : function() {
  125649. updateMembers(this);
  125650. return this._rightWC;
  125651. }
  125652. },
  125653. /**
  125654. * Gets the camera heading in radians.
  125655. * @memberof Camera.prototype
  125656. *
  125657. * @type {Number}
  125658. * @readonly
  125659. */
  125660. heading : {
  125661. get : function() {
  125662. if (this._mode !== SceneMode.MORPHING) {
  125663. var ellipsoid = this._projection.ellipsoid;
  125664. var oldTransform = Matrix4.clone(this._transform, scratchHPRMatrix1);
  125665. var transform = Transforms.eastNorthUpToFixedFrame(this.positionWC, ellipsoid, scratchHPRMatrix2);
  125666. this._setTransform(transform);
  125667. var heading = getHeading(this.direction, this.up);
  125668. this._setTransform(oldTransform);
  125669. return heading;
  125670. }
  125671. return undefined;
  125672. }
  125673. },
  125674. /**
  125675. * Gets the camera pitch in radians.
  125676. * @memberof Camera.prototype
  125677. *
  125678. * @type {Number}
  125679. * @readonly
  125680. */
  125681. pitch : {
  125682. get : function() {
  125683. if (this._mode !== SceneMode.MORPHING) {
  125684. var ellipsoid = this._projection.ellipsoid;
  125685. var oldTransform = Matrix4.clone(this._transform, scratchHPRMatrix1);
  125686. var transform = Transforms.eastNorthUpToFixedFrame(this.positionWC, ellipsoid, scratchHPRMatrix2);
  125687. this._setTransform(transform);
  125688. var pitch = getPitch(this.direction);
  125689. this._setTransform(oldTransform);
  125690. return pitch;
  125691. }
  125692. return undefined;
  125693. }
  125694. },
  125695. /**
  125696. * Gets the camera roll in radians.
  125697. * @memberof Camera.prototype
  125698. *
  125699. * @type {Number}
  125700. * @readonly
  125701. */
  125702. roll : {
  125703. get : function() {
  125704. if (this._mode !== SceneMode.MORPHING) {
  125705. var ellipsoid = this._projection.ellipsoid;
  125706. var oldTransform = Matrix4.clone(this._transform, scratchHPRMatrix1);
  125707. var transform = Transforms.eastNorthUpToFixedFrame(this.positionWC, ellipsoid, scratchHPRMatrix2);
  125708. this._setTransform(transform);
  125709. var roll = getRoll(this.direction, this.up, this.right);
  125710. this._setTransform(oldTransform);
  125711. return roll;
  125712. }
  125713. return undefined;
  125714. }
  125715. },
  125716. /**
  125717. * Gets the event that will be raised at when the camera starts to move.
  125718. * @memberof Camera.prototype
  125719. * @type {Event}
  125720. * @readonly
  125721. */
  125722. moveStart : {
  125723. get : function() {
  125724. return this._moveStart;
  125725. }
  125726. },
  125727. /**
  125728. * Gets the event that will be raised when the camera has stopped moving.
  125729. * @memberof Camera.prototype
  125730. * @type {Event}
  125731. * @readonly
  125732. */
  125733. moveEnd : {
  125734. get : function() {
  125735. return this._moveEnd;
  125736. }
  125737. },
  125738. /**
  125739. * Gets the event that will be raised when the camera has changed by <code>percentageChanged</code>.
  125740. * @memberof Camera.prototype
  125741. * @type {Event}
  125742. * @readonly
  125743. */
  125744. changed : {
  125745. get : function() {
  125746. return this._changed;
  125747. }
  125748. }
  125749. });
  125750. /**
  125751. * @private
  125752. */
  125753. Camera.prototype.update = function(mode) {
  125754. if (!defined(mode)) {
  125755. throw new DeveloperError('mode is required.');
  125756. }
  125757. var updateFrustum = false;
  125758. if (mode !== this._mode) {
  125759. this._mode = mode;
  125760. this._modeChanged = mode !== SceneMode.MORPHING;
  125761. updateFrustum = this._mode === SceneMode.SCENE2D;
  125762. }
  125763. if (updateFrustum) {
  125764. var frustum = this._max2Dfrustum = this.frustum.clone();
  125765. if (!defined(frustum.left) || !defined(frustum.right) || !defined(frustum.top) || !defined(frustum.bottom)) {
  125766. throw new DeveloperError('The camera frustum is expected to be orthographic for 2D camera control.');
  125767. }
  125768. var maxZoomOut = 2.0;
  125769. var ratio = frustum.top / frustum.right;
  125770. frustum.right = this._maxCoord.x * maxZoomOut;
  125771. frustum.left = -frustum.right;
  125772. frustum.top = ratio * frustum.right;
  125773. frustum.bottom = -frustum.top;
  125774. }
  125775. if (this._mode === SceneMode.SCENE2D) {
  125776. clampMove2D(this, this.position);
  125777. }
  125778. var globe = this._scene.globe;
  125779. var globeFinishedUpdating = !defined(globe) || (globe._surface.tileProvider.ready && globe._surface._tileLoadQueueHigh.length === 0 && globe._surface._tileLoadQueueMedium.length === 0 && globe._surface._tileLoadQueueLow.length === 0 && globe._surface._debug.tilesWaitingForChildren === 0);
  125780. if (this._suspendTerrainAdjustment) {
  125781. this._suspendTerrainAdjustment = !globeFinishedUpdating;
  125782. }
  125783. this._adjustHeightForTerrain();
  125784. };
  125785. var setTransformPosition = new Cartesian3();
  125786. var setTransformUp = new Cartesian3();
  125787. var setTransformDirection = new Cartesian3();
  125788. Camera.prototype._setTransform = function(transform) {
  125789. var position = Cartesian3.clone(this.positionWC, setTransformPosition);
  125790. var up = Cartesian3.clone(this.upWC, setTransformUp);
  125791. var direction = Cartesian3.clone(this.directionWC, setTransformDirection);
  125792. Matrix4.clone(transform, this._transform);
  125793. this._transformChanged = true;
  125794. updateMembers(this);
  125795. var inverse = this._actualInvTransform;
  125796. Matrix4.multiplyByPoint(inverse, position, this.position);
  125797. Matrix4.multiplyByPointAsVector(inverse, direction, this.direction);
  125798. Matrix4.multiplyByPointAsVector(inverse, up, this.up);
  125799. Cartesian3.cross(this.direction, this.up, this.right);
  125800. updateMembers(this);
  125801. };
  125802. var scratchSetViewCartesian = new Cartesian3();
  125803. var scratchSetViewTransform1 = new Matrix4();
  125804. var scratchSetViewTransform2 = new Matrix4();
  125805. var scratchSetViewQuaternion = new Quaternion();
  125806. var scratchSetViewMatrix3 = new Matrix3();
  125807. var scratchSetViewCartographic = new Cartographic();
  125808. function setView3D(camera, position, heading, pitch, roll) {
  125809. var currentTransform = Matrix4.clone(camera.transform, scratchSetViewTransform1);
  125810. var localTransform = Transforms.eastNorthUpToFixedFrame(position, camera._projection.ellipsoid, scratchSetViewTransform2);
  125811. camera._setTransform(localTransform);
  125812. Cartesian3.clone(Cartesian3.ZERO, camera.position);
  125813. var rotQuat = Quaternion.fromHeadingPitchRoll(heading - CesiumMath.PI_OVER_TWO, pitch, roll, scratchSetViewQuaternion);
  125814. var rotMat = Matrix3.fromQuaternion(rotQuat, scratchSetViewMatrix3);
  125815. Matrix3.getColumn(rotMat, 0, camera.direction);
  125816. Matrix3.getColumn(rotMat, 2, camera.up);
  125817. Cartesian3.cross(camera.direction, camera.up, camera.right);
  125818. camera._setTransform(currentTransform);
  125819. }
  125820. function setViewCV(camera, position, heading, pitch, roll, convert) {
  125821. var currentTransform = Matrix4.clone(camera.transform, scratchSetViewTransform1);
  125822. camera._setTransform(Matrix4.IDENTITY);
  125823. if (!Cartesian3.equals(position, camera.positionWC)) {
  125824. if (convert) {
  125825. var projection = camera._projection;
  125826. var cartographic = projection.ellipsoid.cartesianToCartographic(position, scratchSetViewCartographic);
  125827. position = projection.project(cartographic, scratchSetViewCartesian);
  125828. }
  125829. Cartesian3.clone(position, camera.position);
  125830. }
  125831. var rotQuat = Quaternion.fromHeadingPitchRoll(heading - CesiumMath.PI_OVER_TWO, pitch, roll, scratchSetViewQuaternion);
  125832. var rotMat = Matrix3.fromQuaternion(rotQuat, scratchSetViewMatrix3);
  125833. Matrix3.getColumn(rotMat, 0, camera.direction);
  125834. Matrix3.getColumn(rotMat, 2, camera.up);
  125835. Cartesian3.cross(camera.direction, camera.up, camera.right);
  125836. camera._setTransform(currentTransform);
  125837. }
  125838. function setView2D(camera, position, heading, convert) {
  125839. var pitch = -CesiumMath.PI_OVER_TWO;
  125840. var roll = 0.0;
  125841. var currentTransform = Matrix4.clone(camera.transform, scratchSetViewTransform1);
  125842. camera._setTransform(Matrix4.IDENTITY);
  125843. if (!Cartesian3.equals(position, camera.positionWC)) {
  125844. if (convert) {
  125845. var projection = camera._projection;
  125846. var cartographic = projection.ellipsoid.cartesianToCartographic(position, scratchSetViewCartographic);
  125847. position = projection.project(cartographic, scratchSetViewCartesian);
  125848. }
  125849. Cartesian2.clone(position, camera.position);
  125850. var newLeft = -position.z * 0.5;
  125851. var newRight = -newLeft;
  125852. var frustum = camera.frustum;
  125853. if (newRight > newLeft) {
  125854. var ratio = frustum.top / frustum.right;
  125855. frustum.right = newRight;
  125856. frustum.left = newLeft;
  125857. frustum.top = frustum.right * ratio;
  125858. frustum.bottom = -frustum.top;
  125859. }
  125860. }
  125861. if (camera._scene.mapMode2D === MapMode2D.ROTATE) {
  125862. var rotQuat = Quaternion.fromHeadingPitchRoll(heading - CesiumMath.PI_OVER_TWO, pitch, roll, scratchSetViewQuaternion);
  125863. var rotMat = Matrix3.fromQuaternion(rotQuat, scratchSetViewMatrix3);
  125864. Matrix3.getColumn(rotMat, 2, camera.up);
  125865. Cartesian3.cross(camera.direction, camera.up, camera.right);
  125866. }
  125867. camera._setTransform(currentTransform);
  125868. }
  125869. var scratchToHPRDirection = new Cartesian3();
  125870. var scratchToHPRUp = new Cartesian3();
  125871. var scratchToHPRRight = new Cartesian3();
  125872. function directionUpToHeadingPitchRoll(camera, position, orientation, result) {
  125873. var direction = Cartesian3.clone(orientation.direction, scratchToHPRDirection);
  125874. var up = Cartesian3.clone(orientation.up, scratchToHPRUp);
  125875. if (camera._scene.mode === SceneMode.SCENE3D) {
  125876. var ellipsoid = camera._projection.ellipsoid;
  125877. var transform = Transforms.eastNorthUpToFixedFrame(position, ellipsoid, scratchHPRMatrix1);
  125878. var invTransform = Matrix4.inverseTransformation(transform, scratchHPRMatrix2);
  125879. Matrix4.multiplyByPointAsVector(invTransform, direction, direction);
  125880. Matrix4.multiplyByPointAsVector(invTransform, up, up);
  125881. }
  125882. var right = Cartesian3.cross(direction, up, scratchToHPRRight);
  125883. result.heading = getHeading(direction, up);
  125884. result.pitch = getPitch(direction);
  125885. result.roll = getRoll(direction, up, right);
  125886. return result;
  125887. }
  125888. var scratchSetViewOptions = {
  125889. destination : undefined,
  125890. orientation : {
  125891. direction : undefined,
  125892. up : undefined,
  125893. heading : undefined,
  125894. pitch : undefined,
  125895. roll : undefined
  125896. },
  125897. convert : undefined,
  125898. endTransform : undefined
  125899. };
  125900. /**
  125901. * Sets the camera position, orientation and transform.
  125902. *
  125903. * @param {Object} options Object with the following properties:
  125904. * @param {Cartesian3|Rectangle} [options.destination] The final position of the camera in WGS84 (world) coordinates or a rectangle that would be visible from a top-down view.
  125905. * @param {Object} [options.orientation] An object that contains either direction and up properties or heading, pith and roll properties. By default, the direction will point
  125906. * towards the center of the frame in 3D and in the negative z direction in Columbus view. The up direction will point towards local north in 3D and in the positive
  125907. * y direction in Columbus view. Orientation is not used in 2D when in infinite scrolling mode.
  125908. * @param {Matrix4} [options.endTransform] Transform matrix representing the reference frame of the camera.
  125909. *
  125910. * @example
  125911. * // 1. Set position with a top-down view
  125912. * viewer.camera.setView({
  125913. * destination : Cesium.Cartesian3.fromDegrees(-117.16, 32.71, 15000.0)
  125914. * });
  125915. *
  125916. * // 2 Set view with heading, pitch and roll
  125917. * viewer.camera.setView({
  125918. * destination : cartesianPosition,
  125919. * orientation: {
  125920. * heading : Cesium.Math.toRadians(90.0), // east, default value is 0.0 (north)
  125921. * pitch : Cesium.Math.toRadians(-90), // default value (looking down)
  125922. * roll : 0.0 // default value
  125923. * }
  125924. * });
  125925. *
  125926. * // 3. Change heading, pitch and roll with the camera position remaining the same.
  125927. * viewer.camera.setView({
  125928. * orientation: {
  125929. * heading : Cesium.Math.toRadians(90.0), // east, default value is 0.0 (north)
  125930. * pitch : Cesium.Math.toRadians(-90), // default value (looking down)
  125931. * roll : 0.0 // default value
  125932. * }
  125933. * });
  125934. *
  125935. *
  125936. * // 4. View rectangle with a top-down view
  125937. * viewer.camera.setView({
  125938. * destination : Cesium.Rectangle.fromDegrees(west, south, east, north)
  125939. * });
  125940. *
  125941. * // 5. Set position with an orientation using unit vectors.
  125942. * viewer.camera.setView({
  125943. * destination : Cesium.Cartesian3.fromDegrees(-122.19, 46.25, 5000.0),
  125944. * orientation : {
  125945. * direction : new Cesium.Cartesian3(-0.04231243104240401, -0.20123236049443421, -0.97862924300734),
  125946. * up : new Cesium.Cartesian3(-0.47934589305293746, -0.8553216253114552, 0.1966022179118339)
  125947. * }
  125948. * });
  125949. */
  125950. Camera.prototype.setView = function(options) {
  125951. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  125952. var orientation = defaultValue(options.orientation, defaultValue.EMPTY_OBJECT);
  125953. var mode = this._mode;
  125954. if (mode === SceneMode.MORPHING) {
  125955. return;
  125956. }
  125957. if (defined(options.endTransform)) {
  125958. this._setTransform(options.endTransform);
  125959. }
  125960. var convert = defaultValue(options.convert, true);
  125961. var destination = defaultValue(options.destination, Cartesian3.clone(this.positionWC, scratchSetViewCartesian));
  125962. if (defined(destination) && defined(destination.west)) {
  125963. destination = this.getRectangleCameraCoordinates(destination, scratchSetViewCartesian);
  125964. convert = false;
  125965. }
  125966. if (defined(orientation.direction)) {
  125967. orientation = directionUpToHeadingPitchRoll(this, destination, orientation, scratchSetViewOptions.orientation);
  125968. }
  125969. var heading = defaultValue(orientation.heading, 0.0);
  125970. var pitch = defaultValue(orientation.pitch, -CesiumMath.PI_OVER_TWO);
  125971. var roll = defaultValue(orientation.roll, 0.0);
  125972. this._suspendTerrainAdjustment = true;
  125973. if (mode === SceneMode.SCENE3D) {
  125974. setView3D(this, destination, heading, pitch, roll);
  125975. } else if (mode === SceneMode.SCENE2D) {
  125976. setView2D(this, destination, heading, convert);
  125977. } else {
  125978. setViewCV(this, destination, heading, pitch, roll, convert);
  125979. }
  125980. };
  125981. var pitchScratch = new Cartesian3();
  125982. /**
  125983. * Fly the camera to the home view. Use {@link Camera#.DEFAULT_VIEW_RECTANGLE} to set
  125984. * the default view for the 3D scene. The home view for 2D and columbus view shows the
  125985. * entire map.
  125986. *
  125987. * @param {Number} [duration] The number of seconds to complete the camera flight to home. See {@link Camera#flyTo}
  125988. */
  125989. Camera.prototype.flyHome = function(duration) {
  125990. var mode = this._mode;
  125991. if (mode === SceneMode.MORPHING) {
  125992. this._scene.completeMorph();
  125993. }
  125994. if (mode === SceneMode.SCENE2D) {
  125995. this.flyTo({
  125996. destination : Rectangle.MAX_VALUE,
  125997. duration : duration,
  125998. endTransform : Matrix4.IDENTITY
  125999. });
  126000. } else if (mode === SceneMode.SCENE3D) {
  126001. var destination = this.getRectangleCameraCoordinates(Camera.DEFAULT_VIEW_RECTANGLE);
  126002. var mag = Cartesian3.magnitude(destination);
  126003. mag += mag * Camera.DEFAULT_VIEW_FACTOR;
  126004. Cartesian3.normalize(destination, destination);
  126005. Cartesian3.multiplyByScalar(destination, mag, destination);
  126006. this.flyTo({
  126007. destination : destination,
  126008. duration : duration,
  126009. endTransform : Matrix4.IDENTITY
  126010. });
  126011. } else if (mode === SceneMode.COLUMBUS_VIEW) {
  126012. var maxRadii = this._projection.ellipsoid.maximumRadius;
  126013. var position = new Cartesian3(0.0, -1.0, 1.0);
  126014. position = Cartesian3.multiplyByScalar(Cartesian3.normalize(position, position), 5.0 * maxRadii, position);
  126015. this.flyTo({
  126016. destination : position,
  126017. duration : duration,
  126018. orientation : {
  126019. heading : 0.0,
  126020. pitch : -Math.acos(Cartesian3.normalize(position, pitchScratch).z),
  126021. roll : 0.0
  126022. },
  126023. endTransform : Matrix4.IDENTITY,
  126024. convert : false
  126025. });
  126026. }
  126027. };
  126028. /**
  126029. * Transform a vector or point from world coordinates to the camera's reference frame.
  126030. *
  126031. * @param {Cartesian4} cartesian The vector or point to transform.
  126032. * @param {Cartesian4} [result] The object onto which to store the result.
  126033. * @returns {Cartesian4} The transformed vector or point.
  126034. */
  126035. Camera.prototype.worldToCameraCoordinates = function(cartesian, result) {
  126036. if (!defined(cartesian)) {
  126037. throw new DeveloperError('cartesian is required.');
  126038. }
  126039. if (!defined(result)) {
  126040. result = new Cartesian4();
  126041. }
  126042. updateMembers(this);
  126043. return Matrix4.multiplyByVector(this._actualInvTransform, cartesian, result);
  126044. };
  126045. /**
  126046. * Transform a point from world coordinates to the camera's reference frame.
  126047. *
  126048. * @param {Cartesian3} cartesian The point to transform.
  126049. * @param {Cartesian3} [result] The object onto which to store the result.
  126050. * @returns {Cartesian3} The transformed point.
  126051. */
  126052. Camera.prototype.worldToCameraCoordinatesPoint = function(cartesian, result) {
  126053. if (!defined(cartesian)) {
  126054. throw new DeveloperError('cartesian is required.');
  126055. }
  126056. if (!defined(result)) {
  126057. result = new Cartesian3();
  126058. }
  126059. updateMembers(this);
  126060. return Matrix4.multiplyByPoint(this._actualInvTransform, cartesian, result);
  126061. };
  126062. /**
  126063. * Transform a vector from world coordinates to the camera's reference frame.
  126064. *
  126065. * @param {Cartesian3} cartesian The vector to transform.
  126066. * @param {Cartesian3} [result] The object onto which to store the result.
  126067. * @returns {Cartesian3} The transformed vector.
  126068. */
  126069. Camera.prototype.worldToCameraCoordinatesVector = function(cartesian, result) {
  126070. if (!defined(cartesian)) {
  126071. throw new DeveloperError('cartesian is required.');
  126072. }
  126073. if (!defined(result)) {
  126074. result = new Cartesian3();
  126075. }
  126076. updateMembers(this);
  126077. return Matrix4.multiplyByPointAsVector(this._actualInvTransform, cartesian, result);
  126078. };
  126079. /**
  126080. * Transform a vector or point from the camera's reference frame to world coordinates.
  126081. *
  126082. * @param {Cartesian4} cartesian The vector or point to transform.
  126083. * @param {Cartesian4} [result] The object onto which to store the result.
  126084. * @returns {Cartesian4} The transformed vector or point.
  126085. */
  126086. Camera.prototype.cameraToWorldCoordinates = function(cartesian, result) {
  126087. if (!defined(cartesian)) {
  126088. throw new DeveloperError('cartesian is required.');
  126089. }
  126090. if (!defined(result)) {
  126091. result = new Cartesian4();
  126092. }
  126093. updateMembers(this);
  126094. return Matrix4.multiplyByVector(this._actualTransform, cartesian, result);
  126095. };
  126096. /**
  126097. * Transform a point from the camera's reference frame to world coordinates.
  126098. *
  126099. * @param {Cartesian3} cartesian The point to transform.
  126100. * @param {Cartesian3} [result] The object onto which to store the result.
  126101. * @returns {Cartesian3} The transformed point.
  126102. */
  126103. Camera.prototype.cameraToWorldCoordinatesPoint = function(cartesian, result) {
  126104. if (!defined(cartesian)) {
  126105. throw new DeveloperError('cartesian is required.');
  126106. }
  126107. if (!defined(result)) {
  126108. result = new Cartesian3();
  126109. }
  126110. updateMembers(this);
  126111. return Matrix4.multiplyByPoint(this._actualTransform, cartesian, result);
  126112. };
  126113. /**
  126114. * Transform a vector from the camera's reference frame to world coordinates.
  126115. *
  126116. * @param {Cartesian3} cartesian The vector to transform.
  126117. * @param {Cartesian3} [result] The object onto which to store the result.
  126118. * @returns {Cartesian3} The transformed vector.
  126119. */
  126120. Camera.prototype.cameraToWorldCoordinatesVector = function(cartesian, result) {
  126121. if (!defined(cartesian)) {
  126122. throw new DeveloperError('cartesian is required.');
  126123. }
  126124. if (!defined(result)) {
  126125. result = new Cartesian3();
  126126. }
  126127. updateMembers(this);
  126128. return Matrix4.multiplyByPointAsVector(this._actualTransform, cartesian, result);
  126129. };
  126130. function clampMove2D(camera, position) {
  126131. var rotatable2D = camera._scene.mapMode2D === MapMode2D.ROTATE;
  126132. var maxProjectedX = camera._maxCoord.x;
  126133. var maxProjectedY = camera._maxCoord.y;
  126134. var minX;
  126135. var maxX;
  126136. if (rotatable2D) {
  126137. maxX = maxProjectedX;
  126138. minX = -maxX;
  126139. } else {
  126140. maxX = position.x - maxProjectedX * 2.0;
  126141. minX = position.x + maxProjectedX * 2.0;
  126142. }
  126143. if (position.x > maxProjectedX) {
  126144. position.x = maxX;
  126145. }
  126146. if (position.x < -maxProjectedX) {
  126147. position.x = minX;
  126148. }
  126149. if (position.y > maxProjectedY) {
  126150. position.y = maxProjectedY;
  126151. }
  126152. if (position.y < -maxProjectedY) {
  126153. position.y = -maxProjectedY;
  126154. }
  126155. }
  126156. var moveScratch = new Cartesian3();
  126157. /**
  126158. * Translates the camera's position by <code>amount</code> along <code>direction</code>.
  126159. *
  126160. * @param {Cartesian3} direction The direction to move.
  126161. * @param {Number} [amount] The amount, in meters, to move. Defaults to <code>defaultMoveAmount</code>.
  126162. *
  126163. * @see Camera#moveBackward
  126164. * @see Camera#moveForward
  126165. * @see Camera#moveLeft
  126166. * @see Camera#moveRight
  126167. * @see Camera#moveUp
  126168. * @see Camera#moveDown
  126169. */
  126170. Camera.prototype.move = function(direction, amount) {
  126171. if (!defined(direction)) {
  126172. throw new DeveloperError('direction is required.');
  126173. }
  126174. var cameraPosition = this.position;
  126175. Cartesian3.multiplyByScalar(direction, amount, moveScratch);
  126176. Cartesian3.add(cameraPosition, moveScratch, cameraPosition);
  126177. if (this._mode === SceneMode.SCENE2D) {
  126178. clampMove2D(this, cameraPosition);
  126179. }
  126180. };
  126181. /**
  126182. * Translates the camera's position by <code>amount</code> along the camera's view vector.
  126183. *
  126184. * @param {Number} [amount] The amount, in meters, to move. Defaults to <code>defaultMoveAmount</code>.
  126185. *
  126186. * @see Camera#moveBackward
  126187. */
  126188. Camera.prototype.moveForward = function(amount) {
  126189. amount = defaultValue(amount, this.defaultMoveAmount);
  126190. this.move(this.direction, amount);
  126191. };
  126192. /**
  126193. * Translates the camera's position by <code>amount</code> along the opposite direction
  126194. * of the camera's view vector.
  126195. *
  126196. * @param {Number} [amount] The amount, in meters, to move. Defaults to <code>defaultMoveAmount</code>.
  126197. *
  126198. * @see Camera#moveForward
  126199. */
  126200. Camera.prototype.moveBackward = function(amount) {
  126201. amount = defaultValue(amount, this.defaultMoveAmount);
  126202. this.move(this.direction, -amount);
  126203. };
  126204. /**
  126205. * Translates the camera's position by <code>amount</code> along the camera's up vector.
  126206. *
  126207. * @param {Number} [amount] The amount, in meters, to move. Defaults to <code>defaultMoveAmount</code>.
  126208. *
  126209. * @see Camera#moveDown
  126210. */
  126211. Camera.prototype.moveUp = function(amount) {
  126212. amount = defaultValue(amount, this.defaultMoveAmount);
  126213. this.move(this.up, amount);
  126214. };
  126215. /**
  126216. * Translates the camera's position by <code>amount</code> along the opposite direction
  126217. * of the camera's up vector.
  126218. *
  126219. * @param {Number} [amount] The amount, in meters, to move. Defaults to <code>defaultMoveAmount</code>.
  126220. *
  126221. * @see Camera#moveUp
  126222. */
  126223. Camera.prototype.moveDown = function(amount) {
  126224. amount = defaultValue(amount, this.defaultMoveAmount);
  126225. this.move(this.up, -amount);
  126226. };
  126227. /**
  126228. * Translates the camera's position by <code>amount</code> along the camera's right vector.
  126229. *
  126230. * @param {Number} [amount] The amount, in meters, to move. Defaults to <code>defaultMoveAmount</code>.
  126231. *
  126232. * @see Camera#moveLeft
  126233. */
  126234. Camera.prototype.moveRight = function(amount) {
  126235. amount = defaultValue(amount, this.defaultMoveAmount);
  126236. this.move(this.right, amount);
  126237. };
  126238. /**
  126239. * Translates the camera's position by <code>amount</code> along the opposite direction
  126240. * of the camera's right vector.
  126241. *
  126242. * @param {Number} [amount] The amount, in meters, to move. Defaults to <code>defaultMoveAmount</code>.
  126243. *
  126244. * @see Camera#moveRight
  126245. */
  126246. Camera.prototype.moveLeft = function(amount) {
  126247. amount = defaultValue(amount, this.defaultMoveAmount);
  126248. this.move(this.right, -amount);
  126249. };
  126250. /**
  126251. * Rotates the camera around its up vector by amount, in radians, in the opposite direction
  126252. * of its right vector.
  126253. *
  126254. * @param {Number} [amount] The amount, in radians, to rotate by. Defaults to <code>defaultLookAmount</code>.
  126255. *
  126256. * @see Camera#lookRight
  126257. */
  126258. Camera.prototype.lookLeft = function(amount) {
  126259. amount = defaultValue(amount, this.defaultLookAmount);
  126260. this.look(this.up, -amount);
  126261. };
  126262. /**
  126263. * Rotates the camera around its up vector by amount, in radians, in the direction
  126264. * of its right vector.
  126265. *
  126266. * @param {Number} [amount] The amount, in radians, to rotate by. Defaults to <code>defaultLookAmount</code>.
  126267. *
  126268. * @see Camera#lookLeft
  126269. */
  126270. Camera.prototype.lookRight = function(amount) {
  126271. amount = defaultValue(amount, this.defaultLookAmount);
  126272. this.look(this.up, amount);
  126273. };
  126274. /**
  126275. * Rotates the camera around its right vector by amount, in radians, in the direction
  126276. * of its up vector.
  126277. *
  126278. * @param {Number} [amount] The amount, in radians, to rotate by. Defaults to <code>defaultLookAmount</code>.
  126279. *
  126280. * @see Camera#lookDown
  126281. */
  126282. Camera.prototype.lookUp = function(amount) {
  126283. amount = defaultValue(amount, this.defaultLookAmount);
  126284. this.look(this.right, -amount);
  126285. };
  126286. /**
  126287. * Rotates the camera around its right vector by amount, in radians, in the opposite direction
  126288. * of its up vector.
  126289. *
  126290. * @param {Number} [amount] The amount, in radians, to rotate by. Defaults to <code>defaultLookAmount</code>.
  126291. *
  126292. * @see Camera#lookUp
  126293. */
  126294. Camera.prototype.lookDown = function(amount) {
  126295. amount = defaultValue(amount, this.defaultLookAmount);
  126296. this.look(this.right, amount);
  126297. };
  126298. var lookScratchQuaternion = new Quaternion();
  126299. var lookScratchMatrix = new Matrix3();
  126300. /**
  126301. * Rotate each of the camera's orientation vectors around <code>axis</code> by <code>angle</code>
  126302. *
  126303. * @param {Cartesian3} axis The axis to rotate around.
  126304. * @param {Number} [angle] The angle, in radians, to rotate by. Defaults to <code>defaultLookAmount</code>.
  126305. *
  126306. * @see Camera#lookUp
  126307. * @see Camera#lookDown
  126308. * @see Camera#lookLeft
  126309. * @see Camera#lookRight
  126310. */
  126311. Camera.prototype.look = function(axis, angle) {
  126312. if (!defined(axis)) {
  126313. throw new DeveloperError('axis is required.');
  126314. }
  126315. var turnAngle = defaultValue(angle, this.defaultLookAmount);
  126316. var quaternion = Quaternion.fromAxisAngle(axis, -turnAngle, lookScratchQuaternion);
  126317. var rotation = Matrix3.fromQuaternion(quaternion, lookScratchMatrix);
  126318. var direction = this.direction;
  126319. var up = this.up;
  126320. var right = this.right;
  126321. Matrix3.multiplyByVector(rotation, direction, direction);
  126322. Matrix3.multiplyByVector(rotation, up, up);
  126323. Matrix3.multiplyByVector(rotation, right, right);
  126324. };
  126325. /**
  126326. * Rotate the camera counter-clockwise around its direction vector by amount, in radians.
  126327. *
  126328. * @param {Number} [amount] The amount, in radians, to rotate by. Defaults to <code>defaultLookAmount</code>.
  126329. *
  126330. * @see Camera#twistRight
  126331. */
  126332. Camera.prototype.twistLeft = function(amount) {
  126333. amount = defaultValue(amount, this.defaultLookAmount);
  126334. this.look(this.direction, amount);
  126335. };
  126336. /**
  126337. * Rotate the camera clockwise around its direction vector by amount, in radians.
  126338. *
  126339. * @param {Number} [amount] The amount, in radians, to rotate by. Defaults to <code>defaultLookAmount</code>.
  126340. *
  126341. * @see Camera#twistLeft
  126342. */
  126343. Camera.prototype.twistRight = function(amount) {
  126344. amount = defaultValue(amount, this.defaultLookAmount);
  126345. this.look(this.direction, -amount);
  126346. };
  126347. var rotateScratchQuaternion = new Quaternion();
  126348. var rotateScratchMatrix = new Matrix3();
  126349. /**
  126350. * Rotates the camera around <code>axis</code> by <code>angle</code>. The distance
  126351. * of the camera's position to the center of the camera's reference frame remains the same.
  126352. *
  126353. * @param {Cartesian3} axis The axis to rotate around given in world coordinates.
  126354. * @param {Number} [angle] The angle, in radians, to rotate by. Defaults to <code>defaultRotateAmount</code>.
  126355. *
  126356. * @see Camera#rotateUp
  126357. * @see Camera#rotateDown
  126358. * @see Camera#rotateLeft
  126359. * @see Camera#rotateRight
  126360. */
  126361. Camera.prototype.rotate = function(axis, angle) {
  126362. if (!defined(axis)) {
  126363. throw new DeveloperError('axis is required.');
  126364. }
  126365. var turnAngle = defaultValue(angle, this.defaultRotateAmount);
  126366. var quaternion = Quaternion.fromAxisAngle(axis, -turnAngle, rotateScratchQuaternion);
  126367. var rotation = Matrix3.fromQuaternion(quaternion, rotateScratchMatrix);
  126368. Matrix3.multiplyByVector(rotation, this.position, this.position);
  126369. Matrix3.multiplyByVector(rotation, this.direction, this.direction);
  126370. Matrix3.multiplyByVector(rotation, this.up, this.up);
  126371. Cartesian3.cross(this.direction, this.up, this.right);
  126372. Cartesian3.cross(this.right, this.direction, this.up);
  126373. };
  126374. /**
  126375. * Rotates the camera around the center of the camera's reference frame by angle downwards.
  126376. *
  126377. * @param {Number} [angle] The angle, in radians, to rotate by. Defaults to <code>defaultRotateAmount</code>.
  126378. *
  126379. * @see Camera#rotateUp
  126380. * @see Camera#rotate
  126381. */
  126382. Camera.prototype.rotateDown = function(angle) {
  126383. angle = defaultValue(angle, this.defaultRotateAmount);
  126384. rotateVertical(this, angle);
  126385. };
  126386. /**
  126387. * Rotates the camera around the center of the camera's reference frame by angle upwards.
  126388. *
  126389. * @param {Number} [angle] The angle, in radians, to rotate by. Defaults to <code>defaultRotateAmount</code>.
  126390. *
  126391. * @see Camera#rotateDown
  126392. * @see Camera#rotate
  126393. */
  126394. Camera.prototype.rotateUp = function(angle) {
  126395. angle = defaultValue(angle, this.defaultRotateAmount);
  126396. rotateVertical(this, -angle);
  126397. };
  126398. var rotateVertScratchP = new Cartesian3();
  126399. var rotateVertScratchA = new Cartesian3();
  126400. var rotateVertScratchTan = new Cartesian3();
  126401. var rotateVertScratchNegate = new Cartesian3();
  126402. function rotateVertical(camera, angle) {
  126403. var position = camera.position;
  126404. var p = Cartesian3.normalize(position, rotateVertScratchP);
  126405. if (defined(camera.constrainedAxis)) {
  126406. var northParallel = Cartesian3.equalsEpsilon(p, camera.constrainedAxis, CesiumMath.EPSILON2);
  126407. var southParallel = Cartesian3.equalsEpsilon(p, Cartesian3.negate(camera.constrainedAxis, rotateVertScratchNegate), CesiumMath.EPSILON2);
  126408. if ((!northParallel && !southParallel)) {
  126409. var constrainedAxis = Cartesian3.normalize(camera.constrainedAxis, rotateVertScratchA);
  126410. var dot = Cartesian3.dot(p, constrainedAxis);
  126411. var angleToAxis = CesiumMath.acosClamped(dot);
  126412. if (angle > 0 && angle > angleToAxis) {
  126413. angle = angleToAxis - CesiumMath.EPSILON4;
  126414. }
  126415. dot = Cartesian3.dot(p, Cartesian3.negate(constrainedAxis, rotateVertScratchNegate));
  126416. angleToAxis = CesiumMath.acosClamped(dot);
  126417. if (angle < 0 && -angle > angleToAxis) {
  126418. angle = -angleToAxis + CesiumMath.EPSILON4;
  126419. }
  126420. var tangent = Cartesian3.cross(constrainedAxis, p, rotateVertScratchTan);
  126421. camera.rotate(tangent, angle);
  126422. } else if ((northParallel && angle < 0) || (southParallel && angle > 0)) {
  126423. camera.rotate(camera.right, angle);
  126424. }
  126425. } else {
  126426. camera.rotate(camera.right, angle);
  126427. }
  126428. }
  126429. /**
  126430. * Rotates the camera around the center of the camera's reference frame by angle to the right.
  126431. *
  126432. * @param {Number} [angle] The angle, in radians, to rotate by. Defaults to <code>defaultRotateAmount</code>.
  126433. *
  126434. * @see Camera#rotateLeft
  126435. * @see Camera#rotate
  126436. */
  126437. Camera.prototype.rotateRight = function(angle) {
  126438. angle = defaultValue(angle, this.defaultRotateAmount);
  126439. rotateHorizontal(this, -angle);
  126440. };
  126441. /**
  126442. * Rotates the camera around the center of the camera's reference frame by angle to the left.
  126443. *
  126444. * @param {Number} [angle] The angle, in radians, to rotate by. Defaults to <code>defaultRotateAmount</code>.
  126445. *
  126446. * @see Camera#rotateRight
  126447. * @see Camera#rotate
  126448. */
  126449. Camera.prototype.rotateLeft = function(angle) {
  126450. angle = defaultValue(angle, this.defaultRotateAmount);
  126451. rotateHorizontal(this, angle);
  126452. };
  126453. function rotateHorizontal(camera, angle) {
  126454. if (defined(camera.constrainedAxis)) {
  126455. camera.rotate(camera.constrainedAxis, angle);
  126456. } else {
  126457. camera.rotate(camera.up, angle);
  126458. }
  126459. }
  126460. function zoom2D(camera, amount) {
  126461. var frustum = camera.frustum;
  126462. if (!defined(frustum.left) || !defined(frustum.right) || !defined(frustum.top) || !defined(frustum.bottom)) {
  126463. throw new DeveloperError('The camera frustum is expected to be orthographic for 2D camera control.');
  126464. }
  126465. amount = amount * 0.5;
  126466. var newRight = frustum.right - amount;
  126467. var newLeft = frustum.left + amount;
  126468. var maxRight = camera._maxCoord.x;
  126469. if (camera._scene.mapMode2D === MapMode2D.ROTATE) {
  126470. maxRight *= camera.maximumZoomFactor;
  126471. }
  126472. if (newRight > maxRight) {
  126473. newRight = maxRight;
  126474. newLeft = -maxRight;
  126475. }
  126476. if (newRight <= newLeft) {
  126477. newRight = 1.0;
  126478. newLeft = -1.0;
  126479. }
  126480. var ratio = frustum.top / frustum.right;
  126481. frustum.right = newRight;
  126482. frustum.left = newLeft;
  126483. frustum.top = frustum.right * ratio;
  126484. frustum.bottom = -frustum.top;
  126485. }
  126486. function zoom3D(camera, amount) {
  126487. camera.move(camera.direction, amount);
  126488. }
  126489. /**
  126490. * Zooms <code>amount</code> along the camera's view vector.
  126491. *
  126492. * @param {Number} [amount] The amount to move. Defaults to <code>defaultZoomAmount</code>.
  126493. *
  126494. * @see Camera#zoomOut
  126495. */
  126496. Camera.prototype.zoomIn = function(amount) {
  126497. amount = defaultValue(amount, this.defaultZoomAmount);
  126498. if (this._mode === SceneMode.SCENE2D) {
  126499. zoom2D(this, amount);
  126500. } else {
  126501. zoom3D(this, amount);
  126502. }
  126503. };
  126504. /**
  126505. * Zooms <code>amount</code> along the opposite direction of
  126506. * the camera's view vector.
  126507. *
  126508. * @param {Number} [amount] The amount to move. Defaults to <code>defaultZoomAmount</code>.
  126509. *
  126510. * @see Camera#zoomIn
  126511. */
  126512. Camera.prototype.zoomOut = function(amount) {
  126513. amount = defaultValue(amount, this.defaultZoomAmount);
  126514. if (this._mode === SceneMode.SCENE2D) {
  126515. zoom2D(this, -amount);
  126516. } else {
  126517. zoom3D(this, -amount);
  126518. }
  126519. };
  126520. /**
  126521. * Gets the magnitude of the camera position. In 3D, this is the vector magnitude. In 2D and
  126522. * Columbus view, this is the distance to the map.
  126523. *
  126524. * @returns {Number} The magnitude of the position.
  126525. */
  126526. Camera.prototype.getMagnitude = function() {
  126527. if (this._mode === SceneMode.SCENE3D) {
  126528. return Cartesian3.magnitude(this.position);
  126529. } else if (this._mode === SceneMode.COLUMBUS_VIEW) {
  126530. return Math.abs(this.position.z);
  126531. } else if (this._mode === SceneMode.SCENE2D) {
  126532. return Math.max(this.frustum.right - this.frustum.left, this.frustum.top - this.frustum.bottom);
  126533. }
  126534. };
  126535. var scratchLookAtMatrix4 = new Matrix4();
  126536. /**
  126537. * Sets the camera position and orientation using a target and offset. The target must be given in
  126538. * world coordinates. The offset can be either a cartesian or heading/pitch/range in the local east-north-up reference frame centered at the target.
  126539. * If the offset is a cartesian, then it is an offset from the center of the reference frame defined by the transformation matrix. If the offset
  126540. * is heading/pitch/range, then the heading and the pitch angles are defined in the reference frame defined by the transformation matrix.
  126541. * The heading is the angle from y axis and increasing towards the x axis. Pitch is the rotation from the xy-plane. Positive pitch
  126542. * angles are below the plane. Negative pitch angles are above the plane. The range is the distance from the center.
  126543. *
  126544. * In 2D, there must be a top down view. The camera will be placed above the target looking down. The height above the
  126545. * target will be the magnitude of the offset. The heading will be determined from the offset. If the heading cannot be
  126546. * determined from the offset, the heading will be north.
  126547. *
  126548. * @param {Cartesian3} target The target position in world coordinates.
  126549. * @param {Cartesian3|HeadingPitchRange} offset The offset from the target in the local east-north-up reference frame centered at the target.
  126550. *
  126551. * @exception {DeveloperError} lookAt is not supported while morphing.
  126552. *
  126553. * @example
  126554. * // 1. Using a cartesian offset
  126555. * var center = Cesium.Cartesian3.fromDegrees(-98.0, 40.0);
  126556. * viewer.camera.lookAt(center, new Cesium.Cartesian3(0.0, -4790000.0, 3930000.0));
  126557. *
  126558. * // 2. Using a HeadingPitchRange offset
  126559. * var center = Cesium.Cartesian3.fromDegrees(-72.0, 40.0);
  126560. * var heading = Cesium.Math.toRadians(50.0);
  126561. * var pitch = Cesium.Math.toRadians(-20.0);
  126562. * var range = 5000.0;
  126563. * viewer.camera.lookAt(center, new Cesium.HeadingPitchRange(heading, pitch, range));
  126564. */
  126565. Camera.prototype.lookAt = function(target, offset) {
  126566. if (!defined(target)) {
  126567. throw new DeveloperError('target is required');
  126568. }
  126569. if (!defined(offset)) {
  126570. throw new DeveloperError('offset is required');
  126571. }
  126572. if (this._mode === SceneMode.MORPHING) {
  126573. throw new DeveloperError('lookAt is not supported while morphing.');
  126574. }
  126575. var transform = Transforms.eastNorthUpToFixedFrame(target, Ellipsoid.WGS84, scratchLookAtMatrix4);
  126576. this.lookAtTransform(transform, offset);
  126577. };
  126578. var scratchLookAtHeadingPitchRangeOffset = new Cartesian3();
  126579. var scratchLookAtHeadingPitchRangeQuaternion1 = new Quaternion();
  126580. var scratchLookAtHeadingPitchRangeQuaternion2 = new Quaternion();
  126581. var scratchHeadingPitchRangeMatrix3 = new Matrix3();
  126582. function offsetFromHeadingPitchRange(heading, pitch, range) {
  126583. pitch = CesiumMath.clamp(pitch, -CesiumMath.PI_OVER_TWO, CesiumMath.PI_OVER_TWO);
  126584. heading = CesiumMath.zeroToTwoPi(heading) - CesiumMath.PI_OVER_TWO;
  126585. var pitchQuat = Quaternion.fromAxisAngle(Cartesian3.UNIT_Y, -pitch, scratchLookAtHeadingPitchRangeQuaternion1);
  126586. var headingQuat = Quaternion.fromAxisAngle(Cartesian3.UNIT_Z, -heading, scratchLookAtHeadingPitchRangeQuaternion2);
  126587. var rotQuat = Quaternion.multiply(headingQuat, pitchQuat, headingQuat);
  126588. var rotMatrix = Matrix3.fromQuaternion(rotQuat, scratchHeadingPitchRangeMatrix3);
  126589. var offset = Cartesian3.clone(Cartesian3.UNIT_X, scratchLookAtHeadingPitchRangeOffset);
  126590. Matrix3.multiplyByVector(rotMatrix, offset, offset);
  126591. Cartesian3.negate(offset, offset);
  126592. Cartesian3.multiplyByScalar(offset, range, offset);
  126593. return offset;
  126594. }
  126595. /**
  126596. * Sets the camera position and orientation using a target and transformation matrix. The offset can be either a cartesian or heading/pitch/range.
  126597. * If the offset is a cartesian, then it is an offset from the center of the reference frame defined by the transformation matrix. If the offset
  126598. * is heading/pitch/range, then the heading and the pitch angles are defined in the reference frame defined by the transformation matrix.
  126599. * The heading is the angle from y axis and increasing towards the x axis. Pitch is the rotation from the xy-plane. Positive pitch
  126600. * angles are below the plane. Negative pitch angles are above the plane. The range is the distance from the center.
  126601. *
  126602. * In 2D, there must be a top down view. The camera will be placed above the center of the reference frame. The height above the
  126603. * target will be the magnitude of the offset. The heading will be determined from the offset. If the heading cannot be
  126604. * determined from the offset, the heading will be north.
  126605. *
  126606. * @param {Matrix4} transform The transformation matrix defining the reference frame.
  126607. * @param {Cartesian3|HeadingPitchRange} [offset] The offset from the target in a reference frame centered at the target.
  126608. *
  126609. * @exception {DeveloperError} lookAtTransform is not supported while morphing.
  126610. *
  126611. * @example
  126612. * // 1. Using a cartesian offset
  126613. * var transform = Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(-98.0, 40.0));
  126614. * viewer.camera.lookAtTransform(transform, new Cesium.Cartesian3(0.0, -4790000.0, 3930000.0));
  126615. *
  126616. * // 2. Using a HeadingPitchRange offset
  126617. * var transform = Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(-72.0, 40.0));
  126618. * var heading = Cesium.Math.toRadians(50.0);
  126619. * var pitch = Cesium.Math.toRadians(-20.0);
  126620. * var range = 5000.0;
  126621. * viewer.camera.lookAtTransform(transform, new Cesium.HeadingPitchRange(heading, pitch, range));
  126622. */
  126623. Camera.prototype.lookAtTransform = function(transform, offset) {
  126624. if (!defined(transform)) {
  126625. throw new DeveloperError('transform is required');
  126626. }
  126627. if (this._mode === SceneMode.MORPHING) {
  126628. throw new DeveloperError('lookAtTransform is not supported while morphing.');
  126629. }
  126630. this._setTransform(transform);
  126631. if (!defined(offset)) {
  126632. return;
  126633. }
  126634. var cartesianOffset;
  126635. if (defined(offset.heading)) {
  126636. cartesianOffset = offsetFromHeadingPitchRange(offset.heading, offset.pitch, offset.range);
  126637. } else {
  126638. cartesianOffset = offset;
  126639. }
  126640. if (this._mode === SceneMode.SCENE2D) {
  126641. Cartesian2.clone(Cartesian2.ZERO, this.position);
  126642. Cartesian3.negate(cartesianOffset, this.up);
  126643. this.up.z = 0.0;
  126644. if (Cartesian3.magnitudeSquared(this.up) < CesiumMath.EPSILON10) {
  126645. Cartesian3.clone(Cartesian3.UNIT_Y, this.up);
  126646. }
  126647. Cartesian3.normalize(this.up, this.up);
  126648. this._setTransform(Matrix4.IDENTITY);
  126649. Cartesian3.negate(Cartesian3.UNIT_Z, this.direction);
  126650. Cartesian3.cross(this.direction, this.up, this.right);
  126651. Cartesian3.normalize(this.right, this.right);
  126652. var frustum = this.frustum;
  126653. var ratio = frustum.top / frustum.right;
  126654. frustum.right = Cartesian3.magnitude(cartesianOffset) * 0.5;
  126655. frustum.left = -frustum.right;
  126656. frustum.top = ratio * frustum.right;
  126657. frustum.bottom = -frustum.top;
  126658. this._setTransform(transform);
  126659. return;
  126660. }
  126661. Cartesian3.clone(cartesianOffset, this.position);
  126662. Cartesian3.negate(this.position, this.direction);
  126663. Cartesian3.normalize(this.direction, this.direction);
  126664. Cartesian3.cross(this.direction, Cartesian3.UNIT_Z, this.right);
  126665. if (Cartesian3.magnitudeSquared(this.right) < CesiumMath.EPSILON10) {
  126666. Cartesian3.clone(Cartesian3.UNIT_X, this.right);
  126667. }
  126668. Cartesian3.normalize(this.right, this.right);
  126669. Cartesian3.cross(this.right, this.direction, this.up);
  126670. Cartesian3.normalize(this.up, this.up);
  126671. };
  126672. var viewRectangle3DCartographic1 = new Cartographic();
  126673. var viewRectangle3DCartographic2 = new Cartographic();
  126674. var viewRectangle3DNorthEast = new Cartesian3();
  126675. var viewRectangle3DSouthWest = new Cartesian3();
  126676. var viewRectangle3DNorthWest = new Cartesian3();
  126677. var viewRectangle3DSouthEast = new Cartesian3();
  126678. var viewRectangle3DNorthCenter = new Cartesian3();
  126679. var viewRectangle3DSouthCenter = new Cartesian3();
  126680. var viewRectangle3DCenter = new Cartesian3();
  126681. var viewRectangle3DEquator = new Cartesian3();
  126682. var defaultRF = {
  126683. direction : new Cartesian3(),
  126684. right : new Cartesian3(),
  126685. up : new Cartesian3()
  126686. };
  126687. var viewRectangle3DEllipsoidGeodesic;
  126688. function computeD(direction, upOrRight, corner, tanThetaOrPhi) {
  126689. var opposite = Math.abs(Cartesian3.dot(upOrRight, corner));
  126690. return opposite / tanThetaOrPhi - Cartesian3.dot(direction, corner);
  126691. }
  126692. function rectangleCameraPosition3D(camera, rectangle, result, updateCamera) {
  126693. var ellipsoid = camera._projection.ellipsoid;
  126694. var cameraRF = updateCamera ? camera : defaultRF;
  126695. var north = rectangle.north;
  126696. var south = rectangle.south;
  126697. var east = rectangle.east;
  126698. var west = rectangle.west;
  126699. // If we go across the International Date Line
  126700. if (west > east) {
  126701. east += CesiumMath.TWO_PI;
  126702. }
  126703. // Find the midpoint latitude.
  126704. //
  126705. // EllipsoidGeodesic will fail if the north and south edges are very close to being on opposite sides of the ellipsoid.
  126706. // Ideally we'd just call EllipsoidGeodesic.setEndPoints and let it throw when it detects this case, but sadly it doesn't
  126707. // even look for this case in optimized builds, so we have to test for it here instead.
  126708. //
  126709. // Fortunately, this case can only happen (here) when north is very close to the north pole and south is very close to the south pole,
  126710. // so handle it just by using 0 latitude as the center. It's certainliy possible to use a smaller tolerance
  126711. // than one degree here, but one degree is safe and putting the center at 0 latitude should be good enough for any
  126712. // rectangle that spans 178+ of the 180 degrees of latitude.
  126713. var longitude = (west + east) * 0.5;
  126714. var latitude;
  126715. if (south < -CesiumMath.PI_OVER_TWO + CesiumMath.RADIANS_PER_DEGREE && north > CesiumMath.PI_OVER_TWO - CesiumMath.RADIANS_PER_DEGREE) {
  126716. latitude = 0.0;
  126717. } else {
  126718. var northCartographic = viewRectangle3DCartographic1;
  126719. northCartographic.longitude = longitude;
  126720. northCartographic.latitude = north;
  126721. northCartographic.height = 0.0;
  126722. var southCartographic = viewRectangle3DCartographic2;
  126723. southCartographic.longitude = longitude;
  126724. southCartographic.latitude = south;
  126725. southCartographic.height = 0.0;
  126726. var ellipsoidGeodesic = viewRectangle3DEllipsoidGeodesic;
  126727. if (!defined(ellipsoidGeodesic) || ellipsoidGeodesic.ellipsoid !== ellipsoid) {
  126728. viewRectangle3DEllipsoidGeodesic = ellipsoidGeodesic = new EllipsoidGeodesic(undefined, undefined, ellipsoid);
  126729. }
  126730. ellipsoidGeodesic.setEndPoints(northCartographic, southCartographic);
  126731. latitude = ellipsoidGeodesic.interpolateUsingFraction(0.5, viewRectangle3DCartographic1).latitude;
  126732. }
  126733. var centerCartographic = viewRectangle3DCartographic1;
  126734. centerCartographic.longitude = longitude;
  126735. centerCartographic.latitude = latitude;
  126736. centerCartographic.height = 0.0;
  126737. var center = ellipsoid.cartographicToCartesian(centerCartographic, viewRectangle3DCenter);
  126738. var cart = viewRectangle3DCartographic1;
  126739. cart.longitude = east;
  126740. cart.latitude = north;
  126741. var northEast = ellipsoid.cartographicToCartesian(cart, viewRectangle3DNorthEast);
  126742. cart.longitude = west;
  126743. var northWest = ellipsoid.cartographicToCartesian(cart, viewRectangle3DNorthWest);
  126744. cart.longitude = longitude;
  126745. var northCenter = ellipsoid.cartographicToCartesian(cart, viewRectangle3DNorthCenter);
  126746. cart.latitude = south;
  126747. var southCenter = ellipsoid.cartographicToCartesian(cart, viewRectangle3DSouthCenter);
  126748. cart.longitude = east;
  126749. var southEast = ellipsoid.cartographicToCartesian(cart, viewRectangle3DSouthEast);
  126750. cart.longitude = west;
  126751. var southWest = ellipsoid.cartographicToCartesian(cart, viewRectangle3DSouthWest);
  126752. Cartesian3.subtract(northWest, center, northWest);
  126753. Cartesian3.subtract(southEast, center, southEast);
  126754. Cartesian3.subtract(northEast, center, northEast);
  126755. Cartesian3.subtract(southWest, center, southWest);
  126756. Cartesian3.subtract(northCenter, center, northCenter);
  126757. Cartesian3.subtract(southCenter, center, southCenter);
  126758. var direction = ellipsoid.geodeticSurfaceNormal(center, cameraRF.direction);
  126759. Cartesian3.negate(direction, direction);
  126760. var right = Cartesian3.cross(direction, Cartesian3.UNIT_Z, cameraRF.right);
  126761. Cartesian3.normalize(right, right);
  126762. var up = Cartesian3.cross(right, direction, cameraRF.up);
  126763. var tanPhi = Math.tan(camera.frustum.fovy * 0.5);
  126764. var tanTheta = camera.frustum.aspectRatio * tanPhi;
  126765. var d = Math.max(
  126766. computeD(direction, up, northWest, tanPhi),
  126767. computeD(direction, up, southEast, tanPhi),
  126768. computeD(direction, up, northEast, tanPhi),
  126769. computeD(direction, up, southWest, tanPhi),
  126770. computeD(direction, up, northCenter, tanPhi),
  126771. computeD(direction, up, southCenter, tanPhi),
  126772. computeD(direction, right, northWest, tanTheta),
  126773. computeD(direction, right, southEast, tanTheta),
  126774. computeD(direction, right, northEast, tanTheta),
  126775. computeD(direction, right, southWest, tanTheta),
  126776. computeD(direction, right, northCenter, tanTheta),
  126777. computeD(direction, right, southCenter, tanTheta));
  126778. // If the rectangle crosses the equator, compute D at the equator, too, because that's the
  126779. // widest part of the rectangle when projected onto the globe.
  126780. if (south < 0 && north > 0) {
  126781. var equatorCartographic = viewRectangle3DCartographic1;
  126782. equatorCartographic.longitude = west;
  126783. equatorCartographic.latitude = 0.0;
  126784. equatorCartographic.height = 0.0;
  126785. var equatorPosition = ellipsoid.cartographicToCartesian(equatorCartographic, viewRectangle3DEquator);
  126786. Cartesian3.subtract(equatorPosition, center, equatorPosition);
  126787. d = Math.max(d, computeD(direction, up, equatorPosition, tanPhi), computeD(direction, right, equatorPosition, tanTheta));
  126788. equatorCartographic.longitude = east;
  126789. equatorPosition = ellipsoid.cartographicToCartesian(equatorCartographic, viewRectangle3DEquator);
  126790. Cartesian3.subtract(equatorPosition, center, equatorPosition);
  126791. d = Math.max(d, computeD(direction, up, equatorPosition, tanPhi), computeD(direction, right, equatorPosition, tanTheta));
  126792. }
  126793. return Cartesian3.add(center, Cartesian3.multiplyByScalar(direction, -d, viewRectangle3DEquator), result);
  126794. }
  126795. var viewRectangleCVCartographic = new Cartographic();
  126796. var viewRectangleCVNorthEast = new Cartesian3();
  126797. var viewRectangleCVSouthWest = new Cartesian3();
  126798. function rectangleCameraPositionColumbusView(camera, rectangle, result) {
  126799. var projection = camera._projection;
  126800. if (rectangle.west > rectangle.east) {
  126801. rectangle = Rectangle.MAX_VALUE;
  126802. }
  126803. var transform = camera._actualTransform;
  126804. var invTransform = camera._actualInvTransform;
  126805. var cart = viewRectangleCVCartographic;
  126806. cart.longitude = rectangle.east;
  126807. cart.latitude = rectangle.north;
  126808. var northEast = projection.project(cart, viewRectangleCVNorthEast);
  126809. Matrix4.multiplyByPoint(transform, northEast, northEast);
  126810. Matrix4.multiplyByPoint(invTransform, northEast, northEast);
  126811. cart.longitude = rectangle.west;
  126812. cart.latitude = rectangle.south;
  126813. var southWest = projection.project(cart, viewRectangleCVSouthWest);
  126814. Matrix4.multiplyByPoint(transform, southWest, southWest);
  126815. Matrix4.multiplyByPoint(invTransform, southWest, southWest);
  126816. var tanPhi = Math.tan(camera.frustum.fovy * 0.5);
  126817. var tanTheta = camera.frustum.aspectRatio * tanPhi;
  126818. result.x = (northEast.x - southWest.x) * 0.5 + southWest.x;
  126819. result.y = (northEast.y - southWest.y) * 0.5 + southWest.y;
  126820. result.z = Math.max((northEast.x - southWest.x) / tanTheta, (northEast.y - southWest.y) / tanPhi) * 0.5;
  126821. return result;
  126822. }
  126823. var viewRectangle2DCartographic = new Cartographic();
  126824. var viewRectangle2DNorthEast = new Cartesian3();
  126825. var viewRectangle2DSouthWest = new Cartesian3();
  126826. function rectangleCameraPosition2D(camera, rectangle, result) {
  126827. var projection = camera._projection;
  126828. if (rectangle.west > rectangle.east) {
  126829. rectangle = Rectangle.MAX_VALUE;
  126830. }
  126831. var cart = viewRectangle2DCartographic;
  126832. cart.longitude = rectangle.east;
  126833. cart.latitude = rectangle.north;
  126834. var northEast = projection.project(cart, viewRectangle2DNorthEast);
  126835. cart.longitude = rectangle.west;
  126836. cart.latitude = rectangle.south;
  126837. var southWest = projection.project(cart, viewRectangle2DSouthWest);
  126838. var width = Math.abs(northEast.x - southWest.x) * 0.5;
  126839. var height = Math.abs(northEast.y - southWest.y) * 0.5;
  126840. var right, top;
  126841. var ratio = camera.frustum.right / camera.frustum.top;
  126842. var heightRatio = height * ratio;
  126843. if (width > heightRatio) {
  126844. right = width;
  126845. top = right / ratio;
  126846. } else {
  126847. top = height;
  126848. right = heightRatio;
  126849. }
  126850. height = Math.max(2.0 * right, 2.0 * top);
  126851. result.x = (northEast.x - southWest.x) * 0.5 + southWest.x;
  126852. result.y = (northEast.y - southWest.y) * 0.5 + southWest.y;
  126853. cart = projection.unproject(result, cart);
  126854. cart.height = height;
  126855. result = projection.project(cart, result);
  126856. return result;
  126857. }
  126858. /**
  126859. * Get the camera position needed to view an rectangle on an ellipsoid or map
  126860. *
  126861. * @param {Rectangle} rectangle The rectangle to view.
  126862. * @param {Cartesian3} [result] The camera position needed to view the rectangle
  126863. * @returns {Cartesian3} The camera position needed to view the rectangle
  126864. */
  126865. Camera.prototype.getRectangleCameraCoordinates = function(rectangle, result) {
  126866. if (!defined(rectangle)) {
  126867. throw new DeveloperError('rectangle is required');
  126868. }
  126869. var mode = this._mode;
  126870. if (!defined(result)) {
  126871. result = new Cartesian3();
  126872. }
  126873. if (mode === SceneMode.SCENE3D) {
  126874. return rectangleCameraPosition3D(this, rectangle, result);
  126875. } else if (mode === SceneMode.COLUMBUS_VIEW) {
  126876. return rectangleCameraPositionColumbusView(this, rectangle, result);
  126877. } else if (mode === SceneMode.SCENE2D) {
  126878. return rectangleCameraPosition2D(this, rectangle, result);
  126879. }
  126880. return undefined;
  126881. };
  126882. var pickEllipsoid3DRay = new Ray();
  126883. function pickEllipsoid3D(camera, windowPosition, ellipsoid, result) {
  126884. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  126885. var ray = camera.getPickRay(windowPosition, pickEllipsoid3DRay);
  126886. var intersection = IntersectionTests.rayEllipsoid(ray, ellipsoid);
  126887. if (!intersection) {
  126888. return undefined;
  126889. }
  126890. var t = intersection.start > 0.0 ? intersection.start : intersection.stop;
  126891. return Ray.getPoint(ray, t, result);
  126892. }
  126893. var pickEllipsoid2DRay = new Ray();
  126894. function pickMap2D(camera, windowPosition, projection, result) {
  126895. var ray = camera.getPickRay(windowPosition, pickEllipsoid2DRay);
  126896. var position = ray.origin;
  126897. position.z = 0.0;
  126898. var cart = projection.unproject(position);
  126899. if (cart.latitude < -CesiumMath.PI_OVER_TWO || cart.latitude > CesiumMath.PI_OVER_TWO) {
  126900. return undefined;
  126901. }
  126902. return projection.ellipsoid.cartographicToCartesian(cart, result);
  126903. }
  126904. var pickEllipsoidCVRay = new Ray();
  126905. function pickMapColumbusView(camera, windowPosition, projection, result) {
  126906. var ray = camera.getPickRay(windowPosition, pickEllipsoidCVRay);
  126907. var scalar = -ray.origin.x / ray.direction.x;
  126908. Ray.getPoint(ray, scalar, result);
  126909. var cart = projection.unproject(new Cartesian3(result.y, result.z, 0.0));
  126910. if (cart.latitude < -CesiumMath.PI_OVER_TWO || cart.latitude > CesiumMath.PI_OVER_TWO ||
  126911. cart.longitude < -Math.PI || cart.longitude > Math.PI) {
  126912. return undefined;
  126913. }
  126914. return projection.ellipsoid.cartographicToCartesian(cart, result);
  126915. }
  126916. /**
  126917. * Pick an ellipsoid or map.
  126918. *
  126919. * @param {Cartesian2} windowPosition The x and y coordinates of a pixel.
  126920. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid to pick.
  126921. * @param {Cartesian3} [result] The object onto which to store the result.
  126922. * @returns {Cartesian3} If the ellipsoid or map was picked, returns the point on the surface of the ellipsoid or map
  126923. * in world coordinates. If the ellipsoid or map was not picked, returns undefined.
  126924. */
  126925. Camera.prototype.pickEllipsoid = function(windowPosition, ellipsoid, result) {
  126926. if (!defined(windowPosition)) {
  126927. throw new DeveloperError('windowPosition is required.');
  126928. }
  126929. if (!defined(result)) {
  126930. result = new Cartesian3();
  126931. }
  126932. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  126933. if (this._mode === SceneMode.SCENE3D) {
  126934. result = pickEllipsoid3D(this, windowPosition, ellipsoid, result);
  126935. } else if (this._mode === SceneMode.SCENE2D) {
  126936. result = pickMap2D(this, windowPosition, this._projection, result);
  126937. } else if (this._mode === SceneMode.COLUMBUS_VIEW) {
  126938. result = pickMapColumbusView(this, windowPosition, this._projection, result);
  126939. } else {
  126940. return undefined;
  126941. }
  126942. return result;
  126943. };
  126944. var pickPerspCenter = new Cartesian3();
  126945. var pickPerspXDir = new Cartesian3();
  126946. var pickPerspYDir = new Cartesian3();
  126947. function getPickRayPerspective(camera, windowPosition, result) {
  126948. var canvas = camera._scene.canvas;
  126949. var width = canvas.clientWidth;
  126950. var height = canvas.clientHeight;
  126951. var tanPhi = Math.tan(camera.frustum.fovy * 0.5);
  126952. var tanTheta = camera.frustum.aspectRatio * tanPhi;
  126953. var near = camera.frustum.near;
  126954. var x = (2.0 / width) * windowPosition.x - 1.0;
  126955. var y = (2.0 / height) * (height - windowPosition.y) - 1.0;
  126956. var position = camera.positionWC;
  126957. Cartesian3.clone(position, result.origin);
  126958. var nearCenter = Cartesian3.multiplyByScalar(camera.directionWC, near, pickPerspCenter);
  126959. Cartesian3.add(position, nearCenter, nearCenter);
  126960. var xDir = Cartesian3.multiplyByScalar(camera.rightWC, x * near * tanTheta, pickPerspXDir);
  126961. var yDir = Cartesian3.multiplyByScalar(camera.upWC, y * near * tanPhi, pickPerspYDir);
  126962. var direction = Cartesian3.add(nearCenter, xDir, result.direction);
  126963. Cartesian3.add(direction, yDir, direction);
  126964. Cartesian3.subtract(direction, position, direction);
  126965. Cartesian3.normalize(direction, direction);
  126966. return result;
  126967. }
  126968. var scratchDirection = new Cartesian3();
  126969. function getPickRayOrthographic(camera, windowPosition, result) {
  126970. var canvas = camera._scene.canvas;
  126971. var width = canvas.clientWidth;
  126972. var height = canvas.clientHeight;
  126973. var x = (2.0 / width) * windowPosition.x - 1.0;
  126974. x *= (camera.frustum.right - camera.frustum.left) * 0.5;
  126975. var y = (2.0 / height) * (height - windowPosition.y) - 1.0;
  126976. y *= (camera.frustum.top - camera.frustum.bottom) * 0.5;
  126977. var origin = result.origin;
  126978. Cartesian3.clone(camera.position, origin);
  126979. Cartesian3.multiplyByScalar(camera.right, x, scratchDirection);
  126980. Cartesian3.add(scratchDirection, origin, origin);
  126981. Cartesian3.multiplyByScalar(camera.up, y, scratchDirection);
  126982. Cartesian3.add(scratchDirection, origin, origin);
  126983. Cartesian3.clone(camera.directionWC, result.direction);
  126984. return result;
  126985. }
  126986. /**
  126987. * Create a ray from the camera position through the pixel at <code>windowPosition</code>
  126988. * in world coordinates.
  126989. *
  126990. * @param {Cartesian2} windowPosition The x and y coordinates of a pixel.
  126991. * @param {Ray} [result] The object onto which to store the result.
  126992. * @returns {Ray} Returns the {@link Cartesian3} position and direction of the ray.
  126993. */
  126994. Camera.prototype.getPickRay = function(windowPosition, result) {
  126995. if (!defined(windowPosition)) {
  126996. throw new DeveloperError('windowPosition is required.');
  126997. }
  126998. if (!defined(result)) {
  126999. result = new Ray();
  127000. }
  127001. var frustum = this.frustum;
  127002. if (defined(frustum.aspectRatio) && defined(frustum.fov) && defined(frustum.near)) {
  127003. return getPickRayPerspective(this, windowPosition, result);
  127004. }
  127005. return getPickRayOrthographic(this, windowPosition, result);
  127006. };
  127007. var scratchToCenter = new Cartesian3();
  127008. var scratchProj = new Cartesian3();
  127009. /**
  127010. * Return the distance from the camera to the front of the bounding sphere.
  127011. *
  127012. * @param {BoundingSphere} boundingSphere The bounding sphere in world coordinates.
  127013. * @returns {Number} The distance to the bounding sphere.
  127014. */
  127015. Camera.prototype.distanceToBoundingSphere = function(boundingSphere) {
  127016. if (!defined(boundingSphere)) {
  127017. throw new DeveloperError('boundingSphere is required.');
  127018. }
  127019. var toCenter = Cartesian3.subtract(this.positionWC, boundingSphere.center, scratchToCenter);
  127020. var proj = Cartesian3.multiplyByScalar(this.directionWC, Cartesian3.dot(toCenter, this.directionWC), scratchProj);
  127021. return Math.max(0.0, Cartesian3.magnitude(proj) - boundingSphere.radius);
  127022. };
  127023. var scratchPixelSize = new Cartesian2();
  127024. /**
  127025. * Return the pixel size in meters.
  127026. *
  127027. * @param {BoundingSphere} boundingSphere The bounding sphere in world coordinates.
  127028. * @param {Number} drawingBufferWidth The drawing buffer width.
  127029. * @param {Number} drawingBufferHeight The drawing buffer height.
  127030. * @returns {Number} The pixel size in meters.
  127031. */
  127032. Camera.prototype.getPixelSize = function(boundingSphere, drawingBufferWidth, drawingBufferHeight) {
  127033. if (!defined(boundingSphere)) {
  127034. throw new DeveloperError('boundingSphere is required.');
  127035. }
  127036. if (!defined(drawingBufferWidth)) {
  127037. throw new DeveloperError('drawingBufferWidth is required.');
  127038. }
  127039. if (!defined(drawingBufferHeight)) {
  127040. throw new DeveloperError('drawingBufferHeight is required.');
  127041. }
  127042. var distance = this.distanceToBoundingSphere(boundingSphere);
  127043. var pixelSize = this.frustum.getPixelDimensions(drawingBufferWidth, drawingBufferHeight, distance, scratchPixelSize);
  127044. return Math.max(pixelSize.x, pixelSize.y);
  127045. };
  127046. function createAnimationTemplateCV(camera, position, center, maxX, maxY, duration) {
  127047. var newPosition = Cartesian3.clone(position);
  127048. if (center.y > maxX) {
  127049. newPosition.y -= center.y - maxX;
  127050. } else if (center.y < -maxX) {
  127051. newPosition.y += -maxX - center.y;
  127052. }
  127053. if (center.z > maxY) {
  127054. newPosition.z -= center.z - maxY;
  127055. } else if (center.z < -maxY) {
  127056. newPosition.z += -maxY - center.z;
  127057. }
  127058. function updateCV(value) {
  127059. var interp = Cartesian3.lerp(position, newPosition, value.time, new Cartesian3());
  127060. camera.worldToCameraCoordinatesPoint(interp, camera.position);
  127061. }
  127062. return {
  127063. easingFunction : EasingFunction.EXPONENTIAL_OUT,
  127064. startObject : {
  127065. time : 0.0
  127066. },
  127067. stopObject : {
  127068. time : 1.0
  127069. },
  127070. duration : duration,
  127071. update : updateCV
  127072. };
  127073. }
  127074. var normalScratch = new Cartesian3();
  127075. var centerScratch = new Cartesian3();
  127076. var posScratch = new Cartesian3();
  127077. var scratchCartesian3Subtract = new Cartesian3();
  127078. function createAnimationCV(camera, duration) {
  127079. var position = camera.position;
  127080. var direction = camera.direction;
  127081. var normal = camera.worldToCameraCoordinatesVector(Cartesian3.UNIT_X, normalScratch);
  127082. var scalar = -Cartesian3.dot(normal, position) / Cartesian3.dot(normal, direction);
  127083. var center = Cartesian3.add(position, Cartesian3.multiplyByScalar(direction, scalar, centerScratch), centerScratch);
  127084. camera.cameraToWorldCoordinatesPoint(center, center);
  127085. position = camera.cameraToWorldCoordinatesPoint(camera.position, posScratch);
  127086. var tanPhi = Math.tan(camera.frustum.fovy * 0.5);
  127087. var tanTheta = camera.frustum.aspectRatio * tanPhi;
  127088. var distToC = Cartesian3.magnitude(Cartesian3.subtract(position, center, scratchCartesian3Subtract));
  127089. var dWidth = tanTheta * distToC;
  127090. var dHeight = tanPhi * distToC;
  127091. var mapWidth = camera._maxCoord.x;
  127092. var mapHeight = camera._maxCoord.y;
  127093. var maxX = Math.max(dWidth - mapWidth, mapWidth);
  127094. var maxY = Math.max(dHeight - mapHeight, mapHeight);
  127095. if (position.z < -maxX || position.z > maxX || position.y < -maxY || position.y > maxY) {
  127096. var translateX = center.y < -maxX || center.y > maxX;
  127097. var translateY = center.z < -maxY || center.z > maxY;
  127098. if (translateX || translateY) {
  127099. return createAnimationTemplateCV(camera, position, center, maxX, maxY, duration);
  127100. }
  127101. }
  127102. return undefined;
  127103. }
  127104. /**
  127105. * Create an animation to move the map into view. This method is only valid for 2D and Columbus modes.
  127106. *
  127107. * @param {Number} duration The duration, in seconds, of the animation.
  127108. * @returns {Object} The animation or undefined if the scene mode is 3D or the map is already ion view.
  127109. *
  127110. * @private
  127111. */
  127112. Camera.prototype.createCorrectPositionTween = function(duration) {
  127113. if (!defined(duration)) {
  127114. throw new DeveloperError('duration is required.');
  127115. }
  127116. if (this._mode === SceneMode.COLUMBUS_VIEW) {
  127117. return createAnimationCV(this, duration);
  127118. }
  127119. return undefined;
  127120. };
  127121. var scratchFlyToDestination = new Cartesian3();
  127122. var newOptions = {
  127123. destination : undefined,
  127124. heading : undefined,
  127125. pitch : undefined,
  127126. roll : undefined,
  127127. duration : undefined,
  127128. complete : undefined,
  127129. cancel : undefined,
  127130. endTransform : undefined,
  127131. maximumHeight : undefined,
  127132. easingFunction : undefined
  127133. };
  127134. /**
  127135. * Cancels the current camera flight if one is in progress.
  127136. * The camera is left at it's current location.
  127137. */
  127138. Camera.prototype.cancelFlight = function () {
  127139. if (defined(this._currentFlight)) {
  127140. this._currentFlight.cancelTween();
  127141. this._currentFlight = undefined;
  127142. }
  127143. };
  127144. /**
  127145. * Flies the camera from its current position to a new position.
  127146. *
  127147. * @param {Object} options Object with the following properties:
  127148. * @param {Cartesian3|Rectangle} options.destination The final position of the camera in WGS84 (world) coordinates or a rectangle that would be visible from a top-down view.
  127149. * @param {Object} [options.orientation] An object that contains either direction and up properties or heading, pith and roll properties. By default, the direction will point
  127150. * towards the center of the frame in 3D and in the negative z direction in Columbus view. The up direction will point towards local north in 3D and in the positive
  127151. * y direction in Columbus view. Orientation is not used in 2D when in infinite scrolling mode.
  127152. * @param {Number} [options.duration] The duration of the flight in seconds. If omitted, Cesium attempts to calculate an ideal duration based on the distance to be traveled by the flight.
  127153. * @param {Camera~FlightCompleteCallback} [options.complete] The function to execute when the flight is complete.
  127154. * @param {Camera~FlightCancelledCallback} [options.cancel] The function to execute if the flight is cancelled.
  127155. * @param {Matrix4} [options.endTransform] Transform matrix representing the reference frame the camera will be in when the flight is completed.
  127156. * @param {Number} [options.maximumHeight] The maximum height at the peak of the flight.
  127157. * @param {EasingFunction|EasingFunction~Callback} [options.easingFunction] Controls how the time is interpolated over the duration of the flight.
  127158. *
  127159. * @exception {DeveloperError} If either direction or up is given, then both are required.
  127160. *
  127161. * @example
  127162. * // 1. Fly to a position with a top-down view
  127163. * viewer.camera.flyTo({
  127164. * destination : Cesium.Cartesian3.fromDegrees(-117.16, 32.71, 15000.0)
  127165. * });
  127166. *
  127167. * // 2. Fly to a Rectangle with a top-down view
  127168. * viewer.camera.flyTo({
  127169. * destination : Cesium.Rectangle.fromDegrees(west, south, east, north)
  127170. * });
  127171. *
  127172. * // 3. Fly to a position with an orientation using unit vectors.
  127173. * viewer.camera.flyTo({
  127174. * destination : Cesium.Cartesian3.fromDegrees(-122.19, 46.25, 5000.0),
  127175. * orientation : {
  127176. * direction : new Cesium.Cartesian3(-0.04231243104240401, -0.20123236049443421, -0.97862924300734),
  127177. * up : new Cesium.Cartesian3(-0.47934589305293746, -0.8553216253114552, 0.1966022179118339)
  127178. * }
  127179. * });
  127180. *
  127181. * // 4. Fly to a position with an orientation using heading, pitch and roll.
  127182. * viewer.camera.flyTo({
  127183. * destination : Cesium.Cartesian3.fromDegrees(-122.19, 46.25, 5000.0),
  127184. * orientation : {
  127185. * heading : Cesium.Math.toRadians(175.0),
  127186. * pitch : Cesium.Math.toRadians(-35.0),
  127187. * roll : 0.0
  127188. * }
  127189. * });
  127190. */
  127191. Camera.prototype.flyTo = function(options) {
  127192. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  127193. var destination = options.destination;
  127194. if (!defined(destination)) {
  127195. throw new DeveloperError('destination is required.');
  127196. }
  127197. var mode = this._mode;
  127198. if (mode === SceneMode.MORPHING) {
  127199. return;
  127200. }
  127201. this.cancelFlight();
  127202. var orientation = defaultValue(options.orientation, defaultValue.EMPTY_OBJECT);
  127203. if (defined(orientation.direction)) {
  127204. orientation = directionUpToHeadingPitchRoll(this, destination, orientation, scratchSetViewOptions.orientation);
  127205. }
  127206. if (defined(options.duration) && options.duration <= 0.0) {
  127207. var setViewOptions = scratchSetViewOptions;
  127208. setViewOptions.destination = options.destination;
  127209. setViewOptions.orientation.heading = orientation.heading;
  127210. setViewOptions.orientation.pitch = orientation.pitch;
  127211. setViewOptions.orientation.roll = orientation.roll;
  127212. setViewOptions.convert = options.convert;
  127213. setViewOptions.endTransform = options.endTransform;
  127214. this.setView(setViewOptions);
  127215. if (typeof options.complete === 'function') {
  127216. options.complete();
  127217. }
  127218. return;
  127219. }
  127220. var isRectangle = defined(destination.west);
  127221. if (isRectangle) {
  127222. destination = this.getRectangleCameraCoordinates(destination, scratchFlyToDestination);
  127223. }
  127224. var that = this;
  127225. var flightTween;
  127226. newOptions.destination = destination;
  127227. newOptions.heading = orientation.heading;
  127228. newOptions.pitch = orientation.pitch;
  127229. newOptions.roll = orientation.roll;
  127230. newOptions.duration = options.duration;
  127231. newOptions.complete = function () {
  127232. if(flightTween === that._currentFlight){
  127233. that._currentFlight = undefined;
  127234. }
  127235. if (defined(options.complete)) {
  127236. options.complete();
  127237. }
  127238. };
  127239. newOptions.cancel = options.cancel;
  127240. newOptions.endTransform = options.endTransform;
  127241. newOptions.convert = isRectangle ? false : options.convert;
  127242. newOptions.maximumHeight = options.maximumHeight;
  127243. newOptions.easingFunction = options.easingFunction;
  127244. var scene = this._scene;
  127245. flightTween = scene.tweens.add(CameraFlightPath.createTween(scene, newOptions));
  127246. this._currentFlight = flightTween;
  127247. };
  127248. function distanceToBoundingSphere3D(camera, radius) {
  127249. var frustum = camera.frustum;
  127250. var tanPhi = Math.tan(frustum.fovy * 0.5);
  127251. var tanTheta = frustum.aspectRatio * tanPhi;
  127252. return Math.max(radius / tanTheta, radius / tanPhi);
  127253. }
  127254. function distanceToBoundingSphere2D(camera, radius) {
  127255. var frustum = camera.frustum;
  127256. var right, top;
  127257. var ratio = frustum.right / frustum.top;
  127258. var heightRatio = radius * ratio;
  127259. if (radius > heightRatio) {
  127260. right = radius;
  127261. top = right / ratio;
  127262. } else {
  127263. top = radius;
  127264. right = heightRatio;
  127265. }
  127266. return Math.max(right, top) * 1.50;
  127267. }
  127268. var scratchDefaultOffset = new HeadingPitchRange(0.0, -CesiumMath.PI_OVER_FOUR, 0.0);
  127269. var MINIMUM_ZOOM = 100.0;
  127270. function adjustBoundingSphereOffset(camera, boundingSphere, offset) {
  127271. if (!defined(offset)) {
  127272. offset = HeadingPitchRange.clone(scratchDefaultOffset);
  127273. }
  127274. var range = offset.range;
  127275. if (!defined(range) || range === 0.0) {
  127276. var radius = boundingSphere.radius;
  127277. if (radius === 0.0) {
  127278. offset.range = MINIMUM_ZOOM;
  127279. } else {
  127280. offset.range = camera._mode === SceneMode.SCENE2D ? distanceToBoundingSphere2D(camera, radius) : distanceToBoundingSphere3D(camera, radius);
  127281. }
  127282. }
  127283. return offset;
  127284. }
  127285. /**
  127286. * Sets the camera so that the current view contains the provided bounding sphere.
  127287. *
  127288. * <p>The offset is heading/pitch/range in the local east-north-up reference frame centered at the center of the bounding sphere.
  127289. * The heading and the pitch angles are defined in the local east-north-up reference frame.
  127290. * The heading is the angle from y axis and increasing towards the x axis. Pitch is the rotation from the xy-plane. Positive pitch
  127291. * angles are below the plane. Negative pitch angles are above the plane. The range is the distance from the center. If the range is
  127292. * zero, a range will be computed such that the whole bounding sphere is visible.</p>
  127293. *
  127294. * <p>In 2D, there must be a top down view. The camera will be placed above the target looking down. The height above the
  127295. * target will be the range. The heading will be determined from the offset. If the heading cannot be
  127296. * determined from the offset, the heading will be north.</p>
  127297. *
  127298. * @param {BoundingSphere} boundingSphere The bounding sphere to view, in world coordinates.
  127299. * @param {HeadingPitchRange} [offset] The offset from the target in the local east-north-up reference frame centered at the target.
  127300. *
  127301. * @exception {DeveloperError} viewBoundingSphere is not supported while morphing.
  127302. */
  127303. Camera.prototype.viewBoundingSphere = function(boundingSphere, offset) {
  127304. if (!defined(boundingSphere)) {
  127305. throw new DeveloperError('boundingSphere is required.');
  127306. }
  127307. if (this._mode === SceneMode.MORPHING) {
  127308. throw new DeveloperError('viewBoundingSphere is not supported while morphing.');
  127309. }
  127310. offset = adjustBoundingSphereOffset(this, boundingSphere, offset);
  127311. this.lookAt(boundingSphere.center, offset);
  127312. };
  127313. var scratchflyToBoundingSphereTransform = new Matrix4();
  127314. var scratchflyToBoundingSphereDestination = new Cartesian3();
  127315. var scratchflyToBoundingSphereDirection = new Cartesian3();
  127316. var scratchflyToBoundingSphereUp = new Cartesian3();
  127317. var scratchflyToBoundingSphereRight = new Cartesian3();
  127318. var scratchFlyToBoundingSphereCart4 = new Cartesian4();
  127319. var scratchFlyToBoundingSphereQuaternion = new Quaternion();
  127320. var scratchFlyToBoundingSphereMatrix3 = new Matrix3();
  127321. /**
  127322. * Flies the camera to a location where the current view contains the provided bounding sphere.
  127323. *
  127324. * <p> The offset is heading/pitch/range in the local east-north-up reference frame centered at the center of the bounding sphere.
  127325. * The heading and the pitch angles are defined in the local east-north-up reference frame.
  127326. * The heading is the angle from y axis and increasing towards the x axis. Pitch is the rotation from the xy-plane. Positive pitch
  127327. * angles are below the plane. Negative pitch angles are above the plane. The range is the distance from the center. If the range is
  127328. * zero, a range will be computed such that the whole bounding sphere is visible.</p>
  127329. *
  127330. * <p>In 2D and Columbus View, there must be a top down view. The camera will be placed above the target looking down. The height above the
  127331. * target will be the range. The heading will be aligned to local north.</p>
  127332. *
  127333. * @param {BoundingSphere} boundingSphere The bounding sphere to view, in world coordinates.
  127334. * @param {Object} [options] Object with the following properties:
  127335. * @param {Number} [options.duration] The duration of the flight in seconds. If omitted, Cesium attempts to calculate an ideal duration based on the distance to be traveled by the flight.
  127336. * @param {HeadingPitchRange} [options.offset] The offset from the target in the local east-north-up reference frame centered at the target.
  127337. * @param {Camera~FlightCompleteCallback} [options.complete] The function to execute when the flight is complete.
  127338. * @param {Camera~FlightCancelledCallback} [options.cancel] The function to execute if the flight is cancelled.
  127339. * @param {Matrix4} [options.endTransform] Transform matrix representing the reference frame the camera will be in when the flight is completed.
  127340. * @param {Number} [options.maximumHeight] The maximum height at the peak of the flight.
  127341. * @param {EasingFunction|EasingFunction~Callback} [options.easingFunction] Controls how the time is interpolated over the duration of the flight.
  127342. */
  127343. Camera.prototype.flyToBoundingSphere = function(boundingSphere, options) {
  127344. if (!defined(boundingSphere)) {
  127345. throw new DeveloperError('boundingSphere is required.');
  127346. }
  127347. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  127348. var scene2D = this._mode === SceneMode.SCENE2D || this._mode === SceneMode.COLUMBUS_VIEW;
  127349. this._setTransform(Matrix4.IDENTITY);
  127350. var offset = adjustBoundingSphereOffset(this, boundingSphere, options.offset);
  127351. var position;
  127352. if (scene2D) {
  127353. position = Cartesian3.multiplyByScalar(Cartesian3.UNIT_Z, offset.range, scratchflyToBoundingSphereDestination);
  127354. } else {
  127355. position = offsetFromHeadingPitchRange(offset.heading, offset.pitch, offset.range);
  127356. }
  127357. var transform = Transforms.eastNorthUpToFixedFrame(boundingSphere.center, Ellipsoid.WGS84, scratchflyToBoundingSphereTransform);
  127358. Matrix4.multiplyByPoint(transform, position, position);
  127359. var direction;
  127360. var up;
  127361. if (!scene2D) {
  127362. direction = Cartesian3.subtract(boundingSphere.center, position, scratchflyToBoundingSphereDirection);
  127363. Cartesian3.normalize(direction, direction);
  127364. up = Matrix4.multiplyByPointAsVector(transform, Cartesian3.UNIT_Z, scratchflyToBoundingSphereUp);
  127365. if (1.0 - Math.abs(Cartesian3.dot(direction, up)) < CesiumMath.EPSILON6) {
  127366. var rotateQuat = Quaternion.fromAxisAngle(direction, offset.heading, scratchFlyToBoundingSphereQuaternion);
  127367. var rotation = Matrix3.fromQuaternion(rotateQuat, scratchFlyToBoundingSphereMatrix3);
  127368. Cartesian3.fromCartesian4(Matrix4.getColumn(transform, 1, scratchFlyToBoundingSphereCart4), up);
  127369. Matrix3.multiplyByVector(rotation, up, up);
  127370. }
  127371. var right = Cartesian3.cross(direction, up, scratchflyToBoundingSphereRight);
  127372. Cartesian3.cross(right, direction, up);
  127373. Cartesian3.normalize(up, up);
  127374. }
  127375. this.flyTo({
  127376. destination : position,
  127377. orientation : {
  127378. direction : direction,
  127379. up : up
  127380. },
  127381. duration : options.duration,
  127382. complete : options.complete,
  127383. cancel : options.cancel,
  127384. endTransform : options.endTransform,
  127385. maximumHeight : options.maximumHeight,
  127386. easingFunction : options.easingFunction
  127387. });
  127388. };
  127389. var scratchCartesian3_1 = new Cartesian3();
  127390. var scratchCartesian3_2 = new Cartesian3();
  127391. var scratchCartesian3_3 = new Cartesian3();
  127392. var scratchCartesian3_4 = new Cartesian3();
  127393. var horizonPoints = [new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3()];
  127394. function computeHorizonQuad(camera, ellipsoid) {
  127395. var radii = ellipsoid.radii;
  127396. var p = camera.positionWC;
  127397. // Find the corresponding position in the scaled space of the ellipsoid.
  127398. var q = Cartesian3.multiplyComponents(ellipsoid.oneOverRadii, p, scratchCartesian3_1);
  127399. var qMagnitude = Cartesian3.magnitude(q);
  127400. var qUnit = Cartesian3.normalize(q, scratchCartesian3_2);
  127401. // Determine the east and north directions at q.
  127402. var eUnit;
  127403. var nUnit;
  127404. if (Cartesian3.equalsEpsilon(qUnit, Cartesian3.UNIT_Z, CesiumMath.EPSILON10)) {
  127405. eUnit = new Cartesian3(0, 1, 0);
  127406. nUnit = new Cartesian3(0, 0, 1);
  127407. } else {
  127408. eUnit = Cartesian3.normalize(Cartesian3.cross(Cartesian3.UNIT_Z, qUnit, scratchCartesian3_3), scratchCartesian3_3);
  127409. nUnit = Cartesian3.normalize(Cartesian3.cross(qUnit, eUnit, scratchCartesian3_4), scratchCartesian3_4);
  127410. }
  127411. // Determine the radius of the 'limb' of the ellipsoid.
  127412. var wMagnitude = Math.sqrt(Cartesian3.magnitudeSquared(q) - 1.0);
  127413. // Compute the center and offsets.
  127414. var center = Cartesian3.multiplyByScalar(qUnit, 1.0 / qMagnitude, scratchCartesian3_1);
  127415. var scalar = wMagnitude / qMagnitude;
  127416. var eastOffset = Cartesian3.multiplyByScalar(eUnit, scalar, scratchCartesian3_2);
  127417. var northOffset = Cartesian3.multiplyByScalar(nUnit, scalar, scratchCartesian3_3);
  127418. // A conservative measure for the longitudes would be to use the min/max longitudes of the bounding frustum.
  127419. var upperLeft = Cartesian3.add(center, northOffset, horizonPoints[0]);
  127420. Cartesian3.subtract(upperLeft, eastOffset, upperLeft);
  127421. Cartesian3.multiplyComponents(radii, upperLeft, upperLeft);
  127422. var lowerLeft = Cartesian3.subtract(center, northOffset, horizonPoints[1]);
  127423. Cartesian3.subtract(lowerLeft, eastOffset, lowerLeft);
  127424. Cartesian3.multiplyComponents(radii, lowerLeft, lowerLeft);
  127425. var lowerRight = Cartesian3.subtract(center, northOffset, horizonPoints[2]);
  127426. Cartesian3.add(lowerRight, eastOffset, lowerRight);
  127427. Cartesian3.multiplyComponents(radii, lowerRight, lowerRight);
  127428. var upperRight = Cartesian3.add(center, northOffset, horizonPoints[3]);
  127429. Cartesian3.add(upperRight, eastOffset, upperRight);
  127430. Cartesian3.multiplyComponents(radii, upperRight, upperRight);
  127431. return horizonPoints;
  127432. }
  127433. var scratchPickCartesian2 = new Cartesian2();
  127434. var scratchRectCartesian = new Cartesian3();
  127435. var cartoArray = [new Cartographic(), new Cartographic(), new Cartographic(), new Cartographic()];
  127436. function addToResult(x, y, index, camera, ellipsoid, computedHorizonQuad) {
  127437. scratchPickCartesian2.x = x;
  127438. scratchPickCartesian2.y = y;
  127439. var r = camera.pickEllipsoid(scratchPickCartesian2, ellipsoid, scratchRectCartesian);
  127440. if (defined(r)) {
  127441. cartoArray[index] = ellipsoid.cartesianToCartographic(r, cartoArray[index]);
  127442. return 1;
  127443. }
  127444. cartoArray[index] = ellipsoid.cartesianToCartographic(computedHorizonQuad[index], cartoArray[index]);
  127445. return 0;
  127446. }
  127447. /**
  127448. * Computes the approximate visible rectangle on the ellipsoid.
  127449. *
  127450. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid that you want to know the visible region.
  127451. * @param {Rectangle} [result] The rectangle in which to store the result
  127452. *
  127453. * @returns {Rectangle|undefined} The visible rectangle or undefined if the ellipsoid isn't visible at all.
  127454. */
  127455. Camera.prototype.computeViewRectangle = function(ellipsoid, result) {
  127456. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  127457. var cullingVolume = this.frustum.computeCullingVolume(this.positionWC, this.directionWC, this.upWC);
  127458. var boundingSphere = new BoundingSphere(Cartesian3.ZERO, ellipsoid.maximumRadius);
  127459. var visibility = cullingVolume.computeVisibility(boundingSphere);
  127460. if (visibility === Intersect.OUTSIDE) {
  127461. return undefined;
  127462. }
  127463. var canvas = this._scene.canvas;
  127464. var width = canvas.clientWidth;
  127465. var height = canvas.clientHeight;
  127466. var successfulPickCount = 0;
  127467. var computedHorizonQuad = computeHorizonQuad(this, ellipsoid);
  127468. successfulPickCount += addToResult(0, 0, 0, this, ellipsoid, computedHorizonQuad);
  127469. successfulPickCount += addToResult(0, height, 1, this, ellipsoid, computedHorizonQuad);
  127470. successfulPickCount += addToResult(width, height, 2, this, ellipsoid, computedHorizonQuad);
  127471. successfulPickCount += addToResult(width, 0, 3, this, ellipsoid, computedHorizonQuad);
  127472. if (successfulPickCount < 2) {
  127473. // If we have space non-globe in 3 or 4 corners then return the whole globe
  127474. return Rectangle.MAX_VALUE;
  127475. }
  127476. result = Rectangle.fromCartographicArray(cartoArray, result);
  127477. // Detect if we go over the poles
  127478. var distance = 0;
  127479. var lastLon = cartoArray[3].longitude;
  127480. for (var i = 0; i < 4; ++i) {
  127481. var lon = cartoArray[i].longitude;
  127482. var diff = Math.abs(lon - lastLon);
  127483. if (diff > CesiumMath.PI) {
  127484. // Crossed the dateline
  127485. distance += CesiumMath.TWO_PI - diff;
  127486. } else {
  127487. distance += diff;
  127488. }
  127489. lastLon = lon;
  127490. }
  127491. // We are over one of the poles so adjust the rectangle accordingly
  127492. if (CesiumMath.equalsEpsilon(Math.abs(distance), CesiumMath.TWO_PI, CesiumMath.EPSILON9)) {
  127493. result.west = -CesiumMath.PI;
  127494. result.east = CesiumMath.PI;
  127495. if (cartoArray[0].latitude >= 0.0) {
  127496. result.north = CesiumMath.PI_OVER_TWO;
  127497. } else {
  127498. result.south = -CesiumMath.PI_OVER_TWO;
  127499. }
  127500. }
  127501. return result;
  127502. };
  127503. /**
  127504. * @private
  127505. */
  127506. Camera.clone = function(camera, result) {
  127507. if (!defined(result)) {
  127508. result = new Camera(camera._scene);
  127509. }
  127510. Cartesian3.clone(camera.position, result.position);
  127511. Cartesian3.clone(camera.direction, result.direction);
  127512. Cartesian3.clone(camera.up, result.up);
  127513. Cartesian3.clone(camera.right, result.right);
  127514. Matrix4.clone(camera._transform, result.transform);
  127515. result._transformChanged = true;
  127516. return result;
  127517. };
  127518. /**
  127519. * A function that will execute when a flight completes.
  127520. * @callback Camera~FlightCompleteCallback
  127521. */
  127522. /**
  127523. * A function that will execute when a flight is cancelled.
  127524. * @callback Camera~FlightCancelledCallback
  127525. */
  127526. return Camera;
  127527. });
  127528. /*global define*/
  127529. define('Scene/CameraEventType',[
  127530. '../Core/freezeObject'
  127531. ], function(
  127532. freezeObject) {
  127533. 'use strict';
  127534. /**
  127535. * Enumerates the available input for interacting with the camera.
  127536. *
  127537. * @exports CameraEventType
  127538. */
  127539. var CameraEventType = {
  127540. /**
  127541. * A left mouse button press followed by moving the mouse and releasing the button.
  127542. *
  127543. * @type {Number}
  127544. * @constant
  127545. */
  127546. LEFT_DRAG : 0,
  127547. /**
  127548. * A right mouse button press followed by moving the mouse and releasing the button.
  127549. *
  127550. * @type {Number}
  127551. * @constant
  127552. */
  127553. RIGHT_DRAG : 1,
  127554. /**
  127555. * A middle mouse button press followed by moving the mouse and releasing the button.
  127556. *
  127557. * @type {Number}
  127558. * @constant
  127559. */
  127560. MIDDLE_DRAG : 2,
  127561. /**
  127562. * Scrolling the middle mouse button.
  127563. *
  127564. * @type {Number}
  127565. * @constant
  127566. */
  127567. WHEEL : 3,
  127568. /**
  127569. * A two-finger touch on a touch surface.
  127570. *
  127571. * @type {Number}
  127572. * @constant
  127573. */
  127574. PINCH : 4
  127575. };
  127576. return freezeObject(CameraEventType);
  127577. });
  127578. /*global define*/
  127579. define('Scene/CameraEventAggregator',[
  127580. '../Core/Cartesian2',
  127581. '../Core/defined',
  127582. '../Core/defineProperties',
  127583. '../Core/destroyObject',
  127584. '../Core/DeveloperError',
  127585. '../Core/KeyboardEventModifier',
  127586. '../Core/Math',
  127587. '../Core/ScreenSpaceEventHandler',
  127588. '../Core/ScreenSpaceEventType',
  127589. './CameraEventType'
  127590. ], function(
  127591. Cartesian2,
  127592. defined,
  127593. defineProperties,
  127594. destroyObject,
  127595. DeveloperError,
  127596. KeyboardEventModifier,
  127597. CesiumMath,
  127598. ScreenSpaceEventHandler,
  127599. ScreenSpaceEventType,
  127600. CameraEventType) {
  127601. 'use strict';
  127602. function getKey(type, modifier) {
  127603. var key = type;
  127604. if (defined(modifier)) {
  127605. key += '+' + modifier;
  127606. }
  127607. return key;
  127608. }
  127609. function clonePinchMovement(pinchMovement, result) {
  127610. Cartesian2.clone(pinchMovement.distance.startPosition, result.distance.startPosition);
  127611. Cartesian2.clone(pinchMovement.distance.endPosition, result.distance.endPosition);
  127612. Cartesian2.clone(pinchMovement.angleAndHeight.startPosition, result.angleAndHeight.startPosition);
  127613. Cartesian2.clone(pinchMovement.angleAndHeight.endPosition, result.angleAndHeight.endPosition);
  127614. }
  127615. function listenToPinch(aggregator, modifier, canvas) {
  127616. var key = getKey(CameraEventType.PINCH, modifier);
  127617. var update = aggregator._update;
  127618. var isDown = aggregator._isDown;
  127619. var eventStartPosition = aggregator._eventStartPosition;
  127620. var pressTime = aggregator._pressTime;
  127621. var releaseTime = aggregator._releaseTime;
  127622. update[key] = true;
  127623. isDown[key] = false;
  127624. eventStartPosition[key] = new Cartesian2();
  127625. var movement = aggregator._movement[key];
  127626. if (!defined(movement)) {
  127627. movement = aggregator._movement[key] = {};
  127628. }
  127629. movement.distance = {
  127630. startPosition : new Cartesian2(),
  127631. endPosition : new Cartesian2()
  127632. };
  127633. movement.angleAndHeight = {
  127634. startPosition : new Cartesian2(),
  127635. endPosition : new Cartesian2()
  127636. };
  127637. movement.prevAngle = 0.0;
  127638. aggregator._eventHandler.setInputAction(function(event) {
  127639. aggregator._buttonsDown++;
  127640. isDown[key] = true;
  127641. pressTime[key] = new Date();
  127642. // Compute center position and store as start point.
  127643. Cartesian2.lerp(event.position1, event.position2, 0.5, eventStartPosition[key]);
  127644. }, ScreenSpaceEventType.PINCH_START, modifier);
  127645. aggregator._eventHandler.setInputAction(function() {
  127646. aggregator._buttonsDown = Math.max(aggregator._buttonsDown - 1, 0);
  127647. isDown[key] = false;
  127648. releaseTime[key] = new Date();
  127649. }, ScreenSpaceEventType.PINCH_END, modifier);
  127650. aggregator._eventHandler.setInputAction(function(mouseMovement) {
  127651. if (isDown[key]) {
  127652. // Aggregate several input events into a single animation frame.
  127653. if (!update[key]) {
  127654. Cartesian2.clone(mouseMovement.distance.endPosition, movement.distance.endPosition);
  127655. Cartesian2.clone(mouseMovement.angleAndHeight.endPosition, movement.angleAndHeight.endPosition);
  127656. } else {
  127657. clonePinchMovement(mouseMovement, movement);
  127658. update[key] = false;
  127659. movement.prevAngle = movement.angleAndHeight.startPosition.x;
  127660. }
  127661. // Make sure our aggregation of angles does not "flip" over 360 degrees.
  127662. var angle = movement.angleAndHeight.endPosition.x;
  127663. var prevAngle = movement.prevAngle;
  127664. var TwoPI = Math.PI * 2;
  127665. while (angle >= (prevAngle + Math.PI)) {
  127666. angle -= TwoPI;
  127667. }
  127668. while (angle < (prevAngle - Math.PI)) {
  127669. angle += TwoPI;
  127670. }
  127671. movement.angleAndHeight.endPosition.x = -angle * canvas.clientWidth / 12;
  127672. movement.angleAndHeight.startPosition.x = -prevAngle * canvas.clientWidth / 12;
  127673. }
  127674. }, ScreenSpaceEventType.PINCH_MOVE, modifier);
  127675. }
  127676. function listenToWheel(aggregator, modifier) {
  127677. var key = getKey(CameraEventType.WHEEL, modifier);
  127678. var update = aggregator._update;
  127679. update[key] = true;
  127680. var movement = aggregator._movement[key];
  127681. if (!defined(movement)) {
  127682. movement = aggregator._movement[key] = {};
  127683. }
  127684. movement.startPosition = new Cartesian2();
  127685. movement.endPosition = new Cartesian2();
  127686. aggregator._eventHandler.setInputAction(function(delta) {
  127687. // TODO: magic numbers
  127688. var arcLength = 15.0 * CesiumMath.toRadians(delta);
  127689. if (!update[key]) {
  127690. movement.endPosition.y = movement.endPosition.y + arcLength;
  127691. } else {
  127692. Cartesian2.clone(Cartesian2.ZERO, movement.startPosition);
  127693. movement.endPosition.x = 0.0;
  127694. movement.endPosition.y = arcLength;
  127695. update[key] = false;
  127696. }
  127697. }, ScreenSpaceEventType.WHEEL, modifier);
  127698. }
  127699. function listenMouseButtonDownUp(aggregator, modifier, type) {
  127700. var key = getKey(type, modifier);
  127701. var isDown = aggregator._isDown;
  127702. var eventStartPosition = aggregator._eventStartPosition;
  127703. var pressTime = aggregator._pressTime;
  127704. var releaseTime = aggregator._releaseTime;
  127705. isDown[key] = false;
  127706. eventStartPosition[key] = new Cartesian2();
  127707. var lastMovement = aggregator._lastMovement[key];
  127708. if (!defined(lastMovement)) {
  127709. lastMovement = aggregator._lastMovement[key] = {
  127710. startPosition : new Cartesian2(),
  127711. endPosition : new Cartesian2(),
  127712. valid : false
  127713. };
  127714. }
  127715. var down;
  127716. var up;
  127717. if (type === CameraEventType.LEFT_DRAG) {
  127718. down = ScreenSpaceEventType.LEFT_DOWN;
  127719. up = ScreenSpaceEventType.LEFT_UP;
  127720. } else if (type === CameraEventType.RIGHT_DRAG) {
  127721. down = ScreenSpaceEventType.RIGHT_DOWN;
  127722. up = ScreenSpaceEventType.RIGHT_UP;
  127723. } else if (type === CameraEventType.MIDDLE_DRAG) {
  127724. down = ScreenSpaceEventType.MIDDLE_DOWN;
  127725. up = ScreenSpaceEventType.MIDDLE_UP;
  127726. }
  127727. aggregator._eventHandler.setInputAction(function(event) {
  127728. aggregator._buttonsDown++;
  127729. lastMovement.valid = false;
  127730. isDown[key] = true;
  127731. pressTime[key] = new Date();
  127732. Cartesian2.clone(event.position, eventStartPosition[key]);
  127733. }, down, modifier);
  127734. aggregator._eventHandler.setInputAction(function() {
  127735. aggregator._buttonsDown = Math.max(aggregator._buttonsDown - 1, 0);
  127736. isDown[key] = false;
  127737. releaseTime[key] = new Date();
  127738. }, up, modifier);
  127739. }
  127740. function cloneMouseMovement(mouseMovement, result) {
  127741. Cartesian2.clone(mouseMovement.startPosition, result.startPosition);
  127742. Cartesian2.clone(mouseMovement.endPosition, result.endPosition);
  127743. }
  127744. function listenMouseMove(aggregator, modifier) {
  127745. var update = aggregator._update;
  127746. var movement = aggregator._movement;
  127747. var lastMovement = aggregator._lastMovement;
  127748. var isDown = aggregator._isDown;
  127749. for ( var typeName in CameraEventType) {
  127750. if (CameraEventType.hasOwnProperty(typeName)) {
  127751. var type = CameraEventType[typeName];
  127752. if (defined(type)) {
  127753. var key = getKey(type, modifier);
  127754. update[key] = true;
  127755. if (!defined(aggregator._lastMovement[key])) {
  127756. aggregator._lastMovement[key] = {
  127757. startPosition : new Cartesian2(),
  127758. endPosition : new Cartesian2(),
  127759. valid : false
  127760. };
  127761. }
  127762. if (!defined(aggregator._movement[key])) {
  127763. aggregator._movement[key] = {
  127764. startPosition : new Cartesian2(),
  127765. endPosition : new Cartesian2()
  127766. };
  127767. }
  127768. }
  127769. }
  127770. }
  127771. aggregator._eventHandler.setInputAction(function(mouseMovement) {
  127772. for ( var typeName in CameraEventType) {
  127773. if (CameraEventType.hasOwnProperty(typeName)) {
  127774. var type = CameraEventType[typeName];
  127775. if (defined(type)) {
  127776. var key = getKey(type, modifier);
  127777. if (isDown[key]) {
  127778. if (!update[key]) {
  127779. Cartesian2.clone(mouseMovement.endPosition, movement[key].endPosition);
  127780. } else {
  127781. cloneMouseMovement(movement[key], lastMovement[key]);
  127782. lastMovement[key].valid = true;
  127783. cloneMouseMovement(mouseMovement, movement[key]);
  127784. update[key] = false;
  127785. }
  127786. }
  127787. }
  127788. }
  127789. }
  127790. Cartesian2.clone(mouseMovement.endPosition, aggregator._currentMousePosition);
  127791. }, ScreenSpaceEventType.MOUSE_MOVE, modifier);
  127792. }
  127793. /**
  127794. * Aggregates input events. For example, suppose the following inputs are received between frames:
  127795. * left mouse button down, mouse move, mouse move, left mouse button up. These events will be aggregated into
  127796. * one event with a start and end position of the mouse.
  127797. *
  127798. * @alias CameraEventAggregator
  127799. * @constructor
  127800. *
  127801. * @param {Canvas} [element=document] The element to handle events for.
  127802. *
  127803. * @see ScreenSpaceEventHandler
  127804. */
  127805. function CameraEventAggregator(canvas) {
  127806. if (!defined(canvas)) {
  127807. throw new DeveloperError('canvas is required.');
  127808. }
  127809. this._eventHandler = new ScreenSpaceEventHandler(canvas, true);
  127810. this._update = {};
  127811. this._movement = {};
  127812. this._lastMovement = {};
  127813. this._isDown = {};
  127814. this._eventStartPosition = {};
  127815. this._pressTime = {};
  127816. this._releaseTime = {};
  127817. this._buttonsDown = 0;
  127818. this._currentMousePosition = new Cartesian2();
  127819. listenToWheel(this, undefined);
  127820. listenToPinch(this, undefined, canvas);
  127821. listenMouseButtonDownUp(this, undefined, CameraEventType.LEFT_DRAG);
  127822. listenMouseButtonDownUp(this, undefined, CameraEventType.RIGHT_DRAG);
  127823. listenMouseButtonDownUp(this, undefined, CameraEventType.MIDDLE_DRAG);
  127824. listenMouseMove(this, undefined);
  127825. for ( var modifierName in KeyboardEventModifier) {
  127826. if (KeyboardEventModifier.hasOwnProperty(modifierName)) {
  127827. var modifier = KeyboardEventModifier[modifierName];
  127828. if (defined(modifier)) {
  127829. listenToWheel(this, modifier);
  127830. listenToPinch(this, modifier, canvas);
  127831. listenMouseButtonDownUp(this, modifier, CameraEventType.LEFT_DRAG);
  127832. listenMouseButtonDownUp(this, modifier, CameraEventType.RIGHT_DRAG);
  127833. listenMouseButtonDownUp(this, modifier, CameraEventType.MIDDLE_DRAG);
  127834. listenMouseMove(this, modifier);
  127835. }
  127836. }
  127837. }
  127838. }
  127839. defineProperties(CameraEventAggregator.prototype, {
  127840. /**
  127841. * Gets the current mouse position.
  127842. * @memberof CameraEventAggregator.prototype
  127843. * @type {Cartesian2}
  127844. */
  127845. currentMousePosition : {
  127846. get : function() {
  127847. return this._currentMousePosition;
  127848. }
  127849. },
  127850. /**
  127851. * Gets whether any mouse button is down, a touch has started, or the wheel has been moved.
  127852. * @memberof CameraEventAggregator.prototype
  127853. * @type {Boolean}
  127854. */
  127855. anyButtonDown : {
  127856. get : function() {
  127857. var wheelMoved = !this._update[getKey(CameraEventType.WHEEL)] ||
  127858. !this._update[getKey(CameraEventType.WHEEL, KeyboardEventModifier.SHIFT)] ||
  127859. !this._update[getKey(CameraEventType.WHEEL, KeyboardEventModifier.CTRL)] ||
  127860. !this._update[getKey(CameraEventType.WHEEL, KeyboardEventModifier.ALT)];
  127861. return this._buttonsDown > 0 || wheelMoved;
  127862. }
  127863. }
  127864. });
  127865. /**
  127866. * Gets if a mouse button down or touch has started and has been moved.
  127867. *
  127868. * @param {CameraEventType} type The camera event type.
  127869. * @param {KeyboardEventModifier} [modifier] The keyboard modifier.
  127870. * @returns {Boolean} Returns <code>true</code> if a mouse button down or touch has started and has been moved; otherwise, <code>false</code>
  127871. */
  127872. CameraEventAggregator.prototype.isMoving = function(type, modifier) {
  127873. if (!defined(type)) {
  127874. throw new DeveloperError('type is required.');
  127875. }
  127876. var key = getKey(type, modifier);
  127877. return !this._update[key];
  127878. };
  127879. /**
  127880. * Gets the aggregated start and end position of the current event.
  127881. *
  127882. * @param {CameraEventType} type The camera event type.
  127883. * @param {KeyboardEventModifier} [modifier] The keyboard modifier.
  127884. * @returns {Object} An object with two {@link Cartesian2} properties: <code>startPosition</code> and <code>endPosition</code>.
  127885. */
  127886. CameraEventAggregator.prototype.getMovement = function(type, modifier) {
  127887. if (!defined(type)) {
  127888. throw new DeveloperError('type is required.');
  127889. }
  127890. var key = getKey(type, modifier);
  127891. var movement = this._movement[key];
  127892. return movement;
  127893. };
  127894. /**
  127895. * Gets the start and end position of the last move event (not the aggregated event).
  127896. *
  127897. * @param {CameraEventType} type The camera event type.
  127898. * @param {KeyboardEventModifier} [modifier] The keyboard modifier.
  127899. * @returns {Object|undefined} An object with two {@link Cartesian2} properties: <code>startPosition</code> and <code>endPosition</code> or <code>undefined</code>.
  127900. */
  127901. CameraEventAggregator.prototype.getLastMovement = function(type, modifier) {
  127902. if (!defined(type)) {
  127903. throw new DeveloperError('type is required.');
  127904. }
  127905. var key = getKey(type, modifier);
  127906. var lastMovement = this._lastMovement[key];
  127907. if (lastMovement.valid) {
  127908. return lastMovement;
  127909. }
  127910. return undefined;
  127911. };
  127912. /**
  127913. * Gets whether the mouse button is down or a touch has started.
  127914. *
  127915. * @param {CameraEventType} type The camera event type.
  127916. * @param {KeyboardEventModifier} [modifier] The keyboard modifier.
  127917. * @returns {Boolean} Whether the mouse button is down or a touch has started.
  127918. */
  127919. CameraEventAggregator.prototype.isButtonDown = function(type, modifier) {
  127920. if (!defined(type)) {
  127921. throw new DeveloperError('type is required.');
  127922. }
  127923. var key = getKey(type, modifier);
  127924. return this._isDown[key];
  127925. };
  127926. /**
  127927. * Gets the mouse position that started the aggregation.
  127928. *
  127929. * @param {CameraEventType} type The camera event type.
  127930. * @param {KeyboardEventModifier} [modifier] The keyboard modifier.
  127931. * @returns {Cartesian2} The mouse position.
  127932. */
  127933. CameraEventAggregator.prototype.getStartMousePosition = function(type, modifier) {
  127934. if (!defined(type)) {
  127935. throw new DeveloperError('type is required.');
  127936. }
  127937. if (type === CameraEventType.WHEEL) {
  127938. return this._currentMousePosition;
  127939. }
  127940. var key = getKey(type, modifier);
  127941. return this._eventStartPosition[key];
  127942. };
  127943. /**
  127944. * Gets the time the button was pressed or the touch was started.
  127945. *
  127946. * @param {CameraEventType} type The camera event type.
  127947. * @param {KeyboardEventModifier} [modifier] The keyboard modifier.
  127948. * @returns {Date} The time the button was pressed or the touch was started.
  127949. */
  127950. CameraEventAggregator.prototype.getButtonPressTime = function(type, modifier) {
  127951. if (!defined(type)) {
  127952. throw new DeveloperError('type is required.');
  127953. }
  127954. var key = getKey(type, modifier);
  127955. return this._pressTime[key];
  127956. };
  127957. /**
  127958. * Gets the time the button was released or the touch was ended.
  127959. *
  127960. * @param {CameraEventType} type The camera event type.
  127961. * @param {KeyboardEventModifier} [modifier] The keyboard modifier.
  127962. * @returns {Date} The time the button was released or the touch was ended.
  127963. */
  127964. CameraEventAggregator.prototype.getButtonReleaseTime = function(type, modifier) {
  127965. if (!defined(type)) {
  127966. throw new DeveloperError('type is required.');
  127967. }
  127968. var key = getKey(type, modifier);
  127969. return this._releaseTime[key];
  127970. };
  127971. /**
  127972. * Signals that all of the events have been handled and the aggregator should be reset to handle new events.
  127973. */
  127974. CameraEventAggregator.prototype.reset = function() {
  127975. for ( var name in this._update) {
  127976. if (this._update.hasOwnProperty(name)) {
  127977. this._update[name] = true;
  127978. }
  127979. }
  127980. };
  127981. /**
  127982. * Returns true if this object was destroyed; otherwise, false.
  127983. * <br /><br />
  127984. * If this object was destroyed, it should not be used; calling any function other than
  127985. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  127986. *
  127987. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  127988. *
  127989. * @see CameraEventAggregator#destroy
  127990. */
  127991. CameraEventAggregator.prototype.isDestroyed = function() {
  127992. return false;
  127993. };
  127994. /**
  127995. * Removes mouse listeners held by this object.
  127996. * <br /><br />
  127997. * Once an object is destroyed, it should not be used; calling any function other than
  127998. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  127999. * assign the return value (<code>undefined</code>) to the object as done in the example.
  128000. *
  128001. * @returns {undefined}
  128002. *
  128003. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  128004. *
  128005. *
  128006. * @example
  128007. * handler = handler && handler.destroy();
  128008. *
  128009. * @see CameraEventAggregator#isDestroyed
  128010. */
  128011. CameraEventAggregator.prototype.destroy = function() {
  128012. this._eventHandler = this._eventHandler && this._eventHandler.destroy();
  128013. return destroyObject(this);
  128014. };
  128015. return CameraEventAggregator;
  128016. });
  128017. /*global define*/
  128018. define('Scene/UrlTemplateImageryProvider',[
  128019. '../Core/Cartesian2',
  128020. '../Core/Cartesian3',
  128021. '../Core/Cartographic',
  128022. '../Core/combine',
  128023. '../Core/Credit',
  128024. '../Core/defaultValue',
  128025. '../Core/defined',
  128026. '../Core/defineProperties',
  128027. '../Core/DeveloperError',
  128028. '../Core/Event',
  128029. '../Core/GeographicTilingScheme',
  128030. '../Core/isArray',
  128031. '../Core/loadJson',
  128032. '../Core/loadText',
  128033. '../Core/loadWithXhr',
  128034. '../Core/loadXML',
  128035. '../Core/Math',
  128036. '../Core/Rectangle',
  128037. '../Core/WebMercatorTilingScheme',
  128038. '../ThirdParty/when',
  128039. './ImageryProvider'
  128040. ], function(
  128041. Cartesian2,
  128042. Cartesian3,
  128043. Cartographic,
  128044. combine,
  128045. Credit,
  128046. defaultValue,
  128047. defined,
  128048. defineProperties,
  128049. DeveloperError,
  128050. Event,
  128051. GeographicTilingScheme,
  128052. isArray,
  128053. loadJson,
  128054. loadText,
  128055. loadWithXhr,
  128056. loadXML,
  128057. CesiumMath,
  128058. Rectangle,
  128059. WebMercatorTilingScheme,
  128060. when,
  128061. ImageryProvider) {
  128062. 'use strict';
  128063. /**
  128064. * Provides imagery by requesting tiles using a specified URL template.
  128065. *
  128066. * @alias UrlTemplateImageryProvider
  128067. * @constructor
  128068. *
  128069. * @param {Promise.<Object>|Object} [options] Object with the following properties:
  128070. * @param {String} options.url The URL template to use to request tiles. It has the following keywords:
  128071. * <ul>
  128072. * <li><code>{z}</code>: The level of the tile in the tiling scheme. Level zero is the root of the quadtree pyramid.</li>
  128073. * <li><code>{x}</code>: The tile X coordinate in the tiling scheme, where 0 is the Westernmost tile.</li>
  128074. * <li><code>{y}</code>: The tile Y coordinate in the tiling scheme, where 0 is the Northernmost tile.</li>
  128075. * <li><code>{s}</code>: One of the available subdomains, used to overcome browser limits on the number of simultaneous requests per host.</li>
  128076. * <li><code>{reverseX}</code>: The tile X coordinate in the tiling scheme, where 0 is the Easternmost tile.</li>
  128077. * <li><code>{reverseY}</code>: The tile Y coordinate in the tiling scheme, where 0 is the Southernmost tile.</li>
  128078. * <li><code>{reverseZ}</code>: The level of the tile in the tiling scheme, where level zero is the maximum level of the quadtree pyramid. In order to use reverseZ, maximumLevel must be defined.</li>
  128079. * <li><code>{westDegrees}</code>: The Western edge of the tile in geodetic degrees.</li>
  128080. * <li><code>{southDegrees}</code>: The Southern edge of the tile in geodetic degrees.</li>
  128081. * <li><code>{eastDegrees}</code>: The Eastern edge of the tile in geodetic degrees.</li>
  128082. * <li><code>{northDegrees}</code>: The Northern edge of the tile in geodetic degrees.</li>
  128083. * <li><code>{westProjected}</code>: The Western edge of the tile in projected coordinates of the tiling scheme.</li>
  128084. * <li><code>{southProjected}</code>: The Southern edge of the tile in projected coordinates of the tiling scheme.</li>
  128085. * <li><code>{eastProjected}</code>: The Eastern edge of the tile in projected coordinates of the tiling scheme.</li>
  128086. * <li><code>{northProjected}</code>: The Northern edge of the tile in projected coordinates of the tiling scheme.</li>
  128087. * <li><code>{width}</code>: The width of each tile in pixels.</li>
  128088. * <li><code>{height}</code>: The height of each tile in pixels.</li>
  128089. * </ul>
  128090. * @param {String} [options.pickFeaturesUrl] The URL template to use to pick features. If this property is not specified,
  128091. * {@link UrlTemplateImageryProvider#pickFeatures} will immediately returned undefined, indicating no
  128092. * features picked. The URL template supports all of the keywords supported by the <code>url</code>
  128093. * parameter, plus the following:
  128094. * <ul>
  128095. * <li><code>{i}</code>: The pixel column (horizontal coordinate) of the picked position, where the Westernmost pixel is 0.</li>
  128096. * <li><code>{j}</code>: The pixel row (vertical coordinate) of the picked position, where the Northernmost pixel is 0.</li>
  128097. * <li><code>{reverseI}</code>: The pixel column (horizontal coordinate) of the picked position, where the Easternmost pixel is 0.</li>
  128098. * <li><code>{reverseJ}</code>: The pixel row (vertical coordinate) of the picked position, where the Southernmost pixel is 0.</li>
  128099. * <li><code>{longitudeDegrees}</code>: The longitude of the picked position in degrees.</li>
  128100. * <li><code>{latitudeDegrees}</code>: The latitude of the picked position in degrees.</li>
  128101. * <li><code>{longitudeProjected}</code>: The longitude of the picked position in the projected coordinates of the tiling scheme.</li>
  128102. * <li><code>{latitudeProjected}</code>: The latitude of the picked position in the projected coordinates of the tiling scheme.</li>
  128103. * <li><code>{format}</code>: The format in which to get feature information, as specified in the {@link GetFeatureInfoFormat}.</li>
  128104. * </ul>
  128105. * @param {Object} [options.urlSchemeZeroPadding] Gets the URL scheme zero padding for each tile coordinate. The format is '000' where
  128106. * each coordinate will be padded on the left with zeros to match the width of the passed string of zeros. e.g. Setting:
  128107. * urlSchemeZeroPadding : { '{x}' : '0000'}
  128108. * will cause an 'x' value of 12 to return the string '0012' for {x} in the generated URL.
  128109. * It the passed object has the following keywords:
  128110. * <ul>
  128111. * <li> <code>{z}</code>: The zero padding for the level of the tile in the tiling scheme.</li>
  128112. * <li> <code>{x}</code>: The zero padding for the tile X coordinate in the tiling scheme.</li>
  128113. * <li> <code>{y}</code>: The zero padding for the the tile Y coordinate in the tiling scheme.</li>
  128114. * <li> <code>{reverseX}</code>: The zero padding for the tile reverseX coordinate in the tiling scheme.</li>
  128115. * <li> <code>{reverseY}</code>: The zero padding for the tile reverseY coordinate in the tiling scheme.</li>
  128116. * <li> <code>{reverseZ}</code>: The zero padding for the reverseZ coordinate of the tile in the tiling scheme.</li>
  128117. * </ul>
  128118. * @param {String|String[]} [options.subdomains='abc'] The subdomains to use for the <code>{s}</code> placeholder in the URL template.
  128119. * If this parameter is a single string, each character in the string is a subdomain. If it is
  128120. * an array, each element in the array is a subdomain.
  128121. * @param {Object} [options.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL.
  128122. * @param {Credit|String} [options.credit=''] A credit for the data source, which is displayed on the canvas.
  128123. * @param {Number} [options.minimumLevel=0] The minimum level-of-detail supported by the imagery provider. Take care when specifying
  128124. * this that the number of tiles at the minimum level is small, such as four or less. A larger number is likely
  128125. * to result in rendering problems.
  128126. * @param {Number} [options.maximumLevel] The maximum level-of-detail supported by the imagery provider, or undefined if there is no limit.
  128127. * @param {Rectangle} [options.rectangle=Rectangle.MAX_VALUE] The rectangle, in radians, covered by the image.
  128128. * @param {TilingScheme} [options.tilingScheme=WebMercatorTilingScheme] The tiling scheme specifying how the ellipsoidal
  128129. * surface is broken into tiles. If this parameter is not provided, a {@link WebMercatorTilingScheme}
  128130. * is used.
  128131. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If the tilingScheme is specified,
  128132. * this parameter is ignored and the tiling scheme's ellipsoid is used instead. If neither
  128133. * parameter is specified, the WGS84 ellipsoid is used.
  128134. * @param {Number} [options.tileWidth=256] Pixel width of image tiles.
  128135. * @param {Number} [options.tileHeight=256] Pixel height of image tiles.
  128136. * @param {Boolean} [options.hasAlphaChannel=true] true if the images provided by this imagery provider
  128137. * include an alpha channel; otherwise, false. If this property is false, an alpha channel, if
  128138. * present, will be ignored. If this property is true, any images without an alpha channel will
  128139. * be treated as if their alpha is 1.0 everywhere. When this property is false, memory usage
  128140. * and texture upload time are potentially reduced.
  128141. * @param {GetFeatureInfoFormat[]} [options.getFeatureInfoFormats] The formats in which to get feature information at a
  128142. * specific location when {@link UrlTemplateImageryProvider#pickFeatures} is invoked. If this
  128143. * parameter is not specified, feature picking is disabled.
  128144. * @param {Boolean} [options.enablePickFeatures=true] If true, {@link UrlTemplateImageryProvider#pickFeatures} will
  128145. * request the <code>options.pickFeaturesUrl</code> and attempt to interpret the features included in the response. If false,
  128146. * {@link UrlTemplateImageryProvider#pickFeatures} will immediately return undefined (indicating no pickable
  128147. * features) without communicating with the server. Set this property to false if you know your data
  128148. * source does not support picking features or if you don't want this provider's features to be pickable. Note
  128149. * that this can be dynamically overridden by modifying the {@link UriTemplateImageryProvider#enablePickFeatures}
  128150. * property.
  128151. *
  128152. *
  128153. * @example
  128154. * // Access Natural Earth II imagery, which uses a TMS tiling scheme and Geographic (EPSG:4326) project
  128155. * var tms = new Cesium.UrlTemplateImageryProvider({
  128156. * url : 'https://cesiumjs.org/tilesets/imagery/naturalearthii/{z}/{x}/{reverseY}.jpg',
  128157. * credit : '© Analytical Graphics, Inc.',
  128158. * tilingScheme : new Cesium.GeographicTilingScheme(),
  128159. * maximumLevel : 5
  128160. * });
  128161. * // Access the CartoDB Positron basemap, which uses an OpenStreetMap-like tiling scheme.
  128162. * var positron = new Cesium.UrlTemplateImageryProvider({
  128163. * url : 'http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
  128164. * credit : 'Map tiles by CartoDB, under CC BY 3.0. Data by OpenStreetMap, under ODbL.'
  128165. * });
  128166. * // Access a Web Map Service (WMS) server.
  128167. * var wms = new Cesium.UrlTemplateImageryProvider({
  128168. * url : 'https://programs.communications.gov.au/geoserver/ows?tiled=true&' +
  128169. * 'transparent=true&format=image%2Fpng&exceptions=application%2Fvnd.ogc.se_xml&' +
  128170. * 'styles=&service=WMS&version=1.1.1&request=GetMap&' +
  128171. * 'layers=public%3AMyBroadband_Availability&srs=EPSG%3A3857&' +
  128172. * 'bbox={westProjected}%2C{southProjected}%2C{eastProjected}%2C{northProjected}&' +
  128173. * 'width=256&height=256',
  128174. * rectangle : Cesium.Rectangle.fromDegrees(96.799393, -43.598214999057824, 153.63925700000001, -9.2159219997013)
  128175. * });
  128176. *
  128177. * @see ArcGisMapServerImageryProvider
  128178. * @see BingMapsImageryProvider
  128179. * @see GoogleEarthImageryProvider
  128180. * @see createOpenStreetMapImageryProvider
  128181. * @see SingleTileImageryProvider
  128182. * @see createTileMapServiceImageryProvider
  128183. * @see WebMapServiceImageryProvider
  128184. * @see WebMapTileServiceImageryProvider
  128185. */
  128186. function UrlTemplateImageryProvider(options) {
  128187. if (!defined(options)) {
  128188. throw new DeveloperError('options is required.');
  128189. }
  128190. if (!when.isPromise(options) && !defined(options.url)) {
  128191. throw new DeveloperError('options is required.');
  128192. }
  128193. this._errorEvent = new Event();
  128194. this._url = undefined;
  128195. this._urlSchemeZeroPadding = undefined;
  128196. this._pickFeaturesUrl = undefined;
  128197. this._proxy = undefined;
  128198. this._tileWidth = undefined;
  128199. this._tileHeight = undefined;
  128200. this._maximumLevel = undefined;
  128201. this._minimumLevel = undefined;
  128202. this._tilingScheme = undefined;
  128203. this._rectangle = undefined;
  128204. this._tileDiscardPolicy = undefined;
  128205. this._credit = undefined;
  128206. this._hasAlphaChannel = undefined;
  128207. this._readyPromise = undefined;
  128208. /**
  128209. * Gets or sets a value indicating whether feature picking is enabled. If true, {@link UrlTemplateImageryProvider#pickFeatures} will
  128210. * request the <code>options.pickFeaturesUrl</code> and attempt to interpret the features included in the response. If false,
  128211. * {@link UrlTemplateImageryProvider#pickFeatures} will immediately return undefined (indicating no pickable
  128212. * features) without communicating with the server. Set this property to false if you know your data
  128213. * source does not support picking features or if you don't want this provider's features to be pickable.
  128214. * @type {Boolean}
  128215. * @default true
  128216. */
  128217. this.enablePickFeatures = true;
  128218. this.reinitialize(options);
  128219. }
  128220. defineProperties(UrlTemplateImageryProvider.prototype, {
  128221. /**
  128222. * Gets the URL template to use to request tiles. It has the following keywords:
  128223. * <ul>
  128224. * <li> <code>{z}</code>: The level of the tile in the tiling scheme. Level zero is the root of the quadtree pyramid.</li>
  128225. * <li> <code>{x}</code>: The tile X coordinate in the tiling scheme, where 0 is the Westernmost tile.</li>
  128226. * <li> <code>{y}</code>: The tile Y coordinate in the tiling scheme, where 0 is the Northernmost tile.</li>
  128227. * <li> <code>{s}</code>: One of the available subdomains, used to overcome browser limits on the number of simultaneous requests per host.</li>
  128228. * <li> <code>{reverseX}</code>: The tile X coordinate in the tiling scheme, where 0 is the Easternmost tile.</li>
  128229. * <li> <code>{reverseY}</code>: The tile Y coordinate in the tiling scheme, where 0 is the Southernmost tile.</li>
  128230. * <li> <code>{reverseZ}</code>: The level of the tile in the tiling scheme, where level zero is the maximum level of the quadtree pyramid. In order to use reverseZ, maximumLevel must be defined.</li>
  128231. * <li> <code>{westDegrees}</code>: The Western edge of the tile in geodetic degrees.</li>
  128232. * <li> <code>{southDegrees}</code>: The Southern edge of the tile in geodetic degrees.</li>
  128233. * <li> <code>{eastDegrees}</code>: The Eastern edge of the tile in geodetic degrees.</li>
  128234. * <li> <code>{northDegrees}</code>: The Northern edge of the tile in geodetic degrees.</li>
  128235. * <li> <code>{westProjected}</code>: The Western edge of the tile in projected coordinates of the tiling scheme.</li>
  128236. * <li> <code>{southProjected}</code>: The Southern edge of the tile in projected coordinates of the tiling scheme.</li>
  128237. * <li> <code>{eastProjected}</code>: The Eastern edge of the tile in projected coordinates of the tiling scheme.</li>
  128238. * <li> <code>{northProjected}</code>: The Northern edge of the tile in projected coordinates of the tiling scheme.</li>
  128239. * <li> <code>{width}</code>: The width of each tile in pixels.</li>
  128240. * <li> <code>{height}</code>: The height of each tile in pixels.</li>
  128241. * </ul>
  128242. * @memberof UrlTemplateImageryProvider.prototype
  128243. * @type {String}
  128244. * @readonly
  128245. */
  128246. url : {
  128247. get : function() {
  128248. return this._url;
  128249. }
  128250. },
  128251. /**
  128252. * Gets the URL scheme zero padding for each tile coordinate. The format is '000' where each coordinate will be padded on
  128253. * the left with zeros to match the width of the passed string of zeros. e.g. Setting:
  128254. * urlSchemeZeroPadding : { '{x}' : '0000'}
  128255. * will cause an 'x' value of 12 to return the string '0012' for {x} in the generated URL.
  128256. * It has the following keywords:
  128257. * <ul>
  128258. * <li> <code>{z}</code>: The zero padding for the level of the tile in the tiling scheme.</li>
  128259. * <li> <code>{x}</code>: The zero padding for the tile X coordinate in the tiling scheme.</li>
  128260. * <li> <code>{y}</code>: The zero padding for the the tile Y coordinate in the tiling scheme.</li>
  128261. * <li> <code>{reverseX}</code>: The zero padding for the tile reverseX coordinate in the tiling scheme.</li>
  128262. * <li> <code>{reverseY}</code>: The zero padding for the tile reverseY coordinate in the tiling scheme.</li>
  128263. * <li> <code>{reverseZ}</code>: The zero padding for the reverseZ coordinate of the tile in the tiling scheme.</li>
  128264. * </ul>
  128265. * @memberof UrlTemplateImageryProvider.prototype
  128266. * @type {Object}
  128267. * @readonly
  128268. */
  128269. urlSchemeZeroPadding : {
  128270. get : function() {
  128271. return this._urlSchemeZeroPadding;
  128272. }
  128273. },
  128274. /**
  128275. * Gets the URL template to use to use to pick features. If this property is not specified,
  128276. * {@link UrlTemplateImageryProvider#pickFeatures} will immediately returned undefined, indicating no
  128277. * features picked. The URL template supports all of the keywords supported by the
  128278. * {@link UrlTemplateImageryProvider#url} property, plus the following:
  128279. * <ul>
  128280. * <li><code>{i}</code>: The pixel column (horizontal coordinate) of the picked position, where the Westernmost pixel is 0.</li>
  128281. * <li><code>{j}</code>: The pixel row (vertical coordinate) of the picked position, where the Northernmost pixel is 0.</li>
  128282. * <li><code>{reverseI}</code>: The pixel column (horizontal coordinate) of the picked position, where the Easternmost pixel is 0.</li>
  128283. * <li><code>{reverseJ}</code>: The pixel row (vertical coordinate) of the picked position, where the Southernmost pixel is 0.</li>
  128284. * <li><code>{longitudeDegrees}</code>: The longitude of the picked position in degrees.</li>
  128285. * <li><code>{latitudeDegrees}</code>: The latitude of the picked position in degrees.</li>
  128286. * <li><code>{longitudeProjected}</code>: The longitude of the picked position in the projected coordinates of the tiling scheme.</li>
  128287. * <li><code>{latitudeProjected}</code>: The latitude of the picked position in the projected coordinates of the tiling scheme.</li>
  128288. * <li><code>{format}</code>: The format in which to get feature information, as specified in the {@link GetFeatureInfoFormat}.</li>
  128289. * </ul>
  128290. * @memberof UrlTemplateImageryProvider.prototype
  128291. * @type {String}
  128292. * @readonly
  128293. */
  128294. pickFeaturesUrl : {
  128295. get : function() {
  128296. return this._pickFeaturesUrl;
  128297. }
  128298. },
  128299. /**
  128300. * Gets the proxy used by this provider.
  128301. * @memberof UrlTemplateImageryProvider.prototype
  128302. * @type {Proxy}
  128303. * @readonly
  128304. * @default undefined
  128305. */
  128306. proxy : {
  128307. get : function() {
  128308. return this._proxy;
  128309. }
  128310. },
  128311. /**
  128312. * Gets the width of each tile, in pixels. This function should
  128313. * not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  128314. * @memberof UrlTemplateImageryProvider.prototype
  128315. * @type {Number}
  128316. * @readonly
  128317. * @default 256
  128318. */
  128319. tileWidth : {
  128320. get : function() {
  128321. if (!this.ready) {
  128322. throw new DeveloperError('tileWidth must not be called before the imagery provider is ready.');
  128323. }
  128324. return this._tileWidth;
  128325. }
  128326. },
  128327. /**
  128328. * Gets the height of each tile, in pixels. This function should
  128329. * not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  128330. * @memberof UrlTemplateImageryProvider.prototype
  128331. * @type {Number}
  128332. * @readonly
  128333. * @default 256
  128334. */
  128335. tileHeight: {
  128336. get : function() {
  128337. if (!this.ready) {
  128338. throw new DeveloperError('tileHeight must not be called before the imagery provider is ready.');
  128339. }
  128340. return this._tileHeight;
  128341. }
  128342. },
  128343. /**
  128344. * Gets the maximum level-of-detail that can be requested, or undefined if there is no limit.
  128345. * This function should not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  128346. * @memberof UrlTemplateImageryProvider.prototype
  128347. * @type {Number}
  128348. * @readonly
  128349. * @default undefined
  128350. */
  128351. maximumLevel : {
  128352. get : function() {
  128353. if (!this.ready) {
  128354. throw new DeveloperError('maximumLevel must not be called before the imagery provider is ready.');
  128355. }
  128356. return this._maximumLevel;
  128357. }
  128358. },
  128359. /**
  128360. * Gets the minimum level-of-detail that can be requested. This function should
  128361. * not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  128362. * @memberof UrlTemplateImageryProvider.prototype
  128363. * @type {Number}
  128364. * @readonly
  128365. * @default 0
  128366. */
  128367. minimumLevel : {
  128368. get : function() {
  128369. if (!this.ready) {
  128370. throw new DeveloperError('minimumLevel must not be called before the imagery provider is ready.');
  128371. }
  128372. return this._minimumLevel;
  128373. }
  128374. },
  128375. /**
  128376. * Gets the tiling scheme used by this provider. This function should
  128377. * not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  128378. * @memberof UrlTemplateImageryProvider.prototype
  128379. * @type {TilingScheme}
  128380. * @readonly
  128381. * @default new WebMercatorTilingScheme()
  128382. */
  128383. tilingScheme : {
  128384. get : function() {
  128385. if (!this.ready) {
  128386. throw new DeveloperError('tilingScheme must not be called before the imagery provider is ready.');
  128387. }
  128388. return this._tilingScheme;
  128389. }
  128390. },
  128391. /**
  128392. * Gets the rectangle, in radians, of the imagery provided by this instance. This function should
  128393. * not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  128394. * @memberof UrlTemplateImageryProvider.prototype
  128395. * @type {Rectangle}
  128396. * @readonly
  128397. * @default tilingScheme.rectangle
  128398. */
  128399. rectangle : {
  128400. get : function() {
  128401. if (!this.ready) {
  128402. throw new DeveloperError('rectangle must not be called before the imagery provider is ready.');
  128403. }
  128404. return this._rectangle;
  128405. }
  128406. },
  128407. /**
  128408. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  128409. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  128410. * returns undefined, no tiles are filtered. This function should
  128411. * not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  128412. * @memberof UrlTemplateImageryProvider.prototype
  128413. * @type {TileDiscardPolicy}
  128414. * @readonly
  128415. * @default undefined
  128416. */
  128417. tileDiscardPolicy : {
  128418. get : function() {
  128419. if (!this.ready) {
  128420. throw new DeveloperError('tileDiscardPolicy must not be called before the imagery provider is ready.');
  128421. }
  128422. return this._tileDiscardPolicy;
  128423. }
  128424. },
  128425. /**
  128426. * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
  128427. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  128428. * are passed an instance of {@link TileProviderError}.
  128429. * @memberof UrlTemplateImageryProvider.prototype
  128430. * @type {Event}
  128431. * @readonly
  128432. */
  128433. errorEvent : {
  128434. get : function() {
  128435. return this._errorEvent;
  128436. }
  128437. },
  128438. /**
  128439. * Gets a value indicating whether or not the provider is ready for use.
  128440. * @memberof UrlTemplateImageryProvider.prototype
  128441. * @type {Boolean}
  128442. * @readonly
  128443. */
  128444. ready : {
  128445. get : function() {
  128446. return defined(this._urlParts);
  128447. }
  128448. },
  128449. /**
  128450. * Gets a promise that resolves to true when the provider is ready for use.
  128451. * @memberof UrlTemplateImageryProvider.prototype
  128452. * @type {Promise.<Boolean>}
  128453. * @readonly
  128454. */
  128455. readyPromise : {
  128456. get : function() {
  128457. return this._readyPromise;
  128458. }
  128459. },
  128460. /**
  128461. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  128462. * the source of the imagery. This function should not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  128463. * @memberof UrlTemplateImageryProvider.prototype
  128464. * @type {Credit}
  128465. * @readonly
  128466. * @default undefined
  128467. */
  128468. credit : {
  128469. get : function() {
  128470. if (!this.ready) {
  128471. throw new DeveloperError('credit must not be called before the imagery provider is ready.');
  128472. }
  128473. return this._credit;
  128474. }
  128475. },
  128476. /**
  128477. * Gets a value indicating whether or not the images provided by this imagery provider
  128478. * include an alpha channel. If this property is false, an alpha channel, if present, will
  128479. * be ignored. If this property is true, any images without an alpha channel will be treated
  128480. * as if their alpha is 1.0 everywhere. When this property is false, memory usage
  128481. * and texture upload time are reduced. This function should
  128482. * not be called before {@link ImageryProvider#ready} returns true.
  128483. * @memberof UrlTemplateImageryProvider.prototype
  128484. * @type {Boolean}
  128485. * @readonly
  128486. * @default true
  128487. */
  128488. hasAlphaChannel : {
  128489. get : function() {
  128490. if (!this.ready) {
  128491. throw new DeveloperError('hasAlphaChannel must not be called before the imagery provider is ready.');
  128492. }
  128493. return this._hasAlphaChannel;
  128494. }
  128495. }
  128496. });
  128497. /**
  128498. * Reinitializes this instance. Reinitializing an instance already in use is supported, but it is not
  128499. * recommended because existing tiles provided by the imagery provider will not be updated.
  128500. *
  128501. * @param {Promise.<Object>|Object} options Any of the options that may be passed to the {@link UrlTemplateImageryProvider} constructor.
  128502. */
  128503. UrlTemplateImageryProvider.prototype.reinitialize = function(options) {
  128504. var that = this;
  128505. that._readyPromise = when(options).then(function(properties) {
  128506. if (!defined(properties)) {
  128507. throw new DeveloperError('options is required.');
  128508. }
  128509. if (!defined(properties.url)) {
  128510. throw new DeveloperError('options.url is required.');
  128511. }
  128512. that.enablePickFeatures = defaultValue(properties.enablePickFeatures, that.enablePickFeatures);
  128513. that._url = properties.url;
  128514. that._urlSchemeZeroPadding = defaultValue(properties.urlSchemeZeroPadding, that.urlSchemeZeroPadding);
  128515. that._pickFeaturesUrl = properties.pickFeaturesUrl;
  128516. that._proxy = properties.proxy;
  128517. that._tileDiscardPolicy = properties.tileDiscardPolicy;
  128518. that._getFeatureInfoFormats = properties.getFeatureInfoFormats;
  128519. that._subdomains = properties.subdomains;
  128520. if (isArray(that._subdomains)) {
  128521. that._subdomains = that._subdomains.slice();
  128522. } else if (defined(that._subdomains) && that._subdomains.length > 0) {
  128523. that._subdomains = that._subdomains.split('');
  128524. } else {
  128525. that._subdomains = ['a', 'b', 'c'];
  128526. }
  128527. that._tileWidth = defaultValue(properties.tileWidth, 256);
  128528. that._tileHeight = defaultValue(properties.tileHeight, 256);
  128529. that._minimumLevel = defaultValue(properties.minimumLevel, 0);
  128530. that._maximumLevel = properties.maximumLevel;
  128531. that._tilingScheme = defaultValue(properties.tilingScheme, new WebMercatorTilingScheme({ ellipsoid : properties.ellipsoid }));
  128532. that._rectangle = defaultValue(properties.rectangle, that._tilingScheme.rectangle);
  128533. that._rectangle = Rectangle.intersection(that._rectangle, that._tilingScheme.rectangle);
  128534. that._hasAlphaChannel = defaultValue(properties.hasAlphaChannel, true);
  128535. var credit = properties.credit;
  128536. if (typeof credit === 'string') {
  128537. credit = new Credit(credit);
  128538. }
  128539. that._credit = credit;
  128540. that._urlParts = urlTemplateToParts(that._url, tags);
  128541. that._pickFeaturesUrlParts = urlTemplateToParts(that._pickFeaturesUrl, pickFeaturesTags);
  128542. return true;
  128543. });
  128544. };
  128545. /**
  128546. * Gets the credits to be displayed when a given tile is displayed.
  128547. *
  128548. * @param {Number} x The tile X coordinate.
  128549. * @param {Number} y The tile Y coordinate.
  128550. * @param {Number} level The tile level;
  128551. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  128552. *
  128553. * @exception {DeveloperError} <code>getTileCredits</code> must not be called before the imagery provider is ready.
  128554. */
  128555. UrlTemplateImageryProvider.prototype.getTileCredits = function(x, y, level) {
  128556. if (!this.ready) {
  128557. throw new DeveloperError('getTileCredits must not be called before the imagery provider is ready.');
  128558. }
  128559. return undefined;
  128560. };
  128561. /**
  128562. * Requests the image for a given tile. This function should
  128563. * not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  128564. *
  128565. * @param {Number} x The tile X coordinate.
  128566. * @param {Number} y The tile Y coordinate.
  128567. * @param {Number} level The tile level.
  128568. * @returns {Promise.<Image|Canvas>|undefined} A promise for the image that will resolve when the image is available, or
  128569. * undefined if there are too many active requests to the server, and the request
  128570. * should be retried later. The resolved image may be either an
  128571. * Image or a Canvas DOM object.
  128572. */
  128573. UrlTemplateImageryProvider.prototype.requestImage = function(x, y, level) {
  128574. if (!this.ready) {
  128575. throw new DeveloperError('requestImage must not be called before the imagery provider is ready.');
  128576. }
  128577. var url = buildImageUrl(this, x, y, level);
  128578. return ImageryProvider.loadImage(this, url);
  128579. };
  128580. /**
  128581. * Asynchronously determines what features, if any, are located at a given longitude and latitude within
  128582. * a tile. This function should not be called before {@link ImageryProvider#ready} returns true.
  128583. *
  128584. * @param {Number} x The tile X coordinate.
  128585. * @param {Number} y The tile Y coordinate.
  128586. * @param {Number} level The tile level.
  128587. * @param {Number} longitude The longitude at which to pick features.
  128588. * @param {Number} latitude The latitude at which to pick features.
  128589. * @return {Promise.<ImageryLayerFeatureInfo[]>|undefined} A promise for the picked features that will resolve when the asynchronous
  128590. * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
  128591. * instances. The array may be empty if no features are found at the given location.
  128592. * It may also be undefined if picking is not supported.
  128593. */
  128594. UrlTemplateImageryProvider.prototype.pickFeatures = function(x, y, level, longitude, latitude) {
  128595. if (!this.ready) {
  128596. throw new DeveloperError('pickFeatures must not be called before the imagery provider is ready.');
  128597. }
  128598. if (!this.enablePickFeatures || !defined(this._pickFeaturesUrl) || this._getFeatureInfoFormats.length === 0) {
  128599. return undefined;
  128600. }
  128601. var formatIndex = 0;
  128602. var that = this;
  128603. function handleResponse(format, data) {
  128604. return format.callback(data);
  128605. }
  128606. function doRequest() {
  128607. if (formatIndex >= that._getFeatureInfoFormats.length) {
  128608. // No valid formats, so no features picked.
  128609. return when([]);
  128610. }
  128611. var format = that._getFeatureInfoFormats[formatIndex];
  128612. var url = buildPickFeaturesUrl(that, x, y, level, longitude, latitude, format.format);
  128613. ++formatIndex;
  128614. if (format.type === 'json') {
  128615. return loadJson(url).then(format.callback).otherwise(doRequest);
  128616. } else if (format.type === 'xml') {
  128617. return loadXML(url).then(format.callback).otherwise(doRequest);
  128618. } else if (format.type === 'text' || format.type === 'html') {
  128619. return loadText(url).then(format.callback).otherwise(doRequest);
  128620. } else {
  128621. return loadWithXhr({
  128622. url: url,
  128623. responseType: format.format
  128624. }).then(handleResponse.bind(undefined, format)).otherwise(doRequest);
  128625. }
  128626. }
  128627. return doRequest();
  128628. };
  128629. function buildImageUrl(imageryProvider, x, y, level) {
  128630. degreesScratchComputed = false;
  128631. projectedScratchComputed = false;
  128632. return buildUrl(imageryProvider, imageryProvider._urlParts, function(partFunction) {
  128633. return partFunction(imageryProvider, x, y, level);
  128634. });
  128635. }
  128636. function buildPickFeaturesUrl(imageryProvider, x, y, level, longitude, latitude, format) {
  128637. degreesScratchComputed = false;
  128638. projectedScratchComputed = false;
  128639. ijScratchComputed = false;
  128640. longitudeLatitudeProjectedScratchComputed = false;
  128641. return buildUrl(imageryProvider, imageryProvider._pickFeaturesUrlParts, function(partFunction) {
  128642. return partFunction(imageryProvider, x, y, level, longitude, latitude, format);
  128643. });
  128644. }
  128645. function buildUrl(imageryProvider, parts, partFunctionInvoker) {
  128646. var url = '';
  128647. for (var i = 0; i < parts.length; ++i) {
  128648. var part = parts[i];
  128649. if (typeof part === 'string') {
  128650. url += part;
  128651. } else {
  128652. url += encodeURIComponent(partFunctionInvoker(part));
  128653. }
  128654. }
  128655. var proxy = imageryProvider._proxy;
  128656. if (defined(proxy)) {
  128657. url = proxy.getURL(url);
  128658. }
  128659. return url;
  128660. }
  128661. function urlTemplateToParts(url, tags) {
  128662. if (!defined(url)) {
  128663. return undefined;
  128664. }
  128665. var parts = [];
  128666. var nextIndex = 0;
  128667. var minIndex;
  128668. var minTag;
  128669. var tagList = Object.keys(tags);
  128670. while (nextIndex < url.length) {
  128671. minIndex = Number.MAX_VALUE;
  128672. minTag = undefined;
  128673. for (var i = 0; i < tagList.length; ++i) {
  128674. var thisIndex = url.indexOf(tagList[i], nextIndex);
  128675. if (thisIndex >= 0 && thisIndex < minIndex) {
  128676. minIndex = thisIndex;
  128677. minTag = tagList[i];
  128678. }
  128679. }
  128680. if (!defined(minTag)) {
  128681. parts.push(url.substring(nextIndex));
  128682. nextIndex = url.length;
  128683. } else {
  128684. if (nextIndex < minIndex) {
  128685. parts.push(url.substring(nextIndex, minIndex));
  128686. }
  128687. parts.push(tags[minTag]);
  128688. nextIndex = minIndex + minTag.length;
  128689. }
  128690. }
  128691. return parts;
  128692. }
  128693. function padWithZerosIfNecessary(imageryProvider, key, value) {
  128694. if (imageryProvider &&
  128695. imageryProvider.urlSchemeZeroPadding &&
  128696. imageryProvider.urlSchemeZeroPadding.hasOwnProperty(key) )
  128697. {
  128698. var paddingTemplate = imageryProvider.urlSchemeZeroPadding[key];
  128699. if (typeof paddingTemplate === 'string') {
  128700. var paddingTemplateWidth = paddingTemplate.length;
  128701. if (paddingTemplateWidth > 1) {
  128702. value = (value.length >= paddingTemplateWidth) ? value : new Array(paddingTemplateWidth - value.toString().length + 1).join('0') + value;
  128703. }
  128704. }
  128705. }
  128706. return value;
  128707. }
  128708. function xTag(imageryProvider, x, y, level) {
  128709. return padWithZerosIfNecessary(imageryProvider, '{x}', x);
  128710. }
  128711. function reverseXTag(imageryProvider, x, y, level) {
  128712. var reverseX = imageryProvider.tilingScheme.getNumberOfXTilesAtLevel(level) - x - 1;
  128713. return padWithZerosIfNecessary(imageryProvider, '{reverseX}', reverseX);
  128714. }
  128715. function yTag(imageryProvider, x, y, level) {
  128716. return padWithZerosIfNecessary(imageryProvider, '{y}', y);
  128717. }
  128718. function reverseYTag(imageryProvider, x, y, level) {
  128719. var reverseY = imageryProvider.tilingScheme.getNumberOfYTilesAtLevel(level) - y - 1;
  128720. return padWithZerosIfNecessary(imageryProvider, '{reverseY}', reverseY);
  128721. }
  128722. function reverseZTag(imageryProvider, x, y, level) {
  128723. var maximumLevel = imageryProvider.maximumLevel;
  128724. var reverseZ = defined(maximumLevel) && level < maximumLevel ? maximumLevel - level - 1 : level;
  128725. return padWithZerosIfNecessary(imageryProvider, '{reverseZ}', reverseZ);
  128726. }
  128727. function zTag(imageryProvider, x, y, level) {
  128728. return padWithZerosIfNecessary(imageryProvider, '{z}', level);
  128729. }
  128730. function sTag(imageryProvider, x, y, level) {
  128731. var index = (x + y + level) % imageryProvider._subdomains.length;
  128732. return imageryProvider._subdomains[index];
  128733. }
  128734. var degreesScratchComputed = false;
  128735. var degreesScratch = new Rectangle();
  128736. function computeDegrees(imageryProvider, x, y, level) {
  128737. if (degreesScratchComputed) {
  128738. return;
  128739. }
  128740. imageryProvider.tilingScheme.tileXYToRectangle(x, y, level, degreesScratch);
  128741. degreesScratch.west = CesiumMath.toDegrees(degreesScratch.west);
  128742. degreesScratch.south = CesiumMath.toDegrees(degreesScratch.south);
  128743. degreesScratch.east = CesiumMath.toDegrees(degreesScratch.east);
  128744. degreesScratch.north = CesiumMath.toDegrees(degreesScratch.north);
  128745. degreesScratchComputed = true;
  128746. }
  128747. function westDegreesTag(imageryProvider, x, y, level) {
  128748. computeDegrees(imageryProvider, x, y, level);
  128749. return degreesScratch.west;
  128750. }
  128751. function southDegreesTag(imageryProvider, x, y, level) {
  128752. computeDegrees(imageryProvider, x, y, level);
  128753. return degreesScratch.south;
  128754. }
  128755. function eastDegreesTag(imageryProvider, x, y, level) {
  128756. computeDegrees(imageryProvider, x, y, level);
  128757. return degreesScratch.east;
  128758. }
  128759. function northDegreesTag(imageryProvider, x, y, level) {
  128760. computeDegrees(imageryProvider, x, y, level);
  128761. return degreesScratch.north;
  128762. }
  128763. var projectedScratchComputed = false;
  128764. var projectedScratch = new Rectangle();
  128765. function computeProjected(imageryProvider, x, y, level) {
  128766. if (projectedScratchComputed) {
  128767. return;
  128768. }
  128769. imageryProvider.tilingScheme.tileXYToNativeRectangle(x, y, level, projectedScratch);
  128770. projectedScratchComputed = true;
  128771. }
  128772. function westProjectedTag(imageryProvider, x, y, level) {
  128773. computeProjected(imageryProvider, x, y, level);
  128774. return projectedScratch.west;
  128775. }
  128776. function southProjectedTag(imageryProvider, x, y, level) {
  128777. computeProjected(imageryProvider, x, y, level);
  128778. return projectedScratch.south;
  128779. }
  128780. function eastProjectedTag(imageryProvider, x, y, level) {
  128781. computeProjected(imageryProvider, x, y, level);
  128782. return projectedScratch.east;
  128783. }
  128784. function northProjectedTag(imageryProvider, x, y, level) {
  128785. computeProjected(imageryProvider, x, y, level);
  128786. return projectedScratch.north;
  128787. }
  128788. function widthTag(imageryProvider, x, y, level) {
  128789. return imageryProvider.tileWidth;
  128790. }
  128791. function heightTag(imageryProvider, x, y, level) {
  128792. return imageryProvider.tileHeight;
  128793. }
  128794. var ijScratchComputed = false;
  128795. var ijScratch = new Cartesian2();
  128796. function iTag(imageryProvider, x, y, level, longitude, latitude, format) {
  128797. computeIJ(imageryProvider, x, y, level, longitude, latitude);
  128798. return ijScratch.x;
  128799. }
  128800. function jTag(imageryProvider, x, y, level, longitude, latitude, format) {
  128801. computeIJ(imageryProvider, x, y, level, longitude, latitude);
  128802. return ijScratch.y;
  128803. }
  128804. function reverseITag(imageryProvider, x, y, level, longitude, latitude, format) {
  128805. computeIJ(imageryProvider, x, y, level, longitude, latitude);
  128806. return imageryProvider.tileWidth - ijScratch.x - 1;
  128807. }
  128808. function reverseJTag(imageryProvider, x, y, level, longitude, latitude, format) {
  128809. computeIJ(imageryProvider, x, y, level, longitude, latitude);
  128810. return imageryProvider.tileHeight - ijScratch.y - 1;
  128811. }
  128812. var rectangleScratch = new Rectangle();
  128813. function computeIJ(imageryProvider, x, y, level, longitude, latitude, format) {
  128814. if (ijScratchComputed) {
  128815. return;
  128816. }
  128817. computeLongitudeLatitudeProjected(imageryProvider, x, y, level, longitude, latitude);
  128818. var projected = longitudeLatitudeProjectedScratch;
  128819. var rectangle = imageryProvider.tilingScheme.tileXYToNativeRectangle(x, y, level, rectangleScratch);
  128820. ijScratch.x = (imageryProvider.tileWidth * (projected.x - rectangle.west) / rectangle.width) | 0;
  128821. ijScratch.y = (imageryProvider.tileHeight * (rectangle.north - projected.y) / rectangle.height) | 0;
  128822. ijScratchComputed = true;
  128823. }
  128824. function longitudeDegreesTag(imageryProvider, x, y, level, longitude, latitude, format) {
  128825. return CesiumMath.toDegrees(longitude);
  128826. }
  128827. function latitudeDegreesTag(imageryProvider, x, y, level, longitude, latitude, format) {
  128828. return CesiumMath.toDegrees(latitude);
  128829. }
  128830. var longitudeLatitudeProjectedScratchComputed = false;
  128831. var longitudeLatitudeProjectedScratch = new Cartesian3();
  128832. function longitudeProjectedTag(imageryProvider, x, y, level, longitude, latitude, format) {
  128833. computeLongitudeLatitudeProjected(imageryProvider, x, y, level, longitude, latitude);
  128834. return longitudeLatitudeProjectedScratch.x;
  128835. }
  128836. function latitudeProjectedTag(imageryProvider, x, y, level, longitude, latitude, format) {
  128837. computeLongitudeLatitudeProjected(imageryProvider, x, y, level, longitude, latitude);
  128838. return longitudeLatitudeProjectedScratch.y;
  128839. }
  128840. var cartographicScratch = new Cartographic();
  128841. function computeLongitudeLatitudeProjected(imageryProvider, x, y, level, longitude, latitude, format) {
  128842. if (longitudeLatitudeProjectedScratchComputed) {
  128843. return;
  128844. }
  128845. var projected;
  128846. if (imageryProvider.tilingScheme instanceof GeographicTilingScheme) {
  128847. longitudeLatitudeProjectedScratch.x = CesiumMath.toDegrees(longitude);
  128848. longitudeLatitudeProjectedScratch.y = CesiumMath.toDegrees(latitude);
  128849. } else {
  128850. var cartographic = cartographicScratch;
  128851. cartographic.longitude = longitude;
  128852. cartographic.latitude = latitude;
  128853. projected = imageryProvider.tilingScheme.projection.project(cartographic, longitudeLatitudeProjectedScratch);
  128854. }
  128855. longitudeLatitudeProjectedScratchComputed = true;
  128856. }
  128857. function formatTag(imageryProvider, x, y, level, longitude, latitude, format) {
  128858. return format;
  128859. }
  128860. var tags = {
  128861. '{x}': xTag,
  128862. '{y}': yTag,
  128863. '{z}': zTag,
  128864. '{s}': sTag,
  128865. '{reverseX}': reverseXTag,
  128866. '{reverseY}': reverseYTag,
  128867. '{reverseZ}': reverseZTag,
  128868. '{westDegrees}': westDegreesTag,
  128869. '{southDegrees}': southDegreesTag,
  128870. '{eastDegrees}': eastDegreesTag,
  128871. '{northDegrees}': northDegreesTag,
  128872. '{westProjected}': westProjectedTag,
  128873. '{southProjected}': southProjectedTag,
  128874. '{eastProjected}': eastProjectedTag,
  128875. '{northProjected}': northProjectedTag,
  128876. '{width}': widthTag,
  128877. '{height}': heightTag
  128878. };
  128879. var pickFeaturesTags = combine(tags, {
  128880. '{i}' : iTag,
  128881. '{j}' : jTag,
  128882. '{reverseI}' : reverseITag,
  128883. '{reverseJ}' : reverseJTag,
  128884. '{longitudeDegrees}' : longitudeDegreesTag,
  128885. '{latitudeDegrees}' : latitudeDegreesTag,
  128886. '{longitudeProjected}' : longitudeProjectedTag,
  128887. '{latitudeProjected}' : latitudeProjectedTag,
  128888. '{format}' : formatTag
  128889. });
  128890. return UrlTemplateImageryProvider;
  128891. });
  128892. /*global define*/
  128893. define('Scene/createOpenStreetMapImageryProvider',[
  128894. '../Core/Credit',
  128895. '../Core/defaultValue',
  128896. '../Core/DeveloperError',
  128897. '../Core/Rectangle',
  128898. '../Core/WebMercatorTilingScheme',
  128899. './UrlTemplateImageryProvider'
  128900. ], function(
  128901. Credit,
  128902. defaultValue,
  128903. DeveloperError,
  128904. Rectangle,
  128905. WebMercatorTilingScheme,
  128906. UrlTemplateImageryProvider) {
  128907. 'use strict';
  128908. var trailingSlashRegex = /\/$/;
  128909. var defaultCredit = new Credit('MapQuest, Open Street Map and contributors, CC-BY-SA');
  128910. /**
  128911. * Creates a {@link UrlTemplateImageryProvider} instance that provides tiled imagery hosted by OpenStreetMap
  128912. * or another provider of Slippy tiles. The default url connects to OpenStreetMap's volunteer-run
  128913. * servers, so you must conform to their
  128914. * {@link http://wiki.openstreetmap.org/wiki/Tile_usage_policy|Tile Usage Policy}.
  128915. *
  128916. * @exports createOpenStreetMapImageryProvider
  128917. *
  128918. * @param {Object} [options] Object with the following properties:
  128919. * @param {String} [options.url='https://a.tile.openstreetmap.org'] The OpenStreetMap server url.
  128920. * @param {String} [options.fileExtension='png'] The file extension for images on the server.
  128921. * @param {Object} [options.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL.
  128922. * @param {Rectangle} [options.rectangle=Rectangle.MAX_VALUE] The rectangle of the layer.
  128923. * @param {Number} [options.minimumLevel=0] The minimum level-of-detail supported by the imagery provider.
  128924. * @param {Number} [options.maximumLevel] The maximum level-of-detail supported by the imagery provider, or undefined if there is no limit.
  128925. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If not specified, the WGS84 ellipsoid is used.
  128926. * @param {Credit|String} [options.credit='MapQuest, Open Street Map and contributors, CC-BY-SA'] A credit for the data source, which is displayed on the canvas.
  128927. * @returns {UrlTemplateImageryProvider} The imagery provider.
  128928. *
  128929. * @exception {DeveloperError} The rectangle and minimumLevel indicate that there are more than four tiles at the minimum level. Imagery providers with more than four tiles at the minimum level are not supported.
  128930. *
  128931. * @see ArcGisMapServerImageryProvider
  128932. * @see BingMapsImageryProvider
  128933. * @see GoogleEarthImageryProvider
  128934. * @see SingleTileImageryProvider
  128935. * @see createTileMapServiceImageryProvider
  128936. * @see WebMapServiceImageryProvider
  128937. * @see WebMapTileServiceImageryProvider
  128938. * @see UrlTemplateImageryProvider
  128939. *
  128940. *
  128941. * @example
  128942. * var osm = Cesium.createOpenStreetMapImageryProvider({
  128943. * url : 'https://a.tile.openstreetmap.org/'
  128944. * });
  128945. *
  128946. * @see {@link http://wiki.openstreetmap.org/wiki/Main_Page|OpenStreetMap Wiki}
  128947. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  128948. */
  128949. function createOpenStreetMapImageryProvider(options) {
  128950. options = defaultValue(options, {});
  128951. var url = defaultValue(options.url, 'https://a.tile.openstreetmap.org/');
  128952. if (!trailingSlashRegex.test(url)) {
  128953. url = url + '/';
  128954. }
  128955. var fileExtension = defaultValue(options.fileExtension, 'png');
  128956. var tilingScheme = new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid });
  128957. var tileWidth = 256;
  128958. var tileHeight = 256;
  128959. var minimumLevel = defaultValue(options.minimumLevel, 0);
  128960. var maximumLevel = options.maximumLevel;
  128961. var rectangle = defaultValue(options.rectangle, tilingScheme.rectangle);
  128962. // Check the number of tiles at the minimum level. If it's more than four,
  128963. // throw an exception, because starting at the higher minimum
  128964. // level will cause too many tiles to be downloaded and rendered.
  128965. var swTile = tilingScheme.positionToTileXY(Rectangle.southwest(rectangle), minimumLevel);
  128966. var neTile = tilingScheme.positionToTileXY(Rectangle.northeast(rectangle), minimumLevel);
  128967. var tileCount = (Math.abs(neTile.x - swTile.x) + 1) * (Math.abs(neTile.y - swTile.y) + 1);
  128968. if (tileCount > 4) {
  128969. throw new DeveloperError('The rectangle and minimumLevel indicate that there are ' + tileCount + ' tiles at the minimum level. Imagery providers with more than four tiles at the minimum level are not supported.');
  128970. }
  128971. var credit = defaultValue(options.credit, defaultCredit);
  128972. if (typeof credit === 'string') {
  128973. credit = new Credit(credit);
  128974. }
  128975. var templateUrl = url + "{z}/{x}/{y}." + fileExtension;
  128976. return new UrlTemplateImageryProvider({
  128977. url: templateUrl,
  128978. proxy: options.proxy,
  128979. credit: credit,
  128980. tilingScheme: tilingScheme,
  128981. tileWidth: tileWidth,
  128982. tileHeight: tileHeight,
  128983. minimumLevel: minimumLevel,
  128984. maximumLevel: maximumLevel,
  128985. rectangle: rectangle
  128986. });
  128987. }
  128988. return createOpenStreetMapImageryProvider;
  128989. });
  128990. /*global define*/
  128991. define('Scene/createTangentSpaceDebugPrimitive',[
  128992. '../Core/ColorGeometryInstanceAttribute',
  128993. '../Core/defaultValue',
  128994. '../Core/defined',
  128995. '../Core/DeveloperError',
  128996. '../Core/GeometryInstance',
  128997. '../Core/GeometryPipeline',
  128998. '../Core/Matrix4',
  128999. './PerInstanceColorAppearance',
  129000. './Primitive'
  129001. ], function(
  129002. ColorGeometryInstanceAttribute,
  129003. defaultValue,
  129004. defined,
  129005. DeveloperError,
  129006. GeometryInstance,
  129007. GeometryPipeline,
  129008. Matrix4,
  129009. PerInstanceColorAppearance,
  129010. Primitive) {
  129011. 'use strict';
  129012. /**
  129013. * Creates a {@link Primitive} to visualize well-known vector vertex attributes:
  129014. * <code>normal</code>, <code>binormal</code>, and <code>tangent</code>. Normal
  129015. * is red; binormal is green; and tangent is blue. If an attribute is not
  129016. * present, it is not drawn.
  129017. *
  129018. * @exports createTangentSpaceDebugPrimitive
  129019. *
  129020. * @param {Object} options Object with the following properties:
  129021. * @param {Geometry} options.geometry The <code>Geometry</code> instance with the attribute.
  129022. * @param {Number} [options.length=10000.0] The length of each line segment in meters. This can be negative to point the vector in the opposite direction.
  129023. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The model matrix that transforms to transform the geometry from model to world coordinates.
  129024. * @returns {Primitive} A new <code>Primitive</code> instance with geometry for the vectors.
  129025. *
  129026. * @example
  129027. * scene.primitives.add(Cesium.createTangentSpaceDebugPrimitive({
  129028. * geometry : instance.geometry,
  129029. * length : 100000.0,
  129030. * modelMatrix : instance.modelMatrix
  129031. * }));
  129032. */
  129033. function createTangentSpaceDebugPrimitive(options) {
  129034. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  129035. var instances = [];
  129036. var geometry = options.geometry;
  129037. if (!defined(geometry)) {
  129038. throw new DeveloperError('options.geometry is required.');
  129039. }
  129040. if (!defined(geometry.attributes) || !defined(geometry.primitiveType)) {
  129041. // to create the debug lines, we need the computed attributes.
  129042. // compute them if they are undefined.
  129043. geometry = geometry.constructor.createGeometry(geometry);
  129044. }
  129045. var attributes = geometry.attributes;
  129046. var modelMatrix = Matrix4.clone(defaultValue(options.modelMatrix, Matrix4.IDENTITY));
  129047. var length = defaultValue(options.length, 10000.0);
  129048. if (defined(attributes.normal)) {
  129049. instances.push(new GeometryInstance({
  129050. geometry : GeometryPipeline.createLineSegmentsForVectors(geometry, 'normal', length),
  129051. attributes : {
  129052. color : new ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 1.0)
  129053. },
  129054. modelMatrix : modelMatrix
  129055. }));
  129056. }
  129057. if (defined(attributes.binormal)) {
  129058. instances.push(new GeometryInstance({
  129059. geometry : GeometryPipeline.createLineSegmentsForVectors(geometry, 'binormal', length),
  129060. attributes : {
  129061. color : new ColorGeometryInstanceAttribute(0.0, 1.0, 0.0, 1.0)
  129062. },
  129063. modelMatrix : modelMatrix
  129064. }));
  129065. }
  129066. if (defined(attributes.tangent)) {
  129067. instances.push(new GeometryInstance({
  129068. geometry : GeometryPipeline.createLineSegmentsForVectors(geometry, 'tangent', length),
  129069. attributes : {
  129070. color : new ColorGeometryInstanceAttribute(0.0, 0.0, 1.0, 1.0)
  129071. },
  129072. modelMatrix : modelMatrix
  129073. }));
  129074. }
  129075. if (instances.length > 0) {
  129076. return new Primitive({
  129077. asynchronous : false,
  129078. geometryInstances : instances,
  129079. appearance : new PerInstanceColorAppearance({
  129080. flat : true,
  129081. translucent : false
  129082. })
  129083. });
  129084. }
  129085. return undefined;
  129086. }
  129087. return createTangentSpaceDebugPrimitive;
  129088. });
  129089. /*global define*/
  129090. define('Scene/createTileMapServiceImageryProvider',[
  129091. '../Core/Cartesian2',
  129092. '../Core/Cartographic',
  129093. '../Core/defaultValue',
  129094. '../Core/defined',
  129095. '../Core/DeveloperError',
  129096. '../Core/GeographicTilingScheme',
  129097. '../Core/joinUrls',
  129098. '../Core/loadXML',
  129099. '../Core/Rectangle',
  129100. '../Core/RuntimeError',
  129101. '../Core/TileProviderError',
  129102. '../Core/WebMercatorTilingScheme',
  129103. '../ThirdParty/when',
  129104. './UrlTemplateImageryProvider'
  129105. ], function(
  129106. Cartesian2,
  129107. Cartographic,
  129108. defaultValue,
  129109. defined,
  129110. DeveloperError,
  129111. GeographicTilingScheme,
  129112. joinUrls,
  129113. loadXML,
  129114. Rectangle,
  129115. RuntimeError,
  129116. TileProviderError,
  129117. WebMercatorTilingScheme,
  129118. when,
  129119. UrlTemplateImageryProvider) {
  129120. 'use strict';
  129121. /**
  129122. * Creates a {@link UrlTemplateImageryProvider} instance that provides tiled imagery as generated by
  129123. * {@link http://www.maptiler.org/'>MapTiler</a> / <a href='http://www.klokan.cz/projects/gdal2tiles/|GDDAL2Tiles} etc.
  129124. *
  129125. * @exports createTileMapServiceImageryProvider
  129126. *
  129127. * @param {Object} [options] Object with the following properties:
  129128. * @param {String} [options.url='.'] Path to image tiles on server.
  129129. * @param {String} [options.fileExtension='png'] The file extension for images on the server.
  129130. * @param {Object} [options.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL.
  129131. * @param {Credit|String} [options.credit=''] A credit for the data source, which is displayed on the canvas.
  129132. * @param {Number} [options.minimumLevel=0] The minimum level-of-detail supported by the imagery provider. Take care when specifying
  129133. * this that the number of tiles at the minimum level is small, such as four or less. A larger number is likely
  129134. * to result in rendering problems.
  129135. * @param {Number} [options.maximumLevel] The maximum level-of-detail supported by the imagery provider, or undefined if there is no limit.
  129136. * @param {Rectangle} [options.rectangle=Rectangle.MAX_VALUE] The rectangle, in radians, covered by the image.
  129137. * @param {TilingScheme} [options.tilingScheme] The tiling scheme specifying how the ellipsoidal
  129138. * surface is broken into tiles. If this parameter is not provided, a {@link WebMercatorTilingScheme}
  129139. * is used.
  129140. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If the tilingScheme is specified,
  129141. * this parameter is ignored and the tiling scheme's ellipsoid is used instead. If neither
  129142. * parameter is specified, the WGS84 ellipsoid is used.
  129143. * @param {Number} [options.tileWidth=256] Pixel width of image tiles.
  129144. * @param {Number} [options.tileHeight=256] Pixel height of image tiles.
  129145. * @param {Boolean} [options.flipXY] Older versions of gdal2tiles.py flipped X and Y values in tilemapresource.xml.
  129146. * Specifying this option will do the same, allowing for loading of these incorrect tilesets.
  129147. * @returns {UrlTemplateImageryProvider} The imagery provider.
  129148. *
  129149. * @see ArcGisMapServerImageryProvider
  129150. * @see BingMapsImageryProvider
  129151. * @see GoogleEarthImageryProvider
  129152. * @see createOpenStreetMapImageryProvider
  129153. * @see SingleTileImageryProvider
  129154. * @see WebMapServiceImageryProvider
  129155. * @see WebMapTileServiceImageryProvider
  129156. * @see UrlTemplateImageryProvider
  129157. *
  129158. * @see {@link http://www.maptiler.org/|MapTiler}
  129159. * @see {@link http://www.klokan.cz/projects/gdal2tiles/|GDDAL2Tiles}
  129160. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  129161. *
  129162. * @example
  129163. * var tms = Cesium.createTileMapServiceImageryProvider({
  129164. * url : '../images/cesium_maptiler/Cesium_Logo_Color',
  129165. * fileExtension: 'png',
  129166. * maximumLevel: 4,
  129167. * rectangle: new Cesium.Rectangle(
  129168. * Cesium.Math.toRadians(-120.0),
  129169. * Cesium.Math.toRadians(20.0),
  129170. * Cesium.Math.toRadians(-60.0),
  129171. * Cesium.Math.toRadians(40.0))
  129172. * });
  129173. */
  129174. function createTileMapServiceImageryProvider(options) {
  129175. options = defaultValue(options, {});
  129176. if (!defined(options.url)) {
  129177. throw new DeveloperError('options.url is required.');
  129178. }
  129179. var url = options.url;
  129180. var deferred = when.defer();
  129181. var imageryProvider = new UrlTemplateImageryProvider(deferred.promise);
  129182. var metadataError;
  129183. function metadataSuccess(xml) {
  129184. var tileFormatRegex = /tileformat/i;
  129185. var tileSetRegex = /tileset/i;
  129186. var tileSetsRegex = /tilesets/i;
  129187. var bboxRegex = /boundingbox/i;
  129188. var srsRegex = /srs/i;
  129189. var format, bbox, tilesets, srs;
  129190. var tilesetsList = []; //list of TileSets
  129191. // Allowing options properties (already copied to that) to override XML values
  129192. // Iterate XML Document nodes for properties
  129193. var nodeList = xml.childNodes[0].childNodes;
  129194. for (var i = 0; i < nodeList.length; i++){
  129195. if (tileFormatRegex.test(nodeList.item(i).nodeName)) {
  129196. format = nodeList.item(i);
  129197. } else if (tileSetsRegex.test(nodeList.item(i).nodeName)) {
  129198. tilesets = nodeList.item(i); // Node list of TileSets
  129199. var tileSetNodes = nodeList.item(i).childNodes;
  129200. // Iterate the nodes to find all TileSets
  129201. for(var j = 0; j < tileSetNodes.length; j++) {
  129202. if (tileSetRegex.test(tileSetNodes.item(j).nodeName)) {
  129203. // Add them to tilesets list
  129204. tilesetsList.push(tileSetNodes.item(j));
  129205. }
  129206. }
  129207. } else if (bboxRegex.test(nodeList.item(i).nodeName)) {
  129208. bbox = nodeList.item(i);
  129209. } else if (srsRegex.test(nodeList.item(i).nodeName)) {
  129210. srs = nodeList.item(i).textContent;
  129211. }
  129212. }
  129213. var fileExtension = defaultValue(options.fileExtension, format.getAttribute('extension'));
  129214. var tileWidth = defaultValue(options.tileWidth, parseInt(format.getAttribute('width'), 10));
  129215. var tileHeight = defaultValue(options.tileHeight, parseInt(format.getAttribute('height'), 10));
  129216. var minimumLevel = defaultValue(options.minimumLevel, parseInt(tilesetsList[0].getAttribute('order'), 10));
  129217. var maximumLevel = defaultValue(options.maximumLevel, parseInt(tilesetsList[tilesetsList.length - 1].getAttribute('order'), 10));
  129218. var tilingSchemeName = tilesets.getAttribute('profile');
  129219. var tilingScheme = options.tilingScheme;
  129220. if (!defined(tilingScheme)) {
  129221. if (tilingSchemeName === 'geodetic' || tilingSchemeName === 'global-geodetic') {
  129222. tilingScheme = new GeographicTilingScheme({ ellipsoid : options.ellipsoid });
  129223. } else if (tilingSchemeName === 'mercator' || tilingSchemeName === 'global-mercator') {
  129224. tilingScheme = new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid });
  129225. } else {
  129226. var message = joinUrls(url, 'tilemapresource.xml') + 'specifies an unsupported profile attribute, ' + tilingSchemeName + '.';
  129227. metadataError = TileProviderError.handleError(metadataError, imageryProvider, imageryProvider.errorEvent, message, undefined, undefined, undefined, requestMetadata);
  129228. if(!metadataError.retry) {
  129229. deferred.reject(new RuntimeError(message));
  129230. }
  129231. return;
  129232. }
  129233. }
  129234. // rectangle handling
  129235. var rectangle = Rectangle.clone(options.rectangle);
  129236. if (!defined(rectangle)) {
  129237. var sw;
  129238. var ne;
  129239. var swXY;
  129240. var neXY;
  129241. // In older versions of gdal x and y values were flipped, which is why we check for an option to flip
  129242. // the values here as well. Unfortunately there is no way to autodetect whether flipping is needed.
  129243. var flipXY = defaultValue(options.flipXY, false);
  129244. if (flipXY) {
  129245. swXY = new Cartesian2(parseFloat(bbox.getAttribute('miny')), parseFloat(bbox.getAttribute('minx')));
  129246. neXY = new Cartesian2(parseFloat(bbox.getAttribute('maxy')), parseFloat(bbox.getAttribute('maxx')));
  129247. } else {
  129248. swXY = new Cartesian2(parseFloat(bbox.getAttribute('minx')), parseFloat(bbox.getAttribute('miny')));
  129249. neXY = new Cartesian2(parseFloat(bbox.getAttribute('maxx')), parseFloat(bbox.getAttribute('maxy')));
  129250. }
  129251. // Determine based on the profile attribute if this tileset was generated by gdal2tiles.py, which
  129252. // uses 'mercator' and 'geodetic' profiles, or by a tool compliant with the TMS standard, which is
  129253. // 'global-mercator' and 'global-geodetic' profiles. In the gdal2Tiles case, X and Y are always in
  129254. // geodetic degrees.
  129255. var isGdal2tiles = tilingSchemeName === 'geodetic' || tilingSchemeName === 'mercator';
  129256. if (tilingScheme instanceof GeographicTilingScheme || isGdal2tiles) {
  129257. sw = Cartographic.fromDegrees(swXY.x, swXY.y);
  129258. ne = Cartographic.fromDegrees(neXY.x, neXY.y);
  129259. } else {
  129260. var projection = tilingScheme.projection;
  129261. sw = projection.unproject(swXY);
  129262. ne = projection.unproject(neXY);
  129263. }
  129264. rectangle = new Rectangle(sw.longitude, sw.latitude, ne.longitude, ne.latitude);
  129265. }
  129266. // The rectangle must not be outside the bounds allowed by the tiling scheme.
  129267. if (rectangle.west < tilingScheme.rectangle.west) {
  129268. rectangle.west = tilingScheme.rectangle.west;
  129269. }
  129270. if (rectangle.east > tilingScheme.rectangle.east) {
  129271. rectangle.east = tilingScheme.rectangle.east;
  129272. }
  129273. if (rectangle.south < tilingScheme.rectangle.south) {
  129274. rectangle.south = tilingScheme.rectangle.south;
  129275. }
  129276. if (rectangle.north > tilingScheme.rectangle.north) {
  129277. rectangle.north = tilingScheme.rectangle.north;
  129278. }
  129279. // Check the number of tiles at the minimum level. If it's more than four,
  129280. // try requesting the lower levels anyway, because starting at the higher minimum
  129281. // level will cause too many tiles to be downloaded and rendered.
  129282. var swTile = tilingScheme.positionToTileXY(Rectangle.southwest(rectangle), minimumLevel);
  129283. var neTile = tilingScheme.positionToTileXY(Rectangle.northeast(rectangle), minimumLevel);
  129284. var tileCount = (Math.abs(neTile.x - swTile.x) + 1) * (Math.abs(neTile.y - swTile.y) + 1);
  129285. if (tileCount > 4) {
  129286. minimumLevel = 0;
  129287. }
  129288. var templateUrl = joinUrls(url, '{z}/{x}/{reverseY}.' + fileExtension);
  129289. deferred.resolve({
  129290. url : templateUrl,
  129291. tilingScheme : tilingScheme,
  129292. rectangle : rectangle,
  129293. tileWidth : tileWidth,
  129294. tileHeight : tileHeight,
  129295. minimumLevel : minimumLevel,
  129296. maximumLevel : maximumLevel,
  129297. proxy : options.proxy,
  129298. tileDiscardPolicy : options.tileDiscardPolicy,
  129299. credit: options.credit
  129300. });
  129301. }
  129302. function metadataFailure(error) {
  129303. // Can't load XML, still allow options and defaults
  129304. var fileExtension = defaultValue(options.fileExtension, 'png');
  129305. var tileWidth = defaultValue(options.tileWidth, 256);
  129306. var tileHeight = defaultValue(options.tileHeight, 256);
  129307. var minimumLevel = defaultValue(options.minimumLevel, 0);
  129308. var maximumLevel = options.maximumLevel;
  129309. var tilingScheme = defined(options.tilingScheme) ? options.tilingScheme : new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid });
  129310. var rectangle = defaultValue(options.rectangle, tilingScheme.rectangle);
  129311. var templateUrl = joinUrls(url, '{z}/{x}/{reverseY}.' + fileExtension);
  129312. deferred.resolve({
  129313. url : templateUrl,
  129314. tilingScheme : tilingScheme,
  129315. rectangle : rectangle,
  129316. tileWidth : tileWidth,
  129317. tileHeight : tileHeight,
  129318. minimumLevel : minimumLevel,
  129319. maximumLevel : maximumLevel,
  129320. proxy : options.proxy,
  129321. tileDiscardPolicy : options.tileDiscardPolicy,
  129322. credit: options.credit
  129323. });
  129324. }
  129325. function requestMetadata() {
  129326. var resourceUrl = joinUrls(url, 'tilemapresource.xml');
  129327. var proxy = options.proxy;
  129328. if (defined(proxy)) {
  129329. resourceUrl = proxy.getURL(resourceUrl);
  129330. }
  129331. // Try to load remaining parameters from XML
  129332. loadXML(resourceUrl).then(metadataSuccess).otherwise(metadataFailure);
  129333. }
  129334. requestMetadata();
  129335. return imageryProvider;
  129336. }
  129337. return createTileMapServiceImageryProvider;
  129338. });
  129339. /*global define*/
  129340. define('Scene/CreditDisplay',[
  129341. '../Core/Credit',
  129342. '../Core/defaultValue',
  129343. '../Core/defined',
  129344. '../Core/destroyObject',
  129345. '../Core/DeveloperError'
  129346. ], function(
  129347. Credit,
  129348. defaultValue,
  129349. defined,
  129350. destroyObject,
  129351. DeveloperError) {
  129352. 'use strict';
  129353. function displayTextCredit(credit, container, delimiter) {
  129354. if (!defined(credit.element)) {
  129355. var text = credit.text;
  129356. var link = credit.link;
  129357. var span = document.createElement('span');
  129358. if (credit.hasLink()) {
  129359. var a = document.createElement('a');
  129360. a.textContent = text;
  129361. a.href = link;
  129362. a.target = '_blank';
  129363. span.appendChild(a);
  129364. } else {
  129365. span.textContent = text;
  129366. }
  129367. span.className = 'cesium-credit-text';
  129368. credit.element = span;
  129369. }
  129370. if (container.hasChildNodes()) {
  129371. var del = document.createElement('span');
  129372. del.textContent = delimiter;
  129373. del.className = 'cesium-credit-delimiter';
  129374. container.appendChild(del);
  129375. }
  129376. container.appendChild(credit.element);
  129377. }
  129378. function displayImageCredit(credit, container) {
  129379. if (!defined(credit.element)) {
  129380. var text = credit.text;
  129381. var link = credit.link;
  129382. var span = document.createElement('span');
  129383. var content = document.createElement('img');
  129384. content.src = credit.imageUrl;
  129385. content.style['vertical-align'] = 'bottom';
  129386. if (defined(text)) {
  129387. content.alt = text;
  129388. content.title = text;
  129389. }
  129390. if (credit.hasLink()) {
  129391. var a = document.createElement('a');
  129392. a.appendChild(content);
  129393. a.href = link;
  129394. a.target = '_blank';
  129395. span.appendChild(a);
  129396. } else {
  129397. span.appendChild(content);
  129398. }
  129399. span.className = 'cesium-credit-image';
  129400. credit.element = span;
  129401. }
  129402. container.appendChild(credit.element);
  129403. }
  129404. function contains(credits, credit) {
  129405. var len = credits.length;
  129406. for ( var i = 0; i < len; i++) {
  129407. var existingCredit = credits[i];
  129408. if (Credit.equals(existingCredit, credit)) {
  129409. return true;
  129410. }
  129411. }
  129412. return false;
  129413. }
  129414. function removeCreditDomElement(credit) {
  129415. var element = credit.element;
  129416. if (defined(element)) {
  129417. var container = element.parentNode;
  129418. if (!credit.hasImage()) {
  129419. var delimiter = element.previousSibling;
  129420. if (delimiter === null) {
  129421. delimiter = element.nextSibling;
  129422. }
  129423. if (delimiter !== null) {
  129424. container.removeChild(delimiter);
  129425. }
  129426. }
  129427. container.removeChild(element);
  129428. }
  129429. }
  129430. function displayTextCredits(creditDisplay, textCredits) {
  129431. var i;
  129432. var index;
  129433. var credit;
  129434. var displayedTextCredits = creditDisplay._displayedCredits.textCredits;
  129435. for (i = 0; i < textCredits.length; i++) {
  129436. credit = textCredits[i];
  129437. if (defined(credit)) {
  129438. index = displayedTextCredits.indexOf(credit);
  129439. if (index === -1) {
  129440. displayTextCredit(credit, creditDisplay._textContainer, creditDisplay._delimiter);
  129441. } else {
  129442. displayedTextCredits.splice(index, 1);
  129443. }
  129444. }
  129445. }
  129446. for (i = 0; i < displayedTextCredits.length; i++) {
  129447. credit = displayedTextCredits[i];
  129448. if (defined(credit)) {
  129449. removeCreditDomElement(credit);
  129450. }
  129451. }
  129452. }
  129453. function displayImageCredits(creditDisplay, imageCredits) {
  129454. var i;
  129455. var index;
  129456. var credit;
  129457. var displayedImageCredits = creditDisplay._displayedCredits.imageCredits;
  129458. for (i = 0; i < imageCredits.length; i++) {
  129459. credit = imageCredits[i];
  129460. if (defined(credit)) {
  129461. index = displayedImageCredits.indexOf(credit);
  129462. if (index === -1) {
  129463. displayImageCredit(credit, creditDisplay._imageContainer);
  129464. } else {
  129465. displayedImageCredits.splice(index, 1);
  129466. }
  129467. }
  129468. }
  129469. for (i = 0; i < displayedImageCredits.length; i++) {
  129470. credit = displayedImageCredits[i];
  129471. if (defined(credit)) {
  129472. removeCreditDomElement(credit);
  129473. }
  129474. }
  129475. }
  129476. /**
  129477. * The credit display is responsible for displaying credits on screen.
  129478. *
  129479. * @param {HTMLElement} container The HTML element where credits will be displayed
  129480. * @param {String} [delimiter= ' • '] The string to separate text credits
  129481. *
  129482. * @alias CreditDisplay
  129483. * @constructor
  129484. *
  129485. * @example
  129486. * var creditDisplay = new Cesium.CreditDisplay(creditContainer);
  129487. */
  129488. function CreditDisplay(container, delimiter) {
  129489. if (!defined(container)) {
  129490. throw new DeveloperError('credit container is required');
  129491. }
  129492. var imageContainer = document.createElement('span');
  129493. imageContainer.className = 'cesium-credit-imageContainer';
  129494. var textContainer = document.createElement('span');
  129495. textContainer.className = 'cesium-credit-textContainer';
  129496. container.appendChild(imageContainer);
  129497. container.appendChild(textContainer);
  129498. this._delimiter = defaultValue(delimiter, ' • ');
  129499. this._textContainer = textContainer;
  129500. this._imageContainer = imageContainer;
  129501. this._defaultImageCredits = [];
  129502. this._defaultTextCredits = [];
  129503. this._displayedCredits = {
  129504. imageCredits : [],
  129505. textCredits : []
  129506. };
  129507. this._currentFrameCredits = {
  129508. imageCredits : [],
  129509. textCredits : []
  129510. };
  129511. /**
  129512. * The HTML element where credits will be displayed.
  129513. * @type {HTMLElement}
  129514. */
  129515. this.container = container;
  129516. }
  129517. /**
  129518. * Adds a credit to the list of current credits to be displayed in the credit container
  129519. *
  129520. * @param {Credit} credit The credit to display
  129521. */
  129522. CreditDisplay.prototype.addCredit = function(credit) {
  129523. if (!defined(credit)) {
  129524. throw new DeveloperError('credit must be defined');
  129525. }
  129526. if (credit.hasImage()) {
  129527. var imageCredits = this._currentFrameCredits.imageCredits;
  129528. if (!contains(this._defaultImageCredits, credit)) {
  129529. imageCredits[credit.id] = credit;
  129530. }
  129531. } else {
  129532. var textCredits = this._currentFrameCredits.textCredits;
  129533. if (!contains(this._defaultTextCredits, credit)) {
  129534. textCredits[credit.id] = credit;
  129535. }
  129536. }
  129537. };
  129538. /**
  129539. * Adds credits that will persist until they are removed
  129540. *
  129541. * @param {Credit} credit The credit to added to defaults
  129542. */
  129543. CreditDisplay.prototype.addDefaultCredit = function(credit) {
  129544. if (!defined(credit)) {
  129545. throw new DeveloperError('credit must be defined');
  129546. }
  129547. if (credit.hasImage()) {
  129548. var imageCredits = this._defaultImageCredits;
  129549. if (!contains(imageCredits, credit)) {
  129550. imageCredits.push(credit);
  129551. }
  129552. } else {
  129553. var textCredits = this._defaultTextCredits;
  129554. if (!contains(textCredits, credit)) {
  129555. textCredits.push(credit);
  129556. }
  129557. }
  129558. };
  129559. /**
  129560. * Removes a default credit
  129561. *
  129562. * @param {Credit} credit The credit to be removed from defaults
  129563. */
  129564. CreditDisplay.prototype.removeDefaultCredit = function(credit) {
  129565. if (!defined(credit)) {
  129566. throw new DeveloperError('credit must be defined');
  129567. }
  129568. var index;
  129569. if (credit.hasImage()) {
  129570. index = this._defaultImageCredits.indexOf(credit);
  129571. if (index !== -1) {
  129572. this._defaultImageCredits.splice(index, 1);
  129573. }
  129574. } else {
  129575. index = this._defaultTextCredits.indexOf(credit);
  129576. if (index !== -1) {
  129577. this._defaultTextCredits.splice(index, 1);
  129578. }
  129579. }
  129580. };
  129581. /**
  129582. * Resets the credit display to a beginning of frame state, clearing out current credits.
  129583. *
  129584. * @param {Credit} credit The credit to display
  129585. */
  129586. CreditDisplay.prototype.beginFrame = function() {
  129587. this._currentFrameCredits.imageCredits.length = 0;
  129588. this._currentFrameCredits.textCredits.length = 0;
  129589. };
  129590. /**
  129591. * Sets the credit display to the end of frame state, displaying current credits in the credit container
  129592. *
  129593. * @param {Credit} credit The credit to display
  129594. */
  129595. CreditDisplay.prototype.endFrame = function() {
  129596. var textCredits = this._defaultTextCredits.concat(this._currentFrameCredits.textCredits);
  129597. var imageCredits = this._defaultImageCredits.concat(this._currentFrameCredits.imageCredits);
  129598. displayTextCredits(this, textCredits);
  129599. displayImageCredits(this, imageCredits);
  129600. this._displayedCredits.textCredits = textCredits;
  129601. this._displayedCredits.imageCredits = imageCredits;
  129602. };
  129603. /**
  129604. * Destroys the resources held by this object. Destroying an object allows for deterministic
  129605. * release of resources, instead of relying on the garbage collector to destroy this object.
  129606. * <br /><br />
  129607. * Once an object is destroyed, it should not be used; calling any function other than
  129608. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  129609. * assign the return value (<code>undefined</code>) to the object as done in the example.
  129610. *
  129611. * @returns {undefined}
  129612. *
  129613. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  129614. */
  129615. CreditDisplay.prototype.destroy = function() {
  129616. this.container.removeChild(this._textContainer);
  129617. this.container.removeChild(this._imageContainer);
  129618. return destroyObject(this);
  129619. };
  129620. /**
  129621. * Returns true if this object was destroyed; otherwise, false.
  129622. * <br /><br />
  129623. *
  129624. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  129625. */
  129626. CreditDisplay.prototype.isDestroyed = function() {
  129627. return false;
  129628. };
  129629. return CreditDisplay;
  129630. });
  129631. /*global define*/
  129632. define('Scene/DebugAppearance',[
  129633. '../Core/defaultValue',
  129634. '../Core/defined',
  129635. '../Core/defineProperties',
  129636. '../Core/DeveloperError',
  129637. './Appearance'
  129638. ], function(
  129639. defaultValue,
  129640. defined,
  129641. defineProperties,
  129642. DeveloperError,
  129643. Appearance) {
  129644. 'use strict';
  129645. /**
  129646. * Visualizes a vertex attribute by displaying it as a color for debugging.
  129647. * <p>
  129648. * Components for well-known unit-length vectors, i.e., <code>normal</code>,
  129649. * <code>binormal</code>, and <code>tangent</code>, are scaled and biased
  129650. * from [-1.0, 1.0] to (-1.0, 1.0).
  129651. * </p>
  129652. *
  129653. * @alias DebugAppearance
  129654. * @constructor
  129655. *
  129656. * @param {Object} options Object with the following properties:
  129657. * @param {String} options.attributeName The name of the attribute to visualize.
  129658. * @param {Boolean} options.perInstanceAttribute Boolean that determines whether this attribute is a per-instance geometry attribute.
  129659. * @param {String} [options.glslDatatype='vec3'] The GLSL datatype of the attribute. Supported datatypes are <code>float</code>, <code>vec2</code>, <code>vec3</code>, and <code>vec4</code>.
  129660. * @param {String} [options.vertexShaderSource] Optional GLSL vertex shader source to override the default vertex shader.
  129661. * @param {String} [options.fragmentShaderSource] Optional GLSL fragment shader source to override the default fragment shader.
  129662. * @param {RenderState} [options.renderState] Optional render state to override the default render state.
  129663. *
  129664. * @exception {DeveloperError} options.glslDatatype must be float, vec2, vec3, or vec4.
  129665. *
  129666. * @example
  129667. * var primitive = new Cesium.Primitive({
  129668. * geometryInstances : // ...
  129669. * appearance : new Cesium.DebugAppearance({
  129670. * attributeName : 'normal'
  129671. * })
  129672. * });
  129673. */
  129674. function DebugAppearance(options) {
  129675. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  129676. var attributeName = options.attributeName;
  129677. var perInstanceAttribute = options.perInstanceAttribute;
  129678. if (!defined(attributeName)) {
  129679. throw new DeveloperError('options.attributeName is required.');
  129680. }
  129681. if (!defined(perInstanceAttribute)) {
  129682. throw new DeveloperError('options.perInstanceAttribute is required.');
  129683. }
  129684. var glslDatatype = defaultValue(options.glslDatatype, 'vec3');
  129685. var varyingName = 'v_' + attributeName;
  129686. var getColor;
  129687. // Well-known normalized vector attributes in VertexFormat
  129688. if ((attributeName === 'normal') || (attributeName === 'binormal') || (attributeName === 'tangent')) {
  129689. getColor = 'vec4 getColor() { return vec4((' + varyingName + ' + vec3(1.0)) * 0.5, 1.0); }\n';
  129690. } else {
  129691. // All other attributes, both well-known and custom
  129692. if (attributeName === 'st') {
  129693. glslDatatype = 'vec2';
  129694. }
  129695. switch(glslDatatype) {
  129696. case 'float':
  129697. getColor = 'vec4 getColor() { return vec4(vec3(' + varyingName + '), 1.0); }\n';
  129698. break;
  129699. case 'vec2':
  129700. getColor = 'vec4 getColor() { return vec4(' + varyingName + ', 0.0, 1.0); }\n';
  129701. break;
  129702. case 'vec3':
  129703. getColor = 'vec4 getColor() { return vec4(' + varyingName + ', 1.0); }\n';
  129704. break;
  129705. case 'vec4':
  129706. getColor = 'vec4 getColor() { return ' + varyingName + '; }\n';
  129707. break;
  129708. default:
  129709. throw new DeveloperError('options.glslDatatype must be float, vec2, vec3, or vec4.');
  129710. }
  129711. }
  129712. var vs =
  129713. 'attribute vec3 position3DHigh;\n' +
  129714. 'attribute vec3 position3DLow;\n' +
  129715. 'attribute float batchId;\n' +
  129716. (perInstanceAttribute ? '' : 'attribute ' + glslDatatype + ' ' + attributeName + ';\n') +
  129717. 'varying ' + glslDatatype + ' ' + varyingName + ';\n' +
  129718. 'void main()\n' +
  129719. '{\n' +
  129720. 'vec4 p = czm_translateRelativeToEye(position3DHigh, position3DLow);\n' +
  129721. (perInstanceAttribute ?
  129722. varyingName + ' = czm_batchTable_' + attributeName + '(batchId);\n' :
  129723. varyingName + ' = ' + attributeName + ';\n') +
  129724. 'gl_Position = czm_modelViewProjectionRelativeToEye * p;\n' +
  129725. '}';
  129726. var fs =
  129727. 'varying ' + glslDatatype + ' ' + varyingName + ';\n' +
  129728. getColor + '\n' +
  129729. 'void main()\n' +
  129730. '{\n' +
  129731. 'gl_FragColor = getColor();\n' +
  129732. '}';
  129733. /**
  129734. * This property is part of the {@link Appearance} interface, but is not
  129735. * used by {@link DebugAppearance} since a fully custom fragment shader is used.
  129736. *
  129737. * @type Material
  129738. *
  129739. * @default undefined
  129740. */
  129741. this.material = undefined;
  129742. /**
  129743. * When <code>true</code>, the geometry is expected to appear translucent.
  129744. *
  129745. * @type {Boolean}
  129746. *
  129747. * @default false
  129748. */
  129749. this.translucent = defaultValue(options.translucent, false);
  129750. this._vertexShaderSource = defaultValue(options.vertexShaderSource, vs);
  129751. this._fragmentShaderSource = defaultValue(options.fragmentShaderSource, fs);
  129752. this._renderState = Appearance.getDefaultRenderState(false, false, options.renderState);
  129753. this._closed = defaultValue(options.closed, false);
  129754. // Non-derived members
  129755. this._attributeName = attributeName;
  129756. this._glslDatatype = glslDatatype;
  129757. }
  129758. defineProperties(DebugAppearance.prototype, {
  129759. /**
  129760. * The GLSL source code for the vertex shader.
  129761. *
  129762. * @memberof DebugAppearance.prototype
  129763. *
  129764. * @type {String}
  129765. * @readonly
  129766. */
  129767. vertexShaderSource : {
  129768. get : function() {
  129769. return this._vertexShaderSource;
  129770. }
  129771. },
  129772. /**
  129773. * The GLSL source code for the fragment shader. The full fragment shader
  129774. * source is built procedurally taking into account the {@link DebugAppearance#material}.
  129775. * Use {@link DebugAppearance#getFragmentShaderSource} to get the full source.
  129776. *
  129777. * @memberof DebugAppearance.prototype
  129778. *
  129779. * @type {String}
  129780. * @readonly
  129781. */
  129782. fragmentShaderSource : {
  129783. get : function() {
  129784. return this._fragmentShaderSource;
  129785. }
  129786. },
  129787. /**
  129788. * The WebGL fixed-function state to use when rendering the geometry.
  129789. *
  129790. * @memberof DebugAppearance.prototype
  129791. *
  129792. * @type {Object}
  129793. * @readonly
  129794. */
  129795. renderState : {
  129796. get : function() {
  129797. return this._renderState;
  129798. }
  129799. },
  129800. /**
  129801. * When <code>true</code>, the geometry is expected to be closed.
  129802. *
  129803. * @memberof DebugAppearance.prototype
  129804. *
  129805. * @type {Boolean}
  129806. * @readonly
  129807. *
  129808. * @default false
  129809. */
  129810. closed : {
  129811. get : function() {
  129812. return this._closed;
  129813. }
  129814. },
  129815. /**
  129816. * The name of the attribute being visualized.
  129817. *
  129818. * @memberof DebugAppearance.prototype
  129819. *
  129820. * @type {String}
  129821. * @readonly
  129822. */
  129823. attributeName : {
  129824. get : function() {
  129825. return this._attributeName;
  129826. }
  129827. },
  129828. /**
  129829. * The GLSL datatype of the attribute being visualized.
  129830. *
  129831. * @memberof DebugAppearance.prototype
  129832. *
  129833. * @type {String}
  129834. * @readonly
  129835. */
  129836. glslDatatype : {
  129837. get : function() {
  129838. return this._glslDatatype;
  129839. }
  129840. }
  129841. });
  129842. /**
  129843. * Returns the full GLSL fragment shader source, which for {@link DebugAppearance} is just
  129844. * {@link DebugAppearance#fragmentShaderSource}.
  129845. *
  129846. * @function
  129847. *
  129848. * @returns {String} The full GLSL fragment shader source.
  129849. */
  129850. DebugAppearance.prototype.getFragmentShaderSource = Appearance.prototype.getFragmentShaderSource;
  129851. /**
  129852. * Determines if the geometry is translucent based on {@link DebugAppearance#translucent}.
  129853. *
  129854. * @function
  129855. *
  129856. * @returns {Boolean} <code>true</code> if the appearance is translucent.
  129857. */
  129858. DebugAppearance.prototype.isTranslucent = Appearance.prototype.isTranslucent;
  129859. /**
  129860. * Creates a render state. This is not the final render state instance; instead,
  129861. * it can contain a subset of render state properties identical to the render state
  129862. * created in the context.
  129863. *
  129864. * @function
  129865. *
  129866. * @returns {Object} The render state.
  129867. */
  129868. DebugAppearance.prototype.getRenderState = Appearance.prototype.getRenderState;
  129869. return DebugAppearance;
  129870. });
  129871. /*global define*/
  129872. define('Scene/DebugCameraPrimitive',[
  129873. '../Core/BoundingSphere',
  129874. '../Core/Cartesian3',
  129875. '../Core/Cartesian4',
  129876. '../Core/Color',
  129877. '../Core/ColorGeometryInstanceAttribute',
  129878. '../Core/ComponentDatatype',
  129879. '../Core/defaultValue',
  129880. '../Core/defined',
  129881. '../Core/destroyObject',
  129882. '../Core/DeveloperError',
  129883. '../Core/GeometryAttribute',
  129884. '../Core/GeometryAttributes',
  129885. '../Core/GeometryInstance',
  129886. '../Core/Matrix4',
  129887. '../Core/PrimitiveType',
  129888. './PerInstanceColorAppearance',
  129889. './Primitive'
  129890. ], function(
  129891. BoundingSphere,
  129892. Cartesian3,
  129893. Cartesian4,
  129894. Color,
  129895. ColorGeometryInstanceAttribute,
  129896. ComponentDatatype,
  129897. defaultValue,
  129898. defined,
  129899. destroyObject,
  129900. DeveloperError,
  129901. GeometryAttribute,
  129902. GeometryAttributes,
  129903. GeometryInstance,
  129904. Matrix4,
  129905. PrimitiveType,
  129906. PerInstanceColorAppearance,
  129907. Primitive) {
  129908. 'use strict';
  129909. /**
  129910. * Draws the outline of the camera's view frustum.
  129911. *
  129912. * @alias DebugCameraPrimitive
  129913. * @constructor
  129914. *
  129915. * @param {Object} options Object with the following properties:
  129916. * @param {Camera} options.camera The camera.
  129917. * @param {Color} [options.color=Color.CYAN] The color of the debug outline.
  129918. * @param {Boolean} [options.updateOnChange=true] Whether the primitive updates when the underlying camera changes.
  129919. * @param {Boolean} [options.show=true] Determines if this primitive will be shown.
  129920. * @param {Object} [options.id] A user-defined object to return when the instance is picked with {@link Scene#pick}.
  129921. *
  129922. * @example
  129923. * primitives.add(new Cesium.DebugCameraPrimitive({
  129924. * camera : camera,
  129925. * color : Cesium.Color.YELLOW
  129926. * }));
  129927. */
  129928. function DebugCameraPrimitive(options) {
  129929. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  129930. if (!defined(options.camera)) {
  129931. throw new DeveloperError('options.camera is required.');
  129932. }
  129933. this._camera = options.camera;
  129934. this._color = defaultValue(options.color, Color.CYAN);
  129935. this._updateOnChange = defaultValue(options.updateOnChange, true);
  129936. /**
  129937. * Determines if this primitive will be shown.
  129938. *
  129939. * @type Boolean
  129940. * @default true
  129941. */
  129942. this.show = defaultValue(options.show, true);
  129943. /**
  129944. * User-defined object returned when the primitive is picked.
  129945. *
  129946. * @type {Object}
  129947. * @default undefined
  129948. *
  129949. * @see Scene#pick
  129950. */
  129951. this.id = options.id;
  129952. this._id = undefined;
  129953. this._outlinePrimitive = undefined;
  129954. this._planesPrimitive = undefined;
  129955. }
  129956. var frustumCornersNDC = new Array(8);
  129957. frustumCornersNDC[0] = new Cartesian4(-1.0, -1.0, -1.0, 1.0);
  129958. frustumCornersNDC[1] = new Cartesian4(1.0, -1.0, -1.0, 1.0);
  129959. frustumCornersNDC[2] = new Cartesian4(1.0, 1.0, -1.0, 1.0);
  129960. frustumCornersNDC[3] = new Cartesian4(-1.0, 1.0, -1.0, 1.0);
  129961. frustumCornersNDC[4] = new Cartesian4(-1.0, -1.0, 1.0, 1.0);
  129962. frustumCornersNDC[5] = new Cartesian4(1.0, -1.0, 1.0, 1.0);
  129963. frustumCornersNDC[6] = new Cartesian4(1.0, 1.0, 1.0, 1.0);
  129964. frustumCornersNDC[7] = new Cartesian4(-1.0, 1.0, 1.0, 1.0);
  129965. var scratchMatrix = new Matrix4();
  129966. var scratchFrustumCorners = new Array(8);
  129967. for (var i = 0; i < 8; ++i) {
  129968. scratchFrustumCorners[i] = new Cartesian4();
  129969. }
  129970. var scratchColor = new Color();
  129971. /**
  129972. * @private
  129973. */
  129974. DebugCameraPrimitive.prototype.update = function(frameState) {
  129975. if (!this.show) {
  129976. return;
  129977. }
  129978. if (this._updateOnChange) {
  129979. // Recreate the primitive every frame
  129980. this._outlinePrimitive = this._outlinePrimitive && this._outlinePrimitive.destroy();
  129981. this._planesPrimitive = this._planesPrimitive && this._planesPrimitive.destroy();
  129982. }
  129983. if (!defined(this._outlinePrimitive)) {
  129984. var view = this._camera.viewMatrix;
  129985. var projection = this._camera.frustum.projectionMatrix;
  129986. var viewProjection = Matrix4.multiply(projection, view, scratchMatrix);
  129987. var inverseViewProjection = Matrix4.inverse(viewProjection, scratchMatrix);
  129988. var positions = new Float64Array(8 * 3);
  129989. for (var i = 0; i < 8; ++i) {
  129990. var corner = Cartesian4.clone(frustumCornersNDC[i], scratchFrustumCorners[i]);
  129991. Matrix4.multiplyByVector(inverseViewProjection, corner, corner);
  129992. Cartesian3.divideByScalar(corner, corner.w, corner); // Handle the perspective divide
  129993. positions[i * 3] = corner.x;
  129994. positions[i * 3 + 1] = corner.y;
  129995. positions[i * 3 + 2] = corner.z;
  129996. }
  129997. var boundingSphere = new BoundingSphere.fromVertices(positions);
  129998. var attributes = new GeometryAttributes();
  129999. attributes.position = new GeometryAttribute({
  130000. componentDatatype : ComponentDatatype.DOUBLE,
  130001. componentsPerAttribute : 3,
  130002. values : positions
  130003. });
  130004. // Create the outline primitive
  130005. var outlineIndices = new Uint16Array([0,1,1,2,2,3,3,0,0,4,4,7,7,3,7,6,6,2,2,1,1,5,5,4,5,6]);
  130006. this._outlinePrimitive = new Primitive({
  130007. geometryInstances : new GeometryInstance({
  130008. geometry : {
  130009. attributes : attributes,
  130010. indices : outlineIndices,
  130011. primitiveType : PrimitiveType.LINES,
  130012. boundingSphere : boundingSphere
  130013. },
  130014. attributes : {
  130015. color : ColorGeometryInstanceAttribute.fromColor(this._color)
  130016. },
  130017. id : this.id,
  130018. pickPrimitive : this
  130019. }),
  130020. appearance : new PerInstanceColorAppearance({
  130021. translucent : false,
  130022. flat : true
  130023. }),
  130024. asynchronous : false
  130025. });
  130026. // Create the planes primitive
  130027. var planesIndices = new Uint16Array([4,5,6,4,6,7,5,1,2,5,2,6,7,6,2,7,2,3,0,1,5,0,5,4,0,4,7,0,7,3,1,0,3,1,3,2]);
  130028. this._planesPrimitive = new Primitive({
  130029. geometryInstances : new GeometryInstance({
  130030. geometry : {
  130031. attributes : attributes,
  130032. indices : planesIndices,
  130033. primitiveType : PrimitiveType.TRIANGLES,
  130034. boundingSphere : boundingSphere
  130035. },
  130036. attributes : {
  130037. color : ColorGeometryInstanceAttribute.fromColor(Color.fromAlpha(this._color, 0.1, scratchColor))
  130038. },
  130039. id : this.id,
  130040. pickPrimitive : this
  130041. }),
  130042. appearance : new PerInstanceColorAppearance({
  130043. translucent : true,
  130044. flat : true
  130045. }),
  130046. asynchronous : false
  130047. });
  130048. }
  130049. this._outlinePrimitive.update(frameState);
  130050. this._planesPrimitive.update(frameState);
  130051. };
  130052. /**
  130053. * Returns true if this object was destroyed; otherwise, false.
  130054. * <p>
  130055. * If this object was destroyed, it should not be used; calling any function other than
  130056. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  130057. * </p>
  130058. *
  130059. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  130060. *
  130061. * @see DebugCameraPrimitive#destroy
  130062. */
  130063. DebugCameraPrimitive.prototype.isDestroyed = function() {
  130064. return false;
  130065. };
  130066. /**
  130067. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  130068. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  130069. * <p>
  130070. * Once an object is destroyed, it should not be used; calling any function other than
  130071. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  130072. * assign the return value (<code>undefined</code>) to the object as done in the example.
  130073. * </p>
  130074. *
  130075. * @returns {undefined}
  130076. *
  130077. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  130078. *
  130079. * @example
  130080. * p = p && p.destroy();
  130081. *
  130082. * @see DebugCameraPrimitive#isDestroyed
  130083. */
  130084. DebugCameraPrimitive.prototype.destroy = function() {
  130085. this._outlinePrimitive = this._outlinePrimitive && this._outlinePrimitive.destroy();
  130086. this._planesPrimitive = this._planesPrimitive && this._planesPrimitive.destroy();
  130087. return destroyObject(this);
  130088. };
  130089. return DebugCameraPrimitive;
  130090. });
  130091. /*global define*/
  130092. define('Scene/DebugModelMatrixPrimitive',[
  130093. '../Core/Cartesian3',
  130094. '../Core/Color',
  130095. '../Core/defaultValue',
  130096. '../Core/defined',
  130097. '../Core/destroyObject',
  130098. '../Core/GeometryInstance',
  130099. '../Core/Matrix4',
  130100. '../Core/PolylineGeometry',
  130101. './PolylineColorAppearance',
  130102. './Primitive'
  130103. ], function(
  130104. Cartesian3,
  130105. Color,
  130106. defaultValue,
  130107. defined,
  130108. destroyObject,
  130109. GeometryInstance,
  130110. Matrix4,
  130111. PolylineGeometry,
  130112. PolylineColorAppearance,
  130113. Primitive) {
  130114. 'use strict';
  130115. /**
  130116. * Draws the axes of a reference frame defined by a matrix that transforms to world
  130117. * coordinates, i.e., Earth's WGS84 coordinates. The most prominent example is
  130118. * a primitives <code>modelMatrix</code>.
  130119. * <p>
  130120. * The X axis is red; Y is green; and Z is blue.
  130121. * </p>
  130122. * <p>
  130123. * This is for debugging only; it is not optimized for production use.
  130124. * </p>
  130125. *
  130126. * @alias DebugModelMatrixPrimitive
  130127. * @constructor
  130128. *
  130129. * @param {Object} [options] Object with the following properties:
  130130. * @param {Number} [options.length=10000000.0] The length of the axes in meters.
  130131. * @param {Number} [options.width=2.0] The width of the axes in pixels.
  130132. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 matrix that defines the reference frame, i.e., origin plus axes, to visualize.
  130133. * @param {Boolean} [options.show=true] Determines if this primitive will be shown.
  130134. * @param {Object} [options.id] A user-defined object to return when the instance is picked with {@link Scene#pick}
  130135. *
  130136. * @example
  130137. * primitives.add(new Cesium.DebugModelMatrixPrimitive({
  130138. * modelMatrix : primitive.modelMatrix, // primitive to debug
  130139. * length : 100000.0,
  130140. * width : 10.0
  130141. * }));
  130142. */
  130143. function DebugModelMatrixPrimitive(options) {
  130144. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  130145. /**
  130146. * The length of the axes in meters.
  130147. *
  130148. * @type {Number}
  130149. * @default 10000000.0
  130150. */
  130151. this.length = defaultValue(options.length, 10000000.0);
  130152. this._length = undefined;
  130153. /**
  130154. * The width of the axes in pixels.
  130155. *
  130156. * @type {Number}
  130157. * @default 2.0
  130158. */
  130159. this.width = defaultValue(options.width, 2.0);
  130160. this._width = undefined;
  130161. /**
  130162. * Determines if this primitive will be shown.
  130163. *
  130164. * @type Boolean
  130165. * @default true
  130166. */
  130167. this.show = defaultValue(options.show, true);
  130168. /**
  130169. * The 4x4 matrix that defines the reference frame, i.e., origin plus axes, to visualize.
  130170. *
  130171. * @type {Matrix4}
  130172. * @default {@link Matrix4.IDENTITY}
  130173. */
  130174. this.modelMatrix = Matrix4.clone(defaultValue(options.modelMatrix, Matrix4.IDENTITY));
  130175. this._modelMatrix = new Matrix4();
  130176. /**
  130177. * User-defined object returned when the primitive is picked.
  130178. *
  130179. * @type {Object}
  130180. * @default undefined
  130181. *
  130182. * @see Scene#pick
  130183. */
  130184. this.id = options.id;
  130185. this._id = undefined;
  130186. this._primitive = undefined;
  130187. }
  130188. /**
  130189. * @private
  130190. */
  130191. DebugModelMatrixPrimitive.prototype.update = function(frameState) {
  130192. if (!this.show) {
  130193. return;
  130194. }
  130195. if (!defined(this._primitive) ||
  130196. (!Matrix4.equals(this._modelMatrix, this.modelMatrix)) ||
  130197. (this._length !== this.length) ||
  130198. (this._width !== this.width) ||
  130199. (this._id !== this.id)) {
  130200. this._modelMatrix = Matrix4.clone(this.modelMatrix, this._modelMatrix);
  130201. this._length = this.length;
  130202. this._width = this.width;
  130203. this._id = this.id;
  130204. if (defined(this._primitive)) {
  130205. this._primitive.destroy();
  130206. }
  130207. // Workaround projecting (0, 0, 0)
  130208. if ((this.modelMatrix[12] === 0.0 && this.modelMatrix[13] === 0.0 && this.modelMatrix[14] === 0.0)) {
  130209. this.modelMatrix[14] = 0.01;
  130210. }
  130211. var x = new GeometryInstance({
  130212. geometry : new PolylineGeometry({
  130213. positions : [
  130214. Cartesian3.ZERO,
  130215. Cartesian3.UNIT_X
  130216. ],
  130217. width : this.width,
  130218. vertexFormat : PolylineColorAppearance.VERTEX_FORMAT,
  130219. colors : [
  130220. Color.RED,
  130221. Color.RED
  130222. ],
  130223. followSurface: false
  130224. }),
  130225. modelMatrix : Matrix4.multiplyByUniformScale(this.modelMatrix, this.length, new Matrix4()),
  130226. id : this.id,
  130227. pickPrimitive : this
  130228. });
  130229. var y = new GeometryInstance({
  130230. geometry : new PolylineGeometry({
  130231. positions : [
  130232. Cartesian3.ZERO,
  130233. Cartesian3.UNIT_Y
  130234. ],
  130235. width : this.width,
  130236. vertexFormat : PolylineColorAppearance.VERTEX_FORMAT,
  130237. colors : [
  130238. Color.GREEN,
  130239. Color.GREEN
  130240. ],
  130241. followSurface: false
  130242. }),
  130243. modelMatrix : Matrix4.multiplyByUniformScale(this.modelMatrix, this.length, new Matrix4()),
  130244. id : this.id,
  130245. pickPrimitive : this
  130246. });
  130247. var z = new GeometryInstance({
  130248. geometry : new PolylineGeometry({
  130249. positions : [
  130250. Cartesian3.ZERO,
  130251. Cartesian3.UNIT_Z
  130252. ],
  130253. width : this.width,
  130254. vertexFormat : PolylineColorAppearance.VERTEX_FORMAT,
  130255. colors : [
  130256. Color.BLUE,
  130257. Color.BLUE
  130258. ],
  130259. followSurface: false
  130260. }),
  130261. modelMatrix : Matrix4.multiplyByUniformScale(this.modelMatrix, this.length, new Matrix4()),
  130262. id : this.id,
  130263. pickPrimitive : this
  130264. });
  130265. this._primitive = new Primitive({
  130266. geometryInstances : [x, y, z],
  130267. appearance : new PolylineColorAppearance(),
  130268. asynchronous : false
  130269. });
  130270. }
  130271. this._primitive.update(frameState);
  130272. };
  130273. /**
  130274. * Returns true if this object was destroyed; otherwise, false.
  130275. * <p>
  130276. * If this object was destroyed, it should not be used; calling any function other than
  130277. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  130278. * </p>
  130279. *
  130280. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  130281. *
  130282. * @see DebugModelMatrixPrimitive#destroy
  130283. */
  130284. DebugModelMatrixPrimitive.prototype.isDestroyed = function() {
  130285. return false;
  130286. };
  130287. /**
  130288. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  130289. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  130290. * <p>
  130291. * Once an object is destroyed, it should not be used; calling any function other than
  130292. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  130293. * assign the return value (<code>undefined</code>) to the object as done in the example.
  130294. * </p>
  130295. *
  130296. * @returns {undefined}
  130297. *
  130298. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  130299. *
  130300. * @example
  130301. * p = p && p.destroy();
  130302. *
  130303. * @see DebugModelMatrixPrimitive#isDestroyed
  130304. */
  130305. DebugModelMatrixPrimitive.prototype.destroy = function() {
  130306. this._primitive = this._primitive && this._primitive.destroy();
  130307. return destroyObject(this);
  130308. };
  130309. return DebugModelMatrixPrimitive;
  130310. });
  130311. //This file is automatically rebuilt by the Cesium build process.
  130312. /*global define*/
  130313. define('Shaders/DepthPlaneFS',[],function() {
  130314. 'use strict';
  130315. return "varying vec4 positionEC;\n\
  130316. void main()\n\
  130317. {\n\
  130318. czm_ellipsoid ellipsoid = czm_getWgs84EllipsoidEC();\n\
  130319. vec3 direction = normalize(positionEC.xyz);\n\
  130320. czm_ray ray = czm_ray(vec3(0.0), direction);\n\
  130321. czm_raySegment intersection = czm_rayEllipsoidIntersectionInterval(ray, ellipsoid);\n\
  130322. if (!czm_isEmpty(intersection))\n\
  130323. {\n\
  130324. gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);\n\
  130325. }\n\
  130326. else\n\
  130327. {\n\
  130328. discard;\n\
  130329. }\n\
  130330. }\n\
  130331. ";
  130332. });
  130333. //This file is automatically rebuilt by the Cesium build process.
  130334. /*global define*/
  130335. define('Shaders/DepthPlaneVS',[],function() {
  130336. 'use strict';
  130337. return "attribute vec4 position;\n\
  130338. varying vec4 positionEC;\n\
  130339. void main()\n\
  130340. {\n\
  130341. positionEC = czm_modelView * position;\n\
  130342. gl_Position = czm_projection * positionEC;\n\
  130343. }\n\
  130344. ";
  130345. });
  130346. /*global define*/
  130347. define('Scene/DepthPlane',[
  130348. '../Core/BoundingSphere',
  130349. '../Core/Cartesian3',
  130350. '../Core/ComponentDatatype',
  130351. '../Core/defined',
  130352. '../Core/FeatureDetection',
  130353. '../Core/Geometry',
  130354. '../Core/GeometryAttribute',
  130355. '../Core/PrimitiveType',
  130356. '../Renderer/BufferUsage',
  130357. '../Renderer/DrawCommand',
  130358. '../Renderer/Pass',
  130359. '../Renderer/RenderState',
  130360. '../Renderer/ShaderProgram',
  130361. '../Renderer/VertexArray',
  130362. '../Shaders/DepthPlaneFS',
  130363. '../Shaders/DepthPlaneVS',
  130364. './DepthFunction',
  130365. './SceneMode'
  130366. ], function(
  130367. BoundingSphere,
  130368. Cartesian3,
  130369. ComponentDatatype,
  130370. defined,
  130371. FeatureDetection,
  130372. Geometry,
  130373. GeometryAttribute,
  130374. PrimitiveType,
  130375. BufferUsage,
  130376. DrawCommand,
  130377. Pass,
  130378. RenderState,
  130379. ShaderProgram,
  130380. VertexArray,
  130381. DepthPlaneFS,
  130382. DepthPlaneVS,
  130383. DepthFunction,
  130384. SceneMode) {
  130385. 'use strict';
  130386. /**
  130387. * @private
  130388. */
  130389. function DepthPlane() {
  130390. this._rs = undefined;
  130391. this._sp = undefined;
  130392. this._va = undefined;
  130393. this._command = undefined;
  130394. this._mode = undefined;
  130395. }
  130396. var depthQuadScratch = FeatureDetection.supportsTypedArrays() ? new Float32Array(12) : [];
  130397. var scratchCartesian1 = new Cartesian3();
  130398. var scratchCartesian2 = new Cartesian3();
  130399. var scratchCartesian3 = new Cartesian3();
  130400. var scratchCartesian4 = new Cartesian3();
  130401. function computeDepthQuad(ellipsoid, frameState) {
  130402. var radii = ellipsoid.radii;
  130403. var p = frameState.camera.positionWC;
  130404. // Find the corresponding position in the scaled space of the ellipsoid.
  130405. var q = Cartesian3.multiplyComponents(ellipsoid.oneOverRadii, p, scratchCartesian1);
  130406. var qMagnitude = Cartesian3.magnitude(q);
  130407. var qUnit = Cartesian3.normalize(q, scratchCartesian2);
  130408. // Determine the east and north directions at q.
  130409. var eUnit = Cartesian3.normalize(Cartesian3.cross(Cartesian3.UNIT_Z, q, scratchCartesian3), scratchCartesian3);
  130410. var nUnit = Cartesian3.normalize(Cartesian3.cross(qUnit, eUnit, scratchCartesian4), scratchCartesian4);
  130411. // Determine the radius of the 'limb' of the ellipsoid.
  130412. var wMagnitude = Math.sqrt(Cartesian3.magnitudeSquared(q) - 1.0);
  130413. // Compute the center and offsets.
  130414. var center = Cartesian3.multiplyByScalar(qUnit, 1.0 / qMagnitude, scratchCartesian1);
  130415. var scalar = wMagnitude / qMagnitude;
  130416. var eastOffset = Cartesian3.multiplyByScalar(eUnit, scalar, scratchCartesian2);
  130417. var northOffset = Cartesian3.multiplyByScalar(nUnit, scalar, scratchCartesian3);
  130418. // A conservative measure for the longitudes would be to use the min/max longitudes of the bounding frustum.
  130419. var upperLeft = Cartesian3.add(center, northOffset, scratchCartesian4);
  130420. Cartesian3.subtract(upperLeft, eastOffset, upperLeft);
  130421. Cartesian3.multiplyComponents(radii, upperLeft, upperLeft);
  130422. Cartesian3.pack(upperLeft, depthQuadScratch, 0);
  130423. var lowerLeft = Cartesian3.subtract(center, northOffset, scratchCartesian4);
  130424. Cartesian3.subtract(lowerLeft, eastOffset, lowerLeft);
  130425. Cartesian3.multiplyComponents(radii, lowerLeft, lowerLeft);
  130426. Cartesian3.pack(lowerLeft, depthQuadScratch, 3);
  130427. var upperRight = Cartesian3.add(center, northOffset, scratchCartesian4);
  130428. Cartesian3.add(upperRight, eastOffset, upperRight);
  130429. Cartesian3.multiplyComponents(radii, upperRight, upperRight);
  130430. Cartesian3.pack(upperRight, depthQuadScratch, 6);
  130431. var lowerRight = Cartesian3.subtract(center, northOffset, scratchCartesian4);
  130432. Cartesian3.add(lowerRight, eastOffset, lowerRight);
  130433. Cartesian3.multiplyComponents(radii, lowerRight, lowerRight);
  130434. Cartesian3.pack(lowerRight, depthQuadScratch, 9);
  130435. return depthQuadScratch;
  130436. }
  130437. DepthPlane.prototype.update = function(frameState) {
  130438. this._mode = frameState.mode;
  130439. if (frameState.mode !== SceneMode.SCENE3D) {
  130440. return;
  130441. }
  130442. var context = frameState.context;
  130443. var ellipsoid = frameState.mapProjection.ellipsoid;
  130444. if (!defined(this._command)) {
  130445. this._rs = RenderState.fromCache({ // Write depth, not color
  130446. cull : {
  130447. enabled : true
  130448. },
  130449. depthTest : {
  130450. enabled : true,
  130451. func : DepthFunction.ALWAYS
  130452. },
  130453. colorMask : {
  130454. red : false,
  130455. green : false,
  130456. blue : false,
  130457. alpha : false
  130458. }
  130459. });
  130460. this._sp = ShaderProgram.fromCache({
  130461. context : context,
  130462. vertexShaderSource : DepthPlaneVS,
  130463. fragmentShaderSource : DepthPlaneFS,
  130464. attributeLocations : {
  130465. position : 0
  130466. }
  130467. });
  130468. this._command = new DrawCommand({
  130469. renderState : this._rs,
  130470. shaderProgram : this._sp,
  130471. boundingVolume : new BoundingSphere(Cartesian3.ZERO, ellipsoid.maximumRadius),
  130472. pass : Pass.OPAQUE,
  130473. owner : this
  130474. });
  130475. }
  130476. // update depth plane
  130477. var depthQuad = computeDepthQuad(ellipsoid, frameState);
  130478. // depth plane
  130479. if (!defined(this._va)) {
  130480. var geometry = new Geometry({
  130481. attributes : {
  130482. position : new GeometryAttribute({
  130483. componentDatatype : ComponentDatatype.FLOAT,
  130484. componentsPerAttribute : 3,
  130485. values : depthQuad
  130486. })
  130487. },
  130488. indices : [0, 1, 2, 2, 1, 3],
  130489. primitiveType : PrimitiveType.TRIANGLES
  130490. });
  130491. this._va = VertexArray.fromGeometry({
  130492. context : context,
  130493. geometry : geometry,
  130494. attributeLocations : {
  130495. position : 0
  130496. },
  130497. bufferUsage : BufferUsage.DYNAMIC_DRAW
  130498. });
  130499. this._command.vertexArray = this._va;
  130500. } else {
  130501. this._va.getAttribute(0).vertexBuffer.copyFromArrayView(depthQuad);
  130502. }
  130503. };
  130504. DepthPlane.prototype.execute = function(context, passState) {
  130505. if (this._mode === SceneMode.SCENE3D) {
  130506. this._command.execute(context, passState);
  130507. }
  130508. };
  130509. DepthPlane.prototype.isDestroyed = function() {
  130510. return false;
  130511. };
  130512. DepthPlane.prototype.destroy = function() {
  130513. this._sp = this._sp && this._sp.destroy();
  130514. this._va = this._va && this._va.destroy();
  130515. };
  130516. return DepthPlane;
  130517. });
  130518. /*global define*/
  130519. define('Scene/DeviceOrientationCameraController',[
  130520. '../Core/defined',
  130521. '../Core/destroyObject',
  130522. '../Core/DeveloperError',
  130523. '../Core/Math',
  130524. '../Core/Matrix3',
  130525. '../Core/Quaternion'
  130526. ], function(
  130527. defined,
  130528. destroyObject,
  130529. DeveloperError,
  130530. CesiumMath,
  130531. Matrix3,
  130532. Quaternion) {
  130533. 'use strict';
  130534. /**
  130535. * @private
  130536. */
  130537. function DeviceOrientationCameraController(scene) {
  130538. if (!defined(scene)) {
  130539. throw new DeveloperError('scene is required.');
  130540. }
  130541. this._scene = scene;
  130542. this._lastAlpha = undefined;
  130543. this._lastBeta = undefined;
  130544. this._lastGamma = undefined;
  130545. this._alpha = undefined;
  130546. this._beta = undefined;
  130547. this._gamma = undefined;
  130548. var that = this;
  130549. function callback(e) {
  130550. var alpha = e.alpha;
  130551. if (!defined(alpha)) {
  130552. that._alpha = undefined;
  130553. that._beta = undefined;
  130554. that._gamma = undefined;
  130555. return;
  130556. }
  130557. that._alpha = CesiumMath.toRadians(alpha);
  130558. that._beta = CesiumMath.toRadians(e.beta);
  130559. that._gamma = CesiumMath.toRadians(e.gamma);
  130560. }
  130561. window.addEventListener('deviceorientation', callback, false);
  130562. this._removeListener = function() {
  130563. window.removeEventListener('deviceorientation', callback, false);
  130564. };
  130565. }
  130566. var scratchQuaternion1 = new Quaternion();
  130567. var scratchQuaternion2 = new Quaternion();
  130568. var scratchMatrix3 = new Matrix3();
  130569. function rotate(camera, alpha, beta, gamma) {
  130570. var direction = camera.direction;
  130571. var right = camera.right;
  130572. var up = camera.up;
  130573. var bQuat = Quaternion.fromAxisAngle(direction, beta, scratchQuaternion2);
  130574. var gQuat = Quaternion.fromAxisAngle(right, gamma, scratchQuaternion1);
  130575. var rotQuat = Quaternion.multiply(gQuat, bQuat, gQuat);
  130576. var aQuat = Quaternion.fromAxisAngle(up, alpha, scratchQuaternion2);
  130577. Quaternion.multiply(aQuat, rotQuat, rotQuat);
  130578. var matrix = Matrix3.fromQuaternion(rotQuat, scratchMatrix3);
  130579. Matrix3.multiplyByVector(matrix, right, right);
  130580. Matrix3.multiplyByVector(matrix, up, up);
  130581. Matrix3.multiplyByVector(matrix, direction, direction);
  130582. }
  130583. DeviceOrientationCameraController.prototype.update = function() {
  130584. if (!defined(this._alpha)) {
  130585. return;
  130586. }
  130587. if (!defined(this._lastAlpha)) {
  130588. this._lastAlpha = this._alpha;
  130589. this._lastBeta = this._beta;
  130590. this._lastGamma = this._gamma;
  130591. }
  130592. var a = this._lastAlpha - this._alpha;
  130593. var b = this._lastBeta - this._beta;
  130594. var g = this._lastGamma - this._gamma;
  130595. rotate(this._scene.camera, -a, b, g);
  130596. this._lastAlpha = this._alpha;
  130597. this._lastBeta = this._beta;
  130598. this._lastGamma = this._gamma;
  130599. };
  130600. /**
  130601. * Returns true if this object was destroyed; otherwise, false.
  130602. * <br /><br />
  130603. *
  130604. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  130605. */
  130606. DeviceOrientationCameraController.prototype.isDestroyed = function() {
  130607. return false;
  130608. };
  130609. /**
  130610. * Destroys the resources held by this object. Destroying an object allows for deterministic
  130611. * release of resources, instead of relying on the garbage collector to destroy this object.
  130612. * <br /><br />
  130613. * Once an object is destroyed, it should not be used; calling any function other than
  130614. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  130615. * assign the return value (<code>undefined</code>) to the object as done in the example.
  130616. *
  130617. * @returns {undefined}
  130618. *
  130619. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  130620. */
  130621. DeviceOrientationCameraController.prototype.destroy = function() {
  130622. this._removeListener();
  130623. return destroyObject(this);
  130624. };
  130625. return DeviceOrientationCameraController;
  130626. });
  130627. //This file is automatically rebuilt by the Cesium build process.
  130628. /*global define*/
  130629. define('Shaders/EllipsoidFS',[],function() {
  130630. 'use strict';
  130631. return "#ifdef WRITE_DEPTH\n\
  130632. #ifdef GL_EXT_frag_depth\n\
  130633. #extension GL_EXT_frag_depth : enable\n\
  130634. #endif\n\
  130635. #endif\n\
  130636. uniform vec3 u_radii;\n\
  130637. uniform vec3 u_oneOverEllipsoidRadiiSquared;\n\
  130638. varying vec3 v_positionEC;\n\
  130639. vec4 computeEllipsoidColor(czm_ray ray, float intersection, float side)\n\
  130640. {\n\
  130641. vec3 positionEC = czm_pointAlongRay(ray, intersection);\n\
  130642. vec3 positionMC = (czm_inverseModelView * vec4(positionEC, 1.0)).xyz;\n\
  130643. vec3 geodeticNormal = normalize(czm_geodeticSurfaceNormal(positionMC, vec3(0.0), u_oneOverEllipsoidRadiiSquared));\n\
  130644. vec3 sphericalNormal = normalize(positionMC / u_radii);\n\
  130645. vec3 normalMC = geodeticNormal * side;\n\
  130646. vec3 normalEC = normalize(czm_normal * normalMC);\n\
  130647. vec2 st = czm_ellipsoidWgs84TextureCoordinates(sphericalNormal);\n\
  130648. vec3 positionToEyeEC = -positionEC;\n\
  130649. czm_materialInput materialInput;\n\
  130650. materialInput.s = st.s;\n\
  130651. materialInput.st = st;\n\
  130652. materialInput.str = (positionMC + u_radii) / u_radii;\n\
  130653. materialInput.normalEC = normalEC;\n\
  130654. materialInput.tangentToEyeMatrix = czm_eastNorthUpToEyeCoordinates(positionMC, normalEC);\n\
  130655. materialInput.positionToEyeEC = positionToEyeEC;\n\
  130656. czm_material material = czm_getMaterial(materialInput);\n\
  130657. #ifdef ONLY_SUN_LIGHTING\n\
  130658. return czm_private_phong(normalize(positionToEyeEC), material);\n\
  130659. #else\n\
  130660. return czm_phong(normalize(positionToEyeEC), material);\n\
  130661. #endif\n\
  130662. }\n\
  130663. void main()\n\
  130664. {\n\
  130665. float maxRadius = max(u_radii.x, max(u_radii.y, u_radii.z)) * 1.5;\n\
  130666. vec3 direction = normalize(v_positionEC);\n\
  130667. vec3 ellipsoidCenter = czm_modelView[3].xyz;\n\
  130668. float t1 = -1.0;\n\
  130669. float t2 = -1.0;\n\
  130670. float b = -2.0 * dot(direction, ellipsoidCenter);\n\
  130671. float c = dot(ellipsoidCenter, ellipsoidCenter) - maxRadius * maxRadius;\n\
  130672. float discriminant = b * b - 4.0 * c;\n\
  130673. if (discriminant >= 0.0) {\n\
  130674. t1 = (-b - sqrt(discriminant)) * 0.5;\n\
  130675. t2 = (-b + sqrt(discriminant)) * 0.5;\n\
  130676. }\n\
  130677. if (t1 < 0.0 && t2 < 0.0) {\n\
  130678. discard;\n\
  130679. }\n\
  130680. float t = min(t1, t2);\n\
  130681. if (t < 0.0) {\n\
  130682. t = 0.0;\n\
  130683. }\n\
  130684. czm_ellipsoid ellipsoid = czm_ellipsoidNew(ellipsoidCenter, u_radii);\n\
  130685. czm_ray ray = czm_ray(t * direction, direction);\n\
  130686. czm_raySegment intersection = czm_rayEllipsoidIntersectionInterval(ray, ellipsoid);\n\
  130687. if (czm_isEmpty(intersection))\n\
  130688. {\n\
  130689. discard;\n\
  130690. }\n\
  130691. vec4 outsideFaceColor = (intersection.start != 0.0) ? computeEllipsoidColor(ray, intersection.start, 1.0) : vec4(0.0);\n\
  130692. vec4 insideFaceColor = (outsideFaceColor.a < 1.0) ? computeEllipsoidColor(ray, intersection.stop, -1.0) : vec4(0.0);\n\
  130693. gl_FragColor = mix(insideFaceColor, outsideFaceColor, outsideFaceColor.a);\n\
  130694. gl_FragColor.a = 1.0 - (1.0 - insideFaceColor.a) * (1.0 - outsideFaceColor.a);\n\
  130695. #ifdef WRITE_DEPTH\n\
  130696. #ifdef GL_EXT_frag_depth\n\
  130697. t = (intersection.start != 0.0) ? intersection.start : intersection.stop;\n\
  130698. vec3 positionEC = czm_pointAlongRay(ray, t);\n\
  130699. vec4 positionCC = czm_projection * vec4(positionEC, 1.0);\n\
  130700. float z = positionCC.z / positionCC.w;\n\
  130701. float n = czm_depthRange.near;\n\
  130702. float f = czm_depthRange.far;\n\
  130703. gl_FragDepthEXT = (z * (f - n) + f + n) * 0.5;\n\
  130704. #endif\n\
  130705. #endif\n\
  130706. }\n\
  130707. ";
  130708. });
  130709. //This file is automatically rebuilt by the Cesium build process.
  130710. /*global define*/
  130711. define('Shaders/EllipsoidVS',[],function() {
  130712. 'use strict';
  130713. return "attribute vec3 position;\n\
  130714. uniform vec3 u_radii;\n\
  130715. varying vec3 v_positionEC;\n\
  130716. void main()\n\
  130717. {\n\
  130718. vec4 p = vec4(u_radii * position, 1.0);\n\
  130719. v_positionEC = (czm_modelView * p).xyz;\n\
  130720. gl_Position = czm_modelViewProjection * p;\n\
  130721. gl_Position.z = clamp(gl_Position.z, czm_depthRange.near, czm_depthRange.far);\n\
  130722. }\n\
  130723. ";
  130724. });
  130725. /*global define*/
  130726. define('Scene/EllipsoidPrimitive',[
  130727. '../Core/BoundingSphere',
  130728. '../Core/BoxGeometry',
  130729. '../Core/Cartesian3',
  130730. '../Core/combine',
  130731. '../Core/defaultValue',
  130732. '../Core/defined',
  130733. '../Core/destroyObject',
  130734. '../Core/DeveloperError',
  130735. '../Core/Matrix4',
  130736. '../Core/VertexFormat',
  130737. '../Renderer/BufferUsage',
  130738. '../Renderer/DrawCommand',
  130739. '../Renderer/Pass',
  130740. '../Renderer/RenderState',
  130741. '../Renderer/ShaderProgram',
  130742. '../Renderer/ShaderSource',
  130743. '../Renderer/VertexArray',
  130744. '../Shaders/EllipsoidFS',
  130745. '../Shaders/EllipsoidVS',
  130746. './BlendingState',
  130747. './CullFace',
  130748. './Material',
  130749. './SceneMode'
  130750. ], function(
  130751. BoundingSphere,
  130752. BoxGeometry,
  130753. Cartesian3,
  130754. combine,
  130755. defaultValue,
  130756. defined,
  130757. destroyObject,
  130758. DeveloperError,
  130759. Matrix4,
  130760. VertexFormat,
  130761. BufferUsage,
  130762. DrawCommand,
  130763. Pass,
  130764. RenderState,
  130765. ShaderProgram,
  130766. ShaderSource,
  130767. VertexArray,
  130768. EllipsoidFS,
  130769. EllipsoidVS,
  130770. BlendingState,
  130771. CullFace,
  130772. Material,
  130773. SceneMode) {
  130774. 'use strict';
  130775. var attributeLocations = {
  130776. position : 0
  130777. };
  130778. /**
  130779. * A renderable ellipsoid. It can also draw spheres when the three {@link EllipsoidPrimitive#radii} components are equal.
  130780. * <p>
  130781. * This is only supported in 3D. The ellipsoid is not shown in 2D or Columbus view.
  130782. * </p>
  130783. *
  130784. * @alias EllipsoidPrimitive
  130785. * @constructor
  130786. *
  130787. * @param {Object} [options] Object with the following properties:
  130788. * @param {Cartesian3} [options.center=Cartesian3.ZERO] The center of the ellipsoid in the ellipsoid's model coordinates.
  130789. * @param {Cartesian3} [options.radii] The radius of the ellipsoid along the <code>x</code>, <code>y</code>, and <code>z</code> axes in the ellipsoid's model coordinates.
  130790. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms the ellipsoid from model to world coordinates.
  130791. * @param {Boolean} [options.show=true] Determines if this primitive will be shown.
  130792. * @param {Material} [options.material=Material.ColorType] The surface appearance of the primitive.
  130793. * @param {Object} [options.id] A user-defined object to return when the instance is picked with {@link Scene#pick}
  130794. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
  130795. *
  130796. * @private
  130797. */
  130798. function EllipsoidPrimitive(options) {
  130799. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  130800. /**
  130801. * The center of the ellipsoid in the ellipsoid's model coordinates.
  130802. * <p>
  130803. * The default is {@link Cartesian3.ZERO}.
  130804. * </p>
  130805. *
  130806. * @type {Cartesian3}
  130807. * @default {@link Cartesian3.ZERO}
  130808. *
  130809. * @see EllipsoidPrimitive#modelMatrix
  130810. */
  130811. this.center = Cartesian3.clone(defaultValue(options.center, Cartesian3.ZERO));
  130812. this._center = new Cartesian3();
  130813. /**
  130814. * The radius of the ellipsoid along the <code>x</code>, <code>y</code>, and <code>z</code> axes in the ellipsoid's model coordinates.
  130815. * When these are the same, the ellipsoid is a sphere.
  130816. * <p>
  130817. * The default is <code>undefined</code>. The ellipsoid is not drawn until a radii is provided.
  130818. * </p>
  130819. *
  130820. * @type {Cartesian3}
  130821. * @default undefined
  130822. *
  130823. *
  130824. * @example
  130825. * // A sphere with a radius of 2.0
  130826. * e.radii = new Cesium.Cartesian3(2.0, 2.0, 2.0);
  130827. *
  130828. * @see EllipsoidPrimitive#modelMatrix
  130829. */
  130830. this.radii = Cartesian3.clone(options.radii);
  130831. this._radii = new Cartesian3();
  130832. this._oneOverEllipsoidRadiiSquared = new Cartesian3();
  130833. this._boundingSphere = new BoundingSphere();
  130834. /**
  130835. * The 4x4 transformation matrix that transforms the ellipsoid from model to world coordinates.
  130836. * When this is the identity matrix, the ellipsoid is drawn in world coordinates, i.e., Earth's WGS84 coordinates.
  130837. * Local reference frames can be used by providing a different transformation matrix, like that returned
  130838. * by {@link Transforms.eastNorthUpToFixedFrame}.
  130839. *
  130840. * @type {Matrix4}
  130841. * @default {@link Matrix4.IDENTITY}
  130842. *
  130843. * @example
  130844. * var origin = Cesium.Cartesian3.fromDegrees(-95.0, 40.0, 200000.0);
  130845. * e.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin);
  130846. */
  130847. this.modelMatrix = Matrix4.clone(defaultValue(options.modelMatrix, Matrix4.IDENTITY));
  130848. this._modelMatrix = new Matrix4();
  130849. this._computedModelMatrix = new Matrix4();
  130850. /**
  130851. * Determines if the ellipsoid primitive will be shown.
  130852. *
  130853. * @type {Boolean}
  130854. * @default true
  130855. */
  130856. this.show = defaultValue(options.show, true);
  130857. /**
  130858. * The surface appearance of the ellipsoid. This can be one of several built-in {@link Material} objects or a custom material, scripted with
  130859. * {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}.
  130860. * <p>
  130861. * The default material is <code>Material.ColorType</code>.
  130862. * </p>
  130863. *
  130864. * @type {Material}
  130865. * @default Material.fromType(Material.ColorType)
  130866. *
  130867. *
  130868. * @example
  130869. * // 1. Change the color of the default material to yellow
  130870. * e.material.uniforms.color = new Cesium.Color(1.0, 1.0, 0.0, 1.0);
  130871. *
  130872. * // 2. Change material to horizontal stripes
  130873. * e.material = Cesium.Material.fromType(Cesium.Material.StripeType);
  130874. *
  130875. * @see {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}
  130876. */
  130877. this.material = defaultValue(options.material, Material.fromType(Material.ColorType));
  130878. this._material = undefined;
  130879. this._translucent = undefined;
  130880. /**
  130881. * User-defined object returned when the ellipsoid is picked.
  130882. *
  130883. * @type Object
  130884. *
  130885. * @default undefined
  130886. *
  130887. * @see Scene#pick
  130888. */
  130889. this.id = options.id;
  130890. this._id = undefined;
  130891. /**
  130892. * This property is for debugging only; it is not for production use nor is it optimized.
  130893. * <p>
  130894. * Draws the bounding sphere for each draw command in the primitive.
  130895. * </p>
  130896. *
  130897. * @type {Boolean}
  130898. *
  130899. * @default false
  130900. */
  130901. this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false);
  130902. /**
  130903. * @private
  130904. */
  130905. this.onlySunLighting = defaultValue(options.onlySunLighting, false);
  130906. this._onlySunLighting = false;
  130907. /**
  130908. * @private
  130909. */
  130910. this._depthTestEnabled = defaultValue(options.depthTestEnabled, true);
  130911. this._sp = undefined;
  130912. this._rs = undefined;
  130913. this._va = undefined;
  130914. this._pickSP = undefined;
  130915. this._pickId = undefined;
  130916. this._colorCommand = new DrawCommand({
  130917. owner : defaultValue(options._owner, this)
  130918. });
  130919. this._pickCommand = new DrawCommand({
  130920. owner : defaultValue(options._owner, this)
  130921. });
  130922. var that = this;
  130923. this._uniforms = {
  130924. u_radii : function() {
  130925. return that.radii;
  130926. },
  130927. u_oneOverEllipsoidRadiiSquared : function() {
  130928. return that._oneOverEllipsoidRadiiSquared;
  130929. }
  130930. };
  130931. this._pickUniforms = {
  130932. czm_pickColor : function() {
  130933. return that._pickId.color;
  130934. }
  130935. };
  130936. }
  130937. function getVertexArray(context) {
  130938. var vertexArray = context.cache.ellipsoidPrimitive_vertexArray;
  130939. if (defined(vertexArray)) {
  130940. return vertexArray;
  130941. }
  130942. var geometry = BoxGeometry.createGeometry(BoxGeometry.fromDimensions({
  130943. dimensions : new Cartesian3(2.0, 2.0, 2.0),
  130944. vertexFormat : VertexFormat.POSITION_ONLY
  130945. }));
  130946. vertexArray = VertexArray.fromGeometry({
  130947. context : context,
  130948. geometry : geometry,
  130949. attributeLocations : attributeLocations,
  130950. bufferUsage : BufferUsage.STATIC_DRAW,
  130951. interleave : true
  130952. });
  130953. context.cache.ellipsoidPrimitive_vertexArray = vertexArray;
  130954. return vertexArray;
  130955. }
  130956. /**
  130957. * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
  130958. * get the draw commands needed to render this primitive.
  130959. * <p>
  130960. * Do not call this function directly. This is documented just to
  130961. * list the exceptions that may be propagated when the scene is rendered:
  130962. * </p>
  130963. *
  130964. * @exception {DeveloperError} this.material must be defined.
  130965. */
  130966. EllipsoidPrimitive.prototype.update = function(frameState) {
  130967. if (!this.show ||
  130968. (frameState.mode !== SceneMode.SCENE3D) ||
  130969. (!defined(this.center)) ||
  130970. (!defined(this.radii))) {
  130971. return;
  130972. }
  130973. if (!defined(this.material)) {
  130974. throw new DeveloperError('this.material must be defined.');
  130975. }
  130976. var context = frameState.context;
  130977. var translucent = this.material.isTranslucent();
  130978. var translucencyChanged = this._translucent !== translucent;
  130979. if (!defined(this._rs) || translucencyChanged) {
  130980. this._translucent = translucent;
  130981. // If this render state is ever updated to use a non-default
  130982. // depth range, the hard-coded values in EllipsoidVS.glsl need
  130983. // to be updated as well.
  130984. this._rs = RenderState.fromCache({
  130985. // Cull front faces - not back faces - so the ellipsoid doesn't
  130986. // disappear if the viewer enters the bounding box.
  130987. cull : {
  130988. enabled : true,
  130989. face : CullFace.FRONT
  130990. },
  130991. depthTest : {
  130992. enabled : this._depthTestEnabled
  130993. },
  130994. // Only write depth when EXT_frag_depth is supported since the depth for
  130995. // the bounding box is wrong; it is not the true depth of the ray casted ellipsoid.
  130996. depthMask : !translucent && context.fragmentDepth,
  130997. blending : translucent ? BlendingState.ALPHA_BLEND : undefined
  130998. });
  130999. }
  131000. if (!defined(this._va)) {
  131001. this._va = getVertexArray(context);
  131002. }
  131003. var boundingSphereDirty = false;
  131004. var radii = this.radii;
  131005. if (!Cartesian3.equals(this._radii, radii)) {
  131006. Cartesian3.clone(radii, this._radii);
  131007. var r = this._oneOverEllipsoidRadiiSquared;
  131008. r.x = 1.0 / (radii.x * radii.x);
  131009. r.y = 1.0 / (radii.y * radii.y);
  131010. r.z = 1.0 / (radii.z * radii.z);
  131011. boundingSphereDirty = true;
  131012. }
  131013. if (!Matrix4.equals(this.modelMatrix, this._modelMatrix) || !Cartesian3.equals(this.center, this._center)) {
  131014. Matrix4.clone(this.modelMatrix, this._modelMatrix);
  131015. Cartesian3.clone(this.center, this._center);
  131016. // Translate model coordinates used for rendering such that the origin is the center of the ellipsoid.
  131017. Matrix4.multiplyByTranslation(this.modelMatrix, this.center, this._computedModelMatrix);
  131018. boundingSphereDirty = true;
  131019. }
  131020. if (boundingSphereDirty) {
  131021. Cartesian3.clone(Cartesian3.ZERO, this._boundingSphere.center);
  131022. this._boundingSphere.radius = Cartesian3.maximumComponent(radii);
  131023. BoundingSphere.transform(this._boundingSphere, this._computedModelMatrix, this._boundingSphere);
  131024. }
  131025. var materialChanged = this._material !== this.material;
  131026. this._material = this.material;
  131027. this._material.update(context);
  131028. var lightingChanged = this.onlySunLighting !== this._onlySunLighting;
  131029. this._onlySunLighting = this.onlySunLighting;
  131030. var colorCommand = this._colorCommand;
  131031. var fs;
  131032. // Recompile shader when material, lighting, or translucency changes
  131033. if (materialChanged || lightingChanged || translucencyChanged) {
  131034. fs = new ShaderSource({
  131035. sources : [this.material.shaderSource, EllipsoidFS]
  131036. });
  131037. if (this.onlySunLighting) {
  131038. fs.defines.push('ONLY_SUN_LIGHTING');
  131039. }
  131040. if (!translucent && context.fragmentDepth) {
  131041. fs.defines.push('WRITE_DEPTH');
  131042. }
  131043. this._sp = ShaderProgram.replaceCache({
  131044. context : context,
  131045. shaderProgram : this._sp,
  131046. vertexShaderSource : EllipsoidVS,
  131047. fragmentShaderSource : fs,
  131048. attributeLocations : attributeLocations
  131049. });
  131050. colorCommand.vertexArray = this._va;
  131051. colorCommand.renderState = this._rs;
  131052. colorCommand.shaderProgram = this._sp;
  131053. colorCommand.uniformMap = combine(this._uniforms, this.material._uniforms);
  131054. colorCommand.executeInClosestFrustum = translucent;
  131055. }
  131056. var commandList = frameState.commandList;
  131057. var passes = frameState.passes;
  131058. if (passes.render) {
  131059. colorCommand.boundingVolume = this._boundingSphere;
  131060. colorCommand.debugShowBoundingVolume = this.debugShowBoundingVolume;
  131061. colorCommand.modelMatrix = this._computedModelMatrix;
  131062. colorCommand.pass = translucent ? Pass.TRANSLUCENT : Pass.OPAQUE;
  131063. commandList.push(colorCommand);
  131064. }
  131065. if (passes.pick) {
  131066. var pickCommand = this._pickCommand;
  131067. if (!defined(this._pickId) || (this._id !== this.id)) {
  131068. this._id = this.id;
  131069. this._pickId = this._pickId && this._pickId.destroy();
  131070. this._pickId = context.createPickId({
  131071. primitive : this,
  131072. id : this.id
  131073. });
  131074. }
  131075. // Recompile shader when material changes
  131076. if (materialChanged || lightingChanged || !defined(this._pickSP)) {
  131077. fs = new ShaderSource({
  131078. sources : [this.material.shaderSource, EllipsoidFS],
  131079. pickColorQualifier : 'uniform'
  131080. });
  131081. if (this.onlySunLighting) {
  131082. fs.defines.push('ONLY_SUN_LIGHTING');
  131083. }
  131084. if (!translucent && context.fragmentDepth) {
  131085. fs.defines.push('WRITE_DEPTH');
  131086. }
  131087. this._pickSP = ShaderProgram.replaceCache({
  131088. context : context,
  131089. shaderProgram : this._pickSP,
  131090. vertexShaderSource : EllipsoidVS,
  131091. fragmentShaderSource : fs,
  131092. attributeLocations : attributeLocations
  131093. });
  131094. pickCommand.vertexArray = this._va;
  131095. pickCommand.renderState = this._rs;
  131096. pickCommand.shaderProgram = this._pickSP;
  131097. pickCommand.uniformMap = combine(combine(this._uniforms, this._pickUniforms), this.material._uniforms);
  131098. pickCommand.executeInClosestFrustum = translucent;
  131099. }
  131100. pickCommand.boundingVolume = this._boundingSphere;
  131101. pickCommand.modelMatrix = this._computedModelMatrix;
  131102. pickCommand.pass = translucent ? Pass.TRANSLUCENT : Pass.OPAQUE;
  131103. commandList.push(pickCommand);
  131104. }
  131105. };
  131106. /**
  131107. * Returns true if this object was destroyed; otherwise, false.
  131108. * <br /><br />
  131109. * If this object was destroyed, it should not be used; calling any function other than
  131110. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  131111. *
  131112. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  131113. *
  131114. * @see EllipsoidPrimitive#destroy
  131115. */
  131116. EllipsoidPrimitive.prototype.isDestroyed = function() {
  131117. return false;
  131118. };
  131119. /**
  131120. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  131121. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  131122. * <br /><br />
  131123. * Once an object is destroyed, it should not be used; calling any function other than
  131124. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  131125. * assign the return value (<code>undefined</code>) to the object as done in the example.
  131126. *
  131127. * @returns {undefined}
  131128. *
  131129. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  131130. *
  131131. *
  131132. * @example
  131133. * e = e && e.destroy();
  131134. *
  131135. * @see EllipsoidPrimitive#isDestroyed
  131136. */
  131137. EllipsoidPrimitive.prototype.destroy = function() {
  131138. this._sp = this._sp && this._sp.destroy();
  131139. this._pickSP = this._pickSP && this._pickSP.destroy();
  131140. this._pickId = this._pickId && this._pickId.destroy();
  131141. return destroyObject(this);
  131142. };
  131143. return EllipsoidPrimitive;
  131144. });
  131145. //This file is automatically rebuilt by the Cesium build process.
  131146. /*global define*/
  131147. define('Shaders/Appearances/EllipsoidSurfaceAppearanceFS',[],function() {
  131148. 'use strict';
  131149. return "varying vec3 v_positionMC;\n\
  131150. varying vec3 v_positionEC;\n\
  131151. varying vec2 v_st;\n\
  131152. void main()\n\
  131153. {\n\
  131154. czm_materialInput materialInput;\n\
  131155. vec3 normalEC = normalize(czm_normal3D * czm_geodeticSurfaceNormal(v_positionMC, vec3(0.0), vec3(1.0)));\n\
  131156. #ifdef FACE_FORWARD\n\
  131157. normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n\
  131158. #endif\n\
  131159. materialInput.s = v_st.s;\n\
  131160. materialInput.st = v_st;\n\
  131161. materialInput.str = vec3(v_st, 0.0);\n\
  131162. materialInput.normalEC = normalEC;\n\
  131163. materialInput.tangentToEyeMatrix = czm_eastNorthUpToEyeCoordinates(v_positionMC, materialInput.normalEC);\n\
  131164. vec3 positionToEyeEC = -v_positionEC;\n\
  131165. materialInput.positionToEyeEC = positionToEyeEC;\n\
  131166. czm_material material = czm_getMaterial(materialInput);\n\
  131167. #ifdef FLAT\n\
  131168. gl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n\
  131169. #else\n\
  131170. gl_FragColor = czm_phong(normalize(positionToEyeEC), material);\n\
  131171. #endif\n\
  131172. }\n\
  131173. ";
  131174. });
  131175. //This file is automatically rebuilt by the Cesium build process.
  131176. /*global define*/
  131177. define('Shaders/Appearances/EllipsoidSurfaceAppearanceVS',[],function() {
  131178. 'use strict';
  131179. return "attribute vec3 position3DHigh;\n\
  131180. attribute vec3 position3DLow;\n\
  131181. attribute vec2 st;\n\
  131182. attribute float batchId;\n\
  131183. varying vec3 v_positionMC;\n\
  131184. varying vec3 v_positionEC;\n\
  131185. varying vec2 v_st;\n\
  131186. void main()\n\
  131187. {\n\
  131188. vec4 p = czm_computePosition();\n\
  131189. v_positionMC = position3DHigh + position3DLow;\n\
  131190. v_positionEC = (czm_modelViewRelativeToEye * p).xyz;\n\
  131191. v_st = st;\n\
  131192. gl_Position = czm_modelViewProjectionRelativeToEye * p;\n\
  131193. }\n\
  131194. ";
  131195. });
  131196. /*global define*/
  131197. define('Scene/EllipsoidSurfaceAppearance',[
  131198. '../Core/defaultValue',
  131199. '../Core/defined',
  131200. '../Core/defineProperties',
  131201. '../Core/VertexFormat',
  131202. '../Shaders/Appearances/EllipsoidSurfaceAppearanceFS',
  131203. '../Shaders/Appearances/EllipsoidSurfaceAppearanceVS',
  131204. './Appearance',
  131205. './Material'
  131206. ], function(
  131207. defaultValue,
  131208. defined,
  131209. defineProperties,
  131210. VertexFormat,
  131211. EllipsoidSurfaceAppearanceFS,
  131212. EllipsoidSurfaceAppearanceVS,
  131213. Appearance,
  131214. Material) {
  131215. 'use strict';
  131216. /**
  131217. * An appearance for geometry on the surface of the ellipsoid like {@link PolygonGeometry}
  131218. * and {@link RectangleGeometry}, which supports all materials like {@link MaterialAppearance}
  131219. * with {@link MaterialAppearance.MaterialSupport.ALL}. However, this appearance requires
  131220. * fewer vertex attributes since the fragment shader can procedurally compute <code>normal</code>,
  131221. * <code>binormal</code>, and <code>tangent</code>.
  131222. *
  131223. * @alias EllipsoidSurfaceAppearance
  131224. * @constructor
  131225. *
  131226. * @param {Object} [options] Object with the following properties:
  131227. * @param {Boolean} [options.flat=false] When <code>true</code>, flat shading is used in the fragment shader, which means lighting is not taking into account.
  131228. * @param {Boolean} [options.faceForward=options.aboveGround] When <code>true</code>, the fragment shader flips the surface normal as needed to ensure that the normal faces the viewer to avoid dark spots. This is useful when both sides of a geometry should be shaded like {@link WallGeometry}.
  131229. * @param {Boolean} [options.translucent=true] When <code>true</code>, the geometry is expected to appear translucent so {@link EllipsoidSurfaceAppearance#renderState} has alpha blending enabled.
  131230. * @param {Boolean} [options.aboveGround=false] When <code>true</code>, the geometry is expected to be on the ellipsoid's surface - not at a constant height above it - so {@link EllipsoidSurfaceAppearance#renderState} has backface culling enabled.
  131231. * @param {Material} [options.material=Material.ColorType] The material used to determine the fragment color.
  131232. * @param {String} [options.vertexShaderSource] Optional GLSL vertex shader source to override the default vertex shader.
  131233. * @param {String} [options.fragmentShaderSource] Optional GLSL fragment shader source to override the default fragment shader.
  131234. * @param {RenderState} [options.renderState] Optional render state to override the default render state.
  131235. *
  131236. * @see {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}
  131237. *
  131238. * @example
  131239. * var primitive = new Cesium.Primitive({
  131240. * geometryInstances : new Cesium.GeometryInstance({
  131241. * geometry : new Cesium.PolygonGeometry({
  131242. * vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
  131243. * // ...
  131244. * })
  131245. * }),
  131246. * appearance : new Cesium.EllipsoidSurfaceAppearance({
  131247. * material : Cesium.Material.fromType('Stripe')
  131248. * })
  131249. * });
  131250. */
  131251. function EllipsoidSurfaceAppearance(options) {
  131252. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  131253. var translucent = defaultValue(options.translucent, true);
  131254. var aboveGround = defaultValue(options.aboveGround, false);
  131255. /**
  131256. * The material used to determine the fragment color. Unlike other {@link EllipsoidSurfaceAppearance}
  131257. * properties, this is not read-only, so an appearance's material can change on the fly.
  131258. *
  131259. * @type Material
  131260. *
  131261. * @default {@link Material.ColorType}
  131262. *
  131263. * @see {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}
  131264. */
  131265. this.material = (defined(options.material)) ? options.material : Material.fromType(Material.ColorType);
  131266. /**
  131267. * When <code>true</code>, the geometry is expected to appear translucent.
  131268. *
  131269. * @type {Boolean}
  131270. *
  131271. * @default true
  131272. */
  131273. this.translucent = defaultValue(options.translucent, true);
  131274. this._vertexShaderSource = defaultValue(options.vertexShaderSource, EllipsoidSurfaceAppearanceVS);
  131275. this._fragmentShaderSource = defaultValue(options.fragmentShaderSource, EllipsoidSurfaceAppearanceFS);
  131276. this._renderState = Appearance.getDefaultRenderState(translucent, !aboveGround, options.renderState);
  131277. this._closed = false;
  131278. // Non-derived members
  131279. this._flat = defaultValue(options.flat, false);
  131280. this._faceForward = defaultValue(options.faceForward, aboveGround);
  131281. this._aboveGround = aboveGround;
  131282. }
  131283. defineProperties(EllipsoidSurfaceAppearance.prototype, {
  131284. /**
  131285. * The GLSL source code for the vertex shader.
  131286. *
  131287. * @memberof EllipsoidSurfaceAppearance.prototype
  131288. *
  131289. * @type {String}
  131290. * @readonly
  131291. */
  131292. vertexShaderSource : {
  131293. get : function() {
  131294. return this._vertexShaderSource;
  131295. }
  131296. },
  131297. /**
  131298. * The GLSL source code for the fragment shader. The full fragment shader
  131299. * source is built procedurally taking into account {@link EllipsoidSurfaceAppearance#material},
  131300. * {@link EllipsoidSurfaceAppearance#flat}, and {@link EllipsoidSurfaceAppearance#faceForward}.
  131301. * Use {@link EllipsoidSurfaceAppearance#getFragmentShaderSource} to get the full source.
  131302. *
  131303. * @memberof EllipsoidSurfaceAppearance.prototype
  131304. *
  131305. * @type {String}
  131306. * @readonly
  131307. */
  131308. fragmentShaderSource : {
  131309. get : function() {
  131310. return this._fragmentShaderSource;
  131311. }
  131312. },
  131313. /**
  131314. * The WebGL fixed-function state to use when rendering the geometry.
  131315. * <p>
  131316. * The render state can be explicitly defined when constructing a {@link EllipsoidSurfaceAppearance}
  131317. * instance, or it is set implicitly via {@link EllipsoidSurfaceAppearance#translucent}
  131318. * and {@link EllipsoidSurfaceAppearance#aboveGround}.
  131319. * </p>
  131320. *
  131321. * @memberof EllipsoidSurfaceAppearance.prototype
  131322. *
  131323. * @type {Object}
  131324. * @readonly
  131325. */
  131326. renderState : {
  131327. get : function() {
  131328. return this._renderState;
  131329. }
  131330. },
  131331. /**
  131332. * When <code>true</code>, the geometry is expected to be closed so
  131333. * {@link EllipsoidSurfaceAppearance#renderState} has backface culling enabled.
  131334. * If the viewer enters the geometry, it will not be visible.
  131335. *
  131336. * @memberof EllipsoidSurfaceAppearance.prototype
  131337. *
  131338. * @type {Boolean}
  131339. * @readonly
  131340. *
  131341. * @default false
  131342. */
  131343. closed : {
  131344. get : function() {
  131345. return this._closed;
  131346. }
  131347. },
  131348. /**
  131349. * The {@link VertexFormat} that this appearance instance is compatible with.
  131350. * A geometry can have more vertex attributes and still be compatible - at a
  131351. * potential performance cost - but it can't have less.
  131352. *
  131353. * @memberof EllipsoidSurfaceAppearance.prototype
  131354. *
  131355. * @type VertexFormat
  131356. * @readonly
  131357. *
  131358. * @default {@link EllipsoidSurfaceAppearance.VERTEX_FORMAT}
  131359. */
  131360. vertexFormat : {
  131361. get : function() {
  131362. return EllipsoidSurfaceAppearance.VERTEX_FORMAT;
  131363. }
  131364. },
  131365. /**
  131366. * When <code>true</code>, flat shading is used in the fragment shader,
  131367. * which means lighting is not taking into account.
  131368. *
  131369. * @memberof EllipsoidSurfaceAppearance.prototype
  131370. *
  131371. * @type {Boolean}
  131372. * @readonly
  131373. *
  131374. * @default false
  131375. */
  131376. flat : {
  131377. get : function() {
  131378. return this._flat;
  131379. }
  131380. },
  131381. /**
  131382. * When <code>true</code>, the fragment shader flips the surface normal
  131383. * as needed to ensure that the normal faces the viewer to avoid
  131384. * dark spots. This is useful when both sides of a geometry should be
  131385. * shaded like {@link WallGeometry}.
  131386. *
  131387. * @memberof EllipsoidSurfaceAppearance.prototype
  131388. *
  131389. * @type {Boolean}
  131390. * @readonly
  131391. *
  131392. * @default true
  131393. */
  131394. faceForward : {
  131395. get : function() {
  131396. return this._faceForward;
  131397. }
  131398. },
  131399. /**
  131400. * When <code>true</code>, the geometry is expected to be on the ellipsoid's
  131401. * surface - not at a constant height above it - so {@link EllipsoidSurfaceAppearance#renderState}
  131402. * has backface culling enabled.
  131403. *
  131404. *
  131405. * @memberof EllipsoidSurfaceAppearance.prototype
  131406. *
  131407. * @type {Boolean}
  131408. * @readonly
  131409. *
  131410. * @default false
  131411. */
  131412. aboveGround : {
  131413. get : function() {
  131414. return this._aboveGround;
  131415. }
  131416. }
  131417. });
  131418. /**
  131419. * The {@link VertexFormat} that all {@link EllipsoidSurfaceAppearance} instances
  131420. * are compatible with, which requires only <code>position</code> and <code>st</code>
  131421. * attributes. Other attributes are procedurally computed in the fragment shader.
  131422. *
  131423. * @type VertexFormat
  131424. *
  131425. * @constant
  131426. */
  131427. EllipsoidSurfaceAppearance.VERTEX_FORMAT = VertexFormat.POSITION_AND_ST;
  131428. /**
  131429. * Procedurally creates the full GLSL fragment shader source. For {@link EllipsoidSurfaceAppearance},
  131430. * this is derived from {@link EllipsoidSurfaceAppearance#fragmentShaderSource}, {@link EllipsoidSurfaceAppearance#flat},
  131431. * and {@link EllipsoidSurfaceAppearance#faceForward}.
  131432. *
  131433. * @function
  131434. *
  131435. * @returns {String} The full GLSL fragment shader source.
  131436. */
  131437. EllipsoidSurfaceAppearance.prototype.getFragmentShaderSource = Appearance.prototype.getFragmentShaderSource;
  131438. /**
  131439. * Determines if the geometry is translucent based on {@link EllipsoidSurfaceAppearance#translucent} and {@link Material#isTranslucent}.
  131440. *
  131441. * @function
  131442. *
  131443. * @returns {Boolean} <code>true</code> if the appearance is translucent.
  131444. */
  131445. EllipsoidSurfaceAppearance.prototype.isTranslucent = Appearance.prototype.isTranslucent;
  131446. /**
  131447. * Creates a render state. This is not the final render state instance; instead,
  131448. * it can contain a subset of render state properties identical to the render state
  131449. * created in the context.
  131450. *
  131451. * @function
  131452. *
  131453. * @returns {Object} The render state.
  131454. */
  131455. EllipsoidSurfaceAppearance.prototype.getRenderState = Appearance.prototype.getRenderState;
  131456. return EllipsoidSurfaceAppearance;
  131457. });
  131458. /*global define*/
  131459. define('Scene/Fog',[
  131460. '../Core/Cartesian3',
  131461. '../Core/defined',
  131462. '../Core/Math',
  131463. './SceneMode'
  131464. ], function(
  131465. Cartesian3,
  131466. defined,
  131467. CesiumMath,
  131468. SceneMode) {
  131469. 'use strict';
  131470. /**
  131471. * Blends the atmosphere to geometry far from the camera for horizon views. Allows for additional
  131472. * performance improvements by rendering less geometry and dispatching less terrain requests.
  131473. *
  131474. * @alias Fog
  131475. * @constructor
  131476. */
  131477. function Fog() {
  131478. /**
  131479. * <code>true</code> if fog is enabled, <code>false</code> otherwise.
  131480. * @type {Boolean}
  131481. * @default true
  131482. */
  131483. this.enabled = true;
  131484. /**
  131485. * A scalar that determines the density of the fog. Terrain that is in full fog are culled.
  131486. * The density of the fog increases as this number approaches 1.0 and becomes less dense as it approaches zero.
  131487. * The more dense the fog is, the more aggressively the terrain is culled. For example, if the camera is a height of
  131488. * 1000.0m above the ellipsoid, increasing the value to 3.0e-3 will cause many tiles close to the viewer be culled.
  131489. * Decreasing the value will push the fog further from the viewer, but decrease performance as more of the terrain is rendered.
  131490. * @type {Number}
  131491. * @default 2.0e-4
  131492. */
  131493. this.density = 2.0e-4;
  131494. /**
  131495. * A factor used to increase the screen space error of terrain tiles when they are partially in fog. The effect is to reduce
  131496. * the number of terrain tiles requested for rendering. If set to zero, the feature will be disabled. If the value is increased
  131497. * for mountainous regions, less tiles will need to be requested, but the terrain meshes near the horizon may be a noticeably
  131498. * lower resolution. If the value is increased in a relatively flat area, there will be little noticeable change on the horizon.
  131499. * @type {Number}
  131500. * @default 2.0
  131501. */
  131502. this.screenSpaceErrorFactor = 2.0;
  131503. }
  131504. // These values were found by sampling the density at certain views and finding at what point culled tiles impacted the view at the horizon.
  131505. var heightsTable = [359.393, 800.749, 1275.6501, 2151.1192, 3141.7763, 4777.5198, 6281.2493, 12364.307, 15900.765, 49889.0549, 78026.8259, 99260.7344, 120036.3873, 151011.0158, 156091.1953, 203849.3112, 274866.9803, 319916.3149, 493552.0528, 628733.5874];
  131506. var densityTable = [2.0e-5, 2.0e-4, 1.0e-4, 7.0e-5, 5.0e-5, 4.0e-5, 3.0e-5, 1.9e-5, 1.0e-5, 8.5e-6, 6.2e-6, 5.8e-6, 5.3e-6, 5.2e-6, 5.1e-6, 4.2e-6, 4.0e-6, 3.4e-6, 2.6e-6, 2.2e-6];
  131507. // Scale densities by 1e6 to bring lowest value to ~1. Prevents divide by zero.
  131508. for (var i = 0; i < densityTable.length; ++i) {
  131509. densityTable[i] *= 1.0e6;
  131510. }
  131511. // Change range to [0, 1].
  131512. var tableStartDensity = densityTable[1];
  131513. var tableEndDensity = densityTable[densityTable.length - 1];
  131514. for (var j = 0; j < densityTable.length; ++j) {
  131515. densityTable[j] = (densityTable[j] - tableEndDensity) / (tableStartDensity - tableEndDensity);
  131516. }
  131517. var tableLastIndex = 0;
  131518. function findInterval(height) {
  131519. var heights = heightsTable;
  131520. var length = heights.length;
  131521. if (height < heights[0]) {
  131522. tableLastIndex = 0;
  131523. return tableLastIndex;
  131524. } else if (height > heights[length - 1]) {
  131525. tableLastIndex = length - 2;
  131526. return tableLastIndex;
  131527. }
  131528. // Take advantage of temporal coherence by checking current, next and previous intervals
  131529. // for containment of time.
  131530. if (height >= heights[tableLastIndex]) {
  131531. if (tableLastIndex + 1 < length && height < heights[tableLastIndex + 1]) {
  131532. return tableLastIndex;
  131533. } else if (tableLastIndex + 2 < length && height < heights[tableLastIndex + 2]) {
  131534. ++tableLastIndex;
  131535. return tableLastIndex;
  131536. }
  131537. } else if (tableLastIndex - 1 >= 0 && height >= heights[tableLastIndex - 1]) {
  131538. --tableLastIndex;
  131539. return tableLastIndex;
  131540. }
  131541. // The above failed so do a linear search.
  131542. var i;
  131543. for (i = 0; i < length - 2; ++i) {
  131544. if (height >= heights[i] && height < heights[i + 1]) {
  131545. break;
  131546. }
  131547. }
  131548. tableLastIndex = i;
  131549. return tableLastIndex;
  131550. }
  131551. var scratchPositionNormal = new Cartesian3();
  131552. Fog.prototype.update = function(frameState) {
  131553. var enabled = frameState.fog.enabled = this.enabled;
  131554. if (!enabled) {
  131555. return;
  131556. }
  131557. var camera = frameState.camera;
  131558. var positionCartographic = camera.positionCartographic;
  131559. // Turn off fog in space.
  131560. if (!defined(positionCartographic) || positionCartographic.height > 800000.0 || frameState.mode !== SceneMode.SCENE3D) {
  131561. frameState.fog.enabled = false;
  131562. return;
  131563. }
  131564. var height = positionCartographic.height;
  131565. var i = findInterval(height);
  131566. var t = CesiumMath.clamp((height - heightsTable[i]) / (heightsTable[i + 1] - heightsTable[i]), 0.0, 1.0);
  131567. var density = CesiumMath.lerp(densityTable[i], densityTable[i + 1], t);
  131568. // Again, scale value to be in the range of densityTable (prevents divide by zero) and change to new range.
  131569. var startDensity = this.density * 1.0e6;
  131570. var endDensity = (startDensity / tableStartDensity) * tableEndDensity;
  131571. density = (density * (startDensity - endDensity)) * 1.0e-6;
  131572. // Fade fog in as the camera tilts toward the horizon.
  131573. var positionNormal = Cartesian3.normalize(camera.positionWC, scratchPositionNormal);
  131574. var dot = CesiumMath.clamp(Cartesian3.dot(camera.directionWC, positionNormal), 0.0, 1.0);
  131575. density *= 1.0 - dot;
  131576. frameState.fog.density = density;
  131577. frameState.fog.sse = this.screenSpaceErrorFactor;
  131578. };
  131579. return Fog;
  131580. });
  131581. /*global define*/
  131582. define('Scene/FrameRateMonitor',[
  131583. '../Core/defaultValue',
  131584. '../Core/defined',
  131585. '../Core/defineProperties',
  131586. '../Core/destroyObject',
  131587. '../Core/DeveloperError',
  131588. '../Core/Event',
  131589. '../Core/getTimestamp',
  131590. '../Core/TimeConstants'
  131591. ], function(
  131592. defaultValue,
  131593. defined,
  131594. defineProperties,
  131595. destroyObject,
  131596. DeveloperError,
  131597. Event,
  131598. getTimestamp,
  131599. TimeConstants) {
  131600. 'use strict';
  131601. /**
  131602. * Monitors the frame rate (frames per second) in a {@link Scene} and raises an event if the frame rate is
  131603. * lower than a threshold. Later, if the frame rate returns to the required level, a separate event is raised.
  131604. * To avoid creating multiple FrameRateMonitors for a single {@link Scene}, use {@link FrameRateMonitor.fromScene}
  131605. * instead of constructing an instance explicitly.
  131606. *
  131607. * @alias FrameRateMonitor
  131608. * @constructor
  131609. *
  131610. * @param {Object} [options] Object with the following properties:
  131611. * @param {Scene} options.scene The Scene instance for which to monitor performance.
  131612. * @param {Number} [options.samplingWindow=5.0] The length of the sliding window over which to compute the average frame rate, in seconds.
  131613. * @param {Number} [options.quietPeriod=2.0] The length of time to wait at startup and each time the page becomes visible (i.e. when the user
  131614. * switches back to the tab) before starting to measure performance, in seconds.
  131615. * @param {Number} [options.warmupPeriod=5.0] The length of the warmup period, in seconds. During the warmup period, a separate
  131616. * (usually lower) frame rate is required.
  131617. * @param {Number} [options.minimumFrameRateDuringWarmup=4] The minimum frames-per-second that are required for acceptable performance during
  131618. * the warmup period. If the frame rate averages less than this during any samplingWindow during the warmupPeriod, the
  131619. * lowFrameRate event will be raised and the page will redirect to the redirectOnLowFrameRateUrl, if any.
  131620. * @param {Number} [options.minimumFrameRateAfterWarmup=8] The minimum frames-per-second that are required for acceptable performance after
  131621. * the end of the warmup period. If the frame rate averages less than this during any samplingWindow after the warmupPeriod, the
  131622. * lowFrameRate event will be raised and the page will redirect to the redirectOnLowFrameRateUrl, if any.
  131623. */
  131624. function FrameRateMonitor(options) {
  131625. if (!defined(options) || !defined(options.scene)) {
  131626. throw new DeveloperError('options.scene is required.');
  131627. }
  131628. this._scene = options.scene;
  131629. /**
  131630. * Gets or sets the length of the sliding window over which to compute the average frame rate, in seconds.
  131631. * @type {Number}
  131632. */
  131633. this.samplingWindow = defaultValue(options.samplingWindow, FrameRateMonitor.defaultSettings.samplingWindow);
  131634. /**
  131635. * Gets or sets the length of time to wait at startup and each time the page becomes visible (i.e. when the user
  131636. * switches back to the tab) before starting to measure performance, in seconds.
  131637. * @type {Number}
  131638. */
  131639. this.quietPeriod = defaultValue(options.quietPeriod, FrameRateMonitor.defaultSettings.quietPeriod);
  131640. /**
  131641. * Gets or sets the length of the warmup period, in seconds. During the warmup period, a separate
  131642. * (usually lower) frame rate is required.
  131643. * @type {Number}
  131644. */
  131645. this.warmupPeriod = defaultValue(options.warmupPeriod, FrameRateMonitor.defaultSettings.warmupPeriod);
  131646. /**
  131647. * Gets or sets the minimum frames-per-second that are required for acceptable performance during
  131648. * the warmup period. If the frame rate averages less than this during any <code>samplingWindow</code> during the <code>warmupPeriod</code>, the
  131649. * <code>lowFrameRate</code> event will be raised and the page will redirect to the <code>redirectOnLowFrameRateUrl</code>, if any.
  131650. * @type {Number}
  131651. */
  131652. this.minimumFrameRateDuringWarmup = defaultValue(options.minimumFrameRateDuringWarmup, FrameRateMonitor.defaultSettings.minimumFrameRateDuringWarmup);
  131653. /**
  131654. * Gets or sets the minimum frames-per-second that are required for acceptable performance after
  131655. * the end of the warmup period. If the frame rate averages less than this during any <code>samplingWindow</code> after the <code>warmupPeriod</code>, the
  131656. * <code>lowFrameRate</code> event will be raised and the page will redirect to the <code>redirectOnLowFrameRateUrl</code>, if any.
  131657. * @type {Number}
  131658. */
  131659. this.minimumFrameRateAfterWarmup = defaultValue(options.minimumFrameRateAfterWarmup, FrameRateMonitor.defaultSettings.minimumFrameRateAfterWarmup);
  131660. this._lowFrameRate = new Event();
  131661. this._nominalFrameRate = new Event();
  131662. this._frameTimes = [];
  131663. this._needsQuietPeriod = true;
  131664. this._quietPeriodEndTime = 0.0;
  131665. this._warmupPeriodEndTime = 0.0;
  131666. this._frameRateIsLow = false;
  131667. this._lastFramesPerSecond = undefined;
  131668. this._pauseCount = 0;
  131669. var that = this;
  131670. this._preRenderRemoveListener = this._scene.preRender.addEventListener(function(scene, time) {
  131671. update(that, time);
  131672. });
  131673. this._hiddenPropertyName = (document.hidden !== undefined) ? 'hidden' :
  131674. (document.mozHidden !== undefined) ? 'mozHidden' :
  131675. (document.msHidden !== undefined) ? 'msHidden' :
  131676. (document.webkitHidden !== undefined) ? 'webkitHidden' : undefined;
  131677. var visibilityChangeEventName = (document.hidden !== undefined) ? 'visibilitychange' :
  131678. (document.mozHidden !== undefined) ? 'mozvisibilitychange' :
  131679. (document.msHidden !== undefined) ? 'msvisibilitychange' :
  131680. (document.webkitHidden !== undefined) ? 'webkitvisibilitychange' : undefined;
  131681. function visibilityChangeListener() {
  131682. visibilityChanged(that);
  131683. }
  131684. this._visibilityChangeRemoveListener = undefined;
  131685. if (defined(visibilityChangeEventName)) {
  131686. document.addEventListener(visibilityChangeEventName, visibilityChangeListener, false);
  131687. this._visibilityChangeRemoveListener = function() {
  131688. document.removeEventListener(visibilityChangeEventName, visibilityChangeListener, false);
  131689. };
  131690. }
  131691. }
  131692. /**
  131693. * The default frame rate monitoring settings. These settings are used when {@link FrameRateMonitor.fromScene}
  131694. * needs to create a new frame rate monitor, and for any settings that are not passed to the
  131695. * {@link FrameRateMonitor} constructor.
  131696. *
  131697. * @memberof FrameRateMonitor
  131698. * @type {Object}
  131699. */
  131700. FrameRateMonitor.defaultSettings = {
  131701. samplingWindow : 5.0,
  131702. quietPeriod : 2.0,
  131703. warmupPeriod : 5.0,
  131704. minimumFrameRateDuringWarmup : 4,
  131705. minimumFrameRateAfterWarmup : 8
  131706. };
  131707. /**
  131708. * Gets the {@link FrameRateMonitor} for a given scene. If the scene does not yet have
  131709. * a {@link FrameRateMonitor}, one is created with the {@link FrameRateMonitor.defaultSettings}.
  131710. *
  131711. * @param {Scene} scene The scene for which to get the {@link FrameRateMonitor}.
  131712. * @returns {FrameRateMonitor} The scene's {@link FrameRateMonitor}.
  131713. */
  131714. FrameRateMonitor.fromScene = function(scene) {
  131715. if (!defined(scene)) {
  131716. throw new DeveloperError('scene is required.');
  131717. }
  131718. if (!defined(scene._frameRateMonitor) || scene._frameRateMonitor.isDestroyed()) {
  131719. scene._frameRateMonitor = new FrameRateMonitor({
  131720. scene : scene
  131721. });
  131722. }
  131723. return scene._frameRateMonitor;
  131724. };
  131725. defineProperties(FrameRateMonitor.prototype, {
  131726. /**
  131727. * Gets the {@link Scene} instance for which to monitor performance.
  131728. * @memberof FrameRateMonitor.prototype
  131729. * @type {Scene}
  131730. */
  131731. scene : {
  131732. get : function() {
  131733. return this._scene;
  131734. }
  131735. },
  131736. /**
  131737. * Gets the event that is raised when a low frame rate is detected. The function will be passed
  131738. * the {@link Scene} instance as its first parameter and the average number of frames per second
  131739. * over the sampling window as its second parameter.
  131740. * @memberof FrameRateMonitor.prototype
  131741. * @type {Event}
  131742. */
  131743. lowFrameRate : {
  131744. get : function() {
  131745. return this._lowFrameRate;
  131746. }
  131747. },
  131748. /**
  131749. * Gets the event that is raised when the frame rate returns to a normal level after having been low.
  131750. * The function will be passed the {@link Scene} instance as its first parameter and the average
  131751. * number of frames per second over the sampling window as its second parameter.
  131752. * @memberof FrameRateMonitor.prototype
  131753. * @type {Event}
  131754. */
  131755. nominalFrameRate : {
  131756. get : function() {
  131757. return this._nominalFrameRate;
  131758. }
  131759. },
  131760. /**
  131761. * Gets the most recently computed average frames-per-second over the last <code>samplingWindow</code>.
  131762. * This property may be undefined if the frame rate has not been computed.
  131763. * @memberof FrameRateMonitor.prototype
  131764. * @type {Number}
  131765. */
  131766. lastFramesPerSecond : {
  131767. get : function() {
  131768. return this._lastFramesPerSecond;
  131769. }
  131770. }
  131771. });
  131772. /**
  131773. * Pauses monitoring of the frame rate. To resume monitoring, {@link FrameRateMonitor#unpause}
  131774. * must be called once for each time this function is called.
  131775. * @memberof FrameRateMonitor
  131776. */
  131777. FrameRateMonitor.prototype.pause = function() {
  131778. ++this._pauseCount;
  131779. if (this._pauseCount === 1) {
  131780. this._frameTimes.length = 0;
  131781. this._lastFramesPerSecond = undefined;
  131782. }
  131783. };
  131784. /**
  131785. * Resumes monitoring of the frame rate. If {@link FrameRateMonitor#pause} was called
  131786. * multiple times, this function must be called the same number of times in order to
  131787. * actually resume monitoring.
  131788. * @memberof FrameRateMonitor
  131789. */
  131790. FrameRateMonitor.prototype.unpause = function() {
  131791. --this._pauseCount;
  131792. if (this._pauseCount <= 0) {
  131793. this._pauseCount = 0;
  131794. this._needsQuietPeriod = true;
  131795. }
  131796. };
  131797. /**
  131798. * Returns true if this object was destroyed; otherwise, false.
  131799. * <br /><br />
  131800. * If this object was destroyed, it should not be used; calling any function other than
  131801. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  131802. *
  131803. * @memberof FrameRateMonitor
  131804. *
  131805. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  131806. *
  131807. * @see FrameRateMonitor#destroy
  131808. */
  131809. FrameRateMonitor.prototype.isDestroyed = function() {
  131810. return false;
  131811. };
  131812. /**
  131813. * Unsubscribes this instance from all events it is listening to.
  131814. * Once an object is destroyed, it should not be used; calling any function other than
  131815. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  131816. * assign the return value (<code>undefined</code>) to the object as done in the example.
  131817. *
  131818. * @memberof FrameRateMonitor
  131819. *
  131820. * @returns {undefined}
  131821. *
  131822. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  131823. *
  131824. * @see FrameRateMonitor#isDestroyed
  131825. */
  131826. FrameRateMonitor.prototype.destroy = function() {
  131827. this._preRenderRemoveListener();
  131828. if (defined(this._visibilityChangeRemoveListener)) {
  131829. this._visibilityChangeRemoveListener();
  131830. }
  131831. return destroyObject(this);
  131832. };
  131833. function update(monitor, time) {
  131834. if (monitor._pauseCount > 0) {
  131835. return;
  131836. }
  131837. var timeStamp = getTimestamp();
  131838. if (monitor._needsQuietPeriod) {
  131839. monitor._needsQuietPeriod = false;
  131840. monitor._frameTimes.length = 0;
  131841. monitor._quietPeriodEndTime = timeStamp + (monitor.quietPeriod / TimeConstants.SECONDS_PER_MILLISECOND);
  131842. monitor._warmupPeriodEndTime = monitor._quietPeriodEndTime + ((monitor.warmupPeriod + monitor.samplingWindow) / TimeConstants.SECONDS_PER_MILLISECOND);
  131843. } else if (timeStamp >= monitor._quietPeriodEndTime) {
  131844. monitor._frameTimes.push(timeStamp);
  131845. var beginningOfWindow = timeStamp - (monitor.samplingWindow / TimeConstants.SECONDS_PER_MILLISECOND);
  131846. if (monitor._frameTimes.length >= 2 && monitor._frameTimes[0] <= beginningOfWindow) {
  131847. while (monitor._frameTimes.length >= 2 && monitor._frameTimes[1] < beginningOfWindow) {
  131848. monitor._frameTimes.shift();
  131849. }
  131850. var averageTimeBetweenFrames = (timeStamp - monitor._frameTimes[0]) / (monitor._frameTimes.length - 1);
  131851. monitor._lastFramesPerSecond = 1000.0 / averageTimeBetweenFrames;
  131852. var maximumFrameTime = 1000.0 / (timeStamp > monitor._warmupPeriodEndTime ? monitor.minimumFrameRateAfterWarmup : monitor.minimumFrameRateDuringWarmup);
  131853. if (averageTimeBetweenFrames > maximumFrameTime) {
  131854. if (!monitor._frameRateIsLow) {
  131855. monitor._frameRateIsLow = true;
  131856. monitor._needsQuietPeriod = true;
  131857. monitor.lowFrameRate.raiseEvent(monitor.scene, monitor._lastFramesPerSecond);
  131858. }
  131859. } else if (monitor._frameRateIsLow) {
  131860. monitor._frameRateIsLow = false;
  131861. monitor._needsQuietPeriod = true;
  131862. monitor.nominalFrameRate.raiseEvent(monitor.scene, monitor._lastFramesPerSecond);
  131863. }
  131864. }
  131865. }
  131866. }
  131867. function visibilityChanged(monitor) {
  131868. if (document[monitor._hiddenPropertyName]) {
  131869. monitor.pause();
  131870. } else {
  131871. monitor.unpause();
  131872. }
  131873. }
  131874. return FrameRateMonitor;
  131875. });
  131876. /*global define*/
  131877. define('Scene/FrameState',[
  131878. './SceneMode'
  131879. ], function(
  131880. SceneMode) {
  131881. 'use strict';
  131882. /**
  131883. * State information about the current frame. An instance of this class
  131884. * is provided to update functions.
  131885. *
  131886. * @param {CreditDisplay} creditDisplay Handles adding and removing credits from an HTML element
  131887. *
  131888. * @alias FrameState
  131889. * @constructor
  131890. *
  131891. * @private
  131892. */
  131893. function FrameState(context, creditDisplay) {
  131894. /**
  131895. * The rendering context.
  131896. * @type {Context}
  131897. */
  131898. this.context = context;
  131899. /**
  131900. * An array of rendering commands.
  131901. * @type {DrawCommand[]}
  131902. */
  131903. this.commandList = [];
  131904. /**
  131905. * An array of shadow maps.
  131906. * @type {ShadowMap[]}
  131907. */
  131908. this.shadowMaps = [];
  131909. /**
  131910. * The current mode of the scene.
  131911. * @type {SceneMode}
  131912. * @default {@link SceneMode.SCENE3D}
  131913. */
  131914. this.mode = SceneMode.SCENE3D;
  131915. /**
  131916. * The current morph transition time between 2D/Columbus View and 3D,
  131917. * with 0.0 being 2D or Columbus View and 1.0 being 3D.
  131918. *
  131919. * @type {Number}
  131920. */
  131921. this.morphTime = SceneMode.getMorphTime(SceneMode.SCENE3D);
  131922. /**
  131923. * The current frame number.
  131924. *
  131925. * @type {Number}
  131926. * @default 0
  131927. */
  131928. this.frameNumber = 0;
  131929. /**
  131930. * The scene's current time.
  131931. *
  131932. * @type {JulianDate}
  131933. * @default undefined
  131934. */
  131935. this.time = undefined;
  131936. /**
  131937. * The map projection to use in 2D and Columbus View modes.
  131938. *
  131939. * @type {MapProjection}
  131940. * @default undefined
  131941. */
  131942. this.mapProjection = undefined;
  131943. /**
  131944. * The current camera.
  131945. * @type {Camera}
  131946. * @default undefined
  131947. */
  131948. this.camera = undefined;
  131949. /**
  131950. * The culling volume.
  131951. * @type {CullingVolume}
  131952. * @default undefined
  131953. */
  131954. this.cullingVolume = undefined;
  131955. /**
  131956. * The current occluder.
  131957. * @type {Occluder}
  131958. * @default undefined
  131959. */
  131960. this.occluder = undefined;
  131961. this.passes = {
  131962. /**
  131963. * <code>true</code> if the primitive should update for a render pass, <code>false</code> otherwise.
  131964. * @type {Boolean}
  131965. * @default false
  131966. */
  131967. render : false,
  131968. /**
  131969. * <code>true</code> if the primitive should update for a picking pass, <code>false</code> otherwise.
  131970. * @type {Boolean}
  131971. * @default false
  131972. */
  131973. pick : false
  131974. };
  131975. /**
  131976. * The credit display.
  131977. * @type {CreditDisplay}
  131978. */
  131979. this.creditDisplay = creditDisplay;
  131980. /**
  131981. * An array of functions to be called at the end of the frame. This array
  131982. * will be cleared after each frame.
  131983. * <p>
  131984. * This allows queueing up events in <code>update</code> functions and
  131985. * firing them at a time when the subscribers are free to change the
  131986. * scene state, e.g., manipulate the camera, instead of firing events
  131987. * directly in <code>update</code> functions.
  131988. * </p>
  131989. *
  131990. * @type {FrameState~AfterRenderCallback[]}
  131991. *
  131992. * @example
  131993. * frameState.afterRender.push(function() {
  131994. * // take some action, raise an event, etc.
  131995. * });
  131996. */
  131997. this.afterRender = [];
  131998. /**
  131999. * Gets whether or not to optimized for 3D only.
  132000. * @type {Boolean}
  132001. * @default false
  132002. */
  132003. this.scene3DOnly = false;
  132004. this.fog = {
  132005. /**
  132006. * <code>true</code> if fog is enabled, <code>false</code> otherwise.
  132007. * @type {Boolean}
  132008. * @default false
  132009. */
  132010. enabled : false,
  132011. /**
  132012. * A positive number used to mix the color and fog color based on camera distance.
  132013. * @type {Number}
  132014. * @default undefined
  132015. */
  132016. density : undefined,
  132017. /**
  132018. * A scalar used to modify the screen space error of geometry partially in fog.
  132019. * @type {Number}
  132020. * @default undefined
  132021. */
  132022. sse : undefined
  132023. };
  132024. /**
  132025. * A scalar used to exaggerate the terrain.
  132026. * @type {Number}
  132027. */
  132028. this.terrainExaggeration = 1.0;
  132029. this.shadowHints = {
  132030. /**
  132031. * Whether there are any active shadow maps this frame.
  132032. * @type {Boolean}
  132033. */
  132034. shadowsEnabled : true,
  132035. /**
  132036. * All shadow maps that are enabled this frame.
  132037. */
  132038. shadowMaps : [],
  132039. /**
  132040. * Shadow maps that originate from light sources. Does not include shadow maps that are used for
  132041. * analytical purposes. Only these shadow maps will be used to generate receive shadows shaders.
  132042. */
  132043. lightShadowMaps : [],
  132044. /**
  132045. * The near plane of the scene's frustum commands. Used for fitting cascaded shadow maps.
  132046. * @type {Number}
  132047. */
  132048. nearPlane : 1.0,
  132049. /**
  132050. * The far plane of the scene's frustum commands. Used for fitting cascaded shadow maps.
  132051. * @type {Number}
  132052. */
  132053. farPlane : 5000.0,
  132054. /**
  132055. * The size of the bounding volume that is closest to the camera. This is used to place more shadow detail near the object.
  132056. * @type {Number}
  132057. */
  132058. closestObjectSize : 1000.0,
  132059. /**
  132060. * The time when a shadow map was last dirty
  132061. * @type {Number}
  132062. */
  132063. lastDirtyTime : 0,
  132064. /**
  132065. * Whether the shadows maps are out of view this frame
  132066. * @type {Boolean}
  132067. */
  132068. outOfView : true
  132069. };
  132070. }
  132071. /**
  132072. * A function that will be called at the end of the frame.
  132073. * @callback FrameState~AfterRenderCallback
  132074. */
  132075. return FrameState;
  132076. });
  132077. /*global define*/
  132078. define('Scene/FrustumCommands',[
  132079. '../Core/defaultValue',
  132080. '../Renderer/Pass'
  132081. ], function(
  132082. defaultValue,
  132083. Pass) {
  132084. 'use strict';
  132085. /**
  132086. * Defines a list of commands whose geometry are bound by near and far distances from the camera.
  132087. * @alias FrustumCommands
  132088. * @constructor
  132089. *
  132090. * @param {Number} [near=0.0] The lower bound or closest distance from the camera.
  132091. * @param {Number} [far=0.0] The upper bound or farthest distance from the camera.
  132092. *
  132093. * @private
  132094. */
  132095. function FrustumCommands(near, far) {
  132096. this.near = defaultValue(near, 0.0);
  132097. this.far = defaultValue(far, 0.0);
  132098. var numPasses = Pass.NUMBER_OF_PASSES;
  132099. var commands = new Array(numPasses);
  132100. var indices = new Array(numPasses);
  132101. for (var i = 0; i < numPasses; ++i) {
  132102. commands[i] = [];
  132103. indices[i] = 0;
  132104. }
  132105. this.commands = commands;
  132106. this.indices = indices;
  132107. }
  132108. return FrustumCommands;
  132109. });
  132110. /**
  132111. * @license
  132112. * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
  132113. *
  132114. * TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED
  132115. * *AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS
  132116. * OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT,IMPLIED WARRANTIES OF
  132117. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA
  132118. * OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT, OR
  132119. * CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS
  132120. * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY
  132121. * OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
  132122. * EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
  132123. */
  132124. //This file is automatically rebuilt by the Cesium build process.
  132125. /*global define*/
  132126. define('Shaders/PostProcessFilters/FXAA',[],function() {
  132127. 'use strict';
  132128. return "#ifndef FXAA_PRESET\n\
  132129. #define FXAA_PRESET 3\n\
  132130. #endif\n\
  132131. #if (FXAA_PRESET == 3)\n\
  132132. #define FXAA_EDGE_THRESHOLD (1.0/8.0)\n\
  132133. #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)\n\
  132134. #define FXAA_SEARCH_STEPS 16\n\
  132135. #define FXAA_SEARCH_THRESHOLD (1.0/4.0)\n\
  132136. #define FXAA_SUBPIX_CAP (3.0/4.0)\n\
  132137. #define FXAA_SUBPIX_TRIM (1.0/4.0)\n\
  132138. #endif\n\
  132139. #if (FXAA_PRESET == 4)\n\
  132140. #define FXAA_EDGE_THRESHOLD (1.0/8.0)\n\
  132141. #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)\n\
  132142. #define FXAA_SEARCH_STEPS 24\n\
  132143. #define FXAA_SEARCH_THRESHOLD (1.0/4.0)\n\
  132144. #define FXAA_SUBPIX_CAP (3.0/4.0)\n\
  132145. #define FXAA_SUBPIX_TRIM (1.0/4.0)\n\
  132146. #endif\n\
  132147. #if (FXAA_PRESET == 5)\n\
  132148. #define FXAA_EDGE_THRESHOLD (1.0/8.0)\n\
  132149. #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)\n\
  132150. #define FXAA_SEARCH_STEPS 32\n\
  132151. #define FXAA_SEARCH_THRESHOLD (1.0/4.0)\n\
  132152. #define FXAA_SUBPIX_CAP (3.0/4.0)\n\
  132153. #define FXAA_SUBPIX_TRIM (1.0/4.0)\n\
  132154. #endif\n\
  132155. #define FXAA_SUBPIX_TRIM_SCALE (1.0/(1.0 - FXAA_SUBPIX_TRIM))\n\
  132156. float FxaaLuma(vec3 rgb) {\n\
  132157. return rgb.y * (0.587/0.299) + rgb.x;\n\
  132158. }\n\
  132159. vec3 FxaaLerp3(vec3 a, vec3 b, float amountOfA) {\n\
  132160. return (vec3(-amountOfA) * b) + ((a * vec3(amountOfA)) + b);\n\
  132161. }\n\
  132162. vec4 FxaaTexOff(sampler2D tex, vec2 pos, ivec2 off, vec2 rcpFrame) {\n\
  132163. float x = pos.x + float(off.x) * rcpFrame.x;\n\
  132164. float y = pos.y + float(off.y) * rcpFrame.y;\n\
  132165. return texture2D(tex, vec2(x, y));\n\
  132166. }\n\
  132167. vec3 FxaaPixelShader(vec2 pos, sampler2D tex, vec2 rcpFrame)\n\
  132168. {\n\
  132169. vec3 rgbN = FxaaTexOff(tex, pos.xy, ivec2( 0,-1), rcpFrame).xyz;\n\
  132170. vec3 rgbW = FxaaTexOff(tex, pos.xy, ivec2(-1, 0), rcpFrame).xyz;\n\
  132171. vec3 rgbM = FxaaTexOff(tex, pos.xy, ivec2( 0, 0), rcpFrame).xyz;\n\
  132172. vec3 rgbE = FxaaTexOff(tex, pos.xy, ivec2( 1, 0), rcpFrame).xyz;\n\
  132173. vec3 rgbS = FxaaTexOff(tex, pos.xy, ivec2( 0, 1), rcpFrame).xyz;\n\
  132174. float lumaN = FxaaLuma(rgbN);\n\
  132175. float lumaW = FxaaLuma(rgbW);\n\
  132176. float lumaM = FxaaLuma(rgbM);\n\
  132177. float lumaE = FxaaLuma(rgbE);\n\
  132178. float lumaS = FxaaLuma(rgbS);\n\
  132179. float rangeMin = min(lumaM, min(min(lumaN, lumaW), min(lumaS, lumaE)));\n\
  132180. float rangeMax = max(lumaM, max(max(lumaN, lumaW), max(lumaS, lumaE)));\n\
  132181. float range = rangeMax - rangeMin;\n\
  132182. if(range < max(FXAA_EDGE_THRESHOLD_MIN, rangeMax * FXAA_EDGE_THRESHOLD))\n\
  132183. {\n\
  132184. return rgbM;\n\
  132185. }\n\
  132186. vec3 rgbL = rgbN + rgbW + rgbM + rgbE + rgbS;\n\
  132187. float lumaL = (lumaN + lumaW + lumaE + lumaS) * 0.25;\n\
  132188. float rangeL = abs(lumaL - lumaM);\n\
  132189. float blendL = max(0.0, (rangeL / range) - FXAA_SUBPIX_TRIM) * FXAA_SUBPIX_TRIM_SCALE;\n\
  132190. blendL = min(FXAA_SUBPIX_CAP, blendL);\n\
  132191. vec3 rgbNW = FxaaTexOff(tex, pos.xy, ivec2(-1,-1), rcpFrame).xyz;\n\
  132192. vec3 rgbNE = FxaaTexOff(tex, pos.xy, ivec2( 1,-1), rcpFrame).xyz;\n\
  132193. vec3 rgbSW = FxaaTexOff(tex, pos.xy, ivec2(-1, 1), rcpFrame).xyz;\n\
  132194. vec3 rgbSE = FxaaTexOff(tex, pos.xy, ivec2( 1, 1), rcpFrame).xyz;\n\
  132195. rgbL += (rgbNW + rgbNE + rgbSW + rgbSE);\n\
  132196. rgbL *= vec3(1.0/9.0);\n\
  132197. float lumaNW = FxaaLuma(rgbNW);\n\
  132198. float lumaNE = FxaaLuma(rgbNE);\n\
  132199. float lumaSW = FxaaLuma(rgbSW);\n\
  132200. float lumaSE = FxaaLuma(rgbSE);\n\
  132201. float edgeVert =\n\
  132202. abs((0.25 * lumaNW) + (-0.5 * lumaN) + (0.25 * lumaNE)) +\n\
  132203. abs((0.50 * lumaW ) + (-1.0 * lumaM) + (0.50 * lumaE )) +\n\
  132204. abs((0.25 * lumaSW) + (-0.5 * lumaS) + (0.25 * lumaSE));\n\
  132205. float edgeHorz =\n\
  132206. abs((0.25 * lumaNW) + (-0.5 * lumaW) + (0.25 * lumaSW)) +\n\
  132207. abs((0.50 * lumaN ) + (-1.0 * lumaM) + (0.50 * lumaS )) +\n\
  132208. abs((0.25 * lumaNE) + (-0.5 * lumaE) + (0.25 * lumaSE));\n\
  132209. bool horzSpan = edgeHorz >= edgeVert;\n\
  132210. float lengthSign = horzSpan ? -rcpFrame.y : -rcpFrame.x;\n\
  132211. if(!horzSpan)\n\
  132212. {\n\
  132213. lumaN = lumaW;\n\
  132214. lumaS = lumaE;\n\
  132215. }\n\
  132216. float gradientN = abs(lumaN - lumaM);\n\
  132217. float gradientS = abs(lumaS - lumaM);\n\
  132218. lumaN = (lumaN + lumaM) * 0.5;\n\
  132219. lumaS = (lumaS + lumaM) * 0.5;\n\
  132220. if (gradientN < gradientS)\n\
  132221. {\n\
  132222. lumaN = lumaS;\n\
  132223. lumaN = lumaS;\n\
  132224. gradientN = gradientS;\n\
  132225. lengthSign *= -1.0;\n\
  132226. }\n\
  132227. vec2 posN;\n\
  132228. posN.x = pos.x + (horzSpan ? 0.0 : lengthSign * 0.5);\n\
  132229. posN.y = pos.y + (horzSpan ? lengthSign * 0.5 : 0.0);\n\
  132230. gradientN *= FXAA_SEARCH_THRESHOLD;\n\
  132231. vec2 posP = posN;\n\
  132232. vec2 offNP = horzSpan ? vec2(rcpFrame.x, 0.0) : vec2(0.0, rcpFrame.y);\n\
  132233. float lumaEndN = lumaN;\n\
  132234. float lumaEndP = lumaN;\n\
  132235. bool doneN = false;\n\
  132236. bool doneP = false;\n\
  132237. posN += offNP * vec2(-1.0, -1.0);\n\
  132238. posP += offNP * vec2( 1.0, 1.0);\n\
  132239. for(int i = 0; i < FXAA_SEARCH_STEPS; i++) {\n\
  132240. if(!doneN)\n\
  132241. {\n\
  132242. lumaEndN = FxaaLuma(texture2D(tex, posN.xy).xyz);\n\
  132243. }\n\
  132244. if(!doneP)\n\
  132245. {\n\
  132246. lumaEndP = FxaaLuma(texture2D(tex, posP.xy).xyz);\n\
  132247. }\n\
  132248. doneN = doneN || (abs(lumaEndN - lumaN) >= gradientN);\n\
  132249. doneP = doneP || (abs(lumaEndP - lumaN) >= gradientN);\n\
  132250. if(doneN && doneP)\n\
  132251. {\n\
  132252. break;\n\
  132253. }\n\
  132254. if(!doneN)\n\
  132255. {\n\
  132256. posN -= offNP;\n\
  132257. }\n\
  132258. if(!doneP)\n\
  132259. {\n\
  132260. posP += offNP;\n\
  132261. }\n\
  132262. }\n\
  132263. float dstN = horzSpan ? pos.x - posN.x : pos.y - posN.y;\n\
  132264. float dstP = horzSpan ? posP.x - pos.x : posP.y - pos.y;\n\
  132265. bool directionN = dstN < dstP;\n\
  132266. lumaEndN = directionN ? lumaEndN : lumaEndP;\n\
  132267. if(((lumaM - lumaN) < 0.0) == ((lumaEndN - lumaN) < 0.0))\n\
  132268. {\n\
  132269. lengthSign = 0.0;\n\
  132270. }\n\
  132271. float spanLength = (dstP + dstN);\n\
  132272. dstN = directionN ? dstN : dstP;\n\
  132273. float subPixelOffset = (0.5 + (dstN * (-1.0/spanLength))) * lengthSign;\n\
  132274. vec3 rgbF = texture2D(tex, vec2(\n\
  132275. pos.x + (horzSpan ? 0.0 : subPixelOffset),\n\
  132276. pos.y + (horzSpan ? subPixelOffset : 0.0))).xyz;\n\
  132277. return FxaaLerp3(rgbL, rgbF, blendL);\n\
  132278. }\n\
  132279. uniform sampler2D u_texture;\n\
  132280. uniform vec2 u_step;\n\
  132281. varying vec2 v_textureCoordinates;\n\
  132282. void main()\n\
  132283. {\n\
  132284. gl_FragColor = vec4(FxaaPixelShader(v_textureCoordinates, u_texture, u_step), 1.0);\n\
  132285. }\n\
  132286. ";
  132287. });
  132288. /*global define*/
  132289. define('Scene/FXAA',[
  132290. '../Core/BoundingRectangle',
  132291. '../Core/Cartesian2',
  132292. '../Core/Color',
  132293. '../Core/defined',
  132294. '../Core/destroyObject',
  132295. '../Core/PixelFormat',
  132296. '../Renderer/ClearCommand',
  132297. '../Renderer/Framebuffer',
  132298. '../Renderer/PixelDatatype',
  132299. '../Renderer/Renderbuffer',
  132300. '../Renderer/RenderbufferFormat',
  132301. '../Renderer/RenderState',
  132302. '../Renderer/Texture',
  132303. '../Shaders/PostProcessFilters/FXAA'
  132304. ], function(
  132305. BoundingRectangle,
  132306. Cartesian2,
  132307. Color,
  132308. defined,
  132309. destroyObject,
  132310. PixelFormat,
  132311. ClearCommand,
  132312. Framebuffer,
  132313. PixelDatatype,
  132314. Renderbuffer,
  132315. RenderbufferFormat,
  132316. RenderState,
  132317. Texture,
  132318. FXAAFS) {
  132319. 'use strict';
  132320. /**
  132321. * @private
  132322. */
  132323. function FXAA(context) {
  132324. this._texture = undefined;
  132325. this._depthStencilTexture = undefined;
  132326. this._depthStencilRenderbuffer = undefined;
  132327. this._fbo = undefined;
  132328. this._command = undefined;
  132329. this._viewport = new BoundingRectangle();
  132330. this._rs = undefined;
  132331. var clearCommand = new ClearCommand({
  132332. color : new Color(0.0, 0.0, 0.0, 0.0),
  132333. depth : 1.0,
  132334. owner : this
  132335. });
  132336. this._clearCommand = clearCommand;
  132337. }
  132338. function destroyResources(fxaa) {
  132339. fxaa._fbo = fxaa._fbo && fxaa._fbo.destroy();
  132340. fxaa._texture = fxaa._texture && fxaa._texture.destroy();
  132341. fxaa._depthStencilTexture = fxaa._depthStencilTexture && fxaa._depthStencilTexture.destroy();
  132342. fxaa._depthStencilRenderbuffer = fxaa._depthStencilRenderbuffer && fxaa._depthStencilRenderbuffer.destroy();
  132343. fxaa._fbo = undefined;
  132344. fxaa._texture = undefined;
  132345. fxaa._depthStencilTexture = undefined;
  132346. fxaa._depthStencilRenderbuffer = undefined;
  132347. if (defined(fxaa._command)) {
  132348. fxaa._command.shaderProgram = fxaa._command.shaderProgram && fxaa._command.shaderProgram.destroy();
  132349. fxaa._command = undefined;
  132350. }
  132351. }
  132352. FXAA.prototype.update = function(context) {
  132353. var width = context.drawingBufferWidth;
  132354. var height = context.drawingBufferHeight;
  132355. var fxaaTexture = this._texture;
  132356. var textureChanged = !defined(fxaaTexture) || fxaaTexture.width !== width || fxaaTexture.height !== height;
  132357. if (textureChanged) {
  132358. this._texture = this._texture && this._texture.destroy();
  132359. this._depthStencilTexture = this._depthStencilTexture && this._depthStencilTexture.destroy();
  132360. this._depthStencilRenderbuffer = this._depthStencilRenderbuffer && this._depthStencilRenderbuffer.destroy();
  132361. this._texture = new Texture({
  132362. context : context,
  132363. width : width,
  132364. height : height,
  132365. pixelFormat : PixelFormat.RGBA,
  132366. pixelDatatype : PixelDatatype.UNSIGNED_BYTE
  132367. });
  132368. if (context.depthTexture) {
  132369. this._depthStencilTexture = new Texture({
  132370. context : context,
  132371. width : width,
  132372. height : height,
  132373. pixelFormat : PixelFormat.DEPTH_STENCIL,
  132374. pixelDatatype : PixelDatatype.UNSIGNED_INT_24_8
  132375. });
  132376. } else {
  132377. this._depthStencilRenderbuffer = new Renderbuffer({
  132378. context : context,
  132379. width : width,
  132380. height : height,
  132381. format : RenderbufferFormat.DEPTH_STENCIL
  132382. });
  132383. }
  132384. }
  132385. if (!defined(this._fbo) || textureChanged) {
  132386. this._fbo = this._fbo && this._fbo.destroy();
  132387. this._fbo = new Framebuffer({
  132388. context : context,
  132389. colorTextures : [this._texture],
  132390. depthStencilTexture : this._depthStencilTexture,
  132391. depthStencilRenderbuffer : this._depthStencilRenderbuffer,
  132392. destroyAttachments : false
  132393. });
  132394. }
  132395. if (!defined(this._command)) {
  132396. this._command = context.createViewportQuadCommand(FXAAFS, {
  132397. owner : this
  132398. });
  132399. }
  132400. this._viewport.width = width;
  132401. this._viewport.height = height;
  132402. if (!defined(this._rs) || !BoundingRectangle.equals(this._rs.viewport, this._viewport)) {
  132403. this._rs = RenderState.fromCache({
  132404. viewport : this._viewport
  132405. });
  132406. }
  132407. this._command.renderState = this._rs;
  132408. if (textureChanged) {
  132409. var that = this;
  132410. var step = new Cartesian2(1.0 / this._texture.width, 1.0 / this._texture.height);
  132411. this._command.uniformMap = {
  132412. u_texture : function() {
  132413. return that._texture;
  132414. },
  132415. u_step : function() {
  132416. return step;
  132417. }
  132418. };
  132419. }
  132420. };
  132421. FXAA.prototype.execute = function(context, passState) {
  132422. this._command.execute(context, passState);
  132423. };
  132424. FXAA.prototype.clear = function(context, passState, clearColor) {
  132425. var framebuffer = passState.framebuffer;
  132426. passState.framebuffer = this._fbo;
  132427. Color.clone(clearColor, this._clearCommand.color);
  132428. this._clearCommand.execute(context, passState);
  132429. passState.framebuffer = framebuffer;
  132430. };
  132431. FXAA.prototype.getColorFramebuffer = function() {
  132432. return this._fbo;
  132433. };
  132434. FXAA.prototype.isDestroyed = function() {
  132435. return false;
  132436. };
  132437. FXAA.prototype.destroy = function() {
  132438. destroyResources(this);
  132439. return destroyObject(this);
  132440. };
  132441. return FXAA;
  132442. });
  132443. /*global define*/
  132444. define('Scene/GetFeatureInfoFormat',[
  132445. '../Core/Cartographic',
  132446. '../Core/defined',
  132447. '../Core/DeveloperError',
  132448. '../Core/RuntimeError',
  132449. './ImageryLayerFeatureInfo'
  132450. ], function(
  132451. Cartographic,
  132452. defined,
  132453. DeveloperError,
  132454. RuntimeError,
  132455. ImageryLayerFeatureInfo) {
  132456. 'use strict';
  132457. /**
  132458. * Describes the format in which to request GetFeatureInfo from a Web Map Service (WMS) server.
  132459. *
  132460. * @alias GetFeatureInfoFormat
  132461. * @constructor
  132462. *
  132463. * @param {String} type The type of response to expect from a GetFeatureInfo request. Valid
  132464. * values are 'json', 'xml', 'html', or 'text'.
  132465. * @param {String} [format] The info format to request from the WMS server. This is usually a
  132466. * MIME type such as 'application/json' or text/xml'. If this parameter is not specified, the provider will request 'json'
  132467. * using 'application/json', 'xml' using 'text/xml', 'html' using 'text/html', and 'text' using 'text/plain'.
  132468. * @param {Function} [callback] A function to invoke with the GetFeatureInfo response from the WMS server
  132469. * in order to produce an array of picked {@link ImageryLayerFeatureInfo} instances. If this parameter is not specified,
  132470. * a default function for the type of response is used.
  132471. */
  132472. function GetFeatureInfoFormat(type, format, callback) {
  132473. if (!defined(type)) {
  132474. throw new DeveloperError('type is required.');
  132475. }
  132476. this.type = type;
  132477. if (!defined(format)) {
  132478. if (type === 'json') {
  132479. format = 'application/json';
  132480. } else if (type === 'xml') {
  132481. format = 'text/xml';
  132482. } else if (type === 'html') {
  132483. format = 'text/html';
  132484. } else if (type === 'text') {
  132485. format = 'text/plain';
  132486. }
  132487. else {
  132488. throw new DeveloperError('format is required when type is not "json", "xml", "html", or "text".');
  132489. }
  132490. }
  132491. this.format = format;
  132492. if (!defined(callback)) {
  132493. if (type === 'json') {
  132494. callback = geoJsonToFeatureInfo;
  132495. } else if (type === 'xml') {
  132496. callback = xmlToFeatureInfo;
  132497. } else if (type === 'html') {
  132498. callback = textToFeatureInfo;
  132499. } else if (type === 'text') {
  132500. callback = textToFeatureInfo;
  132501. }
  132502. else {
  132503. throw new DeveloperError('callback is required when type is not "json", "xml", "html", or "text".');
  132504. }
  132505. }
  132506. this.callback = callback;
  132507. }
  132508. function geoJsonToFeatureInfo(json) {
  132509. var result = [];
  132510. var features = json.features;
  132511. for (var i = 0; i < features.length; ++i) {
  132512. var feature = features[i];
  132513. var featureInfo = new ImageryLayerFeatureInfo();
  132514. featureInfo.data = feature;
  132515. featureInfo.properties = feature.properties;
  132516. featureInfo.configureNameFromProperties(feature.properties);
  132517. featureInfo.configureDescriptionFromProperties(feature.properties);
  132518. // If this is a point feature, use the coordinates of the point.
  132519. if (defined(feature.geometry) && feature.geometry.type === 'Point') {
  132520. var longitude = feature.geometry.coordinates[0];
  132521. var latitude = feature.geometry.coordinates[1];
  132522. featureInfo.position = Cartographic.fromDegrees(longitude, latitude);
  132523. }
  132524. result.push(featureInfo);
  132525. }
  132526. return result;
  132527. }
  132528. var mapInfoMxpNamespace = 'http://www.mapinfo.com/mxp';
  132529. var esriWmsNamespace = 'http://www.esri.com/wms';
  132530. var wfsNamespace = 'http://www.opengis.net/wfs';
  132531. var gmlNamespace = 'http://www.opengis.net/gml';
  132532. function xmlToFeatureInfo(xml) {
  132533. var documentElement = xml.documentElement;
  132534. if (documentElement.localName === 'MultiFeatureCollection' && documentElement.namespaceURI === mapInfoMxpNamespace) {
  132535. // This looks like a MapInfo MXP response
  132536. return mapInfoXmlToFeatureInfo(xml);
  132537. } else if (documentElement.localName === 'FeatureInfoResponse' && documentElement.namespaceURI === esriWmsNamespace) {
  132538. // This looks like an Esri WMS response
  132539. return esriXmlToFeatureInfo(xml);
  132540. } else if (documentElement.localName === 'FeatureCollection' && documentElement.namespaceURI === wfsNamespace) {
  132541. // This looks like a WFS/GML response.
  132542. return gmlToFeatureInfo(xml);
  132543. } else if (documentElement.localName === 'ServiceExceptionReport') {
  132544. // This looks like a WMS server error, so no features picked.
  132545. throw new RuntimeError(new XMLSerializer().serializeToString(documentElement));
  132546. } else if (documentElement.localName === 'msGMLOutput') {
  132547. return msGmlToFeatureInfo(xml);
  132548. } else {
  132549. // Unknown response type, so just dump the XML itself into the description.
  132550. return unknownXmlToFeatureInfo(xml);
  132551. }
  132552. }
  132553. function mapInfoXmlToFeatureInfo(xml) {
  132554. var result = [];
  132555. var multiFeatureCollection = xml.documentElement;
  132556. var features = multiFeatureCollection.getElementsByTagNameNS(mapInfoMxpNamespace, 'Feature');
  132557. for (var featureIndex = 0; featureIndex < features.length; ++featureIndex) {
  132558. var feature = features[featureIndex];
  132559. var properties = {};
  132560. var propertyElements = feature.getElementsByTagNameNS(mapInfoMxpNamespace, 'Val');
  132561. for (var propertyIndex = 0; propertyIndex < propertyElements.length; ++propertyIndex) {
  132562. var propertyElement = propertyElements[propertyIndex];
  132563. if (propertyElement.hasAttribute('ref')) {
  132564. var name = propertyElement.getAttribute('ref');
  132565. var value = propertyElement.textContent.trim();
  132566. properties[name] = value;
  132567. }
  132568. }
  132569. var featureInfo = new ImageryLayerFeatureInfo();
  132570. featureInfo.data = feature;
  132571. featureInfo.properties = properties;
  132572. featureInfo.configureNameFromProperties(properties);
  132573. featureInfo.configureDescriptionFromProperties(properties);
  132574. result.push(featureInfo);
  132575. }
  132576. return result;
  132577. }
  132578. function esriXmlToFeatureInfo(xml) {
  132579. var featureInfoResponse = xml.documentElement;
  132580. var result = [];
  132581. var properties;
  132582. var features = featureInfoResponse.getElementsByTagNameNS('*', 'FIELDS');
  132583. if (features.length > 0) {
  132584. // Standard esri format
  132585. for (var featureIndex = 0; featureIndex < features.length; ++featureIndex) {
  132586. var feature = features[featureIndex];
  132587. properties = {};
  132588. var propertyAttributes = feature.attributes;
  132589. for (var attributeIndex = 0; attributeIndex < propertyAttributes.length; ++attributeIndex) {
  132590. var attribute = propertyAttributes[attributeIndex];
  132591. properties[attribute.name] = attribute.value;
  132592. }
  132593. result.push(imageryLayerFeatureInfoFromDataAndProperties(feature, properties));
  132594. }
  132595. } else {
  132596. // Thredds format -- looks like esri, but instead of containing FIELDS, contains FeatureInfo element
  132597. var featureInfoElements = featureInfoResponse.getElementsByTagNameNS('*', 'FeatureInfo');
  132598. for (var featureInfoElementIndex = 0; featureInfoElementIndex < featureInfoElements.length; ++featureInfoElementIndex) {
  132599. var featureInfoElement = featureInfoElements[featureInfoElementIndex];
  132600. properties = {};
  132601. // node.children is not supported in IE9-11, so use childNodes and check that child.nodeType is an element
  132602. var featureInfoChildren = featureInfoElement.childNodes;
  132603. for (var childIndex = 0; childIndex < featureInfoChildren.length; ++childIndex) {
  132604. var child = featureInfoChildren[childIndex];
  132605. if (child.nodeType === Node.ELEMENT_NODE) {
  132606. properties[child.localName] = child.textContent;
  132607. }
  132608. }
  132609. result.push(imageryLayerFeatureInfoFromDataAndProperties(featureInfoElement, properties));
  132610. }
  132611. }
  132612. return result;
  132613. }
  132614. function gmlToFeatureInfo(xml) {
  132615. var result = [];
  132616. var featureCollection = xml.documentElement;
  132617. var featureMembers = featureCollection.getElementsByTagNameNS(gmlNamespace, 'featureMember');
  132618. for (var featureIndex = 0; featureIndex < featureMembers.length; ++featureIndex) {
  132619. var featureMember = featureMembers[featureIndex];
  132620. var properties = {};
  132621. getGmlPropertiesRecursively(featureMember, properties);
  132622. result.push(imageryLayerFeatureInfoFromDataAndProperties(featureMember, properties));
  132623. }
  132624. return result;
  132625. }
  132626. // msGmlToFeatureInfo is similar to gmlToFeatureInfo, but assumes different XML structure
  132627. // eg. <msGMLOutput> <ABC_layer> <ABC_feature> <foo>bar</foo> ... </ABC_feature> </ABC_layer> </msGMLOutput>
  132628. function msGmlToFeatureInfo(xml) {
  132629. var result = [];
  132630. // Find the first child. Except for IE, this would work:
  132631. // var layer = xml.documentElement.children[0];
  132632. var layer;
  132633. var children = xml.documentElement.childNodes;
  132634. for (var i = 0; i < children.length; i++) {
  132635. if (children[i].nodeType === Node.ELEMENT_NODE) {
  132636. layer = children[i];
  132637. break;
  132638. }
  132639. }
  132640. var featureMembers = layer.childNodes;
  132641. for (var featureIndex = 0; featureIndex < featureMembers.length; ++featureIndex) {
  132642. var featureMember = featureMembers[featureIndex];
  132643. if (featureMember.nodeType === Node.ELEMENT_NODE) {
  132644. var properties = {};
  132645. getGmlPropertiesRecursively(featureMember, properties);
  132646. result.push(imageryLayerFeatureInfoFromDataAndProperties(featureMember, properties));
  132647. }
  132648. }
  132649. return result;
  132650. }
  132651. function getGmlPropertiesRecursively(gmlNode, properties) {
  132652. var isSingleValue = true;
  132653. for (var i = 0; i < gmlNode.childNodes.length; ++i) {
  132654. var child = gmlNode.childNodes[i];
  132655. if (child.nodeType === Node.ELEMENT_NODE) {
  132656. isSingleValue = false;
  132657. }
  132658. if (child.localName === 'Point' || child.localName === 'LineString' || child.localName === 'Polygon' || child.localName === 'boundedBy') {
  132659. continue;
  132660. }
  132661. if (child.hasChildNodes() && getGmlPropertiesRecursively(child, properties)) {
  132662. properties[child.localName] = child.textContent;
  132663. }
  132664. }
  132665. return isSingleValue;
  132666. }
  132667. function imageryLayerFeatureInfoFromDataAndProperties(data, properties) {
  132668. var featureInfo = new ImageryLayerFeatureInfo();
  132669. featureInfo.data = data;
  132670. featureInfo.properties = properties;
  132671. featureInfo.configureNameFromProperties(properties);
  132672. featureInfo.configureDescriptionFromProperties(properties);
  132673. return featureInfo;
  132674. }
  132675. function unknownXmlToFeatureInfo(xml) {
  132676. var xmlText = new XMLSerializer().serializeToString(xml);
  132677. var element = document.createElement('div');
  132678. var pre = document.createElement('pre');
  132679. pre.textContent = xmlText;
  132680. element.appendChild(pre);
  132681. var featureInfo = new ImageryLayerFeatureInfo();
  132682. featureInfo.data = xml;
  132683. featureInfo.description = element.innerHTML;
  132684. return [featureInfo];
  132685. }
  132686. var emptyBodyRegex= /<body>\s*<\/body>/im;
  132687. var wmsServiceExceptionReportRegex = /<ServiceExceptionReport([\s\S]*)<\/ServiceExceptionReport>/im;
  132688. var titleRegex = /<title>([\s\S]*)<\/title>/im;
  132689. function textToFeatureInfo(text) {
  132690. // If the text is HTML and it has an empty body tag, assume it means no features were found.
  132691. if (emptyBodyRegex.test(text)) {
  132692. return undefined;
  132693. }
  132694. // If this is a WMS exception report, treat it as "no features found" rather than showing
  132695. // bogus feature info.
  132696. if (wmsServiceExceptionReportRegex.test(text)) {
  132697. return undefined;
  132698. }
  132699. // If the text has a <title> element, use it as the name.
  132700. var name;
  132701. var title = titleRegex.exec(text);
  132702. if (title && title.length > 1) {
  132703. name = title[1];
  132704. }
  132705. var featureInfo = new ImageryLayerFeatureInfo();
  132706. featureInfo.name = name;
  132707. featureInfo.description = text;
  132708. featureInfo.data = text;
  132709. return [featureInfo];
  132710. }
  132711. return GetFeatureInfoFormat;
  132712. });
  132713. //This file is automatically rebuilt by the Cesium build process.
  132714. /*global define*/
  132715. define('Shaders/GlobeFS',[],function() {
  132716. 'use strict';
  132717. return "uniform vec4 u_initialColor;\n\
  132718. #if TEXTURE_UNITS > 0\n\
  132719. uniform sampler2D u_dayTextures[TEXTURE_UNITS];\n\
  132720. uniform vec4 u_dayTextureTranslationAndScale[TEXTURE_UNITS];\n\
  132721. uniform bool u_dayTextureUseWebMercatorT[TEXTURE_UNITS];\n\
  132722. #ifdef APPLY_ALPHA\n\
  132723. uniform float u_dayTextureAlpha[TEXTURE_UNITS];\n\
  132724. #endif\n\
  132725. #ifdef APPLY_BRIGHTNESS\n\
  132726. uniform float u_dayTextureBrightness[TEXTURE_UNITS];\n\
  132727. #endif\n\
  132728. #ifdef APPLY_CONTRAST\n\
  132729. uniform float u_dayTextureContrast[TEXTURE_UNITS];\n\
  132730. #endif\n\
  132731. #ifdef APPLY_HUE\n\
  132732. uniform float u_dayTextureHue[TEXTURE_UNITS];\n\
  132733. #endif\n\
  132734. #ifdef APPLY_SATURATION\n\
  132735. uniform float u_dayTextureSaturation[TEXTURE_UNITS];\n\
  132736. #endif\n\
  132737. #ifdef APPLY_GAMMA\n\
  132738. uniform float u_dayTextureOneOverGamma[TEXTURE_UNITS];\n\
  132739. #endif\n\
  132740. uniform vec4 u_dayTextureTexCoordsRectangle[TEXTURE_UNITS];\n\
  132741. #endif\n\
  132742. #ifdef SHOW_REFLECTIVE_OCEAN\n\
  132743. uniform sampler2D u_waterMask;\n\
  132744. uniform vec4 u_waterMaskTranslationAndScale;\n\
  132745. uniform float u_zoomedOutOceanSpecularIntensity;\n\
  132746. #endif\n\
  132747. #ifdef SHOW_OCEAN_WAVES\n\
  132748. uniform sampler2D u_oceanNormalMap;\n\
  132749. #endif\n\
  132750. #ifdef ENABLE_DAYNIGHT_SHADING\n\
  132751. uniform vec2 u_lightingFadeDistance;\n\
  132752. #endif\n\
  132753. varying vec3 v_positionMC;\n\
  132754. varying vec3 v_positionEC;\n\
  132755. varying vec3 v_textureCoordinates;\n\
  132756. varying vec3 v_normalMC;\n\
  132757. varying vec3 v_normalEC;\n\
  132758. #ifdef FOG\n\
  132759. varying float v_distance;\n\
  132760. varying vec3 v_rayleighColor;\n\
  132761. varying vec3 v_mieColor;\n\
  132762. #endif\n\
  132763. vec4 sampleAndBlend(\n\
  132764. vec4 previousColor,\n\
  132765. sampler2D texture,\n\
  132766. vec2 tileTextureCoordinates,\n\
  132767. vec4 textureCoordinateRectangle,\n\
  132768. vec4 textureCoordinateTranslationAndScale,\n\
  132769. float textureAlpha,\n\
  132770. float textureBrightness,\n\
  132771. float textureContrast,\n\
  132772. float textureHue,\n\
  132773. float textureSaturation,\n\
  132774. float textureOneOverGamma)\n\
  132775. {\n\
  132776. vec2 alphaMultiplier = step(textureCoordinateRectangle.st, tileTextureCoordinates);\n\
  132777. textureAlpha = textureAlpha * alphaMultiplier.x * alphaMultiplier.y;\n\
  132778. alphaMultiplier = step(vec2(0.0), textureCoordinateRectangle.pq - tileTextureCoordinates);\n\
  132779. textureAlpha = textureAlpha * alphaMultiplier.x * alphaMultiplier.y;\n\
  132780. vec2 translation = textureCoordinateTranslationAndScale.xy;\n\
  132781. vec2 scale = textureCoordinateTranslationAndScale.zw;\n\
  132782. vec2 textureCoordinates = tileTextureCoordinates * scale + translation;\n\
  132783. vec4 value = texture2D(texture, textureCoordinates);\n\
  132784. vec3 color = value.rgb;\n\
  132785. float alpha = value.a;\n\
  132786. #ifdef APPLY_BRIGHTNESS\n\
  132787. color = mix(vec3(0.0), color, textureBrightness);\n\
  132788. #endif\n\
  132789. #ifdef APPLY_CONTRAST\n\
  132790. color = mix(vec3(0.5), color, textureContrast);\n\
  132791. #endif\n\
  132792. #ifdef APPLY_HUE\n\
  132793. color = czm_hue(color, textureHue);\n\
  132794. #endif\n\
  132795. #ifdef APPLY_SATURATION\n\
  132796. color = czm_saturation(color, textureSaturation);\n\
  132797. #endif\n\
  132798. #ifdef APPLY_GAMMA\n\
  132799. color = pow(color, vec3(textureOneOverGamma));\n\
  132800. #endif\n\
  132801. float sourceAlpha = alpha * textureAlpha;\n\
  132802. float outAlpha = mix(previousColor.a, 1.0, sourceAlpha);\n\
  132803. vec3 outColor = mix(previousColor.rgb * previousColor.a, color, sourceAlpha) / outAlpha;\n\
  132804. return vec4(outColor, outAlpha);\n\
  132805. }\n\
  132806. vec4 computeDayColor(vec4 initialColor, vec3 textureCoordinates);\n\
  132807. vec4 computeWaterColor(vec3 positionEyeCoordinates, vec2 textureCoordinates, mat3 enuToEye, vec4 imageryColor, float specularMapValue);\n\
  132808. void main()\n\
  132809. {\n\
  132810. vec4 color = computeDayColor(u_initialColor, clamp(v_textureCoordinates, 0.0, 1.0));\n\
  132811. #ifdef SHOW_TILE_BOUNDARIES\n\
  132812. if (v_textureCoordinates.x < (1.0/256.0) || v_textureCoordinates.x > (255.0/256.0) ||\n\
  132813. v_textureCoordinates.y < (1.0/256.0) || v_textureCoordinates.y > (255.0/256.0))\n\
  132814. {\n\
  132815. color = vec4(1.0, 0.0, 0.0, 1.0);\n\
  132816. }\n\
  132817. #endif\n\
  132818. #if defined(SHOW_REFLECTIVE_OCEAN) || defined(ENABLE_DAYNIGHT_SHADING)\n\
  132819. vec3 normalMC = czm_geodeticSurfaceNormal(v_positionMC, vec3(0.0), vec3(1.0));\n\
  132820. vec3 normalEC = czm_normal3D * normalMC;\n\
  132821. #endif\n\
  132822. #ifdef SHOW_REFLECTIVE_OCEAN\n\
  132823. vec2 waterMaskTranslation = u_waterMaskTranslationAndScale.xy;\n\
  132824. vec2 waterMaskScale = u_waterMaskTranslationAndScale.zw;\n\
  132825. vec2 waterMaskTextureCoordinates = v_textureCoordinates.xy * waterMaskScale + waterMaskTranslation;\n\
  132826. float mask = texture2D(u_waterMask, waterMaskTextureCoordinates).r;\n\
  132827. if (mask > 0.0)\n\
  132828. {\n\
  132829. mat3 enuToEye = czm_eastNorthUpToEyeCoordinates(v_positionMC, normalEC);\n\
  132830. vec2 ellipsoidTextureCoordinates = czm_ellipsoidWgs84TextureCoordinates(normalMC);\n\
  132831. vec2 ellipsoidFlippedTextureCoordinates = czm_ellipsoidWgs84TextureCoordinates(normalMC.zyx);\n\
  132832. vec2 textureCoordinates = mix(ellipsoidTextureCoordinates, ellipsoidFlippedTextureCoordinates, czm_morphTime * smoothstep(0.9, 0.95, normalMC.z));\n\
  132833. color = computeWaterColor(v_positionEC, textureCoordinates, enuToEye, color, mask);\n\
  132834. }\n\
  132835. #endif\n\
  132836. #ifdef ENABLE_VERTEX_LIGHTING\n\
  132837. float diffuseIntensity = clamp(czm_getLambertDiffuse(czm_sunDirectionEC, normalize(v_normalEC)) * 0.9 + 0.3, 0.0, 1.0);\n\
  132838. vec4 finalColor = vec4(color.rgb * diffuseIntensity, color.a);\n\
  132839. #elif defined(ENABLE_DAYNIGHT_SHADING)\n\
  132840. float diffuseIntensity = clamp(czm_getLambertDiffuse(czm_sunDirectionEC, normalEC) * 5.0 + 0.3, 0.0, 1.0);\n\
  132841. float cameraDist = length(czm_view[3]);\n\
  132842. float fadeOutDist = u_lightingFadeDistance.x;\n\
  132843. float fadeInDist = u_lightingFadeDistance.y;\n\
  132844. float t = clamp((cameraDist - fadeOutDist) / (fadeInDist - fadeOutDist), 0.0, 1.0);\n\
  132845. diffuseIntensity = mix(1.0, diffuseIntensity, t);\n\
  132846. vec4 finalColor = vec4(color.rgb * diffuseIntensity, color.a);\n\
  132847. #else\n\
  132848. vec4 finalColor = color;\n\
  132849. #endif\n\
  132850. #ifdef FOG\n\
  132851. const float fExposure = 2.0;\n\
  132852. vec3 fogColor = v_mieColor + finalColor.rgb * v_rayleighColor;\n\
  132853. fogColor = vec3(1.0) - exp(-fExposure * fogColor);\n\
  132854. gl_FragColor = vec4(czm_fog(v_distance, finalColor.rgb, fogColor), finalColor.a);\n\
  132855. #else\n\
  132856. gl_FragColor = finalColor;\n\
  132857. #endif\n\
  132858. }\n\
  132859. #ifdef SHOW_REFLECTIVE_OCEAN\n\
  132860. float waveFade(float edge0, float edge1, float x)\n\
  132861. {\n\
  132862. float y = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n\
  132863. return pow(1.0 - y, 5.0);\n\
  132864. }\n\
  132865. float linearFade(float edge0, float edge1, float x)\n\
  132866. {\n\
  132867. return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n\
  132868. }\n\
  132869. const float oceanFrequencyLowAltitude = 825000.0;\n\
  132870. const float oceanAnimationSpeedLowAltitude = 0.004;\n\
  132871. const float oceanOneOverAmplitudeLowAltitude = 1.0 / 2.0;\n\
  132872. const float oceanSpecularIntensity = 0.5;\n\
  132873. const float oceanFrequencyHighAltitude = 125000.0;\n\
  132874. const float oceanAnimationSpeedHighAltitude = 0.008;\n\
  132875. const float oceanOneOverAmplitudeHighAltitude = 1.0 / 2.0;\n\
  132876. vec4 computeWaterColor(vec3 positionEyeCoordinates, vec2 textureCoordinates, mat3 enuToEye, vec4 imageryColor, float maskValue)\n\
  132877. {\n\
  132878. vec3 positionToEyeEC = -positionEyeCoordinates;\n\
  132879. float positionToEyeECLength = length(positionToEyeEC);\n\
  132880. vec3 normalizedpositionToEyeEC = normalize(normalize(positionToEyeEC));\n\
  132881. float waveIntensity = waveFade(70000.0, 1000000.0, positionToEyeECLength);\n\
  132882. #ifdef SHOW_OCEAN_WAVES\n\
  132883. float time = czm_frameNumber * oceanAnimationSpeedHighAltitude;\n\
  132884. vec4 noise = czm_getWaterNoise(u_oceanNormalMap, textureCoordinates * oceanFrequencyHighAltitude, time, 0.0);\n\
  132885. vec3 normalTangentSpaceHighAltitude = vec3(noise.xy, noise.z * oceanOneOverAmplitudeHighAltitude);\n\
  132886. time = czm_frameNumber * oceanAnimationSpeedLowAltitude;\n\
  132887. noise = czm_getWaterNoise(u_oceanNormalMap, textureCoordinates * oceanFrequencyLowAltitude, time, 0.0);\n\
  132888. vec3 normalTangentSpaceLowAltitude = vec3(noise.xy, noise.z * oceanOneOverAmplitudeLowAltitude);\n\
  132889. float highAltitudeFade = linearFade(0.0, 60000.0, positionToEyeECLength);\n\
  132890. float lowAltitudeFade = 1.0 - linearFade(20000.0, 60000.0, positionToEyeECLength);\n\
  132891. vec3 normalTangentSpace =\n\
  132892. (highAltitudeFade * normalTangentSpaceHighAltitude) +\n\
  132893. (lowAltitudeFade * normalTangentSpaceLowAltitude);\n\
  132894. normalTangentSpace = normalize(normalTangentSpace);\n\
  132895. normalTangentSpace.xy *= waveIntensity;\n\
  132896. normalTangentSpace = normalize(normalTangentSpace);\n\
  132897. #else\n\
  132898. vec3 normalTangentSpace = vec3(0.0, 0.0, 1.0);\n\
  132899. #endif\n\
  132900. vec3 normalEC = enuToEye * normalTangentSpace;\n\
  132901. const vec3 waveHighlightColor = vec3(0.3, 0.45, 0.6);\n\
  132902. float diffuseIntensity = czm_getLambertDiffuse(czm_sunDirectionEC, normalEC) * maskValue;\n\
  132903. vec3 diffuseHighlight = waveHighlightColor * diffuseIntensity;\n\
  132904. #ifdef SHOW_OCEAN_WAVES\n\
  132905. float tsPerturbationRatio = normalTangentSpace.z;\n\
  132906. vec3 nonDiffuseHighlight = mix(waveHighlightColor * 5.0 * (1.0 - tsPerturbationRatio), vec3(0.0), diffuseIntensity);\n\
  132907. #else\n\
  132908. vec3 nonDiffuseHighlight = vec3(0.0);\n\
  132909. #endif\n\
  132910. float specularIntensity = czm_getSpecular(czm_sunDirectionEC, normalizedpositionToEyeEC, normalEC, 10.0) + 0.25 * czm_getSpecular(czm_moonDirectionEC, normalizedpositionToEyeEC, normalEC, 10.0);\n\
  132911. float surfaceReflectance = mix(0.0, mix(u_zoomedOutOceanSpecularIntensity, oceanSpecularIntensity, waveIntensity), maskValue);\n\
  132912. float specular = specularIntensity * surfaceReflectance;\n\
  132913. return vec4(imageryColor.rgb + diffuseHighlight + nonDiffuseHighlight + specular, imageryColor.a);\n\
  132914. }\n\
  132915. #endif // #ifdef SHOW_REFLECTIVE_OCEAN\n\
  132916. ";
  132917. });
  132918. //This file is automatically rebuilt by the Cesium build process.
  132919. /*global define*/
  132920. define('Shaders/GlobeVS',[],function() {
  132921. 'use strict';
  132922. return "#ifdef QUANTIZATION_BITS12\n\
  132923. attribute vec4 compressed0;\n\
  132924. attribute float compressed1;\n\
  132925. #else\n\
  132926. attribute vec4 position3DAndHeight;\n\
  132927. attribute vec4 textureCoordAndEncodedNormals;\n\
  132928. #endif\n\
  132929. uniform vec3 u_center3D;\n\
  132930. uniform mat4 u_modifiedModelView;\n\
  132931. uniform mat4 u_modifiedModelViewProjection;\n\
  132932. uniform vec4 u_tileRectangle;\n\
  132933. uniform vec2 u_southAndNorthLatitude;\n\
  132934. uniform vec2 u_southMercatorYAndOneOverHeight;\n\
  132935. varying vec3 v_positionMC;\n\
  132936. varying vec3 v_positionEC;\n\
  132937. varying vec3 v_textureCoordinates;\n\
  132938. varying vec3 v_normalMC;\n\
  132939. varying vec3 v_normalEC;\n\
  132940. #ifdef FOG\n\
  132941. varying float v_distance;\n\
  132942. varying vec3 v_mieColor;\n\
  132943. varying vec3 v_rayleighColor;\n\
  132944. #endif\n\
  132945. vec4 getPosition(vec3 position, float height, vec2 textureCoordinates);\n\
  132946. float get2DYPositionFraction(vec2 textureCoordinates);\n\
  132947. vec4 getPosition3DMode(vec3 position, float height, vec2 textureCoordinates)\n\
  132948. {\n\
  132949. return u_modifiedModelViewProjection * vec4(position, 1.0);\n\
  132950. }\n\
  132951. float get2DMercatorYPositionFraction(vec2 textureCoordinates)\n\
  132952. {\n\
  132953. const float maxTileWidth = 0.003068;\n\
  132954. float positionFraction = textureCoordinates.y;\n\
  132955. float southLatitude = u_southAndNorthLatitude.x;\n\
  132956. float northLatitude = u_southAndNorthLatitude.y;\n\
  132957. if (northLatitude - southLatitude > maxTileWidth)\n\
  132958. {\n\
  132959. float southMercatorY = u_southMercatorYAndOneOverHeight.x;\n\
  132960. float oneOverMercatorHeight = u_southMercatorYAndOneOverHeight.y;\n\
  132961. float currentLatitude = mix(southLatitude, northLatitude, textureCoordinates.y);\n\
  132962. currentLatitude = clamp(currentLatitude, -czm_webMercatorMaxLatitude, czm_webMercatorMaxLatitude);\n\
  132963. positionFraction = czm_latitudeToWebMercatorFraction(currentLatitude, southMercatorY, oneOverMercatorHeight);\n\
  132964. }\n\
  132965. return positionFraction;\n\
  132966. }\n\
  132967. float get2DGeographicYPositionFraction(vec2 textureCoordinates)\n\
  132968. {\n\
  132969. return textureCoordinates.y;\n\
  132970. }\n\
  132971. vec4 getPositionPlanarEarth(vec3 position, float height, vec2 textureCoordinates)\n\
  132972. {\n\
  132973. float yPositionFraction = get2DYPositionFraction(textureCoordinates);\n\
  132974. vec4 rtcPosition2D = vec4(height, mix(u_tileRectangle.st, u_tileRectangle.pq, vec2(textureCoordinates.x, yPositionFraction)), 1.0);\n\
  132975. return u_modifiedModelViewProjection * rtcPosition2D;\n\
  132976. }\n\
  132977. vec4 getPosition2DMode(vec3 position, float height, vec2 textureCoordinates)\n\
  132978. {\n\
  132979. return getPositionPlanarEarth(position, 0.0, textureCoordinates);\n\
  132980. }\n\
  132981. vec4 getPositionColumbusViewMode(vec3 position, float height, vec2 textureCoordinates)\n\
  132982. {\n\
  132983. return getPositionPlanarEarth(position, height, textureCoordinates);\n\
  132984. }\n\
  132985. vec4 getPositionMorphingMode(vec3 position, float height, vec2 textureCoordinates)\n\
  132986. {\n\
  132987. vec3 position3DWC = position + u_center3D;\n\
  132988. float yPositionFraction = get2DYPositionFraction(textureCoordinates);\n\
  132989. vec4 position2DWC = vec4(height, mix(u_tileRectangle.st, u_tileRectangle.pq, vec2(textureCoordinates.x, yPositionFraction)), 1.0);\n\
  132990. vec4 morphPosition = czm_columbusViewMorph(position2DWC, vec4(position3DWC, 1.0), czm_morphTime);\n\
  132991. return czm_modelViewProjection * morphPosition;\n\
  132992. }\n\
  132993. #ifdef QUANTIZATION_BITS12\n\
  132994. uniform vec2 u_minMaxHeight;\n\
  132995. uniform mat4 u_scaleAndBias;\n\
  132996. #endif\n\
  132997. void main()\n\
  132998. {\n\
  132999. #ifdef QUANTIZATION_BITS12\n\
  133000. vec2 xy = czm_decompressTextureCoordinates(compressed0.x);\n\
  133001. vec2 zh = czm_decompressTextureCoordinates(compressed0.y);\n\
  133002. vec3 position = vec3(xy, zh.x);\n\
  133003. float height = zh.y;\n\
  133004. vec2 textureCoordinates = czm_decompressTextureCoordinates(compressed0.z);\n\
  133005. height = height * (u_minMaxHeight.y - u_minMaxHeight.x) + u_minMaxHeight.x;\n\
  133006. position = (u_scaleAndBias * vec4(position, 1.0)).xyz;\n\
  133007. #if (defined(ENABLE_VERTEX_LIGHTING) || defined(GENERATE_POSITION_AND_NORMAL)) && defined(INCLUDE_WEB_MERCATOR_Y)\n\
  133008. float webMercatorT = czm_decompressTextureCoordinates(compressed0.w).x;\n\
  133009. float encodedNormal = compressed1;\n\
  133010. #elif defined(INCLUDE_WEB_MERCATOR_Y)\n\
  133011. float webMercatorT = czm_decompressTextureCoordinates(compressed0.w).x;\n\
  133012. float encodedNormal = 0.0;\n\
  133013. #elif defined(ENABLE_VERTEX_LIGHTING) || defined(GENERATE_POSITION_AND_NORMAL)\n\
  133014. float webMercatorT = textureCoordinates.y;\n\
  133015. float encodedNormal = compressed0.w;\n\
  133016. #else\n\
  133017. float webMercatorT = textureCoordinates.y;\n\
  133018. float encodedNormal = 0.0;\n\
  133019. #endif\n\
  133020. #else\n\
  133021. vec3 position = position3DAndHeight.xyz;\n\
  133022. float height = position3DAndHeight.w;\n\
  133023. vec2 textureCoordinates = textureCoordAndEncodedNormals.xy;\n\
  133024. #if (defined(ENABLE_VERTEX_LIGHTING) || defined(GENERATE_POSITION_AND_NORMAL)) && defined(INCLUDE_WEB_MERCATOR_Y)\n\
  133025. float webMercatorT = textureCoordAndEncodedNormals.z;\n\
  133026. float encodedNormal = textureCoordAndEncodedNormals.w;\n\
  133027. #elif defined(ENABLE_VERTEX_LIGHTING) || defined(GENERATE_POSITION_AND_NORMAL)\n\
  133028. float webMercatorT = textureCoordinates.y;\n\
  133029. float encodedNormal = textureCoordAndEncodedNormals.z;\n\
  133030. #elif defined(INCLUDE_WEB_MERCATOR_Y)\n\
  133031. float webMercatorT = textureCoordAndEncodedNormals.z;\n\
  133032. float encodedNormal = 0.0;\n\
  133033. #else\n\
  133034. float webMercatorT = textureCoordinates.y;\n\
  133035. float encodedNormal = 0.0;\n\
  133036. #endif\n\
  133037. #endif\n\
  133038. vec3 position3DWC = position + u_center3D;\n\
  133039. gl_Position = getPosition(position, height, textureCoordinates);\n\
  133040. v_textureCoordinates = vec3(textureCoordinates, webMercatorT);\n\
  133041. #if defined(ENABLE_VERTEX_LIGHTING) || defined(GENERATE_POSITION_AND_NORMAL)\n\
  133042. v_positionEC = (u_modifiedModelView * vec4(position, 1.0)).xyz;\n\
  133043. v_positionMC = position3DWC;\n\
  133044. v_normalMC = czm_octDecode(encodedNormal);\n\
  133045. v_normalEC = czm_normal3D * v_normalMC;\n\
  133046. #elif defined(SHOW_REFLECTIVE_OCEAN) || defined(ENABLE_DAYNIGHT_SHADING) || defined(GENERATE_POSITION)\n\
  133047. v_positionEC = (u_modifiedModelView * vec4(position, 1.0)).xyz;\n\
  133048. v_positionMC = position3DWC;\n\
  133049. #endif\n\
  133050. #ifdef FOG\n\
  133051. AtmosphereColor atmosColor = computeGroundAtmosphereFromSpace(position3DWC);\n\
  133052. v_mieColor = atmosColor.mie;\n\
  133053. v_rayleighColor = atmosColor.rayleigh;\n\
  133054. v_distance = length((czm_modelView3D * vec4(position3DWC, 1.0)).xyz);\n\
  133055. #endif\n\
  133056. }\n\
  133057. ";
  133058. });
  133059. //This file is automatically rebuilt by the Cesium build process.
  133060. /*global define*/
  133061. define('Shaders/GroundAtmosphere',[],function() {
  133062. 'use strict';
  133063. return "const float fInnerRadius = 6378137.0;\n\
  133064. const float fOuterRadius = 6378137.0 * 1.025;\n\
  133065. const float fOuterRadius2 = fOuterRadius * fOuterRadius;\n\
  133066. const float Kr = 0.0025;\n\
  133067. const float Km = 0.0015;\n\
  133068. const float ESun = 15.0;\n\
  133069. const float fKrESun = Kr * ESun;\n\
  133070. const float fKmESun = Km * ESun;\n\
  133071. const float fKr4PI = Kr * 4.0 * czm_pi;\n\
  133072. const float fKm4PI = Km * 4.0 * czm_pi;\n\
  133073. const float fScale = 1.0 / (fOuterRadius - fInnerRadius);\n\
  133074. const float fScaleDepth = 0.25;\n\
  133075. const float fScaleOverScaleDepth = fScale / fScaleDepth;\n\
  133076. struct AtmosphereColor\n\
  133077. {\n\
  133078. vec3 mie;\n\
  133079. vec3 rayleigh;\n\
  133080. };\n\
  133081. const int nSamples = 2;\n\
  133082. const float fSamples = 2.0;\n\
  133083. float scale(float fCos)\n\
  133084. {\n\
  133085. float x = 1.0 - fCos;\n\
  133086. return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));\n\
  133087. }\n\
  133088. AtmosphereColor computeGroundAtmosphereFromSpace(vec3 v3Pos)\n\
  133089. {\n\
  133090. vec3 v3InvWavelength = vec3(1.0 / pow(0.650, 4.0), 1.0 / pow(0.570, 4.0), 1.0 / pow(0.475, 4.0));\n\
  133091. vec3 v3Ray = v3Pos - czm_viewerPositionWC;\n\
  133092. float fFar = length(v3Ray);\n\
  133093. v3Ray /= fFar;\n\
  133094. float fCameraHeight = length(czm_viewerPositionWC);\n\
  133095. float fCameraHeight2 = fCameraHeight * fCameraHeight;\n\
  133096. float B = 2.0 * length(czm_viewerPositionWC) * dot(normalize(czm_viewerPositionWC), v3Ray);\n\
  133097. float C = fCameraHeight2 - fOuterRadius2;\n\
  133098. float fDet = max(0.0, B*B - 4.0 * C);\n\
  133099. float fNear = 0.5 * (-B - sqrt(fDet));\n\
  133100. vec3 v3Start = czm_viewerPositionWC + v3Ray * fNear;\n\
  133101. fFar -= fNear;\n\
  133102. float fDepth = exp((fInnerRadius - fOuterRadius) / fScaleDepth);\n\
  133103. float fLightAngle = 1.0;\n\
  133104. float fCameraAngle = dot(-v3Ray, v3Pos) / length(v3Pos);\n\
  133105. float fCameraScale = scale(fCameraAngle);\n\
  133106. float fLightScale = scale(fLightAngle);\n\
  133107. float fCameraOffset = fDepth*fCameraScale;\n\
  133108. float fTemp = (fLightScale + fCameraScale);\n\
  133109. float fSampleLength = fFar / fSamples;\n\
  133110. float fScaledLength = fSampleLength * fScale;\n\
  133111. vec3 v3SampleRay = v3Ray * fSampleLength;\n\
  133112. vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;\n\
  133113. vec3 v3FrontColor = vec3(0.0);\n\
  133114. vec3 v3Attenuate = vec3(0.0);\n\
  133115. for(int i=0; i<nSamples; i++)\n\
  133116. {\n\
  133117. float fHeight = length(v3SamplePoint);\n\
  133118. float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));\n\
  133119. float fScatter = fDepth*fTemp - fCameraOffset;\n\
  133120. v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));\n\
  133121. v3FrontColor += v3Attenuate * (fDepth * fScaledLength);\n\
  133122. v3SamplePoint += v3SampleRay;\n\
  133123. }\n\
  133124. AtmosphereColor color;\n\
  133125. color.mie = v3FrontColor * (v3InvWavelength * fKrESun + fKmESun);\n\
  133126. color.rayleigh = v3Attenuate;\n\
  133127. return color;\n\
  133128. }\n\
  133129. ";
  133130. });
  133131. /*global define*/
  133132. define('Scene/GlobeSurfaceShaderSet',[
  133133. '../Core/defined',
  133134. '../Core/destroyObject',
  133135. '../Core/TerrainQuantization',
  133136. '../Renderer/ShaderProgram',
  133137. '../Scene/SceneMode'
  133138. ], function(
  133139. defined,
  133140. destroyObject,
  133141. TerrainQuantization,
  133142. ShaderProgram,
  133143. SceneMode) {
  133144. 'use strict';
  133145. function GlobeSurfaceShader(numberOfDayTextures, flags, shaderProgram) {
  133146. this.numberOfDayTextures = numberOfDayTextures;
  133147. this.flags = flags;
  133148. this.shaderProgram = shaderProgram;
  133149. }
  133150. /**
  133151. * Manages the shaders used to shade the surface of a {@link Globe}.
  133152. *
  133153. * @alias GlobeSurfaceShaderSet
  133154. * @private
  133155. */
  133156. function GlobeSurfaceShaderSet() {
  133157. this.baseVertexShaderSource = undefined;
  133158. this.baseFragmentShaderSource = undefined;
  133159. this._shadersByTexturesFlags = [];
  133160. this._pickShaderPrograms = [];
  133161. }
  133162. function getPositionMode(sceneMode) {
  133163. var getPosition3DMode = 'vec4 getPosition(vec3 position, float height, vec2 textureCoordinates) { return getPosition3DMode(position, height, textureCoordinates); }';
  133164. var getPositionColumbusViewAnd2DMode = 'vec4 getPosition(vec3 position, float height, vec2 textureCoordinates) { return getPositionColumbusViewMode(position, height, textureCoordinates); }';
  133165. var getPositionMorphingMode = 'vec4 getPosition(vec3 position, float height, vec2 textureCoordinates) { return getPositionMorphingMode(position, height, textureCoordinates); }';
  133166. var positionMode;
  133167. switch (sceneMode) {
  133168. case SceneMode.SCENE3D:
  133169. positionMode = getPosition3DMode;
  133170. break;
  133171. case SceneMode.SCENE2D:
  133172. case SceneMode.COLUMBUS_VIEW:
  133173. positionMode = getPositionColumbusViewAnd2DMode;
  133174. break;
  133175. case SceneMode.MORPHING:
  133176. positionMode = getPositionMorphingMode;
  133177. break;
  133178. }
  133179. return positionMode;
  133180. }
  133181. function get2DYPositionFraction(useWebMercatorProjection) {
  133182. var get2DYPositionFractionGeographicProjection = 'float get2DYPositionFraction(vec2 textureCoordinates) { return get2DGeographicYPositionFraction(textureCoordinates); }';
  133183. var get2DYPositionFractionMercatorProjection = 'float get2DYPositionFraction(vec2 textureCoordinates) { return get2DMercatorYPositionFraction(textureCoordinates); }';
  133184. return useWebMercatorProjection ? get2DYPositionFractionMercatorProjection : get2DYPositionFractionGeographicProjection;
  133185. }
  133186. GlobeSurfaceShaderSet.prototype.getShaderProgram = function(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, showReflectiveOcean, showOceanWaves, enableLighting, hasVertexNormals, useWebMercatorProjection, enableFog) {
  133187. var quantization = 0;
  133188. var quantizationDefine = '';
  133189. var terrainEncoding = surfaceTile.pickTerrain.mesh.encoding;
  133190. var quantizationMode = terrainEncoding.quantization;
  133191. if (quantizationMode === TerrainQuantization.BITS12) {
  133192. quantization = 1;
  133193. quantizationDefine = 'QUANTIZATION_BITS12';
  133194. }
  133195. var sceneMode = frameState.mode;
  133196. var flags = sceneMode |
  133197. (applyBrightness << 2) |
  133198. (applyContrast << 3) |
  133199. (applyHue << 4) |
  133200. (applySaturation << 5) |
  133201. (applyGamma << 6) |
  133202. (applyAlpha << 7) |
  133203. (showReflectiveOcean << 8) |
  133204. (showOceanWaves << 9) |
  133205. (enableLighting << 10) |
  133206. (hasVertexNormals << 11) |
  133207. (useWebMercatorProjection << 12) |
  133208. (enableFog << 13) |
  133209. (quantization << 14);
  133210. var surfaceShader = surfaceTile.surfaceShader;
  133211. if (defined(surfaceShader) &&
  133212. surfaceShader.numberOfDayTextures === numberOfDayTextures &&
  133213. surfaceShader.flags === flags) {
  133214. return surfaceShader.shaderProgram;
  133215. }
  133216. // New tile, or tile changed number of textures or flags.
  133217. var shadersByFlags = this._shadersByTexturesFlags[numberOfDayTextures];
  133218. if (!defined(shadersByFlags)) {
  133219. shadersByFlags = this._shadersByTexturesFlags[numberOfDayTextures] = [];
  133220. }
  133221. surfaceShader = shadersByFlags[flags];
  133222. if (!defined(surfaceShader)) {
  133223. // Cache miss - we've never seen this combination of numberOfDayTextures and flags before.
  133224. var vs = this.baseVertexShaderSource.clone();
  133225. var fs = this.baseFragmentShaderSource.clone();
  133226. vs.defines.push(quantizationDefine);
  133227. fs.defines.push('TEXTURE_UNITS ' + numberOfDayTextures);
  133228. if (applyBrightness) {
  133229. fs.defines.push('APPLY_BRIGHTNESS');
  133230. }
  133231. if (applyContrast) {
  133232. fs.defines.push('APPLY_CONTRAST');
  133233. }
  133234. if (applyHue) {
  133235. fs.defines.push('APPLY_HUE');
  133236. }
  133237. if (applySaturation) {
  133238. fs.defines.push('APPLY_SATURATION');
  133239. }
  133240. if (applyGamma) {
  133241. fs.defines.push('APPLY_GAMMA');
  133242. }
  133243. if (applyAlpha) {
  133244. fs.defines.push('APPLY_ALPHA');
  133245. }
  133246. if (showReflectiveOcean) {
  133247. fs.defines.push('SHOW_REFLECTIVE_OCEAN');
  133248. vs.defines.push('SHOW_REFLECTIVE_OCEAN');
  133249. }
  133250. if (showOceanWaves) {
  133251. fs.defines.push('SHOW_OCEAN_WAVES');
  133252. }
  133253. if (enableLighting) {
  133254. if (hasVertexNormals) {
  133255. vs.defines.push('ENABLE_VERTEX_LIGHTING');
  133256. fs.defines.push('ENABLE_VERTEX_LIGHTING');
  133257. } else {
  133258. vs.defines.push('ENABLE_DAYNIGHT_SHADING');
  133259. fs.defines.push('ENABLE_DAYNIGHT_SHADING');
  133260. }
  133261. }
  133262. vs.defines.push('INCLUDE_WEB_MERCATOR_Y');
  133263. fs.defines.push('INCLUDE_WEB_MERCATOR_Y');
  133264. if (enableFog) {
  133265. vs.defines.push('FOG');
  133266. fs.defines.push('FOG');
  133267. }
  133268. var computeDayColor = '\
  133269. vec4 computeDayColor(vec4 initialColor, vec3 textureCoordinates)\n\
  133270. {\n\
  133271. vec4 color = initialColor;\n';
  133272. for (var i = 0; i < numberOfDayTextures; ++i) {
  133273. computeDayColor += '\
  133274. color = sampleAndBlend(\n\
  133275. color,\n\
  133276. u_dayTextures[' + i + '],\n\
  133277. u_dayTextureUseWebMercatorT[' + i + '] ? textureCoordinates.xz : textureCoordinates.xy,\n\
  133278. u_dayTextureTexCoordsRectangle[' + i + '],\n\
  133279. u_dayTextureTranslationAndScale[' + i + '],\n\
  133280. ' + (applyAlpha ? 'u_dayTextureAlpha[' + i + ']' : '1.0') + ',\n\
  133281. ' + (applyBrightness ? 'u_dayTextureBrightness[' + i + ']' : '0.0') + ',\n\
  133282. ' + (applyContrast ? 'u_dayTextureContrast[' + i + ']' : '0.0') + ',\n\
  133283. ' + (applyHue ? 'u_dayTextureHue[' + i + ']' : '0.0') + ',\n\
  133284. ' + (applySaturation ? 'u_dayTextureSaturation[' + i + ']' : '0.0') + ',\n\
  133285. ' + (applyGamma ? 'u_dayTextureOneOverGamma[' + i + ']' : '0.0') + '\n\
  133286. );\n';
  133287. }
  133288. computeDayColor += '\
  133289. return color;\n\
  133290. }';
  133291. fs.sources.push(computeDayColor);
  133292. vs.sources.push(getPositionMode(sceneMode));
  133293. vs.sources.push(get2DYPositionFraction(useWebMercatorProjection));
  133294. var shader = ShaderProgram.fromCache({
  133295. context : frameState.context,
  133296. vertexShaderSource : vs,
  133297. fragmentShaderSource : fs,
  133298. attributeLocations : terrainEncoding.getAttributeLocations()
  133299. });
  133300. surfaceShader = shadersByFlags[flags] = new GlobeSurfaceShader(numberOfDayTextures, flags, shader);
  133301. }
  133302. surfaceTile.surfaceShader = surfaceShader;
  133303. return surfaceShader.shaderProgram;
  133304. };
  133305. GlobeSurfaceShaderSet.prototype.getPickShaderProgram = function(frameState, surfaceTile, useWebMercatorProjection) {
  133306. var quantization = 0;
  133307. var quantizationDefine = '';
  133308. var terrainEncoding = surfaceTile.pickTerrain.mesh.encoding;
  133309. var quantizationMode = terrainEncoding.quantization;
  133310. if (quantizationMode === TerrainQuantization.BITS12) {
  133311. quantization = 1;
  133312. quantizationDefine = 'QUANTIZATION_BITS12';
  133313. }
  133314. var sceneMode = frameState.mode;
  133315. var flags = sceneMode | (useWebMercatorProjection << 2) | (quantization << 3);
  133316. var pickShader = this._pickShaderPrograms[flags];
  133317. if (!defined(pickShader)) {
  133318. var vs = this.baseVertexShaderSource.clone();
  133319. vs.defines.push(quantizationDefine);
  133320. vs.sources.push(getPositionMode(sceneMode));
  133321. vs.sources.push(get2DYPositionFraction(useWebMercatorProjection));
  133322. // pass through fragment shader. only depth is rendered for the globe on a pick pass
  133323. var fs =
  133324. 'void main()\n' +
  133325. '{\n' +
  133326. ' gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);\n' +
  133327. '}\n';
  133328. pickShader = this._pickShaderPrograms[flags] = ShaderProgram.fromCache({
  133329. context : frameState.context,
  133330. vertexShaderSource : vs,
  133331. fragmentShaderSource : fs,
  133332. attributeLocations : terrainEncoding.getAttributeLocations()
  133333. });
  133334. }
  133335. return pickShader;
  133336. };
  133337. GlobeSurfaceShaderSet.prototype.destroy = function() {
  133338. var flags;
  133339. var shader;
  133340. var shadersByTexturesFlags = this._shadersByTexturesFlags;
  133341. for (var textureCount in shadersByTexturesFlags) {
  133342. if (shadersByTexturesFlags.hasOwnProperty(textureCount)) {
  133343. var shadersByFlags = shadersByTexturesFlags[textureCount];
  133344. if (!defined(shadersByFlags)) {
  133345. continue;
  133346. }
  133347. for (flags in shadersByFlags) {
  133348. if (shadersByFlags.hasOwnProperty(flags)) {
  133349. shader = shadersByFlags[flags];
  133350. if (defined(shader)) {
  133351. shader.shaderProgram.destroy();
  133352. }
  133353. }
  133354. }
  133355. }
  133356. }
  133357. var pickShaderPrograms = this._pickShaderPrograms;
  133358. for (flags in pickShaderPrograms) {
  133359. if (pickShaderPrograms.hasOwnProperty(flags)) {
  133360. shader = pickShaderPrograms[flags];
  133361. shader.destroy();
  133362. }
  133363. }
  133364. return destroyObject(this);
  133365. };
  133366. return GlobeSurfaceShaderSet;
  133367. });
  133368. /*global define*/
  133369. define('Scene/ImageryState',[
  133370. '../Core/freezeObject'
  133371. ], function(
  133372. freezeObject) {
  133373. 'use strict';
  133374. /**
  133375. * @private
  133376. */
  133377. var ImageryState = {
  133378. UNLOADED : 0,
  133379. TRANSITIONING : 1,
  133380. RECEIVED : 2,
  133381. TEXTURE_LOADED : 3,
  133382. READY : 4,
  133383. FAILED : 5,
  133384. INVALID : 6,
  133385. PLACEHOLDER : 7
  133386. };
  133387. return freezeObject(ImageryState);
  133388. });
  133389. /*global define*/
  133390. define('Scene/QuadtreeTileLoadState',[
  133391. '../Core/freezeObject'
  133392. ], function(
  133393. freezeObject) {
  133394. 'use strict';
  133395. /**
  133396. * The state of a {@link QuadtreeTile} in the tile load pipeline.
  133397. * @exports QuadtreeTileLoadState
  133398. * @private
  133399. */
  133400. var QuadtreeTileLoadState = {
  133401. /**
  133402. * The tile is new and loading has not yet begun.
  133403. * @type QuadtreeTileLoadState
  133404. * @constant
  133405. * @default 0
  133406. */
  133407. START : 0,
  133408. /**
  133409. * Loading is in progress.
  133410. * @type QuadtreeTileLoadState
  133411. * @constant
  133412. * @default 1
  133413. */
  133414. LOADING : 1,
  133415. /**
  133416. * Loading is complete.
  133417. * @type QuadtreeTileLoadState
  133418. * @constant
  133419. * @default 2
  133420. */
  133421. DONE : 2,
  133422. /**
  133423. * The tile has failed to load.
  133424. * @type QuadtreeTileLoadState
  133425. * @constant
  133426. * @default 3
  133427. */
  133428. FAILED : 3
  133429. };
  133430. return freezeObject(QuadtreeTileLoadState);
  133431. });
  133432. /*global define*/
  133433. define('Scene/TerrainState',[
  133434. '../Core/freezeObject'
  133435. ], function(
  133436. freezeObject) {
  133437. 'use strict';
  133438. /**
  133439. * @private
  133440. */
  133441. var TerrainState = {
  133442. FAILED : 0,
  133443. UNLOADED : 1,
  133444. RECEIVING : 2,
  133445. RECEIVED : 3,
  133446. TRANSFORMING : 4,
  133447. TRANSFORMED : 5,
  133448. READY : 6
  133449. };
  133450. return freezeObject(TerrainState);
  133451. });
  133452. /*global define*/
  133453. define('Scene/TileBoundingBox',[
  133454. '../Core/Cartesian3',
  133455. '../Core/Cartographic',
  133456. '../Core/defaultValue',
  133457. '../Core/defined',
  133458. '../Core/DeveloperError',
  133459. '../Core/Ellipsoid',
  133460. '../Core/Rectangle',
  133461. './SceneMode'
  133462. ], function(
  133463. Cartesian3,
  133464. Cartographic,
  133465. defaultValue,
  133466. defined,
  133467. DeveloperError,
  133468. Ellipsoid,
  133469. Rectangle,
  133470. SceneMode) {
  133471. 'use strict';
  133472. /**
  133473. * @param {Object} options Object with the following properties:
  133474. * @param {Rectangle} options.rectangle
  133475. * @param {Number} [options.minimumHeight=0.0]
  133476. * @param {Number} [options.maximumHeight=0.0]
  133477. * @param {Ellipsoid} [options.ellipsoid=Cesium.Ellipsoid.WGS84]
  133478. *
  133479. * @private
  133480. */
  133481. var TileBoundingBox = function(options) {
  133482. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  133483. if (!defined(options.rectangle)) {
  133484. throw new DeveloperError('options.url is required.');
  133485. }
  133486. this.rectangle = Rectangle.clone(options.rectangle);
  133487. this.minimumHeight = defaultValue(options.minimumHeight, 0.0);
  133488. this.maximumHeight = defaultValue(options.maximumHeight, 0.0);
  133489. /**
  133490. * The world coordinates of the southwest corner of the tile's rectangle.
  133491. *
  133492. * @type {Cartesian3}
  133493. * @default Cartesian3()
  133494. */
  133495. this.southwestCornerCartesian = new Cartesian3();
  133496. /**
  133497. * The world coordinates of the northeast corner of the tile's rectangle.
  133498. *
  133499. * @type {Cartesian3}
  133500. * @default Cartesian3()
  133501. */
  133502. this.northeastCornerCartesian = new Cartesian3();
  133503. /**
  133504. * A normal that, along with southwestCornerCartesian, defines a plane at the western edge of
  133505. * the tile. Any position above (in the direction of the normal) this plane is outside the tile.
  133506. *
  133507. * @type {Cartesian3}
  133508. * @default Cartesian3()
  133509. */
  133510. this.westNormal = new Cartesian3();
  133511. /**
  133512. * A normal that, along with southwestCornerCartesian, defines a plane at the southern edge of
  133513. * the tile. Any position above (in the direction of the normal) this plane is outside the tile.
  133514. * Because points of constant latitude do not necessary lie in a plane, positions below this
  133515. * plane are not necessarily inside the tile, but they are close.
  133516. *
  133517. * @type {Cartesian3}
  133518. * @default Cartesian3()
  133519. */
  133520. this.southNormal = new Cartesian3();
  133521. /**
  133522. * A normal that, along with northeastCornerCartesian, defines a plane at the eastern edge of
  133523. * the tile. Any position above (in the direction of the normal) this plane is outside the tile.
  133524. *
  133525. * @type {Cartesian3}
  133526. * @default Cartesian3()
  133527. */
  133528. this.eastNormal = new Cartesian3();
  133529. /**
  133530. * A normal that, along with northeastCornerCartesian, defines a plane at the eastern edge of
  133531. * the tile. Any position above (in the direction of the normal) this plane is outside the tile.
  133532. * Because points of constant latitude do not necessary lie in a plane, positions below this
  133533. * plane are not necessarily inside the tile, but they are close.
  133534. *
  133535. * @type {Cartesian3}
  133536. * @default Cartesian3()
  133537. */
  133538. this.northNormal = new Cartesian3();
  133539. var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  133540. computeBox(this, options.rectangle, ellipsoid);
  133541. };
  133542. var cartesian3Scratch = new Cartesian3();
  133543. var cartesian3Scratch2 = new Cartesian3();
  133544. var westernMidpointScratch = new Cartesian3();
  133545. var easternMidpointScratch = new Cartesian3();
  133546. var cartographicScratch = new Cartographic();
  133547. function computeBox(tileBB, rectangle, ellipsoid) {
  133548. ellipsoid.cartographicToCartesian(Rectangle.southwest(rectangle), tileBB.southwestCornerCartesian);
  133549. ellipsoid.cartographicToCartesian(Rectangle.northeast(rectangle), tileBB.northeastCornerCartesian);
  133550. // The middle latitude on the western edge.
  133551. cartographicScratch.longitude = rectangle.west;
  133552. cartographicScratch.latitude = (rectangle.south + rectangle.north) * 0.5;
  133553. cartographicScratch.height = 0.0;
  133554. var westernMidpointCartesian = ellipsoid.cartographicToCartesian(cartographicScratch, westernMidpointScratch);
  133555. // Compute the normal of the plane on the western edge of the tile.
  133556. var westNormal = Cartesian3.cross(westernMidpointCartesian, Cartesian3.UNIT_Z, cartesian3Scratch);
  133557. Cartesian3.normalize(westNormal, tileBB.westNormal);
  133558. // The middle latitude on the eastern edge.
  133559. cartographicScratch.longitude = rectangle.east;
  133560. var easternMidpointCartesian = ellipsoid.cartographicToCartesian(cartographicScratch, easternMidpointScratch);
  133561. // Compute the normal of the plane on the eastern edge of the tile.
  133562. var eastNormal = Cartesian3.cross(Cartesian3.UNIT_Z, easternMidpointCartesian, cartesian3Scratch);
  133563. Cartesian3.normalize(eastNormal, tileBB.eastNormal);
  133564. // Compute the normal of the plane bounding the southern edge of the tile.
  133565. var southeastCornerNormal = ellipsoid.geodeticSurfaceNormalCartographic(Rectangle.southeast(rectangle), cartesian3Scratch2);
  133566. var westVector = Cartesian3.subtract(westernMidpointCartesian, easternMidpointCartesian, cartesian3Scratch);
  133567. var southNormal = Cartesian3.cross(southeastCornerNormal, westVector, cartesian3Scratch2);
  133568. Cartesian3.normalize(southNormal, tileBB.southNormal);
  133569. // Compute the normal of the plane bounding the northern edge of the tile.
  133570. var northwestCornerNormal = ellipsoid.geodeticSurfaceNormalCartographic(Rectangle.northwest(rectangle), cartesian3Scratch2);
  133571. var northNormal = Cartesian3.cross(westVector, northwestCornerNormal, cartesian3Scratch2);
  133572. Cartesian3.normalize(northNormal, tileBB.northNormal);
  133573. }
  133574. var southwestCornerScratch = new Cartesian3();
  133575. var northeastCornerScratch = new Cartesian3();
  133576. var negativeUnitY = new Cartesian3(0.0, -1.0, 0.0);
  133577. var negativeUnitZ = new Cartesian3(0.0, 0.0, -1.0);
  133578. var vectorScratch = new Cartesian3();
  133579. /**
  133580. * Gets the distance from the camera to the closest point on the tile. This is used for level-of-detail selection.
  133581. *
  133582. * @param {FrameState} frameState The state information of the current rendering frame.
  133583. *
  133584. * @returns {Number} The distance from the camera to the closest point on the tile, in meters.
  133585. */
  133586. TileBoundingBox.prototype.distanceToCamera = function(frameState) {
  133587. var camera = frameState.camera;
  133588. var cameraCartesianPosition = camera.positionWC;
  133589. var cameraCartographicPosition = camera.positionCartographic;
  133590. var result = 0.0;
  133591. if (!Rectangle.contains(this.rectangle, cameraCartographicPosition)) {
  133592. var southwestCornerCartesian = this.southwestCornerCartesian;
  133593. var northeastCornerCartesian = this.northeastCornerCartesian;
  133594. var westNormal = this.westNormal;
  133595. var southNormal = this.southNormal;
  133596. var eastNormal = this.eastNormal;
  133597. var northNormal = this.northNormal;
  133598. if (frameState.mode !== SceneMode.SCENE3D) {
  133599. southwestCornerCartesian = frameState.mapProjection.project(Rectangle.southwest(this.rectangle), southwestCornerScratch);
  133600. southwestCornerCartesian.z = southwestCornerCartesian.y;
  133601. southwestCornerCartesian.y = southwestCornerCartesian.x;
  133602. southwestCornerCartesian.x = 0.0;
  133603. northeastCornerCartesian = frameState.mapProjection.project(Rectangle.northeast(this.rectangle), northeastCornerScratch);
  133604. northeastCornerCartesian.z = northeastCornerCartesian.y;
  133605. northeastCornerCartesian.y = northeastCornerCartesian.x;
  133606. northeastCornerCartesian.x = 0.0;
  133607. westNormal = negativeUnitY;
  133608. eastNormal = Cartesian3.UNIT_Y;
  133609. southNormal = negativeUnitZ;
  133610. northNormal = Cartesian3.UNIT_Z;
  133611. }
  133612. var vectorFromSouthwestCorner = Cartesian3.subtract(cameraCartesianPosition, southwestCornerCartesian, vectorScratch);
  133613. var distanceToWestPlane = Cartesian3.dot(vectorFromSouthwestCorner, westNormal);
  133614. var distanceToSouthPlane = Cartesian3.dot(vectorFromSouthwestCorner, southNormal);
  133615. var vectorFromNortheastCorner = Cartesian3.subtract(cameraCartesianPosition, northeastCornerCartesian, vectorScratch);
  133616. var distanceToEastPlane = Cartesian3.dot(vectorFromNortheastCorner, eastNormal);
  133617. var distanceToNorthPlane = Cartesian3.dot(vectorFromNortheastCorner, northNormal);
  133618. if (distanceToWestPlane > 0.0) {
  133619. result += distanceToWestPlane * distanceToWestPlane;
  133620. } else if (distanceToEastPlane > 0.0) {
  133621. result += distanceToEastPlane * distanceToEastPlane;
  133622. }
  133623. if (distanceToSouthPlane > 0.0) {
  133624. result += distanceToSouthPlane * distanceToSouthPlane;
  133625. } else if (distanceToNorthPlane > 0.0) {
  133626. result += distanceToNorthPlane * distanceToNorthPlane;
  133627. }
  133628. }
  133629. var cameraHeight;
  133630. if (frameState.mode === SceneMode.SCENE3D) {
  133631. cameraHeight = cameraCartographicPosition.height;
  133632. } else {
  133633. cameraHeight = cameraCartesianPosition.x;
  133634. }
  133635. var maximumHeight = frameState.mode === SceneMode.SCENE3D ? this.maximumHeight : 0.0;
  133636. var distanceFromTop = cameraHeight - maximumHeight;
  133637. if (distanceFromTop > 0.0) {
  133638. result += distanceFromTop * distanceFromTop;
  133639. }
  133640. return Math.sqrt(result);
  133641. };
  133642. return TileBoundingBox;
  133643. });
  133644. /*global define*/
  133645. define('Scene/TileTerrain',[
  133646. '../Core/BoundingSphere',
  133647. '../Core/Cartesian3',
  133648. '../Core/defined',
  133649. '../Core/DeveloperError',
  133650. '../Core/IndexDatatype',
  133651. '../Core/OrientedBoundingBox',
  133652. '../Core/TileProviderError',
  133653. '../Renderer/Buffer',
  133654. '../Renderer/BufferUsage',
  133655. '../Renderer/VertexArray',
  133656. '../ThirdParty/when',
  133657. './TerrainState',
  133658. './TileBoundingBox'
  133659. ], function(
  133660. BoundingSphere,
  133661. Cartesian3,
  133662. defined,
  133663. DeveloperError,
  133664. IndexDatatype,
  133665. OrientedBoundingBox,
  133666. TileProviderError,
  133667. Buffer,
  133668. BufferUsage,
  133669. VertexArray,
  133670. when,
  133671. TerrainState,
  133672. TileBoundingBox) {
  133673. 'use strict';
  133674. /**
  133675. * Manages details of the terrain load or upsample process.
  133676. *
  133677. * @alias TileTerrain
  133678. * @constructor
  133679. * @private
  133680. *
  133681. * @param {TerrainData} [upsampleDetails.data] The terrain data being upsampled.
  133682. * @param {Number} [upsampleDetails.x] The X coordinate of the tile being upsampled.
  133683. * @param {Number} [upsampleDetails.y] The Y coordinate of the tile being upsampled.
  133684. * @param {Number} [upsampleDetails.level] The level coordinate of the tile being upsampled.
  133685. */
  133686. function TileTerrain(upsampleDetails) {
  133687. /**
  133688. * The current state of the terrain in the terrain processing pipeline.
  133689. * @type {TerrainState}
  133690. * @default {@link TerrainState.UNLOADED}
  133691. */
  133692. this.state = TerrainState.UNLOADED;
  133693. this.data = undefined;
  133694. this.mesh = undefined;
  133695. this.vertexArray = undefined;
  133696. this.upsampleDetails = upsampleDetails;
  133697. }
  133698. TileTerrain.prototype.freeResources = function() {
  133699. this.state = TerrainState.UNLOADED;
  133700. this.data = undefined;
  133701. this.mesh = undefined;
  133702. if (defined(this.vertexArray)) {
  133703. var indexBuffer = this.vertexArray.indexBuffer;
  133704. this.vertexArray.destroy();
  133705. this.vertexArray = undefined;
  133706. if (!indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) {
  133707. --indexBuffer.referenceCount;
  133708. if (indexBuffer.referenceCount === 0) {
  133709. indexBuffer.destroy();
  133710. }
  133711. }
  133712. }
  133713. };
  133714. TileTerrain.prototype.publishToTile = function(tile) {
  133715. var surfaceTile = tile.data;
  133716. var mesh = this.mesh;
  133717. Cartesian3.clone(mesh.center, surfaceTile.center);
  133718. surfaceTile.minimumHeight = mesh.minimumHeight;
  133719. surfaceTile.maximumHeight = mesh.maximumHeight;
  133720. surfaceTile.boundingSphere3D = BoundingSphere.clone(mesh.boundingSphere3D, surfaceTile.boundingSphere3D);
  133721. surfaceTile.orientedBoundingBox = OrientedBoundingBox.clone(mesh.orientedBoundingBox, surfaceTile.orientedBoundingBox);
  133722. surfaceTile.tileBoundingBox = new TileBoundingBox({
  133723. rectangle : tile.rectangle,
  133724. minimumHeight : mesh.minimumHeight,
  133725. maximumHeight : mesh.maximumHeight,
  133726. ellipsoid : tile.tilingScheme.ellipsoid
  133727. });
  133728. tile.data.occludeePointInScaledSpace = Cartesian3.clone(mesh.occludeePointInScaledSpace, surfaceTile.occludeePointInScaledSpace);
  133729. };
  133730. TileTerrain.prototype.processLoadStateMachine = function(frameState, terrainProvider, x, y, level) {
  133731. if (this.state === TerrainState.UNLOADED) {
  133732. requestTileGeometry(this, terrainProvider, x, y, level);
  133733. }
  133734. if (this.state === TerrainState.RECEIVED) {
  133735. transform(this, frameState, terrainProvider, x, y, level);
  133736. }
  133737. if (this.state === TerrainState.TRANSFORMED) {
  133738. createResources(this, frameState.context, terrainProvider, x, y, level);
  133739. }
  133740. };
  133741. function requestTileGeometry(tileTerrain, terrainProvider, x, y, level) {
  133742. function success(terrainData) {
  133743. tileTerrain.data = terrainData;
  133744. tileTerrain.state = TerrainState.RECEIVED;
  133745. }
  133746. function failure() {
  133747. // Initially assume failure. handleError may retry, in which case the state will
  133748. // change to RECEIVING or UNLOADED.
  133749. tileTerrain.state = TerrainState.FAILED;
  133750. var message = 'Failed to obtain terrain tile X: ' + x + ' Y: ' + y + ' Level: ' + level + '.';
  133751. terrainProvider._requestError = TileProviderError.handleError(
  133752. terrainProvider._requestError,
  133753. terrainProvider,
  133754. terrainProvider.errorEvent,
  133755. message,
  133756. x, y, level,
  133757. doRequest);
  133758. }
  133759. function doRequest() {
  133760. // Request the terrain from the terrain provider.
  133761. tileTerrain.data = terrainProvider.requestTileGeometry(x, y, level);
  133762. // If the request method returns undefined (instead of a promise), the request
  133763. // has been deferred.
  133764. if (defined(tileTerrain.data)) {
  133765. tileTerrain.state = TerrainState.RECEIVING;
  133766. when(tileTerrain.data, success, failure);
  133767. } else {
  133768. // Deferred - try again later.
  133769. tileTerrain.state = TerrainState.UNLOADED;
  133770. }
  133771. }
  133772. doRequest();
  133773. }
  133774. TileTerrain.prototype.processUpsampleStateMachine = function(frameState, terrainProvider, x, y, level) {
  133775. if (this.state === TerrainState.UNLOADED) {
  133776. var upsampleDetails = this.upsampleDetails;
  133777. if (!defined(upsampleDetails)) {
  133778. throw new DeveloperError('TileTerrain cannot upsample unless provided upsampleDetails.');
  133779. }
  133780. var sourceData = upsampleDetails.data;
  133781. var sourceX = upsampleDetails.x;
  133782. var sourceY = upsampleDetails.y;
  133783. var sourceLevel = upsampleDetails.level;
  133784. this.data = sourceData.upsample(terrainProvider.tilingScheme, sourceX, sourceY, sourceLevel, x, y, level);
  133785. if (!defined(this.data)) {
  133786. // The upsample request has been deferred - try again later.
  133787. return;
  133788. }
  133789. this.state = TerrainState.RECEIVING;
  133790. var that = this;
  133791. when(this.data, function(terrainData) {
  133792. that.data = terrainData;
  133793. that.state = TerrainState.RECEIVED;
  133794. }, function() {
  133795. that.state = TerrainState.FAILED;
  133796. });
  133797. }
  133798. if (this.state === TerrainState.RECEIVED) {
  133799. transform(this, frameState, terrainProvider, x, y, level);
  133800. }
  133801. if (this.state === TerrainState.TRANSFORMED) {
  133802. createResources(this, frameState.context, terrainProvider, x, y, level);
  133803. }
  133804. };
  133805. function transform(tileTerrain, frameState, terrainProvider, x, y, level) {
  133806. var tilingScheme = terrainProvider.tilingScheme;
  133807. var terrainData = tileTerrain.data;
  133808. var meshPromise = terrainData.createMesh(tilingScheme, x, y, level, frameState.terrainExaggeration);
  133809. if (!defined(meshPromise)) {
  133810. // Postponed.
  133811. return;
  133812. }
  133813. tileTerrain.state = TerrainState.TRANSFORMING;
  133814. when(meshPromise, function(mesh) {
  133815. tileTerrain.mesh = mesh;
  133816. tileTerrain.state = TerrainState.TRANSFORMED;
  133817. }, function() {
  133818. tileTerrain.state = TerrainState.FAILED;
  133819. });
  133820. }
  133821. function createResources(tileTerrain, context, terrainProvider, x, y, level) {
  133822. var typedArray = tileTerrain.mesh.vertices;
  133823. var buffer = Buffer.createVertexBuffer({
  133824. context : context,
  133825. typedArray : typedArray,
  133826. usage : BufferUsage.STATIC_DRAW
  133827. });
  133828. var attributes = tileTerrain.mesh.encoding.getAttributes(buffer);
  133829. var indexBuffers = tileTerrain.mesh.indices.indexBuffers || {};
  133830. var indexBuffer = indexBuffers[context.id];
  133831. if (!defined(indexBuffer) || indexBuffer.isDestroyed()) {
  133832. var indices = tileTerrain.mesh.indices;
  133833. var indexDatatype = (indices.BYTES_PER_ELEMENT === 2) ? IndexDatatype.UNSIGNED_SHORT : IndexDatatype.UNSIGNED_INT;
  133834. indexBuffer = Buffer.createIndexBuffer({
  133835. context : context,
  133836. typedArray : indices,
  133837. usage : BufferUsage.STATIC_DRAW,
  133838. indexDatatype : indexDatatype
  133839. });
  133840. indexBuffer.vertexArrayDestroyable = false;
  133841. indexBuffer.referenceCount = 1;
  133842. indexBuffers[context.id] = indexBuffer;
  133843. tileTerrain.mesh.indices.indexBuffers = indexBuffers;
  133844. } else {
  133845. ++indexBuffer.referenceCount;
  133846. }
  133847. tileTerrain.vertexArray = new VertexArray({
  133848. context : context,
  133849. attributes : attributes,
  133850. indexBuffer : indexBuffer
  133851. });
  133852. tileTerrain.state = TerrainState.READY;
  133853. }
  133854. return TileTerrain;
  133855. });
  133856. /*global define*/
  133857. define('Scene/GlobeSurfaceTile',[
  133858. '../Core/BoundingSphere',
  133859. '../Core/Cartesian3',
  133860. '../Core/Cartesian4',
  133861. '../Core/defaultValue',
  133862. '../Core/defined',
  133863. '../Core/defineProperties',
  133864. '../Core/IntersectionTests',
  133865. '../Core/PixelFormat',
  133866. '../Renderer/PixelDatatype',
  133867. '../Renderer/Sampler',
  133868. '../Renderer/Texture',
  133869. '../Renderer/TextureMagnificationFilter',
  133870. '../Renderer/TextureMinificationFilter',
  133871. '../Renderer/TextureWrap',
  133872. './ImageryState',
  133873. './QuadtreeTileLoadState',
  133874. './SceneMode',
  133875. './TerrainState',
  133876. './TileTerrain'
  133877. ], function(
  133878. BoundingSphere,
  133879. Cartesian3,
  133880. Cartesian4,
  133881. defaultValue,
  133882. defined,
  133883. defineProperties,
  133884. IntersectionTests,
  133885. PixelFormat,
  133886. PixelDatatype,
  133887. Sampler,
  133888. Texture,
  133889. TextureMagnificationFilter,
  133890. TextureMinificationFilter,
  133891. TextureWrap,
  133892. ImageryState,
  133893. QuadtreeTileLoadState,
  133894. SceneMode,
  133895. TerrainState,
  133896. TileTerrain) {
  133897. 'use strict';
  133898. /**
  133899. * Contains additional information about a {@link QuadtreeTile} of the globe's surface, and
  133900. * encapsulates state transition logic for loading tiles.
  133901. *
  133902. * @constructor
  133903. * @alias GlobeSurfaceTile
  133904. * @private
  133905. */
  133906. function GlobeSurfaceTile() {
  133907. /**
  133908. * The {@link TileImagery} attached to this tile.
  133909. * @type {TileImagery[]}
  133910. * @default []
  133911. */
  133912. this.imagery = [];
  133913. this.waterMaskTexture = undefined;
  133914. this.waterMaskTranslationAndScale = new Cartesian4(0.0, 0.0, 1.0, 1.0);
  133915. this.terrainData = undefined;
  133916. this.center = new Cartesian3();
  133917. this.vertexArray = undefined;
  133918. this.minimumHeight = 0.0;
  133919. this.maximumHeight = 0.0;
  133920. this.boundingSphere3D = new BoundingSphere();
  133921. this.boundingSphere2D = new BoundingSphere();
  133922. this.orientedBoundingBox = undefined;
  133923. this.tileBoundingBox = undefined;
  133924. this.occludeePointInScaledSpace = new Cartesian3();
  133925. this.loadedTerrain = undefined;
  133926. this.upsampledTerrain = undefined;
  133927. this.pickBoundingSphere = new BoundingSphere();
  133928. this.pickTerrain = undefined;
  133929. this.surfaceShader = undefined;
  133930. }
  133931. defineProperties(GlobeSurfaceTile.prototype, {
  133932. /**
  133933. * Gets a value indicating whether or not this tile is eligible to be unloaded.
  133934. * Typically, a tile is ineligible to be unloaded while an asynchronous operation,
  133935. * such as a request for data, is in progress on it. A tile will never be
  133936. * unloaded while it is needed for rendering, regardless of the value of this
  133937. * property.
  133938. * @memberof GlobeSurfaceTile.prototype
  133939. * @type {Boolean}
  133940. */
  133941. eligibleForUnloading : {
  133942. get : function() {
  133943. // Do not remove tiles that are transitioning or that have
  133944. // imagery that is transitioning.
  133945. var loadedTerrain = this.loadedTerrain;
  133946. var loadingIsTransitioning = defined(loadedTerrain) &&
  133947. (loadedTerrain.state === TerrainState.RECEIVING || loadedTerrain.state === TerrainState.TRANSFORMING);
  133948. var upsampledTerrain = this.upsampledTerrain;
  133949. var upsamplingIsTransitioning = defined(upsampledTerrain) &&
  133950. (upsampledTerrain.state === TerrainState.RECEIVING || upsampledTerrain.state === TerrainState.TRANSFORMING);
  133951. var shouldRemoveTile = !loadingIsTransitioning && !upsamplingIsTransitioning;
  133952. var imagery = this.imagery;
  133953. for (var i = 0, len = imagery.length; shouldRemoveTile && i < len; ++i) {
  133954. var tileImagery = imagery[i];
  133955. shouldRemoveTile = !defined(tileImagery.loadingImagery) || tileImagery.loadingImagery.state !== ImageryState.TRANSITIONING;
  133956. }
  133957. return shouldRemoveTile;
  133958. }
  133959. }
  133960. });
  133961. function getPosition(encoding, mode, projection, vertices, index, result) {
  133962. encoding.decodePosition(vertices, index, result);
  133963. if (defined(mode) && mode !== SceneMode.SCENE3D) {
  133964. var ellipsoid = projection.ellipsoid;
  133965. var positionCart = ellipsoid.cartesianToCartographic(result);
  133966. projection.project(positionCart, result);
  133967. Cartesian3.fromElements(result.z, result.x, result.y, result);
  133968. }
  133969. return result;
  133970. }
  133971. var scratchV0 = new Cartesian3();
  133972. var scratchV1 = new Cartesian3();
  133973. var scratchV2 = new Cartesian3();
  133974. var scratchResult = new Cartesian3();
  133975. GlobeSurfaceTile.prototype.pick = function(ray, mode, projection, cullBackFaces, result) {
  133976. var terrain = this.pickTerrain;
  133977. if (!defined(terrain)) {
  133978. return undefined;
  133979. }
  133980. var mesh = terrain.mesh;
  133981. if (!defined(mesh)) {
  133982. return undefined;
  133983. }
  133984. var vertices = mesh.vertices;
  133985. var indices = mesh.indices;
  133986. var encoding = mesh.encoding;
  133987. var length = indices.length;
  133988. for (var i = 0; i < length; i += 3) {
  133989. var i0 = indices[i];
  133990. var i1 = indices[i + 1];
  133991. var i2 = indices[i + 2];
  133992. var v0 = getPosition(encoding, mode, projection, vertices, i0, scratchV0);
  133993. var v1 = getPosition(encoding, mode, projection, vertices, i1, scratchV1);
  133994. var v2 = getPosition(encoding, mode, projection, vertices, i2, scratchV2);
  133995. var intersection = IntersectionTests.rayTriangle(ray, v0, v1, v2, cullBackFaces, scratchResult);
  133996. if (defined(intersection)) {
  133997. return Cartesian3.clone(intersection, result);
  133998. }
  133999. }
  134000. return undefined;
  134001. };
  134002. GlobeSurfaceTile.prototype.freeResources = function() {
  134003. if (defined(this.waterMaskTexture)) {
  134004. --this.waterMaskTexture.referenceCount;
  134005. if (this.waterMaskTexture.referenceCount === 0) {
  134006. this.waterMaskTexture.destroy();
  134007. }
  134008. this.waterMaskTexture = undefined;
  134009. }
  134010. this.terrainData = undefined;
  134011. if (defined(this.loadedTerrain)) {
  134012. this.loadedTerrain.freeResources();
  134013. this.loadedTerrain = undefined;
  134014. }
  134015. if (defined(this.upsampledTerrain)) {
  134016. this.upsampledTerrain.freeResources();
  134017. this.upsampledTerrain = undefined;
  134018. }
  134019. if (defined(this.pickTerrain)) {
  134020. this.pickTerrain.freeResources();
  134021. this.pickTerrain = undefined;
  134022. }
  134023. var i, len;
  134024. var imageryList = this.imagery;
  134025. for (i = 0, len = imageryList.length; i < len; ++i) {
  134026. imageryList[i].freeResources();
  134027. }
  134028. this.imagery.length = 0;
  134029. this.freeVertexArray();
  134030. };
  134031. GlobeSurfaceTile.prototype.freeVertexArray = function() {
  134032. var indexBuffer;
  134033. if (defined(this.vertexArray)) {
  134034. indexBuffer = this.vertexArray.indexBuffer;
  134035. this.vertexArray = this.vertexArray.destroy();
  134036. if (!indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) {
  134037. --indexBuffer.referenceCount;
  134038. if (indexBuffer.referenceCount === 0) {
  134039. indexBuffer.destroy();
  134040. }
  134041. }
  134042. }
  134043. if (defined(this.wireframeVertexArray)) {
  134044. indexBuffer = this.wireframeVertexArray.indexBuffer;
  134045. this.wireframeVertexArray = this.wireframeVertexArray.destroy();
  134046. if (!indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) {
  134047. --indexBuffer.referenceCount;
  134048. if (indexBuffer.referenceCount === 0) {
  134049. indexBuffer.destroy();
  134050. }
  134051. }
  134052. }
  134053. };
  134054. GlobeSurfaceTile.processStateMachine = function(tile, frameState, terrainProvider, imageryLayerCollection, vertexArraysToDestroy) {
  134055. var surfaceTile = tile.data;
  134056. if (!defined(surfaceTile)) {
  134057. surfaceTile = tile.data = new GlobeSurfaceTile();
  134058. }
  134059. if (tile.state === QuadtreeTileLoadState.START) {
  134060. prepareNewTile(tile, terrainProvider, imageryLayerCollection);
  134061. tile.state = QuadtreeTileLoadState.LOADING;
  134062. }
  134063. if (tile.state === QuadtreeTileLoadState.LOADING) {
  134064. processTerrainStateMachine(tile, frameState, terrainProvider, vertexArraysToDestroy);
  134065. }
  134066. // The terrain is renderable as soon as we have a valid vertex array.
  134067. var isRenderable = defined(surfaceTile.vertexArray);
  134068. // But it's not done loading until our two state machines are terminated.
  134069. var isDoneLoading = !defined(surfaceTile.loadedTerrain) && !defined(surfaceTile.upsampledTerrain);
  134070. // If this tile's terrain and imagery are just upsampled from its parent, mark the tile as
  134071. // upsampled only. We won't refine a tile if its four children are upsampled only.
  134072. var isUpsampledOnly = defined(surfaceTile.terrainData) && surfaceTile.terrainData.wasCreatedByUpsampling();
  134073. // Transition imagery states
  134074. var tileImageryCollection = surfaceTile.imagery;
  134075. for (var i = 0, len = tileImageryCollection.length; i < len; ++i) {
  134076. var tileImagery = tileImageryCollection[i];
  134077. if (!defined(tileImagery.loadingImagery)) {
  134078. isUpsampledOnly = false;
  134079. continue;
  134080. }
  134081. if (tileImagery.loadingImagery.state === ImageryState.PLACEHOLDER) {
  134082. var imageryLayer = tileImagery.loadingImagery.imageryLayer;
  134083. if (imageryLayer.imageryProvider.ready) {
  134084. // Remove the placeholder and add the actual skeletons (if any)
  134085. // at the same position. Then continue the loop at the same index.
  134086. tileImagery.freeResources();
  134087. tileImageryCollection.splice(i, 1);
  134088. imageryLayer._createTileImagerySkeletons(tile, terrainProvider, i);
  134089. --i;
  134090. len = tileImageryCollection.length;
  134091. continue;
  134092. } else {
  134093. isUpsampledOnly = false;
  134094. }
  134095. }
  134096. var thisTileDoneLoading = tileImagery.processStateMachine(tile, frameState);
  134097. isDoneLoading = isDoneLoading && thisTileDoneLoading;
  134098. // The imagery is renderable as soon as we have any renderable imagery for this region.
  134099. isRenderable = isRenderable && (thisTileDoneLoading || defined(tileImagery.readyImagery));
  134100. isUpsampledOnly = isUpsampledOnly && defined(tileImagery.loadingImagery) &&
  134101. (tileImagery.loadingImagery.state === ImageryState.FAILED || tileImagery.loadingImagery.state === ImageryState.INVALID);
  134102. }
  134103. tile.upsampledFromParent = isUpsampledOnly;
  134104. // The tile becomes renderable when the terrain and all imagery data are loaded.
  134105. if (i === len) {
  134106. if (isRenderable) {
  134107. tile.renderable = true;
  134108. }
  134109. if (isDoneLoading) {
  134110. tile.state = QuadtreeTileLoadState.DONE;
  134111. }
  134112. }
  134113. };
  134114. function prepareNewTile(tile, terrainProvider, imageryLayerCollection) {
  134115. var surfaceTile = tile.data;
  134116. var upsampleTileDetails = getUpsampleTileDetails(tile);
  134117. if (defined(upsampleTileDetails)) {
  134118. surfaceTile.upsampledTerrain = new TileTerrain(upsampleTileDetails);
  134119. }
  134120. if (isDataAvailable(tile, terrainProvider)) {
  134121. surfaceTile.loadedTerrain = new TileTerrain();
  134122. }
  134123. // Map imagery tiles to this terrain tile
  134124. for (var i = 0, len = imageryLayerCollection.length; i < len; ++i) {
  134125. var layer = imageryLayerCollection.get(i);
  134126. if (layer.show) {
  134127. layer._createTileImagerySkeletons(tile, terrainProvider);
  134128. }
  134129. }
  134130. }
  134131. function processTerrainStateMachine(tile, frameState, terrainProvider, vertexArraysToDestroy) {
  134132. var surfaceTile = tile.data;
  134133. var loaded = surfaceTile.loadedTerrain;
  134134. var upsampled = surfaceTile.upsampledTerrain;
  134135. var suspendUpsampling = false;
  134136. if (defined(loaded)) {
  134137. loaded.processLoadStateMachine(frameState, terrainProvider, tile.x, tile.y, tile.level);
  134138. // Publish the terrain data on the tile as soon as it is available.
  134139. // We'll potentially need it to upsample child tiles.
  134140. if (loaded.state >= TerrainState.RECEIVED) {
  134141. if (surfaceTile.terrainData !== loaded.data) {
  134142. surfaceTile.terrainData = loaded.data;
  134143. // If there's a water mask included in the terrain data, create a
  134144. // texture for it.
  134145. createWaterMaskTextureIfNeeded(frameState.context, surfaceTile);
  134146. propagateNewLoadedDataToChildren(tile);
  134147. }
  134148. suspendUpsampling = true;
  134149. }
  134150. if (loaded.state === TerrainState.READY) {
  134151. loaded.publishToTile(tile);
  134152. if (defined(tile.data.vertexArray)) {
  134153. // Free the tiles existing vertex array on next render.
  134154. vertexArraysToDestroy.push(tile.data.vertexArray);
  134155. }
  134156. // Transfer ownership of the vertex array to the tile itself.
  134157. tile.data.vertexArray = loaded.vertexArray;
  134158. loaded.vertexArray = undefined;
  134159. // No further loading or upsampling is necessary.
  134160. surfaceTile.pickTerrain = defaultValue(surfaceTile.loadedTerrain, surfaceTile.upsampledTerrain);
  134161. surfaceTile.loadedTerrain = undefined;
  134162. surfaceTile.upsampledTerrain = undefined;
  134163. } else if (loaded.state === TerrainState.FAILED) {
  134164. // Loading failed for some reason, or data is simply not available,
  134165. // so no need to continue trying to load. Any retrying will happen before we
  134166. // reach this point.
  134167. surfaceTile.loadedTerrain = undefined;
  134168. }
  134169. }
  134170. if (!suspendUpsampling && defined(upsampled)) {
  134171. upsampled.processUpsampleStateMachine(frameState, terrainProvider, tile.x, tile.y, tile.level);
  134172. // Publish the terrain data on the tile as soon as it is available.
  134173. // We'll potentially need it to upsample child tiles.
  134174. // It's safe to overwrite terrainData because we won't get here after
  134175. // loaded terrain data has been received.
  134176. if (upsampled.state >= TerrainState.RECEIVED) {
  134177. if (surfaceTile.terrainData !== upsampled.data) {
  134178. surfaceTile.terrainData = upsampled.data;
  134179. // If the terrain provider has a water mask, "upsample" that as well
  134180. // by computing texture translation and scale.
  134181. if (terrainProvider.hasWaterMask) {
  134182. upsampleWaterMask(tile);
  134183. }
  134184. propagateNewUpsampledDataToChildren(tile);
  134185. }
  134186. }
  134187. if (upsampled.state === TerrainState.READY) {
  134188. upsampled.publishToTile(tile);
  134189. if (defined(tile.data.vertexArray)) {
  134190. // Free the tiles existing vertex array on next render.
  134191. vertexArraysToDestroy.push(tile.data.vertexArray);
  134192. }
  134193. // Transfer ownership of the vertex array to the tile itself.
  134194. tile.data.vertexArray = upsampled.vertexArray;
  134195. upsampled.vertexArray = undefined;
  134196. // No further upsampling is necessary. We need to continue loading, though.
  134197. surfaceTile.pickTerrain = surfaceTile.upsampledTerrain;
  134198. surfaceTile.upsampledTerrain = undefined;
  134199. } else if (upsampled.state === TerrainState.FAILED) {
  134200. // Upsampling failed for some reason. This is pretty much a catastrophic failure,
  134201. // but maybe we'll be saved by loading.
  134202. surfaceTile.upsampledTerrain = undefined;
  134203. }
  134204. }
  134205. }
  134206. function getUpsampleTileDetails(tile) {
  134207. // Find the nearest ancestor with loaded terrain.
  134208. var sourceTile = tile.parent;
  134209. while (defined(sourceTile) && defined(sourceTile.data) && !defined(sourceTile.data.terrainData)) {
  134210. sourceTile = sourceTile.parent;
  134211. }
  134212. if (!defined(sourceTile) || !defined(sourceTile.data)) {
  134213. // No ancestors have loaded terrain - try again later.
  134214. return undefined;
  134215. }
  134216. return {
  134217. data : sourceTile.data.terrainData,
  134218. x : sourceTile.x,
  134219. y : sourceTile.y,
  134220. level : sourceTile.level
  134221. };
  134222. }
  134223. function propagateNewUpsampledDataToChildren(tile) {
  134224. // Now that there's new data for this tile:
  134225. // - child tiles that were previously upsampled need to be re-upsampled based on the new data.
  134226. // Generally this is only necessary when a child tile is upsampled, and then one
  134227. // of its ancestors receives new (better) data and we want to re-upsample from the
  134228. // new data.
  134229. propagateNewUpsampledDataToChild(tile, tile._southwestChild);
  134230. propagateNewUpsampledDataToChild(tile, tile._southeastChild);
  134231. propagateNewUpsampledDataToChild(tile, tile._northwestChild);
  134232. propagateNewUpsampledDataToChild(tile, tile._northeastChild);
  134233. }
  134234. function propagateNewUpsampledDataToChild(tile, childTile) {
  134235. if (defined(childTile) && childTile.state !== QuadtreeTileLoadState.START) {
  134236. var childSurfaceTile = childTile.data;
  134237. if (defined(childSurfaceTile.terrainData) && !childSurfaceTile.terrainData.wasCreatedByUpsampling()) {
  134238. // Data for the child tile has already been loaded.
  134239. return;
  134240. }
  134241. // Restart the upsampling process, no matter its current state.
  134242. // We create a new instance rather than just restarting the existing one
  134243. // because there could be an asynchronous operation pending on the existing one.
  134244. if (defined(childSurfaceTile.upsampledTerrain)) {
  134245. childSurfaceTile.upsampledTerrain.freeResources();
  134246. }
  134247. childSurfaceTile.upsampledTerrain = new TileTerrain({
  134248. data : tile.data.terrainData,
  134249. x : tile.x,
  134250. y : tile.y,
  134251. level : tile.level
  134252. });
  134253. childTile.state = QuadtreeTileLoadState.LOADING;
  134254. }
  134255. }
  134256. function propagateNewLoadedDataToChildren(tile) {
  134257. var surfaceTile = tile.data;
  134258. // Now that there's new data for this tile:
  134259. // - child tiles that were previously upsampled need to be re-upsampled based on the new data.
  134260. // - child tiles that were previously deemed unavailable may now be available.
  134261. propagateNewLoadedDataToChildTile(tile, surfaceTile, tile.southwestChild);
  134262. propagateNewLoadedDataToChildTile(tile, surfaceTile, tile.southeastChild);
  134263. propagateNewLoadedDataToChildTile(tile, surfaceTile, tile.northwestChild);
  134264. propagateNewLoadedDataToChildTile(tile, surfaceTile, tile.northeastChild);
  134265. }
  134266. function propagateNewLoadedDataToChildTile(tile, surfaceTile, childTile) {
  134267. if (childTile.state !== QuadtreeTileLoadState.START) {
  134268. var childSurfaceTile = childTile.data;
  134269. if (defined(childSurfaceTile.terrainData) && !childSurfaceTile.terrainData.wasCreatedByUpsampling()) {
  134270. // Data for the child tile has already been loaded.
  134271. return;
  134272. }
  134273. // Restart the upsampling process, no matter its current state.
  134274. // We create a new instance rather than just restarting the existing one
  134275. // because there could be an asynchronous operation pending on the existing one.
  134276. if (defined(childSurfaceTile.upsampledTerrain)) {
  134277. childSurfaceTile.upsampledTerrain.freeResources();
  134278. }
  134279. childSurfaceTile.upsampledTerrain = new TileTerrain({
  134280. data : surfaceTile.terrainData,
  134281. x : tile.x,
  134282. y : tile.y,
  134283. level : tile.level
  134284. });
  134285. if (surfaceTile.terrainData.isChildAvailable(tile.x, tile.y, childTile.x, childTile.y)) {
  134286. // Data is available for the child now. It might have been before, too.
  134287. if (!defined(childSurfaceTile.loadedTerrain)) {
  134288. // No load process is in progress, so start one.
  134289. childSurfaceTile.loadedTerrain = new TileTerrain();
  134290. }
  134291. }
  134292. childTile.state = QuadtreeTileLoadState.LOADING;
  134293. }
  134294. }
  134295. function isDataAvailable(tile, terrainProvider) {
  134296. var tileDataAvailable = terrainProvider.getTileDataAvailable(tile.x, tile.y, tile.level);
  134297. if (defined(tileDataAvailable)) {
  134298. return tileDataAvailable;
  134299. }
  134300. var parent = tile.parent;
  134301. if (!defined(parent)) {
  134302. // Data is assumed to be available for root tiles.
  134303. return true;
  134304. }
  134305. if (!defined(parent.data) || !defined(parent.data.terrainData)) {
  134306. // Parent tile data is not yet received or upsampled, so assume (for now) that this
  134307. // child tile is not available.
  134308. return false;
  134309. }
  134310. return parent.data.terrainData.isChildAvailable(parent.x, parent.y, tile.x, tile.y);
  134311. }
  134312. function getContextWaterMaskData(context) {
  134313. var data = context.cache.tile_waterMaskData;
  134314. if (!defined(data)) {
  134315. var allWaterTexture = new Texture({
  134316. context : context,
  134317. pixelFormat : PixelFormat.LUMINANCE,
  134318. pixelDatatype : PixelDatatype.UNSIGNED_BYTE,
  134319. source : {
  134320. arrayBufferView : new Uint8Array([255]),
  134321. width : 1,
  134322. height : 1
  134323. }
  134324. });
  134325. allWaterTexture.referenceCount = 1;
  134326. var sampler = new Sampler({
  134327. wrapS : TextureWrap.CLAMP_TO_EDGE,
  134328. wrapT : TextureWrap.CLAMP_TO_EDGE,
  134329. minificationFilter : TextureMinificationFilter.LINEAR,
  134330. magnificationFilter : TextureMagnificationFilter.LINEAR
  134331. });
  134332. data = {
  134333. allWaterTexture : allWaterTexture,
  134334. sampler : sampler,
  134335. destroy : function() {
  134336. this.allWaterTexture.destroy();
  134337. }
  134338. };
  134339. context.cache.tile_waterMaskData = data;
  134340. }
  134341. return data;
  134342. }
  134343. function createWaterMaskTextureIfNeeded(context, surfaceTile) {
  134344. var previousTexture = surfaceTile.waterMaskTexture;
  134345. if (defined(previousTexture)) {
  134346. --previousTexture.referenceCount;
  134347. if (previousTexture.referenceCount === 0) {
  134348. previousTexture.destroy();
  134349. }
  134350. surfaceTile.waterMaskTexture = undefined;
  134351. }
  134352. var waterMask = surfaceTile.terrainData.waterMask;
  134353. if (!defined(waterMask)) {
  134354. return;
  134355. }
  134356. var waterMaskData = getContextWaterMaskData(context);
  134357. var texture;
  134358. var waterMaskLength = waterMask.length;
  134359. if (waterMaskLength === 1) {
  134360. // Length 1 means the tile is entirely land or entirely water.
  134361. // A value of 0 indicates entirely land, a value of 1 indicates entirely water.
  134362. if (waterMask[0] !== 0) {
  134363. texture = waterMaskData.allWaterTexture;
  134364. } else {
  134365. // Leave the texture undefined if the tile is entirely land.
  134366. return;
  134367. }
  134368. } else {
  134369. var textureSize = Math.sqrt(waterMaskLength);
  134370. texture = new Texture({
  134371. context : context,
  134372. pixelFormat : PixelFormat.LUMINANCE,
  134373. pixelDatatype : PixelDatatype.UNSIGNED_BYTE,
  134374. source : {
  134375. width : textureSize,
  134376. height : textureSize,
  134377. arrayBufferView : waterMask
  134378. },
  134379. sampler : waterMaskData.sampler
  134380. });
  134381. texture.referenceCount = 0;
  134382. }
  134383. ++texture.referenceCount;
  134384. surfaceTile.waterMaskTexture = texture;
  134385. Cartesian4.fromElements(0.0, 0.0, 1.0, 1.0, surfaceTile.waterMaskTranslationAndScale);
  134386. }
  134387. function upsampleWaterMask(tile) {
  134388. var surfaceTile = tile.data;
  134389. // Find the nearest ancestor with loaded terrain.
  134390. var sourceTile = tile.parent;
  134391. while (defined(sourceTile) && !defined(sourceTile.data.terrainData) || sourceTile.data.terrainData.wasCreatedByUpsampling()) {
  134392. sourceTile = sourceTile.parent;
  134393. }
  134394. if (!defined(sourceTile) || !defined(sourceTile.data.waterMaskTexture)) {
  134395. // No ancestors have a water mask texture - try again later.
  134396. return;
  134397. }
  134398. surfaceTile.waterMaskTexture = sourceTile.data.waterMaskTexture;
  134399. ++surfaceTile.waterMaskTexture.referenceCount;
  134400. // Compute the water mask translation and scale
  134401. var sourceTileRectangle = sourceTile.rectangle;
  134402. var tileRectangle = tile.rectangle;
  134403. var tileWidth = tileRectangle.width;
  134404. var tileHeight = tileRectangle.height;
  134405. var scaleX = tileWidth / sourceTileRectangle.width;
  134406. var scaleY = tileHeight / sourceTileRectangle.height;
  134407. surfaceTile.waterMaskTranslationAndScale.x = scaleX * (tileRectangle.west - sourceTileRectangle.west) / tileWidth;
  134408. surfaceTile.waterMaskTranslationAndScale.y = scaleY * (tileRectangle.south - sourceTileRectangle.south) / tileHeight;
  134409. surfaceTile.waterMaskTranslationAndScale.z = scaleX;
  134410. surfaceTile.waterMaskTranslationAndScale.w = scaleY;
  134411. }
  134412. return GlobeSurfaceTile;
  134413. });
  134414. //This file is automatically rebuilt by the Cesium build process.
  134415. /*global define*/
  134416. define('Shaders/ReprojectWebMercatorFS',[],function() {
  134417. 'use strict';
  134418. return "uniform sampler2D u_texture;\n\
  134419. varying vec2 v_textureCoordinates;\n\
  134420. void main()\n\
  134421. {\n\
  134422. gl_FragColor = texture2D(u_texture, v_textureCoordinates);\n\
  134423. }\n\
  134424. ";
  134425. });
  134426. //This file is automatically rebuilt by the Cesium build process.
  134427. /*global define*/
  134428. define('Shaders/ReprojectWebMercatorVS',[],function() {
  134429. 'use strict';
  134430. return "attribute vec4 position;\n\
  134431. attribute float webMercatorT;\n\
  134432. uniform vec2 u_textureDimensions;\n\
  134433. varying vec2 v_textureCoordinates;\n\
  134434. void main()\n\
  134435. {\n\
  134436. v_textureCoordinates = vec2(position.x, webMercatorT);\n\
  134437. gl_Position = czm_viewportOrthographic * (position * vec4(u_textureDimensions, 1.0, 1.0));\n\
  134438. }\n\
  134439. ";
  134440. });
  134441. /*global define*/
  134442. define('Scene/Imagery',[
  134443. '../Core/defined',
  134444. '../Core/destroyObject',
  134445. './ImageryState'
  134446. ], function(
  134447. defined,
  134448. destroyObject,
  134449. ImageryState) {
  134450. 'use strict';
  134451. /**
  134452. * Stores details about a tile of imagery.
  134453. *
  134454. * @alias Imagery
  134455. * @private
  134456. */
  134457. function Imagery(imageryLayer, x, y, level, rectangle) {
  134458. this.imageryLayer = imageryLayer;
  134459. this.x = x;
  134460. this.y = y;
  134461. this.level = level;
  134462. if (level !== 0) {
  134463. var parentX = x / 2 | 0;
  134464. var parentY = y / 2 | 0;
  134465. var parentLevel = level - 1;
  134466. this.parent = imageryLayer.getImageryFromCache(parentX, parentY, parentLevel);
  134467. }
  134468. this.state = ImageryState.UNLOADED;
  134469. this.imageUrl = undefined;
  134470. this.image = undefined;
  134471. this.texture = undefined;
  134472. this.textureWebMercator = undefined;
  134473. this.credits = undefined;
  134474. this.referenceCount = 0;
  134475. if (!defined(rectangle) && imageryLayer.imageryProvider.ready) {
  134476. var tilingScheme = imageryLayer.imageryProvider.tilingScheme;
  134477. rectangle = tilingScheme.tileXYToRectangle(x, y, level);
  134478. }
  134479. this.rectangle = rectangle;
  134480. }
  134481. Imagery.createPlaceholder = function(imageryLayer) {
  134482. var result = new Imagery(imageryLayer, 0, 0, 0);
  134483. result.addReference();
  134484. result.state = ImageryState.PLACEHOLDER;
  134485. return result;
  134486. };
  134487. Imagery.prototype.addReference = function() {
  134488. ++this.referenceCount;
  134489. };
  134490. Imagery.prototype.releaseReference = function() {
  134491. --this.referenceCount;
  134492. if (this.referenceCount === 0) {
  134493. this.imageryLayer.removeImageryFromCache(this);
  134494. if (defined(this.parent)) {
  134495. this.parent.releaseReference();
  134496. }
  134497. if (defined(this.image) && defined(this.image.destroy)) {
  134498. this.image.destroy();
  134499. }
  134500. if (defined(this.texture)) {
  134501. this.texture.destroy();
  134502. }
  134503. if (defined(this.textureWebMercator) && this.texture !== this.textureWebMercator) {
  134504. this.textureWebMercator.destroy();
  134505. }
  134506. destroyObject(this);
  134507. return 0;
  134508. }
  134509. return this.referenceCount;
  134510. };
  134511. Imagery.prototype.processStateMachine = function(frameState, needGeographicProjection) {
  134512. if (this.state === ImageryState.UNLOADED) {
  134513. this.state = ImageryState.TRANSITIONING;
  134514. this.imageryLayer._requestImagery(this);
  134515. }
  134516. if (this.state === ImageryState.RECEIVED) {
  134517. this.state = ImageryState.TRANSITIONING;
  134518. this.imageryLayer._createTexture(frameState.context, this);
  134519. }
  134520. // If the imagery is already ready, but we need a geographic version and don't have it yet,
  134521. // we still need to do the reprojection step. This can happen if the Web Mercator version
  134522. // is fine initially, but the geographic one is needed later.
  134523. var needsReprojection = this.state === ImageryState.READY && needGeographicProjection && !this.texture;
  134524. if (this.state === ImageryState.TEXTURE_LOADED || needsReprojection) {
  134525. this.state = ImageryState.TRANSITIONING;
  134526. this.imageryLayer._reprojectTexture(frameState, this, needGeographicProjection);
  134527. }
  134528. };
  134529. return Imagery;
  134530. });
  134531. /*global define*/
  134532. define('Scene/TileImagery',[
  134533. '../Core/defined',
  134534. './ImageryState'
  134535. ], function(
  134536. defined,
  134537. ImageryState) {
  134538. 'use strict';
  134539. /**
  134540. * The assocation between a terrain tile and an imagery tile.
  134541. *
  134542. * @alias TileImagery
  134543. * @private
  134544. *
  134545. * @param {Imagery} imagery The imagery tile.
  134546. * @param {Cartesian4} textureCoordinateRectangle The texture rectangle of the tile that is covered
  134547. * by the imagery, where X=west, Y=south, Z=east, W=north.
  134548. * @param {Boolean} useWebMercatorT true to use the Web Mercator texture coordinates for this imagery tile.
  134549. */
  134550. function TileImagery(imagery, textureCoordinateRectangle, useWebMercatorT) {
  134551. this.readyImagery = undefined;
  134552. this.loadingImagery = imagery;
  134553. this.textureCoordinateRectangle = textureCoordinateRectangle;
  134554. this.textureTranslationAndScale = undefined;
  134555. this.useWebMercatorT = useWebMercatorT;
  134556. }
  134557. /**
  134558. * Frees the resources held by this instance.
  134559. */
  134560. TileImagery.prototype.freeResources = function() {
  134561. if (defined(this.readyImagery)) {
  134562. this.readyImagery.releaseReference();
  134563. }
  134564. if (defined(this.loadingImagery)) {
  134565. this.loadingImagery.releaseReference();
  134566. }
  134567. };
  134568. /**
  134569. * Processes the load state machine for this instance.
  134570. *
  134571. * @param {Tile} tile The tile to which this instance belongs.
  134572. * @param {FrameState} frameState The frameState.
  134573. * @returns {Boolean} True if this instance is done loading; otherwise, false.
  134574. */
  134575. TileImagery.prototype.processStateMachine = function(tile, frameState) {
  134576. var loadingImagery = this.loadingImagery;
  134577. var imageryLayer = loadingImagery.imageryLayer;
  134578. loadingImagery.processStateMachine(frameState, !this.useWebMercatorT);
  134579. if (loadingImagery.state === ImageryState.READY) {
  134580. if (defined(this.readyImagery)) {
  134581. this.readyImagery.releaseReference();
  134582. }
  134583. this.readyImagery = this.loadingImagery;
  134584. this.loadingImagery = undefined;
  134585. this.textureTranslationAndScale = imageryLayer._calculateTextureTranslationAndScale(tile, this);
  134586. return true; // done loading
  134587. }
  134588. // Find some ancestor imagery we can use while this imagery is still loading.
  134589. var ancestor = loadingImagery.parent;
  134590. var closestAncestorThatNeedsLoading;
  134591. while (defined(ancestor) && ancestor.state !== ImageryState.READY) {
  134592. if (ancestor.state !== ImageryState.FAILED && ancestor.state !== ImageryState.INVALID) {
  134593. // ancestor is still loading
  134594. closestAncestorThatNeedsLoading = closestAncestorThatNeedsLoading || ancestor;
  134595. }
  134596. ancestor = ancestor.parent;
  134597. }
  134598. if (this.readyImagery !== ancestor) {
  134599. if (defined(this.readyImagery)) {
  134600. this.readyImagery.releaseReference();
  134601. }
  134602. this.readyImagery = ancestor;
  134603. if (defined(ancestor)) {
  134604. ancestor.addReference();
  134605. this.textureTranslationAndScale = imageryLayer._calculateTextureTranslationAndScale(tile, this);
  134606. }
  134607. }
  134608. if (loadingImagery.state === ImageryState.FAILED || loadingImagery.state === ImageryState.INVALID) {
  134609. // The imagery tile is failed or invalid, so we'd like to use an ancestor instead.
  134610. if (defined(closestAncestorThatNeedsLoading)) {
  134611. // Push the ancestor's load process along a bit. This is necessary because some ancestor imagery
  134612. // tiles may not be attached directly to a terrain tile. Such tiles will never load if
  134613. // we don't do it here.
  134614. closestAncestorThatNeedsLoading.processStateMachine(frameState, !this.useWebMercatorT);
  134615. return false; // not done loading
  134616. } else {
  134617. // This imagery tile is failed or invalid, and we have the "best available" substitute.
  134618. return true; // done loading
  134619. }
  134620. }
  134621. return false; // not done loading
  134622. };
  134623. return TileImagery;
  134624. });
  134625. /*global define*/
  134626. define('Scene/ImageryLayer',[
  134627. '../Core/Cartesian2',
  134628. '../Core/Cartesian4',
  134629. '../Core/defaultValue',
  134630. '../Core/defined',
  134631. '../Core/defineProperties',
  134632. '../Core/destroyObject',
  134633. '../Core/FeatureDetection',
  134634. '../Core/GeographicTilingScheme',
  134635. '../Core/IndexDatatype',
  134636. '../Core/Math',
  134637. '../Core/PixelFormat',
  134638. '../Core/Rectangle',
  134639. '../Core/TerrainProvider',
  134640. '../Core/TileProviderError',
  134641. '../Core/WebMercatorProjection',
  134642. '../Core/WebMercatorTilingScheme',
  134643. '../Renderer/Buffer',
  134644. '../Renderer/BufferUsage',
  134645. '../Renderer/ComputeCommand',
  134646. '../Renderer/ContextLimits',
  134647. '../Renderer/MipmapHint',
  134648. '../Renderer/Sampler',
  134649. '../Renderer/ShaderProgram',
  134650. '../Renderer/ShaderSource',
  134651. '../Renderer/Texture',
  134652. '../Renderer/TextureMagnificationFilter',
  134653. '../Renderer/TextureMinificationFilter',
  134654. '../Renderer/TextureWrap',
  134655. '../Renderer/VertexArray',
  134656. '../Shaders/ReprojectWebMercatorFS',
  134657. '../Shaders/ReprojectWebMercatorVS',
  134658. '../ThirdParty/when',
  134659. './Imagery',
  134660. './ImageryState',
  134661. './TileImagery'
  134662. ], function(
  134663. Cartesian2,
  134664. Cartesian4,
  134665. defaultValue,
  134666. defined,
  134667. defineProperties,
  134668. destroyObject,
  134669. FeatureDetection,
  134670. GeographicTilingScheme,
  134671. IndexDatatype,
  134672. CesiumMath,
  134673. PixelFormat,
  134674. Rectangle,
  134675. TerrainProvider,
  134676. TileProviderError,
  134677. WebMercatorProjection,
  134678. WebMercatorTilingScheme,
  134679. Buffer,
  134680. BufferUsage,
  134681. ComputeCommand,
  134682. ContextLimits,
  134683. MipmapHint,
  134684. Sampler,
  134685. ShaderProgram,
  134686. ShaderSource,
  134687. Texture,
  134688. TextureMagnificationFilter,
  134689. TextureMinificationFilter,
  134690. TextureWrap,
  134691. VertexArray,
  134692. ReprojectWebMercatorFS,
  134693. ReprojectWebMercatorVS,
  134694. when,
  134695. Imagery,
  134696. ImageryState,
  134697. TileImagery) {
  134698. 'use strict';
  134699. /**
  134700. * An imagery layer that displays tiled image data from a single imagery provider
  134701. * on a {@link Globe}.
  134702. *
  134703. * @alias ImageryLayer
  134704. * @constructor
  134705. *
  134706. * @param {ImageryProvider} imageryProvider The imagery provider to use.
  134707. * @param {Object} [options] Object with the following properties:
  134708. * @param {Rectangle} [options.rectangle=imageryProvider.rectangle] The rectangle of the layer. This rectangle
  134709. * can limit the visible portion of the imagery provider.
  134710. * @param {Number|Function} [options.alpha=1.0] The alpha blending value of this layer, from 0.0 to 1.0.
  134711. * This can either be a simple number or a function with the signature
  134712. * <code>function(frameState, layer, x, y, level)</code>. The function is passed the
  134713. * current frame state, this layer, and the x, y, and level coordinates of the
  134714. * imagery tile for which the alpha is required, and it is expected to return
  134715. * the alpha value to use for the tile.
  134716. * @param {Number|Function} [options.brightness=1.0] The brightness of this layer. 1.0 uses the unmodified imagery
  134717. * color. Less than 1.0 makes the imagery darker while greater than 1.0 makes it brighter.
  134718. * This can either be a simple number or a function with the signature
  134719. * <code>function(frameState, layer, x, y, level)</code>. The function is passed the
  134720. * current frame state, this layer, and the x, y, and level coordinates of the
  134721. * imagery tile for which the brightness is required, and it is expected to return
  134722. * the brightness value to use for the tile. The function is executed for every
  134723. * frame and for every tile, so it must be fast.
  134724. * @param {Number|Function} [options.contrast=1.0] The contrast of this layer. 1.0 uses the unmodified imagery color.
  134725. * Less than 1.0 reduces the contrast while greater than 1.0 increases it.
  134726. * This can either be a simple number or a function with the signature
  134727. * <code>function(frameState, layer, x, y, level)</code>. The function is passed the
  134728. * current frame state, this layer, and the x, y, and level coordinates of the
  134729. * imagery tile for which the contrast is required, and it is expected to return
  134730. * the contrast value to use for the tile. The function is executed for every
  134731. * frame and for every tile, so it must be fast.
  134732. * @param {Number|Function} [options.hue=0.0] The hue of this layer. 0.0 uses the unmodified imagery color.
  134733. * This can either be a simple number or a function with the signature
  134734. * <code>function(frameState, layer, x, y, level)</code>. The function is passed the
  134735. * current frame state, this layer, and the x, y, and level coordinates
  134736. * of the imagery tile for which the hue is required, and it is expected to return
  134737. * the contrast value to use for the tile. The function is executed for every
  134738. * frame and for every tile, so it must be fast.
  134739. * @param {Number|Function} [options.saturation=1.0] The saturation of this layer. 1.0 uses the unmodified imagery color.
  134740. * Less than 1.0 reduces the saturation while greater than 1.0 increases it.
  134741. * This can either be a simple number or a function with the signature
  134742. * <code>function(frameState, layer, x, y, level)</code>. The function is passed the
  134743. * current frame state, this layer, and the x, y, and level coordinates
  134744. * of the imagery tile for which the saturation is required, and it is expected to return
  134745. * the contrast value to use for the tile. The function is executed for every
  134746. * frame and for every tile, so it must be fast.
  134747. * @param {Number|Function} [options.gamma=1.0] The gamma correction to apply to this layer. 1.0 uses the unmodified imagery color.
  134748. * This can either be a simple number or a function with the signature
  134749. * <code>function(frameState, layer, x, y, level)</code>. The function is passed the
  134750. * current frame state, this layer, and the x, y, and level coordinates of the
  134751. * imagery tile for which the gamma is required, and it is expected to return
  134752. * the gamma value to use for the tile. The function is executed for every
  134753. * frame and for every tile, so it must be fast.
  134754. * @param {Boolean} [options.show=true] True if the layer is shown; otherwise, false.
  134755. * @param {Number} [options.maximumAnisotropy=maximum supported] The maximum anisotropy level to use
  134756. * for texture filtering. If this parameter is not specified, the maximum anisotropy supported
  134757. * by the WebGL stack will be used. Larger values make the imagery look better in horizon
  134758. * views.
  134759. * @param {Number} [options.minimumTerrainLevel] The minimum terrain level-of-detail at which to show this imagery layer,
  134760. * or undefined to show it at all levels. Level zero is the least-detailed level.
  134761. * @param {Number} [options.maximumTerrainLevel] The maximum terrain level-of-detail at which to show this imagery layer,
  134762. * or undefined to show it at all levels. Level zero is the least-detailed level.
  134763. */
  134764. function ImageryLayer(imageryProvider, options) {
  134765. this._imageryProvider = imageryProvider;
  134766. options = defaultValue(options, {});
  134767. /**
  134768. * The alpha blending value of this layer, with 0.0 representing fully transparent and
  134769. * 1.0 representing fully opaque.
  134770. *
  134771. * @type {Number}
  134772. * @default 1.0
  134773. */
  134774. this.alpha = defaultValue(options.alpha, defaultValue(imageryProvider.defaultAlpha, 1.0));
  134775. /**
  134776. * The brightness of this layer. 1.0 uses the unmodified imagery color. Less than 1.0
  134777. * makes the imagery darker while greater than 1.0 makes it brighter.
  134778. *
  134779. * @type {Number}
  134780. * @default {@link ImageryLayer.DEFAULT_BRIGHTNESS}
  134781. */
  134782. this.brightness = defaultValue(options.brightness, defaultValue(imageryProvider.defaultBrightness, ImageryLayer.DEFAULT_BRIGHTNESS));
  134783. /**
  134784. * The contrast of this layer. 1.0 uses the unmodified imagery color. Less than 1.0 reduces
  134785. * the contrast while greater than 1.0 increases it.
  134786. *
  134787. * @type {Number}
  134788. * @default {@link ImageryLayer.DEFAULT_CONTRAST}
  134789. */
  134790. this.contrast = defaultValue(options.contrast, defaultValue(imageryProvider.defaultContrast, ImageryLayer.DEFAULT_CONTRAST));
  134791. /**
  134792. * The hue of this layer in radians. 0.0 uses the unmodified imagery color.
  134793. *
  134794. * @type {Number}
  134795. * @default {@link ImageryLayer.DEFAULT_HUE}
  134796. */
  134797. this.hue = defaultValue(options.hue, defaultValue(imageryProvider.defaultHue, ImageryLayer.DEFAULT_HUE));
  134798. /**
  134799. * The saturation of this layer. 1.0 uses the unmodified imagery color. Less than 1.0 reduces the
  134800. * saturation while greater than 1.0 increases it.
  134801. *
  134802. * @type {Number}
  134803. * @default {@link ImageryLayer.DEFAULT_SATURATION}
  134804. */
  134805. this.saturation = defaultValue(options.saturation, defaultValue(imageryProvider.defaultSaturation, ImageryLayer.DEFAULT_SATURATION));
  134806. /**
  134807. * The gamma correction to apply to this layer. 1.0 uses the unmodified imagery color.
  134808. *
  134809. * @type {Number}
  134810. * @default {@link ImageryLayer.DEFAULT_GAMMA}
  134811. */
  134812. this.gamma = defaultValue(options.gamma, defaultValue(imageryProvider.defaultGamma, ImageryLayer.DEFAULT_GAMMA));
  134813. /**
  134814. * Determines if this layer is shown.
  134815. *
  134816. * @type {Boolean}
  134817. * @default true
  134818. */
  134819. this.show = defaultValue(options.show, true);
  134820. this._minimumTerrainLevel = options.minimumTerrainLevel;
  134821. this._maximumTerrainLevel = options.maximumTerrainLevel;
  134822. this._rectangle = defaultValue(options.rectangle, Rectangle.MAX_VALUE);
  134823. this._maximumAnisotropy = options.maximumAnisotropy;
  134824. this._imageryCache = {};
  134825. this._skeletonPlaceholder = new TileImagery(Imagery.createPlaceholder(this));
  134826. // The value of the show property on the last update.
  134827. this._show = true;
  134828. // The index of this layer in the ImageryLayerCollection.
  134829. this._layerIndex = -1;
  134830. // true if this is the base (lowest shown) layer.
  134831. this._isBaseLayer = false;
  134832. this._requestImageError = undefined;
  134833. this._reprojectComputeCommands = [];
  134834. }
  134835. defineProperties(ImageryLayer.prototype, {
  134836. /**
  134837. * Gets the imagery provider for this layer.
  134838. * @memberof ImageryLayer.prototype
  134839. * @type {ImageryProvider}
  134840. * @readonly
  134841. */
  134842. imageryProvider : {
  134843. get: function() {
  134844. return this._imageryProvider;
  134845. }
  134846. },
  134847. /**
  134848. * Gets the rectangle of this layer. If this rectangle is smaller than the rectangle of the
  134849. * {@link ImageryProvider}, only a portion of the imagery provider is shown.
  134850. * @memberof ImageryLayer.prototype
  134851. * @type {Rectangle}
  134852. * @readonly
  134853. */
  134854. rectangle: {
  134855. get: function() {
  134856. return this._rectangle;
  134857. }
  134858. }
  134859. });
  134860. /**
  134861. * This value is used as the default brightness for the imagery layer if one is not provided during construction
  134862. * or by the imagery provider. This value does not modify the brightness of the imagery.
  134863. * @type {Number}
  134864. * @default 1.0
  134865. */
  134866. ImageryLayer.DEFAULT_BRIGHTNESS = 1.0;
  134867. /**
  134868. * This value is used as the default contrast for the imagery layer if one is not provided during construction
  134869. * or by the imagery provider. This value does not modify the contrast of the imagery.
  134870. * @type {Number}
  134871. * @default 1.0
  134872. */
  134873. ImageryLayer.DEFAULT_CONTRAST = 1.0;
  134874. /**
  134875. * This value is used as the default hue for the imagery layer if one is not provided during construction
  134876. * or by the imagery provider. This value does not modify the hue of the imagery.
  134877. * @type {Number}
  134878. * @default 0.0
  134879. */
  134880. ImageryLayer.DEFAULT_HUE = 0.0;
  134881. /**
  134882. * This value is used as the default saturation for the imagery layer if one is not provided during construction
  134883. * or by the imagery provider. This value does not modify the saturation of the imagery.
  134884. * @type {Number}
  134885. * @default 1.0
  134886. */
  134887. ImageryLayer.DEFAULT_SATURATION = 1.0;
  134888. /**
  134889. * This value is used as the default gamma for the imagery layer if one is not provided during construction
  134890. * or by the imagery provider. This value does not modify the gamma of the imagery.
  134891. * @type {Number}
  134892. * @default 1.0
  134893. */
  134894. ImageryLayer.DEFAULT_GAMMA = 1.0;
  134895. /**
  134896. * Gets a value indicating whether this layer is the base layer in the
  134897. * {@link ImageryLayerCollection}. The base layer is the one that underlies all
  134898. * others. It is special in that it is treated as if it has global rectangle, even if
  134899. * it actually does not, by stretching the texels at the edges over the entire
  134900. * globe.
  134901. *
  134902. * @returns {Boolean} true if this is the base layer; otherwise, false.
  134903. */
  134904. ImageryLayer.prototype.isBaseLayer = function() {
  134905. return this._isBaseLayer;
  134906. };
  134907. /**
  134908. * Returns true if this object was destroyed; otherwise, false.
  134909. * <br /><br />
  134910. * If this object was destroyed, it should not be used; calling any function other than
  134911. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  134912. *
  134913. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  134914. *
  134915. * @see ImageryLayer#destroy
  134916. */
  134917. ImageryLayer.prototype.isDestroyed = function() {
  134918. return false;
  134919. };
  134920. /**
  134921. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  134922. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  134923. * <br /><br />
  134924. * Once an object is destroyed, it should not be used; calling any function other than
  134925. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  134926. * assign the return value (<code>undefined</code>) to the object as done in the example.
  134927. *
  134928. * @returns {undefined}
  134929. *
  134930. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  134931. *
  134932. *
  134933. * @example
  134934. * imageryLayer = imageryLayer && imageryLayer.destroy();
  134935. *
  134936. * @see ImageryLayer#isDestroyed
  134937. */
  134938. ImageryLayer.prototype.destroy = function() {
  134939. return destroyObject(this);
  134940. };
  134941. var imageryBoundsScratch = new Rectangle();
  134942. var tileImageryBoundsScratch = new Rectangle();
  134943. var clippedRectangleScratch = new Rectangle();
  134944. var terrainRectangleScratch = new Rectangle();
  134945. /**
  134946. * Computes the intersection of this layer's rectangle with the imagery provider's availability rectangle,
  134947. * producing the overall bounds of imagery that can be produced by this layer.
  134948. *
  134949. * @returns {Promise.<Rectangle>} A promise to a rectangle which defines the overall bounds of imagery that can be produced by this layer.
  134950. *
  134951. * @example
  134952. * // Zoom to an imagery layer.
  134953. * imageryLayer.getViewableRectangle().then(function (rectangle) {
  134954. * return camera.flyTo({
  134955. * destination: rectangle
  134956. * });
  134957. * });
  134958. */
  134959. ImageryLayer.prototype.getViewableRectangle = function() {
  134960. var imageryProvider = this._imageryProvider;
  134961. var rectangle = this._rectangle;
  134962. return imageryProvider.readyPromise.then(function() {
  134963. return Rectangle.intersection(imageryProvider.rectangle, rectangle);
  134964. });
  134965. };
  134966. /**
  134967. * Create skeletons for the imagery tiles that partially or completely overlap a given terrain
  134968. * tile.
  134969. *
  134970. * @private
  134971. *
  134972. * @param {Tile} tile The terrain tile.
  134973. * @param {TerrainProvider} terrainProvider The terrain provider associated with the terrain tile.
  134974. * @param {Number} insertionPoint The position to insert new skeletons before in the tile's imagery list.
  134975. * @returns {Boolean} true if this layer overlaps any portion of the terrain tile; otherwise, false.
  134976. */
  134977. ImageryLayer.prototype._createTileImagerySkeletons = function(tile, terrainProvider, insertionPoint) {
  134978. var surfaceTile = tile.data;
  134979. if (defined(this._minimumTerrainLevel) && tile.level < this._minimumTerrainLevel) {
  134980. return false;
  134981. }
  134982. if (defined(this._maximumTerrainLevel) && tile.level > this._maximumTerrainLevel) {
  134983. return false;
  134984. }
  134985. var imageryProvider = this._imageryProvider;
  134986. if (!defined(insertionPoint)) {
  134987. insertionPoint = surfaceTile.imagery.length;
  134988. }
  134989. if (!imageryProvider.ready) {
  134990. // The imagery provider is not ready, so we can't create skeletons, yet.
  134991. // Instead, add a placeholder so that we'll know to create
  134992. // the skeletons once the provider is ready.
  134993. this._skeletonPlaceholder.loadingImagery.addReference();
  134994. surfaceTile.imagery.splice(insertionPoint, 0, this._skeletonPlaceholder);
  134995. return true;
  134996. }
  134997. // Use Web Mercator for our texture coordinate computations if this imagery layer uses
  134998. // that projection and the terrain tile falls entirely inside the valid bounds of the
  134999. // projection.
  135000. var useWebMercatorT = imageryProvider.tilingScheme instanceof WebMercatorTilingScheme &&
  135001. tile.rectangle.north < WebMercatorProjection.MaximumLatitude &&
  135002. tile.rectangle.south > -WebMercatorProjection.MaximumLatitude;
  135003. // Compute the rectangle of the imagery from this imageryProvider that overlaps
  135004. // the geometry tile. The ImageryProvider and ImageryLayer both have the
  135005. // opportunity to constrain the rectangle. The imagery TilingScheme's rectangle
  135006. // always fully contains the ImageryProvider's rectangle.
  135007. var imageryBounds = Rectangle.intersection(imageryProvider.rectangle, this._rectangle, imageryBoundsScratch);
  135008. var rectangle = Rectangle.intersection(tile.rectangle, imageryBounds, tileImageryBoundsScratch);
  135009. if (!defined(rectangle)) {
  135010. // There is no overlap between this terrain tile and this imagery
  135011. // provider. Unless this is the base layer, no skeletons need to be created.
  135012. // We stretch texels at the edge of the base layer over the entire globe.
  135013. if (!this.isBaseLayer()) {
  135014. return false;
  135015. }
  135016. var baseImageryRectangle = imageryBounds;
  135017. var baseTerrainRectangle = tile.rectangle;
  135018. rectangle = tileImageryBoundsScratch;
  135019. if (baseTerrainRectangle.south >= baseImageryRectangle.north) {
  135020. rectangle.north = rectangle.south = baseImageryRectangle.north;
  135021. } else if (baseTerrainRectangle.north <= baseImageryRectangle.south) {
  135022. rectangle.north = rectangle.south = baseImageryRectangle.south;
  135023. } else {
  135024. rectangle.south = Math.max(baseTerrainRectangle.south, baseImageryRectangle.south);
  135025. rectangle.north = Math.min(baseTerrainRectangle.north, baseImageryRectangle.north);
  135026. }
  135027. if (baseTerrainRectangle.west >= baseImageryRectangle.east) {
  135028. rectangle.west = rectangle.east = baseImageryRectangle.east;
  135029. } else if (baseTerrainRectangle.east <= baseImageryRectangle.west) {
  135030. rectangle.west = rectangle.east = baseImageryRectangle.west;
  135031. } else {
  135032. rectangle.west = Math.max(baseTerrainRectangle.west, baseImageryRectangle.west);
  135033. rectangle.east = Math.min(baseTerrainRectangle.east, baseImageryRectangle.east);
  135034. }
  135035. }
  135036. var latitudeClosestToEquator = 0.0;
  135037. if (rectangle.south > 0.0) {
  135038. latitudeClosestToEquator = rectangle.south;
  135039. } else if (rectangle.north < 0.0) {
  135040. latitudeClosestToEquator = rectangle.north;
  135041. }
  135042. // Compute the required level in the imagery tiling scheme.
  135043. // The errorRatio should really be imagerySSE / terrainSSE rather than this hard-coded value.
  135044. // But first we need configurable imagery SSE and we need the rendering to be able to handle more
  135045. // images attached to a terrain tile than there are available texture units. So that's for the future.
  135046. var errorRatio = 1.0;
  135047. var targetGeometricError = errorRatio * terrainProvider.getLevelMaximumGeometricError(tile.level);
  135048. var imageryLevel = getLevelWithMaximumTexelSpacing(this, targetGeometricError, latitudeClosestToEquator);
  135049. imageryLevel = Math.max(0, imageryLevel);
  135050. var maximumLevel = imageryProvider.maximumLevel;
  135051. if (imageryLevel > maximumLevel) {
  135052. imageryLevel = maximumLevel;
  135053. }
  135054. if (defined(imageryProvider.minimumLevel)) {
  135055. var minimumLevel = imageryProvider.minimumLevel;
  135056. if (imageryLevel < minimumLevel) {
  135057. imageryLevel = minimumLevel;
  135058. }
  135059. }
  135060. var imageryTilingScheme = imageryProvider.tilingScheme;
  135061. var northwestTileCoordinates = imageryTilingScheme.positionToTileXY(Rectangle.northwest(rectangle), imageryLevel);
  135062. var southeastTileCoordinates = imageryTilingScheme.positionToTileXY(Rectangle.southeast(rectangle), imageryLevel);
  135063. // If the southeast corner of the rectangle lies very close to the north or west side
  135064. // of the southeast tile, we don't actually need the southernmost or easternmost
  135065. // tiles.
  135066. // Similarly, if the northwest corner of the rectangle lies very close to the south or east side
  135067. // of the northwest tile, we don't actually need the northernmost or westernmost tiles.
  135068. // We define "very close" as being within 1/512 of the width of the tile.
  135069. var veryCloseX = tile.rectangle.width / 512.0;
  135070. var veryCloseY = tile.rectangle.height / 512.0;
  135071. var northwestTileRectangle = imageryTilingScheme.tileXYToRectangle(northwestTileCoordinates.x, northwestTileCoordinates.y, imageryLevel);
  135072. if (Math.abs(northwestTileRectangle.south - tile.rectangle.north) < veryCloseY && northwestTileCoordinates.y < southeastTileCoordinates.y) {
  135073. ++northwestTileCoordinates.y;
  135074. }
  135075. if (Math.abs(northwestTileRectangle.east - tile.rectangle.west) < veryCloseX && northwestTileCoordinates.x < southeastTileCoordinates.x) {
  135076. ++northwestTileCoordinates.x;
  135077. }
  135078. var southeastTileRectangle = imageryTilingScheme.tileXYToRectangle(southeastTileCoordinates.x, southeastTileCoordinates.y, imageryLevel);
  135079. if (Math.abs(southeastTileRectangle.north - tile.rectangle.south) < veryCloseY && southeastTileCoordinates.y > northwestTileCoordinates.y) {
  135080. --southeastTileCoordinates.y;
  135081. }
  135082. if (Math.abs(southeastTileRectangle.west - tile.rectangle.east) < veryCloseX && southeastTileCoordinates.x > northwestTileCoordinates.x) {
  135083. --southeastTileCoordinates.x;
  135084. }
  135085. // Create TileImagery instances for each imagery tile overlapping this terrain tile.
  135086. // We need to do all texture coordinate computations in the imagery tile's tiling scheme.
  135087. var terrainRectangle = Rectangle.clone(tile.rectangle, terrainRectangleScratch);
  135088. var imageryRectangle = imageryTilingScheme.tileXYToRectangle(northwestTileCoordinates.x, northwestTileCoordinates.y, imageryLevel);
  135089. var clippedImageryRectangle = Rectangle.intersection(imageryRectangle, imageryBounds, clippedRectangleScratch);
  135090. var imageryTileXYToRectangle;
  135091. if (useWebMercatorT) {
  135092. imageryTilingScheme.rectangleToNativeRectangle(terrainRectangle, terrainRectangle);
  135093. imageryTilingScheme.rectangleToNativeRectangle(imageryRectangle, imageryRectangle);
  135094. imageryTilingScheme.rectangleToNativeRectangle(clippedImageryRectangle, clippedImageryRectangle);
  135095. imageryTilingScheme.rectangleToNativeRectangle(imageryBounds, imageryBounds);
  135096. imageryTileXYToRectangle = imageryTilingScheme.tileXYToNativeRectangle.bind(imageryTilingScheme);
  135097. veryCloseX = terrainRectangle.width / 512.0;
  135098. veryCloseY = terrainRectangle.height / 512.0;
  135099. } else {
  135100. imageryTileXYToRectangle = imageryTilingScheme.tileXYToRectangle.bind(imageryTilingScheme);
  135101. }
  135102. var minU;
  135103. var maxU = 0.0;
  135104. var minV = 1.0;
  135105. var maxV;
  135106. // If this is the northern-most or western-most tile in the imagery tiling scheme,
  135107. // it may not start at the northern or western edge of the terrain tile.
  135108. // Calculate where it does start.
  135109. if (!this.isBaseLayer() && Math.abs(clippedImageryRectangle.west - terrainRectangle.west) >= veryCloseX) {
  135110. maxU = Math.min(1.0, (clippedImageryRectangle.west - terrainRectangle.west) / terrainRectangle.width);
  135111. }
  135112. if (!this.isBaseLayer() && Math.abs(clippedImageryRectangle.north - terrainRectangle.north) >= veryCloseY) {
  135113. minV = Math.max(0.0, (clippedImageryRectangle.north - terrainRectangle.south) / terrainRectangle.height);
  135114. }
  135115. var initialMinV = minV;
  135116. for ( var i = northwestTileCoordinates.x; i <= southeastTileCoordinates.x; i++) {
  135117. minU = maxU;
  135118. imageryRectangle = imageryTileXYToRectangle(i, northwestTileCoordinates.y, imageryLevel);
  135119. clippedImageryRectangle = Rectangle.simpleIntersection(imageryRectangle, imageryBounds, clippedRectangleScratch);
  135120. if (!defined(clippedImageryRectangle)) {
  135121. continue;
  135122. }
  135123. maxU = Math.min(1.0, (clippedImageryRectangle.east - terrainRectangle.west) / terrainRectangle.width);
  135124. // If this is the eastern-most imagery tile mapped to this terrain tile,
  135125. // and there are more imagery tiles to the east of this one, the maxU
  135126. // should be 1.0 to make sure rounding errors don't make the last
  135127. // image fall shy of the edge of the terrain tile.
  135128. if (i === southeastTileCoordinates.x && (this.isBaseLayer() || Math.abs(clippedImageryRectangle.east - terrainRectangle.east) < veryCloseX)) {
  135129. maxU = 1.0;
  135130. }
  135131. minV = initialMinV;
  135132. for ( var j = northwestTileCoordinates.y; j <= southeastTileCoordinates.y; j++) {
  135133. maxV = minV;
  135134. imageryRectangle = imageryTileXYToRectangle(i, j, imageryLevel);
  135135. clippedImageryRectangle = Rectangle.simpleIntersection(imageryRectangle, imageryBounds, clippedRectangleScratch);
  135136. if (!defined(clippedImageryRectangle)) {
  135137. continue;
  135138. }
  135139. minV = Math.max(0.0, (clippedImageryRectangle.south - terrainRectangle.south) / terrainRectangle.height);
  135140. // If this is the southern-most imagery tile mapped to this terrain tile,
  135141. // and there are more imagery tiles to the south of this one, the minV
  135142. // should be 0.0 to make sure rounding errors don't make the last
  135143. // image fall shy of the edge of the terrain tile.
  135144. if (j === southeastTileCoordinates.y && (this.isBaseLayer() || Math.abs(clippedImageryRectangle.south - terrainRectangle.south) < veryCloseY)) {
  135145. minV = 0.0;
  135146. }
  135147. var texCoordsRectangle = new Cartesian4(minU, minV, maxU, maxV);
  135148. var imagery = this.getImageryFromCache(i, j, imageryLevel);
  135149. surfaceTile.imagery.splice(insertionPoint, 0, new TileImagery(imagery, texCoordsRectangle, useWebMercatorT));
  135150. ++insertionPoint;
  135151. }
  135152. }
  135153. return true;
  135154. };
  135155. /**
  135156. * Calculate the translation and scale for a particular {@link TileImagery} attached to a
  135157. * particular terrain tile.
  135158. *
  135159. * @private
  135160. *
  135161. * @param {Tile} tile The terrain tile.
  135162. * @param {TileImagery} tileImagery The imagery tile mapping.
  135163. * @returns {Cartesian4} The translation and scale where X and Y are the translation and Z and W
  135164. * are the scale.
  135165. */
  135166. ImageryLayer.prototype._calculateTextureTranslationAndScale = function(tile, tileImagery) {
  135167. var imageryRectangle = tileImagery.readyImagery.rectangle;
  135168. var terrainRectangle = tile.rectangle;
  135169. if (tileImagery.useWebMercatorT) {
  135170. var tilingScheme = tileImagery.readyImagery.imageryLayer.imageryProvider.tilingScheme;
  135171. imageryRectangle = tilingScheme.rectangleToNativeRectangle(imageryRectangle, imageryBoundsScratch);
  135172. terrainRectangle = tilingScheme.rectangleToNativeRectangle(terrainRectangle, terrainRectangleScratch);
  135173. }
  135174. var terrainWidth = terrainRectangle.width;
  135175. var terrainHeight = terrainRectangle.height;
  135176. var scaleX = terrainWidth / imageryRectangle.width;
  135177. var scaleY = terrainHeight / imageryRectangle.height;
  135178. return new Cartesian4(
  135179. scaleX * (terrainRectangle.west - imageryRectangle.west) / terrainWidth,
  135180. scaleY * (terrainRectangle.south - imageryRectangle.south) / terrainHeight,
  135181. scaleX,
  135182. scaleY);
  135183. };
  135184. /**
  135185. * Request a particular piece of imagery from the imagery provider. This method handles raising an
  135186. * error event if the request fails, and retrying the request if necessary.
  135187. *
  135188. * @private
  135189. *
  135190. * @param {Imagery} imagery The imagery to request.
  135191. */
  135192. ImageryLayer.prototype._requestImagery = function(imagery) {
  135193. var imageryProvider = this._imageryProvider;
  135194. var that = this;
  135195. function success(image) {
  135196. if (!defined(image)) {
  135197. return failure();
  135198. }
  135199. imagery.image = image;
  135200. imagery.state = ImageryState.RECEIVED;
  135201. TileProviderError.handleSuccess(that._requestImageError);
  135202. }
  135203. function failure(e) {
  135204. // Initially assume failure. handleError may retry, in which case the state will
  135205. // change to TRANSITIONING.
  135206. imagery.state = ImageryState.FAILED;
  135207. var message = 'Failed to obtain image tile X: ' + imagery.x + ' Y: ' + imagery.y + ' Level: ' + imagery.level + '.';
  135208. that._requestImageError = TileProviderError.handleError(
  135209. that._requestImageError,
  135210. imageryProvider,
  135211. imageryProvider.errorEvent,
  135212. message,
  135213. imagery.x, imagery.y, imagery.level,
  135214. doRequest,
  135215. e);
  135216. }
  135217. function doRequest() {
  135218. imagery.state = ImageryState.TRANSITIONING;
  135219. var imagePromise = imageryProvider.requestImage(imagery.x, imagery.y, imagery.level);
  135220. if (!defined(imagePromise)) {
  135221. // Too many parallel requests, so postpone loading tile.
  135222. imagery.state = ImageryState.UNLOADED;
  135223. return;
  135224. }
  135225. if (defined(imageryProvider.getTileCredits)) {
  135226. imagery.credits = imageryProvider.getTileCredits(imagery.x, imagery.y, imagery.level);
  135227. }
  135228. when(imagePromise, success, failure);
  135229. }
  135230. doRequest();
  135231. };
  135232. /**
  135233. * Create a WebGL texture for a given {@link Imagery} instance.
  135234. *
  135235. * @private
  135236. *
  135237. * @param {Context} context The rendered context to use to create textures.
  135238. * @param {Imagery} imagery The imagery for which to create a texture.
  135239. */
  135240. ImageryLayer.prototype._createTexture = function(context, imagery) {
  135241. var imageryProvider = this._imageryProvider;
  135242. // If this imagery provider has a discard policy, use it to check if this
  135243. // image should be discarded.
  135244. if (defined(imageryProvider.tileDiscardPolicy)) {
  135245. var discardPolicy = imageryProvider.tileDiscardPolicy;
  135246. if (defined(discardPolicy)) {
  135247. // If the discard policy is not ready yet, transition back to the
  135248. // RECEIVED state and we'll try again next time.
  135249. if (!discardPolicy.isReady()) {
  135250. imagery.state = ImageryState.RECEIVED;
  135251. return;
  135252. }
  135253. // Mark discarded imagery tiles invalid. Parent imagery will be used instead.
  135254. if (discardPolicy.shouldDiscardImage(imagery.image)) {
  135255. imagery.state = ImageryState.INVALID;
  135256. return;
  135257. }
  135258. }
  135259. }
  135260. // Imagery does not need to be discarded, so upload it to WebGL.
  135261. var texture = new Texture({
  135262. context : context,
  135263. source : imagery.image,
  135264. pixelFormat : imageryProvider.hasAlphaChannel ? PixelFormat.RGBA : PixelFormat.RGB
  135265. });
  135266. if (imageryProvider.tilingScheme instanceof WebMercatorTilingScheme) {
  135267. imagery.textureWebMercator = texture;
  135268. } else {
  135269. imagery.texture = texture;
  135270. }
  135271. imagery.image = undefined;
  135272. imagery.state = ImageryState.TEXTURE_LOADED;
  135273. };
  135274. function finalizeReprojectTexture(imageryLayer, context, imagery, texture) {
  135275. // Use mipmaps if this texture has power-of-two dimensions.
  135276. if (CesiumMath.isPowerOfTwo(texture.width) && CesiumMath.isPowerOfTwo(texture.height)) {
  135277. var mipmapSampler = context.cache.imageryLayer_mipmapSampler;
  135278. if (!defined(mipmapSampler)) {
  135279. var maximumSupportedAnisotropy = ContextLimits.maximumTextureFilterAnisotropy;
  135280. mipmapSampler = context.cache.imageryLayer_mipmapSampler = new Sampler({
  135281. wrapS : TextureWrap.CLAMP_TO_EDGE,
  135282. wrapT : TextureWrap.CLAMP_TO_EDGE,
  135283. minificationFilter : TextureMinificationFilter.LINEAR_MIPMAP_LINEAR,
  135284. magnificationFilter : TextureMagnificationFilter.LINEAR,
  135285. maximumAnisotropy : Math.min(maximumSupportedAnisotropy, defaultValue(imageryLayer._maximumAnisotropy, maximumSupportedAnisotropy))
  135286. });
  135287. }
  135288. texture.generateMipmap(MipmapHint.NICEST);
  135289. texture.sampler = mipmapSampler;
  135290. } else {
  135291. var nonMipmapSampler = context.cache.imageryLayer_nonMipmapSampler;
  135292. if (!defined(nonMipmapSampler)) {
  135293. nonMipmapSampler = context.cache.imageryLayer_nonMipmapSampler = new Sampler({
  135294. wrapS : TextureWrap.CLAMP_TO_EDGE,
  135295. wrapT : TextureWrap.CLAMP_TO_EDGE,
  135296. minificationFilter : TextureMinificationFilter.LINEAR,
  135297. magnificationFilter : TextureMagnificationFilter.LINEAR
  135298. });
  135299. }
  135300. texture.sampler = nonMipmapSampler;
  135301. }
  135302. imagery.state = ImageryState.READY;
  135303. }
  135304. /**
  135305. * Enqueues a command re-projecting a texture to a {@link GeographicProjection} on the next update, if necessary, and generate
  135306. * mipmaps for the geographic texture.
  135307. *
  135308. * @private
  135309. *
  135310. * @param {FrameState} frameState The frameState.
  135311. * @param {Imagery} imagery The imagery instance to reproject.
  135312. * @param {Boolean} [needGeographicProjection=true] True to reproject to geographic, or false if Web Mercator is fine.
  135313. */
  135314. ImageryLayer.prototype._reprojectTexture = function(frameState, imagery, needGeographicProjection) {
  135315. var texture = imagery.textureWebMercator || imagery.texture;
  135316. var rectangle = imagery.rectangle;
  135317. var context = frameState.context;
  135318. needGeographicProjection = defaultValue(needGeographicProjection, true);
  135319. // Reproject this texture if it is not already in a geographic projection and
  135320. // the pixels are more than 1e-5 radians apart. The pixel spacing cutoff
  135321. // avoids precision problems in the reprojection transformation while making
  135322. // no noticeable difference in the georeferencing of the image.
  135323. if (needGeographicProjection &&
  135324. !(this._imageryProvider.tilingScheme instanceof GeographicTilingScheme) &&
  135325. rectangle.width / texture.width > 1e-5) {
  135326. var that = this;
  135327. imagery.addReference();
  135328. var computeCommand = new ComputeCommand({
  135329. persists : true,
  135330. owner : this,
  135331. // Update render resources right before execution instead of now.
  135332. // This allows different ImageryLayers to share the same vao and buffers.
  135333. preExecute : function(command) {
  135334. reprojectToGeographic(command, context, texture, imagery.rectangle);
  135335. },
  135336. postExecute : function(outputTexture) {
  135337. imagery.texture = outputTexture;
  135338. finalizeReprojectTexture(that, context, imagery, outputTexture);
  135339. imagery.releaseReference();
  135340. }
  135341. });
  135342. this._reprojectComputeCommands.push(computeCommand);
  135343. } else {
  135344. if (needGeographicProjection) {
  135345. imagery.texture = texture;
  135346. }
  135347. finalizeReprojectTexture(this, context, imagery, texture);
  135348. }
  135349. };
  135350. /**
  135351. * Updates frame state to execute any queued texture re-projections.
  135352. *
  135353. * @private
  135354. *
  135355. * @param {FrameState} frameState The frameState.
  135356. */
  135357. ImageryLayer.prototype.queueReprojectionCommands = function(frameState) {
  135358. var computeCommands = this._reprojectComputeCommands;
  135359. var length = computeCommands.length;
  135360. for (var i = 0; i < length; ++i) {
  135361. frameState.commandList.push(computeCommands[i]);
  135362. }
  135363. computeCommands.length = 0;
  135364. };
  135365. /**
  135366. * Cancels re-projection commands queued for the next frame.
  135367. *
  135368. * @private
  135369. */
  135370. ImageryLayer.prototype.cancelReprojections = function() {
  135371. this._reprojectComputeCommands.length = 0;
  135372. };
  135373. ImageryLayer.prototype.getImageryFromCache = function(x, y, level, imageryRectangle) {
  135374. var cacheKey = getImageryCacheKey(x, y, level);
  135375. var imagery = this._imageryCache[cacheKey];
  135376. if (!defined(imagery)) {
  135377. imagery = new Imagery(this, x, y, level, imageryRectangle);
  135378. this._imageryCache[cacheKey] = imagery;
  135379. }
  135380. imagery.addReference();
  135381. return imagery;
  135382. };
  135383. ImageryLayer.prototype.removeImageryFromCache = function(imagery) {
  135384. var cacheKey = getImageryCacheKey(imagery.x, imagery.y, imagery.level);
  135385. delete this._imageryCache[cacheKey];
  135386. };
  135387. function getImageryCacheKey(x, y, level) {
  135388. return JSON.stringify([x, y, level]);
  135389. }
  135390. var uniformMap = {
  135391. u_textureDimensions : function() {
  135392. return this.textureDimensions;
  135393. },
  135394. u_texture : function() {
  135395. return this.texture;
  135396. },
  135397. textureDimensions : new Cartesian2(),
  135398. texture : undefined
  135399. };
  135400. var float32ArrayScratch = FeatureDetection.supportsTypedArrays() ? new Float32Array(2 * 64) : undefined;
  135401. function reprojectToGeographic(command, context, texture, rectangle) {
  135402. // This function has gone through a number of iterations, because GPUs are awesome.
  135403. //
  135404. // Originally, we had a very simple vertex shader and computed the Web Mercator texture coordinates
  135405. // per-fragment in the fragment shader. That worked well, except on mobile devices, because
  135406. // fragment shaders have limited precision on many mobile devices. The result was smearing artifacts
  135407. // at medium zoom levels because different geographic texture coordinates would be reprojected to Web
  135408. // Mercator as the same value.
  135409. //
  135410. // Our solution was to reproject to Web Mercator in the vertex shader instead of the fragment shader.
  135411. // This required far more vertex data. With fragment shader reprojection, we only needed a single quad.
  135412. // But to achieve the same precision with vertex shader reprojection, we needed a vertex for each
  135413. // output pixel. So we used a grid of 256x256 vertices, because most of our imagery
  135414. // tiles are 256x256. Fortunately the grid could be created and uploaded to the GPU just once and
  135415. // re-used for all reprojections, so the performance was virtually unchanged from our original fragment
  135416. // shader approach. See https://github.com/AnalyticalGraphicsInc/cesium/pull/714.
  135417. //
  135418. // Over a year later, we noticed (https://github.com/AnalyticalGraphicsInc/cesium/issues/2110)
  135419. // that our reprojection code was creating a rare but severe artifact on some GPUs (Intel HD 4600
  135420. // for one). The problem was that the GLSL sin function on these GPUs had a discontinuity at fine scales in
  135421. // a few places.
  135422. //
  135423. // We solved this by implementing a more reliable sin function based on the CORDIC algorithm
  135424. // (https://github.com/AnalyticalGraphicsInc/cesium/pull/2111). Even though this was a fair
  135425. // amount of code to be executing per vertex, the performance seemed to be pretty good on most GPUs.
  135426. // Unfortunately, on some GPUs, the performance was absolutely terrible
  135427. // (https://github.com/AnalyticalGraphicsInc/cesium/issues/2258).
  135428. //
  135429. // So that brings us to our current solution, the one you see here. Effectively, we compute the Web
  135430. // Mercator texture coordinates on the CPU and store the T coordinate with each vertex (the S coordinate
  135431. // is the same in Geographic and Web Mercator). To make this faster, we reduced our reprojection mesh
  135432. // to be only 2 vertices wide and 64 vertices high. We should have reduced the width to 2 sooner,
  135433. // because the extra vertices weren't buying us anything. The height of 64 means we are technically
  135434. // doing a slightly less accurate reprojection than we were before, but we can't see the difference
  135435. // so it's worth the 4x speedup.
  135436. var reproject = context.cache.imageryLayer_reproject;
  135437. if (!defined(reproject)) {
  135438. reproject = context.cache.imageryLayer_reproject = {
  135439. vertexArray : undefined,
  135440. shaderProgram : undefined,
  135441. sampler : undefined,
  135442. destroy : function() {
  135443. if (defined(this.framebuffer)) {
  135444. this.framebuffer.destroy();
  135445. }
  135446. if (defined(this.vertexArray)) {
  135447. this.vertexArray.destroy();
  135448. }
  135449. if (defined(this.shaderProgram)) {
  135450. this.shaderProgram.destroy();
  135451. }
  135452. }
  135453. };
  135454. var positions = new Float32Array(2 * 64 * 2);
  135455. var index = 0;
  135456. for (var j = 0; j < 64; ++j) {
  135457. var y = j / 63.0;
  135458. positions[index++] = 0.0;
  135459. positions[index++] = y;
  135460. positions[index++] = 1.0;
  135461. positions[index++] = y;
  135462. }
  135463. var reprojectAttributeIndices = {
  135464. position : 0,
  135465. webMercatorT : 1
  135466. };
  135467. var indices = TerrainProvider.getRegularGridIndices(2, 64);
  135468. var indexBuffer = Buffer.createIndexBuffer({
  135469. context : context,
  135470. typedArray : indices,
  135471. usage : BufferUsage.STATIC_DRAW,
  135472. indexDatatype : IndexDatatype.UNSIGNED_SHORT
  135473. });
  135474. reproject.vertexArray = new VertexArray({
  135475. context : context,
  135476. attributes : [{
  135477. index : reprojectAttributeIndices.position,
  135478. vertexBuffer : Buffer.createVertexBuffer({
  135479. context : context,
  135480. typedArray : positions,
  135481. usage : BufferUsage.STATIC_DRAW
  135482. }),
  135483. componentsPerAttribute : 2
  135484. },{
  135485. index : reprojectAttributeIndices.webMercatorT,
  135486. vertexBuffer : Buffer.createVertexBuffer({
  135487. context : context,
  135488. sizeInBytes : 64 * 2 * 4,
  135489. usage : BufferUsage.STREAM_DRAW
  135490. }),
  135491. componentsPerAttribute : 1
  135492. }],
  135493. indexBuffer : indexBuffer
  135494. });
  135495. var vs = new ShaderSource({
  135496. sources : [ReprojectWebMercatorVS]
  135497. });
  135498. reproject.shaderProgram = ShaderProgram.fromCache({
  135499. context : context,
  135500. vertexShaderSource : vs,
  135501. fragmentShaderSource : ReprojectWebMercatorFS,
  135502. attributeLocations : reprojectAttributeIndices
  135503. });
  135504. reproject.sampler = new Sampler({
  135505. wrapS : TextureWrap.CLAMP_TO_EDGE,
  135506. wrapT : TextureWrap.CLAMP_TO_EDGE,
  135507. minificationFilter : TextureMinificationFilter.LINEAR,
  135508. magnificationFilter : TextureMagnificationFilter.LINEAR
  135509. });
  135510. }
  135511. texture.sampler = reproject.sampler;
  135512. var width = texture.width;
  135513. var height = texture.height;
  135514. uniformMap.textureDimensions.x = width;
  135515. uniformMap.textureDimensions.y = height;
  135516. uniformMap.texture = texture;
  135517. var sinLatitude = Math.sin(rectangle.south);
  135518. var southMercatorY = 0.5 * Math.log((1 + sinLatitude) / (1 - sinLatitude));
  135519. sinLatitude = Math.sin(rectangle.north);
  135520. var northMercatorY = 0.5 * Math.log((1 + sinLatitude) / (1 - sinLatitude));
  135521. var oneOverMercatorHeight = 1.0 / (northMercatorY - southMercatorY);
  135522. var outputTexture = new Texture({
  135523. context : context,
  135524. width : width,
  135525. height : height,
  135526. pixelFormat : texture.pixelFormat,
  135527. pixelDatatype : texture.pixelDatatype,
  135528. preMultiplyAlpha : texture.preMultiplyAlpha
  135529. });
  135530. // Allocate memory for the mipmaps. Failure to do this before rendering
  135531. // to the texture via the FBO, and calling generateMipmap later,
  135532. // will result in the texture appearing blank. I can't pretend to
  135533. // understand exactly why this is.
  135534. if (CesiumMath.isPowerOfTwo(width) && CesiumMath.isPowerOfTwo(height)) {
  135535. outputTexture.generateMipmap(MipmapHint.NICEST);
  135536. }
  135537. var south = rectangle.south;
  135538. var north = rectangle.north;
  135539. var webMercatorT = float32ArrayScratch;
  135540. var outputIndex = 0;
  135541. for (var webMercatorTIndex = 0; webMercatorTIndex < 64; ++webMercatorTIndex) {
  135542. var fraction = webMercatorTIndex / 63.0;
  135543. var latitude = CesiumMath.lerp(south, north, fraction);
  135544. sinLatitude = Math.sin(latitude);
  135545. var mercatorY = 0.5 * Math.log((1.0 + sinLatitude) / (1.0 - sinLatitude));
  135546. var mercatorFraction = (mercatorY - southMercatorY) * oneOverMercatorHeight;
  135547. webMercatorT[outputIndex++] = mercatorFraction;
  135548. webMercatorT[outputIndex++] = mercatorFraction;
  135549. }
  135550. reproject.vertexArray.getAttribute(1).vertexBuffer.copyFromArrayView(webMercatorT);
  135551. command.shaderProgram = reproject.shaderProgram;
  135552. command.outputTexture = outputTexture;
  135553. command.uniformMap = uniformMap;
  135554. command.vertexArray = reproject.vertexArray;
  135555. }
  135556. /**
  135557. * Gets the level with the specified world coordinate spacing between texels, or less.
  135558. *
  135559. * @param {Number} texelSpacing The texel spacing for which to find a corresponding level.
  135560. * @param {Number} latitudeClosestToEquator The latitude closest to the equator that we're concerned with.
  135561. * @returns {Number} The level with the specified texel spacing or less.
  135562. */
  135563. function getLevelWithMaximumTexelSpacing(layer, texelSpacing, latitudeClosestToEquator) {
  135564. // PERFORMANCE_IDEA: factor out the stuff that doesn't change.
  135565. var imageryProvider = layer._imageryProvider;
  135566. var tilingScheme = imageryProvider.tilingScheme;
  135567. var ellipsoid = tilingScheme.ellipsoid;
  135568. var latitudeFactor = !(layer._imageryProvider.tilingScheme instanceof GeographicTilingScheme) ? Math.cos(latitudeClosestToEquator) : 1.0;
  135569. var tilingSchemeRectangle = tilingScheme.rectangle;
  135570. var levelZeroMaximumTexelSpacing = ellipsoid.maximumRadius * tilingSchemeRectangle.width * latitudeFactor / (imageryProvider.tileWidth * tilingScheme.getNumberOfXTilesAtLevel(0));
  135571. var twoToTheLevelPower = levelZeroMaximumTexelSpacing / texelSpacing;
  135572. var level = Math.log(twoToTheLevelPower) / Math.log(2);
  135573. var rounded = Math.round(level);
  135574. return rounded | 0;
  135575. }
  135576. return ImageryLayer;
  135577. });
  135578. /*global define*/
  135579. define('Scene/GlobeSurfaceTileProvider',[
  135580. '../Core/BoundingSphere',
  135581. '../Core/BoxOutlineGeometry',
  135582. '../Core/Cartesian2',
  135583. '../Core/Cartesian3',
  135584. '../Core/Cartesian4',
  135585. '../Core/Color',
  135586. '../Core/ColorGeometryInstanceAttribute',
  135587. '../Core/defaultValue',
  135588. '../Core/defined',
  135589. '../Core/defineProperties',
  135590. '../Core/destroyObject',
  135591. '../Core/DeveloperError',
  135592. '../Core/Event',
  135593. '../Core/GeometryInstance',
  135594. '../Core/GeometryPipeline',
  135595. '../Core/IndexDatatype',
  135596. '../Core/Intersect',
  135597. '../Core/Math',
  135598. '../Core/Matrix4',
  135599. '../Core/OrientedBoundingBox',
  135600. '../Core/PrimitiveType',
  135601. '../Core/Rectangle',
  135602. '../Core/SphereOutlineGeometry',
  135603. '../Core/TerrainQuantization',
  135604. '../Core/Visibility',
  135605. '../Core/WebMercatorProjection',
  135606. '../Renderer/Buffer',
  135607. '../Renderer/BufferUsage',
  135608. '../Renderer/ContextLimits',
  135609. '../Renderer/DrawCommand',
  135610. '../Renderer/Pass',
  135611. '../Renderer/RenderState',
  135612. '../Renderer/VertexArray',
  135613. '../Scene/BlendingState',
  135614. '../Scene/DepthFunction',
  135615. '../Scene/PerInstanceColorAppearance',
  135616. '../Scene/Primitive',
  135617. './GlobeSurfaceTile',
  135618. './ImageryLayer',
  135619. './QuadtreeTileLoadState',
  135620. './SceneMode',
  135621. './ShadowMode'
  135622. ], function(
  135623. BoundingSphere,
  135624. BoxOutlineGeometry,
  135625. Cartesian2,
  135626. Cartesian3,
  135627. Cartesian4,
  135628. Color,
  135629. ColorGeometryInstanceAttribute,
  135630. defaultValue,
  135631. defined,
  135632. defineProperties,
  135633. destroyObject,
  135634. DeveloperError,
  135635. Event,
  135636. GeometryInstance,
  135637. GeometryPipeline,
  135638. IndexDatatype,
  135639. Intersect,
  135640. CesiumMath,
  135641. Matrix4,
  135642. OrientedBoundingBox,
  135643. PrimitiveType,
  135644. Rectangle,
  135645. SphereOutlineGeometry,
  135646. TerrainQuantization,
  135647. Visibility,
  135648. WebMercatorProjection,
  135649. Buffer,
  135650. BufferUsage,
  135651. ContextLimits,
  135652. DrawCommand,
  135653. Pass,
  135654. RenderState,
  135655. VertexArray,
  135656. BlendingState,
  135657. DepthFunction,
  135658. PerInstanceColorAppearance,
  135659. Primitive,
  135660. GlobeSurfaceTile,
  135661. ImageryLayer,
  135662. QuadtreeTileLoadState,
  135663. SceneMode,
  135664. ShadowMode) {
  135665. 'use strict';
  135666. /**
  135667. * Provides quadtree tiles representing the surface of the globe. This type is intended to be used
  135668. * with {@link QuadtreePrimitive}.
  135669. *
  135670. * @alias GlobeSurfaceTileProvider
  135671. * @constructor
  135672. *
  135673. * @param {TerrainProvider} options.terrainProvider The terrain provider that describes the surface geometry.
  135674. * @param {ImageryLayerCollection} option.imageryLayers The collection of imagery layers describing the shading of the surface.
  135675. * @param {GlobeSurfaceShaderSet} options.surfaceShaderSet The set of shaders used to render the surface.
  135676. *
  135677. * @private
  135678. */
  135679. function GlobeSurfaceTileProvider(options) {
  135680. if (!defined(options)) {
  135681. throw new DeveloperError('options is required.');
  135682. }
  135683. if (!defined(options.terrainProvider)) {
  135684. throw new DeveloperError('options.terrainProvider is required.');
  135685. } else if (!defined(options.imageryLayers)) {
  135686. throw new DeveloperError('options.imageryLayers is required.');
  135687. } else if (!defined(options.surfaceShaderSet)) {
  135688. throw new DeveloperError('options.surfaceShaderSet is required.');
  135689. }
  135690. this.lightingFadeOutDistance = 6500000.0;
  135691. this.lightingFadeInDistance = 9000000.0;
  135692. this.hasWaterMask = false;
  135693. this.oceanNormalMap = undefined;
  135694. this.zoomedOutOceanSpecularIntensity = 0.5;
  135695. this.enableLighting = false;
  135696. this.shadows = ShadowMode.RECEIVE_ONLY;
  135697. this._quadtree = undefined;
  135698. this._terrainProvider = options.terrainProvider;
  135699. this._imageryLayers = options.imageryLayers;
  135700. this._surfaceShaderSet = options.surfaceShaderSet;
  135701. this._renderState = undefined;
  135702. this._blendRenderState = undefined;
  135703. this._pickRenderState = undefined;
  135704. this._errorEvent = new Event();
  135705. this._imageryLayers.layerAdded.addEventListener(GlobeSurfaceTileProvider.prototype._onLayerAdded, this);
  135706. this._imageryLayers.layerRemoved.addEventListener(GlobeSurfaceTileProvider.prototype._onLayerRemoved, this);
  135707. this._imageryLayers.layerMoved.addEventListener(GlobeSurfaceTileProvider.prototype._onLayerMoved, this);
  135708. this._imageryLayers.layerShownOrHidden.addEventListener(GlobeSurfaceTileProvider.prototype._onLayerShownOrHidden, this);
  135709. this._layerOrderChanged = false;
  135710. this._tilesToRenderByTextureCount = [];
  135711. this._drawCommands = [];
  135712. this._uniformMaps = [];
  135713. this._pickCommands = [];
  135714. this._usedDrawCommands = 0;
  135715. this._usedPickCommands = 0;
  135716. this._vertexArraysToDestroy = [];
  135717. this._debug = {
  135718. wireframe : false,
  135719. boundingSphereTile : undefined
  135720. };
  135721. this._baseColor = undefined;
  135722. this._firstPassInitialColor = undefined;
  135723. this.baseColor = new Color(0.0, 0.0, 0.5, 1.0);
  135724. }
  135725. defineProperties(GlobeSurfaceTileProvider.prototype, {
  135726. /**
  135727. * Gets or sets the color of the globe when no imagery is available.
  135728. * @memberof GlobeSurfaceTileProvider.prototype
  135729. * @type {Color}
  135730. */
  135731. baseColor : {
  135732. get : function() {
  135733. return this._baseColor;
  135734. },
  135735. set : function(value) {
  135736. if (!defined(value)) {
  135737. throw new DeveloperError('value is required.');
  135738. }
  135739. this._baseColor = value;
  135740. this._firstPassInitialColor = Cartesian4.fromColor(value, this._firstPassInitialColor);
  135741. }
  135742. },
  135743. /**
  135744. * Gets or sets the {@link QuadtreePrimitive} for which this provider is
  135745. * providing tiles. This property may be undefined if the provider is not yet associated
  135746. * with a {@link QuadtreePrimitive}.
  135747. * @memberof GlobeSurfaceTileProvider.prototype
  135748. * @type {QuadtreePrimitive}
  135749. */
  135750. quadtree : {
  135751. get : function() {
  135752. return this._quadtree;
  135753. },
  135754. set : function(value) {
  135755. if (!defined(value)) {
  135756. throw new DeveloperError('value is required.');
  135757. }
  135758. this._quadtree = value;
  135759. }
  135760. },
  135761. /**
  135762. * Gets a value indicating whether or not the provider is ready for use.
  135763. * @memberof GlobeSurfaceTileProvider.prototype
  135764. * @type {Boolean}
  135765. */
  135766. ready : {
  135767. get : function() {
  135768. return this._terrainProvider.ready && (this._imageryLayers.length === 0 || this._imageryLayers.get(0).imageryProvider.ready);
  135769. }
  135770. },
  135771. /**
  135772. * Gets the tiling scheme used by the provider. This property should
  135773. * not be accessed before {@link GlobeSurfaceTileProvider#ready} returns true.
  135774. * @memberof GlobeSurfaceTileProvider.prototype
  135775. * @type {TilingScheme}
  135776. */
  135777. tilingScheme : {
  135778. get : function() {
  135779. return this._terrainProvider.tilingScheme;
  135780. }
  135781. },
  135782. /**
  135783. * Gets an event that is raised when the geometry provider encounters an asynchronous error. By subscribing
  135784. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  135785. * are passed an instance of {@link TileProviderError}.
  135786. * @memberof GlobeSurfaceTileProvider.prototype
  135787. * @type {Event}
  135788. */
  135789. errorEvent : {
  135790. get : function() {
  135791. return this._errorEvent;
  135792. }
  135793. },
  135794. /**
  135795. * Gets or sets the terrain provider that describes the surface geometry.
  135796. * @memberof GlobeSurfaceTileProvider.prototype
  135797. * @type {TerrainProvider}
  135798. */
  135799. terrainProvider : {
  135800. get : function() {
  135801. return this._terrainProvider;
  135802. },
  135803. set : function(terrainProvider) {
  135804. if (this._terrainProvider === terrainProvider) {
  135805. return;
  135806. }
  135807. if (!defined(terrainProvider)) {
  135808. throw new DeveloperError('terrainProvider is required.');
  135809. }
  135810. this._terrainProvider = terrainProvider;
  135811. if (defined(this._quadtree)) {
  135812. this._quadtree.invalidateAllTiles();
  135813. }
  135814. }
  135815. }
  135816. });
  135817. function sortTileImageryByLayerIndex(a, b) {
  135818. var aImagery = a.loadingImagery;
  135819. if (!defined(aImagery)) {
  135820. aImagery = a.readyImagery;
  135821. }
  135822. var bImagery = b.loadingImagery;
  135823. if (!defined(bImagery)) {
  135824. bImagery = b.readyImagery;
  135825. }
  135826. return aImagery.imageryLayer._layerIndex - bImagery.imageryLayer._layerIndex;
  135827. }
  135828. function freeVertexArray(vertexArray) {
  135829. var indexBuffer = vertexArray.indexBuffer;
  135830. vertexArray.destroy();
  135831. if (!indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) {
  135832. --indexBuffer.referenceCount;
  135833. if (indexBuffer.referenceCount === 0) {
  135834. indexBuffer.destroy();
  135835. }
  135836. }
  135837. }
  135838. /**
  135839. * Called at the beginning of each render frame, before {@link QuadtreeTileProvider#showTileThisFrame}
  135840. * @param {FrameState} frameState The frame state.
  135841. */
  135842. GlobeSurfaceTileProvider.prototype.initialize = function(frameState) {
  135843. var imageryLayers = this._imageryLayers;
  135844. // update collection: imagery indices, base layers, raise layer show/hide event
  135845. imageryLayers._update();
  135846. // update each layer for texture reprojection.
  135847. imageryLayers.queueReprojectionCommands(frameState);
  135848. if (this._layerOrderChanged) {
  135849. this._layerOrderChanged = false;
  135850. // Sort the TileImagery instances in each tile by the layer index.
  135851. this._quadtree.forEachLoadedTile(function(tile) {
  135852. tile.data.imagery.sort(sortTileImageryByLayerIndex);
  135853. });
  135854. }
  135855. // Add credits for terrain and imagery providers.
  135856. var creditDisplay = frameState.creditDisplay;
  135857. if (this._terrainProvider.ready && defined(this._terrainProvider.credit)) {
  135858. creditDisplay.addCredit(this._terrainProvider.credit);
  135859. }
  135860. for (var i = 0, len = imageryLayers.length; i < len; ++i) {
  135861. var imageryProvider = imageryLayers.get(i).imageryProvider;
  135862. if (imageryProvider.ready && defined(imageryProvider.credit)) {
  135863. creditDisplay.addCredit(imageryProvider.credit);
  135864. }
  135865. }
  135866. var vertexArraysToDestroy = this._vertexArraysToDestroy;
  135867. var length = vertexArraysToDestroy.length;
  135868. for (var j = 0; j < length; ++j) {
  135869. freeVertexArray(vertexArraysToDestroy[j]);
  135870. }
  135871. vertexArraysToDestroy.length = 0;
  135872. };
  135873. /**
  135874. * Called at the beginning of the update cycle for each render frame, before {@link QuadtreeTileProvider#showTileThisFrame}
  135875. * or any other functions.
  135876. *
  135877. * @param {FrameState} frameState The frame state.
  135878. */
  135879. GlobeSurfaceTileProvider.prototype.beginUpdate = function(frameState) {
  135880. var tilesToRenderByTextureCount = this._tilesToRenderByTextureCount;
  135881. for (var i = 0, len = tilesToRenderByTextureCount.length; i < len; ++i) {
  135882. var tiles = tilesToRenderByTextureCount[i];
  135883. if (defined(tiles)) {
  135884. tiles.length = 0;
  135885. }
  135886. }
  135887. this._usedDrawCommands = 0;
  135888. };
  135889. /**
  135890. * Called at the end of the update cycle for each render frame, after {@link QuadtreeTileProvider#showTileThisFrame}
  135891. * and any other functions.
  135892. *
  135893. * @param {FrameState} frameState The frame state.
  135894. */
  135895. GlobeSurfaceTileProvider.prototype.endUpdate = function(frameState) {
  135896. if (!defined(this._renderState)) {
  135897. this._renderState = RenderState.fromCache({ // Write color and depth
  135898. cull : {
  135899. enabled : true
  135900. },
  135901. depthTest : {
  135902. enabled : true,
  135903. func : DepthFunction.LESS
  135904. }
  135905. });
  135906. this._blendRenderState = RenderState.fromCache({ // Write color and depth
  135907. cull : {
  135908. enabled : true
  135909. },
  135910. depthTest : {
  135911. enabled : true,
  135912. func : DepthFunction.LESS_OR_EQUAL
  135913. },
  135914. blending : BlendingState.ALPHA_BLEND
  135915. });
  135916. }
  135917. // Add the tile render commands to the command list, sorted by texture count.
  135918. var tilesToRenderByTextureCount = this._tilesToRenderByTextureCount;
  135919. for (var textureCountIndex = 0, textureCountLength = tilesToRenderByTextureCount.length; textureCountIndex < textureCountLength; ++textureCountIndex) {
  135920. var tilesToRender = tilesToRenderByTextureCount[textureCountIndex];
  135921. if (!defined(tilesToRender)) {
  135922. continue;
  135923. }
  135924. for (var tileIndex = 0, tileLength = tilesToRender.length; tileIndex < tileLength; ++tileIndex) {
  135925. addDrawCommandsForTile(this, tilesToRender[tileIndex], frameState);
  135926. }
  135927. }
  135928. };
  135929. /**
  135930. * Adds draw commands for tiles rendered in the previous frame for a pick pass.
  135931. *
  135932. * @param {FrameState} frameState The frame state.
  135933. */
  135934. GlobeSurfaceTileProvider.prototype.updateForPick = function(frameState) {
  135935. if (!defined(this._pickRenderState)) {
  135936. this._pickRenderState = RenderState.fromCache({
  135937. colorMask : {
  135938. red : false,
  135939. green : false,
  135940. blue : false,
  135941. alpha : false
  135942. },
  135943. depthTest : {
  135944. enabled : true
  135945. }
  135946. });
  135947. }
  135948. this._usedPickCommands = 0;
  135949. var drawCommands = this._drawCommands;
  135950. // Add the tile pick commands from the tiles drawn last frame.
  135951. for (var i = 0, length = this._usedDrawCommands; i < length; ++i) {
  135952. addPickCommandsForTile(this, drawCommands[i], frameState);
  135953. }
  135954. };
  135955. /**
  135956. * Cancels any imagery re-projections in the queue.
  135957. */
  135958. GlobeSurfaceTileProvider.prototype.cancelReprojections = function() {
  135959. this._imageryLayers.cancelReprojections();
  135960. };
  135961. /**
  135962. * Gets the maximum geometric error allowed in a tile at a given level, in meters. This function should not be
  135963. * called before {@link GlobeSurfaceTileProvider#ready} returns true.
  135964. *
  135965. * @param {Number} level The tile level for which to get the maximum geometric error.
  135966. * @returns {Number} The maximum geometric error in meters.
  135967. */
  135968. GlobeSurfaceTileProvider.prototype.getLevelMaximumGeometricError = function(level) {
  135969. return this._terrainProvider.getLevelMaximumGeometricError(level);
  135970. };
  135971. /**
  135972. * Loads, or continues loading, a given tile. This function will continue to be called
  135973. * until {@link QuadtreeTile#state} is no longer {@link QuadtreeTileLoadState#LOADING}. This function should
  135974. * not be called before {@link GlobeSurfaceTileProvider#ready} returns true.
  135975. *
  135976. * @param {FrameState} frameState The frame state.
  135977. * @param {QuadtreeTile} tile The tile to load.
  135978. *
  135979. * @exception {DeveloperError} <code>loadTile</code> must not be called before the tile provider is ready.
  135980. */
  135981. GlobeSurfaceTileProvider.prototype.loadTile = function(frameState, tile) {
  135982. GlobeSurfaceTile.processStateMachine(tile, frameState, this._terrainProvider, this._imageryLayers, this._vertexArraysToDestroy);
  135983. };
  135984. var boundingSphereScratch = new BoundingSphere();
  135985. /**
  135986. * Determines the visibility of a given tile. The tile may be fully visible, partially visible, or not
  135987. * visible at all. Tiles that are renderable and are at least partially visible will be shown by a call
  135988. * to {@link GlobeSurfaceTileProvider#showTileThisFrame}.
  135989. *
  135990. * @param {QuadtreeTile} tile The tile instance.
  135991. * @param {FrameState} frameState The state information about the current frame.
  135992. * @param {QuadtreeOccluders} occluders The objects that may occlude this tile.
  135993. *
  135994. * @returns {Visibility} The visibility of the tile.
  135995. */
  135996. GlobeSurfaceTileProvider.prototype.computeTileVisibility = function(tile, frameState, occluders) {
  135997. var distance = this.computeDistanceToTile(tile, frameState);
  135998. tile._distance = distance;
  135999. if (frameState.fog.enabled) {
  136000. if (CesiumMath.fog(distance, frameState.fog.density) >= 1.0) {
  136001. // Tile is completely in fog so return that it is not visible.
  136002. return Visibility.NONE;
  136003. }
  136004. }
  136005. var surfaceTile = tile.data;
  136006. var cullingVolume = frameState.cullingVolume;
  136007. var boundingVolume = defaultValue(surfaceTile.orientedBoundingBox, surfaceTile.boundingSphere3D);
  136008. if (frameState.mode !== SceneMode.SCENE3D) {
  136009. boundingVolume = boundingSphereScratch;
  136010. BoundingSphere.fromRectangleWithHeights2D(tile.rectangle, frameState.mapProjection, surfaceTile.minimumHeight, surfaceTile.maximumHeight, boundingVolume);
  136011. Cartesian3.fromElements(boundingVolume.center.z, boundingVolume.center.x, boundingVolume.center.y, boundingVolume.center);
  136012. if (frameState.mode === SceneMode.MORPHING) {
  136013. boundingVolume = BoundingSphere.union(surfaceTile.boundingSphere3D, boundingVolume, boundingVolume);
  136014. }
  136015. }
  136016. var intersection = cullingVolume.computeVisibility(boundingVolume);
  136017. if (intersection === Intersect.OUTSIDE) {
  136018. return Visibility.NONE;
  136019. }
  136020. if (frameState.mode === SceneMode.SCENE3D) {
  136021. var occludeePointInScaledSpace = surfaceTile.occludeePointInScaledSpace;
  136022. if (!defined(occludeePointInScaledSpace)) {
  136023. return intersection;
  136024. }
  136025. if (occluders.ellipsoid.isScaledSpacePointVisible(occludeePointInScaledSpace)) {
  136026. return intersection;
  136027. }
  136028. return Visibility.NONE;
  136029. }
  136030. return intersection;
  136031. };
  136032. var modifiedModelViewScratch = new Matrix4();
  136033. var modifiedModelViewProjectionScratch = new Matrix4();
  136034. var tileRectangleScratch = new Cartesian4();
  136035. var rtcScratch = new Cartesian3();
  136036. var centerEyeScratch = new Cartesian3();
  136037. var southwestScratch = new Cartesian3();
  136038. var northeastScratch = new Cartesian3();
  136039. /**
  136040. * Shows a specified tile in this frame. The provider can cause the tile to be shown by adding
  136041. * render commands to the commandList, or use any other method as appropriate. The tile is not
  136042. * expected to be visible next frame as well, unless this method is called next frame, too.
  136043. *
  136044. * @param {Object} tile The tile instance.
  136045. * @param {FrameState} frameState The state information of the current rendering frame.
  136046. */
  136047. GlobeSurfaceTileProvider.prototype.showTileThisFrame = function(tile, frameState) {
  136048. var readyTextureCount = 0;
  136049. var tileImageryCollection = tile.data.imagery;
  136050. for (var i = 0, len = tileImageryCollection.length; i < len; ++i) {
  136051. var tileImagery = tileImageryCollection[i];
  136052. if (defined(tileImagery.readyImagery) && tileImagery.readyImagery.imageryLayer.alpha !== 0.0) {
  136053. ++readyTextureCount;
  136054. }
  136055. }
  136056. var tileSet = this._tilesToRenderByTextureCount[readyTextureCount];
  136057. if (!defined(tileSet)) {
  136058. tileSet = [];
  136059. this._tilesToRenderByTextureCount[readyTextureCount] = tileSet;
  136060. }
  136061. tileSet.push(tile);
  136062. var debug = this._debug;
  136063. ++debug.tilesRendered;
  136064. debug.texturesRendered += readyTextureCount;
  136065. };
  136066. /**
  136067. * Gets the distance from the camera to the closest point on the tile. This is used for level-of-detail selection.
  136068. *
  136069. * @param {QuadtreeTile} tile The tile instance.
  136070. * @param {FrameState} frameState The state information of the current rendering frame.
  136071. *
  136072. * @returns {Number} The distance from the camera to the closest point on the tile, in meters.
  136073. */
  136074. GlobeSurfaceTileProvider.prototype.computeDistanceToTile = function(tile, frameState) {
  136075. var surfaceTile = tile.data;
  136076. var tileBoundingBox = surfaceTile.tileBoundingBox;
  136077. return tileBoundingBox.distanceToCamera(frameState);
  136078. };
  136079. /**
  136080. * Returns true if this object was destroyed; otherwise, false.
  136081. * <br /><br />
  136082. * If this object was destroyed, it should not be used; calling any function other than
  136083. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  136084. *
  136085. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  136086. *
  136087. * @see GlobeSurfaceTileProvider#destroy
  136088. */
  136089. GlobeSurfaceTileProvider.prototype.isDestroyed = function() {
  136090. return false;
  136091. };
  136092. /**
  136093. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  136094. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  136095. * <br /><br />
  136096. * Once an object is destroyed, it should not be used; calling any function other than
  136097. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  136098. * assign the return value (<code>undefined</code>) to the object as done in the example.
  136099. *
  136100. * @returns {undefined}
  136101. *
  136102. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  136103. *
  136104. *
  136105. * @example
  136106. * provider = provider && provider();
  136107. *
  136108. * @see GlobeSurfaceTileProvider#isDestroyed
  136109. */
  136110. GlobeSurfaceTileProvider.prototype.destroy = function() {
  136111. this._tileProvider = this._tileProvider && this._tileProvider.destroy();
  136112. return destroyObject(this);
  136113. };
  136114. GlobeSurfaceTileProvider.prototype._onLayerAdded = function(layer, index) {
  136115. if (layer.show) {
  136116. var terrainProvider = this._terrainProvider;
  136117. // create TileImagerys for this layer for all previously loaded tiles
  136118. this._quadtree.forEachLoadedTile(function(tile) {
  136119. if (layer._createTileImagerySkeletons(tile, terrainProvider)) {
  136120. tile.state = QuadtreeTileLoadState.LOADING;
  136121. }
  136122. });
  136123. this._layerOrderChanged = true;
  136124. }
  136125. };
  136126. GlobeSurfaceTileProvider.prototype._onLayerRemoved = function(layer, index) {
  136127. // destroy TileImagerys for this layer for all previously loaded tiles
  136128. this._quadtree.forEachLoadedTile(function(tile) {
  136129. var tileImageryCollection = tile.data.imagery;
  136130. var startIndex = -1;
  136131. var numDestroyed = 0;
  136132. for (var i = 0, len = tileImageryCollection.length; i < len; ++i) {
  136133. var tileImagery = tileImageryCollection[i];
  136134. var imagery = tileImagery.loadingImagery;
  136135. if (!defined(imagery)) {
  136136. imagery = tileImagery.readyImagery;
  136137. }
  136138. if (imagery.imageryLayer === layer) {
  136139. if (startIndex === -1) {
  136140. startIndex = i;
  136141. }
  136142. tileImagery.freeResources();
  136143. ++numDestroyed;
  136144. } else if (startIndex !== -1) {
  136145. // iterated past the section of TileImagerys belonging to this layer, no need to continue.
  136146. break;
  136147. }
  136148. }
  136149. if (startIndex !== -1) {
  136150. tileImageryCollection.splice(startIndex, numDestroyed);
  136151. }
  136152. });
  136153. };
  136154. GlobeSurfaceTileProvider.prototype._onLayerMoved = function(layer, newIndex, oldIndex) {
  136155. this._layerOrderChanged = true;
  136156. };
  136157. GlobeSurfaceTileProvider.prototype._onLayerShownOrHidden = function(layer, index, show) {
  136158. if (show) {
  136159. this._onLayerAdded(layer, index);
  136160. } else {
  136161. this._onLayerRemoved(layer, index);
  136162. }
  136163. };
  136164. function createTileUniformMap(frameState) {
  136165. var uniformMap = {
  136166. u_initialColor : function() {
  136167. return this.properties.initialColor;
  136168. },
  136169. u_zoomedOutOceanSpecularIntensity : function() {
  136170. return this.properties.zoomedOutOceanSpecularIntensity;
  136171. },
  136172. u_oceanNormalMap : function() {
  136173. return this.properties.oceanNormalMap;
  136174. },
  136175. u_lightingFadeDistance : function() {
  136176. return this.properties.lightingFadeDistance;
  136177. },
  136178. u_center3D : function() {
  136179. return this.properties.center3D;
  136180. },
  136181. u_tileRectangle : function() {
  136182. return this.properties.tileRectangle;
  136183. },
  136184. u_modifiedModelView : function() {
  136185. var viewMatrix = frameState.context.uniformState.view;
  136186. var centerEye = Matrix4.multiplyByPoint(viewMatrix, this.properties.rtc, centerEyeScratch);
  136187. Matrix4.setTranslation(viewMatrix, centerEye, modifiedModelViewScratch);
  136188. return modifiedModelViewScratch;
  136189. },
  136190. u_modifiedModelViewProjection : function() {
  136191. var viewMatrix = frameState.context.uniformState.view;
  136192. var projectionMatrix = frameState.context.uniformState.projection;
  136193. var centerEye = Matrix4.multiplyByPoint(viewMatrix, this.properties.rtc, centerEyeScratch);
  136194. Matrix4.setTranslation(viewMatrix, centerEye, modifiedModelViewProjectionScratch);
  136195. Matrix4.multiply(projectionMatrix, modifiedModelViewProjectionScratch, modifiedModelViewProjectionScratch);
  136196. return modifiedModelViewProjectionScratch;
  136197. },
  136198. u_dayTextures : function() {
  136199. return this.properties.dayTextures;
  136200. },
  136201. u_dayTextureTranslationAndScale : function() {
  136202. return this.properties.dayTextureTranslationAndScale;
  136203. },
  136204. u_dayTextureTexCoordsRectangle : function() {
  136205. return this.properties.dayTextureTexCoordsRectangle;
  136206. },
  136207. u_dayTextureUseWebMercatorT : function() {
  136208. return this.properties.dayTextureUseWebMercatorT;
  136209. },
  136210. u_dayTextureAlpha : function() {
  136211. return this.properties.dayTextureAlpha;
  136212. },
  136213. u_dayTextureBrightness : function() {
  136214. return this.properties.dayTextureBrightness;
  136215. },
  136216. u_dayTextureContrast : function() {
  136217. return this.properties.dayTextureContrast;
  136218. },
  136219. u_dayTextureHue : function() {
  136220. return this.properties.dayTextureHue;
  136221. },
  136222. u_dayTextureSaturation : function() {
  136223. return this.properties.dayTextureSaturation;
  136224. },
  136225. u_dayTextureOneOverGamma : function() {
  136226. return this.properties.dayTextureOneOverGamma;
  136227. },
  136228. u_dayIntensity : function() {
  136229. return this.properties.dayIntensity;
  136230. },
  136231. u_southAndNorthLatitude : function() {
  136232. return this.properties.southAndNorthLatitude;
  136233. },
  136234. u_southMercatorYAndOneOverHeight : function() {
  136235. return this.properties.southMercatorYAndOneOverHeight;
  136236. },
  136237. u_waterMask : function() {
  136238. return this.properties.waterMask;
  136239. },
  136240. u_waterMaskTranslationAndScale : function() {
  136241. return this.properties.waterMaskTranslationAndScale;
  136242. },
  136243. u_minMaxHeight : function() {
  136244. return this.properties.minMaxHeight;
  136245. },
  136246. u_scaleAndBias : function() {
  136247. return this.properties.scaleAndBias;
  136248. },
  136249. // make a separate object so that changes to the properties are seen on
  136250. // derived commands that combine another uniform map with this one.
  136251. properties : {
  136252. initialColor : new Cartesian4(0.0, 0.0, 0.5, 1.0),
  136253. zoomedOutOceanSpecularIntensity : 0.5,
  136254. oceanNormalMap : undefined,
  136255. lightingFadeDistance : new Cartesian2(6500000.0, 9000000.0),
  136256. center3D : undefined,
  136257. rtc : new Cartesian3(),
  136258. modifiedModelView : new Matrix4(),
  136259. tileRectangle : new Cartesian4(),
  136260. dayTextures : [],
  136261. dayTextureTranslationAndScale : [],
  136262. dayTextureTexCoordsRectangle : [],
  136263. dayTextureUseWebMercatorT : [],
  136264. dayTextureAlpha : [],
  136265. dayTextureBrightness : [],
  136266. dayTextureContrast : [],
  136267. dayTextureHue : [],
  136268. dayTextureSaturation : [],
  136269. dayTextureOneOverGamma : [],
  136270. dayIntensity : 0.0,
  136271. southAndNorthLatitude : new Cartesian2(),
  136272. southMercatorYAndOneOverHeight : new Cartesian2(),
  136273. waterMask : undefined,
  136274. waterMaskTranslationAndScale : new Cartesian4(),
  136275. minMaxHeight : new Cartesian2(),
  136276. scaleAndBias : new Matrix4()
  136277. }
  136278. };
  136279. return uniformMap;
  136280. }
  136281. function createWireframeVertexArrayIfNecessary(context, provider, tile) {
  136282. var surfaceTile = tile.data;
  136283. if (defined(surfaceTile.wireframeVertexArray)) {
  136284. return;
  136285. }
  136286. if (!defined(surfaceTile.terrainData) || !defined(surfaceTile.terrainData._mesh)) {
  136287. return;
  136288. }
  136289. surfaceTile.wireframeVertexArray = createWireframeVertexArray(context, surfaceTile.vertexArray, surfaceTile.terrainData._mesh);
  136290. }
  136291. /**
  136292. * Creates a vertex array for wireframe rendering of a terrain tile.
  136293. *
  136294. * @private
  136295. *
  136296. * @param {Context} context The context in which to create the vertex array.
  136297. * @param {VertexArray} vertexArray The existing, non-wireframe vertex array. The new vertex array
  136298. * will share vertex buffers with this existing one.
  136299. * @param {TerrainMesh} terrainMesh The terrain mesh containing non-wireframe indices.
  136300. * @returns {VertexArray} The vertex array for wireframe rendering.
  136301. */
  136302. function createWireframeVertexArray(context, vertexArray, terrainMesh) {
  136303. var geometry = {
  136304. indices : terrainMesh.indices,
  136305. primitiveType : PrimitiveType.TRIANGLES
  136306. };
  136307. GeometryPipeline.toWireframe(geometry);
  136308. var wireframeIndices = geometry.indices;
  136309. var wireframeIndexBuffer = Buffer.createIndexBuffer({
  136310. context : context,
  136311. typedArray : wireframeIndices,
  136312. usage : BufferUsage.STATIC_DRAW,
  136313. indexDatatype : IndexDatatype.UNSIGNED_SHORT
  136314. });
  136315. return new VertexArray({
  136316. context : context,
  136317. attributes : vertexArray._attributes,
  136318. indexBuffer : wireframeIndexBuffer
  136319. });
  136320. }
  136321. var getDebugOrientedBoundingBox;
  136322. var getDebugBoundingSphere;
  136323. var debugDestroyPrimitive;
  136324. (function() {
  136325. var instanceOBB = new GeometryInstance({
  136326. geometry: BoxOutlineGeometry.fromDimensions({ dimensions: new Cartesian3(2.0, 2.0, 2.0) })
  136327. });
  136328. var instanceSphere = new GeometryInstance({
  136329. geometry: new SphereOutlineGeometry({ radius: 1.0 })
  136330. });
  136331. var modelMatrix = new Matrix4();
  136332. var previousVolume;
  136333. var primitive;
  136334. function createDebugPrimitive(instance) {
  136335. return new Primitive({
  136336. geometryInstances : instance,
  136337. appearance : new PerInstanceColorAppearance({
  136338. translucent : false,
  136339. flat : true
  136340. }),
  136341. asynchronous : false
  136342. });
  136343. }
  136344. getDebugOrientedBoundingBox = function(obb, color) {
  136345. if (obb === previousVolume) {
  136346. return primitive;
  136347. }
  136348. debugDestroyPrimitive();
  136349. previousVolume = obb;
  136350. modelMatrix = Matrix4.fromRotationTranslation(obb.halfAxes, obb.center, modelMatrix);
  136351. instanceOBB.modelMatrix = modelMatrix;
  136352. instanceOBB.attributes.color = ColorGeometryInstanceAttribute.fromColor(color);
  136353. primitive = createDebugPrimitive(instanceOBB);
  136354. return primitive;
  136355. };
  136356. getDebugBoundingSphere = function(sphere, color) {
  136357. if (sphere === previousVolume) {
  136358. return primitive;
  136359. }
  136360. debugDestroyPrimitive();
  136361. previousVolume = sphere;
  136362. modelMatrix = Matrix4.fromTranslation(sphere.center, modelMatrix);
  136363. modelMatrix = Matrix4.multiplyByUniformScale(modelMatrix, sphere.radius, modelMatrix);
  136364. instanceSphere.modelMatrix = modelMatrix;
  136365. instanceSphere.attributes.color = ColorGeometryInstanceAttribute.fromColor(color);
  136366. primitive = createDebugPrimitive(instanceSphere);
  136367. return primitive;
  136368. };
  136369. debugDestroyPrimitive = function() {
  136370. if (defined(primitive)) {
  136371. primitive.destroy();
  136372. primitive = undefined;
  136373. previousVolume = undefined;
  136374. }
  136375. };
  136376. })();
  136377. var otherPassesInitialColor = new Cartesian4(0.0, 0.0, 0.0, 0.0);
  136378. function addDrawCommandsForTile(tileProvider, tile, frameState) {
  136379. var surfaceTile = tile.data;
  136380. var maxTextures = ContextLimits.maximumTextureImageUnits;
  136381. var waterMaskTexture = surfaceTile.waterMaskTexture;
  136382. var showReflectiveOcean = tileProvider.hasWaterMask && defined(waterMaskTexture);
  136383. var oceanNormalMap = tileProvider.oceanNormalMap;
  136384. var showOceanWaves = showReflectiveOcean && defined(oceanNormalMap);
  136385. var hasVertexNormals = tileProvider.terrainProvider.ready && tileProvider.terrainProvider.hasVertexNormals;
  136386. var enableFog = frameState.fog.enabled;
  136387. var castShadows = ShadowMode.castShadows(tileProvider.shadows);
  136388. var receiveShadows = ShadowMode.receiveShadows(tileProvider.shadows);
  136389. if (showReflectiveOcean) {
  136390. --maxTextures;
  136391. }
  136392. if (showOceanWaves) {
  136393. --maxTextures;
  136394. }
  136395. var rtc = surfaceTile.center;
  136396. var encoding = surfaceTile.pickTerrain.mesh.encoding;
  136397. // Not used in 3D.
  136398. var tileRectangle = tileRectangleScratch;
  136399. // Only used for Mercator projections.
  136400. var southLatitude = 0.0;
  136401. var northLatitude = 0.0;
  136402. var southMercatorY = 0.0;
  136403. var oneOverMercatorHeight = 0.0;
  136404. var useWebMercatorProjection = false;
  136405. if (frameState.mode !== SceneMode.SCENE3D) {
  136406. var projection = frameState.mapProjection;
  136407. var southwest = projection.project(Rectangle.southwest(tile.rectangle), southwestScratch);
  136408. var northeast = projection.project(Rectangle.northeast(tile.rectangle), northeastScratch);
  136409. tileRectangle.x = southwest.x;
  136410. tileRectangle.y = southwest.y;
  136411. tileRectangle.z = northeast.x;
  136412. tileRectangle.w = northeast.y;
  136413. // In 2D and Columbus View, use the center of the tile for RTC rendering.
  136414. if (frameState.mode !== SceneMode.MORPHING) {
  136415. rtc = rtcScratch;
  136416. rtc.x = 0.0;
  136417. rtc.y = (tileRectangle.z + tileRectangle.x) * 0.5;
  136418. rtc.z = (tileRectangle.w + tileRectangle.y) * 0.5;
  136419. tileRectangle.x -= rtc.y;
  136420. tileRectangle.y -= rtc.z;
  136421. tileRectangle.z -= rtc.y;
  136422. tileRectangle.w -= rtc.z;
  136423. }
  136424. if (frameState.mode === SceneMode.SCENE2D && encoding.quantization === TerrainQuantization.BITS12) {
  136425. // In 2D, the texture coordinates of the tile are interpolated over the rectangle to get the position in the vertex shader.
  136426. // When the texture coordinates are quantized, error is introduced. This can be seen through the 1px wide cracking
  136427. // between the quantized tiles in 2D. To compensate for the error, move the expand the rectangle in each direction by
  136428. // half the error amount.
  136429. var epsilon = (1.0 / (Math.pow(2.0, 12.0) - 1.0)) * 0.5;
  136430. var widthEpsilon = (tileRectangle.z - tileRectangle.x) * epsilon;
  136431. var heightEpsilon = (tileRectangle.w - tileRectangle.y) * epsilon;
  136432. tileRectangle.x -= widthEpsilon;
  136433. tileRectangle.y -= heightEpsilon;
  136434. tileRectangle.z += widthEpsilon;
  136435. tileRectangle.w += heightEpsilon;
  136436. }
  136437. if (projection instanceof WebMercatorProjection) {
  136438. southLatitude = tile.rectangle.south;
  136439. northLatitude = tile.rectangle.north;
  136440. southMercatorY = WebMercatorProjection.geodeticLatitudeToMercatorAngle(southLatitude);
  136441. oneOverMercatorHeight = 1.0 / (WebMercatorProjection.geodeticLatitudeToMercatorAngle(northLatitude) - southMercatorY);
  136442. useWebMercatorProjection = true;
  136443. }
  136444. }
  136445. var tileImageryCollection = surfaceTile.imagery;
  136446. var imageryIndex = 0;
  136447. var imageryLen = tileImageryCollection.length;
  136448. var firstPassRenderState = tileProvider._renderState;
  136449. var otherPassesRenderState = tileProvider._blendRenderState;
  136450. var renderState = firstPassRenderState;
  136451. var initialColor = tileProvider._firstPassInitialColor;
  136452. var context = frameState.context;
  136453. if (!defined(tileProvider._debug.boundingSphereTile)) {
  136454. debugDestroyPrimitive();
  136455. }
  136456. do {
  136457. var numberOfDayTextures = 0;
  136458. var command;
  136459. var uniformMap;
  136460. if (tileProvider._drawCommands.length <= tileProvider._usedDrawCommands) {
  136461. command = new DrawCommand();
  136462. command.owner = tile;
  136463. command.cull = false;
  136464. command.boundingVolume = new BoundingSphere();
  136465. command.orientedBoundingBox = undefined;
  136466. uniformMap = createTileUniformMap(frameState);
  136467. tileProvider._drawCommands.push(command);
  136468. tileProvider._uniformMaps.push(uniformMap);
  136469. } else {
  136470. command = tileProvider._drawCommands[tileProvider._usedDrawCommands];
  136471. uniformMap = tileProvider._uniformMaps[tileProvider._usedDrawCommands];
  136472. }
  136473. command.owner = tile;
  136474. ++tileProvider._usedDrawCommands;
  136475. if (tile === tileProvider._debug.boundingSphereTile) {
  136476. // If a debug primitive already exists for this tile, it will not be
  136477. // re-created, to avoid allocation every frame. If it were possible
  136478. // to have more than one selected tile, this would have to change.
  136479. if (defined(surfaceTile.orientedBoundingBox)) {
  136480. getDebugOrientedBoundingBox(surfaceTile.orientedBoundingBox, Color.RED).update(frameState);
  136481. } else if (defined(surfaceTile.boundingSphere3D)) {
  136482. getDebugBoundingSphere(surfaceTile.boundingSphere3D, Color.RED).update(frameState);
  136483. }
  136484. }
  136485. var uniformMapProperties = uniformMap.properties;
  136486. Cartesian4.clone(initialColor, uniformMapProperties.initialColor);
  136487. uniformMapProperties.oceanNormalMap = oceanNormalMap;
  136488. uniformMapProperties.lightingFadeDistance.x = tileProvider.lightingFadeOutDistance;
  136489. uniformMapProperties.lightingFadeDistance.y = tileProvider.lightingFadeInDistance;
  136490. uniformMapProperties.zoomedOutOceanSpecularIntensity = tileProvider.zoomedOutOceanSpecularIntensity;
  136491. uniformMapProperties.center3D = surfaceTile.center;
  136492. Cartesian3.clone(rtc, uniformMapProperties.rtc);
  136493. Cartesian4.clone(tileRectangle, uniformMapProperties.tileRectangle);
  136494. uniformMapProperties.southAndNorthLatitude.x = southLatitude;
  136495. uniformMapProperties.southAndNorthLatitude.y = northLatitude;
  136496. uniformMapProperties.southMercatorYAndOneOverHeight.x = southMercatorY;
  136497. uniformMapProperties.southMercatorYAndOneOverHeight.y = oneOverMercatorHeight;
  136498. // For performance, use fog in the shader only when the tile is in fog.
  136499. var applyFog = enableFog && CesiumMath.fog(tile._distance, frameState.fog.density) > CesiumMath.EPSILON3;
  136500. var applyBrightness = false;
  136501. var applyContrast = false;
  136502. var applyHue = false;
  136503. var applySaturation = false;
  136504. var applyGamma = false;
  136505. var applyAlpha = false;
  136506. while (numberOfDayTextures < maxTextures && imageryIndex < imageryLen) {
  136507. var tileImagery = tileImageryCollection[imageryIndex];
  136508. var imagery = tileImagery.readyImagery;
  136509. ++imageryIndex;
  136510. if (!defined(imagery) || imagery.imageryLayer.alpha === 0.0) {
  136511. continue;
  136512. }
  136513. var texture = tileImagery.useWebMercatorT ? imagery.textureWebMercator : imagery.texture;
  136514. if (!defined(texture)) {
  136515. // Our "ready" texture isn't actually ready. This should never happen.
  136516. //
  136517. // Side note: It IS possible for it to not be in the READY ImageryState, though.
  136518. // This can happen when a single imagery tile is shared by two terrain tiles (common)
  136519. // and one of them (A) needs a geographic version of the tile because it is near the poles,
  136520. // and the other (B) does not. B can and will transition the imagery tile to the READY state
  136521. // without reprojecting to geographic. Then, later, A will deem that same tile not-ready-yet
  136522. // because it only has the Web Mercator texture, and flip it back to the TRANSITIONING state.
  136523. // The imagery tile won't be in the READY state anymore, but it's still READY enough for B's
  136524. // purposes.
  136525. throw new DeveloperError('readyImagery is not actually ready!');
  136526. }
  136527. var imageryLayer = imagery.imageryLayer;
  136528. if (!defined(tileImagery.textureTranslationAndScale)) {
  136529. tileImagery.textureTranslationAndScale = imageryLayer._calculateTextureTranslationAndScale(tile, tileImagery);
  136530. }
  136531. uniformMapProperties.dayTextures[numberOfDayTextures] = texture;
  136532. uniformMapProperties.dayTextureTranslationAndScale[numberOfDayTextures] = tileImagery.textureTranslationAndScale;
  136533. uniformMapProperties.dayTextureTexCoordsRectangle[numberOfDayTextures] = tileImagery.textureCoordinateRectangle;
  136534. uniformMapProperties.dayTextureUseWebMercatorT[numberOfDayTextures] = tileImagery.useWebMercatorT;
  136535. uniformMapProperties.dayTextureAlpha[numberOfDayTextures] = imageryLayer.alpha;
  136536. applyAlpha = applyAlpha || uniformMapProperties.dayTextureAlpha[numberOfDayTextures] !== 1.0;
  136537. uniformMapProperties.dayTextureBrightness[numberOfDayTextures] = imageryLayer.brightness;
  136538. applyBrightness = applyBrightness || uniformMapProperties.dayTextureBrightness[numberOfDayTextures] !== ImageryLayer.DEFAULT_BRIGHTNESS;
  136539. uniformMapProperties.dayTextureContrast[numberOfDayTextures] = imageryLayer.contrast;
  136540. applyContrast = applyContrast || uniformMapProperties.dayTextureContrast[numberOfDayTextures] !== ImageryLayer.DEFAULT_CONTRAST;
  136541. uniformMapProperties.dayTextureHue[numberOfDayTextures] = imageryLayer.hue;
  136542. applyHue = applyHue || uniformMapProperties.dayTextureHue[numberOfDayTextures] !== ImageryLayer.DEFAULT_HUE;
  136543. uniformMapProperties.dayTextureSaturation[numberOfDayTextures] = imageryLayer.saturation;
  136544. applySaturation = applySaturation || uniformMapProperties.dayTextureSaturation[numberOfDayTextures] !== ImageryLayer.DEFAULT_SATURATION;
  136545. uniformMapProperties.dayTextureOneOverGamma[numberOfDayTextures] = 1.0 / imageryLayer.gamma;
  136546. applyGamma = applyGamma || uniformMapProperties.dayTextureOneOverGamma[numberOfDayTextures] !== 1.0 / ImageryLayer.DEFAULT_GAMMA;
  136547. if (defined(imagery.credits)) {
  136548. var creditDisplay = frameState.creditDisplay;
  136549. var credits = imagery.credits;
  136550. for (var creditIndex = 0, creditLength = credits.length; creditIndex < creditLength; ++creditIndex) {
  136551. creditDisplay.addCredit(credits[creditIndex]);
  136552. }
  136553. }
  136554. ++numberOfDayTextures;
  136555. }
  136556. // trim texture array to the used length so we don't end up using old textures
  136557. // which might get destroyed eventually
  136558. uniformMapProperties.dayTextures.length = numberOfDayTextures;
  136559. uniformMapProperties.waterMask = waterMaskTexture;
  136560. Cartesian4.clone(surfaceTile.waterMaskTranslationAndScale, uniformMapProperties.waterMaskTranslationAndScale);
  136561. uniformMapProperties.minMaxHeight.x = encoding.minimumHeight;
  136562. uniformMapProperties.minMaxHeight.y = encoding.maximumHeight;
  136563. Matrix4.clone(encoding.matrix, uniformMapProperties.scaleAndBias);
  136564. command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, applyFog);
  136565. command.castShadows = castShadows;
  136566. command.receiveShadows = receiveShadows;
  136567. command.renderState = renderState;
  136568. command.primitiveType = PrimitiveType.TRIANGLES;
  136569. command.vertexArray = surfaceTile.vertexArray;
  136570. command.uniformMap = uniformMap;
  136571. command.pass = Pass.GLOBE;
  136572. if (tileProvider._debug.wireframe) {
  136573. createWireframeVertexArrayIfNecessary(context, tileProvider, tile);
  136574. if (defined(surfaceTile.wireframeVertexArray)) {
  136575. command.vertexArray = surfaceTile.wireframeVertexArray;
  136576. command.primitiveType = PrimitiveType.LINES;
  136577. }
  136578. }
  136579. var boundingVolume = command.boundingVolume;
  136580. var orientedBoundingBox = command.orientedBoundingBox;
  136581. if (frameState.mode !== SceneMode.SCENE3D) {
  136582. BoundingSphere.fromRectangleWithHeights2D(tile.rectangle, frameState.mapProjection, surfaceTile.minimumHeight, surfaceTile.maximumHeight, boundingVolume);
  136583. Cartesian3.fromElements(boundingVolume.center.z, boundingVolume.center.x, boundingVolume.center.y, boundingVolume.center);
  136584. if (frameState.mode === SceneMode.MORPHING) {
  136585. boundingVolume = BoundingSphere.union(surfaceTile.boundingSphere3D, boundingVolume, boundingVolume);
  136586. }
  136587. } else {
  136588. command.boundingVolume = BoundingSphere.clone(surfaceTile.boundingSphere3D, boundingVolume);
  136589. command.orientedBoundingBox = OrientedBoundingBox.clone(surfaceTile.orientedBoundingBox, orientedBoundingBox);
  136590. }
  136591. frameState.commandList.push(command);
  136592. renderState = otherPassesRenderState;
  136593. initialColor = otherPassesInitialColor;
  136594. } while (imageryIndex < imageryLen);
  136595. }
  136596. function addPickCommandsForTile(tileProvider, drawCommand, frameState) {
  136597. var pickCommand;
  136598. if (tileProvider._pickCommands.length <= tileProvider._usedPickCommands) {
  136599. pickCommand = new DrawCommand();
  136600. pickCommand.cull = false;
  136601. tileProvider._pickCommands.push(pickCommand);
  136602. } else {
  136603. pickCommand = tileProvider._pickCommands[tileProvider._usedPickCommands];
  136604. }
  136605. ++tileProvider._usedPickCommands;
  136606. var surfaceTile = drawCommand.owner.data;
  136607. var useWebMercatorProjection = frameState.projection instanceof WebMercatorProjection;
  136608. pickCommand.shaderProgram = tileProvider._surfaceShaderSet.getPickShaderProgram(frameState, surfaceTile, useWebMercatorProjection);
  136609. pickCommand.renderState = tileProvider._pickRenderState;
  136610. pickCommand.owner = drawCommand.owner;
  136611. pickCommand.primitiveType = drawCommand.primitiveType;
  136612. pickCommand.vertexArray = drawCommand.vertexArray;
  136613. pickCommand.uniformMap = drawCommand.uniformMap;
  136614. pickCommand.boundingVolume = drawCommand.boundingVolume;
  136615. pickCommand.orientedBoundingBox = drawCommand.orientedBoundingBox;
  136616. pickCommand.pass = drawCommand.pass;
  136617. frameState.commandList.push(pickCommand);
  136618. }
  136619. return GlobeSurfaceTileProvider;
  136620. });
  136621. /*global define*/
  136622. define('Scene/ImageryLayerCollection',[
  136623. '../Core/defaultValue',
  136624. '../Core/defined',
  136625. '../Core/defineProperties',
  136626. '../Core/destroyObject',
  136627. '../Core/DeveloperError',
  136628. '../Core/Event',
  136629. '../Core/Math',
  136630. '../Core/Rectangle',
  136631. '../ThirdParty/when',
  136632. './ImageryLayer'
  136633. ], function(
  136634. defaultValue,
  136635. defined,
  136636. defineProperties,
  136637. destroyObject,
  136638. DeveloperError,
  136639. Event,
  136640. CesiumMath,
  136641. Rectangle,
  136642. when,
  136643. ImageryLayer) {
  136644. 'use strict';
  136645. /**
  136646. * An ordered collection of imagery layers.
  136647. *
  136648. * @alias ImageryLayerCollection
  136649. * @constructor
  136650. *
  136651. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Imagery%20Adjustment.html|Cesium Sandcastle Imagery Adjustment Demo}
  136652. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Imagery%20Layers%20Manipulation.html|Cesium Sandcastle Imagery Manipulation Demo}
  136653. */
  136654. function ImageryLayerCollection() {
  136655. this._layers = [];
  136656. /**
  136657. * An event that is raised when a layer is added to the collection. Event handlers are passed the layer that
  136658. * was added and the index at which it was added.
  136659. * @type {Event}
  136660. * @default Event()
  136661. */
  136662. this.layerAdded = new Event();
  136663. /**
  136664. * An event that is raised when a layer is removed from the collection. Event handlers are passed the layer that
  136665. * was removed and the index from which it was removed.
  136666. * @type {Event}
  136667. * @default Event()
  136668. */
  136669. this.layerRemoved = new Event();
  136670. /**
  136671. * An event that is raised when a layer changes position in the collection. Event handlers are passed the layer that
  136672. * was moved, its new index after the move, and its old index prior to the move.
  136673. * @type {Event}
  136674. * @default Event()
  136675. */
  136676. this.layerMoved = new Event();
  136677. /**
  136678. * An event that is raised when a layer is shown or hidden by setting the
  136679. * {@link ImageryLayer#show} property. Event handlers are passed a reference to this layer,
  136680. * the index of the layer in the collection, and a flag that is true if the layer is now
  136681. * shown or false if it is now hidden.
  136682. *
  136683. * @type {Event}
  136684. * @default Event()
  136685. */
  136686. this.layerShownOrHidden = new Event();
  136687. }
  136688. defineProperties(ImageryLayerCollection.prototype, {
  136689. /**
  136690. * Gets the number of layers in this collection.
  136691. * @memberof ImageryLayerCollection.prototype
  136692. * @type {Number}
  136693. */
  136694. length : {
  136695. get : function() {
  136696. return this._layers.length;
  136697. }
  136698. }
  136699. });
  136700. /**
  136701. * Adds a layer to the collection.
  136702. *
  136703. * @param {ImageryLayer} layer the layer to add.
  136704. * @param {Number} [index] the index to add the layer at. If omitted, the layer will
  136705. * added on top of all existing layers.
  136706. *
  136707. * @exception {DeveloperError} index, if supplied, must be greater than or equal to zero and less than or equal to the number of the layers.
  136708. */
  136709. ImageryLayerCollection.prototype.add = function(layer, index) {
  136710. var hasIndex = defined(index);
  136711. if (!defined(layer)) {
  136712. throw new DeveloperError('layer is required.');
  136713. }
  136714. if (hasIndex) {
  136715. if (index < 0) {
  136716. throw new DeveloperError('index must be greater than or equal to zero.');
  136717. } else if (index > this._layers.length) {
  136718. throw new DeveloperError('index must be less than or equal to the number of layers.');
  136719. }
  136720. }
  136721. if (!hasIndex) {
  136722. index = this._layers.length;
  136723. this._layers.push(layer);
  136724. } else {
  136725. this._layers.splice(index, 0, layer);
  136726. }
  136727. this._update();
  136728. this.layerAdded.raiseEvent(layer, index);
  136729. };
  136730. /**
  136731. * Creates a new layer using the given ImageryProvider and adds it to the collection.
  136732. *
  136733. * @param {ImageryProvider} imageryProvider the imagery provider to create a new layer for.
  136734. * @param {Number} [index] the index to add the layer at. If omitted, the layer will
  136735. * added on top of all existing layers.
  136736. * @returns {ImageryLayer} The newly created layer.
  136737. */
  136738. ImageryLayerCollection.prototype.addImageryProvider = function(imageryProvider, index) {
  136739. if (!defined(imageryProvider)) {
  136740. throw new DeveloperError('imageryProvider is required.');
  136741. }
  136742. var layer = new ImageryLayer(imageryProvider);
  136743. this.add(layer, index);
  136744. return layer;
  136745. };
  136746. /**
  136747. * Removes a layer from this collection, if present.
  136748. *
  136749. * @param {ImageryLayer} layer The layer to remove.
  136750. * @param {Boolean} [destroy=true] whether to destroy the layers in addition to removing them.
  136751. * @returns {Boolean} true if the layer was in the collection and was removed,
  136752. * false if the layer was not in the collection.
  136753. */
  136754. ImageryLayerCollection.prototype.remove = function(layer, destroy) {
  136755. destroy = defaultValue(destroy, true);
  136756. var index = this._layers.indexOf(layer);
  136757. if (index !== -1) {
  136758. this._layers.splice(index, 1);
  136759. this._update();
  136760. this.layerRemoved.raiseEvent(layer, index);
  136761. if (destroy) {
  136762. layer.destroy();
  136763. }
  136764. return true;
  136765. }
  136766. return false;
  136767. };
  136768. /**
  136769. * Removes all layers from this collection.
  136770. *
  136771. * @param {Boolean} [destroy=true] whether to destroy the layers in addition to removing them.
  136772. */
  136773. ImageryLayerCollection.prototype.removeAll = function(destroy) {
  136774. destroy = defaultValue(destroy, true);
  136775. var layers = this._layers;
  136776. for (var i = 0, len = layers.length; i < len; i++) {
  136777. var layer = layers[i];
  136778. this.layerRemoved.raiseEvent(layer, i);
  136779. if (destroy) {
  136780. layer.destroy();
  136781. }
  136782. }
  136783. this._layers = [];
  136784. };
  136785. /**
  136786. * Checks to see if the collection contains a given layer.
  136787. *
  136788. * @param {ImageryLayer} layer the layer to check for.
  136789. *
  136790. * @returns {Boolean} true if the collection contains the layer, false otherwise.
  136791. */
  136792. ImageryLayerCollection.prototype.contains = function(layer) {
  136793. return this.indexOf(layer) !== -1;
  136794. };
  136795. /**
  136796. * Determines the index of a given layer in the collection.
  136797. *
  136798. * @param {ImageryLayer} layer The layer to find the index of.
  136799. *
  136800. * @returns {Number} The index of the layer in the collection, or -1 if the layer does not exist in the collection.
  136801. */
  136802. ImageryLayerCollection.prototype.indexOf = function(layer) {
  136803. return this._layers.indexOf(layer);
  136804. };
  136805. /**
  136806. * Gets a layer by index from the collection.
  136807. *
  136808. * @param {Number} index the index to retrieve.
  136809. *
  136810. * @returns {ImageryLayer} The imagery layer at the given index.
  136811. */
  136812. ImageryLayerCollection.prototype.get = function(index) {
  136813. if (!defined(index)) {
  136814. throw new DeveloperError('index is required.', 'index');
  136815. }
  136816. return this._layers[index];
  136817. };
  136818. function getLayerIndex(layers, layer) {
  136819. if (!defined(layer)) {
  136820. throw new DeveloperError('layer is required.');
  136821. }
  136822. var index = layers.indexOf(layer);
  136823. if (index === -1) {
  136824. throw new DeveloperError('layer is not in this collection.');
  136825. }
  136826. return index;
  136827. }
  136828. function swapLayers(collection, i, j) {
  136829. var arr = collection._layers;
  136830. i = CesiumMath.clamp(i, 0, arr.length - 1);
  136831. j = CesiumMath.clamp(j, 0, arr.length - 1);
  136832. if (i === j) {
  136833. return;
  136834. }
  136835. var temp = arr[i];
  136836. arr[i] = arr[j];
  136837. arr[j] = temp;
  136838. collection._update();
  136839. collection.layerMoved.raiseEvent(temp, j, i);
  136840. }
  136841. /**
  136842. * Raises a layer up one position in the collection.
  136843. *
  136844. * @param {ImageryLayer} layer the layer to move.
  136845. *
  136846. * @exception {DeveloperError} layer is not in this collection.
  136847. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  136848. */
  136849. ImageryLayerCollection.prototype.raise = function(layer) {
  136850. var index = getLayerIndex(this._layers, layer);
  136851. swapLayers(this, index, index + 1);
  136852. };
  136853. /**
  136854. * Lowers a layer down one position in the collection.
  136855. *
  136856. * @param {ImageryLayer} layer the layer to move.
  136857. *
  136858. * @exception {DeveloperError} layer is not in this collection.
  136859. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  136860. */
  136861. ImageryLayerCollection.prototype.lower = function(layer) {
  136862. var index = getLayerIndex(this._layers, layer);
  136863. swapLayers(this, index, index - 1);
  136864. };
  136865. /**
  136866. * Raises a layer to the top of the collection.
  136867. *
  136868. * @param {ImageryLayer} layer the layer to move.
  136869. *
  136870. * @exception {DeveloperError} layer is not in this collection.
  136871. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  136872. */
  136873. ImageryLayerCollection.prototype.raiseToTop = function(layer) {
  136874. var index = getLayerIndex(this._layers, layer);
  136875. if (index === this._layers.length - 1) {
  136876. return;
  136877. }
  136878. this._layers.splice(index, 1);
  136879. this._layers.push(layer);
  136880. this._update();
  136881. this.layerMoved.raiseEvent(layer, this._layers.length - 1, index);
  136882. };
  136883. /**
  136884. * Lowers a layer to the bottom of the collection.
  136885. *
  136886. * @param {ImageryLayer} layer the layer to move.
  136887. *
  136888. * @exception {DeveloperError} layer is not in this collection.
  136889. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  136890. */
  136891. ImageryLayerCollection.prototype.lowerToBottom = function(layer) {
  136892. var index = getLayerIndex(this._layers, layer);
  136893. if (index === 0) {
  136894. return;
  136895. }
  136896. this._layers.splice(index, 1);
  136897. this._layers.splice(0, 0, layer);
  136898. this._update();
  136899. this.layerMoved.raiseEvent(layer, 0, index);
  136900. };
  136901. var applicableRectangleScratch = new Rectangle();
  136902. /**
  136903. * Asynchronously determines the imagery layer features that are intersected by a pick ray. The intersected imagery
  136904. * layer features are found by invoking {@link ImageryProvider#pickFeatures} for each imagery layer tile intersected
  136905. * by the pick ray. To compute a pick ray from a location on the screen, use {@link Camera.getPickRay}.
  136906. *
  136907. * @param {Ray} ray The ray to test for intersection.
  136908. * @param {Scene} scene The scene.
  136909. * @return {Promise.<ImageryLayerFeatureInfo[]>|undefined} A promise that resolves to an array of features intersected by the pick ray.
  136910. * If it can be quickly determined that no features are intersected (for example,
  136911. * because no active imagery providers support {@link ImageryProvider#pickFeatures}
  136912. * or because the pick ray does not intersect the surface), this function will
  136913. * return undefined.
  136914. *
  136915. * @example
  136916. * var pickRay = viewer.camera.getPickRay(windowPosition);
  136917. * var featuresPromise = viewer.imageryLayers.pickImageryLayerFeatures(pickRay, viewer.scene);
  136918. * if (!Cesium.defined(featuresPromise)) {
  136919. * console.log('No features picked.');
  136920. * } else {
  136921. * Cesium.when(featuresPromise, function(features) {
  136922. * // This function is called asynchronously when the list if picked features is available.
  136923. * console.log('Number of features: ' + features.length);
  136924. * if (features.length > 0) {
  136925. * console.log('First feature name: ' + features[0].name);
  136926. * }
  136927. * });
  136928. * }
  136929. */
  136930. ImageryLayerCollection.prototype.pickImageryLayerFeatures = function(ray, scene) {
  136931. // Find the picked location on the globe.
  136932. var pickedPosition = scene.globe.pick(ray, scene);
  136933. if (!defined(pickedPosition)) {
  136934. return undefined;
  136935. }
  136936. var pickedLocation = scene.globe.ellipsoid.cartesianToCartographic(pickedPosition);
  136937. // Find the terrain tile containing the picked location.
  136938. var tilesToRender = scene.globe._surface._tilesToRender;
  136939. var pickedTile;
  136940. for (var textureIndex = 0; !defined(pickedTile) && textureIndex < tilesToRender.length; ++textureIndex) {
  136941. var tile = tilesToRender[textureIndex];
  136942. if (Rectangle.contains(tile.rectangle, pickedLocation)) {
  136943. pickedTile = tile;
  136944. }
  136945. }
  136946. if (!defined(pickedTile)) {
  136947. return undefined;
  136948. }
  136949. // Pick against all attached imagery tiles containing the pickedLocation.
  136950. var imageryTiles = pickedTile.data.imagery;
  136951. var promises = [];
  136952. var imageryLayers = [];
  136953. for (var i = imageryTiles.length - 1; i >= 0; --i) {
  136954. var terrainImagery = imageryTiles[i];
  136955. var imagery = terrainImagery.readyImagery;
  136956. if (!defined(imagery)) {
  136957. continue;
  136958. }
  136959. var provider = imagery.imageryLayer.imageryProvider;
  136960. if (!defined(provider.pickFeatures)) {
  136961. continue;
  136962. }
  136963. if (!Rectangle.contains(imagery.rectangle, pickedLocation)) {
  136964. continue;
  136965. }
  136966. // If this imagery came from a parent, it may not be applicable to its entire rectangle.
  136967. // Check the textureCoordinateRectangle.
  136968. var applicableRectangle = applicableRectangleScratch;
  136969. var epsilon = 1 / 1024; // 1/4 of a pixel in a typical 256x256 tile.
  136970. applicableRectangle.west = CesiumMath.lerp(pickedTile.rectangle.west, pickedTile.rectangle.east, terrainImagery.textureCoordinateRectangle.x - epsilon);
  136971. applicableRectangle.east = CesiumMath.lerp(pickedTile.rectangle.west, pickedTile.rectangle.east, terrainImagery.textureCoordinateRectangle.z + epsilon);
  136972. applicableRectangle.south = CesiumMath.lerp(pickedTile.rectangle.south, pickedTile.rectangle.north, terrainImagery.textureCoordinateRectangle.y - epsilon);
  136973. applicableRectangle.north = CesiumMath.lerp(pickedTile.rectangle.south, pickedTile.rectangle.north, terrainImagery.textureCoordinateRectangle.w + epsilon);
  136974. if (!Rectangle.contains(applicableRectangle, pickedLocation)) {
  136975. continue;
  136976. }
  136977. var promise = provider.pickFeatures(imagery.x, imagery.y, imagery.level, pickedLocation.longitude, pickedLocation.latitude);
  136978. if (!defined(promise)) {
  136979. continue;
  136980. }
  136981. promises.push(promise);
  136982. imageryLayers.push(imagery.imageryLayer);
  136983. }
  136984. if (promises.length === 0) {
  136985. return undefined;
  136986. }
  136987. return when.all(promises, function(results) {
  136988. var features = [];
  136989. for (var resultIndex = 0; resultIndex < results.length; ++resultIndex) {
  136990. var result = results[resultIndex];
  136991. var image = imageryLayers[resultIndex];
  136992. if (defined(result) && result.length > 0) {
  136993. for (var featureIndex = 0; featureIndex < result.length; ++featureIndex) {
  136994. var feature = result[featureIndex];
  136995. feature.imageryLayer = image;
  136996. // For features without a position, use the picked location.
  136997. if (!defined(feature.position)) {
  136998. feature.position = pickedLocation;
  136999. }
  137000. features.push(feature);
  137001. }
  137002. }
  137003. }
  137004. return features;
  137005. });
  137006. };
  137007. /**
  137008. * Updates frame state to execute any queued texture re-projections.
  137009. *
  137010. * @private
  137011. *
  137012. * @param {FrameState} frameState The frameState.
  137013. */
  137014. ImageryLayerCollection.prototype.queueReprojectionCommands = function(frameState) {
  137015. var layers = this._layers;
  137016. for (var i = 0, len = layers.length; i < len; ++i) {
  137017. layers[i].queueReprojectionCommands(frameState);
  137018. }
  137019. };
  137020. /**
  137021. * Cancels re-projection commands queued for the next frame.
  137022. *
  137023. * @private
  137024. */
  137025. ImageryLayerCollection.prototype.cancelReprojections = function() {
  137026. var layers = this._layers;
  137027. for (var i = 0, len = layers.length; i < len; ++i) {
  137028. layers[i].cancelReprojections();
  137029. }
  137030. };
  137031. /**
  137032. * Returns true if this object was destroyed; otherwise, false.
  137033. * <br /><br />
  137034. * If this object was destroyed, it should not be used; calling any function other than
  137035. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  137036. *
  137037. * @returns {Boolean} true if this object was destroyed; otherwise, false.
  137038. *
  137039. * @see ImageryLayerCollection#destroy
  137040. */
  137041. ImageryLayerCollection.prototype.isDestroyed = function() {
  137042. return false;
  137043. };
  137044. /**
  137045. * Destroys the WebGL resources held by all layers in this collection. Explicitly destroying this
  137046. * object allows for deterministic release of WebGL resources, instead of relying on the garbage
  137047. * collector.
  137048. * <br /><br />
  137049. * Once this object is destroyed, it should not be used; calling any function other than
  137050. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  137051. * assign the return value (<code>undefined</code>) to the object as done in the example.
  137052. *
  137053. * @returns {undefined}
  137054. *
  137055. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  137056. *
  137057. *
  137058. * @example
  137059. * layerCollection = layerCollection && layerCollection.destroy();
  137060. *
  137061. * @see ImageryLayerCollection#isDestroyed
  137062. */
  137063. ImageryLayerCollection.prototype.destroy = function() {
  137064. this.removeAll(true);
  137065. return destroyObject(this);
  137066. };
  137067. ImageryLayerCollection.prototype._update = function() {
  137068. var isBaseLayer = true;
  137069. var layers = this._layers;
  137070. var layersShownOrHidden;
  137071. var layer;
  137072. for (var i = 0, len = layers.length; i < len; ++i) {
  137073. layer = layers[i];
  137074. layer._layerIndex = i;
  137075. if (layer.show) {
  137076. layer._isBaseLayer = isBaseLayer;
  137077. isBaseLayer = false;
  137078. } else {
  137079. layer._isBaseLayer = false;
  137080. }
  137081. if (layer.show !== layer._show) {
  137082. if (defined(layer._show)) {
  137083. if (!defined(layersShownOrHidden)) {
  137084. layersShownOrHidden = [];
  137085. }
  137086. layersShownOrHidden.push(layer);
  137087. }
  137088. layer._show = layer.show;
  137089. }
  137090. }
  137091. if (defined(layersShownOrHidden)) {
  137092. for (i = 0, len = layersShownOrHidden.length; i < len; ++i) {
  137093. layer = layersShownOrHidden[i];
  137094. this.layerShownOrHidden.raiseEvent(layer, layer._layerIndex, layer.show);
  137095. }
  137096. }
  137097. };
  137098. return ImageryLayerCollection;
  137099. });
  137100. /*global define*/
  137101. define('Scene/QuadtreeOccluders',[
  137102. '../Core/Cartesian3',
  137103. '../Core/defineProperties',
  137104. '../Core/EllipsoidalOccluder'
  137105. ], function(
  137106. Cartesian3,
  137107. defineProperties,
  137108. EllipsoidalOccluder) {
  137109. 'use strict';
  137110. /**
  137111. * A set of occluders that can be used to test quadtree tiles for occlusion.
  137112. *
  137113. * @alias QuadtreeOccluders
  137114. * @constructor
  137115. * @private
  137116. *
  137117. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid that potentially occludes tiles.
  137118. */
  137119. function QuadtreeOccluders(options) {
  137120. this._ellipsoid = new EllipsoidalOccluder(options.ellipsoid, Cartesian3.ZERO);
  137121. }
  137122. defineProperties(QuadtreeOccluders.prototype, {
  137123. /**
  137124. * Gets the {@link EllipsoidalOccluder} that can be used to determine if a point is
  137125. * occluded by an {@link Ellipsoid}.
  137126. * @type {EllipsoidalOccluder}
  137127. * @memberof QuadtreeOccluders.prototype
  137128. */
  137129. ellipsoid : {
  137130. get : function() {
  137131. return this._ellipsoid;
  137132. }
  137133. }
  137134. });
  137135. return QuadtreeOccluders;
  137136. });
  137137. /*global define*/
  137138. define('Scene/QuadtreeTile',[
  137139. '../Core/defined',
  137140. '../Core/defineProperties',
  137141. '../Core/DeveloperError',
  137142. '../Core/Rectangle',
  137143. './QuadtreeTileLoadState'
  137144. ], function(
  137145. defined,
  137146. defineProperties,
  137147. DeveloperError,
  137148. Rectangle,
  137149. QuadtreeTileLoadState) {
  137150. 'use strict';
  137151. /**
  137152. * A single tile in a {@link QuadtreePrimitive}.
  137153. *
  137154. * @alias QuadtreeTile
  137155. * @constructor
  137156. * @private
  137157. *
  137158. * @param {Number} options.level The level of the tile in the quadtree.
  137159. * @param {Number} options.x The X coordinate of the tile in the quadtree. 0 is the westernmost tile.
  137160. * @param {Number} options.y The Y coordinate of the tile in the quadtree. 0 is the northernmost tile.
  137161. * @param {TilingScheme} options.tilingScheme The tiling scheme in which this tile exists.
  137162. * @param {QuadtreeTile} [options.parent] This tile's parent, or undefined if this is a root tile.
  137163. */
  137164. function QuadtreeTile(options) {
  137165. if (!defined(options)) {
  137166. throw new DeveloperError('options is required.');
  137167. }
  137168. if (!defined(options.x)) {
  137169. throw new DeveloperError('options.x is required.');
  137170. } else if (!defined(options.y)) {
  137171. throw new DeveloperError('options.y is required.');
  137172. } else if (options.x < 0 || options.y < 0) {
  137173. throw new DeveloperError('options.x and options.y must be greater than or equal to zero.');
  137174. }
  137175. if (!defined(options.level)) {
  137176. throw new DeveloperError('options.level is required and must be greater than or equal to zero.');
  137177. }
  137178. if (!defined(options.tilingScheme)) {
  137179. throw new DeveloperError('options.tilingScheme is required.');
  137180. }
  137181. this._tilingScheme = options.tilingScheme;
  137182. this._x = options.x;
  137183. this._y = options.y;
  137184. this._level = options.level;
  137185. this._parent = options.parent;
  137186. this._rectangle = this._tilingScheme.tileXYToRectangle(this._x, this._y, this._level);
  137187. this._southwestChild = undefined;
  137188. this._southeastChild = undefined;
  137189. this._northwestChild = undefined;
  137190. this._northeastChild = undefined;
  137191. // QuadtreeTileReplacementQueue gets/sets these private properties.
  137192. this._replacementPrevious = undefined;
  137193. this._replacementNext = undefined;
  137194. // The distance from the camera to this tile, updated when the tile is selected
  137195. // for rendering. We can get rid of this if we have a better way to sort by
  137196. // distance - for example, by using the natural ordering of a quadtree.
  137197. // QuadtreePrimitive gets/sets this private property.
  137198. this._distance = 0.0;
  137199. this._customData = [];
  137200. this._frameUpdated = undefined;
  137201. this._frameRendered = undefined;
  137202. /**
  137203. * Gets or sets the current state of the tile in the tile load pipeline.
  137204. * @type {QuadtreeTileLoadState}
  137205. * @default {@link QuadtreeTileLoadState.START}
  137206. */
  137207. this.state = QuadtreeTileLoadState.START;
  137208. /**
  137209. * Gets or sets a value indicating whether or not the tile is currently renderable.
  137210. * @type {Boolean}
  137211. * @default false
  137212. */
  137213. this.renderable = false;
  137214. /**
  137215. * Gets or set a value indicating whether or not the tile was entire upsampled from its
  137216. * parent tile. If all four children of a parent tile were upsampled from the parent,
  137217. * we will render the parent instead of the children even if the LOD indicates that
  137218. * the children would be preferable.
  137219. * @type {Boolean}
  137220. * @default false
  137221. */
  137222. this.upsampledFromParent = false;
  137223. /**
  137224. * Gets or sets the additional data associated with this tile. The exact content is specific to the
  137225. * {@link QuadtreeTileProvider}.
  137226. * @type {Object}
  137227. * @default undefined
  137228. */
  137229. this.data = undefined;
  137230. }
  137231. /**
  137232. * Creates a rectangular set of tiles for level of detail zero, the coarsest, least detailed level.
  137233. *
  137234. * @memberof QuadtreeTile
  137235. *
  137236. * @param {TilingScheme} tilingScheme The tiling scheme for which the tiles are to be created.
  137237. * @returns {QuadtreeTile[]} An array containing the tiles at level of detail zero, starting with the
  137238. * tile in the northwest corner and followed by the tile (if any) to its east.
  137239. */
  137240. QuadtreeTile.createLevelZeroTiles = function(tilingScheme) {
  137241. if (!defined(tilingScheme)) {
  137242. throw new DeveloperError('tilingScheme is required.');
  137243. }
  137244. var numberOfLevelZeroTilesX = tilingScheme.getNumberOfXTilesAtLevel(0);
  137245. var numberOfLevelZeroTilesY = tilingScheme.getNumberOfYTilesAtLevel(0);
  137246. var result = new Array(numberOfLevelZeroTilesX * numberOfLevelZeroTilesY);
  137247. var index = 0;
  137248. for (var y = 0; y < numberOfLevelZeroTilesY; ++y) {
  137249. for (var x = 0; x < numberOfLevelZeroTilesX; ++x) {
  137250. result[index++] = new QuadtreeTile({
  137251. tilingScheme : tilingScheme,
  137252. x : x,
  137253. y : y,
  137254. level : 0
  137255. });
  137256. }
  137257. }
  137258. return result;
  137259. };
  137260. QuadtreeTile.prototype._updateCustomData = function(frameNumber, added, removed) {
  137261. var customData = this.customData;
  137262. var i;
  137263. var data;
  137264. var rectangle;
  137265. if (defined(added) && defined(removed)) {
  137266. customData = customData.filter(function(value) {
  137267. return removed.indexOf(value) === -1;
  137268. });
  137269. this._customData = customData;
  137270. rectangle = this._rectangle;
  137271. for (i = 0; i < added.length; ++i) {
  137272. data = added[i];
  137273. if (Rectangle.contains(rectangle, data.positionCartographic)) {
  137274. customData.push(data);
  137275. }
  137276. }
  137277. this._frameUpdated = frameNumber;
  137278. } else {
  137279. // interior or leaf tile, update from parent
  137280. var parent = this._parent;
  137281. if (defined(parent) && this._frameUpdated !== parent._frameUpdated) {
  137282. customData.length = 0;
  137283. rectangle = this._rectangle;
  137284. var parentCustomData = parent.customData;
  137285. for (i = 0; i < parentCustomData.length; ++i) {
  137286. data = parentCustomData[i];
  137287. if (Rectangle.contains(rectangle, data.positionCartographic)) {
  137288. customData.push(data);
  137289. }
  137290. }
  137291. this._frameUpdated = parent._frameUpdated;
  137292. }
  137293. }
  137294. };
  137295. defineProperties(QuadtreeTile.prototype, {
  137296. /**
  137297. * Gets the tiling scheme used to tile the surface.
  137298. * @memberof QuadtreeTile.prototype
  137299. * @type {TilingScheme}
  137300. */
  137301. tilingScheme : {
  137302. get : function() {
  137303. return this._tilingScheme;
  137304. }
  137305. },
  137306. /**
  137307. * Gets the tile X coordinate.
  137308. * @memberof QuadtreeTile.prototype
  137309. * @type {Number}
  137310. */
  137311. x : {
  137312. get : function() {
  137313. return this._x;
  137314. }
  137315. },
  137316. /**
  137317. * Gets the tile Y coordinate.
  137318. * @memberof QuadtreeTile.prototype
  137319. * @type {Number}
  137320. */
  137321. y : {
  137322. get : function() {
  137323. return this._y;
  137324. }
  137325. },
  137326. /**
  137327. * Gets the level-of-detail, where zero is the coarsest, least-detailed.
  137328. * @memberof QuadtreeTile.prototype
  137329. * @type {Number}
  137330. */
  137331. level : {
  137332. get : function() {
  137333. return this._level;
  137334. }
  137335. },
  137336. /**
  137337. * Gets the parent tile of this tile.
  137338. * @memberof QuadtreeTile.prototype
  137339. * @type {QuadtreeTile}
  137340. */
  137341. parent : {
  137342. get : function() {
  137343. return this._parent;
  137344. }
  137345. },
  137346. /**
  137347. * Gets the cartographic rectangle of the tile, with north, south, east and
  137348. * west properties in radians.
  137349. * @memberof QuadtreeTile.prototype
  137350. * @type {Rectangle}
  137351. */
  137352. rectangle : {
  137353. get : function() {
  137354. return this._rectangle;
  137355. }
  137356. },
  137357. /**
  137358. * An array of tiles that is at the next level of the tile tree.
  137359. * @memberof QuadtreeTile.prototype
  137360. * @type {QuadtreeTile[]}
  137361. */
  137362. children : {
  137363. get : function() {
  137364. return [this.northwestChild, this.northeastChild, this.southwestChild, this.southeastChild];
  137365. }
  137366. },
  137367. /**
  137368. * Gets the southwest child tile.
  137369. * @memberof QuadtreeTile.prototype
  137370. * @type {QuadtreeTile}
  137371. */
  137372. southwestChild : {
  137373. get : function() {
  137374. if (!defined(this._southwestChild)) {
  137375. this._southwestChild = new QuadtreeTile({
  137376. tilingScheme : this.tilingScheme,
  137377. x : this.x * 2,
  137378. y : this.y * 2 + 1,
  137379. level : this.level + 1,
  137380. parent : this
  137381. });
  137382. }
  137383. return this._southwestChild;
  137384. }
  137385. },
  137386. /**
  137387. * Gets the southeast child tile.
  137388. * @memberof QuadtreeTile.prototype
  137389. * @type {QuadtreeTile}
  137390. */
  137391. southeastChild : {
  137392. get : function() {
  137393. if (!defined(this._southeastChild)) {
  137394. this._southeastChild = new QuadtreeTile({
  137395. tilingScheme : this.tilingScheme,
  137396. x : this.x * 2 + 1,
  137397. y : this.y * 2 + 1,
  137398. level : this.level + 1,
  137399. parent : this
  137400. });
  137401. }
  137402. return this._southeastChild;
  137403. }
  137404. },
  137405. /**
  137406. * Gets the northwest child tile.
  137407. * @memberof QuadtreeTile.prototype
  137408. * @type {QuadtreeTile}
  137409. */
  137410. northwestChild : {
  137411. get : function() {
  137412. if (!defined(this._northwestChild)) {
  137413. this._northwestChild = new QuadtreeTile({
  137414. tilingScheme : this.tilingScheme,
  137415. x : this.x * 2,
  137416. y : this.y * 2,
  137417. level : this.level + 1,
  137418. parent : this
  137419. });
  137420. }
  137421. return this._northwestChild;
  137422. }
  137423. },
  137424. /**
  137425. * Gets the northeast child tile.
  137426. * @memberof QuadtreeTile.prototype
  137427. * @type {QuadtreeTile}
  137428. */
  137429. northeastChild : {
  137430. get : function() {
  137431. if (!defined(this._northeastChild)) {
  137432. this._northeastChild = new QuadtreeTile({
  137433. tilingScheme : this.tilingScheme,
  137434. x : this.x * 2 + 1,
  137435. y : this.y * 2,
  137436. level : this.level + 1,
  137437. parent : this
  137438. });
  137439. }
  137440. return this._northeastChild;
  137441. }
  137442. },
  137443. /**
  137444. * An array of objects associated with this tile.
  137445. * @memberof QuadtreeTile.prototype
  137446. * @type {Array}
  137447. */
  137448. customData : {
  137449. get : function() {
  137450. return this._customData;
  137451. }
  137452. },
  137453. /**
  137454. * Gets a value indicating whether or not this tile needs further loading.
  137455. * This property will return true if the {@link QuadtreeTile#state} is
  137456. * <code>START</code> or <code>LOADING</code>.
  137457. * @memberof QuadtreeTile.prototype
  137458. * @type {Boolean}
  137459. */
  137460. needsLoading : {
  137461. get : function() {
  137462. return this.state < QuadtreeTileLoadState.DONE;
  137463. }
  137464. },
  137465. /**
  137466. * Gets a value indicating whether or not this tile is eligible to be unloaded.
  137467. * Typically, a tile is ineligible to be unloaded while an asynchronous operation,
  137468. * such as a request for data, is in progress on it. A tile will never be
  137469. * unloaded while it is needed for rendering, regardless of the value of this
  137470. * property. If {@link QuadtreeTile#data} is defined and has an
  137471. * <code>eligibleForUnloading</code> property, the value of that property is returned.
  137472. * Otherwise, this property returns true.
  137473. * @memberof QuadtreeTile.prototype
  137474. * @type {Boolean}
  137475. */
  137476. eligibleForUnloading : {
  137477. get : function() {
  137478. var result = true;
  137479. if (defined(this.data)) {
  137480. result = this.data.eligibleForUnloading;
  137481. if (!defined(result)) {
  137482. result = true;
  137483. }
  137484. }
  137485. return result;
  137486. }
  137487. }
  137488. });
  137489. /**
  137490. * Frees the resources associated with this tile and returns it to the <code>START</code>
  137491. * {@link QuadtreeTileLoadState}. If the {@link QuadtreeTile#data} property is defined and it
  137492. * has a <code>freeResources</code> method, the method will be invoked.
  137493. *
  137494. * @memberof QuadtreeTile
  137495. */
  137496. QuadtreeTile.prototype.freeResources = function() {
  137497. this.state = QuadtreeTileLoadState.START;
  137498. this.renderable = false;
  137499. this.upsampledFromParent = false;
  137500. if (defined(this.data) && defined(this.data.freeResources)) {
  137501. this.data.freeResources();
  137502. }
  137503. freeTile(this._southwestChild);
  137504. this._southwestChild = undefined;
  137505. freeTile(this._southeastChild);
  137506. this._southeastChild = undefined;
  137507. freeTile(this._northwestChild);
  137508. this._northwestChild = undefined;
  137509. freeTile(this._northeastChild);
  137510. this._northeastChild = undefined;
  137511. };
  137512. function freeTile(tile) {
  137513. if (defined(tile)) {
  137514. tile.freeResources();
  137515. }
  137516. }
  137517. return QuadtreeTile;
  137518. });
  137519. /*global define*/
  137520. define('Scene/TileReplacementQueue',[
  137521. '../Core/defined'
  137522. ], function(
  137523. defined) {
  137524. 'use strict';
  137525. /**
  137526. * A priority queue of tiles to be replaced, if necessary, to make room for new tiles. The queue
  137527. * is implemented as a linked list.
  137528. *
  137529. * @alias TileReplacementQueue
  137530. * @private
  137531. */
  137532. function TileReplacementQueue() {
  137533. this.head = undefined;
  137534. this.tail = undefined;
  137535. this.count = 0;
  137536. this._lastBeforeStartOfFrame = undefined;
  137537. }
  137538. /**
  137539. * Marks the start of the render frame. Tiles before (closer to the head) this tile in the
  137540. * list were used last frame and must not be unloaded.
  137541. */
  137542. TileReplacementQueue.prototype.markStartOfRenderFrame = function() {
  137543. this._lastBeforeStartOfFrame = this.head;
  137544. };
  137545. /**
  137546. * Reduces the size of the queue to a specified size by unloading the least-recently used
  137547. * tiles. Tiles that were used last frame will not be unloaded, even if that puts the number
  137548. * of tiles above the specified maximum.
  137549. *
  137550. * @param {Number} maximumTiles The maximum number of tiles in the queue.
  137551. */
  137552. TileReplacementQueue.prototype.trimTiles = function(maximumTiles) {
  137553. var tileToTrim = this.tail;
  137554. var keepTrimming = true;
  137555. while (keepTrimming &&
  137556. defined(this._lastBeforeStartOfFrame) &&
  137557. this.count > maximumTiles &&
  137558. defined(tileToTrim)) {
  137559. // Stop trimming after we process the last tile not used in the
  137560. // current frame.
  137561. keepTrimming = tileToTrim !== this._lastBeforeStartOfFrame;
  137562. var previous = tileToTrim.replacementPrevious;
  137563. if (tileToTrim.eligibleForUnloading) {
  137564. tileToTrim.freeResources();
  137565. remove(this, tileToTrim);
  137566. }
  137567. tileToTrim = previous;
  137568. }
  137569. };
  137570. function remove(tileReplacementQueue, item) {
  137571. var previous = item.replacementPrevious;
  137572. var next = item.replacementNext;
  137573. if (item === tileReplacementQueue._lastBeforeStartOfFrame) {
  137574. tileReplacementQueue._lastBeforeStartOfFrame = next;
  137575. }
  137576. if (item === tileReplacementQueue.head) {
  137577. tileReplacementQueue.head = next;
  137578. } else {
  137579. previous.replacementNext = next;
  137580. }
  137581. if (item === tileReplacementQueue.tail) {
  137582. tileReplacementQueue.tail = previous;
  137583. } else {
  137584. next.replacementPrevious = previous;
  137585. }
  137586. item.replacementPrevious = undefined;
  137587. item.replacementNext = undefined;
  137588. --tileReplacementQueue.count;
  137589. }
  137590. /**
  137591. * Marks a tile as rendered this frame and moves it before the first tile that was not rendered
  137592. * this frame.
  137593. *
  137594. * @param {TileReplacementQueue} item The tile that was rendered.
  137595. */
  137596. TileReplacementQueue.prototype.markTileRendered = function(item) {
  137597. var head = this.head;
  137598. if (head === item) {
  137599. if (item === this._lastBeforeStartOfFrame) {
  137600. this._lastBeforeStartOfFrame = item.replacementNext;
  137601. }
  137602. return;
  137603. }
  137604. ++this.count;
  137605. if (!defined(head)) {
  137606. // no other tiles in the list
  137607. item.replacementPrevious = undefined;
  137608. item.replacementNext = undefined;
  137609. this.head = item;
  137610. this.tail = item;
  137611. return;
  137612. }
  137613. if (defined(item.replacementPrevious) || defined(item.replacementNext)) {
  137614. // tile already in the list, remove from its current location
  137615. remove(this, item);
  137616. }
  137617. item.replacementPrevious = undefined;
  137618. item.replacementNext = head;
  137619. head.replacementPrevious = item;
  137620. this.head = item;
  137621. };
  137622. return TileReplacementQueue;
  137623. });
  137624. /*global define*/
  137625. define('Scene/QuadtreePrimitive',[
  137626. '../Core/Cartesian3',
  137627. '../Core/Cartographic',
  137628. '../Core/defaultValue',
  137629. '../Core/defined',
  137630. '../Core/defineProperties',
  137631. '../Core/DeveloperError',
  137632. '../Core/Event',
  137633. '../Core/getTimestamp',
  137634. '../Core/Math',
  137635. '../Core/Queue',
  137636. '../Core/Ray',
  137637. '../Core/Rectangle',
  137638. '../Core/Visibility',
  137639. './QuadtreeOccluders',
  137640. './QuadtreeTile',
  137641. './QuadtreeTileLoadState',
  137642. './SceneMode',
  137643. './TileReplacementQueue'
  137644. ], function(
  137645. Cartesian3,
  137646. Cartographic,
  137647. defaultValue,
  137648. defined,
  137649. defineProperties,
  137650. DeveloperError,
  137651. Event,
  137652. getTimestamp,
  137653. CesiumMath,
  137654. Queue,
  137655. Ray,
  137656. Rectangle,
  137657. Visibility,
  137658. QuadtreeOccluders,
  137659. QuadtreeTile,
  137660. QuadtreeTileLoadState,
  137661. SceneMode,
  137662. TileReplacementQueue) {
  137663. 'use strict';
  137664. /**
  137665. * Renders massive sets of data by utilizing level-of-detail and culling. The globe surface is divided into
  137666. * a quadtree of tiles with large, low-detail tiles at the root and small, high-detail tiles at the leaves.
  137667. * The set of tiles to render is selected by projecting an estimate of the geometric error in a tile onto
  137668. * the screen to estimate screen-space error, in pixels, which must be below a user-specified threshold.
  137669. * The actual content of the tiles is arbitrary and is specified using a {@link QuadtreeTileProvider}.
  137670. *
  137671. * @alias QuadtreePrimitive
  137672. * @constructor
  137673. * @private
  137674. *
  137675. * @param {QuadtreeTileProvider} options.tileProvider The tile provider that loads, renders, and estimates
  137676. * the distance to individual tiles.
  137677. * @param {Number} [options.maximumScreenSpaceError=2] The maximum screen-space error, in pixels, that is allowed.
  137678. * A higher maximum error will render fewer tiles and improve performance, while a lower
  137679. * value will improve visual quality.
  137680. * @param {Number} [options.tileCacheSize=100] The maximum number of tiles that will be retained in the tile cache.
  137681. * Note that tiles will never be unloaded if they were used for rendering the last
  137682. * frame, so the actual number of resident tiles may be higher. The value of
  137683. * this property will not affect visual quality.
  137684. */
  137685. function QuadtreePrimitive(options) {
  137686. if (!defined(options) || !defined(options.tileProvider)) {
  137687. throw new DeveloperError('options.tileProvider is required.');
  137688. }
  137689. if (defined(options.tileProvider.quadtree)) {
  137690. throw new DeveloperError('A QuadtreeTileProvider can only be used with a single QuadtreePrimitive');
  137691. }
  137692. this._tileProvider = options.tileProvider;
  137693. this._tileProvider.quadtree = this;
  137694. this._debug = {
  137695. enableDebugOutput : false,
  137696. maxDepth : 0,
  137697. tilesVisited : 0,
  137698. tilesCulled : 0,
  137699. tilesRendered : 0,
  137700. tilesWaitingForChildren : 0,
  137701. lastMaxDepth : -1,
  137702. lastTilesVisited : -1,
  137703. lastTilesCulled : -1,
  137704. lastTilesRendered : -1,
  137705. lastTilesWaitingForChildren : -1,
  137706. suspendLodUpdate : false
  137707. };
  137708. var tilingScheme = this._tileProvider.tilingScheme;
  137709. var ellipsoid = tilingScheme.ellipsoid;
  137710. this._tilesToRender = [];
  137711. this._tileLoadQueueHigh = []; // high priority tiles are preventing refinement
  137712. this._tileLoadQueueMedium = []; // medium priority tiles are being rendered
  137713. this._tileLoadQueueLow = []; // low priority tiles were refined past or are non-visible parts of quads.
  137714. this._tileReplacementQueue = new TileReplacementQueue();
  137715. this._levelZeroTiles = undefined;
  137716. this._levelZeroTilesReady = false;
  137717. this._loadQueueTimeSlice = 5.0;
  137718. this._addHeightCallbacks = [];
  137719. this._removeHeightCallbacks = [];
  137720. this._tileToUpdateHeights = [];
  137721. this._lastTileIndex = 0;
  137722. this._updateHeightsTimeSlice = 2.0;
  137723. /**
  137724. * Gets or sets the maximum screen-space error, in pixels, that is allowed.
  137725. * A higher maximum error will render fewer tiles and improve performance, while a lower
  137726. * value will improve visual quality.
  137727. * @type {Number}
  137728. * @default 2
  137729. */
  137730. this.maximumScreenSpaceError = defaultValue(options.maximumScreenSpaceError, 2);
  137731. /**
  137732. * Gets or sets the maximum number of tiles that will be retained in the tile cache.
  137733. * Note that tiles will never be unloaded if they were used for rendering the last
  137734. * frame, so the actual number of resident tiles may be higher. The value of
  137735. * this property will not affect visual quality.
  137736. * @type {Number}
  137737. * @default 100
  137738. */
  137739. this.tileCacheSize = defaultValue(options.tileCacheSize, 100);
  137740. this._occluders = new QuadtreeOccluders({
  137741. ellipsoid : ellipsoid
  137742. });
  137743. this._tileLoadProgressEvent = new Event();
  137744. this._lastTileLoadQueueLength = 0;
  137745. }
  137746. defineProperties(QuadtreePrimitive.prototype, {
  137747. /**
  137748. * Gets the provider of {@link QuadtreeTile} instances for this quadtree.
  137749. * @type {QuadtreeTile}
  137750. * @memberof QuadtreePrimitive.prototype
  137751. */
  137752. tileProvider : {
  137753. get : function() {
  137754. return this._tileProvider;
  137755. }
  137756. },
  137757. /**
  137758. * Gets an event that's raised when the length of the tile load queue has changed since the last render frame. When the load queue is empty,
  137759. * all terrain and imagery for the current view have been loaded. The event passes the new length of the tile load queue.
  137760. *
  137761. * @memberof QuadtreePrimitive.prototype
  137762. * @type {Event}
  137763. */
  137764. tileLoadProgressEvent : {
  137765. get : function() {
  137766. return this._tileLoadProgressEvent;
  137767. }
  137768. }
  137769. });
  137770. /**
  137771. * Invalidates and frees all the tiles in the quadtree. The tiles must be reloaded
  137772. * before they can be displayed.
  137773. *
  137774. * @memberof QuadtreePrimitive
  137775. */
  137776. QuadtreePrimitive.prototype.invalidateAllTiles = function() {
  137777. // Clear the replacement queue
  137778. var replacementQueue = this._tileReplacementQueue;
  137779. replacementQueue.head = undefined;
  137780. replacementQueue.tail = undefined;
  137781. replacementQueue.count = 0;
  137782. // Free and recreate the level zero tiles.
  137783. var levelZeroTiles = this._levelZeroTiles;
  137784. if (defined(levelZeroTiles)) {
  137785. for (var i = 0; i < levelZeroTiles.length; ++i) {
  137786. var tile = levelZeroTiles[i];
  137787. var customData = tile.customData;
  137788. var customDataLength = customData.length;
  137789. for (var j = 0; j < customDataLength; ++j) {
  137790. var data = customData[j];
  137791. data.level = 0;
  137792. this._addHeightCallbacks.push(data);
  137793. }
  137794. levelZeroTiles[i].freeResources();
  137795. }
  137796. }
  137797. this._levelZeroTiles = undefined;
  137798. this._tileProvider.cancelReprojections();
  137799. };
  137800. /**
  137801. * Invokes a specified function for each {@link QuadtreeTile} that is partially
  137802. * or completely loaded.
  137803. *
  137804. * @param {Function} tileFunction The function to invoke for each loaded tile. The
  137805. * function is passed a reference to the tile as its only parameter.
  137806. */
  137807. QuadtreePrimitive.prototype.forEachLoadedTile = function(tileFunction) {
  137808. var tile = this._tileReplacementQueue.head;
  137809. while (defined(tile)) {
  137810. if (tile.state !== QuadtreeTileLoadState.START) {
  137811. tileFunction(tile);
  137812. }
  137813. tile = tile.replacementNext;
  137814. }
  137815. };
  137816. /**
  137817. * Invokes a specified function for each {@link QuadtreeTile} that was rendered
  137818. * in the most recent frame.
  137819. *
  137820. * @param {Function} tileFunction The function to invoke for each rendered tile. The
  137821. * function is passed a reference to the tile as its only parameter.
  137822. */
  137823. QuadtreePrimitive.prototype.forEachRenderedTile = function(tileFunction) {
  137824. var tilesRendered = this._tilesToRender;
  137825. for (var i = 0, len = tilesRendered.length; i < len; ++i) {
  137826. tileFunction(tilesRendered[i]);
  137827. }
  137828. };
  137829. /**
  137830. * Calls the callback when a new tile is rendered that contains the given cartographic. The only parameter
  137831. * is the cartesian position on the tile.
  137832. *
  137833. * @param {Cartographic} cartographic The cartographic position.
  137834. * @param {Function} callback The function to be called when a new tile is loaded containing cartographic.
  137835. * @returns {Function} The function to remove this callback from the quadtree.
  137836. */
  137837. QuadtreePrimitive.prototype.updateHeight = function(cartographic, callback) {
  137838. var primitive = this;
  137839. var object = {
  137840. positionOnEllipsoidSurface : undefined,
  137841. positionCartographic : cartographic,
  137842. level : -1,
  137843. callback : callback
  137844. };
  137845. object.removeFunc = function() {
  137846. var addedCallbacks = primitive._addHeightCallbacks;
  137847. var length = addedCallbacks.length;
  137848. for (var i = 0; i < length; ++i) {
  137849. if (addedCallbacks[i] === object) {
  137850. addedCallbacks.splice(i, 1);
  137851. break;
  137852. }
  137853. }
  137854. primitive._removeHeightCallbacks.push(object);
  137855. };
  137856. primitive._addHeightCallbacks.push(object);
  137857. return object.removeFunc;
  137858. };
  137859. /**
  137860. * @private
  137861. */
  137862. QuadtreePrimitive.prototype.beginFrame = function(frameState) {
  137863. var passes = frameState.passes;
  137864. if (!passes.render) {
  137865. return;
  137866. }
  137867. // Gets commands for any texture re-projections and updates the credit display
  137868. this._tileProvider.initialize(frameState);
  137869. var debug = this._debug;
  137870. if (debug.suspendLodUpdate) {
  137871. return;
  137872. }
  137873. debug.maxDepth = 0;
  137874. debug.tilesVisited = 0;
  137875. debug.tilesCulled = 0;
  137876. debug.tilesRendered = 0;
  137877. debug.tilesWaitingForChildren = 0;
  137878. this._tileLoadQueueHigh.length = 0;
  137879. this._tileLoadQueueMedium.length = 0;
  137880. this._tileLoadQueueLow.length = 0;
  137881. this._tileReplacementQueue.markStartOfRenderFrame();
  137882. };
  137883. /**
  137884. * @private
  137885. */
  137886. QuadtreePrimitive.prototype.update = function(frameState) {
  137887. var passes = frameState.passes;
  137888. if (passes.render) {
  137889. this._tileProvider.beginUpdate(frameState);
  137890. selectTilesForRendering(this, frameState);
  137891. createRenderCommandsForSelectedTiles(this, frameState);
  137892. this._tileProvider.endUpdate(frameState);
  137893. }
  137894. if (passes.pick && this._tilesToRender.length > 0) {
  137895. this._tileProvider.updateForPick(frameState);
  137896. }
  137897. };
  137898. /**
  137899. * @private
  137900. */
  137901. QuadtreePrimitive.prototype.endFrame = function(frameState) {
  137902. var passes = frameState.passes;
  137903. if (!passes.render || frameState.mode === SceneMode.MORPHING) {
  137904. // Only process the load queue for a single pass.
  137905. // Don't process the load queue or update heights during the morph flights.
  137906. return;
  137907. }
  137908. // Load/create resources for terrain and imagery. Prepare texture re-projections for the next frame.
  137909. processTileLoadQueue(this, frameState);
  137910. updateHeights(this, frameState);
  137911. var debug = this._debug;
  137912. if (debug.suspendLodUpdate) {
  137913. return;
  137914. }
  137915. if (debug.enableDebugOutput) {
  137916. if (debug.tilesVisited !== debug.lastTilesVisited ||
  137917. debug.tilesRendered !== debug.lastTilesRendered ||
  137918. debug.tilesCulled !== debug.lastTilesCulled ||
  137919. debug.maxDepth !== debug.lastMaxDepth ||
  137920. debug.tilesWaitingForChildren !== debug.lastTilesWaitingForChildren) {
  137921. console.log('Visited ' + debug.tilesVisited + ', Rendered: ' + debug.tilesRendered + ', Culled: ' + debug.tilesCulled + ', Max Depth: ' + debug.maxDepth + ', Waiting for children: ' + debug.tilesWaitingForChildren);
  137922. debug.lastTilesVisited = debug.tilesVisited;
  137923. debug.lastTilesRendered = debug.tilesRendered;
  137924. debug.lastTilesCulled = debug.tilesCulled;
  137925. debug.lastMaxDepth = debug.maxDepth;
  137926. debug.lastTilesWaitingForChildren = debug.tilesWaitingForChildren;
  137927. }
  137928. }
  137929. };
  137930. /**
  137931. * Returns true if this object was destroyed; otherwise, false.
  137932. * <br /><br />
  137933. * If this object was destroyed, it should not be used; calling any function other than
  137934. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  137935. *
  137936. * @memberof QuadtreePrimitive
  137937. *
  137938. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  137939. *
  137940. * @see QuadtreePrimitive#destroy
  137941. */
  137942. QuadtreePrimitive.prototype.isDestroyed = function() {
  137943. return false;
  137944. };
  137945. /**
  137946. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  137947. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  137948. * <br /><br />
  137949. * Once an object is destroyed, it should not be used; calling any function other than
  137950. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  137951. * assign the return value (<code>undefined</code>) to the object as done in the example.
  137952. *
  137953. * @memberof QuadtreePrimitive
  137954. *
  137955. * @returns {undefined}
  137956. *
  137957. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  137958. *
  137959. *
  137960. * @example
  137961. * primitive = primitive && primitive.destroy();
  137962. *
  137963. * @see QuadtreePrimitive#isDestroyed
  137964. */
  137965. QuadtreePrimitive.prototype.destroy = function() {
  137966. this._tileProvider = this._tileProvider && this._tileProvider.destroy();
  137967. };
  137968. var comparisonPoint;
  137969. var centerScratch = new Cartographic();
  137970. function compareDistanceToPoint(a, b) {
  137971. var center = Rectangle.center(a.rectangle, centerScratch);
  137972. var alon = center.longitude - comparisonPoint.longitude;
  137973. var alat = center.latitude - comparisonPoint.latitude;
  137974. center = Rectangle.center(b.rectangle, centerScratch);
  137975. var blon = center.longitude - comparisonPoint.longitude;
  137976. var blat = center.latitude - comparisonPoint.latitude;
  137977. return (alon * alon + alat * alat) - (blon * blon + blat * blat);
  137978. }
  137979. function selectTilesForRendering(primitive, frameState) {
  137980. var debug = primitive._debug;
  137981. if (debug.suspendLodUpdate) {
  137982. return;
  137983. }
  137984. var i;
  137985. var len;
  137986. // Clear the render list.
  137987. var tilesToRender = primitive._tilesToRender;
  137988. tilesToRender.length = 0;
  137989. // We can't render anything before the level zero tiles exist.
  137990. if (!defined(primitive._levelZeroTiles)) {
  137991. if (primitive._tileProvider.ready) {
  137992. var tilingScheme = primitive._tileProvider.tilingScheme;
  137993. primitive._levelZeroTiles = QuadtreeTile.createLevelZeroTiles(tilingScheme);
  137994. } else {
  137995. // Nothing to do until the provider is ready.
  137996. return;
  137997. }
  137998. }
  137999. primitive._occluders.ellipsoid.cameraPosition = frameState.camera.positionWC;
  138000. var tileProvider = primitive._tileProvider;
  138001. var occluders = primitive._occluders;
  138002. var tile;
  138003. var levelZeroTiles = primitive._levelZeroTiles;
  138004. // Sort the level zero tiles by the distance from the center to the camera.
  138005. // The level zero tiles aren't necessarily a nice neat quad, so we can use the
  138006. // quadtree ordering we use elsewhere in the tree
  138007. comparisonPoint = frameState.camera.positionCartographic;
  138008. levelZeroTiles.sort(compareDistanceToPoint);
  138009. var customDataAdded = primitive._addHeightCallbacks;
  138010. var customDataRemoved = primitive._removeHeightCallbacks;
  138011. var frameNumber = frameState.frameNumber;
  138012. if (customDataAdded.length > 0 || customDataRemoved.length > 0) {
  138013. for (i = 0, len = levelZeroTiles.length; i < len; ++i) {
  138014. tile = levelZeroTiles[i];
  138015. tile._updateCustomData(frameNumber, customDataAdded, customDataRemoved);
  138016. }
  138017. customDataAdded.length = 0;
  138018. customDataRemoved.length = 0;
  138019. }
  138020. // Our goal with load ordering is to first load all of the tiles we need to
  138021. // render the current scene at full detail. Loading any other tiles is just
  138022. // a form of prefetching, and we need not do it at all (other concerns aside). This
  138023. // simple and obvious statement gets more complicated when we realize that, because
  138024. // we don't have bounding volumes for the entire terrain tile pyramid, we don't
  138025. // precisely know which tiles we need to render the scene at full detail, until we do
  138026. // some loading.
  138027. //
  138028. // So our load priority is (from high to low):
  138029. // 1. Tiles that we _would_ render, except that they're not sufficiently loaded yet.
  138030. // Ideally this would only include tiles that we've already determined to be visible,
  138031. // but since we don't have reliable visibility information until a tile is loaded,
  138032. // and because we (currently) must have all children in a quad renderable before we
  138033. // can refine, this pretty much means tiles we'd like to refine to, regardless of
  138034. // visibility. (high)
  138035. // 2. Tiles that we're rendering. (medium)
  138036. // 3. All other tiles. (low)
  138037. //
  138038. // Within each priority group, tiles should be loaded in approximate near-to-far order,
  138039. // but currently they're just loaded in our traversal order which makes no guarantees
  138040. // about depth ordering.
  138041. // Traverse in depth-first, near-to-far order.
  138042. for (i = 0, len = levelZeroTiles.length; i < len; ++i) {
  138043. tile = levelZeroTiles[i];
  138044. primitive._tileReplacementQueue.markTileRendered(tile);
  138045. if (!tile.renderable) {
  138046. if (tile.needsLoading) {
  138047. primitive._tileLoadQueueHigh.push(tile);
  138048. }
  138049. ++debug.tilesWaitingForChildren;
  138050. } else if (tileProvider.computeTileVisibility(tile, frameState, occluders) !== Visibility.NONE) {
  138051. visitTile(primitive, frameState, tile);
  138052. } else {
  138053. if (tile.needsLoading) {
  138054. primitive._tileLoadQueueLow.push(tile);
  138055. }
  138056. ++debug.tilesCulled;
  138057. }
  138058. }
  138059. raiseTileLoadProgressEvent(primitive);
  138060. }
  138061. function visitTile(primitive, frameState, tile) {
  138062. var debug = primitive._debug;
  138063. ++debug.tilesVisited;
  138064. primitive._tileReplacementQueue.markTileRendered(tile);
  138065. tile._updateCustomData(frameState.frameNumber);
  138066. if (tile.level > debug.maxDepth) {
  138067. debug.maxDepth = tile.level;
  138068. }
  138069. if (screenSpaceError(primitive, frameState, tile) < primitive.maximumScreenSpaceError) {
  138070. // This tile meets SSE requirements, so render it.
  138071. if (tile.needsLoading) {
  138072. // Rendered tile meeting SSE loads with medium priority.
  138073. primitive._tileLoadQueueMedium.push(tile);
  138074. }
  138075. addTileToRenderList(primitive, tile);
  138076. return;
  138077. }
  138078. var southwestChild = tile.southwestChild;
  138079. var southeastChild = tile.southeastChild;
  138080. var northwestChild = tile.northwestChild;
  138081. var northeastChild = tile.northeastChild;
  138082. var allAreRenderable = southwestChild.renderable && southeastChild.renderable &&
  138083. northwestChild.renderable && northeastChild.renderable;
  138084. var allAreUpsampled = southwestChild.upsampledFromParent && southeastChild.upsampledFromParent &&
  138085. northwestChild.upsampledFromParent && northeastChild.upsampledFromParent;
  138086. if (allAreRenderable) {
  138087. if (allAreUpsampled) {
  138088. // No point in rendering the children because they're all upsampled. Render this tile instead.
  138089. addTileToRenderList(primitive, tile);
  138090. // Load the children even though we're (currently) not going to render them.
  138091. // A tile that is "upsampled only" right now might change its tune once it does more loading.
  138092. // A tile that is upsampled now and forever should also be done loading, so no harm done.
  138093. queueChildLoadNearToFar(primitive, frameState.camera.positionCartographic, southwestChild, southeastChild, northwestChild, northeastChild);
  138094. if (tile.needsLoading) {
  138095. // Rendered tile that's not waiting on children loads with medium priority.
  138096. primitive._tileLoadQueueMedium.push(tile);
  138097. }
  138098. } else {
  138099. // SSE is not good enough and children are loaded, so refine.
  138100. // No need to add the children to the load queue because they'll be added (if necessary) when they're visited.
  138101. visitVisibleChildrenNearToFar(primitive, southwestChild, southeastChild, northwestChild, northeastChild, frameState);
  138102. if (tile.needsLoading) {
  138103. // Tile is not rendered, so load it with low priority.
  138104. primitive._tileLoadQueueLow.push(tile);
  138105. }
  138106. }
  138107. } else {
  138108. // We'd like to refine but can't because not all of our children are renderable. Load the refinement blockers with high priority and
  138109. // render this tile in the meantime.
  138110. queueChildLoadNearToFar(primitive, frameState.camera.positionCartographic, southwestChild, southeastChild, northwestChild, northeastChild);
  138111. addTileToRenderList(primitive, tile);
  138112. if (tile.needsLoading) {
  138113. // We will refine this tile when it's possible, so load this tile only with low priority.
  138114. primitive._tileLoadQueueLow.push(tile);
  138115. }
  138116. }
  138117. }
  138118. function queueChildLoadNearToFar(primitive, cameraPosition, southwest, southeast, northwest, northeast) {
  138119. if (cameraPosition.longitude < southwest.east) {
  138120. if (cameraPosition.latitude < southwest.north) {
  138121. // Camera in southwest quadrant
  138122. queueChildTileLoad(primitive, southwest);
  138123. queueChildTileLoad(primitive, southeast);
  138124. queueChildTileLoad(primitive, northwest);
  138125. queueChildTileLoad(primitive, northeast);
  138126. } else {
  138127. // Camera in northwest quadrant
  138128. queueChildTileLoad(primitive, northwest);
  138129. queueChildTileLoad(primitive, southwest);
  138130. queueChildTileLoad(primitive, northeast);
  138131. queueChildTileLoad(primitive, southeast);
  138132. }
  138133. } else {
  138134. if (cameraPosition.latitude < southwest.north) {
  138135. // Camera southeast quadrant
  138136. queueChildTileLoad(primitive, southeast);
  138137. queueChildTileLoad(primitive, southwest);
  138138. queueChildTileLoad(primitive, northeast);
  138139. queueChildTileLoad(primitive, northwest);
  138140. } else {
  138141. // Camera in northeast quadrant
  138142. queueChildTileLoad(primitive, northeast);
  138143. queueChildTileLoad(primitive, northwest);
  138144. queueChildTileLoad(primitive, southeast);
  138145. queueChildTileLoad(primitive, southwest);
  138146. }
  138147. }
  138148. }
  138149. function queueChildTileLoad(primitive, childTile) {
  138150. primitive._tileReplacementQueue.markTileRendered(childTile);
  138151. if (childTile.needsLoading) {
  138152. if (childTile.renderable) {
  138153. primitive._tileLoadQueueLow.push(childTile);
  138154. } else {
  138155. // A tile blocking refine loads with high priority
  138156. primitive._tileLoadQueueHigh.push(childTile);
  138157. }
  138158. }
  138159. }
  138160. function visitVisibleChildrenNearToFar(primitive, southwest, southeast, northwest, northeast, frameState) {
  138161. var cameraPosition = frameState.camera.positionCartographic;
  138162. var tileProvider = primitive._tileProvider;
  138163. var occluders = primitive._occluders;
  138164. if (cameraPosition.longitude < southwest.rectangle.east) {
  138165. if (cameraPosition.latitude < southwest.rectangle.north) {
  138166. // Camera in southwest quadrant
  138167. visitIfVisible(primitive, southwest, tileProvider, frameState, occluders);
  138168. visitIfVisible(primitive, southeast, tileProvider, frameState, occluders);
  138169. visitIfVisible(primitive, northwest, tileProvider, frameState, occluders);
  138170. visitIfVisible(primitive, northeast, tileProvider, frameState, occluders);
  138171. } else {
  138172. // Camera in northwest quadrant
  138173. visitIfVisible(primitive, northwest, tileProvider, frameState, occluders);
  138174. visitIfVisible(primitive, southwest, tileProvider, frameState, occluders);
  138175. visitIfVisible(primitive, northeast, tileProvider, frameState, occluders);
  138176. visitIfVisible(primitive, southeast, tileProvider, frameState, occluders);
  138177. }
  138178. } else {
  138179. if (cameraPosition.latitude < southwest.rectangle.north) {
  138180. // Camera southeast quadrant
  138181. visitIfVisible(primitive, southeast, tileProvider, frameState, occluders);
  138182. visitIfVisible(primitive, southwest, tileProvider, frameState, occluders);
  138183. visitIfVisible(primitive, northeast, tileProvider, frameState, occluders);
  138184. visitIfVisible(primitive, northwest, tileProvider, frameState, occluders);
  138185. } else {
  138186. // Camera in northeast quadrant
  138187. visitIfVisible(primitive, northeast, tileProvider, frameState, occluders);
  138188. visitIfVisible(primitive, northwest, tileProvider, frameState, occluders);
  138189. visitIfVisible(primitive, southeast, tileProvider, frameState, occluders);
  138190. visitIfVisible(primitive, southwest, tileProvider, frameState, occluders);
  138191. }
  138192. }
  138193. }
  138194. function visitIfVisible(primitive, tile, tileProvider, frameState, occluders) {
  138195. if (tileProvider.computeTileVisibility(tile, frameState, occluders) !== Visibility.NONE) {
  138196. visitTile(primitive, frameState, tile);
  138197. } else {
  138198. ++primitive._debug.tilesCulled;
  138199. primitive._tileReplacementQueue.markTileRendered(tile);
  138200. }
  138201. }
  138202. /**
  138203. * Checks if the load queue length has changed since the last time we raised a queue change event - if so, raises
  138204. * a new one.
  138205. */
  138206. function raiseTileLoadProgressEvent(primitive) {
  138207. var currentLoadQueueLength = primitive._tileLoadQueueHigh.length + primitive._tileLoadQueueMedium.length + primitive._tileLoadQueueLow.length;
  138208. if (currentLoadQueueLength !== primitive._lastTileLoadQueueLength) {
  138209. primitive._tileLoadProgressEvent.raiseEvent(currentLoadQueueLength);
  138210. primitive._lastTileLoadQueueLength = currentLoadQueueLength;
  138211. }
  138212. }
  138213. function screenSpaceError(primitive, frameState, tile) {
  138214. if (frameState.mode === SceneMode.SCENE2D) {
  138215. return screenSpaceError2D(primitive, frameState, tile);
  138216. }
  138217. var maxGeometricError = primitive._tileProvider.getLevelMaximumGeometricError(tile.level);
  138218. var distance = tile._distance;
  138219. var height = frameState.context.drawingBufferHeight;
  138220. var sseDenominator = frameState.camera.frustum.sseDenominator;
  138221. var error = (maxGeometricError * height) / (distance * sseDenominator);
  138222. if (frameState.fog.enabled) {
  138223. error = error - CesiumMath.fog(distance, frameState.fog.density) * frameState.fog.sse;
  138224. }
  138225. return error;
  138226. }
  138227. function screenSpaceError2D(primitive, frameState, tile) {
  138228. var camera = frameState.camera;
  138229. var frustum = camera.frustum;
  138230. var context = frameState.context;
  138231. var width = context.drawingBufferWidth;
  138232. var height = context.drawingBufferHeight;
  138233. var maxGeometricError = primitive._tileProvider.getLevelMaximumGeometricError(tile.level);
  138234. var pixelSize = Math.max(frustum.top - frustum.bottom, frustum.right - frustum.left) / Math.max(width, height);
  138235. return maxGeometricError / pixelSize;
  138236. }
  138237. function addTileToRenderList(primitive, tile) {
  138238. primitive._tilesToRender.push(tile);
  138239. ++primitive._debug.tilesRendered;
  138240. }
  138241. function processTileLoadQueue(primitive, frameState) {
  138242. var tileLoadQueueHigh = primitive._tileLoadQueueHigh;
  138243. var tileLoadQueueMedium = primitive._tileLoadQueueMedium;
  138244. var tileLoadQueueLow = primitive._tileLoadQueueLow;
  138245. var tileProvider = primitive._tileProvider;
  138246. if (tileLoadQueueHigh.length === 0 && tileLoadQueueMedium.length === 0 && tileLoadQueueLow.length === 0) {
  138247. return;
  138248. }
  138249. // Remove any tiles that were not used this frame beyond the number
  138250. // we're allowed to keep.
  138251. primitive._tileReplacementQueue.trimTiles(primitive.tileCacheSize);
  138252. var endTime = getTimestamp() + primitive._loadQueueTimeSlice;
  138253. processSinglePriorityLoadQueue(primitive, frameState, tileProvider, endTime, tileLoadQueueHigh);
  138254. processSinglePriorityLoadQueue(primitive, frameState, tileProvider, endTime, tileLoadQueueMedium);
  138255. processSinglePriorityLoadQueue(primitive, frameState, tileProvider, endTime, tileLoadQueueLow);
  138256. }
  138257. function processSinglePriorityLoadQueue(primitive, frameState, tileProvider, endTime, loadQueue) {
  138258. for (var i = 0, len = loadQueue.length; i < len && getTimestamp() < endTime; ++i) {
  138259. var tile = loadQueue[i];
  138260. primitive._tileReplacementQueue.markTileRendered(tile);
  138261. tileProvider.loadTile(frameState, tile);
  138262. }
  138263. }
  138264. var scratchRay = new Ray();
  138265. var scratchCartographic = new Cartographic();
  138266. var scratchPosition = new Cartesian3();
  138267. function updateHeights(primitive, frameState) {
  138268. var tilesToUpdateHeights = primitive._tileToUpdateHeights;
  138269. var terrainProvider = primitive._tileProvider.terrainProvider;
  138270. var startTime = getTimestamp();
  138271. var timeSlice = primitive._updateHeightsTimeSlice;
  138272. var endTime = startTime + timeSlice;
  138273. var mode = frameState.mode;
  138274. var projection = frameState.mapProjection;
  138275. var ellipsoid = projection.ellipsoid;
  138276. while (tilesToUpdateHeights.length > 0) {
  138277. var tile = tilesToUpdateHeights[0];
  138278. var customData = tile.customData;
  138279. var customDataLength = customData.length;
  138280. var timeSliceMax = false;
  138281. for (var i = primitive._lastTileIndex; i < customDataLength; ++i) {
  138282. var data = customData[i];
  138283. if (tile.level > data.level) {
  138284. if (!defined(data.positionOnEllipsoidSurface)) {
  138285. // cartesian has to be on the ellipsoid surface for `ellipsoid.geodeticSurfaceNormal`
  138286. data.positionOnEllipsoidSurface = Cartesian3.fromRadians(data.positionCartographic.longitude, data.positionCartographic.latitude, 0.0, ellipsoid);
  138287. }
  138288. if (mode === SceneMode.SCENE3D) {
  138289. var surfaceNormal = ellipsoid.geodeticSurfaceNormal(data.positionOnEllipsoidSurface, scratchRay.direction);
  138290. // compute origin point
  138291. // Try to find the intersection point between the surface normal and z-axis.
  138292. // minimum height (-11500.0) for the terrain set, need to get this information from the terrain provider
  138293. var rayOrigin = ellipsoid.getSurfaceNormalIntersectionWithZAxis(data.positionOnEllipsoidSurface, 11500.0, scratchRay.origin);
  138294. // Theoretically, not with Earth datums, the intersection point can be outside the ellipsoid
  138295. if (!defined(rayOrigin)) {
  138296. // intersection point is outside the ellipsoid, try other value
  138297. // minimum height (-11500.0) for the terrain set, need to get this information from the terrain provider
  138298. var magnitude = Math.min(defaultValue(tile.data.minimumHeight, 0.0),-11500.0);
  138299. // multiply by the *positive* value of the magnitude
  138300. var vectorToMinimumPoint = Cartesian3.multiplyByScalar(surfaceNormal, Math.abs(magnitude) + 1, scratchPosition);
  138301. Cartesian3.subtract(data.positionOnEllipsoidSurface, vectorToMinimumPoint, scratchRay.origin);
  138302. }
  138303. } else {
  138304. Cartographic.clone(data.positionCartographic, scratchCartographic);
  138305. // minimum height for the terrain set, need to get this information from the terrain provider
  138306. scratchCartographic.height = -11500.0;
  138307. projection.project(scratchCartographic, scratchPosition);
  138308. Cartesian3.fromElements(scratchPosition.z, scratchPosition.x, scratchPosition.y, scratchPosition);
  138309. Cartesian3.clone(scratchPosition, scratchRay.origin);
  138310. Cartesian3.clone(Cartesian3.UNIT_X, scratchRay.direction);
  138311. }
  138312. var position = tile.data.pick(scratchRay, mode, projection, false, scratchPosition);
  138313. if (defined(position)) {
  138314. data.callback(position);
  138315. }
  138316. data.level = tile.level;
  138317. } else if (tile.level === data.level) {
  138318. var children = tile.children;
  138319. var childrenLength = children.length;
  138320. var child;
  138321. for (var j = 0; j < childrenLength; ++j) {
  138322. child = children[j];
  138323. if (Rectangle.contains(child.rectangle, data.positionCartographic)) {
  138324. break;
  138325. }
  138326. }
  138327. var tileDataAvailable = terrainProvider.getTileDataAvailable(child.x, child.y, child.level);
  138328. var parentTile = tile.parent;
  138329. if ((defined(tileDataAvailable) && !tileDataAvailable) ||
  138330. (defined(parentTile) && defined(parentTile.data) && defined(parentTile.data.terrainData) &&
  138331. !parentTile.data.terrainData.isChildAvailable(parentTile.x, parentTile.y, child.x, child.y))) {
  138332. data.removeFunc();
  138333. }
  138334. }
  138335. if (getTimestamp() >= endTime) {
  138336. timeSliceMax = true;
  138337. break;
  138338. }
  138339. }
  138340. if (timeSliceMax) {
  138341. primitive._lastTileIndex = i;
  138342. break;
  138343. } else {
  138344. primitive._lastTileIndex = 0;
  138345. tilesToUpdateHeights.shift();
  138346. }
  138347. }
  138348. }
  138349. function createRenderCommandsForSelectedTiles(primitive, frameState) {
  138350. var tileProvider = primitive._tileProvider;
  138351. var tilesToRender = primitive._tilesToRender;
  138352. var tilesToUpdateHeights = primitive._tileToUpdateHeights;
  138353. for (var i = 0, len = tilesToRender.length; i < len; ++i) {
  138354. var tile = tilesToRender[i];
  138355. tileProvider.showTileThisFrame(tile, frameState);
  138356. if (tile._frameRendered !== frameState.frameNumber - 1) {
  138357. tilesToUpdateHeights.push(tile);
  138358. }
  138359. tile._frameRendered = frameState.frameNumber;
  138360. }
  138361. }
  138362. return QuadtreePrimitive;
  138363. });
  138364. /*global define*/
  138365. define('Scene/Globe',[
  138366. '../Core/BoundingSphere',
  138367. '../Core/buildModuleUrl',
  138368. '../Core/Cartesian3',
  138369. '../Core/Cartographic',
  138370. '../Core/defaultValue',
  138371. '../Core/defined',
  138372. '../Core/defineProperties',
  138373. '../Core/destroyObject',
  138374. '../Core/DeveloperError',
  138375. '../Core/Ellipsoid',
  138376. '../Core/EllipsoidTerrainProvider',
  138377. '../Core/Event',
  138378. '../Core/IntersectionTests',
  138379. '../Core/loadImage',
  138380. '../Core/Math',
  138381. '../Core/Ray',
  138382. '../Core/Rectangle',
  138383. '../Renderer/ShaderSource',
  138384. '../Renderer/Texture',
  138385. '../Shaders/GlobeFS',
  138386. '../Shaders/GlobeVS',
  138387. '../Shaders/GroundAtmosphere',
  138388. '../ThirdParty/when',
  138389. './GlobeSurfaceShaderSet',
  138390. './GlobeSurfaceTileProvider',
  138391. './ImageryLayerCollection',
  138392. './QuadtreePrimitive',
  138393. './SceneMode',
  138394. './ShadowMode'
  138395. ], function(
  138396. BoundingSphere,
  138397. buildModuleUrl,
  138398. Cartesian3,
  138399. Cartographic,
  138400. defaultValue,
  138401. defined,
  138402. defineProperties,
  138403. destroyObject,
  138404. DeveloperError,
  138405. Ellipsoid,
  138406. EllipsoidTerrainProvider,
  138407. Event,
  138408. IntersectionTests,
  138409. loadImage,
  138410. CesiumMath,
  138411. Ray,
  138412. Rectangle,
  138413. ShaderSource,
  138414. Texture,
  138415. GlobeFS,
  138416. GlobeVS,
  138417. GroundAtmosphere,
  138418. when,
  138419. GlobeSurfaceShaderSet,
  138420. GlobeSurfaceTileProvider,
  138421. ImageryLayerCollection,
  138422. QuadtreePrimitive,
  138423. SceneMode,
  138424. ShadowMode) {
  138425. 'use strict';
  138426. /**
  138427. * The globe rendered in the scene, including its terrain ({@link Globe#terrainProvider})
  138428. * and imagery layers ({@link Globe#imageryLayers}). Access the globe using {@link Scene#globe}.
  138429. *
  138430. * @alias Globe
  138431. * @constructor
  138432. *
  138433. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] Determines the size and shape of the
  138434. * globe.
  138435. */
  138436. function Globe(ellipsoid) {
  138437. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  138438. var terrainProvider = new EllipsoidTerrainProvider({
  138439. ellipsoid : ellipsoid
  138440. });
  138441. var imageryLayerCollection = new ImageryLayerCollection();
  138442. this._ellipsoid = ellipsoid;
  138443. this._imageryLayerCollection = imageryLayerCollection;
  138444. this._surfaceShaderSet = new GlobeSurfaceShaderSet();
  138445. this._surfaceShaderSet.baseVertexShaderSource = new ShaderSource({
  138446. sources : [GroundAtmosphere, GlobeVS]
  138447. });
  138448. this._surfaceShaderSet.baseFragmentShaderSource = new ShaderSource({
  138449. sources : [GlobeFS]
  138450. });
  138451. this._surface = new QuadtreePrimitive({
  138452. tileProvider : new GlobeSurfaceTileProvider({
  138453. terrainProvider : terrainProvider,
  138454. imageryLayers : imageryLayerCollection,
  138455. surfaceShaderSet : this._surfaceShaderSet
  138456. })
  138457. });
  138458. this._terrainProvider = terrainProvider;
  138459. this._terrainProviderChanged = new Event();
  138460. /**
  138461. * Determines if the globe will be shown.
  138462. *
  138463. * @type {Boolean}
  138464. * @default true
  138465. */
  138466. this.show = true;
  138467. /**
  138468. * The normal map to use for rendering waves in the ocean. Setting this property will
  138469. * only have an effect if the configured terrain provider includes a water mask.
  138470. *
  138471. * @type {String}
  138472. * @default buildModuleUrl('Assets/Textures/waterNormalsSmall.jpg')
  138473. */
  138474. this.oceanNormalMapUrl = buildModuleUrl('Assets/Textures/waterNormalsSmall.jpg');
  138475. this._oceanNormalMapUrl = undefined;
  138476. /**
  138477. * The maximum screen-space error used to drive level-of-detail refinement. Higher
  138478. * values will provide better performance but lower visual quality.
  138479. *
  138480. * @type {Number}
  138481. * @default 2
  138482. */
  138483. this.maximumScreenSpaceError = 2;
  138484. /**
  138485. * The size of the terrain tile cache, expressed as a number of tiles. Any additional
  138486. * tiles beyond this number will be freed, as long as they aren't needed for rendering
  138487. * this frame. A larger number will consume more memory but will show detail faster
  138488. * when, for example, zooming out and then back in.
  138489. *
  138490. * @type {Number}
  138491. * @default 100
  138492. */
  138493. this.tileCacheSize = 100;
  138494. /**
  138495. * Enable lighting the globe with the sun as a light source.
  138496. *
  138497. * @type {Boolean}
  138498. * @default false
  138499. */
  138500. this.enableLighting = false;
  138501. /**
  138502. * The distance where everything becomes lit. This only takes effect
  138503. * when <code>enableLighting</code> is <code>true</code>.
  138504. *
  138505. * @type {Number}
  138506. * @default 6500000.0
  138507. */
  138508. this.lightingFadeOutDistance = 6500000.0;
  138509. /**
  138510. * The distance where lighting resumes. This only takes effect
  138511. * when <code>enableLighting</code> is <code>true</code>.
  138512. *
  138513. * @type {Number}
  138514. * @default 9000000.0
  138515. */
  138516. this.lightingFadeInDistance = 9000000.0;
  138517. /**
  138518. * True if an animated wave effect should be shown in areas of the globe
  138519. * covered by water; otherwise, false. This property is ignored if the
  138520. * <code>terrainProvider</code> does not provide a water mask.
  138521. *
  138522. * @type {Boolean}
  138523. * @default true
  138524. */
  138525. this.showWaterEffect = true;
  138526. /**
  138527. * True if primitives such as billboards, polylines, labels, etc. should be depth-tested
  138528. * against the terrain surface, or false if such primitives should always be drawn on top
  138529. * of terrain unless they're on the opposite side of the globe. The disadvantage of depth
  138530. * testing primitives against terrain is that slight numerical noise or terrain level-of-detail
  138531. * switched can sometimes make a primitive that should be on the surface disappear underneath it.
  138532. *
  138533. * @type {Boolean}
  138534. * @default false
  138535. *
  138536. */
  138537. this.depthTestAgainstTerrain = false;
  138538. /**
  138539. * Determines whether the globe casts or receives shadows from each light source. Setting the globe
  138540. * to cast shadows may impact performance since the terrain is rendered again from the light's perspective.
  138541. * Currently only terrain that is in view casts shadows. By default the globe does not cast shadows.
  138542. *
  138543. * @type {ShadowMode}
  138544. * @default ShadowMode.RECEIVE_ONLY
  138545. */
  138546. this.shadows = ShadowMode.RECEIVE_ONLY;
  138547. this._oceanNormalMap = undefined;
  138548. this._zoomedOutOceanSpecularIntensity = 0.5;
  138549. }
  138550. defineProperties(Globe.prototype, {
  138551. /**
  138552. * Gets an ellipsoid describing the shape of this globe.
  138553. * @memberof Globe.prototype
  138554. * @type {Ellipsoid}
  138555. */
  138556. ellipsoid : {
  138557. get : function() {
  138558. return this._ellipsoid;
  138559. }
  138560. },
  138561. /**
  138562. * Gets the collection of image layers that will be rendered on this globe.
  138563. * @memberof Globe.prototype
  138564. * @type {ImageryLayerCollection}
  138565. */
  138566. imageryLayers : {
  138567. get : function() {
  138568. return this._imageryLayerCollection;
  138569. }
  138570. },
  138571. /**
  138572. * Gets or sets the color of the globe when no imagery is available.
  138573. * @memberof Globe.prototype
  138574. * @type {Color}
  138575. */
  138576. baseColor : {
  138577. get : function() {
  138578. return this._surface.tileProvider.baseColor;
  138579. },
  138580. set : function(value) {
  138581. this._surface.tileProvider.baseColor = value;
  138582. }
  138583. },
  138584. /**
  138585. * The terrain provider providing surface geometry for this globe.
  138586. * @type {TerrainProvider}
  138587. *
  138588. * @memberof Globe.prototype
  138589. * @type {TerrainProvider}
  138590. *
  138591. */
  138592. terrainProvider : {
  138593. get : function() {
  138594. return this._terrainProvider;
  138595. },
  138596. set : function(value) {
  138597. if (value !== this._terrainProvider) {
  138598. this._terrainProvider = value;
  138599. this._terrainProviderChanged.raiseEvent(value);
  138600. }
  138601. }
  138602. },
  138603. /**
  138604. * Gets an event that's raised when the terrain provider is changed
  138605. *
  138606. * @memberof Globe.prototype
  138607. * @type {Event}
  138608. * @readonly
  138609. */
  138610. terrainProviderChanged : {
  138611. get: function() {
  138612. return this._terrainProviderChanged;
  138613. }
  138614. },
  138615. /**
  138616. * Gets an event that's raised when the length of the tile load queue has changed since the last render frame. When the load queue is empty,
  138617. * all terrain and imagery for the current view have been loaded. The event passes the new length of the tile load queue.
  138618. *
  138619. * @memberof Globe.prototype
  138620. * @type {Event}
  138621. */
  138622. tileLoadProgressEvent : {
  138623. get: function() {
  138624. return this._surface.tileLoadProgressEvent;
  138625. }
  138626. }
  138627. });
  138628. function createComparePickTileFunction(rayOrigin) {
  138629. return function(a, b) {
  138630. var aDist = BoundingSphere.distanceSquaredTo(a.pickBoundingSphere, rayOrigin);
  138631. var bDist = BoundingSphere.distanceSquaredTo(b.pickBoundingSphere, rayOrigin);
  138632. return aDist - bDist;
  138633. };
  138634. }
  138635. var scratchArray = [];
  138636. var scratchSphereIntersectionResult = {
  138637. start : 0.0,
  138638. stop : 0.0
  138639. };
  138640. /**
  138641. * Find an intersection between a ray and the globe surface that was rendered. The ray must be given in world coordinates.
  138642. *
  138643. * @param {Ray} ray The ray to test for intersection.
  138644. * @param {Scene} scene The scene.
  138645. * @param {Cartesian3} [result] The object onto which to store the result.
  138646. * @returns {Cartesian3|undefined} The intersection or <code>undefined</code> if none was found.
  138647. *
  138648. * @example
  138649. * // find intersection of ray through a pixel and the globe
  138650. * var ray = viewer.camera.getPickRay(windowCoordinates);
  138651. * var intersection = globe.pick(ray, scene);
  138652. */
  138653. Globe.prototype.pick = function(ray, scene, result) {
  138654. if (!defined(ray)) {
  138655. throw new DeveloperError('ray is required');
  138656. }
  138657. if (!defined(scene)) {
  138658. throw new DeveloperError('scene is required');
  138659. }
  138660. var mode = scene.mode;
  138661. var projection = scene.mapProjection;
  138662. var sphereIntersections = scratchArray;
  138663. sphereIntersections.length = 0;
  138664. var tilesToRender = this._surface._tilesToRender;
  138665. var length = tilesToRender.length;
  138666. var tile;
  138667. var i;
  138668. for (i = 0; i < length; ++i) {
  138669. tile = tilesToRender[i];
  138670. var tileData = tile.data;
  138671. if (!defined(tileData)) {
  138672. continue;
  138673. }
  138674. var boundingVolume = tileData.pickBoundingSphere;
  138675. if (mode !== SceneMode.SCENE3D) {
  138676. BoundingSphere.fromRectangleWithHeights2D(tile.rectangle, projection, tileData.minimumHeight, tileData.maximumHeight, boundingVolume);
  138677. Cartesian3.fromElements(boundingVolume.center.z, boundingVolume.center.x, boundingVolume.center.y, boundingVolume.center);
  138678. } else {
  138679. BoundingSphere.clone(tileData.boundingSphere3D, boundingVolume);
  138680. }
  138681. var boundingSphereIntersection = IntersectionTests.raySphere(ray, boundingVolume, scratchSphereIntersectionResult);
  138682. if (defined(boundingSphereIntersection)) {
  138683. sphereIntersections.push(tileData);
  138684. }
  138685. }
  138686. sphereIntersections.sort(createComparePickTileFunction(ray.origin));
  138687. var intersection;
  138688. length = sphereIntersections.length;
  138689. for (i = 0; i < length; ++i) {
  138690. intersection = sphereIntersections[i].pick(ray, scene.mode, scene.mapProjection, true, result);
  138691. if (defined(intersection)) {
  138692. break;
  138693. }
  138694. }
  138695. return intersection;
  138696. };
  138697. var scratchGetHeightCartesian = new Cartesian3();
  138698. var scratchGetHeightIntersection = new Cartesian3();
  138699. var scratchGetHeightCartographic = new Cartographic();
  138700. var scratchGetHeightRay = new Ray();
  138701. function tileIfContainsCartographic(tile, cartographic) {
  138702. return Rectangle.contains(tile.rectangle, cartographic) ? tile : undefined;
  138703. }
  138704. /**
  138705. * Get the height of the surface at a given cartographic.
  138706. *
  138707. * @param {Cartographic} cartographic The cartographic for which to find the height.
  138708. * @returns {Number|undefined} The height of the cartographic or undefined if it could not be found.
  138709. */
  138710. Globe.prototype.getHeight = function(cartographic) {
  138711. if (!defined(cartographic)) {
  138712. throw new DeveloperError('cartographic is required');
  138713. }
  138714. var levelZeroTiles = this._surface._levelZeroTiles;
  138715. if (!defined(levelZeroTiles)) {
  138716. return;
  138717. }
  138718. var tile;
  138719. var i;
  138720. var length = levelZeroTiles.length;
  138721. for (i = 0; i < length; ++i) {
  138722. tile = levelZeroTiles[i];
  138723. if (Rectangle.contains(tile.rectangle, cartographic)) {
  138724. break;
  138725. }
  138726. }
  138727. if (!defined(tile) || !Rectangle.contains(tile.rectangle, cartographic)) {
  138728. return undefined;
  138729. }
  138730. while (tile.renderable) {
  138731. tile = tileIfContainsCartographic(tile.southwestChild, cartographic) ||
  138732. tileIfContainsCartographic(tile.southeastChild, cartographic) ||
  138733. tileIfContainsCartographic(tile.northwestChild, cartographic) ||
  138734. tile.northeastChild;
  138735. }
  138736. while (defined(tile) && (!defined(tile.data) || !defined(tile.data.pickTerrain))) {
  138737. tile = tile.parent;
  138738. }
  138739. if (!defined(tile)) {
  138740. return undefined;
  138741. }
  138742. var ellipsoid = this._surface._tileProvider.tilingScheme.ellipsoid;
  138743. //cartesian has to be on the ellipsoid surface for `ellipsoid.geodeticSurfaceNormal`
  138744. var cartesian = Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0, ellipsoid, scratchGetHeightCartesian);
  138745. var ray = scratchGetHeightRay;
  138746. var surfaceNormal = ellipsoid.geodeticSurfaceNormal(cartesian, ray.direction);
  138747. // Try to find the intersection point between the surface normal and z-axis.
  138748. // minimum height (-11500.0) for the terrain set, need to get this information from the terrain provider
  138749. var rayOrigin = ellipsoid.getSurfaceNormalIntersectionWithZAxis(cartesian, 11500.0, ray.origin);
  138750. // Theoretically, not with Earth datums, the intersection point can be outside the ellipsoid
  138751. if (!defined(rayOrigin)) {
  138752. // intersection point is outside the ellipsoid, try other value
  138753. // minimum height (-11500.0) for the terrain set, need to get this information from the terrain provider
  138754. var magnitude = Math.min(defaultValue(tile.data.minimumHeight, 0.0),-11500.0);
  138755. // multiply by the *positive* value of the magnitude
  138756. var vectorToMinimumPoint = Cartesian3.multiplyByScalar(surfaceNormal, Math.abs(magnitude) + 1, scratchGetHeightIntersection);
  138757. Cartesian3.subtract(cartesian, vectorToMinimumPoint, ray.origin);
  138758. }
  138759. var intersection = tile.data.pick(ray, undefined, undefined, false, scratchGetHeightIntersection);
  138760. if (!defined(intersection)) {
  138761. return undefined;
  138762. }
  138763. return ellipsoid.cartesianToCartographic(intersection, scratchGetHeightCartographic).height;
  138764. };
  138765. /**
  138766. * @private
  138767. */
  138768. Globe.prototype.beginFrame = function(frameState) {
  138769. if (!this.show) {
  138770. return;
  138771. }
  138772. var surface = this._surface;
  138773. var tileProvider = surface.tileProvider;
  138774. var terrainProvider = this.terrainProvider;
  138775. var hasWaterMask = this.showWaterEffect && terrainProvider.ready && terrainProvider.hasWaterMask;
  138776. if (hasWaterMask && this.oceanNormalMapUrl !== this._oceanNormalMapUrl) {
  138777. // url changed, load new normal map asynchronously
  138778. var oceanNormalMapUrl = this.oceanNormalMapUrl;
  138779. this._oceanNormalMapUrl = oceanNormalMapUrl;
  138780. if (defined(oceanNormalMapUrl)) {
  138781. var that = this;
  138782. when(loadImage(oceanNormalMapUrl), function(image) {
  138783. if (oceanNormalMapUrl !== that.oceanNormalMapUrl) {
  138784. // url changed while we were loading
  138785. return;
  138786. }
  138787. that._oceanNormalMap = that._oceanNormalMap && that._oceanNormalMap.destroy();
  138788. that._oceanNormalMap = new Texture({
  138789. context : frameState.context,
  138790. source : image
  138791. });
  138792. });
  138793. } else {
  138794. this._oceanNormalMap = this._oceanNormalMap && this._oceanNormalMap.destroy();
  138795. }
  138796. }
  138797. var mode = frameState.mode;
  138798. var pass = frameState.passes;
  138799. if (pass.render) {
  138800. // Don't show the ocean specular highlights when zoomed out in 2D and Columbus View.
  138801. if (mode === SceneMode.SCENE3D) {
  138802. this._zoomedOutOceanSpecularIntensity = 0.5;
  138803. } else {
  138804. this._zoomedOutOceanSpecularIntensity = 0.0;
  138805. }
  138806. surface.maximumScreenSpaceError = this.maximumScreenSpaceError;
  138807. surface.tileCacheSize = this.tileCacheSize;
  138808. tileProvider.terrainProvider = this.terrainProvider;
  138809. tileProvider.lightingFadeOutDistance = this.lightingFadeOutDistance;
  138810. tileProvider.lightingFadeInDistance = this.lightingFadeInDistance;
  138811. tileProvider.zoomedOutOceanSpecularIntensity = this._zoomedOutOceanSpecularIntensity;
  138812. tileProvider.hasWaterMask = hasWaterMask;
  138813. tileProvider.oceanNormalMap = this._oceanNormalMap;
  138814. tileProvider.enableLighting = this.enableLighting;
  138815. tileProvider.shadows = this.shadows;
  138816. surface.beginFrame(frameState);
  138817. }
  138818. };
  138819. /**
  138820. * @private
  138821. */
  138822. Globe.prototype.update = function(frameState) {
  138823. if (!this.show) {
  138824. return;
  138825. }
  138826. var surface = this._surface;
  138827. var pass = frameState.passes;
  138828. if (pass.render) {
  138829. surface.update(frameState);
  138830. }
  138831. if (pass.pick) {
  138832. surface.update(frameState);
  138833. }
  138834. };
  138835. /**
  138836. * @private
  138837. */
  138838. Globe.prototype.endFrame = function(frameState) {
  138839. if (!this.show) {
  138840. return;
  138841. }
  138842. if (frameState.passes.render) {
  138843. this._surface.endFrame(frameState);
  138844. }
  138845. };
  138846. /**
  138847. * Returns true if this object was destroyed; otherwise, false.
  138848. * <br /><br />
  138849. * If this object was destroyed, it should not be used; calling any function other than
  138850. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  138851. *
  138852. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  138853. *
  138854. * @see Globe#destroy
  138855. */
  138856. Globe.prototype.isDestroyed = function() {
  138857. return false;
  138858. };
  138859. /**
  138860. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  138861. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  138862. * <br /><br />
  138863. * Once an object is destroyed, it should not be used; calling any function other than
  138864. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  138865. * assign the return value (<code>undefined</code>) to the object as done in the example.
  138866. *
  138867. * @returns {undefined}
  138868. *
  138869. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  138870. *
  138871. *
  138872. * @example
  138873. * globe = globe && globe.destroy();
  138874. *
  138875. * @see Globe#isDestroyed
  138876. */
  138877. Globe.prototype.destroy = function() {
  138878. this._surfaceShaderSet = this._surfaceShaderSet && this._surfaceShaderSet.destroy();
  138879. this._surface = this._surface && this._surface.destroy();
  138880. this._oceanNormalMap = this._oceanNormalMap && this._oceanNormalMap.destroy();
  138881. return destroyObject(this);
  138882. };
  138883. return Globe;
  138884. });
  138885. //This file is automatically rebuilt by the Cesium build process.
  138886. /*global define*/
  138887. define('Shaders/PostProcessFilters/PassThrough',[],function() {
  138888. 'use strict';
  138889. return "uniform sampler2D u_texture;\n\
  138890. varying vec2 v_textureCoordinates;\n\
  138891. void main()\n\
  138892. {\n\
  138893. gl_FragColor = texture2D(u_texture, v_textureCoordinates);\n\
  138894. }\n\
  138895. ";
  138896. });
  138897. /*global define*/
  138898. define('Scene/GlobeDepth',[
  138899. '../Core/BoundingRectangle',
  138900. '../Core/Color',
  138901. '../Core/defined',
  138902. '../Core/destroyObject',
  138903. '../Core/PixelFormat',
  138904. '../Renderer/ClearCommand',
  138905. '../Renderer/Framebuffer',
  138906. '../Renderer/PixelDatatype',
  138907. '../Renderer/RenderState',
  138908. '../Renderer/Texture',
  138909. '../Shaders/PostProcessFilters/PassThrough'
  138910. ], function(
  138911. BoundingRectangle,
  138912. Color,
  138913. defined,
  138914. destroyObject,
  138915. PixelFormat,
  138916. ClearCommand,
  138917. Framebuffer,
  138918. PixelDatatype,
  138919. RenderState,
  138920. Texture,
  138921. PassThrough) {
  138922. 'use strict';
  138923. /**
  138924. * @private
  138925. */
  138926. function GlobeDepth() {
  138927. this._colorTexture = undefined;
  138928. this._depthStencilTexture = undefined;
  138929. this._globeDepthTexture = undefined;
  138930. this.framebuffer = undefined;
  138931. this._copyDepthFramebuffer = undefined;
  138932. this._clearColorCommand = undefined;
  138933. this._copyColorCommand = undefined;
  138934. this._copyDepthCommand = undefined;
  138935. this._viewport = new BoundingRectangle();
  138936. this._rs = undefined;
  138937. this._debugGlobeDepthViewportCommand = undefined;
  138938. }
  138939. function executeDebugGlobeDepth(globeDepth, context, passState) {
  138940. if (!defined(globeDepth._debugGlobeDepthViewportCommand)) {
  138941. var fs =
  138942. 'uniform sampler2D u_texture;\n' +
  138943. 'varying vec2 v_textureCoordinates;\n' +
  138944. 'void main()\n' +
  138945. '{\n' +
  138946. ' float z_window = czm_unpackDepth(texture2D(u_texture, v_textureCoordinates));\n' +
  138947. ' float n_range = czm_depthRange.near;\n' +
  138948. ' float f_range = czm_depthRange.far;\n' +
  138949. ' float z_ndc = (2.0 * z_window - n_range - f_range) / (f_range - n_range);\n' +
  138950. ' float scale = pow(z_ndc * 0.5 + 0.5, 8.0);\n' +
  138951. ' gl_FragColor = vec4(mix(vec3(0.0), vec3(1.0), scale), 1.0);\n' +
  138952. '}\n';
  138953. globeDepth._debugGlobeDepthViewportCommand = context.createViewportQuadCommand(fs, {
  138954. uniformMap : {
  138955. u_texture : function() {
  138956. return globeDepth._globeDepthTexture;
  138957. }
  138958. },
  138959. owner : globeDepth
  138960. });
  138961. }
  138962. globeDepth._debugGlobeDepthViewportCommand.execute(context, passState);
  138963. }
  138964. function destroyTextures(globeDepth) {
  138965. globeDepth._colorTexture = globeDepth._colorTexture && !globeDepth._colorTexture.isDestroyed() && globeDepth._colorTexture.destroy();
  138966. globeDepth._depthStencilTexture = globeDepth._depthStencilTexture && !globeDepth._depthStencilTexture.isDestroyed() && globeDepth._depthStencilTexture.destroy();
  138967. globeDepth._globeDepthTexture = globeDepth._globeDepthTexture && !globeDepth._globeDepthTexture.isDestroyed() && globeDepth._globeDepthTexture.destroy();
  138968. }
  138969. function destroyFramebuffers(globeDepth) {
  138970. globeDepth.framebuffer = globeDepth.framebuffer && !globeDepth.framebuffer.isDestroyed() && globeDepth.framebuffer.destroy();
  138971. globeDepth._copyDepthFramebuffer = globeDepth._copyDepthFramebuffer && !globeDepth._copyDepthFramebuffer.isDestroyed() && globeDepth._copyDepthFramebuffer.destroy();
  138972. }
  138973. function createTextures(globeDepth, context, width, height) {
  138974. globeDepth._colorTexture = new Texture({
  138975. context : context,
  138976. width : width,
  138977. height : height,
  138978. pixelFormat : PixelFormat.RGBA,
  138979. pixelDatatype : PixelDatatype.UNSIGNED_BYTE
  138980. });
  138981. globeDepth._depthStencilTexture = new Texture({
  138982. context : context,
  138983. width : width,
  138984. height : height,
  138985. pixelFormat : PixelFormat.DEPTH_STENCIL,
  138986. pixelDatatype : PixelDatatype.UNSIGNED_INT_24_8
  138987. });
  138988. globeDepth._globeDepthTexture = new Texture({
  138989. context : context,
  138990. width : width,
  138991. height : height,
  138992. pixelFormat : PixelFormat.RGBA,
  138993. pixelDatatype : PixelDatatype.UNSIGNED_BYTE
  138994. });
  138995. }
  138996. function createFramebuffers(globeDepth, context, width, height) {
  138997. globeDepth.framebuffer = new Framebuffer({
  138998. context : context,
  138999. colorTextures : [globeDepth._colorTexture],
  139000. depthStencilTexture : globeDepth._depthStencilTexture,
  139001. destroyAttachments : false
  139002. });
  139003. globeDepth._copyDepthFramebuffer = new Framebuffer({
  139004. context : context,
  139005. colorTextures : [globeDepth._globeDepthTexture],
  139006. destroyAttachments : false
  139007. });
  139008. }
  139009. function updateFramebuffers(globeDepth, context, width, height) {
  139010. var colorTexture = globeDepth._colorTexture;
  139011. var textureChanged = !defined(colorTexture) || colorTexture.width !== width || colorTexture.height !== height;
  139012. if (!defined(globeDepth.framebuffer) || textureChanged) {
  139013. destroyTextures(globeDepth);
  139014. destroyFramebuffers(globeDepth);
  139015. createTextures(globeDepth, context, width, height);
  139016. createFramebuffers(globeDepth, context, width, height);
  139017. }
  139018. }
  139019. function updateCopyCommands(globeDepth, context, width, height) {
  139020. globeDepth._viewport.width = width;
  139021. globeDepth._viewport.height = height;
  139022. if (!defined(globeDepth._rs) || !BoundingRectangle.equals(globeDepth._viewport, globeDepth._rs.viewport)) {
  139023. globeDepth._rs = RenderState.fromCache({
  139024. viewport : globeDepth._viewport
  139025. });
  139026. }
  139027. if (!defined(globeDepth._copyDepthCommand)) {
  139028. var fs =
  139029. 'uniform sampler2D u_texture;\n' +
  139030. 'varying vec2 v_textureCoordinates;\n' +
  139031. 'void main()\n' +
  139032. '{\n' +
  139033. ' gl_FragColor = czm_packDepth(texture2D(u_texture, v_textureCoordinates).r);\n' +
  139034. '}\n';
  139035. globeDepth._copyDepthCommand = context.createViewportQuadCommand(fs, {
  139036. uniformMap : {
  139037. u_texture : function() {
  139038. return globeDepth._depthStencilTexture;
  139039. }
  139040. },
  139041. owner : globeDepth
  139042. });
  139043. }
  139044. globeDepth._copyDepthCommand.framebuffer = globeDepth._copyDepthFramebuffer;
  139045. if (!defined(globeDepth._copyColorCommand)) {
  139046. globeDepth._copyColorCommand = context.createViewportQuadCommand(PassThrough, {
  139047. uniformMap : {
  139048. u_texture : function() {
  139049. return globeDepth._colorTexture;
  139050. }
  139051. },
  139052. owner : globeDepth
  139053. });
  139054. }
  139055. globeDepth._copyDepthCommand.renderState = globeDepth._rs;
  139056. globeDepth._copyColorCommand.renderState = globeDepth._rs;
  139057. if (!defined(globeDepth._clearColorCommand)) {
  139058. globeDepth._clearColorCommand = new ClearCommand({
  139059. color : new Color(0.0, 0.0, 0.0, 0.0),
  139060. stencil : 0.0,
  139061. owner : globeDepth
  139062. });
  139063. }
  139064. globeDepth._clearColorCommand.framebuffer = globeDepth.framebuffer;
  139065. }
  139066. GlobeDepth.prototype.executeDebugGlobeDepth = function(context, passState) {
  139067. executeDebugGlobeDepth(this, context, passState);
  139068. };
  139069. GlobeDepth.prototype.update = function(context) {
  139070. var width = context.drawingBufferWidth;
  139071. var height = context.drawingBufferHeight;
  139072. updateFramebuffers(this, context, width, height);
  139073. updateCopyCommands(this, context, width, height);
  139074. context.uniformState.globeDepthTexture = undefined;
  139075. };
  139076. GlobeDepth.prototype.executeCopyDepth = function(context, passState) {
  139077. if (defined(this._copyDepthCommand)) {
  139078. this._copyDepthCommand.execute(context, passState);
  139079. context.uniformState.globeDepthTexture = this._globeDepthTexture;
  139080. }
  139081. };
  139082. GlobeDepth.prototype.executeCopyColor = function(context, passState) {
  139083. if (defined(this._copyColorCommand)) {
  139084. this._copyColorCommand.execute(context, passState);
  139085. }
  139086. };
  139087. GlobeDepth.prototype.clear = function(context, passState, clearColor) {
  139088. var clear = this._clearColorCommand;
  139089. if (defined(clear)) {
  139090. Color.clone(clearColor, clear.color);
  139091. clear.execute(context, passState);
  139092. }
  139093. };
  139094. GlobeDepth.prototype.isDestroyed = function() {
  139095. return false;
  139096. };
  139097. GlobeDepth.prototype.destroy = function() {
  139098. destroyTextures(this);
  139099. destroyFramebuffers(this);
  139100. if (defined(this._copyColorCommand)) {
  139101. this._copyColorCommand.shaderProgram = this._copyColorCommand.shaderProgram.destroy();
  139102. }
  139103. if (defined(this._copyDepthCommand)) {
  139104. this._copyDepthCommand.shaderProgram = this._copyDepthCommand.shaderProgram.destroy();
  139105. }
  139106. var command = this._debugGlobeDepthViewportCommand;
  139107. if (defined(command)) {
  139108. command.shaderProgram = command.shaderProgram.destroy();
  139109. }
  139110. return destroyObject(this);
  139111. };
  139112. return GlobeDepth;
  139113. });
  139114. /*global define*/
  139115. define('Scene/GoogleEarthImageryProvider',[
  139116. '../Core/Credit',
  139117. '../Core/defaultValue',
  139118. '../Core/defined',
  139119. '../Core/defineProperties',
  139120. '../Core/DeveloperError',
  139121. '../Core/Event',
  139122. '../Core/GeographicTilingScheme',
  139123. '../Core/loadText',
  139124. '../Core/Rectangle',
  139125. '../Core/RuntimeError',
  139126. '../Core/TileProviderError',
  139127. '../Core/WebMercatorTilingScheme',
  139128. '../ThirdParty/when',
  139129. './ImageryProvider'
  139130. ], function(
  139131. Credit,
  139132. defaultValue,
  139133. defined,
  139134. defineProperties,
  139135. DeveloperError,
  139136. Event,
  139137. GeographicTilingScheme,
  139138. loadText,
  139139. Rectangle,
  139140. RuntimeError,
  139141. TileProviderError,
  139142. WebMercatorTilingScheme,
  139143. when,
  139144. ImageryProvider) {
  139145. 'use strict';
  139146. /**
  139147. * Provides tiled imagery using the Google Earth Imagery API.
  139148. *
  139149. * Notes: This imagery provider does not work with the public Google Earth servers. It works with the
  139150. * Google Earth Enterprise Server.
  139151. *
  139152. * By default the Google Earth Enterprise server does not set the
  139153. * {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing} headers. You can either
  139154. * use a proxy server which adds these headers, or in the /opt/google/gehttpd/conf/gehttpd.conf
  139155. * and add the 'Header set Access-Control-Allow-Origin "*"' option to the '&lt;Directory /&gt;' and
  139156. * '&lt;Directory "/opt/google/gehttpd/htdocs"&gt;' directives.
  139157. *
  139158. * @alias GoogleEarthImageryProvider
  139159. * @constructor
  139160. *
  139161. * @param {Object} options Object with the following properties:
  139162. * @param {String} options.url The url of the Google Earth server hosting the imagery.
  139163. * @param {Number} options.channel The channel (id) to be used when requesting data from the server.
  139164. * The channel number can be found by looking at the json file located at:
  139165. * earth.localdomain/default_map/query?request=Json&vars=geeServerDefs The /default_map path may
  139166. * differ depending on your Google Earth Enterprise server configuration. Look for the "id" that
  139167. * is associated with a "ImageryMaps" requestType. There may be more than one id available.
  139168. * Example:
  139169. * {
  139170. * layers: [
  139171. * {
  139172. * id: 1002,
  139173. * requestType: "ImageryMaps"
  139174. * },
  139175. * {
  139176. * id: 1007,
  139177. * requestType: "VectorMapsRaster"
  139178. * }
  139179. * ]
  139180. * }
  139181. * @param {String} [options.path="/default_map"] The path of the Google Earth server hosting the imagery.
  139182. * @param {Number} [options.maximumLevel] The maximum level-of-detail supported by the Google Earth
  139183. * Enterprise server, or undefined if there is no limit.
  139184. * @param {TileDiscardPolicy} [options.tileDiscardPolicy] The policy that determines if a tile
  139185. * is invalid and should be discarded. To ensure that no tiles are discarded, construct and pass
  139186. * a {@link NeverTileDiscardPolicy} for this parameter.
  139187. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If not specified, the WGS84 ellipsoid is used.
  139188. * @param {Proxy} [options.proxy] A proxy to use for requests. This object is
  139189. * expected to have a getURL function which returns the proxied URL, if needed.
  139190. *
  139191. * @exception {RuntimeError} Could not find layer with channel (id) of <code>options.channel</code>.
  139192. * @exception {RuntimeError} Could not find a version in channel (id) <code>options.channel</code>.
  139193. * @exception {RuntimeError} Unsupported projection <code>data.projection</code>.
  139194. *
  139195. * @see ArcGisMapServerImageryProvider
  139196. * @see BingMapsImageryProvider
  139197. * @see createOpenStreetMapImageryProvider
  139198. * @see SingleTileImageryProvider
  139199. * @see createTileMapServiceImageryProvider
  139200. * @see WebMapServiceImageryProvider
  139201. * @see WebMapTileServiceImageryProvider
  139202. * @see UrlTemplateImageryProvider
  139203. *
  139204. *
  139205. * @example
  139206. * var google = new Cesium.GoogleEarthImageryProvider({
  139207. * url : 'https://earth.localdomain',
  139208. * channel : 1008
  139209. * });
  139210. *
  139211. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  139212. */
  139213. function GoogleEarthImageryProvider(options) {
  139214. options = defaultValue(options, {});
  139215. if (!defined(options.url)) {
  139216. throw new DeveloperError('options.url is required.');
  139217. }
  139218. if (!defined(options.channel)) {
  139219. throw new DeveloperError('options.channel is required.');
  139220. }
  139221. this._url = options.url;
  139222. this._path = defaultValue(options.path, '/default_map');
  139223. this._tileDiscardPolicy = options.tileDiscardPolicy;
  139224. this._proxy = options.proxy;
  139225. this._channel = options.channel;
  139226. this._requestType = 'ImageryMaps';
  139227. this._credit = new Credit('Google Imagery', GoogleEarthImageryProvider._logoData, 'http://www.google.com/enterprise/mapsearth/products/earthenterprise.html');
  139228. /**
  139229. * The default {@link ImageryLayer#gamma} to use for imagery layers created for this provider.
  139230. * By default, this is set to 1.9. Changing this value after creating an {@link ImageryLayer} for this provider will have
  139231. * no effect. Instead, set the layer's {@link ImageryLayer#gamma} property.
  139232. *
  139233. * @type {Number}
  139234. * @default 1.9
  139235. */
  139236. this.defaultGamma = 1.9;
  139237. this._tilingScheme = undefined;
  139238. this._version = undefined;
  139239. this._tileWidth = 256;
  139240. this._tileHeight = 256;
  139241. this._maximumLevel = options.maximumLevel;
  139242. this._imageUrlTemplate = this._url + this._path + '/query?request={request}&channel={channel}&version={version}&x={x}&y={y}&z={zoom}';
  139243. this._errorEvent = new Event();
  139244. this._ready = false;
  139245. this._readyPromise = when.defer();
  139246. var metadataUrl = this._url + this._path + '/query?request=Json&vars=geeServerDefs&is2d=t';
  139247. var that = this;
  139248. var metadataError;
  139249. function metadataSuccess(text) {
  139250. var data;
  139251. // The Google Earth server sends malformed JSON data currently...
  139252. try {
  139253. // First, try parsing it like normal in case a future version sends correctly formatted JSON
  139254. data = JSON.parse(text);
  139255. } catch(e) {
  139256. // Quote object strings manually, then try parsing again
  139257. data = JSON.parse(text.replace(/([\[\{,])[\n\r ]*([A-Za-z0-9]+)[\n\r ]*:/g, '$1"$2":'));
  139258. }
  139259. var layer;
  139260. for(var i = 0; i < data.layers.length; i++) {
  139261. if(data.layers[i].id === that._channel) {
  139262. layer = data.layers[i];
  139263. break;
  139264. }
  139265. }
  139266. var message;
  139267. if(!defined(layer)) {
  139268. message = 'Could not find layer with channel (id) of ' + that._channel + '.';
  139269. metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
  139270. throw new RuntimeError(message);
  139271. }
  139272. if(!defined(layer.version)) {
  139273. message = 'Could not find a version in channel (id) ' + that._channel + '.';
  139274. metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
  139275. throw new RuntimeError(message);
  139276. }
  139277. that._version = layer.version;
  139278. if(defined(data.projection) && data.projection === 'flat') {
  139279. that._tilingScheme = new GeographicTilingScheme({
  139280. numberOfLevelZeroTilesX : 2,
  139281. numberOfLevelZeroTilesY : 2,
  139282. rectangle: new Rectangle(-Math.PI, -Math.PI, Math.PI, Math.PI),
  139283. ellipsoid : options.ellipsoid
  139284. });
  139285. // Default to mercator projection when projection is undefined
  139286. } else if(!defined(data.projection) || data.projection === 'mercator') {
  139287. that._tilingScheme = new WebMercatorTilingScheme({
  139288. numberOfLevelZeroTilesX : 2,
  139289. numberOfLevelZeroTilesY : 2,
  139290. ellipsoid : options.ellipsoid
  139291. });
  139292. } else {
  139293. message = 'Unsupported projection ' + data.projection + '.';
  139294. metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
  139295. throw new RuntimeError(message);
  139296. }
  139297. that._imageUrlTemplate = that._imageUrlTemplate.replace('{request}', that._requestType)
  139298. .replace('{channel}', that._channel).replace('{version}', that._version);
  139299. that._ready = true;
  139300. that._readyPromise.resolve(true);
  139301. TileProviderError.handleSuccess(metadataError);
  139302. }
  139303. function metadataFailure(e) {
  139304. var message = 'An error occurred while accessing ' + metadataUrl + '.';
  139305. metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
  139306. that._readyPromise.reject(new RuntimeError(message));
  139307. }
  139308. function requestMetadata() {
  139309. var url = (!defined(that._proxy)) ? metadataUrl : that._proxy.getURL(metadataUrl);
  139310. var metadata = loadText(url);
  139311. when(metadata, metadataSuccess, metadataFailure);
  139312. }
  139313. requestMetadata();
  139314. }
  139315. defineProperties(GoogleEarthImageryProvider.prototype, {
  139316. /**
  139317. * Gets the URL of the Google Earth MapServer.
  139318. * @memberof GoogleEarthImageryProvider.prototype
  139319. * @type {String}
  139320. * @readonly
  139321. */
  139322. url : {
  139323. get : function() {
  139324. return this._url;
  139325. }
  139326. },
  139327. /**
  139328. * Gets the url path of the data on the Google Earth server.
  139329. * @memberof GoogleEarthImageryProvider.prototype
  139330. * @type {String}
  139331. * @readonly
  139332. */
  139333. path : {
  139334. get : function() {
  139335. return this._path;
  139336. }
  139337. },
  139338. /**
  139339. * Gets the proxy used by this provider.
  139340. * @memberof GoogleEarthImageryProvider.prototype
  139341. * @type {Proxy}
  139342. * @readonly
  139343. */
  139344. proxy : {
  139345. get : function() {
  139346. return this._proxy;
  139347. }
  139348. },
  139349. /**
  139350. * Gets the imagery channel (id) currently being used.
  139351. * @memberof GoogleEarthImageryProvider.prototype
  139352. * @type {Number}
  139353. * @readonly
  139354. */
  139355. channel : {
  139356. get : function() {
  139357. return this._channel;
  139358. }
  139359. },
  139360. /**
  139361. * Gets the width of each tile, in pixels. This function should
  139362. * not be called before {@link GoogleEarthImageryProvider#ready} returns true.
  139363. * @memberof GoogleEarthImageryProvider.prototype
  139364. * @type {Number}
  139365. * @readonly
  139366. */
  139367. tileWidth : {
  139368. get : function() {
  139369. if (!this._ready) {
  139370. throw new DeveloperError('tileWidth must not be called before the imagery provider is ready.');
  139371. }
  139372. return this._tileWidth;
  139373. }
  139374. },
  139375. /**
  139376. * Gets the height of each tile, in pixels. This function should
  139377. * not be called before {@link GoogleEarthImageryProvider#ready} returns true.
  139378. * @memberof GoogleEarthImageryProvider.prototype
  139379. * @type {Number}
  139380. * @readonly
  139381. */
  139382. tileHeight: {
  139383. get : function() {
  139384. if (!this._ready) {
  139385. throw new DeveloperError('tileHeight must not be called before the imagery provider is ready.');
  139386. }
  139387. return this._tileHeight;
  139388. }
  139389. },
  139390. /**
  139391. * Gets the maximum level-of-detail that can be requested. This function should
  139392. * not be called before {@link GoogleEarthImageryProvider#ready} returns true.
  139393. * @memberof GoogleEarthImageryProvider.prototype
  139394. * @type {Number}
  139395. * @readonly
  139396. */
  139397. maximumLevel : {
  139398. get : function() {
  139399. if (!this._ready) {
  139400. throw new DeveloperError('maximumLevel must not be called before the imagery provider is ready.');
  139401. }
  139402. return this._maximumLevel;
  139403. }
  139404. },
  139405. /**
  139406. * Gets the minimum level-of-detail that can be requested. This function should
  139407. * not be called before {@link GoogleEarthImageryProvider#ready} returns true.
  139408. * @memberof GoogleEarthImageryProvider.prototype
  139409. * @type {Number}
  139410. * @readonly
  139411. */
  139412. minimumLevel : {
  139413. get : function() {
  139414. if (!this._ready) {
  139415. throw new DeveloperError('minimumLevel must not be called before the imagery provider is ready.');
  139416. }
  139417. return 0;
  139418. }
  139419. },
  139420. /**
  139421. * Gets the tiling scheme used by this provider. This function should
  139422. * not be called before {@link GoogleEarthImageryProvider#ready} returns true.
  139423. * @memberof GoogleEarthImageryProvider.prototype
  139424. * @type {TilingScheme}
  139425. * @readonly
  139426. */
  139427. tilingScheme : {
  139428. get : function() {
  139429. if (!this._ready) {
  139430. throw new DeveloperError('tilingScheme must not be called before the imagery provider is ready.');
  139431. }
  139432. return this._tilingScheme;
  139433. }
  139434. },
  139435. /**
  139436. * Gets the version of the data used by this provider. This function should
  139437. * not be called before {@link GoogleEarthImageryProvider#ready} returns true.
  139438. * @memberof GoogleEarthImageryProvider.prototype
  139439. * @type {Number}
  139440. * @readonly
  139441. */
  139442. version : {
  139443. get : function() {
  139444. if (!this._ready) {
  139445. throw new DeveloperError('version must not be called before the imagery provider is ready.');
  139446. }
  139447. return this._version;
  139448. }
  139449. },
  139450. /**
  139451. * Gets the type of data that is being requested from the provider. This function should
  139452. * not be called before {@link GoogleEarthImageryProvider#ready} returns true.
  139453. * @memberof GoogleEarthImageryProvider.prototype
  139454. * @type {String}
  139455. * @readonly
  139456. */
  139457. requestType : {
  139458. get : function() {
  139459. if (!this._ready) {
  139460. throw new DeveloperError('requestType must not be called before the imagery provider is ready.');
  139461. }
  139462. return this._requestType;
  139463. }
  139464. },
  139465. /**
  139466. * Gets the rectangle, in radians, of the imagery provided by this instance. This function should
  139467. * not be called before {@link GoogleEarthImageryProvider#ready} returns true.
  139468. * @memberof GoogleEarthImageryProvider.prototype
  139469. * @type {Rectangle}
  139470. * @readonly
  139471. */
  139472. rectangle : {
  139473. get : function() {
  139474. if (!this._ready) {
  139475. throw new DeveloperError('rectangle must not be called before the imagery provider is ready.');
  139476. }
  139477. return this._tilingScheme.rectangle;
  139478. }
  139479. },
  139480. /**
  139481. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  139482. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  139483. * returns undefined, no tiles are filtered. This function should
  139484. * not be called before {@link GoogleEarthImageryProvider#ready} returns true.
  139485. * @memberof GoogleEarthImageryProvider.prototype
  139486. * @type {TileDiscardPolicy}
  139487. * @readonly
  139488. */
  139489. tileDiscardPolicy : {
  139490. get : function() {
  139491. if (!this._ready) {
  139492. throw new DeveloperError('tileDiscardPolicy must not be called before the imagery provider is ready.');
  139493. }
  139494. return this._tileDiscardPolicy;
  139495. }
  139496. },
  139497. /**
  139498. * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
  139499. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  139500. * are passed an instance of {@link TileProviderError}.
  139501. * @memberof GoogleEarthImageryProvider.prototype
  139502. * @type {Event}
  139503. * @readonly
  139504. */
  139505. errorEvent : {
  139506. get : function() {
  139507. return this._errorEvent;
  139508. }
  139509. },
  139510. /**
  139511. * Gets a value indicating whether or not the provider is ready for use.
  139512. * @memberof GoogleEarthImageryProvider.prototype
  139513. * @type {Boolean}
  139514. * @readonly
  139515. */
  139516. ready : {
  139517. get : function() {
  139518. return this._ready;
  139519. }
  139520. },
  139521. /**
  139522. * Gets a promise that resolves to true when the provider is ready for use.
  139523. * @memberof GoogleEarthImageryProvider.prototype
  139524. * @type {Promise.<Boolean>}
  139525. * @readonly
  139526. */
  139527. readyPromise : {
  139528. get : function() {
  139529. return this._readyPromise.promise;
  139530. }
  139531. },
  139532. /**
  139533. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  139534. * the source of the imagery. This function should not be called before {@link GoogleEarthImageryProvider#ready} returns true.
  139535. * @memberof GoogleEarthImageryProvider.prototype
  139536. * @type {Credit}
  139537. * @readonly
  139538. */
  139539. credit : {
  139540. get : function() {
  139541. return this._credit;
  139542. }
  139543. },
  139544. /**
  139545. * Gets a value indicating whether or not the images provided by this imagery provider
  139546. * include an alpha channel. If this property is false, an alpha channel, if present, will
  139547. * be ignored. If this property is true, any images without an alpha channel will be treated
  139548. * as if their alpha is 1.0 everywhere. When this property is false, memory usage
  139549. * and texture upload time are reduced.
  139550. * @memberof GoogleEarthImageryProvider.prototype
  139551. * @type {Boolean}
  139552. * @readonly
  139553. */
  139554. hasAlphaChannel : {
  139555. get : function() {
  139556. return true;
  139557. }
  139558. }
  139559. });
  139560. /**
  139561. * Gets the credits to be displayed when a given tile is displayed.
  139562. *
  139563. * @param {Number} x The tile X coordinate.
  139564. * @param {Number} y The tile Y coordinate.
  139565. * @param {Number} level The tile level;
  139566. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  139567. *
  139568. * @exception {DeveloperError} <code>getTileCredits</code> must not be called before the imagery provider is ready.
  139569. */
  139570. GoogleEarthImageryProvider.prototype.getTileCredits = function(x, y, level) {
  139571. return undefined;
  139572. };
  139573. /**
  139574. * Requests the image for a given tile. This function should
  139575. * not be called before {@link GoogleEarthImageryProvider#ready} returns true.
  139576. *
  139577. * @param {Number} x The tile X coordinate.
  139578. * @param {Number} y The tile Y coordinate.
  139579. * @param {Number} level The tile level.
  139580. * @returns {Promise.<Image|Canvas>|undefined} A promise for the image that will resolve when the image is available, or
  139581. * undefined if there are too many active requests to the server, and the request
  139582. * should be retried later. The resolved image may be either an
  139583. * Image or a Canvas DOM object.
  139584. *
  139585. * @exception {DeveloperError} <code>requestImage</code> must not be called before the imagery provider is ready.
  139586. */
  139587. GoogleEarthImageryProvider.prototype.requestImage = function(x, y, level) {
  139588. if (!this._ready) {
  139589. throw new DeveloperError('requestImage must not be called before the imagery provider is ready.');
  139590. }
  139591. var url = buildImageUrl(this, x, y, level);
  139592. return ImageryProvider.loadImage(this, url);
  139593. };
  139594. /**
  139595. * Picking features is not currently supported by this imagery provider, so this function simply returns
  139596. * undefined.
  139597. *
  139598. * @param {Number} x The tile X coordinate.
  139599. * @param {Number} y The tile Y coordinate.
  139600. * @param {Number} level The tile level.
  139601. * @param {Number} longitude The longitude at which to pick features.
  139602. * @param {Number} latitude The latitude at which to pick features.
  139603. * @return {Promise.<ImageryLayerFeatureInfo[]>|undefined} A promise for the picked features that will resolve when the asynchronous
  139604. * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
  139605. * instances. The array may be empty if no features are found at the given location.
  139606. * It may also be undefined if picking is not supported.
  139607. */
  139608. GoogleEarthImageryProvider.prototype.pickFeatures = function() {
  139609. return undefined;
  139610. };
  139611. GoogleEarthImageryProvider._logoData = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAAnCAYAAACmP2LfAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAAAHdElNRQfcDB4TJDr1mp5kAAAAGnRFWHRTb2Z0d2FyZQBQYWludC5ORVQgdjMuNS4xMDD0cqEAAB1zSURBVHhe7ZwHeFTFFsf/u+l9N70npOxuSAKEFFIhCSH0qhEQUHkgKCgWUFGBB6IoCAoo0ntooaRvEkIIBBBpoYSa3nvvfd+5u4sQUigPfMX8v2/Y3Tkzs3fv/d0z58zcgF69Ql1SY+MM1wQJem44ZeiJk8beEOqPwG6uC7ZqyElb9eo/JZEIkH2nRQkBIlNMauuPCS3uGN/kjkmNDghoskBAgzrZ2NLmf1+JwIKQpYsoxdmIV9+N07onCegzBPM9bOdmYKnazF6g/1N6UySPqSJzvCaaiLHtP8G/Phq+FRfgU5ogKWUXMLT6Mvzqr2BE40mMadqO8c3zMabBC6PqDDC8SlY60t9HByCLVTKu+ERmHr5TWI9wjVxEaOZivWo1pil8D1tZeWnLXv1l8iZ3PF2kjymiWRgvCoJv5U243IyAXcQq8A9Mg9W+4bDe6wv+kVGwCZkL+4Sf4ZR+BZ5VGQR3EkbWn8Hopm3wq54Lz2JD6ah/P21XGopQ9Qoc16jGSqVyTJWbQbUsibFXf42mihTwZpsvAtp3k0dOhFOSEH1+ngaDefrgjFCgFkxY8fCisCBvKgODzxRh9qslBFGfYmDGLbiV5mBwRRo8KtPhVBgPu8teMP7u73chD6kMRYRGBY5xqrFKqQwz5SdTbS/Qf5mmUYw8rf01CjHC4VP7AHZxO6E3qy9ZZCQNnio2rE/4o9/tkxiQUYp+KRXgx8XC5FsXcLz/hkCrDUU4pxLHuDVYpdwL9F+qqSJZKlPwenskfOoI5tN7YPCJGVme7wKYr5EBXzgYfW+mwTI0Gjrznaj2WW+I/y8dVPdDGLcKRzXrsEqlHO8oTKHaXqAZWe9hQXCi63NhHWYI3ilfWIW/YLjqL2JRiOFBJRz+LffhcPs09D+0J8vzn3zXdBnYnp8Mi6NboTWzH9X8fVc+DhDQodxqAroe36lU9AJNWr4cEAjNwI8OAC9cT1rbUfzwGeCfKiL7dGnNc+q1NiO80b4BY1oT4V6WDcsdc6j2xbyq4wMWrA9rQmeWFn36ey/jBaoPQ4hmLYI0G/AtAf22fC/QDols8ITrIYi/Bl6knbS2o3gRbxHQxQQ0k0S/gCa2v4OJovPwacqAQ1ICjL40klr+UrWoQbFBETo18jCpZsOoFODkvuCNJYoHW3QKXFEM7ETRcKfiQe8d6NVIFImXvg4skhY40mxnQYVRIIeA1qrHEc1GrFSpxFtP99AiFbDbNKDZpAzzGkVYVcvBuBJQEo/9/6C+dyjPitwLwak74D8V6Bfw0P5VShjXFoTR7TfhUZkL29M/wfATJan1lauWC3aDOgyaVDCuTgbf1bFkfmtkye1ogsK2asivLYfCglIoD8qCknI2NHuG4QSVGMgQyMbt0fioRYh9VYcRU7QX55uDcaHtFOJEsThMtmWtQgxsDodsWaC0c3ea3MzGBJEqxrfbYmzr6xjfPAeTmt5HQPO7eK1xDibUz8eY+k8xtHYJPCtXwvHOu7AXMrMTsF/TH8HajTis1YwVqpWY0TXQDKy1OpBr5EJA52Fukxx+bmKxtjWx2DuaWawNlZD5qhzyo9KhpHAbKpJO/6t65UCPbPHA2PYrGNacgkElabCJJDev/MpDhUKKnuq44LRoYEK1IiswkS1zYCfk5y+F0qjvoTwqBOof34dGeAnUL1ZCLboEnJ9zoe0QD/Nuj00UBVXRabzVLETM3S0ICfwA8yc7Y6C3ANYbZsA7aQ1W1xzEfZEQ6dT2BkG9pP4ouo7jGE1u42JS20QMrzkCr4xwuN4+AM+cYII3EaNar2J86zmMrP8DHulCON4NhU3YWuhOYy6SZENpH9cfx7WacFC7BSvUqjBDsRPQIiugURvazeqYVaqAw6dYrJ9WQy7gayj4nYDy3HtQOVQGpYRqKEWXQf2HdGha/AFdae9Xr4czz0ubISRA75ECbSut7agegO75OLxpahze8j5GtifBpzEDLiV30Dd2mNT6StWiCbVmLt5rUkBQCEt2zWzIMSA8HgrIBkLD+Sp0jhHISYXQ/KMYukfvQ3fQxq68XCTBHId/tMTg7LV1CFs4BszJ6hBarBgHlcRv8H7tbuSKQpFPYGe0BmND+nZ0npECaPKf0r4UIxsuoF/IMpitsAVnrA4s15uh3x8fwLXkLobUZGJIXTqcUzbDaJE5FAVq0t4S7dEcjqMEc6B2K5arVWN6Z6AbdOmm5mJelQKOHWSxF44Cy4CqxW0s6RwchCovFRohdGNfLgX3WiZ0N4aD++y7jfwYJUrAPCle/ZjKV+BFTSegrGAZIm3QjXhBytTWB3zhByzryMUU986jz16wD+96ijCNUIAgmkc3tS6G7GERjCbgR82B4OTbEESqIiCIcqsIYzoGGyrBEMSmgh8xBoIIAR2fAHZhj8Z9DOhl9FHeKkSDvn809fuc+iyCddRYaiOZBTvIt1YJfs0b4N+WDO+GHPLQN2Ab7S61vjJV60C9SRPvNSqzTpxlyQfS1dGUmjppK7gW16B/LhN6abnQu5cDwzO3YNhhqqK4WJY887sEdGzWFpxfOxmDpKZOOvgWFB8sx9L6nShvP4FyUQjKGg5gScpGKEqbUE7RxiGYv6QQ4zIG/r4D2m88sjEy/EIW/a6+TQ4gHe5VhXCvy4JL7gLYnesI2i6t4Tii04r92u1YKt767gB0ozrkGzmY26zEOh7Hkt+kAKhLTX9qOVVdg9aoNOjcToR+wUVKLYKgN0Zq7l7884wn9CKgr4AfWw/B6SwqKQRKOdXVghe9CpbherASSjtIpGpxRIHFjwygNreoXy0lb+lU7lHJBP9kPcGXQnBNghUB/Lh44fbUp5JA+5Hs71LbPPLCVRDEJZDNGIJgeQI6mG6KegKzldq1U7tGKjQmHR8vwl86kgRoAQN0xBw6ztn0nQ/ocxEdQ7L4d/BjG6g+m8aZTL/xsXPuW82Fb8t+DG1Ox5D6XAwqvQ67OA+p9ZWoUQPsei78mjSwNU9GLmEzVGZJTd3qFPTn3YZhXgYMMjNhlHsDxms/hNWfoUdrNPgEc2h7BG5d/Bo7Blt0BuNxXf4MVmXrkdRyEHWiY6hr2oc7mevRX2wc18gioEeI1+N9a+/CNnImVAZ0mhEoNOPAJT8MHjUF8KTiWhqHgbfMpVaJdhLQh3XasU9bJAZ6ekeg6zQwgEKuLSWysmd3QGmatLqD8qDNug3dCX/AIPk4jGr2wDB/JXTmkan70IvmZTY/rB9BdZlKLkG0lG0d5klAObKsw1+jzyFiWPnRawiaDrMYwTyMwMwh220WP2IWFVfqN4CKO8E3n0C6R/ZUej9Y2kUiMdDRFTRePH3nA3q/m7xpAEtAXl0QrkTwscnmS/3eptdzNEYevZLnZ5booqk8tuYs9tAny+n1LL1mghezlcULH0VtHamOZhvhIvoNOXQsd2EZIbluYnlWaMO75TCFG9kYXJ8H14o76H/10Z3yClSrCm6jGtbWK7LC7kIlYRfUmY2XHnUa+mbXYRSfCuNCptyE6b1jMBD/EPKwchQPLxGdxOWWI8iKXYBPqLozgI8pfA5YBWvxbfMeNLUfRmPTLjRnr8YKsdGvRQ5j2zZTSSRQ78H+7GhxfScFAINypsG9ukDspZ0LKKE+O0pqlGi71ggcIqD3dga6RhFKjSqYT+VEFkvu/E9Q+HNWKaE2VVDgVkPFqwAaay5CN3En9M59BM2vfKDs7AvljjPGE5LlharQdL+LoCmhOHU0rIUyD+NgVTOa+q2iVQiIcAKpHtbhXuJOjPqeVCRYThNE6VTvKNs3hM3cHGIxntxKyCbP7Erj1lHZJbVIJAG6iiCroZCAPGukvOyASJbvCgoaAoKoAQ1kHcGC7nmZDkmhBR2PfSQLtkcl4zCSAE2eO6qExYuYxrE4KqdvelBiM4+ncYQy1IY8d0wbhUSLJAZGbsUceNYdwJCGPAyuy4NbZToG3JoO1Qk9AvHvqF4ejo0KCKlisyl04Jw+AE1ma71HRUJP+QqM1t2HcVEyTEoSYVYQCuN3HenCt4XDhGA+KorAnYZ9KIj5ELOl3XpU/k/wrt+OmraDaG7cjpacbxFvYAAZDG5Vw/DWCxjRdp+ATsWAS6+D69H1+XDNsoVb1T06b0VwzCmBIOYdqUWibTojcFBH1CXQctBtUcA6Oh/RmVC4sBmKA5j6erC1qqE4sRpqG25A43QIOHuXgvOmP5R4ZH6m5UY2L9SSLjZ5sKjjsI/o8olH8ngjCZoSgmw9DMIl3t42Up0g+pq89/sEjLK47knZhSkSuDepJP4JOyNJyEFAR8VQKMOR1nbWM69yxNJYwh+VLE90ffPyxLE3EwL9Jq0huWQqwL1iA7zq8+FVl0+epgBO6T+gb2TH+OglqgastxtZrNNlkLt8E5oJx6HZdab7mFZBk3UZRjMewCT7HkzLfodZxREYr5sBjiIBPYiAPt8ehvSGPSg5vwjzpd16VNkmmDTswp22QDTXbkJrxhJkzHGDFoUQmvBpvo2hrZl0TnLhlLIYfUO7nt7dSg3hURcP1/JiDEgphuXBqVKLRFsfA3oJAf3mI6Cr2OjTwGYdqWGzzmZD6WoYVCfehdqsZKjuuwS1oB1Q+5piHac3oaxBzZ9vLZ4nHEeesoXg6niDPSYWP9yUgD5PHu48eKE64krHcErchHIEuRysTpAXjObQWIYEHiV4EQYEojp5aEoyY+IIpOQugKYYOnIdJXrdJ63PtWwXMQM6m6SVT4gfZkbHV0XHsVtaQ3K8yoJr0YfwoHDDq5ZiQSqDik/B4Q9taYtn18gyNia1qGJsmTrGlUjK2FJ1jCjRwOASDnkxDvN95ZD/og5yl0qgfCMJ2leDoeksHaFHXYOJVyrMkm/DrPwMzGr2wmjnLGipthyHL0W7t9pDkduwF2U3lmGFtvbTdyirt0OreT+iWwPRUrUBbSkLkT/fCUZwKVYikBMwpDlPXNzLwuAQ2rWX8KzUh2dDDJyLSmB7/S5Mf3WRWiR6CPSezkCXQs6qBnLCKsheyoXqnTCoL9oOFd9/Qtl9KJT6UJMX3/zhCz8iuCjhiviSYtMx3ZTJBN8lCE7eIRgF0p6krRRaRBDskTTGySBKws5SuUjJHYUiMQdpzCUE0Q3y5MnSDhJJQg5JUvjSgO5hHZofaioGmvc40IycMgbRtJktjgOZ5Ma9irzSg46xYHcaVEZevkgBHqUWGFK+FENKQ+BdGAq/wiMYWbwHI6h4FwTDOes0BMKFMHxPNg9qn1dANakYanfuQSs5FJoTpaP1qBswsSGgb9+EeUU0Af0LDH4dBhXlmv3wajuOpPYQFDcEojxtNQ6sn9ZzUsiofjfUWg/iYOt+tJatRtvN95DqZgxNuKTKwLV4Jdyqc8Wz1uCGTLjmDIVDQqewQ8anwpJi6GsYkF4Ey2O/QvsfXKlJIgboAwT07s5AZ0G1TylUIsuhdKMI6vcuQ3PVAqg+9UZ8JvGEywiuNoIwD4IzaV2X+HSa1otgE3+NwJImVkycG0kx8snfyUZJW+QFApeSu+hN9BpIn6n+ZBp9bqDv+C8Fum+8IpzzJNOmR3UhTaGFcC07iAHXmamuZw28C/S/aIt+CcthF7+ToN0EQdhqOFzcBu/Sm/ApvAGX3DzYXIiF9jtWTJf74L6ZC83UfGg8SId2xnloSZKxp+gWjC0J6KSrMK8KhmnlSugtInpkCzaBV78Hl5oPoaLpECrLt+Bi4jfgS7t1q+YDUGsPwj5KDFsLlqD97JuIpmpZmP+TftM1ezjlxsOllM4H3eReDWHwKrOBW84jqMeK5OBTv4Bu6HxxgqU1s/N3MkAHSoH+ioCe+gjoJHB0s8ENLID6/UJo3E+GVlwoNEwY278tXhR50RhmeexzgmM8JXjdF36MHwEoiXn70Csv6gxBm8PiRc6gJFD1HDzFpq1cP0omo5QJZAfqQzH0f6uHZjQgeR4cC/IJZCnUtSkYVPAWBiX2/CdU/S7Ql+9TgtFCTaiP0qAEXA2yRsqwuzECziWZcM4tgv2DSljF7ID+l+JNh9+hY38HuvcYmLOhk5EEnVPfQOmpW+33YGaXhj53E2BWuxvGebOh5cPUX/sWSgXrsa9mB2qaDqCK4C7I2IA3jn8u7tat2g6D034MIbWb0fZgHlr2DscXUhNNuYdkYRPrg/7JiXDMLYBrZS6GNEZgVJM/JjWY4I16G4xr/BCDq2nKjjoAvY+Zpwo7eXBskQK9Swr0lEdAn4a2wk3o/DMNWmn54KYUQIuZsebGQuXFQ42H4kfNk4QckSOkNZ1lGkGAUoInOKkAm2jJsVtH+om9Nj9ytZxNcNdhljXByo+JJXj/i4G2u2xM02YInPJLxFB7VudTPH0ZHkWu0hbPpwHpfnAszoFDVgVsb1fDMmoL9L8S7wTFQE/1AvR33oB+QSp0czKgl34B2iO9uwJCKib5SGaZjbqLPlkhMG1YDr1gQyioSs24vQTDitagsnIL6loCUVu9C2EJK9FjYtsWBNP2Q7hb9A155zdwY5mTeGexo0w32hEcy2F7JQaOqZfgk38KY6rDMKFBiGHNt+iGPgCNYd0/s/sbAb2fgN5JQC9Wq8bkR0AzioOOx3Xo30mGbnY+tNMKoJOQCm03qfnFxRf6E1yUFAqZJcyuZRWuQmB+TWHJcgJfkjPxImcSSIUsXviMx/O9DvqfALrPDjb6nhuBAWkZ5JFKKTYuIqhz4FUdAo9CGwzO7Ra2LjUg0w9OxdlwyKxAXzHQm8lDi4HeAT1WMPSHnYXR7aswKE6Gfl4K9PdfgZ6+uG8XSmMbKyXD/LsEmFduglH2NHA7rA3Hvg+Ve1/gYO4KNFRvQUPLQVRU7MG4yn1dJ4eiULAo3JhW9xsa77+Hml8GY8FQ425uAM5wRRivNoPlTjs4XhoH35oLGFZ/S/wglyDkbWmrrsUAvY+A3kHlSwJ6ihKzCvLnuQyElmIs9LdfhmHxA+jn5kI3jcrRFOjxU6DTbTx9DybsOBh0f034EeYEVyaFD0IYhnQ9y1pTIsiPvU5AnKYkUBL78yKmQhDLgDRPSWtPp/HFkFtHqFCfRBr73wX67qsD+qFsEubCnqKBAZllcCkkT12RjSHVMfApH0bJXfcH+aQGZg6FU1EWeeoK2NwgoMM3Q++zP/fq/Smf2g392ZEwzk2Acfl9GBHURmuSYPyn132oHBizH8B8wjX0SadQI2cWtOZZQbHTdEgRn8XN93EiczFayn5GU3Mg7lJMPab5SEeoCWZZ0TF4Ne/A/ZSPUbXdDz9Qdddrrk/KtcwR7jX34VXDzGCFGFT0GzyLu922x069kdiv145tOu34jlOHBWoz4arUAZQt0LYOhmFcHJ2H6zAsYnZDc2FwKhv60+m9UQrLUJ4hSYQAVhpM1O6jj30EDD33Q6frZyoY8cMVaWZZR560kuB5V9H6iVUas+Py5L1/IHsT2ZldR4nEkMdkUd8Y8tYd43mLIMhYhenDWvgjQSQiGFOkiEv0rEAzK2u8yG10M2WwBWFdb6q9NKDNd6rCOuYD9L2VI/57QMfcEniU5cCnJgG+lR9haAnz4MzT5ZjmA4e8HBqnGtYXamF+nK7bpx0uwHxoqGyE3sKD5HHjYVJ1C6Z5qTD5Ph2G1hnQEV/0LBhxU2E+4yYsbgTCJGsuNBfYQrnjA0CPxDo2CRYJ0xGesgD1ZWvQ3LQbKeSJ54uC0UcUDVVRGExFR/FB2y7cSf4C+Zv9sXSUeQ9P2z2pQdnmBHQsPKqKqFCyWJsM75o1GMw8O/iEhFZs/KK9CD9wRfhCTYTP1dqwnBOHrQYz8IuuH5ZxxI/MLQZH5kfoeu6D4cVQGNecgXHFbRgXZsD4Xg5MjqfDeE0KTBbRDLXsLiwOR8HkxCJoOs+Eavdr08ZBBGdYP7rYzAZILsH3LYUYtgSsAXlYRwLqW0r8Ksl2id4/Onaz47IE+kayUfwddYhsgwkqXRrLgOpHEuyhVF9B7ytoTAL//qNjeFagGfGEi5nvYPEifqOx/ek4p1J/8aKBWC8N6Icy2+oL6zOhECTmw46SuoHZpXBn/pK7/DK8K1bCp3Q0vAv7wqfIBD55OuS9teFVYASPfAFccseThw+E4Ho5LOMqYB6ZCeOdK6H1bleJH2sOOPZradqlC3otDqY5F2GafQmmCZdgFnMBZteEML2yCnprh0CZWVp66gbDuD5Q2uSLUacm43jSB0gq+h55JeuRX7wRqUUbkJL8DS4GTcPqCdZgduZ6XiZjgvcp9fIY3aAH/yY+3KvcMDBjLSXQBXDML4VbaQG8a9PgUxcOzyIneKY/Or6FHDO8q7INY+RiMFJaJijE4i2VeEylej/FDs99TAPH8Dvofv8bDK/vhVHxMRhX0W+vOgXTijiY5UXANGkNnYeRUGN2VrsPNx6XVaQNgRNM03sBgUjeOKJJ/Cr+LNzFsg61YB5/elyKtic0qM031CaZAG0gqJnVEuYBIoI49gy9D6DXrQR3GoU2j3YE+WE2FI9TGBG1FLywnhNbPt1Y/OhY+o5iGqsGNmdLaVxfqZUB+g0Iztwi2AOkNZ3FCzOm30bHeHK9tKYHKfPZMFhlAtM9c2EpjALv93zY3qlE/8xyOOUVUTiSBrfy83CvDIdbRZC4uJSGwzHzd0qgkmEVfRnGW/dC79vPobtkFLRmm0HDpVt43MnrzoOm/dfQeeOf0P3wB+guJogXrIDuhHfAsdOFbKdQ5GkaYQbNNYNht2c8/AOnYNKB6Ri//Q14zRwIuohdPC76pCbWKGFCkx9GNC7B0NZD8CiJh8Odi7A59zud7EuwvU4hVUYZBhUXwqsqA56V0RiUM1Dam36UoiyFuprQhc6fRZuKKhV5+rcLKD2hrPQ+NPsvgNb0j6C9eCG0v/kU2l9/BK0ZM8EdRJQ833noG8Qib6lDkA0lYD6i8GIJlffZ/IhhbJtQjW4TP164EiWWztTnH9T+a4L/MxpjAn02hWWYDAQnefSZzm7Io7zDOpiSzGh3grwPwd3zDccPZdH4phBEkXcWBrD4wlE07qObw5pmBUGsK43T/YPfgmAFWEe5U2EeCXhGcV5nQ3u2KrTf6w+jdTNhtud7mB/ZC4vg43QAwbAMDYLF0e3os+8HGP80D7oLx0F9dD+oj9AGZ4Y85K0Yj/Vs3kQiFgeybFPIySiDzdwAz9O3JzHjPNtYk8gjv948FOOatlGodR0Dk07Bau9n0F8wFBp+luBO1CXeuDD51Q3830PRP7UIzgUlcC0vhHPRSdic6eI53ecT3W0sKyjI2EFRxhzyz3sOO8voBkEUTclYhAyshCwr642PR79diwlbBOEs8vLMFjgbbuelhpeoz5rEDxsNNl/+9ON5RWJOLsXCysQdh5IhWWbzhUmoel6v/l/RxGpZTKgbh3EtEZQMp5AX2ASd2f3AVu7695ky/7nOuc2U/BZSCFIGp+I82F/rfprsVa/+Mk0sZ2F0tTvGNZ+gRO8B7C/HQ92beWine+/IDWDBbJUmbBN/hUNOGRyyStH34vfQeP3ZV4R61atXIu9Kefg1rIB/XRJciwso9nymLXmxbP+wxcCsVAxIKwfv1AZoDH96jN6rXr1SuVeowKsuFINrs+BSXATbc59JLU/XwCwdDMw7B/vUEpgHfQYZ7v9HCNar/2E55ynDpSwYrhXF4uKUeQiY0/Oy3kM555nCITcJgmvp0F30Yo8L9KpXL1X9E2XhkPoVBuYWwbmolKDOhmv+WHiXyGNkgbTRE1pOublXkRycCz+AfUoRzPdsgKJN1w/19KpXf7n6xlnCPikE/SkWdswrozDkNoZUfIWhFTYYWaPy4a6NkgSR2XAZXSOLIWUWcCv7FP1T7sH8wFZwp7ycxz971auXIm4AG+b77MFLEKLv7ULJMy0FefCsPAOv0t0YUrIMg0s+gVfxYrgVbIJLUSzsrl2F2ZZl4L7J/Pdp/956ca969UrEna0O41/HwSJ4F3in42Fz5Trsbt5Bv3u30e9uImyvnoV15GGY/LIA6kOZP1966pZ8r3r1n5eqhwZ0F/aB4ToHGK9zh/FPHjD60RE6H1tDaaA2cdy7mvFfI+BffksPNrEksu0AAAAASUVORK5CYII=';
  139612. function buildImageUrl(imageryProvider, x, y, level) {
  139613. var imageUrl = imageryProvider._imageUrlTemplate;
  139614. imageUrl = imageUrl.replace('{x}', x);
  139615. imageUrl = imageUrl.replace('{y}', y);
  139616. // Google Earth starts with a zoom level of 1, not 0
  139617. imageUrl = imageUrl.replace('{zoom}', (level + 1));
  139618. var proxy = imageryProvider._proxy;
  139619. if (defined(proxy)) {
  139620. imageUrl = proxy.getURL(imageUrl);
  139621. }
  139622. return imageUrl;
  139623. }
  139624. return GoogleEarthImageryProvider;
  139625. });
  139626. /*global define*/
  139627. define('Scene/GridImageryProvider',[
  139628. '../Core/Color',
  139629. '../Core/defaultValue',
  139630. '../Core/defined',
  139631. '../Core/defineProperties',
  139632. '../Core/Event',
  139633. '../Core/GeographicTilingScheme',
  139634. '../ThirdParty/when'
  139635. ], function(
  139636. Color,
  139637. defaultValue,
  139638. defined,
  139639. defineProperties,
  139640. Event,
  139641. GeographicTilingScheme,
  139642. when) {
  139643. 'use strict';
  139644. var defaultColor = new Color(1.0, 1.0, 1.0, 0.4);
  139645. var defaultGlowColor = new Color(0.0, 1.0, 0.0, 0.05);
  139646. var defaultBackgroundColor = new Color(0.0, 0.5, 0.0, 0.2);
  139647. /**
  139648. * An {@link ImageryProvider} that draws a wireframe grid on every tile with controllable background and glow.
  139649. * May be useful for custom rendering effects or debugging terrain.
  139650. *
  139651. * @alias GridImageryProvider
  139652. * @constructor
  139653. *
  139654. * @param {Object} [options] Object with the following properties:
  139655. * @param {TilingScheme} [options.tilingScheme=new GeographicTilingScheme()] The tiling scheme for which to draw tiles.
  139656. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If the tilingScheme is specified,
  139657. * this parameter is ignored and the tiling scheme's ellipsoid is used instead. If neither
  139658. * parameter is specified, the WGS84 ellipsoid is used.
  139659. * @param {Number} [options.cells=8] The number of grids cells.
  139660. * @param {Color} [options.color=Color(1.0, 1.0, 1.0, 0.4)] The color to draw grid lines.
  139661. * @param {Color} [options.glowColor=Color(0.0, 1.0, 0.0, 0.05)] The color to draw glow for grid lines.
  139662. * @param {Number} [options.glowWidth=6] The width of lines used for rendering the line glow effect.
  139663. * @param {Color} [backgroundColor=Color(0.0, 0.5, 0.0, 0.2)] Background fill color.
  139664. * @param {Number} [options.tileWidth=256] The width of the tile for level-of-detail selection purposes.
  139665. * @param {Number} [options.tileHeight=256] The height of the tile for level-of-detail selection purposes.
  139666. * @param {Number} [options.canvasSize=256] The size of the canvas used for rendering.
  139667. */
  139668. function GridImageryProvider(options) {
  139669. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  139670. this._tilingScheme = defined(options.tilingScheme) ? options.tilingScheme : new GeographicTilingScheme({ ellipsoid : options.ellipsoid });
  139671. this._cells = defaultValue(options.cells, 8);
  139672. this._color = defaultValue(options.color, defaultColor);
  139673. this._glowColor = defaultValue(options.glowColor, defaultGlowColor);
  139674. this._glowWidth = defaultValue(options.glowWidth, 6);
  139675. this._backgroundColor = defaultValue(options.backgroundColor, defaultBackgroundColor);
  139676. this._errorEvent = new Event();
  139677. this._tileWidth = defaultValue(options.tileWidth, 256);
  139678. this._tileHeight = defaultValue(options.tileHeight, 256);
  139679. // A little larger than tile size so lines are sharper
  139680. // Note: can't be too much difference otherwise texture blowout
  139681. this._canvasSize = defaultValue(options.canvasSize, 256);
  139682. // We only need a single canvas since all tiles will be the same
  139683. this._canvas = this._createGridCanvas();
  139684. this._readyPromise = when.resolve(true);
  139685. }
  139686. defineProperties(GridImageryProvider.prototype, {
  139687. /**
  139688. * Gets the proxy used by this provider.
  139689. * @memberof GridImageryProvider.prototype
  139690. * @type {Proxy}
  139691. * @readonly
  139692. */
  139693. proxy : {
  139694. get : function() {
  139695. return undefined;
  139696. }
  139697. },
  139698. /**
  139699. * Gets the width of each tile, in pixels. This function should
  139700. * not be called before {@link GridImageryProvider#ready} returns true.
  139701. * @memberof GridImageryProvider.prototype
  139702. * @type {Number}
  139703. * @readonly
  139704. */
  139705. tileWidth : {
  139706. get : function() {
  139707. return this._tileWidth;
  139708. }
  139709. },
  139710. /**
  139711. * Gets the height of each tile, in pixels. This function should
  139712. * not be called before {@link GridImageryProvider#ready} returns true.
  139713. * @memberof GridImageryProvider.prototype
  139714. * @type {Number}
  139715. * @readonly
  139716. */
  139717. tileHeight : {
  139718. get : function() {
  139719. return this._tileHeight;
  139720. }
  139721. },
  139722. /**
  139723. * Gets the maximum level-of-detail that can be requested. This function should
  139724. * not be called before {@link GridImageryProvider#ready} returns true.
  139725. * @memberof GridImageryProvider.prototype
  139726. * @type {Number}
  139727. * @readonly
  139728. */
  139729. maximumLevel : {
  139730. get : function() {
  139731. return undefined;
  139732. }
  139733. },
  139734. /**
  139735. * Gets the minimum level-of-detail that can be requested. This function should
  139736. * not be called before {@link GridImageryProvider#ready} returns true.
  139737. * @memberof GridImageryProvider.prototype
  139738. * @type {Number}
  139739. * @readonly
  139740. */
  139741. minimumLevel : {
  139742. get : function() {
  139743. return undefined;
  139744. }
  139745. },
  139746. /**
  139747. * Gets the tiling scheme used by this provider. This function should
  139748. * not be called before {@link GridImageryProvider#ready} returns true.
  139749. * @memberof GridImageryProvider.prototype
  139750. * @type {TilingScheme}
  139751. * @readonly
  139752. */
  139753. tilingScheme : {
  139754. get : function() {
  139755. return this._tilingScheme;
  139756. }
  139757. },
  139758. /**
  139759. * Gets the rectangle, in radians, of the imagery provided by this instance. This function should
  139760. * not be called before {@link GridImageryProvider#ready} returns true.
  139761. * @memberof GridImageryProvider.prototype
  139762. * @type {Rectangle}
  139763. * @readonly
  139764. */
  139765. rectangle : {
  139766. get : function() {
  139767. return this._tilingScheme.rectangle;
  139768. }
  139769. },
  139770. /**
  139771. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  139772. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  139773. * returns undefined, no tiles are filtered. This function should
  139774. * not be called before {@link GridImageryProvider#ready} returns true.
  139775. * @memberof GridImageryProvider.prototype
  139776. * @type {TileDiscardPolicy}
  139777. * @readonly
  139778. */
  139779. tileDiscardPolicy : {
  139780. get : function() {
  139781. return undefined;
  139782. }
  139783. },
  139784. /**
  139785. * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
  139786. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  139787. * are passed an instance of {@link TileProviderError}.
  139788. * @memberof GridImageryProvider.prototype
  139789. * @type {Event}
  139790. * @readonly
  139791. */
  139792. errorEvent : {
  139793. get : function() {
  139794. return this._errorEvent;
  139795. }
  139796. },
  139797. /**
  139798. * Gets a value indicating whether or not the provider is ready for use.
  139799. * @memberof GridImageryProvider.prototype
  139800. * @type {Boolean}
  139801. * @readonly
  139802. */
  139803. ready : {
  139804. get : function() {
  139805. return true;
  139806. }
  139807. },
  139808. /**
  139809. * Gets a promise that resolves to true when the provider is ready for use.
  139810. * @memberof GridImageryProvider.prototype
  139811. * @type {Promise.<Boolean>}
  139812. * @readonly
  139813. */
  139814. readyPromise : {
  139815. get : function() {
  139816. return this._readyPromise;
  139817. }
  139818. },
  139819. /**
  139820. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  139821. * the source of the imagery. This function should not be called before {@link GridImageryProvider#ready} returns true.
  139822. * @memberof GridImageryProvider.prototype
  139823. * @type {Credit}
  139824. * @readonly
  139825. */
  139826. credit : {
  139827. get : function() {
  139828. return undefined;
  139829. }
  139830. },
  139831. /**
  139832. * Gets a value indicating whether or not the images provided by this imagery provider
  139833. * include an alpha channel. If this property is false, an alpha channel, if present, will
  139834. * be ignored. If this property is true, any images without an alpha channel will be treated
  139835. * as if their alpha is 1.0 everywhere. When this property is false, memory usage
  139836. * and texture upload time are reduced.
  139837. * @memberof GridImageryProvider.prototype
  139838. * @type {Boolean}
  139839. * @readonly
  139840. */
  139841. hasAlphaChannel : {
  139842. get : function() {
  139843. return true;
  139844. }
  139845. }
  139846. });
  139847. /**
  139848. * Draws a grid of lines into a canvas.
  139849. */
  139850. GridImageryProvider.prototype._drawGrid = function(context) {
  139851. var minPixel = 0;
  139852. var maxPixel = this._canvasSize;
  139853. for (var x = 0; x <= this._cells; ++x) {
  139854. var nx = x / this._cells;
  139855. var val = 1 + nx * (maxPixel - 1);
  139856. context.moveTo(val, minPixel);
  139857. context.lineTo(val, maxPixel);
  139858. context.moveTo(minPixel, val);
  139859. context.lineTo(maxPixel, val);
  139860. }
  139861. context.stroke();
  139862. };
  139863. /**
  139864. * Render a grid into a canvas with background and glow
  139865. */
  139866. GridImageryProvider.prototype._createGridCanvas = function() {
  139867. var canvas = document.createElement('canvas');
  139868. canvas.width = this._canvasSize;
  139869. canvas.height = this._canvasSize;
  139870. var minPixel = 0;
  139871. var maxPixel = this._canvasSize;
  139872. var context = canvas.getContext('2d');
  139873. // Fill the background
  139874. var cssBackgroundColor = this._backgroundColor.toCssColorString();
  139875. context.fillStyle = cssBackgroundColor;
  139876. context.fillRect(minPixel, minPixel, maxPixel, maxPixel);
  139877. // Glow for grid lines
  139878. var cssGlowColor = this._glowColor.toCssColorString();
  139879. context.strokeStyle = cssGlowColor;
  139880. // Wide
  139881. context.lineWidth = this._glowWidth;
  139882. context.strokeRect(minPixel, minPixel, maxPixel, maxPixel);
  139883. this._drawGrid(context);
  139884. // Narrow
  139885. context.lineWidth = this._glowWidth * 0.5;
  139886. context.strokeRect(minPixel, minPixel, maxPixel, maxPixel);
  139887. this._drawGrid(context);
  139888. // Grid lines
  139889. var cssColor = this._color.toCssColorString();
  139890. // Border
  139891. context.strokeStyle = cssColor;
  139892. context.lineWidth = 2;
  139893. context.strokeRect(minPixel, minPixel, maxPixel, maxPixel);
  139894. // Inner
  139895. context.lineWidth = 1;
  139896. this._drawGrid(context);
  139897. return canvas;
  139898. };
  139899. /**
  139900. * Gets the credits to be displayed when a given tile is displayed.
  139901. *
  139902. * @param {Number} x The tile X coordinate.
  139903. * @param {Number} y The tile Y coordinate.
  139904. * @param {Number} level The tile level;
  139905. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  139906. *
  139907. * @exception {DeveloperError} <code>getTileCredits</code> must not be called before the imagery provider is ready.
  139908. */
  139909. GridImageryProvider.prototype.getTileCredits = function(x, y, level) {
  139910. return undefined;
  139911. };
  139912. /**
  139913. * Requests the image for a given tile. This function should
  139914. * not be called before {@link GridImageryProvider#ready} returns true.
  139915. *
  139916. * @param {Number} x The tile X coordinate.
  139917. * @param {Number} y The tile Y coordinate.
  139918. * @param {Number} level The tile level.
  139919. * @returns {Promise.<Image|Canvas>|undefined} A promise for the image that will resolve when the image is available, or
  139920. * undefined if there are too many active requests to the server, and the request
  139921. * should be retried later. The resolved image may be either an
  139922. * Image or a Canvas DOM object.
  139923. */
  139924. GridImageryProvider.prototype.requestImage = function(x, y, level) {
  139925. return this._canvas;
  139926. };
  139927. /**
  139928. * Picking features is not currently supported by this imagery provider, so this function simply returns
  139929. * undefined.
  139930. *
  139931. * @param {Number} x The tile X coordinate.
  139932. * @param {Number} y The tile Y coordinate.
  139933. * @param {Number} level The tile level.
  139934. * @param {Number} longitude The longitude at which to pick features.
  139935. * @param {Number} latitude The latitude at which to pick features.
  139936. * @return {Promise.<ImageryLayerFeatureInfo[]>|undefined} A promise for the picked features that will resolve when the asynchronous
  139937. * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
  139938. * instances. The array may be empty if no features are found at the given location.
  139939. * It may also be undefined if picking is not supported.
  139940. */
  139941. GridImageryProvider.prototype.pickFeatures = function() {
  139942. return undefined;
  139943. };
  139944. return GridImageryProvider;
  139945. });
  139946. /*global define*/
  139947. define('Scene/MapboxImageryProvider',[
  139948. '../Core/Credit',
  139949. '../Core/defaultValue',
  139950. '../Core/defined',
  139951. '../Core/defineProperties',
  139952. '../Core/DeveloperError',
  139953. '../Core/MapboxApi',
  139954. './UrlTemplateImageryProvider'
  139955. ], function(
  139956. Credit,
  139957. defaultValue,
  139958. defined,
  139959. defineProperties,
  139960. DeveloperError,
  139961. MapboxApi,
  139962. UrlTemplateImageryProvider) {
  139963. 'use strict';
  139964. var trailingSlashRegex = /\/$/;
  139965. var defaultCredit1 = new Credit('© Mapbox © OpenStreetMap', undefined, 'https://www.mapbox.com/about/maps/');
  139966. var defaultCredit2 = [new Credit('Improve this map', undefined, 'https://www.mapbox.com/map-feedback/')];
  139967. /**
  139968. * Provides tiled imagery hosted by Mapbox.
  139969. *
  139970. * @alias MapboxImageryProvider
  139971. * @constructor
  139972. *
  139973. * @param {Object} [options] Object with the following properties:
  139974. * @param {String} [options.url='https://api.mapbox.com/v4/'] The Mapbox server url.
  139975. * @param {String} options.mapId The Mapbox Map ID.
  139976. * @param {String} [options.accessToken] The public access token for the imagery.
  139977. * @param {String} [options.format='png'] The format of the image request.
  139978. * @param {Object} [options.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL.
  139979. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If not specified, the WGS84 ellipsoid is used.
  139980. * @param {Number} [options.minimumLevel=0] The minimum level-of-detail supported by the imagery provider. Take care when specifying
  139981. * this that the number of tiles at the minimum level is small, such as four or less. A larger number is likely
  139982. * to result in rendering problems.
  139983. * @param {Number} [options.maximumLevel] The maximum level-of-detail supported by the imagery provider, or undefined if there is no limit.
  139984. * @param {Rectangle} [options.rectangle=Rectangle.MAX_VALUE] The rectangle, in radians, covered by the image.
  139985. * @param {Credit|String} [options.credit] A credit for the data source, which is displayed on the canvas.
  139986. *
  139987. *
  139988. * @example
  139989. * // Mapbox tile provider
  139990. * var mapbox = new Cesium.MapboxImageryProvider({
  139991. * mapId: 'mapbox.streets',
  139992. * accessToken: 'thisIsMyAccessToken'
  139993. * });
  139994. *
  139995. * @see {@link https://www.mapbox.com/developers/api/maps/#tiles}
  139996. * @see {@link https://www.mapbox.com/developers/api/#access-tokens}
  139997. */
  139998. function MapboxImageryProvider(options) {
  139999. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  140000. var mapId = options.mapId;
  140001. if (!defined(mapId)) {
  140002. throw new DeveloperError('options.mapId is required.');
  140003. }
  140004. var url = defaultValue(options.url, 'https://api.mapbox.com/v4/');
  140005. this._url = url;
  140006. this._mapId = mapId;
  140007. this._accessToken = MapboxApi.getAccessToken(options.accessToken);
  140008. this._accessTokenErrorCredit = MapboxApi.getErrorCredit(options.key);
  140009. var format = defaultValue(options.format, 'png');
  140010. if (!/\./.test(format)) {
  140011. format = '.' + format;
  140012. }
  140013. this._format = format;
  140014. var templateUrl = url;
  140015. if (!trailingSlashRegex.test(url)) {
  140016. templateUrl += '/';
  140017. }
  140018. templateUrl += mapId + '/{z}/{x}/{y}' + this._format;
  140019. if (defined(this._accessToken)) {
  140020. templateUrl += '?access_token=' + this._accessToken;
  140021. }
  140022. if (defined(options.credit)) {
  140023. var credit = options.credit;
  140024. if (typeof credit === 'string') {
  140025. credit = new Credit(credit);
  140026. }
  140027. defaultCredit1 = credit;
  140028. defaultCredit2.length = 0;
  140029. }
  140030. this._imageryProvider = new UrlTemplateImageryProvider({
  140031. url: templateUrl,
  140032. proxy: options.proxy,
  140033. credit: defaultCredit1,
  140034. ellipsoid: options.ellipsoid,
  140035. minimumLevel: options.minimumLevel,
  140036. maximumLevel: options.maximumLevel,
  140037. rectangle: options.rectangle
  140038. });
  140039. }
  140040. defineProperties(MapboxImageryProvider.prototype, {
  140041. /**
  140042. * Gets the URL of the Mapbox server.
  140043. * @memberof MapboxImageryProvider.prototype
  140044. * @type {String}
  140045. * @readonly
  140046. */
  140047. url : {
  140048. get : function() {
  140049. return this._url;
  140050. }
  140051. },
  140052. /**
  140053. * Gets a value indicating whether or not the provider is ready for use.
  140054. * @memberof MapboxImageryProvider.prototype
  140055. * @type {Boolean}
  140056. * @readonly
  140057. */
  140058. ready : {
  140059. get : function() {
  140060. return this._imageryProvider.ready;
  140061. }
  140062. },
  140063. /**
  140064. * Gets a promise that resolves to true when the provider is ready for use.
  140065. * @memberof MapboxImageryProvider.prototype
  140066. * @type {Promise.<Boolean>}
  140067. * @readonly
  140068. */
  140069. readyPromise : {
  140070. get : function() {
  140071. return this._imageryProvider.readyPromise;
  140072. }
  140073. },
  140074. /**
  140075. * Gets the rectangle, in radians, of the imagery provided by the instance. This function should
  140076. * not be called before {@link MapboxImageryProvider#ready} returns true.
  140077. * @memberof MapboxImageryProvider.prototype
  140078. * @type {Rectangle}
  140079. * @readonly
  140080. */
  140081. rectangle: {
  140082. get : function() {
  140083. return this._imageryProvider.rectangle;
  140084. }
  140085. },
  140086. /**
  140087. * Gets the width of each tile, in pixels. This function should
  140088. * not be called before {@link MapboxImageryProvider#ready} returns true.
  140089. * @memberof MapboxImageryProvider.prototype
  140090. * @type {Number}
  140091. * @readonly
  140092. */
  140093. tileWidth : {
  140094. get : function() {
  140095. return this._imageryProvider.tileWidth;
  140096. }
  140097. },
  140098. /**
  140099. * Gets the height of each tile, in pixels. This function should
  140100. * not be called before {@link MapboxImageryProvider#ready} returns true.
  140101. * @memberof MapboxImageryProvider.prototype
  140102. * @type {Number}
  140103. * @readonly
  140104. */
  140105. tileHeight : {
  140106. get : function() {
  140107. return this._imageryProvider.tileHeight;
  140108. }
  140109. },
  140110. /**
  140111. * Gets the maximum level-of-detail that can be requested. This function should
  140112. * not be called before {@link MapboxImageryProvider#ready} returns true.
  140113. * @memberof MapboxImageryProvider.prototype
  140114. * @type {Number}
  140115. * @readonly
  140116. */
  140117. maximumLevel : {
  140118. get : function() {
  140119. return this._imageryProvider.maximumLevel;
  140120. }
  140121. },
  140122. /**
  140123. * Gets the minimum level-of-detail that can be requested. This function should
  140124. * not be called before {@link MapboxImageryProvider#ready} returns true. Generally,
  140125. * a minimum level should only be used when the rectangle of the imagery is small
  140126. * enough that the number of tiles at the minimum level is small. An imagery
  140127. * provider with more than a few tiles at the minimum level will lead to
  140128. * rendering problems.
  140129. * @memberof MapboxImageryProvider.prototype
  140130. * @type {Number}
  140131. * @readonly
  140132. */
  140133. minimumLevel : {
  140134. get : function() {
  140135. return this._imageryProvider.minimumLevel;
  140136. }
  140137. },
  140138. /**
  140139. * Gets the tiling scheme used by the provider. This function should
  140140. * not be called before {@link MapboxImageryProvider#ready} returns true.
  140141. * @memberof MapboxImageryProvider.prototype
  140142. * @type {TilingScheme}
  140143. * @readonly
  140144. */
  140145. tilingScheme : {
  140146. get : function() {
  140147. return this._imageryProvider.tilingScheme;
  140148. }
  140149. },
  140150. /**
  140151. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  140152. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  140153. * returns undefined, no tiles are filtered. This function should
  140154. * not be called before {@link MapboxImageryProvider#ready} returns true.
  140155. * @memberof MapboxImageryProvider.prototype
  140156. * @type {TileDiscardPolicy}
  140157. * @readonly
  140158. */
  140159. tileDiscardPolicy : {
  140160. get : function() {
  140161. return this._imageryProvider.tileDiscardPolicy;
  140162. }
  140163. },
  140164. /**
  140165. * Gets an event that is raised when the imagery provider encounters an asynchronous error.. By subscribing
  140166. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  140167. * are passed an instance of {@link TileProviderError}.
  140168. * @memberof MapboxImageryProvider.prototype
  140169. * @type {Event}
  140170. * @readonly
  140171. */
  140172. errorEvent : {
  140173. get : function() {
  140174. return this._imageryProvider.errorEvent;
  140175. }
  140176. },
  140177. /**
  140178. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  140179. * the source of the imagery. This function should
  140180. * not be called before {@link MapboxImageryProvider#ready} returns true.
  140181. * @memberof MapboxImageryProvider.prototype
  140182. * @type {Credit}
  140183. * @readonly
  140184. */
  140185. credit : {
  140186. get : function() {
  140187. return this._imageryProvider.credit;
  140188. }
  140189. },
  140190. /**
  140191. * Gets the proxy used by this provider.
  140192. * @memberof MapboxImageryProvider.prototype
  140193. * @type {Proxy}
  140194. * @readonly
  140195. */
  140196. proxy : {
  140197. get : function() {
  140198. return this._imageryProvider.proxy;
  140199. }
  140200. },
  140201. /**
  140202. * Gets a value indicating whether or not the images provided by this imagery provider
  140203. * include an alpha channel. If this property is false, an alpha channel, if present, will
  140204. * be ignored. If this property is true, any images without an alpha channel will be treated
  140205. * as if their alpha is 1.0 everywhere. When this property is false, memory usage
  140206. * and texture upload time are reduced.
  140207. * @memberof MapboxImageryProvider.prototype
  140208. * @type {Boolean}
  140209. * @readonly
  140210. */
  140211. hasAlphaChannel : {
  140212. get : function() {
  140213. return this._imageryProvider.hasAlphaChannel;
  140214. }
  140215. }
  140216. });
  140217. /**
  140218. * Gets the credits to be displayed when a given tile is displayed.
  140219. *
  140220. * @param {Number} x The tile X coordinate.
  140221. * @param {Number} y The tile Y coordinate.
  140222. * @param {Number} level The tile level;
  140223. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  140224. *
  140225. * @exception {DeveloperError} <code>getTileCredits</code> must not be called before the imagery provider is ready.
  140226. */
  140227. MapboxImageryProvider.prototype.getTileCredits = function(x, y, level) {
  140228. var credits = defaultCredit2.slice();
  140229. if (defined(this._accessTokenErrorCredit)) {
  140230. credits.push(this._accessTokenErrorCredit);
  140231. }
  140232. return credits;
  140233. };
  140234. /**
  140235. * Requests the image for a given tile. This function should
  140236. * not be called before {@link MapboxImageryProvider#ready} returns true.
  140237. *
  140238. * @param {Number} x The tile X coordinate.
  140239. * @param {Number} y The tile Y coordinate.
  140240. * @param {Number} level The tile level.
  140241. * @returns {Promise.<Image|Canvas>|undefined} A promise for the image that will resolve when the image is available, or
  140242. * undefined if there are too many active requests to the server, and the request
  140243. * should be retried later. The resolved image may be either an
  140244. * Image or a Canvas DOM object.
  140245. *
  140246. * @exception {DeveloperError} <code>requestImage</code> must not be called before the imagery provider is ready.
  140247. */
  140248. MapboxImageryProvider.prototype.requestImage = function(x, y, level) {
  140249. return this._imageryProvider.requestImage(x, y, level);
  140250. };
  140251. /**
  140252. * Asynchronously determines what features, if any, are located at a given longitude and latitude within
  140253. * a tile. This function should not be called before {@link MapboxImageryProvider#ready} returns true.
  140254. * This function is optional, so it may not exist on all ImageryProviders.
  140255. *
  140256. *
  140257. * @param {Number} x The tile X coordinate.
  140258. * @param {Number} y The tile Y coordinate.
  140259. * @param {Number} level The tile level.
  140260. * @param {Number} longitude The longitude at which to pick features.
  140261. * @param {Number} latitude The latitude at which to pick features.
  140262. * @return {Promise.<ImageryLayerFeatureInfo[]>|undefined} A promise for the picked features that will resolve when the asynchronous
  140263. * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
  140264. * instances. The array may be empty if no features are found at the given location.
  140265. * It may also be undefined if picking is not supported.
  140266. *
  140267. * @exception {DeveloperError} <code>pickFeatures</code> must not be called before the imagery provider is ready.
  140268. */
  140269. MapboxImageryProvider.prototype.pickFeatures = function(x, y, level, longitude, latitude) {
  140270. return this._imageryProvider.pickFeatures(x, y, level, longitude, latitude);
  140271. };
  140272. return MapboxImageryProvider;
  140273. });
  140274. /*global define*/
  140275. define('Scene/Moon',[
  140276. '../Core/buildModuleUrl',
  140277. '../Core/Cartesian3',
  140278. '../Core/defaultValue',
  140279. '../Core/defined',
  140280. '../Core/defineProperties',
  140281. '../Core/destroyObject',
  140282. '../Core/Ellipsoid',
  140283. '../Core/IauOrientationAxes',
  140284. '../Core/Matrix3',
  140285. '../Core/Matrix4',
  140286. '../Core/Simon1994PlanetaryPositions',
  140287. '../Core/Transforms',
  140288. './EllipsoidPrimitive',
  140289. './Material'
  140290. ], function(
  140291. buildModuleUrl,
  140292. Cartesian3,
  140293. defaultValue,
  140294. defined,
  140295. defineProperties,
  140296. destroyObject,
  140297. Ellipsoid,
  140298. IauOrientationAxes,
  140299. Matrix3,
  140300. Matrix4,
  140301. Simon1994PlanetaryPositions,
  140302. Transforms,
  140303. EllipsoidPrimitive,
  140304. Material) {
  140305. 'use strict';
  140306. /**
  140307. * Draws the Moon in 3D.
  140308. * @alias Moon
  140309. * @constructor
  140310. *
  140311. * @param {Object} [options] Object with the following properties:
  140312. * @param {Boolean} [options.show=true] Determines whether the moon will be rendered.
  140313. * @param {String} [options.textureUrl=buildModuleUrl('Assets/Textures/moonSmall.jpg')] The moon texture.
  140314. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.MOON] The moon ellipsoid.
  140315. * @param {Boolean} [options.onlySunLighting=true] Use the sun as the only light source.
  140316. *
  140317. *
  140318. * @example
  140319. * scene.moon = new Cesium.Moon();
  140320. *
  140321. * @see Scene#moon
  140322. */
  140323. function Moon(options) {
  140324. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  140325. var url = options.textureUrl;
  140326. if (!defined(url)) {
  140327. url = buildModuleUrl('Assets/Textures/moonSmall.jpg');
  140328. }
  140329. /**
  140330. * Determines if the moon will be shown.
  140331. *
  140332. * @type {Boolean}
  140333. * @default true
  140334. */
  140335. this.show = defaultValue(options.show, true);
  140336. /**
  140337. * The moon texture.
  140338. * @type {String}
  140339. * @default buildModuleUrl('Assets/Textures/moonSmall.jpg')
  140340. */
  140341. this.textureUrl = url;
  140342. this._ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.MOON);
  140343. /**
  140344. * Use the sun as the only light source.
  140345. * @type {Boolean}
  140346. * @default true
  140347. */
  140348. this.onlySunLighting = defaultValue(options.onlySunLighting, true);
  140349. this._ellipsoidPrimitive = new EllipsoidPrimitive({
  140350. radii : this.ellipsoid.radii,
  140351. material : Material.fromType(Material.ImageType),
  140352. depthTestEnabled : false,
  140353. _owner : this
  140354. });
  140355. this._ellipsoidPrimitive.material.translucent = false;
  140356. this._axes = new IauOrientationAxes();
  140357. }
  140358. defineProperties(Moon.prototype, {
  140359. /**
  140360. * Get the ellipsoid that defines the shape of the moon.
  140361. *
  140362. * @memberof Moon.prototype
  140363. *
  140364. * @type {Ellipsoid}
  140365. * @readonly
  140366. *
  140367. * @default {@link Ellipsoid.MOON}
  140368. */
  140369. ellipsoid : {
  140370. get : function() {
  140371. return this._ellipsoid;
  140372. }
  140373. }
  140374. });
  140375. var icrfToFixed = new Matrix3();
  140376. var rotationScratch = new Matrix3();
  140377. var translationScratch = new Cartesian3();
  140378. var scratchCommandList = [];
  140379. /**
  140380. * @private
  140381. */
  140382. Moon.prototype.update = function(frameState) {
  140383. if (!this.show) {
  140384. return;
  140385. }
  140386. var ellipsoidPrimitive = this._ellipsoidPrimitive;
  140387. ellipsoidPrimitive.material.uniforms.image = this.textureUrl;
  140388. ellipsoidPrimitive.onlySunLighting = this.onlySunLighting;
  140389. var date = frameState.time;
  140390. if (!defined(Transforms.computeIcrfToFixedMatrix(date, icrfToFixed))) {
  140391. Transforms.computeTemeToPseudoFixedMatrix(date, icrfToFixed);
  140392. }
  140393. var rotation = this._axes.evaluate(date, rotationScratch);
  140394. Matrix3.transpose(rotation, rotation);
  140395. Matrix3.multiply(icrfToFixed, rotation, rotation);
  140396. var translation = Simon1994PlanetaryPositions.computeMoonPositionInEarthInertialFrame(date, translationScratch);
  140397. Matrix3.multiplyByVector(icrfToFixed, translation, translation);
  140398. Matrix4.fromRotationTranslation(rotation, translation, ellipsoidPrimitive.modelMatrix);
  140399. var savedCommandList = frameState.commandList;
  140400. frameState.commandList = scratchCommandList;
  140401. scratchCommandList.length = 0;
  140402. ellipsoidPrimitive.update(frameState);
  140403. frameState.commandList = savedCommandList;
  140404. return (scratchCommandList.length === 1) ? scratchCommandList[0] : undefined;
  140405. };
  140406. /**
  140407. * Returns true if this object was destroyed; otherwise, false.
  140408. * <br /><br />
  140409. * If this object was destroyed, it should not be used; calling any function other than
  140410. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  140411. *
  140412. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  140413. *
  140414. * @see Moon#destroy
  140415. */
  140416. Moon.prototype.isDestroyed = function() {
  140417. return false;
  140418. };
  140419. /**
  140420. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  140421. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  140422. * <br /><br />
  140423. * Once an object is destroyed, it should not be used; calling any function other than
  140424. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  140425. * assign the return value (<code>undefined</code>) to the object as done in the example.
  140426. *
  140427. * @returns {undefined}
  140428. *
  140429. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  140430. *
  140431. *
  140432. * @example
  140433. * moon = moon && moon.destroy();
  140434. *
  140435. * @see Moon#isDestroyed
  140436. */
  140437. Moon.prototype.destroy = function() {
  140438. this._ellipsoidPrimitive = this._ellipsoidPrimitive && this._ellipsoidPrimitive.destroy();
  140439. return destroyObject(this);
  140440. };
  140441. return Moon;
  140442. });
  140443. /*global define*/
  140444. define('Scene/NeverTileDiscardPolicy',[], function() {
  140445. 'use strict';
  140446. /**
  140447. * A {@link TileDiscardPolicy} specifying that tile images should never be discard.
  140448. *
  140449. * @alias NeverTileDiscardPolicy
  140450. * @constructor
  140451. *
  140452. * @see DiscardMissingTileImagePolicy
  140453. */
  140454. function NeverTileDiscardPolicy(options) {
  140455. }
  140456. /**
  140457. * Determines if the discard policy is ready to process images.
  140458. * @returns {Boolean} True if the discard policy is ready to process images; otherwise, false.
  140459. */
  140460. NeverTileDiscardPolicy.prototype.isReady = function() {
  140461. return true;
  140462. };
  140463. /**
  140464. * Given a tile image, decide whether to discard that image.
  140465. *
  140466. * @param {Image} image An image to test.
  140467. * @returns {Boolean} True if the image should be discarded; otherwise, false.
  140468. */
  140469. NeverTileDiscardPolicy.prototype.shouldDiscardImage = function(image) {
  140470. return false;
  140471. };
  140472. return NeverTileDiscardPolicy;
  140473. });
  140474. //This file is automatically rebuilt by the Cesium build process.
  140475. /*global define*/
  140476. define('Shaders/AdjustTranslucentFS',[],function() {
  140477. 'use strict';
  140478. return "#ifdef MRT\n\
  140479. #extension GL_EXT_draw_buffers : enable\n\
  140480. #endif\n\
  140481. uniform vec4 u_bgColor;\n\
  140482. uniform sampler2D u_depthTexture;\n\
  140483. varying vec2 v_textureCoordinates;\n\
  140484. void main()\n\
  140485. {\n\
  140486. if (texture2D(u_depthTexture, v_textureCoordinates).r < 1.0)\n\
  140487. {\n\
  140488. #ifdef MRT\n\
  140489. gl_FragData[0] = u_bgColor;\n\
  140490. gl_FragData[1] = vec4(u_bgColor.a);\n\
  140491. #else\n\
  140492. gl_FragColor = u_bgColor;\n\
  140493. #endif\n\
  140494. return;\n\
  140495. }\n\
  140496. discard;\n\
  140497. }\n\
  140498. ";
  140499. });
  140500. //This file is automatically rebuilt by the Cesium build process.
  140501. /*global define*/
  140502. define('Shaders/CompositeOITFS',[],function() {
  140503. 'use strict';
  140504. return "uniform sampler2D u_opaque;\n\
  140505. uniform sampler2D u_accumulation;\n\
  140506. uniform sampler2D u_revealage;\n\
  140507. varying vec2 v_textureCoordinates;\n\
  140508. void main()\n\
  140509. {\n\
  140510. vec4 opaque = texture2D(u_opaque, v_textureCoordinates);\n\
  140511. vec4 accum = texture2D(u_accumulation, v_textureCoordinates);\n\
  140512. float r = texture2D(u_revealage, v_textureCoordinates).r;\n\
  140513. #ifdef MRT\n\
  140514. vec4 transparent = vec4(accum.rgb / clamp(r, 1e-4, 5e4), accum.a);\n\
  140515. #else\n\
  140516. vec4 transparent = vec4(accum.rgb / clamp(accum.a, 1e-4, 5e4), r);\n\
  140517. #endif\n\
  140518. gl_FragColor = (1.0 - transparent.a) * transparent + transparent.a * opaque;\n\
  140519. }\n\
  140520. ";
  140521. });
  140522. /*global define*/
  140523. define('Scene/OIT',[
  140524. '../Core/BoundingRectangle',
  140525. '../Core/Color',
  140526. '../Core/defined',
  140527. '../Core/destroyObject',
  140528. '../Core/PixelFormat',
  140529. '../Core/WebGLConstants',
  140530. '../Renderer/ClearCommand',
  140531. '../Renderer/DrawCommand',
  140532. '../Renderer/Framebuffer',
  140533. '../Renderer/PixelDatatype',
  140534. '../Renderer/RenderState',
  140535. '../Renderer/ShaderProgram',
  140536. '../Renderer/ShaderSource',
  140537. '../Renderer/Texture',
  140538. '../Shaders/AdjustTranslucentFS',
  140539. '../Shaders/CompositeOITFS',
  140540. './BlendEquation',
  140541. './BlendFunction'
  140542. ], function(
  140543. BoundingRectangle,
  140544. Color,
  140545. defined,
  140546. destroyObject,
  140547. PixelFormat,
  140548. WebGLConstants,
  140549. ClearCommand,
  140550. DrawCommand,
  140551. Framebuffer,
  140552. PixelDatatype,
  140553. RenderState,
  140554. ShaderProgram,
  140555. ShaderSource,
  140556. Texture,
  140557. AdjustTranslucentFS,
  140558. CompositeOITFS,
  140559. BlendEquation,
  140560. BlendFunction) {
  140561. 'use strict';
  140562. /**
  140563. * @private
  140564. */
  140565. function OIT(context) {
  140566. // We support multipass for the Chrome D3D9 backend and ES 2.0 on mobile.
  140567. this._translucentMultipassSupport = false;
  140568. this._translucentMRTSupport = false;
  140569. var extensionsSupported = context.floatingPointTexture && context.depthTexture;
  140570. this._translucentMRTSupport = context.drawBuffers && extensionsSupported;
  140571. this._translucentMultipassSupport = !this._translucentMRTSupport && extensionsSupported;
  140572. this._opaqueFBO = undefined;
  140573. this._opaqueTexture = undefined;
  140574. this._depthStencilTexture = undefined;
  140575. this._accumulationTexture = undefined;
  140576. this._translucentFBO = undefined;
  140577. this._alphaFBO = undefined;
  140578. this._adjustTranslucentFBO = undefined;
  140579. this._adjustAlphaFBO = undefined;
  140580. this._opaqueClearCommand = new ClearCommand({
  140581. color : new Color(0.0, 0.0, 0.0, 0.0),
  140582. owner : this
  140583. });
  140584. this._translucentMRTClearCommand = new ClearCommand({
  140585. color : new Color(0.0, 0.0, 0.0, 1.0),
  140586. owner : this
  140587. });
  140588. this._translucentMultipassClearCommand = new ClearCommand({
  140589. color : new Color(0.0, 0.0, 0.0, 0.0),
  140590. owner : this
  140591. });
  140592. this._alphaClearCommand = new ClearCommand({
  140593. color : new Color(1.0, 1.0, 1.0, 1.0),
  140594. owner : this
  140595. });
  140596. this._translucentRenderStateCache = {};
  140597. this._alphaRenderStateCache = {};
  140598. this._translucentShaderCache = {};
  140599. this._alphaShaderCache = {};
  140600. this._compositeCommand = undefined;
  140601. this._adjustTranslucentCommand = undefined;
  140602. this._adjustAlphaCommand = undefined;
  140603. this._viewport = new BoundingRectangle();
  140604. this._rs = undefined;
  140605. }
  140606. function destroyTextures(oit) {
  140607. oit._accumulationTexture = oit._accumulationTexture && !oit._accumulationTexture.isDestroyed() && oit._accumulationTexture.destroy();
  140608. oit._revealageTexture = oit._revealageTexture && !oit._revealageTexture.isDestroyed() && oit._revealageTexture.destroy();
  140609. }
  140610. function destroyFramebuffers(oit) {
  140611. oit._translucentFBO = oit._translucentFBO && !oit._translucentFBO.isDestroyed() && oit._translucentFBO.destroy();
  140612. oit._alphaFBO = oit._alphaFBO && !oit._alphaFBO.isDestroyed() && oit._alphaFBO.destroy();
  140613. oit._adjustTranslucentFBO = oit._adjustTranslucentFBO && !oit._adjustTranslucentFBO.isDestroyed() && oit._adjustTranslucentFBO.destroy();
  140614. oit._adjustAlphaFBO = oit._adjustAlphaFBO && !oit._adjustAlphaFBO.isDestroyed() && oit._adjustAlphaFBO.destroy();
  140615. }
  140616. function destroyResources(oit) {
  140617. destroyTextures(oit);
  140618. destroyFramebuffers(oit);
  140619. }
  140620. function updateTextures(oit, context, width, height) {
  140621. destroyTextures(oit);
  140622. // Use zeroed arraybuffer instead of null to initialize texture
  140623. // to workaround Firefox 50. https://github.com/AnalyticalGraphicsInc/cesium/pull/4762
  140624. var source = new Float32Array(width * height * 4);
  140625. oit._accumulationTexture = new Texture({
  140626. context : context,
  140627. pixelFormat : PixelFormat.RGBA,
  140628. pixelDatatype : PixelDatatype.FLOAT,
  140629. source : {
  140630. arrayBufferView : source,
  140631. width : width,
  140632. height : height
  140633. }
  140634. });
  140635. oit._revealageTexture = new Texture({
  140636. context : context,
  140637. pixelFormat : PixelFormat.RGBA,
  140638. pixelDatatype : PixelDatatype.FLOAT,
  140639. source : {
  140640. arrayBufferView : source,
  140641. width : width,
  140642. height : height
  140643. }
  140644. });
  140645. }
  140646. function updateFramebuffers(oit, context) {
  140647. destroyFramebuffers(oit);
  140648. var completeFBO = WebGLConstants.FRAMEBUFFER_COMPLETE;
  140649. var supported = true;
  140650. // if MRT is supported, attempt to make an FBO with multiple color attachments
  140651. if (oit._translucentMRTSupport) {
  140652. oit._translucentFBO = new Framebuffer({
  140653. context : context,
  140654. colorTextures : [oit._accumulationTexture, oit._revealageTexture],
  140655. depthStencilTexture : oit._depthStencilTexture,
  140656. destroyAttachments : false
  140657. });
  140658. oit._adjustTranslucentFBO = new Framebuffer({
  140659. context : context,
  140660. colorTextures : [oit._accumulationTexture, oit._revealageTexture],
  140661. destroyAttachments : false
  140662. });
  140663. if (oit._translucentFBO.status !== completeFBO || oit._adjustTranslucentFBO.status !== completeFBO) {
  140664. destroyFramebuffers(oit);
  140665. oit._translucentMRTSupport = false;
  140666. }
  140667. }
  140668. // either MRT isn't supported or FBO creation failed, attempt multipass
  140669. if (!oit._translucentMRTSupport) {
  140670. oit._translucentFBO = new Framebuffer({
  140671. context : context,
  140672. colorTextures : [oit._accumulationTexture],
  140673. depthStencilTexture : oit._depthStencilTexture,
  140674. destroyAttachments : false
  140675. });
  140676. oit._alphaFBO = new Framebuffer({
  140677. context : context,
  140678. colorTextures : [oit._revealageTexture],
  140679. depthStencilTexture : oit._depthStencilTexture,
  140680. destroyAttachments : false
  140681. });
  140682. oit._adjustTranslucentFBO = new Framebuffer({
  140683. context : context,
  140684. colorTextures : [oit._accumulationTexture],
  140685. destroyAttachments : false
  140686. });
  140687. oit._adjustAlphaFBO = new Framebuffer({
  140688. context : context,
  140689. colorTextures : [oit._revealageTexture],
  140690. destroyAttachments : false
  140691. });
  140692. var translucentComplete = oit._translucentFBO.status === completeFBO;
  140693. var alphaComplete = oit._alphaFBO.status === completeFBO;
  140694. var adjustTranslucentComplete = oit._adjustTranslucentFBO.status === completeFBO;
  140695. var adjustAlphaComplete = oit._adjustAlphaFBO.status === completeFBO;
  140696. if (!translucentComplete || !alphaComplete || !adjustTranslucentComplete || !adjustAlphaComplete) {
  140697. destroyResources(oit);
  140698. oit._translucentMultipassSupport = false;
  140699. supported = false;
  140700. }
  140701. }
  140702. return supported;
  140703. }
  140704. OIT.prototype.update = function(context, framebuffer) {
  140705. if (!this.isSupported()) {
  140706. return;
  140707. }
  140708. this._opaqueFBO = framebuffer;
  140709. this._opaqueTexture = framebuffer.getColorTexture(0);
  140710. this._depthStencilTexture = framebuffer.depthStencilTexture;
  140711. var width = this._opaqueTexture.width;
  140712. var height = this._opaqueTexture.height;
  140713. var accumulationTexture = this._accumulationTexture;
  140714. var textureChanged = !defined(accumulationTexture) || accumulationTexture.width !== width || accumulationTexture.height !== height;
  140715. if (textureChanged) {
  140716. updateTextures(this, context, width, height);
  140717. }
  140718. if (!defined(this._translucentFBO) || textureChanged) {
  140719. if (!updateFramebuffers(this, context)) {
  140720. // framebuffer creation failed
  140721. return;
  140722. }
  140723. }
  140724. var that = this;
  140725. var fs;
  140726. var uniformMap;
  140727. if (!defined(this._compositeCommand)) {
  140728. fs = new ShaderSource({
  140729. sources : [CompositeOITFS]
  140730. });
  140731. if (this._translucentMRTSupport) {
  140732. fs.defines.push('MRT');
  140733. }
  140734. uniformMap = {
  140735. u_opaque : function() {
  140736. return that._opaqueTexture;
  140737. },
  140738. u_accumulation : function() {
  140739. return that._accumulationTexture;
  140740. },
  140741. u_revealage : function() {
  140742. return that._revealageTexture;
  140743. }
  140744. };
  140745. this._compositeCommand = context.createViewportQuadCommand(fs, {
  140746. uniformMap : uniformMap,
  140747. owner : this
  140748. });
  140749. }
  140750. if (!defined(this._adjustTranslucentCommand)) {
  140751. if (this._translucentMRTSupport) {
  140752. fs = new ShaderSource({
  140753. defines : ['MRT'],
  140754. sources : [AdjustTranslucentFS]
  140755. });
  140756. uniformMap = {
  140757. u_bgColor : function() {
  140758. return that._translucentMRTClearCommand.color;
  140759. },
  140760. u_depthTexture : function() {
  140761. return that._depthStencilTexture;
  140762. }
  140763. };
  140764. this._adjustTranslucentCommand = context.createViewportQuadCommand(fs, {
  140765. uniformMap : uniformMap,
  140766. owner : this
  140767. });
  140768. } else if (this._translucentMultipassSupport) {
  140769. fs = new ShaderSource({
  140770. sources : [AdjustTranslucentFS]
  140771. });
  140772. uniformMap = {
  140773. u_bgColor : function() {
  140774. return that._translucentMultipassClearCommand.color;
  140775. },
  140776. u_depthTexture : function() {
  140777. return that._depthStencilTexture;
  140778. }
  140779. };
  140780. this._adjustTranslucentCommand = context.createViewportQuadCommand(fs, {
  140781. uniformMap : uniformMap,
  140782. owner : this
  140783. });
  140784. uniformMap = {
  140785. u_bgColor : function() {
  140786. return that._alphaClearCommand.color;
  140787. },
  140788. u_depthTexture : function() {
  140789. return that._depthStencilTexture;
  140790. }
  140791. };
  140792. this._adjustAlphaCommand = context.createViewportQuadCommand(fs, {
  140793. uniformMap : uniformMap,
  140794. owner : this
  140795. });
  140796. }
  140797. }
  140798. this._viewport.width = width;
  140799. this._viewport.height = height;
  140800. if (!defined(this._rs) || !BoundingRectangle.equals(this._viewport, this._rs.viewport)) {
  140801. this._rs = RenderState.fromCache({
  140802. viewport : this._viewport
  140803. });
  140804. }
  140805. if (defined(this._compositeCommand)) {
  140806. this._compositeCommand.renderState = this._rs;
  140807. }
  140808. if (this._adjustTranslucentCommand) {
  140809. this._adjustTranslucentCommand.renderState = this._rs;
  140810. }
  140811. if (defined(this._adjustAlphaCommand)) {
  140812. this._adjustAlphaCommand.renderState = this._rs;
  140813. }
  140814. };
  140815. var translucentMRTBlend = {
  140816. enabled : true,
  140817. color : new Color(0.0, 0.0, 0.0, 0.0),
  140818. equationRgb : BlendEquation.ADD,
  140819. equationAlpha : BlendEquation.ADD,
  140820. functionSourceRgb : BlendFunction.ONE,
  140821. functionDestinationRgb : BlendFunction.ONE,
  140822. functionSourceAlpha : BlendFunction.ZERO,
  140823. functionDestinationAlpha : BlendFunction.ONE_MINUS_SOURCE_ALPHA
  140824. };
  140825. var translucentColorBlend = {
  140826. enabled : true,
  140827. color : new Color(0.0, 0.0, 0.0, 0.0),
  140828. equationRgb : BlendEquation.ADD,
  140829. equationAlpha : BlendEquation.ADD,
  140830. functionSourceRgb : BlendFunction.ONE,
  140831. functionDestinationRgb : BlendFunction.ONE,
  140832. functionSourceAlpha : BlendFunction.ONE,
  140833. functionDestinationAlpha : BlendFunction.ONE
  140834. };
  140835. var translucentAlphaBlend = {
  140836. enabled : true,
  140837. color : new Color(0.0, 0.0, 0.0, 0.0),
  140838. equationRgb : BlendEquation.ADD,
  140839. equationAlpha : BlendEquation.ADD,
  140840. functionSourceRgb : BlendFunction.ZERO,
  140841. functionDestinationRgb : BlendFunction.ONE_MINUS_SOURCE_ALPHA,
  140842. functionSourceAlpha : BlendFunction.ZERO,
  140843. functionDestinationAlpha : BlendFunction.ONE_MINUS_SOURCE_ALPHA
  140844. };
  140845. function getTranslucentRenderState(context, translucentBlending, cache, renderState) {
  140846. var translucentState = cache[renderState.id];
  140847. if (!defined(translucentState)) {
  140848. var rs = RenderState.getState(renderState);
  140849. rs.depthMask = false;
  140850. rs.blending = translucentBlending;
  140851. translucentState = RenderState.fromCache(rs);
  140852. cache[renderState.id] = translucentState;
  140853. }
  140854. return translucentState;
  140855. }
  140856. function getTranslucentMRTRenderState(oit, context, renderState) {
  140857. return getTranslucentRenderState(context, translucentMRTBlend, oit._translucentRenderStateCache, renderState);
  140858. }
  140859. function getTranslucentColorRenderState(oit, context, renderState) {
  140860. return getTranslucentRenderState(context, translucentColorBlend, oit._translucentRenderStateCache, renderState);
  140861. }
  140862. function getTranslucentAlphaRenderState(oit, context, renderState) {
  140863. return getTranslucentRenderState(context, translucentAlphaBlend, oit._alphaRenderStateCache, renderState);
  140864. }
  140865. var mrtShaderSource =
  140866. ' vec3 Ci = czm_gl_FragColor.rgb * czm_gl_FragColor.a;\n' +
  140867. ' float ai = czm_gl_FragColor.a;\n' +
  140868. ' float wzi = czm_alphaWeight(ai);\n' +
  140869. ' gl_FragData[0] = vec4(Ci * wzi, ai);\n' +
  140870. ' gl_FragData[1] = vec4(ai * wzi);\n';
  140871. var colorShaderSource =
  140872. ' vec3 Ci = czm_gl_FragColor.rgb * czm_gl_FragColor.a;\n' +
  140873. ' float ai = czm_gl_FragColor.a;\n' +
  140874. ' float wzi = czm_alphaWeight(ai);\n' +
  140875. ' gl_FragColor = vec4(Ci, ai) * wzi;\n';
  140876. var alphaShaderSource =
  140877. ' float ai = czm_gl_FragColor.a;\n' +
  140878. ' gl_FragColor = vec4(ai);\n';
  140879. function getTranslucentShaderProgram(context, shaderProgram, cache, source) {
  140880. var id = shaderProgram.id;
  140881. var shader = cache[id];
  140882. if (!defined(shader)) {
  140883. var attributeLocations = shaderProgram._attributeLocations;
  140884. var fs = shaderProgram.fragmentShaderSource.clone();
  140885. fs.sources = fs.sources.map(function(source) {
  140886. source = ShaderSource.replaceMain(source, 'czm_translucent_main');
  140887. source = source.replace(/gl_FragColor/g, 'czm_gl_FragColor');
  140888. source = source.replace(/\bdiscard\b/g, 'czm_discard = true');
  140889. source = source.replace(/czm_phong/g, 'czm_translucentPhong');
  140890. return source;
  140891. });
  140892. // Discarding the fragment in main is a workaround for ANGLE D3D9
  140893. // shader compilation errors.
  140894. fs.sources.splice(0, 0,
  140895. (source.indexOf('gl_FragData') !== -1 ? '#extension GL_EXT_draw_buffers : enable \n' : '') +
  140896. 'vec4 czm_gl_FragColor;\n' +
  140897. 'bool czm_discard = false;\n');
  140898. fs.sources.push(
  140899. 'void main()\n' +
  140900. '{\n' +
  140901. ' czm_translucent_main();\n' +
  140902. ' if (czm_discard)\n' +
  140903. ' {\n' +
  140904. ' discard;\n' +
  140905. ' }\n' +
  140906. source +
  140907. '}\n');
  140908. shader = ShaderProgram.fromCache({
  140909. context : context,
  140910. vertexShaderSource : shaderProgram.vertexShaderSource,
  140911. fragmentShaderSource : fs,
  140912. attributeLocations : attributeLocations
  140913. });
  140914. cache[id] = shader;
  140915. }
  140916. return shader;
  140917. }
  140918. function getTranslucentMRTShaderProgram(oit, context, shaderProgram) {
  140919. return getTranslucentShaderProgram(context, shaderProgram, oit._translucentShaderCache, mrtShaderSource);
  140920. }
  140921. function getTranslucentColorShaderProgram(oit, context, shaderProgram) {
  140922. return getTranslucentShaderProgram(context, shaderProgram, oit._translucentShaderCache, colorShaderSource);
  140923. }
  140924. function getTranslucentAlphaShaderProgram(oit, context, shaderProgram) {
  140925. return getTranslucentShaderProgram(context, shaderProgram, oit._alphaShaderCache, alphaShaderSource);
  140926. }
  140927. OIT.prototype.createDerivedCommands = function(command, context, result) {
  140928. if (!defined(result)) {
  140929. result = {};
  140930. }
  140931. if (this._translucentMRTSupport) {
  140932. var translucentShader;
  140933. var translucentRenderState;
  140934. if (defined(result.translucentCommand)) {
  140935. translucentShader = result.translucentCommand.shaderProgram;
  140936. translucentRenderState = result.translucentCommand.renderState;
  140937. }
  140938. result.translucentCommand = DrawCommand.shallowClone(command, result.translucentCommand);
  140939. if (!defined(translucentShader) || result.shaderProgramId !== command.shaderProgram.id) {
  140940. result.translucentCommand.shaderProgram = getTranslucentMRTShaderProgram(this, context, command.shaderProgram);
  140941. result.translucentCommand.renderState = getTranslucentMRTRenderState(this, context, command.renderState);
  140942. result.shaderProgramId = command.shaderProgram.id;
  140943. } else {
  140944. result.translucentCommand.shaderProgram = translucentShader;
  140945. result.translucentCommand.renderState = translucentRenderState;
  140946. }
  140947. } else {
  140948. var colorShader;
  140949. var colorRenderState;
  140950. var alphaShader;
  140951. var alphaRenderState;
  140952. if (defined(result.translucentCommand)) {
  140953. colorShader = result.translucentCommand.shaderProgram;
  140954. colorRenderState = result.translucentCommand.renderState;
  140955. alphaShader = result.alphaCommand.shaderProgram;
  140956. alphaRenderState = result.alphaCommand.renderState;
  140957. }
  140958. result.translucentCommand = DrawCommand.shallowClone(command, result.translucentCommand);
  140959. result.alphaCommand = DrawCommand.shallowClone(command, result.alphaCommand);
  140960. if (!defined(colorShader) || result.shaderProgramId !== command.shaderProgram.id) {
  140961. result.translucentCommand.shaderProgram = getTranslucentColorShaderProgram(this, context, command.shaderProgram);
  140962. result.translucentCommand.renderState = getTranslucentColorRenderState(this, context, command.renderState);
  140963. result.alphaCommand.shaderProgram = getTranslucentAlphaShaderProgram(this, context, command.shaderProgram);
  140964. result.alphaCommand.renderState = getTranslucentAlphaRenderState(this, context, command.renderState);
  140965. result.shaderProgramId = command.shaderProgram.id;
  140966. } else {
  140967. result.translucentCommand.shaderProgram = colorShader;
  140968. result.translucentCommand.renderState = colorRenderState;
  140969. result.alphaCommand.shaderProgram = alphaShader;
  140970. result.alphaCommand.renderState = alphaRenderState;
  140971. }
  140972. }
  140973. return result;
  140974. };
  140975. function executeTranslucentCommandsSortedMultipass(oit, scene, executeFunction, passState, commands) {
  140976. var command;
  140977. var derivedCommand;
  140978. var j;
  140979. var context = scene.context;
  140980. var framebuffer = passState.framebuffer;
  140981. var length = commands.length;
  140982. var shadowsEnabled = scene.frameState.shadowHints.shadowsEnabled;
  140983. passState.framebuffer = oit._adjustTranslucentFBO;
  140984. oit._adjustTranslucentCommand.execute(context, passState);
  140985. passState.framebuffer = oit._adjustAlphaFBO;
  140986. oit._adjustAlphaCommand.execute(context, passState);
  140987. var debugFramebuffer = oit._opaqueFBO;
  140988. passState.framebuffer = oit._translucentFBO;
  140989. for (j = 0; j < length; ++j) {
  140990. command = commands[j];
  140991. derivedCommand = (shadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.translucentCommand : command.derivedCommands.oit.translucentCommand;
  140992. executeFunction(derivedCommand, scene, context, passState, debugFramebuffer);
  140993. }
  140994. passState.framebuffer = oit._alphaFBO;
  140995. for (j = 0; j < length; ++j) {
  140996. command = commands[j];
  140997. derivedCommand = (shadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.alphaCommand : command.derivedCommands.oit.alphaCommand;
  140998. executeFunction(derivedCommand, scene, context, passState, debugFramebuffer);
  140999. }
  141000. passState.framebuffer = framebuffer;
  141001. }
  141002. function executeTranslucentCommandsSortedMRT(oit, scene, executeFunction, passState, commands) {
  141003. var context = scene.context;
  141004. var framebuffer = passState.framebuffer;
  141005. var length = commands.length;
  141006. var shadowsEnabled = scene.frameState.shadowHints.shadowsEnabled;
  141007. passState.framebuffer = oit._adjustTranslucentFBO;
  141008. oit._adjustTranslucentCommand.execute(context, passState);
  141009. var debugFramebuffer = oit._opaqueFBO;
  141010. passState.framebuffer = oit._translucentFBO;
  141011. for (var j = 0; j < length; ++j) {
  141012. var command = commands[j];
  141013. var derivedCommand = (shadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.translucentCommand : command.derivedCommands.oit.translucentCommand;
  141014. executeFunction(derivedCommand, scene, context, passState, debugFramebuffer);
  141015. }
  141016. passState.framebuffer = framebuffer;
  141017. }
  141018. OIT.prototype.executeCommands = function(scene, executeFunction, passState, commands) {
  141019. if (this._translucentMRTSupport) {
  141020. executeTranslucentCommandsSortedMRT(this, scene, executeFunction, passState, commands);
  141021. return;
  141022. }
  141023. executeTranslucentCommandsSortedMultipass(this, scene, executeFunction, passState, commands);
  141024. };
  141025. OIT.prototype.execute = function(context, passState) {
  141026. this._compositeCommand.execute(context, passState);
  141027. };
  141028. OIT.prototype.clear = function(context, passState, clearColor) {
  141029. var framebuffer = passState.framebuffer;
  141030. passState.framebuffer = this._opaqueFBO;
  141031. Color.clone(clearColor, this._opaqueClearCommand.color);
  141032. this._opaqueClearCommand.execute(context, passState);
  141033. passState.framebuffer = this._translucentFBO;
  141034. var translucentClearCommand = this._translucentMRTSupport ? this._translucentMRTClearCommand : this._translucentMultipassClearCommand;
  141035. translucentClearCommand.execute(context, passState);
  141036. if (this._translucentMultipassSupport) {
  141037. passState.framebuffer = this._alphaFBO;
  141038. this._alphaClearCommand.execute(context, passState);
  141039. }
  141040. passState.framebuffer = framebuffer;
  141041. };
  141042. OIT.prototype.isSupported = function() {
  141043. return this._translucentMRTSupport || this._translucentMultipassSupport;
  141044. };
  141045. OIT.prototype.isDestroyed = function() {
  141046. return false;
  141047. };
  141048. OIT.prototype.destroy = function() {
  141049. destroyResources(this);
  141050. if (defined(this._compositeCommand)) {
  141051. this._compositeCommand.shaderProgram = this._compositeCommand.shaderProgram && this._compositeCommand.shaderProgram.destroy();
  141052. }
  141053. if (defined(this._adjustTranslucentCommand)) {
  141054. this._adjustTranslucentCommand.shaderProgram = this._adjustTranslucentCommand.shaderProgram && this._adjustTranslucentCommand.shaderProgram.destroy();
  141055. }
  141056. if (defined(this._adjustAlphaCommand)) {
  141057. this._adjustAlphaCommand.shaderProgram = this._adjustAlphaCommand.shaderProgram && this._adjustAlphaCommand.shaderProgram.destroy();
  141058. }
  141059. var name;
  141060. var cache = this._translucentShaderCache;
  141061. for (name in cache) {
  141062. if (cache.hasOwnProperty(name) && defined(cache[name])) {
  141063. cache[name].destroy();
  141064. }
  141065. }
  141066. this._translucentShaderCache = {};
  141067. cache = this._alphaShaderCache;
  141068. for (name in cache) {
  141069. if (cache.hasOwnProperty(name) && defined(cache[name])) {
  141070. cache[name].destroy();
  141071. }
  141072. }
  141073. this._alphaShaderCache = {};
  141074. return destroyObject(this);
  141075. };
  141076. return OIT;
  141077. });
  141078. /*global define*/
  141079. define('Scene/OrthographicFrustum',[
  141080. '../Core/Cartesian3',
  141081. '../Core/Cartesian4',
  141082. '../Core/defined',
  141083. '../Core/defineProperties',
  141084. '../Core/DeveloperError',
  141085. '../Core/Matrix4',
  141086. './CullingVolume'
  141087. ], function(
  141088. Cartesian3,
  141089. Cartesian4,
  141090. defined,
  141091. defineProperties,
  141092. DeveloperError,
  141093. Matrix4,
  141094. CullingVolume) {
  141095. 'use strict';
  141096. /**
  141097. * The viewing frustum is defined by 6 planes.
  141098. * Each plane is represented by a {@link Cartesian4} object, where the x, y, and z components
  141099. * define the unit vector normal to the plane, and the w component is the distance of the
  141100. * plane from the origin/camera position.
  141101. *
  141102. * @alias OrthographicFrustum
  141103. * @constructor
  141104. *
  141105. * @example
  141106. * var maxRadii = ellipsoid.maximumRadius;
  141107. *
  141108. * var frustum = new Cesium.OrthographicFrustum();
  141109. * frustum.right = maxRadii * Cesium.Math.PI;
  141110. * frustum.left = -c.frustum.right;
  141111. * frustum.top = c.frustum.right * (canvas.clientHeight / canvas.clientWidth);
  141112. * frustum.bottom = -c.frustum.top;
  141113. * frustum.near = 0.01 * maxRadii;
  141114. * frustum.far = 50.0 * maxRadii;
  141115. */
  141116. function OrthographicFrustum() {
  141117. /**
  141118. * The left clipping plane.
  141119. * @type {Number}
  141120. * @default undefined
  141121. */
  141122. this.left = undefined;
  141123. this._left = undefined;
  141124. /**
  141125. * The right clipping plane.
  141126. * @type {Number}
  141127. * @default undefined
  141128. */
  141129. this.right = undefined;
  141130. this._right = undefined;
  141131. /**
  141132. * The top clipping plane.
  141133. * @type {Number}
  141134. * @default undefined
  141135. */
  141136. this.top = undefined;
  141137. this._top = undefined;
  141138. /**
  141139. * The bottom clipping plane.
  141140. * @type {Number}
  141141. * @default undefined
  141142. */
  141143. this.bottom = undefined;
  141144. this._bottom = undefined;
  141145. /**
  141146. * The distance of the near plane.
  141147. * @type {Number}
  141148. * @default 1.0
  141149. */
  141150. this.near = 1.0;
  141151. this._near = this.near;
  141152. /**
  141153. * The distance of the far plane.
  141154. * @type {Number}
  141155. * @default 500000000.0;
  141156. */
  141157. this.far = 500000000.0;
  141158. this._far = this.far;
  141159. this._cullingVolume = new CullingVolume();
  141160. this._orthographicMatrix = new Matrix4();
  141161. }
  141162. function update(frustum) {
  141163. if (!defined(frustum.right) || !defined(frustum.left) ||
  141164. !defined(frustum.top) || !defined(frustum.bottom) ||
  141165. !defined(frustum.near) || !defined(frustum.far)) {
  141166. throw new DeveloperError('right, left, top, bottom, near, or far parameters are not set.');
  141167. }
  141168. if (frustum.top !== frustum._top || frustum.bottom !== frustum._bottom ||
  141169. frustum.left !== frustum._left || frustum.right !== frustum._right ||
  141170. frustum.near !== frustum._near || frustum.far !== frustum._far) {
  141171. if (frustum.left > frustum.right) {
  141172. throw new DeveloperError('right must be greater than left.');
  141173. }
  141174. if (frustum.bottom > frustum.top) {
  141175. throw new DeveloperError('top must be greater than bottom.');
  141176. }
  141177. if (frustum.near <= 0 || frustum.near > frustum.far) {
  141178. throw new DeveloperError('near must be greater than zero and less than far.');
  141179. }
  141180. frustum._left = frustum.left;
  141181. frustum._right = frustum.right;
  141182. frustum._top = frustum.top;
  141183. frustum._bottom = frustum.bottom;
  141184. frustum._near = frustum.near;
  141185. frustum._far = frustum.far;
  141186. frustum._orthographicMatrix = Matrix4.computeOrthographicOffCenter(frustum.left, frustum.right, frustum.bottom, frustum.top, frustum.near, frustum.far, frustum._orthographicMatrix);
  141187. }
  141188. }
  141189. defineProperties(OrthographicFrustum.prototype, {
  141190. /**
  141191. * Gets the orthographic projection matrix computed from the view frustum.
  141192. * @memberof OrthographicFrustum.prototype
  141193. * @type {Matrix4}
  141194. * @readonly
  141195. */
  141196. projectionMatrix : {
  141197. get : function() {
  141198. update(this);
  141199. return this._orthographicMatrix;
  141200. }
  141201. }
  141202. });
  141203. var getPlanesRight = new Cartesian3();
  141204. var getPlanesNearCenter = new Cartesian3();
  141205. var getPlanesPoint = new Cartesian3();
  141206. var negateScratch = new Cartesian3();
  141207. /**
  141208. * Creates a culling volume for this frustum.
  141209. *
  141210. * @param {Cartesian3} position The eye position.
  141211. * @param {Cartesian3} direction The view direction.
  141212. * @param {Cartesian3} up The up direction.
  141213. * @returns {CullingVolume} A culling volume at the given position and orientation.
  141214. *
  141215. * @example
  141216. * // Check if a bounding volume intersects the frustum.
  141217. * var cullingVolume = frustum.computeCullingVolume(cameraPosition, cameraDirection, cameraUp);
  141218. * var intersect = cullingVolume.computeVisibility(boundingVolume);
  141219. */
  141220. OrthographicFrustum.prototype.computeCullingVolume = function(position, direction, up) {
  141221. if (!defined(position)) {
  141222. throw new DeveloperError('position is required.');
  141223. }
  141224. if (!defined(direction)) {
  141225. throw new DeveloperError('direction is required.');
  141226. }
  141227. if (!defined(up)) {
  141228. throw new DeveloperError('up is required.');
  141229. }
  141230. var planes = this._cullingVolume.planes;
  141231. var t = this.top;
  141232. var b = this.bottom;
  141233. var r = this.right;
  141234. var l = this.left;
  141235. var n = this.near;
  141236. var f = this.far;
  141237. var right = Cartesian3.cross(direction, up, getPlanesRight);
  141238. var nearCenter = getPlanesNearCenter;
  141239. Cartesian3.multiplyByScalar(direction, n, nearCenter);
  141240. Cartesian3.add(position, nearCenter, nearCenter);
  141241. var point = getPlanesPoint;
  141242. // Left plane
  141243. Cartesian3.multiplyByScalar(right, l, point);
  141244. Cartesian3.add(nearCenter, point, point);
  141245. var plane = planes[0];
  141246. if (!defined(plane)) {
  141247. plane = planes[0] = new Cartesian4();
  141248. }
  141249. plane.x = right.x;
  141250. plane.y = right.y;
  141251. plane.z = right.z;
  141252. plane.w = -Cartesian3.dot(right, point);
  141253. // Right plane
  141254. Cartesian3.multiplyByScalar(right, r, point);
  141255. Cartesian3.add(nearCenter, point, point);
  141256. plane = planes[1];
  141257. if (!defined(plane)) {
  141258. plane = planes[1] = new Cartesian4();
  141259. }
  141260. plane.x = -right.x;
  141261. plane.y = -right.y;
  141262. plane.z = -right.z;
  141263. plane.w = -Cartesian3.dot(Cartesian3.negate(right, negateScratch), point);
  141264. // Bottom plane
  141265. Cartesian3.multiplyByScalar(up, b, point);
  141266. Cartesian3.add(nearCenter, point, point);
  141267. plane = planes[2];
  141268. if (!defined(plane)) {
  141269. plane = planes[2] = new Cartesian4();
  141270. }
  141271. plane.x = up.x;
  141272. plane.y = up.y;
  141273. plane.z = up.z;
  141274. plane.w = -Cartesian3.dot(up, point);
  141275. // Top plane
  141276. Cartesian3.multiplyByScalar(up, t, point);
  141277. Cartesian3.add(nearCenter, point, point);
  141278. plane = planes[3];
  141279. if (!defined(plane)) {
  141280. plane = planes[3] = new Cartesian4();
  141281. }
  141282. plane.x = -up.x;
  141283. plane.y = -up.y;
  141284. plane.z = -up.z;
  141285. plane.w = -Cartesian3.dot(Cartesian3.negate(up, negateScratch), point);
  141286. // Near plane
  141287. plane = planes[4];
  141288. if (!defined(plane)) {
  141289. plane = planes[4] = new Cartesian4();
  141290. }
  141291. plane.x = direction.x;
  141292. plane.y = direction.y;
  141293. plane.z = direction.z;
  141294. plane.w = -Cartesian3.dot(direction, nearCenter);
  141295. // Far plane
  141296. Cartesian3.multiplyByScalar(direction, f, point);
  141297. Cartesian3.add(position, point, point);
  141298. plane = planes[5];
  141299. if (!defined(plane)) {
  141300. plane = planes[5] = new Cartesian4();
  141301. }
  141302. plane.x = -direction.x;
  141303. plane.y = -direction.y;
  141304. plane.z = -direction.z;
  141305. plane.w = -Cartesian3.dot(Cartesian3.negate(direction, negateScratch), point);
  141306. return this._cullingVolume;
  141307. };
  141308. /**
  141309. * Returns the pixel's width and height in meters.
  141310. *
  141311. * @param {Number} drawingBufferWidth The width of the drawing buffer.
  141312. * @param {Number} drawingBufferHeight The height of the drawing buffer.
  141313. * @param {Number} distance The distance to the near plane in meters.
  141314. * @param {Cartesian2} result The object onto which to store the result.
  141315. * @returns {Cartesian2} The modified result parameter or a new instance of {@link Cartesian2} with the pixel's width and height in the x and y properties, respectively.
  141316. *
  141317. * @exception {DeveloperError} drawingBufferWidth must be greater than zero.
  141318. * @exception {DeveloperError} drawingBufferHeight must be greater than zero.
  141319. *
  141320. * @example
  141321. * // Example 1
  141322. * // Get the width and height of a pixel.
  141323. * var pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, 0.0, new Cesium.Cartesian2());
  141324. */
  141325. OrthographicFrustum.prototype.getPixelDimensions = function(drawingBufferWidth, drawingBufferHeight, distance, result) {
  141326. update(this);
  141327. if (!defined(drawingBufferWidth) || !defined(drawingBufferHeight)) {
  141328. throw new DeveloperError('Both drawingBufferWidth and drawingBufferHeight are required.');
  141329. }
  141330. if (drawingBufferWidth <= 0) {
  141331. throw new DeveloperError('drawingBufferWidth must be greater than zero.');
  141332. }
  141333. if (drawingBufferHeight <= 0) {
  141334. throw new DeveloperError('drawingBufferHeight must be greater than zero.');
  141335. }
  141336. if (!defined(distance)) {
  141337. throw new DeveloperError('distance is required.');
  141338. }
  141339. if (!defined(result)) {
  141340. throw new DeveloperError('A result object is required.');
  141341. }
  141342. var frustumWidth = this.right - this.left;
  141343. var frustumHeight = this.top - this.bottom;
  141344. var pixelWidth = frustumWidth / drawingBufferWidth;
  141345. var pixelHeight = frustumHeight / drawingBufferHeight;
  141346. result.x = pixelWidth;
  141347. result.y = pixelHeight;
  141348. return result;
  141349. };
  141350. /**
  141351. * Returns a duplicate of a OrthographicFrustum instance.
  141352. *
  141353. * @param {OrthographicFrustum} [result] The object onto which to store the result.
  141354. * @returns {OrthographicFrustum} The modified result parameter or a new PerspectiveFrustum instance if one was not provided.
  141355. */
  141356. OrthographicFrustum.prototype.clone = function(result) {
  141357. if (!defined(result)) {
  141358. result = new OrthographicFrustum();
  141359. }
  141360. result.left = this.left;
  141361. result.right = this.right;
  141362. result.top = this.top;
  141363. result.bottom = this.bottom;
  141364. result.near = this.near;
  141365. result.far = this.far;
  141366. // force update of clone to compute matrices
  141367. result._left = undefined;
  141368. result._right = undefined;
  141369. result._top = undefined;
  141370. result._bottom = undefined;
  141371. result._near = undefined;
  141372. result._far = undefined;
  141373. return result;
  141374. };
  141375. /**
  141376. * Compares the provided OrthographicFrustum componentwise and returns
  141377. * <code>true</code> if they are equal, <code>false</code> otherwise.
  141378. *
  141379. * @param {OrthographicFrustum} [other] The right hand side OrthographicFrustum.
  141380. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  141381. */
  141382. OrthographicFrustum.prototype.equals = function(other) {
  141383. return (defined(other) &&
  141384. this.right === other.right &&
  141385. this.left === other.left &&
  141386. this.top === other.top &&
  141387. this.bottom === other.bottom &&
  141388. this.near === other.near &&
  141389. this.far === other.far);
  141390. };
  141391. return OrthographicFrustum;
  141392. });
  141393. /*global define*/
  141394. define('Widgets/getElement',[
  141395. '../Core/DeveloperError'
  141396. ], function(
  141397. DeveloperError) {
  141398. 'use strict';
  141399. /**
  141400. * If element is a string, look up the element in the DOM by ID. Otherwise return element.
  141401. *
  141402. * @private
  141403. *
  141404. * @exception {DeveloperError} Element with id "id" does not exist in the document.
  141405. */
  141406. function getElement(element) {
  141407. if (typeof element === 'string') {
  141408. var foundElement = document.getElementById(element);
  141409. if (foundElement === null) {
  141410. throw new DeveloperError('Element with id "' + element + '" does not exist in the document.');
  141411. }
  141412. element = foundElement;
  141413. }
  141414. return element;
  141415. }
  141416. return getElement;
  141417. });
  141418. /*global define*/
  141419. define('Scene/PerformanceDisplay',[
  141420. '../Core/defaultValue',
  141421. '../Core/defined',
  141422. '../Core/destroyObject',
  141423. '../Core/DeveloperError',
  141424. '../Core/getTimestamp',
  141425. '../Widgets/getElement'
  141426. ], function(
  141427. defaultValue,
  141428. defined,
  141429. destroyObject,
  141430. DeveloperError,
  141431. getTimestamp,
  141432. getElement) {
  141433. 'use strict';
  141434. /**
  141435. * @private
  141436. */
  141437. function PerformanceDisplay(options) {
  141438. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  141439. var container = getElement(options.container);
  141440. if (!defined(container)) {
  141441. throw new DeveloperError('container is required');
  141442. }
  141443. this._container = container;
  141444. var display = document.createElement('div');
  141445. display.className = 'cesium-performanceDisplay';
  141446. var fpsElement = document.createElement('div');
  141447. fpsElement.className = 'cesium-performanceDisplay-fps';
  141448. this._fpsText = document.createTextNode("");
  141449. fpsElement.appendChild(this._fpsText);
  141450. var msElement = document.createElement('div');
  141451. msElement.className = 'cesium-performanceDisplay-ms';
  141452. this._msText = document.createTextNode("");
  141453. msElement.appendChild(this._msText);
  141454. display.appendChild(msElement);
  141455. display.appendChild(fpsElement);
  141456. this._container.appendChild(display);
  141457. this._lastFpsSampleTime = undefined;
  141458. this._frameCount = 0;
  141459. this._time = undefined;
  141460. this._fps = 0;
  141461. this._frameTime = 0;
  141462. }
  141463. /**
  141464. * Update the display. This function should only be called once per frame, because
  141465. * each call records a frame in the internal buffer and redraws the display.
  141466. */
  141467. PerformanceDisplay.prototype.update = function() {
  141468. if (!defined(this._time)) {
  141469. //first update
  141470. this._lastFpsSampleTime = getTimestamp();
  141471. this._time = getTimestamp();
  141472. return;
  141473. }
  141474. var previousTime = this._time;
  141475. var time = getTimestamp();
  141476. this._time = time;
  141477. var frameTime = time - previousTime;
  141478. this._frameCount++;
  141479. var fps = this._fps;
  141480. var fpsElapsedTime = time - this._lastFpsSampleTime;
  141481. if (fpsElapsedTime > 1000) {
  141482. fps = this._frameCount * 1000 / fpsElapsedTime | 0;
  141483. this._lastFpsSampleTime = time;
  141484. this._frameCount = 0;
  141485. }
  141486. if (fps !== this._fps) {
  141487. this._fpsText.nodeValue = fps + ' FPS';
  141488. this._fps = fps;
  141489. }
  141490. if (frameTime !== this._frameTime) {
  141491. this._msText.nodeValue = frameTime.toFixed(2) + ' MS';
  141492. this._frameTime = frameTime;
  141493. }
  141494. };
  141495. /**
  141496. * Destroys the WebGL resources held by this object.
  141497. */
  141498. PerformanceDisplay.prototype.destroy = function() {
  141499. return destroyObject(this);
  141500. };
  141501. return PerformanceDisplay;
  141502. });
  141503. /*global define*/
  141504. define('Scene/PickDepth',[
  141505. '../Core/defined',
  141506. '../Core/destroyObject',
  141507. '../Core/PixelFormat',
  141508. '../Renderer/Framebuffer',
  141509. '../Renderer/PixelDatatype',
  141510. '../Renderer/RenderState',
  141511. '../Renderer/Texture'
  141512. ], function(
  141513. defined,
  141514. destroyObject,
  141515. PixelFormat,
  141516. Framebuffer,
  141517. PixelDatatype,
  141518. RenderState,
  141519. Texture) {
  141520. 'use strict';
  141521. /**
  141522. * @private
  141523. */
  141524. function PickDepth() {
  141525. this.framebuffer = undefined;
  141526. this._depthTexture = undefined;
  141527. this._textureToCopy = undefined;
  141528. this._copyDepthCommand = undefined;
  141529. this._debugPickDepthViewportCommand = undefined;
  141530. }
  141531. function executeDebugPickDepth(pickDepth, context, passState) {
  141532. if (!defined(pickDepth._debugPickDepthViewportCommand)) {
  141533. var fs =
  141534. 'uniform sampler2D u_texture;\n' +
  141535. 'varying vec2 v_textureCoordinates;\n' +
  141536. 'void main()\n' +
  141537. '{\n' +
  141538. ' float z_window = czm_unpackDepth(texture2D(u_texture, v_textureCoordinates));\n' +
  141539. ' float n_range = czm_depthRange.near;\n' +
  141540. ' float f_range = czm_depthRange.far;\n' +
  141541. ' float z_ndc = (2.0 * z_window - n_range - f_range) / (f_range - n_range);\n' +
  141542. ' float scale = pow(z_ndc * 0.5 + 0.5, 8.0);\n' +
  141543. ' gl_FragColor = vec4(mix(vec3(0.0), vec3(1.0), scale), 1.0);\n' +
  141544. '}\n';
  141545. pickDepth._debugPickDepthViewportCommand = context.createViewportQuadCommand(fs, {
  141546. uniformMap : {
  141547. u_texture : function() {
  141548. return pickDepth._depthTexture;
  141549. }
  141550. },
  141551. owner : pickDepth
  141552. });
  141553. }
  141554. pickDepth._debugPickDepthViewportCommand.execute(context, passState);
  141555. }
  141556. function destroyTextures(pickDepth) {
  141557. pickDepth._depthTexture = pickDepth._depthTexture && !pickDepth._depthTexture.isDestroyed() && pickDepth._depthTexture.destroy();
  141558. }
  141559. function destroyFramebuffers(pickDepth) {
  141560. pickDepth.framebuffer = pickDepth.framebuffer && !pickDepth.framebuffer.isDestroyed() && pickDepth.framebuffer.destroy();
  141561. }
  141562. function createTextures(pickDepth, context, width, height) {
  141563. pickDepth._depthTexture = new Texture({
  141564. context : context,
  141565. width : width,
  141566. height : height,
  141567. pixelFormat : PixelFormat.RGBA,
  141568. pixelDatatype : PixelDatatype.UNSIGNED_BYTE
  141569. });
  141570. }
  141571. function createFramebuffers(pickDepth, context, width, height) {
  141572. destroyTextures(pickDepth);
  141573. destroyFramebuffers(pickDepth);
  141574. createTextures(pickDepth, context, width, height);
  141575. pickDepth.framebuffer = new Framebuffer({
  141576. context : context,
  141577. colorTextures : [pickDepth._depthTexture],
  141578. destroyAttachments : false
  141579. });
  141580. }
  141581. function updateFramebuffers(pickDepth, context, depthTexture) {
  141582. var width = depthTexture.width;
  141583. var height = depthTexture.height;
  141584. var texture = pickDepth._depthTexture;
  141585. var textureChanged = !defined(texture) || texture.width !== width || texture.height !== height;
  141586. if (!defined(pickDepth.framebuffer) || textureChanged) {
  141587. createFramebuffers(pickDepth, context, width, height);
  141588. }
  141589. }
  141590. function updateCopyCommands(pickDepth, context, depthTexture) {
  141591. if (!defined(pickDepth._copyDepthCommand)) {
  141592. var fs =
  141593. 'uniform sampler2D u_texture;\n' +
  141594. 'varying vec2 v_textureCoordinates;\n' +
  141595. 'void main()\n' +
  141596. '{\n' +
  141597. ' gl_FragColor = czm_packDepth(texture2D(u_texture, v_textureCoordinates).r);\n' +
  141598. '}\n';
  141599. pickDepth._copyDepthCommand = context.createViewportQuadCommand(fs, {
  141600. renderState : RenderState.fromCache(),
  141601. uniformMap : {
  141602. u_texture : function() {
  141603. return pickDepth._textureToCopy;
  141604. }
  141605. },
  141606. owner : pickDepth
  141607. });
  141608. }
  141609. pickDepth._textureToCopy = depthTexture;
  141610. pickDepth._copyDepthCommand.framebuffer = pickDepth.framebuffer;
  141611. }
  141612. PickDepth.prototype.executeDebugPickDepth = function(context, passState) {
  141613. executeDebugPickDepth(this, context, passState);
  141614. };
  141615. PickDepth.prototype.update = function(context, depthTexture) {
  141616. updateFramebuffers(this, context, depthTexture);
  141617. updateCopyCommands(this, context, depthTexture);
  141618. };
  141619. PickDepth.prototype.executeCopyDepth = function(context, passState) {
  141620. this._copyDepthCommand.execute(context, passState);
  141621. };
  141622. PickDepth.prototype.isDestroyed = function() {
  141623. return false;
  141624. };
  141625. PickDepth.prototype.destroy = function() {
  141626. destroyTextures(this);
  141627. destroyFramebuffers(this);
  141628. this._copyDepthCommand.shaderProgram = defined(this._copyDepthCommand.shaderProgram) && this._copyDepthCommand.shaderProgram.destroy();
  141629. return destroyObject(this);
  141630. };
  141631. return PickDepth;
  141632. });
  141633. //This file is automatically rebuilt by the Cesium build process.
  141634. /*global define*/
  141635. define('Shaders/Appearances/PointAppearanceFS',[],function() {
  141636. 'use strict';
  141637. return "uniform vec4 highlightColor;\n\
  141638. varying vec3 v_color;\n\
  141639. void main()\n\
  141640. {\n\
  141641. gl_FragColor = vec4(v_color * highlightColor.rgb, highlightColor.a);\n\
  141642. }\n\
  141643. ";
  141644. });
  141645. //This file is automatically rebuilt by the Cesium build process.
  141646. /*global define*/
  141647. define('Shaders/Appearances/PointAppearanceVS',[],function() {
  141648. 'use strict';
  141649. return "attribute vec3 position3DHigh;\n\
  141650. attribute vec3 position3DLow;\n\
  141651. attribute vec3 color;\n\
  141652. attribute float batchId;\n\
  141653. uniform float pointSize;\n\
  141654. varying vec3 v_positionEC;\n\
  141655. varying vec3 v_color;\n\
  141656. void main()\n\
  141657. {\n\
  141658. v_color = color;\n\
  141659. gl_Position = czm_modelViewProjectionRelativeToEye * czm_computePosition();\n\
  141660. gl_PointSize = pointSize;\n\
  141661. }\n\
  141662. ";
  141663. });
  141664. /*global define*/
  141665. define('Scene/PointAppearance',[
  141666. '../Core/Color',
  141667. '../Core/combine',
  141668. '../Core/defaultValue',
  141669. '../Core/defined',
  141670. '../Core/defineProperties',
  141671. '../Core/VertexFormat',
  141672. '../Shaders/Appearances/PointAppearanceFS',
  141673. '../Shaders/Appearances/PointAppearanceVS',
  141674. './Appearance'
  141675. ], function(
  141676. Color,
  141677. combine,
  141678. defaultValue,
  141679. defined,
  141680. defineProperties,
  141681. VertexFormat,
  141682. PointAppearanceFS,
  141683. PointAppearanceVS,
  141684. Appearance) {
  141685. 'use strict';
  141686. /**
  141687. * An appearance for point geometry {@link PointGeometry}
  141688. *
  141689. * @alias PointAppearance
  141690. * @constructor
  141691. *
  141692. * @param {Object} [options] Object with the following properties:
  141693. * @param {Boolean} [options.translucent=false] When <code>true</code>, the geometry is expected to appear translucent so {@link PointAppearance#renderState} has alpha blending enabled.
  141694. * @param {String} [options.vertexShaderSource] Optional GLSL vertex shader source to override the default vertex shader.
  141695. * @param {String} [options.fragmentShaderSource] Optional GLSL fragment shader source to override the default fragment shader.
  141696. * @param {RenderState} [options.renderState] Optional render state to override the default render state.
  141697. * @param {Object} [options.uniforms] Additional uniforms that are used by the vertex and fragment shaders.
  141698. * @param {Number} [options.pointSize] Point size in pixels.
  141699. * @param {Color} [options.highlightColor] Color multiplier in the fragment shader. The alpha channel is used for alpha blending when translucency is enabled.
  141700. *
  141701. * @example
  141702. * var primitive = new Cesium.Primitive({
  141703. * geometryInstances : new Cesium.GeometryInstance({
  141704. * geometry : new Cesium.PointGeometry({
  141705. * positionsTypedArray : positions,
  141706. * colorsTypedArray : colors,
  141707. * boundingSphere : boundingSphere
  141708. * })
  141709. * }),
  141710. * appearance : new Cesium.PointAppearance({
  141711. * translucent : true
  141712. * })
  141713. * });
  141714. *
  141715. * @private
  141716. */
  141717. function PointAppearance(options) {
  141718. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  141719. this._vertexShaderSource = defaultValue(options.vertexShaderSource, PointAppearanceVS);
  141720. this._fragmentShaderSource = defaultValue(options.fragmentShaderSource, PointAppearanceFS);
  141721. this._renderState = Appearance.getDefaultRenderState(false, false, options.renderState);
  141722. this._pointSize = defaultValue(options.pointSize, 2.0);
  141723. this._highlightColor = defined(options.highlightColor) ? options.highlightColor : new Color();
  141724. /**
  141725. * This property is part of the {@link Appearance} interface, but is not
  141726. * used by {@link PointAppearance} since a fully custom fragment shader is used.
  141727. *
  141728. * @type Material
  141729. *
  141730. * @default undefined
  141731. */
  141732. this.material = undefined;
  141733. /**
  141734. * When <code>true</code>, the geometry is expected to appear translucent.
  141735. *
  141736. * @type {Boolean}
  141737. *
  141738. * @default false
  141739. */
  141740. this.translucent = defaultValue(options.translucent, false);
  141741. /**
  141742. * @private
  141743. */
  141744. this.uniforms = {
  141745. highlightColor : this._highlightColor,
  141746. pointSize : this._pointSize
  141747. };
  141748. // Combine default uniforms and additional uniforms
  141749. var optionsUniforms = options.uniforms;
  141750. this.uniforms = combine(this.uniforms, optionsUniforms, true);
  141751. }
  141752. defineProperties(PointAppearance.prototype, {
  141753. /**
  141754. * The GLSL source code for the vertex shader.
  141755. *
  141756. * @memberof PointAppearance.prototype
  141757. *
  141758. * @type {String}
  141759. * @readonly
  141760. */
  141761. vertexShaderSource : {
  141762. get : function() {
  141763. return this._vertexShaderSource;
  141764. }
  141765. },
  141766. /**
  141767. * The GLSL source code for the fragment shader. The full fragment shader
  141768. * source is built procedurally taking into account the {@link PointAppearance#material}.
  141769. * Use {@link PointAppearance#getFragmentShaderSource} to get the full source.
  141770. *
  141771. * @memberof PointAppearance.prototype
  141772. *
  141773. * @type {String}
  141774. * @readonly
  141775. */
  141776. fragmentShaderSource : {
  141777. get : function() {
  141778. return this._fragmentShaderSource;
  141779. }
  141780. },
  141781. /**
  141782. * The WebGL fixed-function state to use when rendering the geometry.
  141783. *
  141784. * @memberof PointAppearance.prototype
  141785. *
  141786. * @type {Object}
  141787. * @readonly
  141788. */
  141789. renderState : {
  141790. get : function() {
  141791. return this._renderState;
  141792. }
  141793. },
  141794. /**
  141795. * When <code>true</code>, the geometry is expected to be closed.
  141796. *
  141797. * @memberof PointAppearance.prototype
  141798. *
  141799. * @type {Boolean}
  141800. * @readonly
  141801. *
  141802. * @default false
  141803. */
  141804. closed : {
  141805. get : function() {
  141806. return false;
  141807. }
  141808. },
  141809. /**
  141810. * The {@link VertexFormat} that this appearance instance is compatible with.
  141811. * A geometry can have more vertex attributes and still be compatible - at a
  141812. * potential performance cost - but it can't have less.
  141813. *
  141814. * @memberof PointAppearance.prototype
  141815. *
  141816. * @type VertexFormat
  141817. * @readonly
  141818. *
  141819. * @default {@link PointAppearance.VERTEX_FORMAT}
  141820. */
  141821. vertexFormat : {
  141822. get : function() {
  141823. return PointAppearance.VERTEX_FORMAT;
  141824. }
  141825. },
  141826. /**
  141827. * The size in pixels used when rendering the primitive. This helps calculate an accurate
  141828. * bounding volume for point rendering and other appearances that are defined in pixel sizes.
  141829. *
  141830. * @memberof PointAppearance.prototype
  141831. *
  141832. * @type {Number}
  141833. * @readonly
  141834. */
  141835. pixelSize : {
  141836. get : function() {
  141837. return this._pointSize;
  141838. }
  141839. }
  141840. });
  141841. /**
  141842. * The {@link VertexFormat} that all {@link PointAppearance} instances
  141843. * are compatible with, which requires only <code>position</code> and <code>color</code>
  141844. * attributes. Other attributes are procedurally computed in the fragment shader.
  141845. *
  141846. * @type VertexFormat
  141847. *
  141848. * @constant
  141849. */
  141850. PointAppearance.VERTEX_FORMAT = VertexFormat.POSITION_AND_COLOR;
  141851. /**
  141852. * Returns the full GLSL fragment shader source, which for {@link PointAppearance} is just
  141853. * {@link PointAppearance#fragmentShaderSource}.
  141854. *
  141855. * @function
  141856. *
  141857. * @returns {String} The full GLSL fragment shader source.
  141858. */
  141859. PointAppearance.prototype.getFragmentShaderSource = Appearance.prototype.getFragmentShaderSource;
  141860. /**
  141861. * Determines if the geometry is translucent based on {@link PointAppearance#translucent}.
  141862. *
  141863. * @function
  141864. *
  141865. * @returns {Boolean} <code>true</code> if the appearance is translucent.
  141866. */
  141867. PointAppearance.prototype.isTranslucent = Appearance.prototype.isTranslucent;
  141868. /**
  141869. * Creates a render state. This is not the final render state instance; instead,
  141870. * it can contain a subset of render state properties identical to the render state
  141871. * created in the context.
  141872. *
  141873. * @function
  141874. *
  141875. * @returns {Object} The render state.
  141876. */
  141877. PointAppearance.prototype.getRenderState = Appearance.prototype.getRenderState;
  141878. return PointAppearance;
  141879. });
  141880. /*global define*/
  141881. define('Scene/PrimitiveCollection',[
  141882. '../Core/createGuid',
  141883. '../Core/defaultValue',
  141884. '../Core/defined',
  141885. '../Core/defineProperties',
  141886. '../Core/destroyObject',
  141887. '../Core/DeveloperError'
  141888. ], function(
  141889. createGuid,
  141890. defaultValue,
  141891. defined,
  141892. defineProperties,
  141893. destroyObject,
  141894. DeveloperError) {
  141895. 'use strict';
  141896. /**
  141897. * A collection of primitives. This is most often used with {@link Scene#primitives},
  141898. * but <code>PrimitiveCollection</code> is also a primitive itself so collections can
  141899. * be added to collections forming a hierarchy.
  141900. *
  141901. * @alias PrimitiveCollection
  141902. * @constructor
  141903. *
  141904. * @param {Object} [options] Object with the following properties:
  141905. * @param {Boolean} [options.show=true] Determines if the primitives in the collection will be shown.
  141906. * @param {Boolean} [options.destroyPrimitives=true] Determines if primitives in the collection are destroyed when they are removed.
  141907. *
  141908. * @example
  141909. * var billboards = new Cesium.BillboardCollection();
  141910. * var labels = new Cesium.LabelCollection();
  141911. *
  141912. * var collection = new Cesium.PrimitiveCollection();
  141913. * collection.add(billboards);
  141914. *
  141915. * scene.primitives.add(collection); // Add collection
  141916. * scene.primitives.add(labels); // Add regular primitive
  141917. */
  141918. function PrimitiveCollection(options) {
  141919. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  141920. this._primitives = [];
  141921. this._guid = createGuid();
  141922. /**
  141923. * Determines if primitives in this collection will be shown.
  141924. *
  141925. * @type {Boolean}
  141926. * @default true
  141927. */
  141928. this.show = defaultValue(options.show, true);
  141929. /**
  141930. * Determines if primitives in the collection are destroyed when they are removed by
  141931. * {@link PrimitiveCollection#destroy} or {@link PrimitiveCollection#remove} or implicitly
  141932. * by {@link PrimitiveCollection#removeAll}.
  141933. *
  141934. * @type {Boolean}
  141935. * @default true
  141936. *
  141937. * @example
  141938. * // Example 1. Primitives are destroyed by default.
  141939. * var primitives = new Cesium.PrimitiveCollection();
  141940. * var labels = primitives.add(new Cesium.LabelCollection());
  141941. * primitives = primitives.destroy();
  141942. * var b = labels.isDestroyed(); // true
  141943. *
  141944. * @example
  141945. * // Example 2. Do not destroy primitives in a collection.
  141946. * var primitives = new Cesium.PrimitiveCollection();
  141947. * primitives.destroyPrimitives = false;
  141948. * var labels = primitives.add(new Cesium.LabelCollection());
  141949. * primitives = primitives.destroy();
  141950. * var b = labels.isDestroyed(); // false
  141951. * labels = labels.destroy(); // explicitly destroy
  141952. */
  141953. this.destroyPrimitives = defaultValue(options.destroyPrimitives, true);
  141954. }
  141955. defineProperties(PrimitiveCollection.prototype, {
  141956. /**
  141957. * Gets the number of primitives in the collection.
  141958. *
  141959. * @memberof PrimitiveCollection.prototype
  141960. *
  141961. * @type {Number}
  141962. * @readonly
  141963. */
  141964. length : {
  141965. get : function() {
  141966. return this._primitives.length;
  141967. }
  141968. }
  141969. });
  141970. /**
  141971. * Adds a primitive to the collection.
  141972. *
  141973. * @param {Object} primitive The primitive to add.
  141974. * @returns {Object} The primitive added to the collection.
  141975. *
  141976. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  141977. *
  141978. * @example
  141979. * var billboards = scene.primitives.add(new Cesium.BillboardCollection());
  141980. */
  141981. PrimitiveCollection.prototype.add = function(primitive) {
  141982. if (!defined(primitive)) {
  141983. throw new DeveloperError('primitive is required.');
  141984. }
  141985. var external = (primitive._external = primitive._external || {});
  141986. var composites = (external._composites = external._composites || {});
  141987. composites[this._guid] = {
  141988. collection : this
  141989. };
  141990. this._primitives.push(primitive);
  141991. return primitive;
  141992. };
  141993. /**
  141994. * Removes a primitive from the collection.
  141995. *
  141996. * @param {Object} [primitive] The primitive to remove.
  141997. * @returns {Boolean} <code>true</code> if the primitive was removed; <code>false</code> if the primitive is <code>undefined</code> or was not found in the collection.
  141998. *
  141999. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  142000. *
  142001. *
  142002. * @example
  142003. * var billboards = scene.primitives.add(new Cesium.BillboardCollection());
  142004. * scene.primitives.remove(p); // Returns true
  142005. *
  142006. * @see PrimitiveCollection#destroyPrimitives
  142007. */
  142008. PrimitiveCollection.prototype.remove = function(primitive) {
  142009. // PERFORMANCE_IDEA: We can obviously make this a lot faster.
  142010. if (this.contains(primitive)) {
  142011. var index = this._primitives.indexOf(primitive);
  142012. if (index !== -1) {
  142013. this._primitives.splice(index, 1);
  142014. delete primitive._external._composites[this._guid];
  142015. if (this.destroyPrimitives) {
  142016. primitive.destroy();
  142017. }
  142018. return true;
  142019. }
  142020. // else ... this is not possible, I swear.
  142021. }
  142022. return false;
  142023. };
  142024. /**
  142025. * Removes and destroys a primitive, regardless of destroyPrimitives setting.
  142026. * @private
  142027. */
  142028. PrimitiveCollection.prototype.removeAndDestroy = function(primitive) {
  142029. var removed = this.remove(primitive);
  142030. if (removed && !this.destroyPrimitives) {
  142031. primitive.destroy();
  142032. }
  142033. return removed;
  142034. };
  142035. /**
  142036. * Removes all primitives in the collection.
  142037. *
  142038. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  142039. *
  142040. * @see PrimitiveCollection#destroyPrimitives
  142041. */
  142042. PrimitiveCollection.prototype.removeAll = function() {
  142043. if (this.destroyPrimitives) {
  142044. var primitives = this._primitives;
  142045. var length = primitives.length;
  142046. for ( var i = 0; i < length; ++i) {
  142047. primitives[i].destroy();
  142048. }
  142049. }
  142050. this._primitives = [];
  142051. };
  142052. /**
  142053. * Determines if this collection contains a primitive.
  142054. *
  142055. * @param {Object} [primitive] The primitive to check for.
  142056. * @returns {Boolean} <code>true</code> if the primitive is in the collection; <code>false</code> if the primitive is <code>undefined</code> or was not found in the collection.
  142057. *
  142058. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  142059. *
  142060. * @see PrimitiveCollection#get
  142061. */
  142062. PrimitiveCollection.prototype.contains = function(primitive) {
  142063. return !!(defined(primitive) &&
  142064. primitive._external &&
  142065. primitive._external._composites &&
  142066. primitive._external._composites[this._guid]);
  142067. };
  142068. function getPrimitiveIndex(compositePrimitive, primitive) {
  142069. if (!compositePrimitive.contains(primitive)) {
  142070. throw new DeveloperError('primitive is not in this collection.');
  142071. }
  142072. return compositePrimitive._primitives.indexOf(primitive);
  142073. }
  142074. /**
  142075. * Raises a primitive "up one" in the collection. If all primitives in the collection are drawn
  142076. * on the globe surface, this visually moves the primitive up one.
  142077. *
  142078. * @param {Object} [primitive] The primitive to raise.
  142079. *
  142080. * @exception {DeveloperError} primitive is not in this collection.
  142081. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  142082. *
  142083. * @see PrimitiveCollection#raiseToTop
  142084. * @see PrimitiveCollection#lower
  142085. * @see PrimitiveCollection#lowerToBottom
  142086. */
  142087. PrimitiveCollection.prototype.raise = function(primitive) {
  142088. if (defined(primitive)) {
  142089. var index = getPrimitiveIndex(this, primitive);
  142090. var primitives = this._primitives;
  142091. if (index !== primitives.length - 1) {
  142092. var p = primitives[index];
  142093. primitives[index] = primitives[index + 1];
  142094. primitives[index + 1] = p;
  142095. }
  142096. }
  142097. };
  142098. /**
  142099. * Raises a primitive to the "top" of the collection. If all primitives in the collection are drawn
  142100. * on the globe surface, this visually moves the primitive to the top.
  142101. *
  142102. * @param {Object} [primitive] The primitive to raise the top.
  142103. *
  142104. * @exception {DeveloperError} primitive is not in this collection.
  142105. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  142106. *
  142107. * @see PrimitiveCollection#raise
  142108. * @see PrimitiveCollection#lower
  142109. * @see PrimitiveCollection#lowerToBottom
  142110. */
  142111. PrimitiveCollection.prototype.raiseToTop = function(primitive) {
  142112. if (defined(primitive)) {
  142113. var index = getPrimitiveIndex(this, primitive);
  142114. var primitives = this._primitives;
  142115. if (index !== primitives.length - 1) {
  142116. // PERFORMANCE_IDEA: Could be faster
  142117. primitives.splice(index, 1);
  142118. primitives.push(primitive);
  142119. }
  142120. }
  142121. };
  142122. /**
  142123. * Lowers a primitive "down one" in the collection. If all primitives in the collection are drawn
  142124. * on the globe surface, this visually moves the primitive down one.
  142125. *
  142126. * @param {Object} [primitive] The primitive to lower.
  142127. *
  142128. * @exception {DeveloperError} primitive is not in this collection.
  142129. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  142130. *
  142131. * @see PrimitiveCollection#lowerToBottom
  142132. * @see PrimitiveCollection#raise
  142133. * @see PrimitiveCollection#raiseToTop
  142134. */
  142135. PrimitiveCollection.prototype.lower = function(primitive) {
  142136. if (defined(primitive)) {
  142137. var index = getPrimitiveIndex(this, primitive);
  142138. var primitives = this._primitives;
  142139. if (index !== 0) {
  142140. var p = primitives[index];
  142141. primitives[index] = primitives[index - 1];
  142142. primitives[index - 1] = p;
  142143. }
  142144. }
  142145. };
  142146. /**
  142147. * Lowers a primitive to the "bottom" of the collection. If all primitives in the collection are drawn
  142148. * on the globe surface, this visually moves the primitive to the bottom.
  142149. *
  142150. * @param {Object} [primitive] The primitive to lower to the bottom.
  142151. *
  142152. * @exception {DeveloperError} primitive is not in this collection.
  142153. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  142154. *
  142155. * @see PrimitiveCollection#lower
  142156. * @see PrimitiveCollection#raise
  142157. * @see PrimitiveCollection#raiseToTop
  142158. */
  142159. PrimitiveCollection.prototype.lowerToBottom = function(primitive) {
  142160. if (defined(primitive)) {
  142161. var index = getPrimitiveIndex(this, primitive);
  142162. var primitives = this._primitives;
  142163. if (index !== 0) {
  142164. // PERFORMANCE_IDEA: Could be faster
  142165. primitives.splice(index, 1);
  142166. primitives.unshift(primitive);
  142167. }
  142168. }
  142169. };
  142170. /**
  142171. * Returns the primitive in the collection at the specified index.
  142172. *
  142173. * @param {Number} index The zero-based index of the primitive to return.
  142174. * @returns {Object} The primitive at the <code>index</code>.
  142175. *
  142176. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  142177. *
  142178. *
  142179. * @example
  142180. * // Toggle the show property of every primitive in the collection.
  142181. * var primitives = scene.primitives;
  142182. * var length = primitives.length;
  142183. * for (var i = 0; i < length; ++i) {
  142184. * var p = primitives.get(i);
  142185. * p.show = !p.show;
  142186. * }
  142187. *
  142188. * @see PrimitiveCollection#length
  142189. */
  142190. PrimitiveCollection.prototype.get = function(index) {
  142191. if (!defined(index)) {
  142192. throw new DeveloperError('index is required.');
  142193. }
  142194. return this._primitives[index];
  142195. };
  142196. /**
  142197. * @private
  142198. */
  142199. PrimitiveCollection.prototype.update = function(frameState) {
  142200. if (!this.show) {
  142201. return;
  142202. }
  142203. var primitives = this._primitives;
  142204. // Using primitives.length in the loop is a temporary workaround
  142205. // to allow quadtree updates to add and remove primitives in
  142206. // update(). This will be changed to manage added and removed lists.
  142207. for (var i = 0; i < primitives.length; ++i) {
  142208. primitives[i].update(frameState);
  142209. }
  142210. };
  142211. /**
  142212. * Returns true if this object was destroyed; otherwise, false.
  142213. * <br /><br />
  142214. * If this object was destroyed, it should not be used; calling any function other than
  142215. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  142216. *
  142217. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  142218. *
  142219. * @see PrimitiveCollection#destroy
  142220. */
  142221. PrimitiveCollection.prototype.isDestroyed = function() {
  142222. return false;
  142223. };
  142224. /**
  142225. * Destroys the WebGL resources held by each primitive in this collection. Explicitly destroying this
  142226. * collection allows for deterministic release of WebGL resources, instead of relying on the garbage
  142227. * collector to destroy this collection.
  142228. * <br /><br />
  142229. * Since destroying a collection destroys all the contained primitives, only destroy a collection
  142230. * when you are sure no other code is still using any of the contained primitives.
  142231. * <br /><br />
  142232. * Once this collection is destroyed, it should not be used; calling any function other than
  142233. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  142234. * assign the return value (<code>undefined</code>) to the object as done in the example.
  142235. *
  142236. * @returns {undefined}
  142237. *
  142238. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  142239. *
  142240. *
  142241. * @example
  142242. * primitives = primitives && primitives.destroy();
  142243. *
  142244. * @see PrimitiveCollection#isDestroyed
  142245. */
  142246. PrimitiveCollection.prototype.destroy = function() {
  142247. this.removeAll();
  142248. return destroyObject(this);
  142249. };
  142250. return PrimitiveCollection;
  142251. });
  142252. /*global define*/
  142253. define('Scene/QuadtreeTileProvider',[
  142254. '../Core/defineProperties',
  142255. '../Core/DeveloperError'
  142256. ], function(
  142257. defineProperties,
  142258. DeveloperError) {
  142259. 'use strict';
  142260. /**
  142261. * Provides general quadtree tiles to be displayed on or near the surface of an ellipsoid. It is intended to be
  142262. * used with the {@link QuadtreePrimitive}. This type describes an interface and is not intended to be
  142263. * instantiated directly.
  142264. *
  142265. * @alias QuadtreeTileProvider
  142266. * @constructor
  142267. * @private
  142268. */
  142269. function QuadtreeTileProvider() {
  142270. DeveloperError.throwInstantiationError();
  142271. }
  142272. /**
  142273. * Computes the default geometric error for level zero of the quadtree.
  142274. *
  142275. * @memberof QuadtreeTileProvider
  142276. *
  142277. * @param {TilingScheme} tilingScheme The tiling scheme for which to compute the geometric error.
  142278. * @returns {Number} The maximum geometric error at level zero, in meters.
  142279. */
  142280. QuadtreeTileProvider.computeDefaultLevelZeroMaximumGeometricError = function(tilingScheme) {
  142281. return tilingScheme.ellipsoid.maximumRadius * 2 * Math.PI * 0.25 / (65 * tilingScheme.getNumberOfXTilesAtLevel(0));
  142282. };
  142283. defineProperties(QuadtreeTileProvider.prototype, {
  142284. /**
  142285. * Gets or sets the {@link QuadtreePrimitive} for which this provider is
  142286. * providing tiles.
  142287. * @memberof QuadtreeTileProvider.prototype
  142288. * @type {QuadtreePrimitive}
  142289. */
  142290. quadtree : {
  142291. get : DeveloperError.throwInstantiationError,
  142292. set : DeveloperError.throwInstantiationError
  142293. },
  142294. /**
  142295. * Gets a value indicating whether or not the provider is ready for use.
  142296. * @memberof QuadtreeTileProvider.prototype
  142297. * @type {Boolean}
  142298. */
  142299. ready : {
  142300. get : DeveloperError.throwInstantiationError
  142301. },
  142302. /**
  142303. * Gets the tiling scheme used by the provider. This property should
  142304. * not be accessed before {@link QuadtreeTileProvider#ready} returns true.
  142305. * @memberof QuadtreeTileProvider.prototype
  142306. * @type {TilingScheme}
  142307. */
  142308. tilingScheme : {
  142309. get : DeveloperError.throwInstantiationError
  142310. },
  142311. /**
  142312. * Gets an event that is raised when the geometry provider encounters an asynchronous error. By subscribing
  142313. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  142314. * are passed an instance of {@link TileProviderError}.
  142315. * @memberof QuadtreeTileProvider.prototype
  142316. * @type {Event}
  142317. */
  142318. errorEvent : {
  142319. get : DeveloperError.throwInstantiationError
  142320. }
  142321. });
  142322. /**
  142323. * Called at the beginning of the update cycle for each render frame, before {@link QuadtreeTileProvider#showTileThisFrame}
  142324. * or any other functions.
  142325. * @memberof QuadtreeTileProvider
  142326. * @function
  142327. *
  142328. * @param {Context} context The rendering context.
  142329. * @param {FrameState} frameState The frame state.
  142330. * @param {DrawCommand[]} commandList An array of rendering commands. This method may push
  142331. * commands into this array.
  142332. */
  142333. QuadtreeTileProvider.prototype.beginUpdate = DeveloperError.throwInstantiationError;
  142334. /**
  142335. * Called at the end of the update cycle for each render frame, after {@link QuadtreeTileProvider#showTileThisFrame}
  142336. * and any other functions.
  142337. * @memberof QuadtreeTileProvider
  142338. * @function
  142339. *
  142340. * @param {Context} context The rendering context.
  142341. * @param {FrameState} frameState The frame state.
  142342. * @param {DrawCommand[]} commandList An array of rendering commands. This method may push
  142343. * commands into this array.
  142344. */
  142345. QuadtreeTileProvider.prototype.endUpdate = DeveloperError.throwInstantiationError;
  142346. /**
  142347. * Gets the maximum geometric error allowed in a tile at a given level, in meters. This function should not be
  142348. * called before {@link QuadtreeTileProvider#ready} returns true.
  142349. *
  142350. * @see {QuadtreeTileProvider.computeDefaultLevelZeroMaximumGeometricError}
  142351. *
  142352. * @memberof QuadtreeTileProvider
  142353. * @function
  142354. *
  142355. * @param {Number} level The tile level for which to get the maximum geometric error.
  142356. * @returns {Number} The maximum geometric error in meters.
  142357. */
  142358. QuadtreeTileProvider.prototype.getLevelMaximumGeometricError = DeveloperError.throwInstantiationError;
  142359. /**
  142360. * Loads, or continues loading, a given tile. This function will continue to be called
  142361. * until {@link QuadtreeTile#state} is no longer {@link QuadtreeTileLoadState#LOADING}. This function should
  142362. * not be called before {@link QuadtreeTileProvider#ready} returns true.
  142363. *
  142364. * @memberof QuadtreeTileProvider
  142365. * @function
  142366. *
  142367. * @param {Context} context The rendering context.
  142368. * @param {FrameState} frameState The frame state.
  142369. * @param {QuadtreeTile} tile The tile to load.
  142370. *
  142371. * @exception {DeveloperError} <code>loadTile</code> must not be called before the tile provider is ready.
  142372. */
  142373. QuadtreeTileProvider.prototype.loadTile = DeveloperError.throwInstantiationError;
  142374. /**
  142375. * Determines the visibility of a given tile. The tile may be fully visible, partially visible, or not
  142376. * visible at all. Tiles that are renderable and are at least partially visible will be shown by a call
  142377. * to {@link QuadtreeTileProvider#showTileThisFrame}.
  142378. *
  142379. * @memberof QuadtreeTileProvider
  142380. *
  142381. * @param {QuadtreeTile} tile The tile instance.
  142382. * @param {FrameState} frameState The state information about the current frame.
  142383. * @param {QuadtreeOccluders} occluders The objects that may occlude this tile.
  142384. *
  142385. * @returns {Visibility} The visibility of the tile.
  142386. */
  142387. QuadtreeTileProvider.prototype.computeTileVisibility = DeveloperError.throwInstantiationError;
  142388. /**
  142389. * Shows a specified tile in this frame. The provider can cause the tile to be shown by adding
  142390. * render commands to the commandList, or use any other method as appropriate. The tile is not
  142391. * expected to be visible next frame as well, unless this method is call next frame, too.
  142392. *
  142393. * @memberof QuadtreeTileProvider
  142394. * @function
  142395. *
  142396. * @param {QuadtreeTile} tile The tile instance.
  142397. * @param {Context} context The rendering context.
  142398. * @param {FrameState} frameState The state information of the current rendering frame.
  142399. * @param {DrawCommand[]} commandList The list of rendering commands. This method may add additional commands to this list.
  142400. */
  142401. QuadtreeTileProvider.prototype.showTileThisFrame = DeveloperError.throwInstantiationError;
  142402. /**
  142403. * Gets the distance from the camera to the closest point on the tile. This is used for level-of-detail selection.
  142404. *
  142405. * @memberof QuadtreeTileProvider
  142406. * @function
  142407. *
  142408. * @param {QuadtreeTile} tile The tile instance.
  142409. * @param {FrameState} frameState The state information of the current rendering frame.
  142410. *
  142411. * @returns {Number} The distance from the camera to the closest point on the tile, in meters.
  142412. */
  142413. QuadtreeTileProvider.prototype.computeDistanceToTile = DeveloperError.throwInstantiationError;
  142414. /**
  142415. * Returns true if this object was destroyed; otherwise, false.
  142416. * <br /><br />
  142417. * If this object was destroyed, it should not be used; calling any function other than
  142418. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  142419. *
  142420. * @memberof QuadtreeTileProvider
  142421. *
  142422. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  142423. *
  142424. * @see QuadtreeTileProvider#destroy
  142425. */
  142426. QuadtreeTileProvider.prototype.isDestroyed = DeveloperError.throwInstantiationError;
  142427. /**
  142428. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  142429. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  142430. * <br /><br />
  142431. * Once an object is destroyed, it should not be used; calling any function other than
  142432. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  142433. * assign the return value (<code>undefined</code>) to the object as done in the example.
  142434. *
  142435. * @memberof QuadtreeTileProvider
  142436. *
  142437. * @returns {undefined}
  142438. *
  142439. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  142440. *
  142441. *
  142442. * @example
  142443. * provider = provider && provider();
  142444. *
  142445. * @see QuadtreeTileProvider#isDestroyed
  142446. */
  142447. QuadtreeTileProvider.prototype.destroy = DeveloperError.throwInstantiationError;
  142448. return QuadtreeTileProvider;
  142449. });
  142450. /*global define*/
  142451. define('Scene/SceneTransitioner',[
  142452. '../Core/Cartesian3',
  142453. '../Core/Cartographic',
  142454. '../Core/defined',
  142455. '../Core/destroyObject',
  142456. '../Core/DeveloperError',
  142457. '../Core/EasingFunction',
  142458. '../Core/Math',
  142459. '../Core/Matrix4',
  142460. '../Core/Ray',
  142461. '../Core/ScreenSpaceEventHandler',
  142462. '../Core/ScreenSpaceEventType',
  142463. '../Core/Transforms',
  142464. './Camera',
  142465. './OrthographicFrustum',
  142466. './PerspectiveFrustum',
  142467. './SceneMode'
  142468. ], function(
  142469. Cartesian3,
  142470. Cartographic,
  142471. defined,
  142472. destroyObject,
  142473. DeveloperError,
  142474. EasingFunction,
  142475. CesiumMath,
  142476. Matrix4,
  142477. Ray,
  142478. ScreenSpaceEventHandler,
  142479. ScreenSpaceEventType,
  142480. Transforms,
  142481. Camera,
  142482. OrthographicFrustum,
  142483. PerspectiveFrustum,
  142484. SceneMode) {
  142485. 'use strict';
  142486. /**
  142487. * @private
  142488. */
  142489. function SceneTransitioner(scene) {
  142490. if (!defined(scene)) {
  142491. throw new DeveloperError('scene is required.');
  142492. }
  142493. this._scene = scene;
  142494. this._currentTweens = [];
  142495. this._morphHandler = undefined;
  142496. this._morphCancelled = false;
  142497. this._completeMorph = undefined;
  142498. }
  142499. SceneTransitioner.prototype.completeMorph = function() {
  142500. if (defined(this._completeMorph)) {
  142501. this._completeMorph();
  142502. }
  142503. };
  142504. SceneTransitioner.prototype.morphTo2D = function(duration, ellipsoid) {
  142505. if (defined(this._completeMorph)) {
  142506. this._completeMorph();
  142507. }
  142508. var scene = this._scene;
  142509. this._previousMode = scene.mode;
  142510. if (this._previousMode === SceneMode.SCENE2D || this._previousMode === SceneMode.MORPHING) {
  142511. return;
  142512. }
  142513. this._scene.morphStart.raiseEvent(this, this._previousMode, SceneMode.SCENE2D, true);
  142514. scene._mode = SceneMode.MORPHING;
  142515. scene.camera._setTransform(Matrix4.IDENTITY);
  142516. if (this._previousMode === SceneMode.COLUMBUS_VIEW) {
  142517. morphFromColumbusViewTo2D(this, duration);
  142518. } else {
  142519. morphFrom3DTo2D(this, duration, ellipsoid);
  142520. }
  142521. if (duration === 0.0 && defined(this._completeMorph)) {
  142522. this._completeMorph();
  142523. }
  142524. };
  142525. var scratchToCVPosition = new Cartesian3();
  142526. var scratchToCVDirection = new Cartesian3();
  142527. var scratchToCVUp = new Cartesian3();
  142528. var scratchToCVPosition2D = new Cartesian3();
  142529. var scratchToCVDirection2D = new Cartesian3();
  142530. var scratchToCVUp2D = new Cartesian3();
  142531. var scratchToCVSurfacePosition = new Cartesian3();
  142532. var scratchToCVCartographic = new Cartographic();
  142533. var scratchToCVToENU = new Matrix4();
  142534. var scratchToCVFrustum = new PerspectiveFrustum();
  142535. var scratchToCVCamera = {
  142536. position : undefined,
  142537. direction : undefined,
  142538. up : undefined,
  142539. position2D : undefined,
  142540. direction2D : undefined,
  142541. up2D : undefined,
  142542. frustum : undefined
  142543. };
  142544. SceneTransitioner.prototype.morphToColumbusView = function(duration, ellipsoid) {
  142545. if (defined(this._completeMorph)) {
  142546. this._completeMorph();
  142547. }
  142548. var scene = this._scene;
  142549. this._previousMode = scene.mode;
  142550. if (this._previousMode === SceneMode.COLUMBUS_VIEW || this._previousMode === SceneMode.MORPHING) {
  142551. return;
  142552. }
  142553. this._scene.morphStart.raiseEvent(this, this._previousMode, SceneMode.COLUMBUS_VIEW, true);
  142554. scene.camera._setTransform(Matrix4.IDENTITY);
  142555. var position = scratchToCVPosition;
  142556. var direction = scratchToCVDirection;
  142557. var up = scratchToCVUp;
  142558. if (duration > 0.0) {
  142559. position.x = 0.0;
  142560. position.y = 0.0;
  142561. position.z = 5.0 * ellipsoid.maximumRadius;
  142562. Cartesian3.negate(Cartesian3.UNIT_Z, direction);
  142563. Cartesian3.clone(Cartesian3.UNIT_Y, up);
  142564. } else {
  142565. var camera = scene.camera;
  142566. if (this._previousMode === SceneMode.SCENE2D) {
  142567. Cartesian3.clone(camera.position, position);
  142568. position.z = camera.frustum.right - camera.frustum.left;
  142569. Cartesian3.negate(Cartesian3.UNIT_Z, direction);
  142570. Cartesian3.clone(Cartesian3.UNIT_Y, up);
  142571. } else {
  142572. Cartesian3.clone(camera.positionWC, position);
  142573. Cartesian3.clone(camera.directionWC, direction);
  142574. Cartesian3.clone(camera.upWC, up);
  142575. var surfacePoint = ellipsoid.scaleToGeodeticSurface(position, scratchToCVSurfacePosition);
  142576. var toENU = Transforms.eastNorthUpToFixedFrame(surfacePoint, ellipsoid, scratchToCVToENU);
  142577. Matrix4.inverseTransformation(toENU, toENU);
  142578. scene.mapProjection.project(ellipsoid.cartesianToCartographic(position, scratchToCVCartographic), position);
  142579. Matrix4.multiplyByPointAsVector(toENU, direction, direction);
  142580. Matrix4.multiplyByPointAsVector(toENU, up, up);
  142581. }
  142582. }
  142583. var frustum = scratchToCVFrustum;
  142584. frustum.aspectRatio = scene.drawingBufferWidth / scene.drawingBufferHeight;
  142585. frustum.fov = CesiumMath.toRadians(60.0);
  142586. var cameraCV = scratchToCVCamera;
  142587. cameraCV.position = position;
  142588. cameraCV.direction = direction;
  142589. cameraCV.up = up;
  142590. cameraCV.frustum = frustum;
  142591. var complete = completeColumbusViewCallback(cameraCV);
  142592. createMorphHandler(this, complete);
  142593. if (this._previousMode === SceneMode.SCENE2D) {
  142594. morphFrom2DToColumbusView(this, duration, cameraCV, complete);
  142595. } else {
  142596. cameraCV.position2D = Matrix4.multiplyByPoint(Camera.TRANSFORM_2D, position, scratchToCVPosition2D);
  142597. cameraCV.direction2D = Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D, direction, scratchToCVDirection2D);
  142598. cameraCV.up2D = Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D, up, scratchToCVUp2D);
  142599. scene._mode = SceneMode.MORPHING;
  142600. morphFrom3DToColumbusView(this, duration, cameraCV, complete);
  142601. }
  142602. if (duration === 0.0 && defined(this._completeMorph)) {
  142603. this._completeMorph();
  142604. }
  142605. };
  142606. SceneTransitioner.prototype.morphTo3D = function(duration, ellipsoid) {
  142607. if (defined(this._completeMorph)) {
  142608. this._completeMorph();
  142609. }
  142610. var scene = this._scene;
  142611. this._previousMode = scene.mode;
  142612. if (this._previousMode === SceneMode.SCENE3D || this._previousMode === SceneMode.MORPHING) {
  142613. return;
  142614. }
  142615. this._scene.morphStart.raiseEvent(this, this._previousMode, SceneMode.SCENE3D, true);
  142616. scene._mode = SceneMode.MORPHING;
  142617. scene.camera._setTransform(Matrix4.IDENTITY);
  142618. if (this._previousMode === SceneMode.SCENE2D) {
  142619. morphFrom2DTo3D(this, duration, ellipsoid);
  142620. } else {
  142621. var camera3D;
  142622. if (duration > 0.0) {
  142623. camera3D = scratchCVTo3DCamera;
  142624. Cartesian3.fromDegrees(0.0, 0.0, 5.0 * ellipsoid.maximumRadius, ellipsoid, camera3D.position);
  142625. Cartesian3.negate(camera3D.position, camera3D.direction);
  142626. Cartesian3.normalize(camera3D.direction, camera3D.direction);
  142627. Cartesian3.clone(Cartesian3.UNIT_Z, camera3D.up);
  142628. } else {
  142629. camera3D = getColumbusViewTo3DCamera(this, ellipsoid);
  142630. }
  142631. var complete = complete3DCallback(camera3D);
  142632. createMorphHandler(this, complete);
  142633. morphFromColumbusViewTo3D(this, duration, camera3D, complete);
  142634. }
  142635. if (duration === 0.0 && defined(this._completeMorph)) {
  142636. this._completeMorph();
  142637. }
  142638. };
  142639. /**
  142640. * Returns true if this object was destroyed; otherwise, false.
  142641. * <br /><br />
  142642. * If this object was destroyed, it should not be used; calling any function other than
  142643. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  142644. *
  142645. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  142646. */
  142647. SceneTransitioner.prototype.isDestroyed = function() {
  142648. return false;
  142649. };
  142650. /**
  142651. * Once an object is destroyed, it should not be used; calling any function other than
  142652. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  142653. * assign the return value (<code>undefined</code>) to the object as done in the example.
  142654. *
  142655. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  142656. *
  142657. * @example
  142658. * transitioner = transitioner && transitioner.destroy();
  142659. */
  142660. SceneTransitioner.prototype.destroy = function() {
  142661. destroyMorphHandler(this);
  142662. return destroyObject(this);
  142663. };
  142664. function createMorphHandler(transitioner, completeMorphFunction) {
  142665. if (transitioner._scene.completeMorphOnUserInput) {
  142666. transitioner._morphHandler = new ScreenSpaceEventHandler(transitioner._scene.canvas, false);
  142667. var completeMorph = function() {
  142668. transitioner._morphCancelled = true;
  142669. completeMorphFunction(transitioner);
  142670. };
  142671. transitioner._completeMorph = completeMorph;
  142672. transitioner._morphHandler.setInputAction(completeMorph, ScreenSpaceEventType.LEFT_DOWN);
  142673. transitioner._morphHandler.setInputAction(completeMorph, ScreenSpaceEventType.MIDDLE_DOWN);
  142674. transitioner._morphHandler.setInputAction(completeMorph, ScreenSpaceEventType.RIGHT_DOWN);
  142675. transitioner._morphHandler.setInputAction(completeMorph, ScreenSpaceEventType.WHEEL);
  142676. }
  142677. }
  142678. function destroyMorphHandler(transitioner) {
  142679. var tweens = transitioner._currentTweens;
  142680. for ( var i = 0; i < tweens.length; ++i) {
  142681. tweens[i].cancelTween();
  142682. }
  142683. transitioner._currentTweens.length = 0;
  142684. transitioner._morphHandler = transitioner._morphHandler && transitioner._morphHandler.destroy();
  142685. }
  142686. var scratchCVTo3DCartographic = new Cartographic();
  142687. var scratchCVTo3DSurfacePoint = new Cartesian3();
  142688. var scratchCVTo3DFromENU = new Matrix4();
  142689. var scratchCVTo3DCamera = {
  142690. position : new Cartesian3(),
  142691. direction : new Cartesian3(),
  142692. up : new Cartesian3(),
  142693. frustum : undefined
  142694. };
  142695. function getColumbusViewTo3DCamera(transitioner, ellipsoid) {
  142696. var scene = transitioner._scene;
  142697. var camera = scene.camera;
  142698. var camera3D = scratchCVTo3DCamera;
  142699. var position = camera3D.position;
  142700. var direction = camera3D.direction;
  142701. var up = camera3D.up;
  142702. var positionCarto = scene.mapProjection.unproject(camera.position, scratchCVTo3DCartographic);
  142703. ellipsoid.cartographicToCartesian(positionCarto, position);
  142704. var surfacePoint = ellipsoid.scaleToGeodeticSurface(position, scratchCVTo3DSurfacePoint);
  142705. var fromENU = Transforms.eastNorthUpToFixedFrame(surfacePoint, ellipsoid, scratchCVTo3DFromENU);
  142706. Matrix4.multiplyByPointAsVector(fromENU, camera.direction, direction);
  142707. Matrix4.multiplyByPointAsVector(fromENU, camera.up, up);
  142708. return camera3D;
  142709. }
  142710. var scratchCVTo3DStartPos = new Cartesian3();
  142711. var scratchCVTo3DStartDir = new Cartesian3();
  142712. var scratchCVTo3DStartUp = new Cartesian3();
  142713. var scratchCVTo3DEndPos = new Cartesian3();
  142714. var scratchCVTo3DEndDir = new Cartesian3();
  142715. var scratchCVTo3DEndUp = new Cartesian3();
  142716. function morphFromColumbusViewTo3D(transitioner, duration, endCamera, complete) {
  142717. duration *= 0.5;
  142718. var scene = transitioner._scene;
  142719. var camera = scene.camera;
  142720. var startPos = Cartesian3.clone(camera.position, scratchCVTo3DStartPos);
  142721. var startDir = Cartesian3.clone(camera.direction, scratchCVTo3DStartDir);
  142722. var startUp = Cartesian3.clone(camera.up, scratchCVTo3DStartUp);
  142723. var endPos = Matrix4.multiplyByPoint(Camera.TRANSFORM_2D_INVERSE, endCamera.position, scratchCVTo3DEndPos);
  142724. var endDir = Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D_INVERSE, endCamera.direction, scratchCVTo3DEndDir);
  142725. var endUp = Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D_INVERSE, endCamera.up, scratchCVTo3DEndUp);
  142726. function update(value) {
  142727. columbusViewMorph(startPos, endPos, value.time, camera.position);
  142728. columbusViewMorph(startDir, endDir, value.time, camera.direction);
  142729. columbusViewMorph(startUp, endUp, value.time, camera.up);
  142730. Cartesian3.cross(camera.direction, camera.up, camera.right);
  142731. Cartesian3.normalize(camera.right, camera.right);
  142732. }
  142733. var tween = scene.tweens.add({
  142734. duration : duration,
  142735. easingFunction : EasingFunction.QUARTIC_OUT,
  142736. startObject : {
  142737. time : 0.0
  142738. },
  142739. stopObject : {
  142740. time : 1.0
  142741. },
  142742. update : update,
  142743. complete : function() {
  142744. addMorphTimeAnimations(transitioner, scene, 0.0, 1.0, duration, complete);
  142745. }
  142746. });
  142747. transitioner._currentTweens.push(tween);
  142748. }
  142749. var scratch2DTo3DFrustum = new PerspectiveFrustum();
  142750. function morphFrom2DTo3D(transitioner, duration, ellipsoid) {
  142751. duration /= 3.0;
  142752. var scene = transitioner._scene;
  142753. var camera = scene.camera;
  142754. var frustum = scratch2DTo3DFrustum;
  142755. frustum.aspectRatio = scene.drawingBufferWidth / scene.drawingBufferHeight;
  142756. frustum.fov = CesiumMath.toRadians(60.0);
  142757. var camera3D;
  142758. if (duration > 0.0) {
  142759. camera3D = scratchCVTo3DCamera;
  142760. Cartesian3.fromDegrees(0.0, 0.0, 5.0 * ellipsoid.maximumRadius, ellipsoid, camera3D.position);
  142761. Cartesian3.negate(camera3D.position, camera3D.direction);
  142762. Cartesian3.normalize(camera3D.direction, camera3D.direction);
  142763. Cartesian3.clone(Cartesian3.UNIT_Z, camera3D.up);
  142764. } else {
  142765. camera.position.z = camera.frustum.right - camera.frustum.left;
  142766. camera3D = getColumbusViewTo3DCamera(transitioner, ellipsoid);
  142767. }
  142768. camera3D.frustum = frustum;
  142769. var complete = complete3DCallback(camera3D);
  142770. createMorphHandler(transitioner, complete);
  142771. var startPos = Cartesian3.clone(camera.position, scratch3DToCVStartPos);
  142772. var startDir = Cartesian3.clone(camera.direction, scratch3DToCVStartDir);
  142773. var startUp = Cartesian3.clone(camera.up, scratch3DToCVStartUp);
  142774. var endPos = Cartesian3.fromElements(0.0, 0.0, 5.0 * ellipsoid.maximumRadius, scratch3DToCVEndPos);
  142775. var endDir = Cartesian3.negate(Cartesian3.UNIT_Z, scratch3DToCVEndDir);
  142776. var endUp = Cartesian3.clone(Cartesian3.UNIT_Y, scratch3DToCVEndUp);
  142777. var startRight = camera.frustum.right;
  142778. var endRight = endPos.z * 0.5;
  142779. function update(value) {
  142780. columbusViewMorph(startPos, endPos, value.time, camera.position);
  142781. columbusViewMorph(startDir, endDir, value.time, camera.direction);
  142782. columbusViewMorph(startUp, endUp, value.time, camera.up);
  142783. Cartesian3.cross(camera.direction, camera.up, camera.right);
  142784. Cartesian3.normalize(camera.right, camera.right);
  142785. var frustum = camera.frustum;
  142786. frustum.right = CesiumMath.lerp(startRight, endRight, value.time);
  142787. frustum.left = -frustum.right;
  142788. frustum.top = frustum.right * (scene.drawingBufferHeight / scene.drawingBufferWidth);
  142789. frustum.bottom = -frustum.top;
  142790. camera.position.z = 2.0 * scene.mapProjection.ellipsoid.maximumRadius;
  142791. }
  142792. if (duration > 0.0) {
  142793. var tween = scene.tweens.add({
  142794. duration : duration,
  142795. easingFunction : EasingFunction.QUARTIC_OUT,
  142796. startObject : {
  142797. time : 0.0
  142798. },
  142799. stopObject : {
  142800. time : 1.0
  142801. },
  142802. update : update,
  142803. complete : function() {
  142804. scene._mode = SceneMode.MORPHING;
  142805. morphOrthographicToPerspective(transitioner, duration, camera3D, function() {
  142806. morphFromColumbusViewTo3D(transitioner, duration, camera3D, complete);
  142807. });
  142808. }
  142809. });
  142810. transitioner._currentTweens.push(tween);
  142811. } else {
  142812. morphOrthographicToPerspective(transitioner, duration, camera3D, function() {
  142813. morphFromColumbusViewTo3D(transitioner, duration, camera3D, complete);
  142814. });
  142815. }
  142816. }
  142817. function columbusViewMorph(startPosition, endPosition, time, result) {
  142818. // Just linear for now.
  142819. return Cartesian3.lerp(startPosition, endPosition, time, result);
  142820. }
  142821. function morphPerspectiveToOrthographic(transitioner, duration, endCamera, updateHeight, complete) {
  142822. var scene = transitioner._scene;
  142823. var camera = scene.camera;
  142824. var startFOV = camera.frustum.fov;
  142825. var endFOV = CesiumMath.RADIANS_PER_DEGREE * 0.5;
  142826. var d = endCamera.position.z * Math.tan(startFOV * 0.5);
  142827. camera.frustum.far = d / Math.tan(endFOV * 0.5) + 10000000.0;
  142828. function update(value) {
  142829. camera.frustum.fov = CesiumMath.lerp(startFOV, endFOV, value.time);
  142830. var height = d / Math.tan(camera.frustum.fov * 0.5);
  142831. updateHeight(camera, height);
  142832. }
  142833. var tween = scene.tweens.add({
  142834. duration : duration,
  142835. easingFunction : EasingFunction.QUARTIC_OUT,
  142836. startObject : {
  142837. time : 0.0
  142838. },
  142839. stopObject : {
  142840. time : 1.0
  142841. },
  142842. update : update,
  142843. complete : function() {
  142844. camera.frustum = endCamera.frustum.clone();
  142845. complete(transitioner);
  142846. }
  142847. });
  142848. transitioner._currentTweens.push(tween);
  142849. }
  142850. var scratchCVTo2DStartPos = new Cartesian3();
  142851. var scratchCVTo2DStartDir = new Cartesian3();
  142852. var scratchCVTo2DStartUp = new Cartesian3();
  142853. var scratchCVTo2DEndPos = new Cartesian3();
  142854. var scratchCVTo2DEndDir = new Cartesian3();
  142855. var scratchCVTo2DEndUp = new Cartesian3();
  142856. var scratchCVTo2DFrustum = new OrthographicFrustum();
  142857. var scratchCVTo2DRay = new Ray();
  142858. var scratchCVTo2DPickPos = new Cartesian3();
  142859. var scratchCVTo2DCamera = {
  142860. position : undefined,
  142861. direction : undefined,
  142862. up : undefined,
  142863. frustum : undefined
  142864. };
  142865. function morphFromColumbusViewTo2D(transitioner, duration) {
  142866. duration *= 0.5;
  142867. var scene = transitioner._scene;
  142868. var camera = scene.camera;
  142869. var startPos = Cartesian3.clone(camera.position, scratchCVTo2DStartPos);
  142870. var startDir = Cartesian3.clone(camera.direction, scratchCVTo2DStartDir);
  142871. var startUp = Cartesian3.clone(camera.up, scratchCVTo2DStartUp);
  142872. var endDir = Cartesian3.negate(Cartesian3.UNIT_Z, scratchCVTo2DEndDir);
  142873. var endUp = Cartesian3.clone(Cartesian3.UNIT_Y, scratchCVTo2DEndUp);
  142874. var endPos = scratchCVTo2DEndPos;
  142875. if (duration > 0.0) {
  142876. Cartesian3.clone(Cartesian3.ZERO, scratchCVTo2DEndPos);
  142877. endPos.z = 5.0 * scene.mapProjection.ellipsoid.maximumRadius;
  142878. } else {
  142879. Cartesian3.clone(startPos, scratchCVTo2DEndPos);
  142880. var ray = scratchCVTo2DRay;
  142881. Matrix4.multiplyByPoint(Camera.TRANSFORM_2D, startPos, ray.origin);
  142882. Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D, startDir, ray.direction);
  142883. var globe = scene.globe;
  142884. if (defined(globe)) {
  142885. var pickPos = globe.pick(ray, scene, scratchCVTo2DPickPos);
  142886. if (defined(pickPos)) {
  142887. Matrix4.multiplyByPoint(Camera.TRANSFORM_2D_INVERSE, pickPos, endPos);
  142888. endPos.z += Cartesian3.distance(startPos, endPos);
  142889. }
  142890. }
  142891. }
  142892. var frustum = scratchCVTo2DFrustum;
  142893. frustum.right = endPos.z * 0.5;
  142894. frustum.left = -frustum.right;
  142895. frustum.top = frustum.right * (scene.drawingBufferHeight / scene.drawingBufferWidth);
  142896. frustum.bottom = -frustum.top;
  142897. var camera2D = scratchCVTo2DCamera;
  142898. camera2D.position = endPos;
  142899. camera2D.direction = endDir;
  142900. camera2D.up = endUp;
  142901. camera2D.frustum = frustum;
  142902. var complete = complete2DCallback(camera2D);
  142903. createMorphHandler(transitioner, complete);
  142904. function updateCV(value) {
  142905. columbusViewMorph(startPos, endPos, value.time, camera.position);
  142906. columbusViewMorph(startDir, endDir, value.time, camera.direction);
  142907. columbusViewMorph(startUp, endUp, value.time, camera.up);
  142908. Cartesian3.cross(camera.direction, camera.up, camera.right);
  142909. Cartesian3.normalize(camera.right, camera.right);
  142910. }
  142911. function updateHeight(camera, height) {
  142912. camera.position.z = height;
  142913. }
  142914. var tween = scene.tweens.add({
  142915. duration : duration,
  142916. easingFunction : EasingFunction.QUARTIC_OUT,
  142917. startObject : {
  142918. time : 0.0
  142919. },
  142920. stopObject : {
  142921. time : 1.0
  142922. },
  142923. update : updateCV,
  142924. complete : function() {
  142925. morphPerspectiveToOrthographic(transitioner, duration, camera2D, updateHeight, complete);
  142926. }
  142927. });
  142928. transitioner._currentTweens.push(tween);
  142929. }
  142930. var scratch3DTo2DCartographic = new Cartographic();
  142931. var scratch3DTo2DCamera = {
  142932. position : new Cartesian3(),
  142933. direction : new Cartesian3(),
  142934. up : new Cartesian3(),
  142935. position2D : new Cartesian3(),
  142936. direction2D : new Cartesian3(),
  142937. up2D : new Cartesian3(),
  142938. frustum : new OrthographicFrustum()
  142939. };
  142940. var scratch3DTo2DEndCamera = {
  142941. position : new Cartesian3(),
  142942. direction : new Cartesian3(),
  142943. up : new Cartesian3(),
  142944. frustum : undefined
  142945. };
  142946. var scratch3DTo2DPickPosition = new Cartesian3();
  142947. var scratch3DTo2DRay = new Ray();
  142948. var scratch3DTo2DToENU = new Matrix4();
  142949. var scratch3DTo2DSurfacePoint = new Cartesian3();
  142950. function morphFrom3DTo2D(transitioner, duration, ellipsoid) {
  142951. duration *= 0.5;
  142952. var scene = transitioner._scene;
  142953. var camera = scene.camera;
  142954. var camera2D = scratch3DTo2DCamera;
  142955. if (duration > 0.0) {
  142956. Cartesian3.clone(Cartesian3.ZERO, camera2D.position);
  142957. camera2D.position.z = 5.0 * ellipsoid.maximumRadius;
  142958. Cartesian3.negate(Cartesian3.UNIT_Z, camera2D.direction);
  142959. Cartesian3.clone(Cartesian3.UNIT_Y, camera2D.up);
  142960. } else {
  142961. ellipsoid.cartesianToCartographic(camera.positionWC, scratch3DTo2DCartographic);
  142962. scene.mapProjection.project(scratch3DTo2DCartographic, camera2D.position);
  142963. Cartesian3.negate(Cartesian3.UNIT_Z, camera2D.direction);
  142964. Cartesian3.clone(Cartesian3.UNIT_Y, camera2D.up);
  142965. var ray = scratch3DTo2DRay;
  142966. Cartesian3.clone(camera2D.position2D, ray.origin);
  142967. var rayDirection = Cartesian3.clone(camera.directionWC, ray.direction);
  142968. var surfacePoint = ellipsoid.scaleToGeodeticSurface(camera.positionWC, scratch3DTo2DSurfacePoint);
  142969. var toENU = Transforms.eastNorthUpToFixedFrame(surfacePoint, ellipsoid, scratch3DTo2DToENU);
  142970. Matrix4.inverseTransformation(toENU, toENU);
  142971. Matrix4.multiplyByPointAsVector(toENU, rayDirection, rayDirection);
  142972. Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D, rayDirection, rayDirection);
  142973. var globe = scene.globe;
  142974. if (defined(globe)) {
  142975. var pickedPos = globe.pick(ray, scene, scratch3DTo2DPickPosition);
  142976. if (defined(pickedPos)) {
  142977. var height = Cartesian3.distance(camera2D.position2D, pickedPos);
  142978. pickedPos.x += height;
  142979. Cartesian3.clone(pickedPos, camera2D.position2D);
  142980. }
  142981. }
  142982. }
  142983. function updateHeight(camera, height) {
  142984. camera.position.x = height;
  142985. }
  142986. Matrix4.multiplyByPoint(Camera.TRANSFORM_2D, camera2D.position, camera2D.position2D);
  142987. Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D, camera2D.direction, camera2D.direction2D);
  142988. Matrix4.multiplyByPointAsVector(Camera.TRANSFORM_2D, camera2D.up, camera2D.up2D);
  142989. var frustum = camera2D.frustum;
  142990. frustum.right = camera2D.position.z * 0.5;
  142991. frustum.left = -frustum.right;
  142992. frustum.top = frustum.right * (scene.drawingBufferHeight / scene.drawingBufferWidth);
  142993. frustum.bottom = -frustum.top;
  142994. var endCamera = scratch3DTo2DEndCamera;
  142995. Matrix4.multiplyByPoint(Camera.TRANSFORM_2D_INVERSE, camera2D.position2D, endCamera.position);
  142996. Cartesian3.clone(camera2D.direction, endCamera.direction);
  142997. Cartesian3.clone(camera2D.up, endCamera.up);
  142998. endCamera.frustum = frustum;
  142999. var complete = complete2DCallback(endCamera);
  143000. createMorphHandler(transitioner, complete);
  143001. function completeCallback() {
  143002. morphPerspectiveToOrthographic(transitioner, duration, camera2D, updateHeight, complete);
  143003. }
  143004. morphFrom3DToColumbusView(transitioner, duration, camera2D, completeCallback);
  143005. }
  143006. function morphOrthographicToPerspective(transitioner, duration, cameraCV, complete) {
  143007. var scene = transitioner._scene;
  143008. var camera = scene.camera;
  143009. var height = camera.frustum.right - camera.frustum.left;
  143010. camera.frustum = cameraCV.frustum.clone();
  143011. var endFOV = camera.frustum.fov;
  143012. var startFOV = CesiumMath.RADIANS_PER_DEGREE * 0.5;
  143013. var d = height * Math.tan(endFOV * 0.5);
  143014. camera.frustum.far = d / Math.tan(startFOV * 0.5) + 10000000.0;
  143015. camera.frustum.fov = startFOV;
  143016. function update(value) {
  143017. camera.frustum.fov = CesiumMath.lerp(startFOV, endFOV, value.time);
  143018. camera.position.z = d / Math.tan(camera.frustum.fov * 0.5);
  143019. }
  143020. var tween = scene.tweens.add({
  143021. duration : duration,
  143022. easingFunction : EasingFunction.QUARTIC_OUT,
  143023. startObject : {
  143024. time : 0.0
  143025. },
  143026. stopObject : {
  143027. time : 1.0
  143028. },
  143029. update : update,
  143030. complete : function() {
  143031. complete(transitioner);
  143032. }
  143033. });
  143034. transitioner._currentTweens.push(tween);
  143035. }
  143036. function morphFrom2DToColumbusView(transitioner, duration, cameraCV, complete) {
  143037. duration *= 0.5;
  143038. var scene = transitioner._scene;
  143039. var camera = scene.camera;
  143040. var startPos = Cartesian3.clone(camera.position, scratch3DToCVStartPos);
  143041. var startDir = Cartesian3.clone(camera.direction, scratch3DToCVStartDir);
  143042. var startUp = Cartesian3.clone(camera.up, scratch3DToCVStartUp);
  143043. var endPos = Cartesian3.clone(cameraCV.position, scratch3DToCVEndPos);
  143044. var endDir = Cartesian3.clone(cameraCV.direction, scratch3DToCVEndDir);
  143045. var endUp = Cartesian3.clone(cameraCV.up, scratch3DToCVEndUp);
  143046. var startRight = camera.frustum.right;
  143047. var endRight = endPos.z * 0.5;
  143048. function update(value) {
  143049. columbusViewMorph(startPos, endPos, value.time, camera.position);
  143050. columbusViewMorph(startDir, endDir, value.time, camera.direction);
  143051. columbusViewMorph(startUp, endUp, value.time, camera.up);
  143052. Cartesian3.cross(camera.direction, camera.up, camera.right);
  143053. Cartesian3.normalize(camera.right, camera.right);
  143054. var frustum = camera.frustum;
  143055. frustum.right = CesiumMath.lerp(startRight, endRight, value.time);
  143056. frustum.left = -frustum.right;
  143057. frustum.top = frustum.right * (scene.drawingBufferHeight / scene.drawingBufferWidth);
  143058. frustum.bottom = -frustum.top;
  143059. camera.position.z = 2.0 * scene.mapProjection.ellipsoid.maximumRadius;
  143060. }
  143061. var tween = scene.tweens.add({
  143062. duration : duration,
  143063. easingFunction : EasingFunction.QUARTIC_OUT,
  143064. startObject : {
  143065. time : 0.0
  143066. },
  143067. stopObject : {
  143068. time : 1.0
  143069. },
  143070. update : update,
  143071. complete : function() {
  143072. scene._mode = SceneMode.MORPHING;
  143073. morphOrthographicToPerspective(transitioner, duration, cameraCV, complete);
  143074. }
  143075. });
  143076. transitioner._currentTweens.push(tween);
  143077. }
  143078. var scratch3DToCVStartPos = new Cartesian3();
  143079. var scratch3DToCVStartDir = new Cartesian3();
  143080. var scratch3DToCVStartUp = new Cartesian3();
  143081. var scratch3DToCVEndPos = new Cartesian3();
  143082. var scratch3DToCVEndDir = new Cartesian3();
  143083. var scratch3DToCVEndUp = new Cartesian3();
  143084. function morphFrom3DToColumbusView(transitioner, duration, endCamera, complete) {
  143085. var scene = transitioner._scene;
  143086. var camera = scene.camera;
  143087. var startPos = Cartesian3.clone(camera.position, scratch3DToCVStartPos);
  143088. var startDir = Cartesian3.clone(camera.direction, scratch3DToCVStartDir);
  143089. var startUp = Cartesian3.clone(camera.up, scratch3DToCVStartUp);
  143090. var endPos = Cartesian3.clone(endCamera.position2D, scratch3DToCVEndPos);
  143091. var endDir = Cartesian3.clone(endCamera.direction2D, scratch3DToCVEndDir);
  143092. var endUp = Cartesian3.clone(endCamera.up2D, scratch3DToCVEndUp);
  143093. function update(value) {
  143094. columbusViewMorph(startPos, endPos, value.time, camera.position);
  143095. columbusViewMorph(startDir, endDir, value.time, camera.direction);
  143096. columbusViewMorph(startUp, endUp, value.time, camera.up);
  143097. Cartesian3.cross(camera.direction, camera.up, camera.right);
  143098. Cartesian3.normalize(camera.right, camera.right);
  143099. }
  143100. var tween = scene.tweens.add({
  143101. duration : duration,
  143102. easingFunction : EasingFunction.QUARTIC_OUT,
  143103. startObject : {
  143104. time : 0.0
  143105. },
  143106. stopObject : {
  143107. time : 1.0
  143108. },
  143109. update : update,
  143110. complete : function() {
  143111. addMorphTimeAnimations(transitioner, scene, 1.0, 0.0, duration, complete);
  143112. }
  143113. });
  143114. transitioner._currentTweens.push(tween);
  143115. }
  143116. function addMorphTimeAnimations(transitioner, scene, start, stop, duration, complete) {
  143117. // Later, this will be linear and each object will adjust, if desired, in its vertex shader.
  143118. var options = {
  143119. object : scene,
  143120. property : 'morphTime',
  143121. startValue : start,
  143122. stopValue : stop,
  143123. duration : duration,
  143124. easingFunction : EasingFunction.QUARTIC_OUT
  143125. };
  143126. if (defined(complete)) {
  143127. options.complete = function() {
  143128. complete(transitioner);
  143129. };
  143130. }
  143131. var tween = scene.tweens.addProperty(options);
  143132. transitioner._currentTweens.push(tween);
  143133. }
  143134. function complete3DCallback(camera3D) {
  143135. return function(transitioner) {
  143136. var scene = transitioner._scene;
  143137. scene._mode = SceneMode.SCENE3D;
  143138. scene.morphTime = SceneMode.getMorphTime(SceneMode.SCENE3D);
  143139. destroyMorphHandler(transitioner);
  143140. if (transitioner._previousMode !== SceneMode.MORPHING || transitioner._morphCancelled) {
  143141. transitioner._morphCancelled = false;
  143142. var camera = scene.camera;
  143143. Cartesian3.clone(camera3D.position, camera.position);
  143144. Cartesian3.clone(camera3D.direction, camera.direction);
  143145. Cartesian3.clone(camera3D.up, camera.up);
  143146. Cartesian3.cross(camera.direction, camera.up, camera.right);
  143147. Cartesian3.normalize(camera.right, camera.right);
  143148. if (defined(camera3D.frustum)) {
  143149. camera.frustum = camera3D.frustum.clone();
  143150. }
  143151. }
  143152. var wasMorphing = defined(transitioner._completeMorph);
  143153. transitioner._completeMorph = undefined;
  143154. scene.camera.update(scene.mode);
  143155. transitioner._scene.morphComplete.raiseEvent(transitioner, transitioner._previousMode, SceneMode.SCENE3D, wasMorphing);
  143156. };
  143157. }
  143158. function complete2DCallback(camera2D) {
  143159. return function(transitioner) {
  143160. var scene = transitioner._scene;
  143161. scene._mode = SceneMode.SCENE2D;
  143162. scene.morphTime = SceneMode.getMorphTime(SceneMode.SCENE2D);
  143163. destroyMorphHandler(transitioner);
  143164. var camera = scene.camera;
  143165. Cartesian3.clone(camera2D.position, camera.position);
  143166. camera.position.z = scene.mapProjection.ellipsoid.maximumRadius * 2.0;
  143167. Cartesian3.clone(camera2D.direction, camera.direction);
  143168. Cartesian3.clone(camera2D.up, camera.up);
  143169. Cartesian3.cross(camera.direction, camera.up, camera.right);
  143170. Cartesian3.normalize(camera.right, camera.right);
  143171. camera.frustum = camera2D.frustum.clone();
  143172. var wasMorphing = defined(transitioner._completeMorph);
  143173. transitioner._completeMorph = undefined;
  143174. scene.camera.update(scene.mode);
  143175. transitioner._scene.morphComplete.raiseEvent(transitioner, transitioner._previousMode, SceneMode.SCENE2D, wasMorphing);
  143176. };
  143177. }
  143178. function completeColumbusViewCallback(cameraCV) {
  143179. return function(transitioner) {
  143180. var scene = transitioner._scene;
  143181. scene._mode = SceneMode.COLUMBUS_VIEW;
  143182. scene.morphTime = SceneMode.getMorphTime(SceneMode.COLUMBUS_VIEW);
  143183. destroyMorphHandler(transitioner);
  143184. scene.camera.frustum = cameraCV.frustum.clone();
  143185. if (transitioner._previousModeMode !== SceneMode.MORPHING || transitioner._morphCancelled) {
  143186. transitioner._morphCancelled = false;
  143187. var camera = scene.camera;
  143188. Cartesian3.clone(cameraCV.position, camera.position);
  143189. Cartesian3.clone(cameraCV.direction, camera.direction);
  143190. Cartesian3.clone(cameraCV.up, camera.up);
  143191. Cartesian3.cross(camera.direction, camera.up, camera.right);
  143192. Cartesian3.normalize(camera.right, camera.right);
  143193. }
  143194. var wasMorphing = defined(transitioner._completeMorph);
  143195. transitioner._completeMorph = undefined;
  143196. scene.camera.update(scene.mode);
  143197. transitioner._scene.morphComplete.raiseEvent(transitioner, transitioner._previousMode, SceneMode.COLUMBUS_VIEW, wasMorphing);
  143198. };
  143199. }
  143200. return SceneTransitioner;
  143201. });
  143202. /*global define*/
  143203. define('Scene/TweenCollection',[
  143204. '../Core/clone',
  143205. '../Core/defaultValue',
  143206. '../Core/defined',
  143207. '../Core/defineProperties',
  143208. '../Core/DeveloperError',
  143209. '../Core/EasingFunction',
  143210. '../Core/getTimestamp',
  143211. '../Core/TimeConstants',
  143212. '../ThirdParty/Tween'
  143213. ], function(
  143214. clone,
  143215. defaultValue,
  143216. defined,
  143217. defineProperties,
  143218. DeveloperError,
  143219. EasingFunction,
  143220. getTimestamp,
  143221. TimeConstants,
  143222. TweenJS) {
  143223. 'use strict';
  143224. /**
  143225. * A tween is an animation that interpolates the properties of two objects using an {@link EasingFunction}. Create
  143226. * one using {@link Scene#tweens} and {@link TweenCollection#add} and related add functions.
  143227. *
  143228. * @alias Tween
  143229. * @constructor
  143230. *
  143231. * @private
  143232. */
  143233. function Tween(tweens, tweenjs, startObject, stopObject, duration, delay, easingFunction, update, complete, cancel) {
  143234. this._tweens = tweens;
  143235. this._tweenjs = tweenjs;
  143236. this._startObject = clone(startObject);
  143237. this._stopObject = clone(stopObject);
  143238. this._duration = duration;
  143239. this._delay = delay;
  143240. this._easingFunction = easingFunction;
  143241. this._update = update;
  143242. this._complete = complete;
  143243. /**
  143244. * The callback to call if the tween is canceled either because {@link Tween#cancelTween}
  143245. * was called or because the tween was removed from the collection.
  143246. *
  143247. * @type {TweenCollection~TweenCancelledCallback}
  143248. */
  143249. this.cancel = cancel;
  143250. /**
  143251. * @private
  143252. */
  143253. this.needsStart = true;
  143254. }
  143255. defineProperties(Tween.prototype, {
  143256. /**
  143257. * An object with properties for initial values of the tween. The properties of this object are changed during the tween's animation.
  143258. * @memberof Tween.prototype
  143259. *
  143260. * @type {Object}
  143261. * @readonly
  143262. */
  143263. startObject : {
  143264. get : function() {
  143265. return this._startObject;
  143266. }
  143267. },
  143268. /**
  143269. * An object with properties for the final values of the tween.
  143270. * @memberof Tween.prototype
  143271. *
  143272. * @type {Object}
  143273. * @readonly
  143274. */
  143275. stopObject : {
  143276. get : function() {
  143277. return this._stopObject;
  143278. }
  143279. },
  143280. /**
  143281. * The duration, in seconds, for the tween. The tween is automatically removed from the collection when it stops.
  143282. * @memberof Tween.prototype
  143283. *
  143284. * @type {Number}
  143285. * @readonly
  143286. */
  143287. duration : {
  143288. get : function() {
  143289. return this._duration;
  143290. }
  143291. },
  143292. /**
  143293. * The delay, in seconds, before the tween starts animating.
  143294. * @memberof Tween.prototype
  143295. *
  143296. * @type {Number}
  143297. * @readonly
  143298. */
  143299. delay : {
  143300. get : function() {
  143301. return this._delay;
  143302. }
  143303. },
  143304. /**
  143305. * Determines the curve for animtion.
  143306. * @memberof Tween.prototype
  143307. *
  143308. * @type {EasingFunction}
  143309. * @readonly
  143310. */
  143311. easingFunction : {
  143312. get : function() {
  143313. return this._easingFunction;
  143314. }
  143315. },
  143316. /**
  143317. * The callback to call at each animation update (usually tied to the a rendered frame).
  143318. * @memberof Tween.prototype
  143319. *
  143320. * @type {TweenCollection~TweenUpdateCallback}
  143321. * @readonly
  143322. */
  143323. update : {
  143324. get : function() {
  143325. return this._update;
  143326. }
  143327. },
  143328. /**
  143329. * The callback to call when the tween finishes animating.
  143330. * @memberof Tween.prototype
  143331. *
  143332. * @type {TweenCollection~TweenCompleteCallback}
  143333. * @readonly
  143334. */
  143335. complete : {
  143336. get : function() {
  143337. return this._complete;
  143338. }
  143339. },
  143340. /**
  143341. * @memberof Tween.prototype
  143342. *
  143343. * @private
  143344. */
  143345. tweenjs : {
  143346. get : function() {
  143347. return this._tweenjs;
  143348. }
  143349. }
  143350. });
  143351. /**
  143352. * Cancels the tween calling the {@link Tween#cancel} callback if one exists. This
  143353. * has no effect if the tween finished or was already canceled.
  143354. */
  143355. Tween.prototype.cancelTween = function() {
  143356. this._tweens.remove(this);
  143357. };
  143358. /**
  143359. * A collection of tweens for animating properties. Commonly accessed using {@link Scene#tweens}.
  143360. *
  143361. * @alias TweenCollection
  143362. * @constructor
  143363. *
  143364. * @private
  143365. */
  143366. function TweenCollection() {
  143367. this._tweens = [];
  143368. }
  143369. defineProperties(TweenCollection.prototype, {
  143370. /**
  143371. * The number of tweens in the collection.
  143372. * @memberof TweenCollection.prototype
  143373. *
  143374. * @type {Number}
  143375. * @readonly
  143376. */
  143377. length : {
  143378. get : function() {
  143379. return this._tweens.length;
  143380. }
  143381. }
  143382. });
  143383. /**
  143384. * Creates a tween for animating between two sets of properties. The tween starts animating at the next call to {@link TweenCollection#update}, which
  143385. * is implicit when {@link Viewer} or {@link CesiumWidget} render the scene.
  143386. *
  143387. * @param {Object} [options] Object with the following properties:
  143388. * @param {Object} options.startObject An object with properties for initial values of the tween. The properties of this object are changed during the tween's animation.
  143389. * @param {Object} options.stopObject An object with properties for the final values of the tween.
  143390. * @param {Number} options.duration The duration, in seconds, for the tween. The tween is automatically removed from the collection when it stops.
  143391. * @param {Number} [options.delay=0.0] The delay, in seconds, before the tween starts animating.
  143392. * @param {EasingFunction} [options.easingFunction=EasingFunction.LINEAR_NONE] Determines the curve for animtion.
  143393. * @param {TweenCollection~TweenUpdateCallback} [options.update] The callback to call at each animation update (usually tied to the a rendered frame).
  143394. * @param {TweenCollection~TweenCompleteCallback} [options.complete] The callback to call when the tween finishes animating.
  143395. * @param {TweenCollection~TweenCancelledCallback} [options.cancel] The callback to call if the tween is canceled either because {@link Tween#cancelTween} was called or because the tween was removed from the collection.
  143396. * @returns {Tween} The tween.
  143397. *
  143398. * @exception {DeveloperError} options.duration must be positive.
  143399. */
  143400. TweenCollection.prototype.add = function(options) {
  143401. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  143402. if (!defined(options.startObject) || !defined(options.stopObject)) {
  143403. throw new DeveloperError('options.startObject and options.stopObject are required.');
  143404. }
  143405. if (!defined(options.duration) || options.duration < 0.0) {
  143406. throw new DeveloperError('options.duration is required and must be positive.');
  143407. }
  143408. if (options.duration === 0.0) {
  143409. if (defined(options.complete)) {
  143410. options.complete();
  143411. }
  143412. return new Tween(this);
  143413. }
  143414. var duration = options.duration / TimeConstants.SECONDS_PER_MILLISECOND;
  143415. var delayInSeconds = defaultValue(options.delay, 0.0);
  143416. var delay = delayInSeconds / TimeConstants.SECONDS_PER_MILLISECOND;
  143417. var easingFunction = defaultValue(options.easingFunction, EasingFunction.LINEAR_NONE);
  143418. var value = options.startObject;
  143419. var tweenjs = new TweenJS.Tween(value);
  143420. tweenjs.to(clone(options.stopObject), duration);
  143421. tweenjs.delay(delay);
  143422. tweenjs.easing(easingFunction);
  143423. if (defined(options.update)) {
  143424. tweenjs.onUpdate(function() {
  143425. options.update(value);
  143426. });
  143427. }
  143428. tweenjs.onComplete(defaultValue(options.complete, null));
  143429. tweenjs.repeat(defaultValue(options._repeat, 0.0));
  143430. var tween = new Tween(this, tweenjs, options.startObject, options.stopObject, options.duration, delayInSeconds, easingFunction, options.update, options.complete, options.cancel);
  143431. this._tweens.push(tween);
  143432. return tween;
  143433. };
  143434. /**
  143435. * Creates a tween for animating a scalar property on the given object. The tween starts animating at the next call to {@link TweenCollection#update}, which
  143436. * is implicit when {@link Viewer} or {@link CesiumWidget} render the scene.
  143437. *
  143438. * @param {Object} [options] Object with the following properties:
  143439. * @param {Object} options.object The object containing the property to animate.
  143440. * @param {String} options.property The name of the property to animate.
  143441. * @param {Number} options.startValue The initial value.
  143442. * @param {Number} options.stopValue The final value.
  143443. * @param {Number} [options.duration=3.0] The duration, in seconds, for the tween. The tween is automatically removed from the collection when it stops.
  143444. * @param {Number} [options.delay=0.0] The delay, in seconds, before the tween starts animating.
  143445. * @param {EasingFunction} [options.easingFunction=EasingFunction.LINEAR_NONE] Determines the curve for animtion.
  143446. * @param {TweenCollection~TweenUpdateCallback} [options.update] The callback to call at each animation update (usually tied to the a rendered frame).
  143447. * @param {TweenCollection~TweenCompleteCallback} [options.complete] The callback to call when the tween finishes animating.
  143448. * @param {TweenCollection~TweenCancelledCallback} [options.cancel] The callback to call if the tween is canceled either because {@link Tween#cancelTween} was called or because the tween was removed from the collection.
  143449. * @returns {Tween} The tween.
  143450. *
  143451. * @exception {DeveloperError} options.object must have the specified property.
  143452. * @exception {DeveloperError} options.duration must be positive.
  143453. */
  143454. TweenCollection.prototype.addProperty = function(options) {
  143455. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  143456. var object = options.object;
  143457. var property = options.property;
  143458. var startValue = options.startValue;
  143459. var stopValue = options.stopValue;
  143460. if (!defined(object) || !defined(options.property)) {
  143461. throw new DeveloperError('options.object and options.property are required.');
  143462. }
  143463. if (!defined(object[property])) {
  143464. throw new DeveloperError('options.object must have the specified property.');
  143465. }
  143466. if (!defined(startValue) || !defined(stopValue)) {
  143467. throw new DeveloperError('options.startValue and options.stopValue are required.');
  143468. }
  143469. function update(value) {
  143470. object[property] = value.value;
  143471. }
  143472. return this.add({
  143473. startObject : {
  143474. value : startValue
  143475. },
  143476. stopObject : {
  143477. value : stopValue
  143478. },
  143479. duration : defaultValue(options.duration, 3.0),
  143480. delay : options.delay,
  143481. easingFunction : options.easingFunction,
  143482. update : update,
  143483. complete : options.complete,
  143484. cancel : options.cancel,
  143485. _repeat : options._repeat
  143486. });
  143487. };
  143488. /**
  143489. * Creates a tween for animating the alpha of all color uniforms on a {@link Material}. The tween starts animating at the next call to {@link TweenCollection#update}, which
  143490. * is implicit when {@link Viewer} or {@link CesiumWidget} render the scene.
  143491. *
  143492. * @param {Object} [options] Object with the following properties:
  143493. * @param {Material} options.material The material to animate.
  143494. * @param {Number} [options.startValue=0.0] The initial alpha value.
  143495. * @param {Number} [options.stopValue=1.0] The final alpha value.
  143496. * @param {Number} [options.duration=3.0] The duration, in seconds, for the tween. The tween is automatically removed from the collection when it stops.
  143497. * @param {Number} [options.delay=0.0] The delay, in seconds, before the tween starts animating.
  143498. * @param {EasingFunction} [options.easingFunction=EasingFunction.LINEAR_NONE] Determines the curve for animtion.
  143499. * @param {TweenCollection~TweenUpdateCallback} [options.update] The callback to call at each animation update (usually tied to the a rendered frame).
  143500. * @param {TweenCollection~TweenCompleteCallback} [options.complete] The callback to call when the tween finishes animating.
  143501. * @param {TweenCollection~TweenCancelledCallback} [options.cancel] The callback to call if the tween is canceled either because {@link Tween#cancelTween} was called or because the tween was removed from the collection.
  143502. * @returns {Tween} The tween.
  143503. *
  143504. * @exception {DeveloperError} material has no properties with alpha components.
  143505. * @exception {DeveloperError} options.duration must be positive.
  143506. */
  143507. TweenCollection.prototype.addAlpha = function(options) {
  143508. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  143509. var material = options.material;
  143510. if (!defined(material)) {
  143511. throw new DeveloperError('options.material is required.');
  143512. }
  143513. var properties = [];
  143514. for (var property in material.uniforms) {
  143515. if (material.uniforms.hasOwnProperty(property) &&
  143516. defined(material.uniforms[property]) &&
  143517. defined(material.uniforms[property].alpha)) {
  143518. properties.push(property);
  143519. }
  143520. }
  143521. if (properties.length === 0) {
  143522. throw new DeveloperError('material has no properties with alpha components.');
  143523. }
  143524. function update(value) {
  143525. var length = properties.length;
  143526. for (var i = 0; i < length; ++i) {
  143527. material.uniforms[properties[i]].alpha = value.alpha;
  143528. }
  143529. }
  143530. return this.add({
  143531. startObject : {
  143532. alpha : defaultValue(options.startValue, 0.0) // Default to fade in
  143533. },
  143534. stopObject : {
  143535. alpha : defaultValue(options.stopValue, 1.0)
  143536. },
  143537. duration : defaultValue(options.duration, 3.0),
  143538. delay : options.delay,
  143539. easingFunction : options.easingFunction,
  143540. update : update,
  143541. complete : options.complete,
  143542. cancel : options.cancel
  143543. });
  143544. };
  143545. /**
  143546. * Creates a tween for animating the offset uniform of a {@link Material}. The tween starts animating at the next call to {@link TweenCollection#update}, which
  143547. * is implicit when {@link Viewer} or {@link CesiumWidget} render the scene.
  143548. *
  143549. * @param {Object} [options] Object with the following properties:
  143550. * @param {Material} options.material The material to animate.
  143551. * @param {Number} options.startValue The initial alpha value.
  143552. * @param {Number} options.stopValue The final alpha value.
  143553. * @param {Number} [options.duration=3.0] The duration, in seconds, for the tween. The tween is automatically removed from the collection when it stops.
  143554. * @param {Number} [options.delay=0.0] The delay, in seconds, before the tween starts animating.
  143555. * @param {EasingFunction} [options.easingFunction=EasingFunction.LINEAR_NONE] Determines the curve for animtion.
  143556. * @param {TweenCollection~TweenUpdateCallback} [options.update] The callback to call at each animation update (usually tied to the a rendered frame).
  143557. * @param {TweenCollection~TweenCancelledCallback} [options.cancel] The callback to call if the tween is canceled either because {@link Tween#cancelTween} was called or because the tween was removed from the collection.
  143558. * @returns {Tween} The tween.
  143559. *
  143560. * @exception {DeveloperError} material.uniforms must have an offset property.
  143561. * @exception {DeveloperError} options.duration must be positive.
  143562. */
  143563. TweenCollection.prototype.addOffsetIncrement = function(options) {
  143564. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  143565. var material = options.material;
  143566. if (!defined(material)) {
  143567. throw new DeveloperError('material is required.');
  143568. }
  143569. if (!defined(material.uniforms.offset)) {
  143570. throw new DeveloperError('material.uniforms must have an offset property.');
  143571. }
  143572. var uniforms = material.uniforms;
  143573. return this.addProperty({
  143574. object : uniforms,
  143575. property : 'offset',
  143576. startValue : uniforms.offset,
  143577. stopValue : uniforms.offset + 1,
  143578. duration : options.duration,
  143579. delay : options.delay,
  143580. easingFunction : options.easingFunction,
  143581. update : options.update,
  143582. cancel : options.cancel,
  143583. _repeat : Infinity
  143584. });
  143585. };
  143586. /**
  143587. * Removes a tween from the collection.
  143588. * <p>
  143589. * This calls the {@link Tween#cancel} callback if the tween has one.
  143590. * </p>
  143591. *
  143592. * @param {Tween} tween The tween to remove.
  143593. * @returns {Boolean} <code>true</code> if the tween was removed; <code>false</code> if the tween was not found in the collection.
  143594. */
  143595. TweenCollection.prototype.remove = function(tween) {
  143596. if (!defined(tween)) {
  143597. return false;
  143598. }
  143599. var index = this._tweens.indexOf(tween);
  143600. if (index !== -1) {
  143601. tween.tweenjs.stop();
  143602. if (defined(tween.cancel)) {
  143603. tween.cancel();
  143604. }
  143605. this._tweens.splice(index, 1);
  143606. return true;
  143607. }
  143608. return false;
  143609. };
  143610. /**
  143611. * Removes all tweens from the collection.
  143612. * <p>
  143613. * This calls the {@link Tween#cancel} callback for each tween that has one.
  143614. * </p>
  143615. */
  143616. TweenCollection.prototype.removeAll = function() {
  143617. var tweens = this._tweens;
  143618. for (var i = 0; i < tweens.length; ++i) {
  143619. var tween = tweens[i];
  143620. tween.tweenjs.stop();
  143621. if (defined(tween.cancel)) {
  143622. tween.cancel();
  143623. }
  143624. }
  143625. tweens.length = 0;
  143626. };
  143627. /**
  143628. * Determines whether this collection contains a given tween.
  143629. *
  143630. * @param {Tween} tween The tween to check for.
  143631. * @returns {Boolean} <code>true</code> if this collection contains the tween, <code>false</code> otherwise.
  143632. */
  143633. TweenCollection.prototype.contains = function(tween) {
  143634. return defined(tween) && (this._tweens.indexOf(tween) !== -1);
  143635. };
  143636. /**
  143637. * Returns the tween in the collection at the specified index. Indices are zero-based
  143638. * and increase as tweens are added. Removing a tween shifts all tweens after
  143639. * it to the left, changing their indices. This function is commonly used to iterate over
  143640. * all the tween in the collection.
  143641. *
  143642. * @param {Number} index The zero-based index of the tween.
  143643. * @returns {Tween} The tween at the specified index.
  143644. *
  143645. * @example
  143646. * // Output the duration of all the tweens in the collection.
  143647. * var tweens = scene.tweens;
  143648. * var length = tweens.length;
  143649. * for (var i = 0; i < length; ++i) {
  143650. * console.log(tweens.get(i).duration);
  143651. * }
  143652. */
  143653. TweenCollection.prototype.get = function(index) {
  143654. if (!defined(index)) {
  143655. throw new DeveloperError('index is required.');
  143656. }
  143657. return this._tweens[index];
  143658. };
  143659. /**
  143660. * Updates the tweens in the collection to be at the provide time. When a tween finishes, it is removed
  143661. * from the collection.
  143662. *
  143663. * @param {Number} [time=getTimestamp()] The time in seconds. By default tweens are synced to the system clock.
  143664. */
  143665. TweenCollection.prototype.update = function(time) {
  143666. var tweens = this._tweens;
  143667. var i = 0;
  143668. time = defined(time) ? time / TimeConstants.SECONDS_PER_MILLISECOND : getTimestamp();
  143669. while (i < tweens.length) {
  143670. var tween = tweens[i];
  143671. var tweenjs = tween.tweenjs;
  143672. if (tween.needsStart) {
  143673. tween.needsStart = false;
  143674. tweenjs.start(time);
  143675. } else {
  143676. if (tweenjs.update(time)) {
  143677. i++;
  143678. } else {
  143679. tweenjs.stop();
  143680. tweens.splice(i, 1);
  143681. }
  143682. }
  143683. }
  143684. };
  143685. /**
  143686. * A function that will execute when a tween completes.
  143687. * @callback TweenCollection~TweenCompleteCallback
  143688. */
  143689. /**
  143690. * A function that will execute when a tween updates.
  143691. * @callback TweenCollection~TweenUpdateCallback
  143692. */
  143693. /**
  143694. * A function that will execute when a tween is cancelled.
  143695. * @callback TweenCollection~TweenCancelledCallback
  143696. */
  143697. return TweenCollection;
  143698. });
  143699. /*global define*/
  143700. define('Scene/ScreenSpaceCameraController',[
  143701. '../Core/Cartesian2',
  143702. '../Core/Cartesian3',
  143703. '../Core/Cartesian4',
  143704. '../Core/Cartographic',
  143705. '../Core/defaultValue',
  143706. '../Core/defined',
  143707. '../Core/destroyObject',
  143708. '../Core/DeveloperError',
  143709. '../Core/Ellipsoid',
  143710. '../Core/IntersectionTests',
  143711. '../Core/isArray',
  143712. '../Core/KeyboardEventModifier',
  143713. '../Core/Math',
  143714. '../Core/Matrix3',
  143715. '../Core/Matrix4',
  143716. '../Core/Plane',
  143717. '../Core/Quaternion',
  143718. '../Core/Ray',
  143719. '../Core/Transforms',
  143720. './CameraEventAggregator',
  143721. './CameraEventType',
  143722. './MapMode2D',
  143723. './SceneMode',
  143724. './SceneTransforms',
  143725. './TweenCollection'
  143726. ], function(
  143727. Cartesian2,
  143728. Cartesian3,
  143729. Cartesian4,
  143730. Cartographic,
  143731. defaultValue,
  143732. defined,
  143733. destroyObject,
  143734. DeveloperError,
  143735. Ellipsoid,
  143736. IntersectionTests,
  143737. isArray,
  143738. KeyboardEventModifier,
  143739. CesiumMath,
  143740. Matrix3,
  143741. Matrix4,
  143742. Plane,
  143743. Quaternion,
  143744. Ray,
  143745. Transforms,
  143746. CameraEventAggregator,
  143747. CameraEventType,
  143748. MapMode2D,
  143749. SceneMode,
  143750. SceneTransforms,
  143751. TweenCollection) {
  143752. 'use strict';
  143753. /**
  143754. * Modifies the camera position and orientation based on mouse input to a canvas.
  143755. * @alias ScreenSpaceCameraController
  143756. * @constructor
  143757. *
  143758. * @param {Scene} scene The scene.
  143759. */
  143760. function ScreenSpaceCameraController(scene) {
  143761. if (!defined(scene)) {
  143762. throw new DeveloperError('scene is required.');
  143763. }
  143764. /**
  143765. * If true, inputs are allowed conditionally with the flags enableTranslate, enableZoom,
  143766. * enableRotate, enableTilt, and enableLook. If false, all inputs are disabled.
  143767. *
  143768. * NOTE: This setting is for temporary use cases, such as camera flights and
  143769. * drag-selection of regions (see Picking demo). It is typically set to false at the
  143770. * start of such events, and set true on completion. To keep inputs disabled
  143771. * past the end of camera flights, you must use the other booleans (enableTranslate,
  143772. * enableZoom, enableRotate, enableTilt, and enableLook).
  143773. * @type {Boolean}
  143774. * @default true
  143775. */
  143776. this.enableInputs = true;
  143777. /**
  143778. * If true, allows the user to pan around the map. If false, the camera stays locked at the current position.
  143779. * This flag only applies in 2D and Columbus view modes.
  143780. * @type {Boolean}
  143781. * @default true
  143782. */
  143783. this.enableTranslate = true;
  143784. /**
  143785. * If true, allows the user to zoom in and out. If false, the camera is locked to the current distance from the ellipsoid.
  143786. * @type {Boolean}
  143787. * @default true
  143788. */
  143789. this.enableZoom = true;
  143790. /**
  143791. * If true, allows the user to rotate the camera. If false, the camera is locked to the current heading.
  143792. * This flag only applies in 2D and 3D.
  143793. * @type {Boolean}
  143794. * @default true
  143795. */
  143796. this.enableRotate = true;
  143797. /**
  143798. * If true, allows the user to tilt the camera. If false, the camera is locked to the current heading.
  143799. * This flag only applies in 3D and Columbus view.
  143800. * @type {Boolean}
  143801. * @default true
  143802. */
  143803. this.enableTilt = true;
  143804. /**
  143805. * If true, allows the user to use free-look. If false, the camera view direction can only be changed through translating
  143806. * or rotating. This flag only applies in 3D and Columbus view modes.
  143807. * @type {Boolean}
  143808. * @default true
  143809. */
  143810. this.enableLook = true;
  143811. /**
  143812. * A parameter in the range <code>[0, 1)</code> used to determine how long
  143813. * the camera will continue to spin because of inertia.
  143814. * With value of zero, the camera will have no inertia.
  143815. * @type {Number}
  143816. * @default 0.9
  143817. */
  143818. this.inertiaSpin = 0.9;
  143819. /**
  143820. * A parameter in the range <code>[0, 1)</code> used to determine how long
  143821. * the camera will continue to translate because of inertia.
  143822. * With value of zero, the camera will have no inertia.
  143823. * @type {Number}
  143824. * @default 0.9
  143825. */
  143826. this.inertiaTranslate = 0.9;
  143827. /**
  143828. * A parameter in the range <code>[0, 1)</code> used to determine how long
  143829. * the camera will continue to zoom because of inertia.
  143830. * With value of zero, the camera will have no inertia.
  143831. * @type {Number}
  143832. * @default 0.8
  143833. */
  143834. this.inertiaZoom = 0.8;
  143835. /**
  143836. * A parameter in the range <code>[0, 1)</code> used to limit the range
  143837. * of various user inputs to a percentage of the window width/height per animation frame.
  143838. * This helps keep the camera under control in low-frame-rate situations.
  143839. * @type {Number}
  143840. * @default 0.1
  143841. */
  143842. this.maximumMovementRatio = 0.1;
  143843. /**
  143844. * Sets the duration, in seconds, of the bounce back animations in 2D and Columbus view.
  143845. * @type {Number}
  143846. * @default 3.0
  143847. */
  143848. this.bounceAnimationTime = 3.0;
  143849. /**
  143850. * The minimum magnitude, in meters, of the camera position when zooming. Defaults to 1.0.
  143851. * @type {Number}
  143852. * @default 1.0
  143853. */
  143854. this.minimumZoomDistance = 1.0;
  143855. /**
  143856. * The maximum magnitude, in meters, of the camera position when zooming. Defaults to positive infinity.
  143857. * @type {Number}
  143858. * @default {@link Number.POSITIVE_INFINITY}
  143859. */
  143860. this.maximumZoomDistance = Number.POSITIVE_INFINITY;
  143861. /**
  143862. * The input that allows the user to pan around the map. This only applies in 2D and Columbus view modes.
  143863. * <p>
  143864. * The type came be a {@link CameraEventType}, <code>undefined</code>, an object with <code>eventType</code>
  143865. * and <code>modifier</code> properties with types <code>CameraEventType</code> and {@link KeyboardEventModifier},
  143866. * or an array of any of the preceding.
  143867. * </p>
  143868. * @type {CameraEventType|Array|undefined}
  143869. * @default {@link CameraEventType.LEFT_DRAG}
  143870. */
  143871. this.translateEventTypes = CameraEventType.LEFT_DRAG;
  143872. /**
  143873. * The input that allows the user to zoom in/out.
  143874. * <p>
  143875. * The type came be a {@link CameraEventType}, <code>undefined</code>, an object with <code>eventType</code>
  143876. * and <code>modifier</code> properties with types <code>CameraEventType</code> and {@link KeyboardEventModifier},
  143877. * or an array of any of the preceding.
  143878. * </p>
  143879. * @type {CameraEventType|Array|undefined}
  143880. * @default [{@link CameraEventType.RIGHT_DRAG}, {@link CameraEventType.WHEEL}, {@link CameraEventType.PINCH}]
  143881. */
  143882. this.zoomEventTypes = [CameraEventType.RIGHT_DRAG, CameraEventType.WHEEL, CameraEventType.PINCH];
  143883. /**
  143884. * The input that allows the user to rotate around the globe or another object. This only applies in 3D and Columbus view modes.
  143885. * <p>
  143886. * The type came be a {@link CameraEventType}, <code>undefined</code>, an object with <code>eventType</code>
  143887. * and <code>modifier</code> properties with types <code>CameraEventType</code> and {@link KeyboardEventModifier},
  143888. * or an array of any of the preceding.
  143889. * </p>
  143890. * @type {CameraEventType|Array|undefined}
  143891. * @default {@link CameraEventType.LEFT_DRAG}
  143892. */
  143893. this.rotateEventTypes = CameraEventType.LEFT_DRAG;
  143894. /**
  143895. * The input that allows the user to tilt in 3D and Columbus view or twist in 2D.
  143896. * <p>
  143897. * The type came be a {@link CameraEventType}, <code>undefined</code>, an object with <code>eventType</code>
  143898. * and <code>modifier</code> properties with types <code>CameraEventType</code> and {@link KeyboardEventModifier},
  143899. * or an array of any of the preceding.
  143900. * </p>
  143901. * @type {CameraEventType|Array|undefined}
  143902. * @default [{@link CameraEventType.MIDDLE_DRAG}, {@link CameraEventType.PINCH}, {
  143903. * eventType : {@link CameraEventType.LEFT_DRAG},
  143904. * modifier : {@link KeyboardEventModifier.CTRL}
  143905. * }, {
  143906. * eventType : {@link CameraEventType.RIGHT_DRAG},
  143907. * modifier : {@link KeyboardEventModifier.CTRL}
  143908. * }]
  143909. */
  143910. this.tiltEventTypes = [CameraEventType.MIDDLE_DRAG, CameraEventType.PINCH, {
  143911. eventType : CameraEventType.LEFT_DRAG,
  143912. modifier : KeyboardEventModifier.CTRL
  143913. }, {
  143914. eventType : CameraEventType.RIGHT_DRAG,
  143915. modifier : KeyboardEventModifier.CTRL
  143916. }];
  143917. /**
  143918. * The input that allows the user to change the direction the camera is viewing. This only applies in 3D and Columbus view modes.
  143919. * <p>
  143920. * The type came be a {@link CameraEventType}, <code>undefined</code>, an object with <code>eventType</code>
  143921. * and <code>modifier</code> properties with types <code>CameraEventType</code> and {@link KeyboardEventModifier},
  143922. * or an array of any of the preceding.
  143923. * </p>
  143924. * @type {CameraEventType|Array|undefined}
  143925. * @default { eventType : {@link CameraEventType.LEFT_DRAG}, modifier : {@link KeyboardEventModifier.SHIFT} }
  143926. */
  143927. this.lookEventTypes = {
  143928. eventType : CameraEventType.LEFT_DRAG,
  143929. modifier : KeyboardEventModifier.SHIFT
  143930. };
  143931. /**
  143932. * The minimum height the camera must be before picking the terrain instead of the ellipsoid.
  143933. * @type {Number}
  143934. * @default 150000.0
  143935. */
  143936. this.minimumPickingTerrainHeight = 150000.0;
  143937. this._minimumPickingTerrainHeight = this.minimumPickingTerrainHeight;
  143938. /**
  143939. * The minimum height the camera must be before testing for collision with terrain.
  143940. * @type {Number}
  143941. * @default 10000.0
  143942. */
  143943. this.minimumCollisionTerrainHeight = 15000.0;
  143944. this._minimumCollisionTerrainHeight = this.minimumCollisionTerrainHeight;
  143945. /**
  143946. * The minimum height the camera must be before switching from rotating a track ball to
  143947. * free look when clicks originate on the sky on in space.
  143948. * @type {Number}
  143949. * @default 7500000.0
  143950. */
  143951. this.minimumTrackBallHeight = 7500000.0;
  143952. this._minimumTrackBallHeight = this.minimumTrackBallHeight;
  143953. /**
  143954. * Enables or disables camera collision detection with terrain.
  143955. * @type {Boolean}
  143956. * @default true
  143957. */
  143958. this.enableCollisionDetection = true;
  143959. this._scene = scene;
  143960. this._globe = undefined;
  143961. this._ellipsoid = undefined;
  143962. this._aggregator = new CameraEventAggregator(scene.canvas);
  143963. this._lastInertiaSpinMovement = undefined;
  143964. this._lastInertiaZoomMovement = undefined;
  143965. this._lastInertiaTranslateMovement = undefined;
  143966. this._lastInertiaTiltMovement = undefined;
  143967. this._tweens = new TweenCollection();
  143968. this._tween = undefined;
  143969. this._horizontalRotationAxis = undefined;
  143970. this._tiltCenterMousePosition = new Cartesian2(-1.0, -1.0);
  143971. this._tiltCenter = new Cartesian3();
  143972. this._rotateMousePosition = new Cartesian2(-1.0, -1.0);
  143973. this._rotateStartPosition = new Cartesian3();
  143974. this._strafeStartPosition = new Cartesian3();
  143975. this._zoomMouseStart = new Cartesian2(-1.0, -1.0);
  143976. this._zoomWorldPosition = new Cartesian3();
  143977. this._useZoomWorldPosition = false;
  143978. this._tiltCVOffMap = false;
  143979. this._looking = false;
  143980. this._rotating = false;
  143981. this._strafing = false;
  143982. this._zoomingOnVector = false;
  143983. this._rotatingZoom = false;
  143984. var projection = scene.mapProjection;
  143985. this._maxCoord = projection.project(new Cartographic(Math.PI, CesiumMath.PI_OVER_TWO));
  143986. // Constants, Make any of these public?
  143987. this._zoomFactor = 5.0;
  143988. this._rotateFactor = undefined;
  143989. this._rotateRateRangeAdjustment = undefined;
  143990. this._maximumRotateRate = 1.77;
  143991. this._minimumRotateRate = 1.0 / 5000.0;
  143992. this._minimumZoomRate = 20.0;
  143993. this._maximumZoomRate = 5906376272000.0; // distance from the Sun to Pluto in meters.
  143994. }
  143995. function decay(time, coefficient) {
  143996. if (time < 0) {
  143997. return 0.0;
  143998. }
  143999. var tau = (1.0 - coefficient) * 25.0;
  144000. return Math.exp(-tau * time);
  144001. }
  144002. function sameMousePosition(movement) {
  144003. return Cartesian2.equalsEpsilon(movement.startPosition, movement.endPosition, CesiumMath.EPSILON14);
  144004. }
  144005. // If the time between mouse down and mouse up is not between
  144006. // these thresholds, the camera will not move with inertia.
  144007. // This value is probably dependent on the browser and/or the
  144008. // hardware. Should be investigated further.
  144009. var inertiaMaxClickTimeThreshold = 0.4;
  144010. function maintainInertia(aggregator, type, modifier, decayCoef, action, object, lastMovementName) {
  144011. var movementState = object[lastMovementName];
  144012. if (!defined(movementState)) {
  144013. movementState = object[lastMovementName] = {
  144014. startPosition : new Cartesian2(),
  144015. endPosition : new Cartesian2(),
  144016. motion : new Cartesian2(),
  144017. active : false
  144018. };
  144019. }
  144020. var ts = aggregator.getButtonPressTime(type, modifier);
  144021. var tr = aggregator.getButtonReleaseTime(type, modifier);
  144022. var threshold = ts && tr && ((tr.getTime() - ts.getTime()) / 1000.0);
  144023. var now = new Date();
  144024. var fromNow = tr && ((now.getTime() - tr.getTime()) / 1000.0);
  144025. if (ts && tr && threshold < inertiaMaxClickTimeThreshold) {
  144026. var d = decay(fromNow, decayCoef);
  144027. if (!movementState.active) {
  144028. var lastMovement = aggregator.getLastMovement(type, modifier);
  144029. if (!defined(lastMovement) || sameMousePosition(lastMovement)) {
  144030. return;
  144031. }
  144032. movementState.motion.x = (lastMovement.endPosition.x - lastMovement.startPosition.x) * 0.5;
  144033. movementState.motion.y = (lastMovement.endPosition.y - lastMovement.startPosition.y) * 0.5;
  144034. movementState.startPosition = Cartesian2.clone(lastMovement.startPosition, movementState.startPosition);
  144035. movementState.endPosition = Cartesian2.multiplyByScalar(movementState.motion, d, movementState.endPosition);
  144036. movementState.endPosition = Cartesian2.add(movementState.startPosition, movementState.endPosition, movementState.endPosition);
  144037. movementState.active = true;
  144038. } else {
  144039. movementState.startPosition = Cartesian2.clone(movementState.endPosition, movementState.startPosition);
  144040. movementState.endPosition = Cartesian2.multiplyByScalar(movementState.motion, d, movementState.endPosition);
  144041. movementState.endPosition = Cartesian2.add(movementState.startPosition, movementState.endPosition, movementState.endPosition);
  144042. movementState.motion = Cartesian2.clone(Cartesian2.ZERO, movementState.motion);
  144043. }
  144044. // If value from the decreasing exponential function is close to zero,
  144045. // the end coordinates may be NaN.
  144046. if (isNaN(movementState.endPosition.x) || isNaN(movementState.endPosition.y) || Cartesian2.distance(movementState.startPosition, movementState.endPosition) < 0.5) {
  144047. movementState.active = false;
  144048. return;
  144049. }
  144050. if (!aggregator.isButtonDown(type, modifier)) {
  144051. var startPosition = aggregator.getStartMousePosition(type, modifier);
  144052. action(object, startPosition, movementState);
  144053. }
  144054. } else {
  144055. movementState.active = false;
  144056. }
  144057. }
  144058. var scratchEventTypeArray = [];
  144059. function reactToInput(controller, enabled, eventTypes, action, inertiaConstant, inertiaStateName) {
  144060. if (!defined(eventTypes)) {
  144061. return;
  144062. }
  144063. var aggregator = controller._aggregator;
  144064. if (!isArray(eventTypes)) {
  144065. scratchEventTypeArray[0] = eventTypes;
  144066. eventTypes = scratchEventTypeArray;
  144067. }
  144068. var length = eventTypes.length;
  144069. for (var i = 0; i < length; ++i) {
  144070. var eventType = eventTypes[i];
  144071. var type = defined(eventType.eventType) ? eventType.eventType : eventType;
  144072. var modifier = eventType.modifier;
  144073. var movement = aggregator.isMoving(type, modifier) && aggregator.getMovement(type, modifier);
  144074. var startPosition = aggregator.getStartMousePosition(type, modifier);
  144075. if (controller.enableInputs && enabled) {
  144076. if (movement) {
  144077. action(controller, startPosition, movement);
  144078. } else if (inertiaConstant < 1.0) {
  144079. maintainInertia(aggregator, type, modifier, inertiaConstant, action, controller, inertiaStateName);
  144080. }
  144081. }
  144082. }
  144083. }
  144084. var scratchZoomPickRay = new Ray();
  144085. var scratchPickCartesian = new Cartesian3();
  144086. var scratchZoomOffset = new Cartesian2();
  144087. var scratchZoomDirection = new Cartesian3();
  144088. var scratchCenterPixel = new Cartesian2();
  144089. var scratchCenterPosition = new Cartesian3();
  144090. var scratchPositionNormal = new Cartesian3();
  144091. var scratchPickNormal = new Cartesian3();
  144092. var scratchZoomAxis = new Cartesian3();
  144093. var scratchCameraPositionNormal = new Cartesian3();
  144094. // Scratch variables used in zooming algorithm
  144095. var scratchTargetNormal = new Cartesian3();
  144096. var scratchCameraPosition = new Cartesian3();
  144097. var scratchCameraUpNormal = new Cartesian3();
  144098. var scratchCameraRightNormal = new Cartesian3();
  144099. var scratchForwardNormal = new Cartesian3();
  144100. var scratchPositionToTarget = new Cartesian3();
  144101. var scratchPositionToTargetNormal = new Cartesian3();
  144102. var scratchPan = new Cartesian3();
  144103. var scratchCenterMovement = new Cartesian3();
  144104. var scratchCenter = new Cartesian3();
  144105. var scratchCartesian = new Cartesian3();
  144106. var scratchCartesianTwo = new Cartesian3();
  144107. var scratchCartesianThree = new Cartesian3();
  144108. function handleZoom(object, startPosition, movement, zoomFactor, distanceMeasure, unitPositionDotDirection) {
  144109. var percentage = 1.0;
  144110. if (defined(unitPositionDotDirection)) {
  144111. percentage = CesiumMath.clamp(Math.abs(unitPositionDotDirection), 0.25, 1.0);
  144112. }
  144113. // distanceMeasure should be the height above the ellipsoid.
  144114. // The zoomRate slows as it approaches the surface and stops minimumZoomDistance above it.
  144115. var minHeight = object.minimumZoomDistance * percentage;
  144116. var maxHeight = object.maximumZoomDistance;
  144117. var minDistance = distanceMeasure - minHeight;
  144118. var zoomRate = zoomFactor * minDistance;
  144119. zoomRate = CesiumMath.clamp(zoomRate, object._minimumZoomRate, object._maximumZoomRate);
  144120. var diff = movement.endPosition.y - movement.startPosition.y;
  144121. var rangeWindowRatio = diff / object._scene.canvas.clientHeight;
  144122. rangeWindowRatio = Math.min(rangeWindowRatio, object.maximumMovementRatio);
  144123. var distance = zoomRate * rangeWindowRatio;
  144124. if (distance > 0.0 && Math.abs(distanceMeasure - minHeight) < 1.0) {
  144125. return;
  144126. }
  144127. if (distance < 0.0 && Math.abs(distanceMeasure - maxHeight) < 1.0) {
  144128. return;
  144129. }
  144130. if (distanceMeasure - distance < minHeight) {
  144131. distance = distanceMeasure - minHeight - 1.0;
  144132. } else if (distanceMeasure - distance > maxHeight) {
  144133. distance = distanceMeasure - maxHeight;
  144134. }
  144135. var scene = object._scene;
  144136. var camera = scene.camera;
  144137. var mode = scene.mode;
  144138. var sameStartPosition = Cartesian2.equals(startPosition, object._zoomMouseStart);
  144139. var zoomingOnVector = object._zoomingOnVector;
  144140. var rotatingZoom = object._rotatingZoom;
  144141. var pickedPosition;
  144142. if (!sameStartPosition) {
  144143. object._zoomMouseStart = Cartesian2.clone(startPosition, object._zoomMouseStart);
  144144. if (defined(object._globe)) {
  144145. pickedPosition = mode !== SceneMode.SCENE2D ? pickGlobe(object, startPosition, scratchPickCartesian) : camera.getPickRay(startPosition, scratchZoomPickRay).origin;
  144146. }
  144147. if (defined(pickedPosition)) {
  144148. object._useZoomWorldPosition = true;
  144149. object._zoomWorldPosition = Cartesian3.clone(pickedPosition, object._zoomWorldPosition);
  144150. } else {
  144151. object._useZoomWorldPosition = false;
  144152. }
  144153. zoomingOnVector = object._zoomingOnVector = false;
  144154. rotatingZoom = object._rotatingZoom = false;
  144155. }
  144156. if (!object._useZoomWorldPosition) {
  144157. camera.zoomIn(distance);
  144158. return;
  144159. }
  144160. var zoomOnVector = mode === SceneMode.COLUMBUS_VIEW;
  144161. if (camera.positionCartographic.height < 2000000) {
  144162. rotatingZoom = true;
  144163. }
  144164. if (!sameStartPosition || rotatingZoom) {
  144165. if (mode === SceneMode.SCENE2D) {
  144166. var worldPosition = object._zoomWorldPosition;
  144167. var endPosition = camera.position;
  144168. if (!Cartesian3.equals(worldPosition, endPosition) && camera.positionCartographic.height < object._maxCoord.x * 2.0) {
  144169. var savedX = camera.position.x;
  144170. var direction = Cartesian3.subtract(worldPosition, endPosition, scratchZoomDirection);
  144171. Cartesian3.normalize(direction, direction);
  144172. var d = Cartesian3.distance(worldPosition, endPosition) * distance / (camera.getMagnitude() * 0.5);
  144173. camera.move(direction, d * 0.5);
  144174. if ((camera.position.x < 0.0 && savedX > 0.0) || (camera.position.x > 0.0 && savedX < 0.0)) {
  144175. pickedPosition = camera.getPickRay(startPosition, scratchZoomPickRay).origin;
  144176. object._zoomWorldPosition = Cartesian3.clone(pickedPosition, object._zoomWorldPosition);
  144177. }
  144178. }
  144179. } else if (mode === SceneMode.SCENE3D) {
  144180. var cameraPositionNormal = Cartesian3.normalize(camera.position, scratchCameraPositionNormal);
  144181. if (camera.positionCartographic.height < 3000.0 && Math.abs(Cartesian3.dot(camera.direction, cameraPositionNormal)) < 0.6) {
  144182. zoomOnVector = true;
  144183. } else {
  144184. var canvas = scene.canvas;
  144185. var centerPixel = scratchCenterPixel;
  144186. centerPixel.x = canvas.clientWidth / 2;
  144187. centerPixel.y = canvas.clientHeight / 2;
  144188. var centerPosition = pickGlobe(object, centerPixel, scratchCenterPosition);
  144189. // If centerPosition is not defined, it means the globe does not cover the center position of screen
  144190. if (defined(centerPosition) && camera.positionCartographic.height < 1000000) {
  144191. var cameraPosition = scratchCameraPosition;
  144192. Cartesian3.clone(camera.position, cameraPosition);
  144193. var target = object._zoomWorldPosition;
  144194. var targetNormal = scratchTargetNormal;
  144195. targetNormal = Cartesian3.normalize(target, targetNormal);
  144196. if (Cartesian3.dot(targetNormal, cameraPositionNormal) < 0.0) {
  144197. return;
  144198. }
  144199. var center = scratchCenter;
  144200. var forward = scratchForwardNormal;
  144201. Cartesian3.clone(camera.direction, forward);
  144202. Cartesian3.add(cameraPosition, Cartesian3.multiplyByScalar(forward, 1000, scratchCartesian), center);
  144203. var positionToTarget = scratchPositionToTarget;
  144204. var positionToTargetNormal = scratchPositionToTargetNormal;
  144205. Cartesian3.subtract(target, cameraPosition, positionToTarget);
  144206. Cartesian3.normalize(positionToTarget, positionToTargetNormal);
  144207. var alpha = Math.acos( -Cartesian3.dot( cameraPositionNormal, positionToTargetNormal ) );
  144208. var cameraDistance = Cartesian3.magnitude( cameraPosition );
  144209. var targetDistance = Cartesian3.magnitude( target );
  144210. var remainingDistance = cameraDistance - distance;
  144211. var positionToTargetDistance = Cartesian3.magnitude(positionToTarget);
  144212. var gamma = Math.asin( CesiumMath.clamp( positionToTargetDistance / targetDistance * Math.sin(alpha), -1.0, 1.0 ) );
  144213. var delta = Math.asin( CesiumMath.clamp( remainingDistance / targetDistance * Math.sin(alpha), -1.0, 1.0 ) );
  144214. var beta = gamma - delta + alpha;
  144215. var up = scratchCameraUpNormal;
  144216. Cartesian3.normalize(cameraPosition, up);
  144217. var right = scratchCameraRightNormal;
  144218. right = Cartesian3.cross(positionToTargetNormal, up, right);
  144219. right = Cartesian3.normalize(right, right );
  144220. Cartesian3.normalize( Cartesian3.cross(up, right, scratchCartesian), forward );
  144221. // Calculate new position to move to
  144222. Cartesian3.multiplyByScalar(Cartesian3.normalize(center, scratchCartesian), (Cartesian3.magnitude(center) - distance), center);
  144223. Cartesian3.normalize(cameraPosition, cameraPosition);
  144224. Cartesian3.multiplyByScalar(cameraPosition, remainingDistance, cameraPosition);
  144225. // Pan
  144226. var pMid = scratchPan;
  144227. Cartesian3.multiplyByScalar(Cartesian3.add(
  144228. Cartesian3.multiplyByScalar(up, Math.cos(beta) - 1, scratchCartesianTwo),
  144229. Cartesian3.multiplyByScalar(forward, Math.sin(beta), scratchCartesianThree),
  144230. scratchCartesian
  144231. ), remainingDistance, pMid);
  144232. Cartesian3.add(cameraPosition, pMid, cameraPosition);
  144233. Cartesian3.normalize(center, up);
  144234. Cartesian3.normalize( Cartesian3.cross(up, right, scratchCartesian), forward );
  144235. var cMid = scratchCenterMovement;
  144236. Cartesian3.multiplyByScalar(Cartesian3.add(
  144237. Cartesian3.multiplyByScalar(up, Math.cos(beta) - 1, scratchCartesianTwo),
  144238. Cartesian3.multiplyByScalar(forward, Math.sin(beta), scratchCartesianThree),
  144239. scratchCartesian
  144240. ), Cartesian3.magnitude(center), cMid);
  144241. Cartesian3.add(center, cMid, center);
  144242. // Update camera
  144243. // Set new position
  144244. Cartesian3.clone(cameraPosition, camera.position);
  144245. // Set new direction
  144246. Cartesian3.normalize(Cartesian3.subtract(center, cameraPosition, scratchCartesian), camera.direction);
  144247. Cartesian3.clone(camera.direction, camera.direction);
  144248. // Set new right & up vectors
  144249. Cartesian3.cross(camera.direction, camera.up, camera.right);
  144250. Cartesian3.cross(camera.right, camera.direction, camera.up);
  144251. return;
  144252. } else if (defined(centerPosition)) {
  144253. var positionNormal = Cartesian3.normalize(centerPosition, scratchPositionNormal);
  144254. var pickedNormal = Cartesian3.normalize(object._zoomWorldPosition, scratchPickNormal);
  144255. var dotProduct = Cartesian3.dot(pickedNormal, positionNormal);
  144256. if (dotProduct > 0.0 && dotProduct < 1.0) {
  144257. var angle = CesiumMath.acosClamped(dotProduct);
  144258. var axis = Cartesian3.cross(pickedNormal, positionNormal, scratchZoomAxis);
  144259. var denom = Math.abs(angle) > CesiumMath.toRadians(20.0) ? camera.positionCartographic.height * 0.75 : camera.positionCartographic.height - distance;
  144260. var scalar = distance / denom;
  144261. camera.rotate(axis, angle * scalar);
  144262. }
  144263. } else {
  144264. zoomOnVector = true;
  144265. }
  144266. }
  144267. }
  144268. object._rotatingZoom = !zoomOnVector;
  144269. }
  144270. if ((!sameStartPosition && zoomOnVector) || zoomingOnVector) {
  144271. var ray;
  144272. var zoomMouseStart = SceneTransforms.wgs84ToWindowCoordinates(scene, object._zoomWorldPosition, scratchZoomOffset);
  144273. if (mode !== SceneMode.COLUMBUS_VIEW && Cartesian2.equals(startPosition, object._zoomMouseStart) && defined(zoomMouseStart)) {
  144274. ray = camera.getPickRay(zoomMouseStart, scratchZoomPickRay);
  144275. } else {
  144276. ray = camera.getPickRay(startPosition, scratchZoomPickRay);
  144277. }
  144278. var rayDirection = ray.direction;
  144279. if (mode === SceneMode.COLUMBUS_VIEW) {
  144280. Cartesian3.fromElements(rayDirection.y, rayDirection.z, rayDirection.x, rayDirection);
  144281. }
  144282. camera.move(rayDirection, distance);
  144283. object._zoomingOnVector = true;
  144284. } else {
  144285. camera.zoomIn(distance);
  144286. }
  144287. }
  144288. var translate2DStart = new Ray();
  144289. var translate2DEnd = new Ray();
  144290. var scratchTranslateP0 = new Cartesian3();
  144291. function translate2D(controller, startPosition, movement) {
  144292. var scene = controller._scene;
  144293. var camera = scene.camera;
  144294. var start = camera.getPickRay(movement.startPosition, translate2DStart).origin;
  144295. var end = camera.getPickRay(movement.endPosition, translate2DEnd).origin;
  144296. var direction = Cartesian3.subtract(start, end, scratchTranslateP0);
  144297. var distance = Cartesian3.magnitude(direction);
  144298. if (distance > 0.0) {
  144299. Cartesian3.normalize(direction, direction);
  144300. camera.move(direction, distance);
  144301. }
  144302. }
  144303. function zoom2D(controller, startPosition, movement) {
  144304. if (defined(movement.distance)) {
  144305. movement = movement.distance;
  144306. }
  144307. var scene = controller._scene;
  144308. var camera = scene.camera;
  144309. handleZoom(controller, startPosition, movement, controller._zoomFactor, camera.getMagnitude());
  144310. }
  144311. var twist2DStart = new Cartesian2();
  144312. var twist2DEnd = new Cartesian2();
  144313. function twist2D(controller, startPosition, movement) {
  144314. if (defined(movement.angleAndHeight)) {
  144315. singleAxisTwist2D(controller, startPosition, movement.angleAndHeight);
  144316. return;
  144317. }
  144318. var scene = controller._scene;
  144319. var camera = scene.camera;
  144320. var canvas = scene.canvas;
  144321. var width = canvas.clientWidth;
  144322. var height = canvas.clientHeight;
  144323. var start = twist2DStart;
  144324. start.x = (2.0 / width) * movement.startPosition.x - 1.0;
  144325. start.y = (2.0 / height) * (height - movement.startPosition.y) - 1.0;
  144326. start = Cartesian2.normalize(start, start);
  144327. var end = twist2DEnd;
  144328. end.x = (2.0 / width) * movement.endPosition.x - 1.0;
  144329. end.y = (2.0 / height) * (height - movement.endPosition.y) - 1.0;
  144330. end = Cartesian2.normalize(end, end);
  144331. var startTheta = CesiumMath.acosClamped(start.x);
  144332. if (start.y < 0) {
  144333. startTheta = CesiumMath.TWO_PI - startTheta;
  144334. }
  144335. var endTheta = CesiumMath.acosClamped(end.x);
  144336. if (end.y < 0) {
  144337. endTheta = CesiumMath.TWO_PI - endTheta;
  144338. }
  144339. var theta = endTheta - startTheta;
  144340. camera.twistRight(theta);
  144341. }
  144342. function singleAxisTwist2D(controller, startPosition, movement) {
  144343. var rotateRate = controller._rotateFactor * controller._rotateRateRangeAdjustment;
  144344. if (rotateRate > controller._maximumRotateRate) {
  144345. rotateRate = controller._maximumRotateRate;
  144346. }
  144347. if (rotateRate < controller._minimumRotateRate) {
  144348. rotateRate = controller._minimumRotateRate;
  144349. }
  144350. var scene = controller._scene;
  144351. var camera = scene.camera;
  144352. var canvas = scene.canvas;
  144353. var phiWindowRatio = (movement.endPosition.x - movement.startPosition.x) / canvas.clientWidth;
  144354. phiWindowRatio = Math.min(phiWindowRatio, controller.maximumMovementRatio);
  144355. var deltaPhi = rotateRate * phiWindowRatio * Math.PI * 4.0;
  144356. camera.twistRight(deltaPhi);
  144357. }
  144358. function update2D(controller) {
  144359. var rotatable2D = controller._scene.mapMode2D === MapMode2D.ROTATE;
  144360. if (!Matrix4.equals(Matrix4.IDENTITY, controller._scene.camera.transform)) {
  144361. reactToInput(controller, controller.enableZoom, controller.zoomEventTypes, zoom2D, controller.inertiaZoom, '_lastInertiaZoomMovement');
  144362. if (rotatable2D) {
  144363. reactToInput(controller, controller.enableRotate, controller.translateEventTypes, twist2D, controller.inertiaSpin, '_lastInertiaSpinMovement');
  144364. }
  144365. } else {
  144366. reactToInput(controller, controller.enableTranslate, controller.translateEventTypes, translate2D, controller.inertiaTranslate, '_lastInertiaTranslateMovement');
  144367. reactToInput(controller, controller.enableZoom, controller.zoomEventTypes, zoom2D, controller.inertiaZoom, '_lastInertiaZoomMovement');
  144368. if (rotatable2D) {
  144369. reactToInput(controller, controller.enableRotate, controller.tiltEventTypes, twist2D, controller.inertiaSpin, '_lastInertiaTiltMovement');
  144370. }
  144371. }
  144372. }
  144373. var pickGlobeScratchRay = new Ray();
  144374. var scratchDepthIntersection = new Cartesian3();
  144375. var scratchRayIntersection = new Cartesian3();
  144376. function pickGlobe(controller, mousePosition, result) {
  144377. var scene = controller._scene;
  144378. var globe = controller._globe;
  144379. var camera = scene.camera;
  144380. if (!defined(globe)) {
  144381. return undefined;
  144382. }
  144383. var depthIntersection;
  144384. if (scene.pickPositionSupported) {
  144385. depthIntersection = scene.pickPosition(mousePosition, scratchDepthIntersection);
  144386. }
  144387. var ray = camera.getPickRay(mousePosition, pickGlobeScratchRay);
  144388. var rayIntersection = globe.pick(ray, scene, scratchRayIntersection);
  144389. var pickDistance = defined(depthIntersection) ? Cartesian3.distance(depthIntersection, camera.positionWC) : Number.POSITIVE_INFINITY;
  144390. var rayDistance = defined(rayIntersection) ? Cartesian3.distance(rayIntersection, camera.positionWC) : Number.POSITIVE_INFINITY;
  144391. if (pickDistance < rayDistance) {
  144392. return Cartesian3.clone(depthIntersection, result);
  144393. }
  144394. return Cartesian3.clone(rayIntersection, result);
  144395. }
  144396. var translateCVStartRay = new Ray();
  144397. var translateCVEndRay = new Ray();
  144398. var translateCVStartPos = new Cartesian3();
  144399. var translateCVEndPos = new Cartesian3();
  144400. var translatCVDifference = new Cartesian3();
  144401. var translateCVOrigin = new Cartesian3();
  144402. var translateCVPlane = new Plane(Cartesian3.ZERO, 0.0);
  144403. var translateCVStartMouse = new Cartesian2();
  144404. var translateCVEndMouse = new Cartesian2();
  144405. function translateCV(controller, startPosition, movement) {
  144406. if (!Cartesian3.equals(startPosition, controller._translateMousePosition)) {
  144407. controller._looking = false;
  144408. }
  144409. if (!Cartesian3.equals(startPosition, controller._strafeMousePosition)) {
  144410. controller._strafing = false;
  144411. }
  144412. if (controller._looking) {
  144413. look3D(controller, startPosition, movement);
  144414. return;
  144415. }
  144416. if (controller._strafing) {
  144417. strafe(controller, startPosition, movement);
  144418. return;
  144419. }
  144420. var scene = controller._scene;
  144421. var camera = scene.camera;
  144422. var startMouse = Cartesian2.clone(movement.startPosition, translateCVStartMouse);
  144423. var endMouse = Cartesian2.clone(movement.endPosition, translateCVEndMouse);
  144424. var startRay = camera.getPickRay(startMouse, translateCVStartRay);
  144425. var origin = Cartesian3.clone(Cartesian3.ZERO, translateCVOrigin);
  144426. var normal = Cartesian3.UNIT_X;
  144427. var globePos;
  144428. if (camera.position.z < controller._minimumPickingTerrainHeight) {
  144429. globePos = pickGlobe(controller, startMouse, translateCVStartPos);
  144430. if (defined(globePos)) {
  144431. origin.x = globePos.x;
  144432. }
  144433. }
  144434. if (origin.x > camera.position.z && defined(globePos)) {
  144435. Cartesian3.clone(globePos, controller._strafeStartPosition);
  144436. controller._strafing = true;
  144437. strafe(controller, startPosition, movement);
  144438. controller._strafeMousePosition = Cartesian2.clone(startPosition, controller._strafeMousePosition);
  144439. return;
  144440. }
  144441. var plane = Plane.fromPointNormal(origin, normal, translateCVPlane);
  144442. startRay = camera.getPickRay(startMouse, translateCVStartRay);
  144443. var startPlanePos = IntersectionTests.rayPlane(startRay, plane, translateCVStartPos);
  144444. var endRay = camera.getPickRay(endMouse, translateCVEndRay);
  144445. var endPlanePos = IntersectionTests.rayPlane(endRay, plane, translateCVEndPos);
  144446. if (!defined(startPlanePos) || !defined(endPlanePos)) {
  144447. controller._looking = true;
  144448. look3D(controller, startPosition, movement);
  144449. Cartesian2.clone(startPosition, controller._translateMousePosition);
  144450. return;
  144451. }
  144452. var diff = Cartesian3.subtract(startPlanePos, endPlanePos, translatCVDifference);
  144453. var temp = diff.x;
  144454. diff.x = diff.y;
  144455. diff.y = diff.z;
  144456. diff.z = temp;
  144457. var mag = Cartesian3.magnitude(diff);
  144458. if (mag > CesiumMath.EPSILON6) {
  144459. Cartesian3.normalize(diff, diff);
  144460. camera.move(diff, mag);
  144461. }
  144462. }
  144463. var rotateCVWindowPos = new Cartesian2();
  144464. var rotateCVWindowRay = new Ray();
  144465. var rotateCVCenter = new Cartesian3();
  144466. var rotateCVVerticalCenter = new Cartesian3();
  144467. var rotateCVTransform = new Matrix4();
  144468. var rotateCVVerticalTransform = new Matrix4();
  144469. var rotateCVOrigin = new Cartesian3();
  144470. var rotateCVPlane = new Plane(Cartesian3.ZERO, 0.0);
  144471. var rotateCVCartesian3 = new Cartesian3();
  144472. var rotateCVCart = new Cartographic();
  144473. var rotateCVOldTransform = new Matrix4();
  144474. var rotateCVQuaternion = new Quaternion();
  144475. var rotateCVMatrix = new Matrix3();
  144476. function rotateCV(controller, startPosition, movement) {
  144477. if (defined(movement.angleAndHeight)) {
  144478. movement = movement.angleAndHeight;
  144479. }
  144480. if (!Cartesian2.equals(startPosition, controller._tiltCenterMousePosition)) {
  144481. controller._tiltCVOffMap = false;
  144482. controller._looking = false;
  144483. }
  144484. if (controller._looking) {
  144485. look3D(controller, startPosition, movement);
  144486. return;
  144487. }
  144488. var scene = controller._scene;
  144489. var camera = scene.camera;
  144490. var maxCoord = controller._maxCoord;
  144491. var onMap = Math.abs(camera.position.x) - maxCoord.x < 0 && Math.abs(camera.position.y) - maxCoord.y < 0;
  144492. if (controller._tiltCVOffMap || !onMap || camera.position.z > controller._minimumPickingTerrainHeight) {
  144493. controller._tiltCVOffMap = true;
  144494. rotateCVOnPlane(controller, startPosition, movement);
  144495. } else {
  144496. rotateCVOnTerrain(controller, startPosition, movement);
  144497. }
  144498. }
  144499. function rotateCVOnPlane(controller, startPosition, movement) {
  144500. var scene = controller._scene;
  144501. var camera = scene.camera;
  144502. var canvas = scene.canvas;
  144503. var windowPosition = rotateCVWindowPos;
  144504. windowPosition.x = canvas.clientWidth / 2;
  144505. windowPosition.y = canvas.clientHeight / 2;
  144506. var ray = camera.getPickRay(windowPosition, rotateCVWindowRay);
  144507. var normal = Cartesian3.UNIT_X;
  144508. var position = ray.origin;
  144509. var direction = ray.direction;
  144510. var scalar;
  144511. var normalDotDirection = Cartesian3.dot(normal, direction);
  144512. if (Math.abs(normalDotDirection) > CesiumMath.EPSILON6) {
  144513. scalar = -Cartesian3.dot(normal, position) / normalDotDirection;
  144514. }
  144515. if (!defined(scalar) || scalar <= 0.0) {
  144516. controller._looking = true;
  144517. look3D(controller, startPosition, movement);
  144518. Cartesian2.clone(startPosition, controller._tiltCenterMousePosition);
  144519. return;
  144520. }
  144521. var center = Cartesian3.multiplyByScalar(direction, scalar, rotateCVCenter);
  144522. Cartesian3.add(position, center, center);
  144523. var projection = scene.mapProjection;
  144524. var ellipsoid = projection.ellipsoid;
  144525. Cartesian3.fromElements(center.y, center.z, center.x, center);
  144526. var cart = projection.unproject(center, rotateCVCart);
  144527. ellipsoid.cartographicToCartesian(cart, center);
  144528. var transform = Transforms.eastNorthUpToFixedFrame(center, ellipsoid, rotateCVTransform);
  144529. var oldGlobe = controller._globe;
  144530. var oldEllipsoid = controller._ellipsoid;
  144531. controller._globe = undefined;
  144532. controller._ellipsoid = Ellipsoid.UNIT_SPHERE;
  144533. controller._rotateFactor = 1.0;
  144534. controller._rotateRateRangeAdjustment = 1.0;
  144535. var oldTransform = Matrix4.clone(camera.transform, rotateCVOldTransform);
  144536. camera._setTransform(transform);
  144537. rotate3D(controller, startPosition, movement, Cartesian3.UNIT_Z);
  144538. camera._setTransform(oldTransform);
  144539. controller._globe = oldGlobe;
  144540. controller._ellipsoid = oldEllipsoid;
  144541. var radius = oldEllipsoid.maximumRadius;
  144542. controller._rotateFactor = 1.0 / radius;
  144543. controller._rotateRateRangeAdjustment = radius;
  144544. }
  144545. function rotateCVOnTerrain(controller, startPosition, movement) {
  144546. var scene = controller._scene;
  144547. var camera = scene.camera;
  144548. var center;
  144549. var ray;
  144550. var normal = Cartesian3.UNIT_X;
  144551. if (Cartesian2.equals(startPosition, controller._tiltCenterMousePosition)) {
  144552. center = Cartesian3.clone(controller._tiltCenter, rotateCVCenter);
  144553. } else {
  144554. if (camera.position.z < controller._minimumPickingTerrainHeight) {
  144555. center = pickGlobe(controller, startPosition, rotateCVCenter);
  144556. }
  144557. if (!defined(center)) {
  144558. ray = camera.getPickRay(startPosition, rotateCVWindowRay);
  144559. var position = ray.origin;
  144560. var direction = ray.direction;
  144561. var scalar;
  144562. var normalDotDirection = Cartesian3.dot(normal, direction);
  144563. if (Math.abs(normalDotDirection) > CesiumMath.EPSILON6) {
  144564. scalar = -Cartesian3.dot(normal, position) / normalDotDirection;
  144565. }
  144566. if (!defined(scalar) || scalar <= 0.0) {
  144567. controller._looking = true;
  144568. look3D(controller, startPosition, movement);
  144569. Cartesian2.clone(startPosition, controller._tiltCenterMousePosition);
  144570. return;
  144571. }
  144572. center = Cartesian3.multiplyByScalar(direction, scalar, rotateCVCenter);
  144573. Cartesian3.add(position, center, center);
  144574. }
  144575. Cartesian2.clone(startPosition, controller._tiltCenterMousePosition);
  144576. Cartesian3.clone(center, controller._tiltCenter);
  144577. }
  144578. var canvas = scene.canvas;
  144579. var windowPosition = rotateCVWindowPos;
  144580. windowPosition.x = canvas.clientWidth / 2;
  144581. windowPosition.y = controller._tiltCenterMousePosition.y;
  144582. ray = camera.getPickRay(windowPosition, rotateCVWindowRay);
  144583. var origin = Cartesian3.clone(Cartesian3.ZERO, rotateCVOrigin);
  144584. origin.x = center.x;
  144585. var plane = Plane.fromPointNormal(origin, normal, rotateCVPlane);
  144586. var verticalCenter = IntersectionTests.rayPlane(ray, plane, rotateCVVerticalCenter);
  144587. var projection = camera._projection;
  144588. var ellipsoid = projection.ellipsoid;
  144589. Cartesian3.fromElements(center.y, center.z, center.x, center);
  144590. var cart = projection.unproject(center, rotateCVCart);
  144591. ellipsoid.cartographicToCartesian(cart, center);
  144592. var transform = Transforms.eastNorthUpToFixedFrame(center, ellipsoid, rotateCVTransform);
  144593. var verticalTransform;
  144594. if (defined(verticalCenter)) {
  144595. Cartesian3.fromElements(verticalCenter.y, verticalCenter.z, verticalCenter.x, verticalCenter);
  144596. cart = projection.unproject(verticalCenter, rotateCVCart);
  144597. ellipsoid.cartographicToCartesian(cart, verticalCenter);
  144598. verticalTransform = Transforms.eastNorthUpToFixedFrame(verticalCenter, ellipsoid, rotateCVVerticalTransform);
  144599. } else {
  144600. verticalTransform = transform;
  144601. }
  144602. var oldGlobe = controller._globe;
  144603. var oldEllipsoid = controller._ellipsoid;
  144604. controller._globe = undefined;
  144605. controller._ellipsoid = Ellipsoid.UNIT_SPHERE;
  144606. controller._rotateFactor = 1.0;
  144607. controller._rotateRateRangeAdjustment = 1.0;
  144608. var constrainedAxis = Cartesian3.UNIT_Z;
  144609. var oldTransform = Matrix4.clone(camera.transform, rotateCVOldTransform);
  144610. camera._setTransform(transform);
  144611. var tangent = Cartesian3.cross(Cartesian3.UNIT_Z, Cartesian3.normalize(camera.position, rotateCVCartesian3), rotateCVCartesian3);
  144612. var dot = Cartesian3.dot(camera.right, tangent);
  144613. rotate3D(controller, startPosition, movement, constrainedAxis, false, true);
  144614. camera._setTransform(verticalTransform);
  144615. if (dot < 0.0) {
  144616. if (movement.startPosition.y > movement.endPosition.y) {
  144617. constrainedAxis = undefined;
  144618. }
  144619. var oldConstrainedAxis = camera.constrainedAxis;
  144620. camera.constrainedAxis = undefined;
  144621. rotate3D(controller, startPosition, movement, constrainedAxis, true, false);
  144622. camera.constrainedAxis = oldConstrainedAxis;
  144623. } else {
  144624. rotate3D(controller, startPosition, movement, constrainedAxis, true, false);
  144625. }
  144626. if (defined(camera.constrainedAxis)) {
  144627. var right = Cartesian3.cross(camera.direction, camera.constrainedAxis, tilt3DCartesian3);
  144628. if (!Cartesian3.equalsEpsilon(right, Cartesian3.ZERO, CesiumMath.EPSILON6)) {
  144629. if (Cartesian3.dot(right, camera.right) < 0.0) {
  144630. Cartesian3.negate(right, right);
  144631. }
  144632. Cartesian3.cross(right, camera.direction, camera.up);
  144633. Cartesian3.cross(camera.direction, camera.up, camera.right);
  144634. Cartesian3.normalize(camera.up, camera.up);
  144635. Cartesian3.normalize(camera.right, camera.right);
  144636. }
  144637. }
  144638. camera._setTransform(oldTransform);
  144639. controller._globe = oldGlobe;
  144640. controller._ellipsoid = oldEllipsoid;
  144641. var radius = oldEllipsoid.maximumRadius;
  144642. controller._rotateFactor = 1.0 / radius;
  144643. controller._rotateRateRangeAdjustment = radius;
  144644. var originalPosition = Cartesian3.clone(camera.positionWC, rotateCVCartesian3);
  144645. camera._adjustHeightForTerrain();
  144646. if (!Cartesian3.equals(camera.positionWC, originalPosition)) {
  144647. camera._setTransform(verticalTransform);
  144648. camera.worldToCameraCoordinatesPoint(originalPosition, originalPosition);
  144649. var magSqrd = Cartesian3.magnitudeSquared(originalPosition);
  144650. if (Cartesian3.magnitudeSquared(camera.position) > magSqrd) {
  144651. Cartesian3.normalize(camera.position, camera.position);
  144652. Cartesian3.multiplyByScalar(camera.position, Math.sqrt(magSqrd), camera.position);
  144653. }
  144654. var angle = Cartesian3.angleBetween(originalPosition, camera.position);
  144655. var axis = Cartesian3.cross(originalPosition, camera.position, originalPosition);
  144656. Cartesian3.normalize(axis, axis);
  144657. var quaternion = Quaternion.fromAxisAngle(axis, angle, rotateCVQuaternion);
  144658. var rotation = Matrix3.fromQuaternion(quaternion, rotateCVMatrix);
  144659. Matrix3.multiplyByVector(rotation, camera.direction, camera.direction);
  144660. Matrix3.multiplyByVector(rotation, camera.up, camera.up);
  144661. Cartesian3.cross(camera.direction, camera.up, camera.right);
  144662. Cartesian3.cross(camera.right, camera.direction, camera.up);
  144663. camera._setTransform(oldTransform);
  144664. }
  144665. }
  144666. var zoomCVWindowPos = new Cartesian2();
  144667. var zoomCVWindowRay = new Ray();
  144668. var zoomCVIntersection = new Cartesian3();
  144669. function zoomCV(controller, startPosition, movement) {
  144670. if (defined(movement.distance)) {
  144671. movement = movement.distance;
  144672. }
  144673. var scene = controller._scene;
  144674. var camera = scene.camera;
  144675. var canvas = scene.canvas;
  144676. var windowPosition = zoomCVWindowPos;
  144677. windowPosition.x = canvas.clientWidth / 2;
  144678. windowPosition.y = canvas.clientHeight / 2;
  144679. var ray = camera.getPickRay(windowPosition, zoomCVWindowRay);
  144680. var intersection;
  144681. if (camera.position.z < controller._minimumPickingTerrainHeight) {
  144682. intersection = pickGlobe(controller, windowPosition, zoomCVIntersection);
  144683. }
  144684. var distance;
  144685. if (defined(intersection)) {
  144686. distance = Cartesian3.distance(ray.origin, intersection);
  144687. } else {
  144688. var normal = Cartesian3.UNIT_X;
  144689. var position = ray.origin;
  144690. var direction = ray.direction;
  144691. distance = -Cartesian3.dot(normal, position) / Cartesian3.dot(normal, direction);
  144692. }
  144693. handleZoom(controller, startPosition, movement, controller._zoomFactor, distance);
  144694. }
  144695. function updateCV(controller) {
  144696. var scene = controller._scene;
  144697. var camera = scene.camera;
  144698. if (!Matrix4.equals(Matrix4.IDENTITY, camera.transform)) {
  144699. reactToInput(controller, controller.enableRotate, controller.rotateEventTypes, rotate3D, controller.inertiaSpin, '_lastInertiaSpinMovement');
  144700. reactToInput(controller, controller.enableZoom, controller.zoomEventTypes, zoom3D, controller.inertiaZoom, '_lastInertiaZoomMovement');
  144701. } else {
  144702. var tweens = controller._tweens;
  144703. if (controller._aggregator.anyButtonDown) {
  144704. tweens.removeAll();
  144705. }
  144706. reactToInput(controller, controller.enableTilt, controller.tiltEventTypes, rotateCV, controller.inertiaSpin, '_lastInertiaTiltMovement');
  144707. reactToInput(controller, controller.enableTranslate, controller.translateEventTypes, translateCV, controller.inertiaTranslate, '_lastInertiaTranslateMovement');
  144708. reactToInput(controller, controller.enableZoom, controller.zoomEventTypes, zoomCV, controller.inertiaZoom, '_lastInertiaZoomMovement');
  144709. reactToInput(controller, controller.enableLook, controller.lookEventTypes, look3D);
  144710. if (!controller._aggregator.anyButtonDown &&
  144711. (!defined(controller._lastInertiaZoomMovement) || !controller._lastInertiaZoomMovement.active) &&
  144712. (!defined(controller._lastInertiaTranslateMovement) || !controller._lastInertiaTranslateMovement.active) &&
  144713. !tweens.contains(controller._tween)) {
  144714. var tween = camera.createCorrectPositionTween(controller.bounceAnimationTime);
  144715. if (defined(tween)) {
  144716. controller._tween = tweens.add(tween);
  144717. }
  144718. }
  144719. tweens.update();
  144720. }
  144721. }
  144722. var scratchStrafeRay = new Ray();
  144723. var scratchStrafePlane = new Plane(Cartesian3.ZERO, 0.0);
  144724. var scratchStrafeIntersection = new Cartesian3();
  144725. var scratchStrafeDirection = new Cartesian3();
  144726. function strafe(controller, startPosition, movement) {
  144727. var scene = controller._scene;
  144728. var camera = scene.camera;
  144729. var mouseStartPosition = pickGlobe(controller, movement.startPosition, scratchMousePos);
  144730. if (!defined(mouseStartPosition)) {
  144731. return;
  144732. }
  144733. var mousePosition = movement.endPosition;
  144734. var ray = camera.getPickRay(mousePosition, scratchStrafeRay);
  144735. var direction = Cartesian3.clone(camera.direction, scratchStrafeDirection);
  144736. if (scene.mode === SceneMode.COLUMBUS_VIEW) {
  144737. Cartesian3.fromElements(direction.z, direction.x, direction.y, direction);
  144738. }
  144739. var plane = Plane.fromPointNormal(mouseStartPosition, direction, scratchStrafePlane);
  144740. var intersection = IntersectionTests.rayPlane(ray, plane, scratchStrafeIntersection);
  144741. if (!defined(intersection)) {
  144742. return;
  144743. }
  144744. direction = Cartesian3.subtract(mouseStartPosition, intersection, direction);
  144745. if (scene.mode === SceneMode.COLUMBUS_VIEW) {
  144746. Cartesian3.fromElements(direction.y, direction.z, direction.x, direction);
  144747. }
  144748. Cartesian3.add(camera.position, direction, camera.position);
  144749. }
  144750. var spin3DPick = new Cartesian3();
  144751. var scratchCartographic = new Cartographic();
  144752. var scratchMousePos = new Cartesian3();
  144753. var scratchRadii = new Cartesian3();
  144754. var scratchEllipsoid = new Ellipsoid();
  144755. var scratchLookUp = new Cartesian3();
  144756. function spin3D(controller, startPosition, movement) {
  144757. var scene = controller._scene;
  144758. var camera = scene.camera;
  144759. if (!Matrix4.equals(camera.transform, Matrix4.IDENTITY)) {
  144760. rotate3D(controller, startPosition, movement);
  144761. return;
  144762. }
  144763. var magnitude;
  144764. var radii;
  144765. var ellipsoid;
  144766. var up = controller._ellipsoid.geodeticSurfaceNormal(camera.position, scratchLookUp);
  144767. var height = controller._ellipsoid.cartesianToCartographic(camera.positionWC, scratchCartographic).height;
  144768. var globe = controller._globe;
  144769. var mousePos;
  144770. var tangentPick = false;
  144771. if (defined(globe) && height < controller._minimumPickingTerrainHeight) {
  144772. mousePos = pickGlobe(controller, movement.startPosition, scratchMousePos);
  144773. if (defined(mousePos)) {
  144774. var ray = camera.getPickRay(movement.startPosition, pickGlobeScratchRay);
  144775. var normal = controller._ellipsoid.geodeticSurfaceNormal(mousePos);
  144776. tangentPick = Math.abs(Cartesian3.dot(ray.direction, normal)) < 0.05;
  144777. if (tangentPick && !controller._looking) {
  144778. controller._rotating = false;
  144779. controller._strafing = true;
  144780. }
  144781. }
  144782. }
  144783. if (Cartesian2.equals(startPosition, controller._rotateMousePosition)) {
  144784. if (controller._looking) {
  144785. look3D(controller, startPosition, movement, up);
  144786. } else if (controller._rotating) {
  144787. rotate3D(controller, startPosition, movement);
  144788. } else if (controller._strafing) {
  144789. Cartesian3.clone(mousePos, controller._strafeStartPosition);
  144790. strafe(controller, startPosition, movement);
  144791. } else {
  144792. magnitude = Cartesian3.magnitude(controller._rotateStartPosition);
  144793. radii = scratchRadii;
  144794. radii.x = radii.y = radii.z = magnitude;
  144795. ellipsoid = Ellipsoid.fromCartesian3(radii, scratchEllipsoid);
  144796. pan3D(controller, startPosition, movement, ellipsoid);
  144797. }
  144798. return;
  144799. } else {
  144800. controller._looking = false;
  144801. controller._rotating = false;
  144802. controller._strafing = false;
  144803. }
  144804. if (defined(globe) && height < controller._minimumPickingTerrainHeight) {
  144805. if (defined(mousePos)) {
  144806. if (Cartesian3.magnitude(camera.position) < Cartesian3.magnitude(mousePos)) {
  144807. Cartesian3.clone(mousePos, controller._strafeStartPosition);
  144808. controller._strafing = true;
  144809. strafe(controller, startPosition, movement);
  144810. } else {
  144811. magnitude = Cartesian3.magnitude(mousePos);
  144812. radii = scratchRadii;
  144813. radii.x = radii.y = radii.z = magnitude;
  144814. ellipsoid = Ellipsoid.fromCartesian3(radii, scratchEllipsoid);
  144815. pan3D(controller, startPosition, movement, ellipsoid);
  144816. Cartesian3.clone(mousePos, controller._rotateStartPosition);
  144817. }
  144818. } else {
  144819. controller._looking = true;
  144820. look3D(controller, startPosition, movement, up);
  144821. }
  144822. } else if (defined(camera.pickEllipsoid(movement.startPosition, controller._ellipsoid, spin3DPick))) {
  144823. pan3D(controller, startPosition, movement, controller._ellipsoid);
  144824. Cartesian3.clone(spin3DPick, controller._rotateStartPosition);
  144825. } else if (height > controller._minimumTrackBallHeight) {
  144826. controller._rotating = true;
  144827. rotate3D(controller, startPosition, movement);
  144828. } else {
  144829. controller._looking = true;
  144830. look3D(controller, startPosition, movement, up);
  144831. }
  144832. Cartesian2.clone(startPosition, controller._rotateMousePosition);
  144833. }
  144834. function rotate3D(controller, startPosition, movement, constrainedAxis, rotateOnlyVertical, rotateOnlyHorizontal) {
  144835. rotateOnlyVertical = defaultValue(rotateOnlyVertical, false);
  144836. rotateOnlyHorizontal = defaultValue(rotateOnlyHorizontal, false);
  144837. var scene = controller._scene;
  144838. var camera = scene.camera;
  144839. var canvas = scene.canvas;
  144840. var oldAxis = camera.constrainedAxis;
  144841. if (defined(constrainedAxis)) {
  144842. camera.constrainedAxis = constrainedAxis;
  144843. }
  144844. var rho = Cartesian3.magnitude(camera.position);
  144845. var rotateRate = controller._rotateFactor * (rho - controller._rotateRateRangeAdjustment);
  144846. if (rotateRate > controller._maximumRotateRate) {
  144847. rotateRate = controller._maximumRotateRate;
  144848. }
  144849. if (rotateRate < controller._minimumRotateRate) {
  144850. rotateRate = controller._minimumRotateRate;
  144851. }
  144852. var phiWindowRatio = (movement.startPosition.x - movement.endPosition.x) / canvas.clientWidth;
  144853. var thetaWindowRatio = (movement.startPosition.y - movement.endPosition.y) / canvas.clientHeight;
  144854. phiWindowRatio = Math.min(phiWindowRatio, controller.maximumMovementRatio);
  144855. thetaWindowRatio = Math.min(thetaWindowRatio, controller.maximumMovementRatio);
  144856. var deltaPhi = rotateRate * phiWindowRatio * Math.PI * 2.0;
  144857. var deltaTheta = rotateRate * thetaWindowRatio * Math.PI;
  144858. if (!rotateOnlyVertical) {
  144859. camera.rotateRight(deltaPhi);
  144860. }
  144861. if (!rotateOnlyHorizontal) {
  144862. camera.rotateUp(deltaTheta);
  144863. }
  144864. camera.constrainedAxis = oldAxis;
  144865. }
  144866. var pan3DP0 = Cartesian4.clone(Cartesian4.UNIT_W);
  144867. var pan3DP1 = Cartesian4.clone(Cartesian4.UNIT_W);
  144868. var pan3DTemp0 = new Cartesian3();
  144869. var pan3DTemp1 = new Cartesian3();
  144870. var pan3DTemp2 = new Cartesian3();
  144871. var pan3DTemp3 = new Cartesian3();
  144872. var pan3DStartMousePosition = new Cartesian2();
  144873. var pan3DEndMousePosition = new Cartesian2();
  144874. function pan3D(controller, startPosition, movement, ellipsoid) {
  144875. var scene = controller._scene;
  144876. var camera = scene.camera;
  144877. var startMousePosition = Cartesian2.clone(movement.startPosition, pan3DStartMousePosition);
  144878. var endMousePosition = Cartesian2.clone(movement.endPosition, pan3DEndMousePosition);
  144879. var p0 = camera.pickEllipsoid(startMousePosition, ellipsoid, pan3DP0);
  144880. var p1 = camera.pickEllipsoid(endMousePosition, ellipsoid, pan3DP1);
  144881. if (!defined(p0) || !defined(p1)) {
  144882. controller._rotating = true;
  144883. rotate3D(controller, startPosition, movement);
  144884. return;
  144885. }
  144886. p0 = camera.worldToCameraCoordinates(p0, p0);
  144887. p1 = camera.worldToCameraCoordinates(p1, p1);
  144888. if (!defined(camera.constrainedAxis)) {
  144889. Cartesian3.normalize(p0, p0);
  144890. Cartesian3.normalize(p1, p1);
  144891. var dot = Cartesian3.dot(p0, p1);
  144892. var axis = Cartesian3.cross(p0, p1, pan3DTemp0);
  144893. if (dot < 1.0 && !Cartesian3.equalsEpsilon(axis, Cartesian3.ZERO, CesiumMath.EPSILON14)) { // dot is in [0, 1]
  144894. var angle = Math.acos(dot);
  144895. camera.rotate(axis, angle);
  144896. }
  144897. } else {
  144898. var basis0 = camera.constrainedAxis;
  144899. var basis1 = Cartesian3.mostOrthogonalAxis(basis0, pan3DTemp0);
  144900. Cartesian3.cross(basis1, basis0, basis1);
  144901. Cartesian3.normalize(basis1, basis1);
  144902. var basis2 = Cartesian3.cross(basis0, basis1, pan3DTemp1);
  144903. var startRho = Cartesian3.magnitude(p0);
  144904. var startDot = Cartesian3.dot(basis0, p0);
  144905. var startTheta = Math.acos(startDot / startRho);
  144906. var startRej = Cartesian3.multiplyByScalar(basis0, startDot, pan3DTemp2);
  144907. Cartesian3.subtract(p0, startRej, startRej);
  144908. Cartesian3.normalize(startRej, startRej);
  144909. var endRho = Cartesian3.magnitude(p1);
  144910. var endDot = Cartesian3.dot(basis0, p1);
  144911. var endTheta = Math.acos(endDot / endRho);
  144912. var endRej = Cartesian3.multiplyByScalar(basis0, endDot, pan3DTemp3);
  144913. Cartesian3.subtract(p1, endRej, endRej);
  144914. Cartesian3.normalize(endRej, endRej);
  144915. var startPhi = Math.acos(Cartesian3.dot(startRej, basis1));
  144916. if (Cartesian3.dot(startRej, basis2) < 0) {
  144917. startPhi = CesiumMath.TWO_PI - startPhi;
  144918. }
  144919. var endPhi = Math.acos(Cartesian3.dot(endRej, basis1));
  144920. if (Cartesian3.dot(endRej, basis2) < 0) {
  144921. endPhi = CesiumMath.TWO_PI - endPhi;
  144922. }
  144923. var deltaPhi = startPhi - endPhi;
  144924. var east;
  144925. if (Cartesian3.equalsEpsilon(basis0, camera.position, CesiumMath.EPSILON2)) {
  144926. east = camera.right;
  144927. } else {
  144928. east = Cartesian3.cross(basis0, camera.position, pan3DTemp0);
  144929. }
  144930. var planeNormal = Cartesian3.cross(basis0, east, pan3DTemp0);
  144931. var side0 = Cartesian3.dot(planeNormal, Cartesian3.subtract(p0, basis0, pan3DTemp1));
  144932. var side1 = Cartesian3.dot(planeNormal, Cartesian3.subtract(p1, basis0, pan3DTemp1));
  144933. var deltaTheta;
  144934. if (side0 > 0 && side1 > 0) {
  144935. deltaTheta = endTheta - startTheta;
  144936. } else if (side0 > 0 && side1 <= 0) {
  144937. if (Cartesian3.dot(camera.position, basis0) > 0) {
  144938. deltaTheta = -startTheta - endTheta;
  144939. } else {
  144940. deltaTheta = startTheta + endTheta;
  144941. }
  144942. } else {
  144943. deltaTheta = startTheta - endTheta;
  144944. }
  144945. camera.rotateRight(deltaPhi);
  144946. camera.rotateUp(deltaTheta);
  144947. }
  144948. }
  144949. var zoom3DUnitPosition = new Cartesian3();
  144950. var zoom3DCartographic = new Cartographic();
  144951. function zoom3D(controller, startPosition, movement) {
  144952. if (defined(movement.distance)) {
  144953. movement = movement.distance;
  144954. }
  144955. var ellipsoid = controller._ellipsoid;
  144956. var scene = controller._scene;
  144957. var camera = scene.camera;
  144958. var canvas = scene.canvas;
  144959. var windowPosition = zoomCVWindowPos;
  144960. windowPosition.x = canvas.clientWidth / 2;
  144961. windowPosition.y = canvas.clientHeight / 2;
  144962. var ray = camera.getPickRay(windowPosition, zoomCVWindowRay);
  144963. var intersection;
  144964. var height = ellipsoid.cartesianToCartographic(camera.position, zoom3DCartographic).height;
  144965. if (height < controller._minimumPickingTerrainHeight) {
  144966. intersection = pickGlobe(controller, windowPosition, zoomCVIntersection);
  144967. }
  144968. var distance;
  144969. if (defined(intersection)) {
  144970. distance = Cartesian3.distance(ray.origin, intersection);
  144971. } else {
  144972. distance = height;
  144973. }
  144974. var unitPosition = Cartesian3.normalize(camera.position, zoom3DUnitPosition);
  144975. handleZoom(controller, startPosition, movement, controller._zoomFactor, distance, Cartesian3.dot(unitPosition, camera.direction));
  144976. }
  144977. var tilt3DWindowPos = new Cartesian2();
  144978. var tilt3DRay = new Ray();
  144979. var tilt3DCenter = new Cartesian3();
  144980. var tilt3DVerticalCenter = new Cartesian3();
  144981. var tilt3DTransform = new Matrix4();
  144982. var tilt3DVerticalTransform = new Matrix4();
  144983. var tilt3DCartesian3 = new Cartesian3();
  144984. var tilt3DOldTransform = new Matrix4();
  144985. var tilt3DQuaternion = new Quaternion();
  144986. var tilt3DMatrix = new Matrix3();
  144987. var tilt3DCart = new Cartographic();
  144988. var tilt3DLookUp = new Cartesian3();
  144989. function tilt3D(controller, startPosition, movement) {
  144990. var scene = controller._scene;
  144991. var camera = scene.camera;
  144992. if (!Matrix4.equals(camera.transform, Matrix4.IDENTITY)) {
  144993. return;
  144994. }
  144995. if (defined(movement.angleAndHeight)) {
  144996. movement = movement.angleAndHeight;
  144997. }
  144998. if (!Cartesian2.equals(startPosition, controller._tiltCenterMousePosition)) {
  144999. controller._tiltOnEllipsoid = false;
  145000. controller._looking = false;
  145001. }
  145002. if (controller._looking) {
  145003. var up = controller._ellipsoid.geodeticSurfaceNormal(camera.position, tilt3DLookUp);
  145004. look3D(controller, startPosition, movement, up);
  145005. return;
  145006. }
  145007. var ellipsoid = controller._ellipsoid;
  145008. var cartographic = ellipsoid.cartesianToCartographic(camera.position, tilt3DCart);
  145009. if (controller._tiltOnEllipsoid || cartographic.height > controller._minimumCollisionTerrainHeight) {
  145010. controller._tiltOnEllipsoid = true;
  145011. tilt3DOnEllipsoid(controller, startPosition, movement);
  145012. } else {
  145013. tilt3DOnTerrain(controller, startPosition, movement);
  145014. }
  145015. }
  145016. var tilt3DOnEllipsoidCartographic = new Cartographic();
  145017. function tilt3DOnEllipsoid(controller, startPosition, movement) {
  145018. var ellipsoid = controller._ellipsoid;
  145019. var scene = controller._scene;
  145020. var camera = scene.camera;
  145021. var minHeight = controller.minimumZoomDistance * 0.25;
  145022. var height = ellipsoid.cartesianToCartographic(camera.positionWC, tilt3DOnEllipsoidCartographic).height;
  145023. if (height - minHeight - 1.0 < CesiumMath.EPSILON3 &&
  145024. movement.endPosition.y - movement.startPosition.y < 0) {
  145025. return;
  145026. }
  145027. var canvas = scene.canvas;
  145028. var windowPosition = tilt3DWindowPos;
  145029. windowPosition.x = canvas.clientWidth / 2;
  145030. windowPosition.y = canvas.clientHeight / 2;
  145031. var ray = camera.getPickRay(windowPosition, tilt3DRay);
  145032. var center;
  145033. var intersection = IntersectionTests.rayEllipsoid(ray, ellipsoid);
  145034. if (defined(intersection)) {
  145035. center = Ray.getPoint(ray, intersection.start, tilt3DCenter);
  145036. } else if (height > controller._minimumTrackBallHeight) {
  145037. var grazingAltitudeLocation = IntersectionTests.grazingAltitudeLocation(ray, ellipsoid);
  145038. if (!defined(grazingAltitudeLocation)) {
  145039. return;
  145040. }
  145041. var grazingAltitudeCart = ellipsoid.cartesianToCartographic(grazingAltitudeLocation, tilt3DCart);
  145042. grazingAltitudeCart.height = 0.0;
  145043. center = ellipsoid.cartographicToCartesian(grazingAltitudeCart, tilt3DCenter);
  145044. } else {
  145045. controller._looking = true;
  145046. var up = controller._ellipsoid.geodeticSurfaceNormal(camera.position, tilt3DLookUp);
  145047. look3D(controller, startPosition, movement, up);
  145048. Cartesian2.clone(startPosition, controller._tiltCenterMousePosition);
  145049. return;
  145050. }
  145051. var transform = Transforms.eastNorthUpToFixedFrame(center, ellipsoid, tilt3DTransform);
  145052. var oldGlobe = controller._globe;
  145053. var oldEllipsoid = controller._ellipsoid;
  145054. controller._globe = undefined;
  145055. controller._ellipsoid = Ellipsoid.UNIT_SPHERE;
  145056. controller._rotateFactor = 1.0;
  145057. controller._rotateRateRangeAdjustment = 1.0;
  145058. var oldTransform = Matrix4.clone(camera.transform, tilt3DOldTransform);
  145059. camera._setTransform(transform);
  145060. rotate3D(controller, startPosition, movement, Cartesian3.UNIT_Z);
  145061. camera._setTransform(oldTransform);
  145062. controller._globe = oldGlobe;
  145063. controller._ellipsoid = oldEllipsoid;
  145064. var radius = oldEllipsoid.maximumRadius;
  145065. controller._rotateFactor = 1.0 / radius;
  145066. controller._rotateRateRangeAdjustment = radius;
  145067. }
  145068. function tilt3DOnTerrain(controller, startPosition, movement) {
  145069. var ellipsoid = controller._ellipsoid;
  145070. var scene = controller._scene;
  145071. var camera = scene.camera;
  145072. var center;
  145073. var ray;
  145074. var intersection;
  145075. if (Cartesian2.equals(startPosition, controller._tiltCenterMousePosition)) {
  145076. center = Cartesian3.clone(controller._tiltCenter, tilt3DCenter);
  145077. } else {
  145078. center = pickGlobe(controller, startPosition, tilt3DCenter);
  145079. if (!defined(center)) {
  145080. ray = camera.getPickRay(startPosition, tilt3DRay);
  145081. intersection = IntersectionTests.rayEllipsoid(ray, ellipsoid);
  145082. if (!defined(intersection)) {
  145083. var cartographic = ellipsoid.cartesianToCartographic(camera.position, tilt3DCart);
  145084. if (cartographic.height <= controller._minimumTrackBallHeight) {
  145085. controller._looking = true;
  145086. var up = controller._ellipsoid.geodeticSurfaceNormal(camera.position, tilt3DLookUp);
  145087. look3D(controller, startPosition, movement, up);
  145088. Cartesian2.clone(startPosition, controller._tiltCenterMousePosition);
  145089. }
  145090. return;
  145091. }
  145092. center = Ray.getPoint(ray, intersection.start, tilt3DCenter);
  145093. }
  145094. Cartesian2.clone(startPosition, controller._tiltCenterMousePosition);
  145095. Cartesian3.clone(center, controller._tiltCenter);
  145096. }
  145097. var canvas = scene.canvas;
  145098. var windowPosition = tilt3DWindowPos;
  145099. windowPosition.x = canvas.clientWidth / 2;
  145100. windowPosition.y = controller._tiltCenterMousePosition.y;
  145101. ray = camera.getPickRay(windowPosition, tilt3DRay);
  145102. var mag = Cartesian3.magnitude(center);
  145103. var radii = Cartesian3.fromElements(mag, mag, mag, scratchRadii);
  145104. var newEllipsoid = Ellipsoid.fromCartesian3(radii, scratchEllipsoid);
  145105. intersection = IntersectionTests.rayEllipsoid(ray, newEllipsoid);
  145106. if (!defined(intersection)) {
  145107. return;
  145108. }
  145109. var t = Cartesian3.magnitude(ray.origin) > mag ? intersection.start : intersection.stop;
  145110. var verticalCenter = Ray.getPoint(ray, t, tilt3DVerticalCenter);
  145111. var transform = Transforms.eastNorthUpToFixedFrame(center, ellipsoid, tilt3DTransform);
  145112. var verticalTransform = Transforms.eastNorthUpToFixedFrame(verticalCenter, newEllipsoid, tilt3DVerticalTransform);
  145113. var oldGlobe = controller._globe;
  145114. var oldEllipsoid = controller._ellipsoid;
  145115. controller._globe = undefined;
  145116. controller._ellipsoid = Ellipsoid.UNIT_SPHERE;
  145117. controller._rotateFactor = 1.0;
  145118. controller._rotateRateRangeAdjustment = 1.0;
  145119. var constrainedAxis = Cartesian3.UNIT_Z;
  145120. var oldTransform = Matrix4.clone(camera.transform, tilt3DOldTransform);
  145121. camera._setTransform(transform);
  145122. var tangent = Cartesian3.cross(verticalCenter, camera.positionWC, tilt3DCartesian3);
  145123. var dot = Cartesian3.dot(camera.rightWC, tangent);
  145124. rotate3D(controller, startPosition, movement, constrainedAxis, false, true);
  145125. camera._setTransform(verticalTransform);
  145126. if (dot < 0.0) {
  145127. if (movement.startPosition.y > movement.endPosition.y) {
  145128. constrainedAxis = undefined;
  145129. }
  145130. var oldConstrainedAxis = camera.constrainedAxis;
  145131. camera.constrainedAxis = undefined;
  145132. rotate3D(controller, startPosition, movement, constrainedAxis, true, false);
  145133. camera.constrainedAxis = oldConstrainedAxis;
  145134. } else {
  145135. rotate3D(controller, startPosition, movement, constrainedAxis, true, false);
  145136. }
  145137. if (defined(camera.constrainedAxis)) {
  145138. var right = Cartesian3.cross(camera.direction, camera.constrainedAxis, tilt3DCartesian3);
  145139. if (!Cartesian3.equalsEpsilon(right, Cartesian3.ZERO, CesiumMath.EPSILON6)) {
  145140. if (Cartesian3.dot(right, camera.right) < 0.0) {
  145141. Cartesian3.negate(right, right);
  145142. }
  145143. Cartesian3.cross(right, camera.direction, camera.up);
  145144. Cartesian3.cross(camera.direction, camera.up, camera.right);
  145145. Cartesian3.normalize(camera.up, camera.up);
  145146. Cartesian3.normalize(camera.right, camera.right);
  145147. }
  145148. }
  145149. camera._setTransform(oldTransform);
  145150. controller._globe = oldGlobe;
  145151. controller._ellipsoid = oldEllipsoid;
  145152. var radius = oldEllipsoid.maximumRadius;
  145153. controller._rotateFactor = 1.0 / radius;
  145154. controller._rotateRateRangeAdjustment = radius;
  145155. var originalPosition = Cartesian3.clone(camera.positionWC, tilt3DCartesian3);
  145156. camera._adjustHeightForTerrain();
  145157. if (!Cartesian3.equals(camera.positionWC, originalPosition)) {
  145158. camera._setTransform(verticalTransform);
  145159. camera.worldToCameraCoordinatesPoint(originalPosition, originalPosition);
  145160. var magSqrd = Cartesian3.magnitudeSquared(originalPosition);
  145161. if (Cartesian3.magnitudeSquared(camera.position) > magSqrd) {
  145162. Cartesian3.normalize(camera.position, camera.position);
  145163. Cartesian3.multiplyByScalar(camera.position, Math.sqrt(magSqrd), camera.position);
  145164. }
  145165. var angle = Cartesian3.angleBetween(originalPosition, camera.position);
  145166. var axis = Cartesian3.cross(originalPosition, camera.position, originalPosition);
  145167. Cartesian3.normalize(axis, axis);
  145168. var quaternion = Quaternion.fromAxisAngle(axis, angle, tilt3DQuaternion);
  145169. var rotation = Matrix3.fromQuaternion(quaternion, tilt3DMatrix);
  145170. Matrix3.multiplyByVector(rotation, camera.direction, camera.direction);
  145171. Matrix3.multiplyByVector(rotation, camera.up, camera.up);
  145172. Cartesian3.cross(camera.direction, camera.up, camera.right);
  145173. Cartesian3.cross(camera.right, camera.direction, camera.up);
  145174. camera._setTransform(oldTransform);
  145175. }
  145176. }
  145177. var look3DStartPos = new Cartesian2();
  145178. var look3DEndPos = new Cartesian2();
  145179. var look3DStartRay = new Ray();
  145180. var look3DEndRay = new Ray();
  145181. var look3DNegativeRot = new Cartesian3();
  145182. var look3DTan = new Cartesian3();
  145183. function look3D(controller, startPosition, movement, rotationAxis) {
  145184. var scene = controller._scene;
  145185. var camera = scene.camera;
  145186. var startPos = look3DStartPos;
  145187. startPos.x = movement.startPosition.x;
  145188. startPos.y = 0.0;
  145189. var endPos = look3DEndPos;
  145190. endPos.x = movement.endPosition.x;
  145191. endPos.y = 0.0;
  145192. var start = camera.getPickRay(startPos, look3DStartRay).direction;
  145193. var end = camera.getPickRay(endPos, look3DEndRay).direction;
  145194. var angle = 0.0;
  145195. var dot = Cartesian3.dot(start, end);
  145196. if (dot < 1.0) { // dot is in [0, 1]
  145197. angle = Math.acos(dot);
  145198. }
  145199. angle = (movement.startPosition.x > movement.endPosition.x) ? -angle : angle;
  145200. var horizontalRotationAxis = controller._horizontalRotationAxis;
  145201. if (defined(rotationAxis)) {
  145202. camera.look(rotationAxis, -angle);
  145203. } else if (defined(horizontalRotationAxis)) {
  145204. camera.look(horizontalRotationAxis, -angle);
  145205. } else {
  145206. camera.lookLeft(angle);
  145207. }
  145208. startPos.x = 0.0;
  145209. startPos.y = movement.startPosition.y;
  145210. endPos.x = 0.0;
  145211. endPos.y = movement.endPosition.y;
  145212. start = camera.getPickRay(startPos, look3DStartRay).direction;
  145213. end = camera.getPickRay(endPos, look3DEndRay).direction;
  145214. angle = 0.0;
  145215. dot = Cartesian3.dot(start, end);
  145216. if (dot < 1.0) { // dot is in [0, 1]
  145217. angle = Math.acos(dot);
  145218. }
  145219. angle = (movement.startPosition.y > movement.endPosition.y) ? -angle : angle;
  145220. rotationAxis = defaultValue(rotationAxis, horizontalRotationAxis);
  145221. if (defined(rotationAxis)) {
  145222. var direction = camera.direction;
  145223. var negativeRotationAxis = Cartesian3.negate(rotationAxis, look3DNegativeRot);
  145224. var northParallel = Cartesian3.equalsEpsilon(direction, rotationAxis, CesiumMath.EPSILON2);
  145225. var southParallel = Cartesian3.equalsEpsilon(direction, negativeRotationAxis, CesiumMath.EPSILON2);
  145226. if ((!northParallel && !southParallel)) {
  145227. dot = Cartesian3.dot(direction, rotationAxis);
  145228. var angleToAxis = CesiumMath.acosClamped(dot);
  145229. if (angle > 0 && angle > angleToAxis) {
  145230. angle = angleToAxis - CesiumMath.EPSILON4;
  145231. }
  145232. dot = Cartesian3.dot(direction, negativeRotationAxis);
  145233. angleToAxis = CesiumMath.acosClamped(dot);
  145234. if (angle < 0 && -angle > angleToAxis) {
  145235. angle = -angleToAxis + CesiumMath.EPSILON4;
  145236. }
  145237. var tangent = Cartesian3.cross(rotationAxis, direction, look3DTan);
  145238. camera.look(tangent, angle);
  145239. } else if ((northParallel && angle < 0) || (southParallel && angle > 0)) {
  145240. camera.look(camera.right, -angle);
  145241. }
  145242. } else {
  145243. camera.lookUp(angle);
  145244. }
  145245. }
  145246. function update3D(controller) {
  145247. reactToInput(controller, controller.enableRotate, controller.rotateEventTypes, spin3D, controller.inertiaSpin, '_lastInertiaSpinMovement');
  145248. reactToInput(controller, controller.enableZoom, controller.zoomEventTypes, zoom3D, controller.inertiaZoom, '_lastInertiaZoomMovement');
  145249. reactToInput(controller, controller.enableTilt, controller.tiltEventTypes, tilt3D, controller.inertiaSpin, '_lastInertiaTiltMovement');
  145250. reactToInput(controller, controller.enableLook, controller.lookEventTypes, look3D);
  145251. }
  145252. /**
  145253. * @private
  145254. */
  145255. ScreenSpaceCameraController.prototype.update = function() {
  145256. if (!Matrix4.equals(this._scene.camera.transform, Matrix4.IDENTITY)) {
  145257. this._globe = undefined;
  145258. this._ellipsoid = Ellipsoid.UNIT_SPHERE;
  145259. } else {
  145260. this._globe = this._scene.globe;
  145261. this._ellipsoid = defined(this._globe) ? this._globe.ellipsoid : this._scene.mapProjection.ellipsoid;
  145262. }
  145263. this._minimumCollisionTerrainHeight = this.minimumCollisionTerrainHeight * this._scene.terrainExaggeration;
  145264. this._minimumPickingTerrainHeight = this.minimumPickingTerrainHeight * this._scene.terrainExaggeration;
  145265. this._minimumTrackBallHeight = this.minimumTrackBallHeight * this._scene.terrainExaggeration;
  145266. var radius = this._ellipsoid.maximumRadius;
  145267. this._rotateFactor = 1.0 / radius;
  145268. this._rotateRateRangeAdjustment = radius;
  145269. var scene = this._scene;
  145270. var mode = scene.mode;
  145271. if (mode === SceneMode.SCENE2D) {
  145272. update2D(this);
  145273. } else if (mode === SceneMode.COLUMBUS_VIEW) {
  145274. this._horizontalRotationAxis = Cartesian3.UNIT_Z;
  145275. updateCV(this);
  145276. } else if (mode === SceneMode.SCENE3D) {
  145277. this._horizontalRotationAxis = undefined;
  145278. update3D(this);
  145279. }
  145280. this._aggregator.reset();
  145281. };
  145282. /**
  145283. * Returns true if this object was destroyed; otherwise, false.
  145284. * <br /><br />
  145285. * If this object was destroyed, it should not be used; calling any function other than
  145286. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  145287. *
  145288. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  145289. *
  145290. * @see ScreenSpaceCameraController#destroy
  145291. */
  145292. ScreenSpaceCameraController.prototype.isDestroyed = function() {
  145293. return false;
  145294. };
  145295. /**
  145296. * Removes mouse listeners held by this object.
  145297. * <br /><br />
  145298. * Once an object is destroyed, it should not be used; calling any function other than
  145299. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  145300. * assign the return value (<code>undefined</code>) to the object as done in the example.
  145301. *
  145302. * @returns {undefined}
  145303. *
  145304. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  145305. *
  145306. *
  145307. * @example
  145308. * controller = controller && controller.destroy();
  145309. *
  145310. * @see ScreenSpaceCameraController#isDestroyed
  145311. */
  145312. ScreenSpaceCameraController.prototype.destroy = function() {
  145313. this._tweens.removeAll();
  145314. this._aggregator = this._aggregator && this._aggregator.destroy();
  145315. return destroyObject(this);
  145316. };
  145317. return ScreenSpaceCameraController;
  145318. });
  145319. /*global define*/
  145320. define('Scene/ShadowMapShader',[
  145321. '../Core/defined',
  145322. '../Renderer/ShaderSource'
  145323. ], function(
  145324. defined,
  145325. ShaderSource) {
  145326. 'use strict';
  145327. /**
  145328. * @private
  145329. */
  145330. function ShadowMapShader() {
  145331. }
  145332. ShadowMapShader.createShadowCastVertexShader = function(vs, isPointLight, isTerrain) {
  145333. var defines = vs.defines.slice(0);
  145334. var sources = vs.sources.slice(0);
  145335. if (isTerrain) {
  145336. defines.push('GENERATE_POSITION');
  145337. }
  145338. var positionVaryingName = ShaderSource.findPositionVarying(vs);
  145339. var hasPositionVarying = defined(positionVaryingName);
  145340. if (isPointLight && !hasPositionVarying) {
  145341. var length = sources.length;
  145342. for (var j = 0; j < length; ++j) {
  145343. sources[j] = ShaderSource.replaceMain(sources[j], 'czm_shadow_cast_main');
  145344. }
  145345. var shadowVS =
  145346. 'varying vec3 v_positionEC; \n' +
  145347. 'void main() \n' +
  145348. '{ \n' +
  145349. ' czm_shadow_cast_main(); \n' +
  145350. ' v_positionEC = (czm_inverseProjection * gl_Position).xyz; \n' +
  145351. '}';
  145352. sources.push(shadowVS);
  145353. }
  145354. return new ShaderSource({
  145355. defines : defines,
  145356. sources : sources
  145357. });
  145358. };
  145359. ShadowMapShader.createShadowCastFragmentShader = function(fs, isPointLight, usesDepthTexture, opaque) {
  145360. var defines = fs.defines.slice(0);
  145361. var sources = fs.sources.slice(0);
  145362. var positionVaryingName = ShaderSource.findPositionVarying(fs);
  145363. var hasPositionVarying = defined(positionVaryingName);
  145364. if (!hasPositionVarying) {
  145365. positionVaryingName = 'v_positionEC';
  145366. }
  145367. var length = sources.length;
  145368. for (var i = 0; i < length; ++i) {
  145369. sources[i] = ShaderSource.replaceMain(sources[i], 'czm_shadow_cast_main');
  145370. }
  145371. var fsSource = '';
  145372. if (isPointLight) {
  145373. if (!hasPositionVarying) {
  145374. fsSource += 'varying vec3 v_positionEC; \n';
  145375. }
  145376. fsSource += 'uniform vec4 shadowMap_lightPositionEC; \n';
  145377. }
  145378. if (opaque) {
  145379. fsSource +=
  145380. 'void main() \n' +
  145381. '{ \n';
  145382. } else {
  145383. fsSource +=
  145384. 'void main() \n' +
  145385. '{ \n' +
  145386. ' czm_shadow_cast_main(); \n' +
  145387. ' if (gl_FragColor.a == 0.0) \n' +
  145388. ' { \n' +
  145389. ' discard; \n' +
  145390. ' } \n';
  145391. }
  145392. if (isPointLight) {
  145393. fsSource +=
  145394. 'float distance = length(' + positionVaryingName + '); \n' +
  145395. 'distance /= shadowMap_lightPositionEC.w; // radius \n' +
  145396. 'gl_FragColor = czm_packDepth(distance); \n';
  145397. } else if (usesDepthTexture) {
  145398. fsSource += 'gl_FragColor = vec4(1.0); \n';
  145399. } else {
  145400. fsSource += 'gl_FragColor = czm_packDepth(gl_FragCoord.z); \n';
  145401. }
  145402. fsSource += '} \n';
  145403. sources.push(fsSource);
  145404. return new ShaderSource({
  145405. defines : defines,
  145406. sources : sources
  145407. });
  145408. };
  145409. ShadowMapShader.createShadowReceiveVertexShader = function(vs, isTerrain, hasTerrainNormal) {
  145410. var defines = vs.defines.slice(0);
  145411. var sources = vs.sources.slice(0);
  145412. if (isTerrain) {
  145413. if (hasTerrainNormal) {
  145414. defines.push('GENERATE_POSITION_AND_NORMAL');
  145415. } else {
  145416. defines.push('GENERATE_POSITION');
  145417. }
  145418. }
  145419. return new ShaderSource({
  145420. defines : defines,
  145421. sources : sources
  145422. });
  145423. };
  145424. ShadowMapShader.createShadowReceiveFragmentShader = function(fs, shadowMap, castShadows, isTerrain, hasTerrainNormal) {
  145425. var normalVaryingName = ShaderSource.findNormalVarying(fs);
  145426. var hasNormalVarying = (!isTerrain && defined(normalVaryingName)) || (isTerrain && hasTerrainNormal);
  145427. var positionVaryingName = ShaderSource.findPositionVarying(fs);
  145428. var hasPositionVarying = defined(positionVaryingName);
  145429. var usesDepthTexture = shadowMap._usesDepthTexture;
  145430. var polygonOffsetSupported = shadowMap._polygonOffsetSupported;
  145431. var isPointLight = shadowMap._isPointLight;
  145432. var isSpotLight = shadowMap._isSpotLight;
  145433. var hasCascades = shadowMap._numberOfCascades > 1;
  145434. var debugCascadeColors = shadowMap.debugCascadeColors;
  145435. var softShadows = shadowMap.softShadows;
  145436. var bias = isPointLight ? shadowMap._pointBias : (isTerrain ? shadowMap._terrainBias : shadowMap._primitiveBias);
  145437. var defines = fs.defines.slice(0);
  145438. var sources = fs.sources.slice(0);
  145439. var length = sources.length;
  145440. for (var i = 0; i < length; ++i) {
  145441. sources[i] = ShaderSource.replaceMain(sources[i], 'czm_shadow_receive_main');
  145442. }
  145443. if (isPointLight) {
  145444. defines.push('USE_CUBE_MAP_SHADOW');
  145445. } else if (usesDepthTexture) {
  145446. defines.push('USE_SHADOW_DEPTH_TEXTURE');
  145447. }
  145448. if (softShadows && !isPointLight) {
  145449. defines.push('USE_SOFT_SHADOWS');
  145450. }
  145451. // Enable day-night shading so that the globe is dark when the light is below the horizon
  145452. if (hasCascades && castShadows && isTerrain) {
  145453. if (hasNormalVarying) {
  145454. defines.push('ENABLE_VERTEX_LIGHTING');
  145455. } else {
  145456. defines.push('ENABLE_DAYNIGHT_SHADING');
  145457. }
  145458. }
  145459. if (castShadows && bias.normalShading && hasNormalVarying) {
  145460. defines.push('USE_NORMAL_SHADING');
  145461. if (bias.normalShadingSmooth > 0.0) {
  145462. defines.push('USE_NORMAL_SHADING_SMOOTH');
  145463. }
  145464. }
  145465. var fsSource = '';
  145466. if (isPointLight) {
  145467. fsSource += 'uniform samplerCube shadowMap_textureCube; \n';
  145468. } else {
  145469. fsSource += 'uniform sampler2D shadowMap_texture; \n';
  145470. }
  145471. fsSource +=
  145472. 'uniform mat4 shadowMap_matrix; \n' +
  145473. 'uniform vec3 shadowMap_lightDirectionEC; \n' +
  145474. 'uniform vec4 shadowMap_lightPositionEC; \n' +
  145475. 'uniform vec4 shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness; \n' +
  145476. 'uniform vec4 shadowMap_texelSizeDepthBiasAndNormalShadingSmooth; \n' +
  145477. 'vec4 getPositionEC() \n' +
  145478. '{ \n' +
  145479. (hasPositionVarying ?
  145480. ' return vec4(' + positionVaryingName + ', 1.0); \n' :
  145481. ' return czm_windowToEyeCoordinates(gl_FragCoord); \n') +
  145482. '} \n' +
  145483. 'vec3 getNormalEC() \n' +
  145484. '{ \n' +
  145485. (hasNormalVarying ?
  145486. ' return normalize(' + normalVaryingName + '); \n' :
  145487. ' return vec3(1.0); \n') +
  145488. '} \n' +
  145489. // Offset the shadow position in the direction of the normal for perpendicular and back faces
  145490. 'void applyNormalOffset(inout vec4 positionEC, vec3 normalEC, float nDotL) \n' +
  145491. '{ \n' +
  145492. (bias.normalOffset && hasNormalVarying ?
  145493. ' float normalOffset = shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.x; \n' +
  145494. ' float normalOffsetScale = 1.0 - nDotL; \n' +
  145495. ' vec3 offset = normalOffset * normalOffsetScale * normalEC; \n' +
  145496. ' positionEC.xyz += offset; \n' : '') +
  145497. '} \n';
  145498. fsSource +=
  145499. 'void main() \n' +
  145500. '{ \n' +
  145501. ' czm_shadow_receive_main(); \n' +
  145502. ' vec4 positionEC = getPositionEC(); \n' +
  145503. ' vec3 normalEC = getNormalEC(); \n' +
  145504. ' float depth = -positionEC.z; \n';
  145505. fsSource +=
  145506. ' czm_shadowParameters shadowParameters; \n' +
  145507. ' shadowParameters.texelStepSize = shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.xy; \n' +
  145508. ' shadowParameters.depthBias = shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.z; \n' +
  145509. ' shadowParameters.normalShadingSmooth = shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.w; \n' +
  145510. ' shadowParameters.darkness = shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.w; \n';
  145511. if (isTerrain) {
  145512. // Scale depth bias based on view distance to reduce z-fighting in distant terrain
  145513. fsSource += ' shadowParameters.depthBias *= max(depth * 0.01, 1.0); \n';
  145514. } else if (!polygonOffsetSupported) {
  145515. // If polygon offset isn't supported push the depth back based on view, however this
  145516. // causes light leaking at further away views
  145517. fsSource += ' shadowParameters.depthBias *= mix(1.0, 100.0, depth * 0.0015); \n';
  145518. }
  145519. if (isPointLight) {
  145520. fsSource +=
  145521. ' vec3 directionEC = positionEC.xyz - shadowMap_lightPositionEC.xyz; \n' +
  145522. ' float distance = length(directionEC); \n' +
  145523. ' directionEC = normalize(directionEC); \n' +
  145524. ' float radius = shadowMap_lightPositionEC.w; \n' +
  145525. ' // Stop early if the fragment is beyond the point light radius \n' +
  145526. ' if (distance > radius) \n' +
  145527. ' { \n' +
  145528. ' return; \n' +
  145529. ' } \n' +
  145530. ' vec3 directionWC = czm_inverseViewRotation * directionEC; \n' +
  145531. ' shadowParameters.depth = distance / radius; \n' +
  145532. ' shadowParameters.nDotL = clamp(dot(normalEC, -directionEC), 0.0, 1.0); \n' +
  145533. ' shadowParameters.texCoords = directionWC; \n' +
  145534. ' float visibility = czm_shadowVisibility(shadowMap_textureCube, shadowParameters); \n';
  145535. } else if (isSpotLight) {
  145536. fsSource +=
  145537. ' vec3 directionEC = normalize(positionEC.xyz - shadowMap_lightPositionEC.xyz); \n' +
  145538. ' float nDotL = clamp(dot(normalEC, -directionEC), 0.0, 1.0); \n' +
  145539. ' applyNormalOffset(positionEC, normalEC, nDotL); \n' +
  145540. ' vec4 shadowPosition = shadowMap_matrix * positionEC; \n' +
  145541. ' // Spot light uses a perspective projection, so perform the perspective divide \n' +
  145542. ' shadowPosition /= shadowPosition.w; \n' +
  145543. ' // Stop early if the fragment is not in the shadow bounds \n' +
  145544. ' if (any(lessThan(shadowPosition.xyz, vec3(0.0))) || any(greaterThan(shadowPosition.xyz, vec3(1.0)))) \n' +
  145545. ' { \n' +
  145546. ' return; \n' +
  145547. ' } \n' +
  145548. ' shadowParameters.texCoords = shadowPosition.xy; \n' +
  145549. ' shadowParameters.depth = shadowPosition.z; \n' +
  145550. ' shadowParameters.nDotL = nDotL; \n' +
  145551. ' float visibility = czm_shadowVisibility(shadowMap_texture, shadowParameters); \n';
  145552. } else if (hasCascades) {
  145553. fsSource +=
  145554. ' float maxDepth = shadowMap_cascadeSplits[1].w; \n' +
  145555. ' // Stop early if the eye depth exceeds the last cascade \n' +
  145556. ' if (depth > maxDepth) \n' +
  145557. ' { \n' +
  145558. ' return; \n' +
  145559. ' } \n' +
  145560. ' // Get the cascade based on the eye-space depth \n' +
  145561. ' vec4 weights = czm_cascadeWeights(depth); \n' +
  145562. ' // Apply normal offset \n' +
  145563. ' float nDotL = clamp(dot(normalEC, shadowMap_lightDirectionEC), 0.0, 1.0); \n' +
  145564. ' applyNormalOffset(positionEC, normalEC, nDotL); \n' +
  145565. ' // Transform position into the cascade \n' +
  145566. ' vec4 shadowPosition = czm_cascadeMatrix(weights) * positionEC; \n' +
  145567. ' // Get visibility \n' +
  145568. ' shadowParameters.texCoords = shadowPosition.xy; \n' +
  145569. ' shadowParameters.depth = shadowPosition.z; \n' +
  145570. ' shadowParameters.nDotL = nDotL; \n' +
  145571. ' float visibility = czm_shadowVisibility(shadowMap_texture, shadowParameters); \n' +
  145572. ' // Fade out shadows that are far away \n' +
  145573. ' float shadowMapMaximumDistance = shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.z; \n' +
  145574. ' float fade = max((depth - shadowMapMaximumDistance * 0.8) / (shadowMapMaximumDistance * 0.2), 0.0); \n' +
  145575. ' visibility = mix(visibility, 1.0, fade); \n' +
  145576. (debugCascadeColors ?
  145577. ' // Draw cascade colors for debugging \n' +
  145578. ' gl_FragColor *= czm_cascadeColor(weights); \n' : '');
  145579. } else {
  145580. fsSource +=
  145581. ' float nDotL = clamp(dot(normalEC, shadowMap_lightDirectionEC), 0.0, 1.0); \n' +
  145582. ' applyNormalOffset(positionEC, normalEC, nDotL); \n' +
  145583. ' vec4 shadowPosition = shadowMap_matrix * positionEC; \n' +
  145584. ' // Stop early if the fragment is not in the shadow bounds \n' +
  145585. ' if (any(lessThan(shadowPosition.xyz, vec3(0.0))) || any(greaterThan(shadowPosition.xyz, vec3(1.0)))) \n' +
  145586. ' { \n' +
  145587. ' return; \n' +
  145588. ' } \n' +
  145589. ' shadowParameters.texCoords = shadowPosition.xy; \n' +
  145590. ' shadowParameters.depth = shadowPosition.z; \n' +
  145591. ' shadowParameters.nDotL = nDotL; \n' +
  145592. ' float visibility = czm_shadowVisibility(shadowMap_texture, shadowParameters); \n';
  145593. }
  145594. fsSource +=
  145595. ' gl_FragColor.rgb *= visibility; \n' +
  145596. '} \n';
  145597. sources.push(fsSource);
  145598. return new ShaderSource({
  145599. defines : defines,
  145600. sources : sources
  145601. });
  145602. };
  145603. return ShadowMapShader;
  145604. });
  145605. /*global define*/
  145606. define('Scene/ShadowMap',[
  145607. '../Core/BoundingRectangle',
  145608. '../Core/BoundingSphere',
  145609. '../Core/BoxOutlineGeometry',
  145610. '../Core/Cartesian2',
  145611. '../Core/Cartesian3',
  145612. '../Core/Cartesian4',
  145613. '../Core/Cartographic',
  145614. '../Core/clone',
  145615. '../Core/Color',
  145616. '../Core/ColorGeometryInstanceAttribute',
  145617. '../Core/combine',
  145618. '../Core/defaultValue',
  145619. '../Core/defined',
  145620. '../Core/defineProperties',
  145621. '../Core/destroyObject',
  145622. '../Core/DeveloperError',
  145623. '../Core/FeatureDetection',
  145624. '../Core/GeometryInstance',
  145625. '../Core/Intersect',
  145626. '../Core/Math',
  145627. '../Core/Matrix4',
  145628. '../Core/PixelFormat',
  145629. '../Core/Quaternion',
  145630. '../Core/SphereOutlineGeometry',
  145631. '../Core/WebGLConstants',
  145632. '../Renderer/ClearCommand',
  145633. '../Renderer/ContextLimits',
  145634. '../Renderer/CubeMap',
  145635. '../Renderer/DrawCommand',
  145636. '../Renderer/Framebuffer',
  145637. '../Renderer/Pass',
  145638. '../Renderer/PassState',
  145639. '../Renderer/PixelDatatype',
  145640. '../Renderer/Renderbuffer',
  145641. '../Renderer/RenderbufferFormat',
  145642. '../Renderer/RenderState',
  145643. '../Renderer/Sampler',
  145644. '../Renderer/ShaderProgram',
  145645. '../Renderer/Texture',
  145646. '../Renderer/TextureMagnificationFilter',
  145647. '../Renderer/TextureMinificationFilter',
  145648. '../Renderer/TextureWrap',
  145649. './Camera',
  145650. './CullFace',
  145651. './CullingVolume',
  145652. './DebugCameraPrimitive',
  145653. './OrthographicFrustum',
  145654. './PerInstanceColorAppearance',
  145655. './PerspectiveFrustum',
  145656. './Primitive',
  145657. './ShadowMapShader'
  145658. ], function(
  145659. BoundingRectangle,
  145660. BoundingSphere,
  145661. BoxOutlineGeometry,
  145662. Cartesian2,
  145663. Cartesian3,
  145664. Cartesian4,
  145665. Cartographic,
  145666. clone,
  145667. Color,
  145668. ColorGeometryInstanceAttribute,
  145669. combine,
  145670. defaultValue,
  145671. defined,
  145672. defineProperties,
  145673. destroyObject,
  145674. DeveloperError,
  145675. FeatureDetection,
  145676. GeometryInstance,
  145677. Intersect,
  145678. CesiumMath,
  145679. Matrix4,
  145680. PixelFormat,
  145681. Quaternion,
  145682. SphereOutlineGeometry,
  145683. WebGLConstants,
  145684. ClearCommand,
  145685. ContextLimits,
  145686. CubeMap,
  145687. DrawCommand,
  145688. Framebuffer,
  145689. Pass,
  145690. PassState,
  145691. PixelDatatype,
  145692. Renderbuffer,
  145693. RenderbufferFormat,
  145694. RenderState,
  145695. Sampler,
  145696. ShaderProgram,
  145697. Texture,
  145698. TextureMagnificationFilter,
  145699. TextureMinificationFilter,
  145700. TextureWrap,
  145701. Camera,
  145702. CullFace,
  145703. CullingVolume,
  145704. DebugCameraPrimitive,
  145705. OrthographicFrustum,
  145706. PerInstanceColorAppearance,
  145707. PerspectiveFrustum,
  145708. Primitive,
  145709. ShadowMapShader) {
  145710. 'use strict';
  145711. /**
  145712. * Creates a shadow map from the provided light camera.
  145713. *
  145714. * The normalOffset bias pushes the shadows forward slightly, and may be disabled
  145715. * for applications that require ultra precise shadows.
  145716. *
  145717. * @alias ShadowMap
  145718. * @constructor
  145719. *
  145720. * @param {Object} options An object containing the following properties:
  145721. * @param {Context} options.context The context in which to create the shadow map.
  145722. * @param {Camera} options.lightCamera A camera representing the light source.
  145723. * @param {Boolean} [options.enabled=true] Whether the shadow map is enabled.
  145724. * @param {Boolean} [options.isPointLight=false] Whether the light source is a point light. Point light shadows do not use cascades.
  145725. * @param {Boolean} [options.pointLightRadius=100.0] Radius of the point light.
  145726. * @param {Boolean} [options.cascadesEnabled=true] Use multiple shadow maps to cover different partitions of the view frustum.
  145727. * @param {Number} [options.numberOfCascades=4] The number of cascades to use for the shadow map. Supported values are one and four.
  145728. * @param {Number} [options.maximumDistance=5000.0] The maximum distance used for generating cascaded shadows. Lower values improve shadow quality.
  145729. * @param {Number} [options.size=2048] The width and height, in pixels, of each shadow map.
  145730. * @param {Boolean} [options.softShadows=false] Whether percentage-closer-filtering is enabled for producing softer shadows.
  145731. * @param {Number} [options.darkness=0.3] The shadow darkness.
  145732. *
  145733. * @exception {DeveloperError} Only one or four cascades are supported.
  145734. *
  145735. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Shadows.html|Cesium Sandcastle Shadows Demo}
  145736. */
  145737. function ShadowMap(options) {
  145738. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  145739. var context = options.context;
  145740. if (!defined(context)) {
  145741. throw new DeveloperError('context is required.');
  145742. }
  145743. if (!defined(options.lightCamera)) {
  145744. throw new DeveloperError('lightCamera is required.');
  145745. }
  145746. if (defined(options.numberOfCascades) && ((options.numberOfCascades !== 1) && (options.numberOfCascades !== 4))) {
  145747. throw new DeveloperError('Only one or four cascades are supported.');
  145748. }
  145749. this._enabled = defaultValue(options.enabled, true);
  145750. this._softShadows = defaultValue(options.softShadows, false);
  145751. this.dirty = true;
  145752. /**
  145753. * Specifies whether the shadow map originates from a light source. Shadow maps that are used for analytical
  145754. * purposes should set this to false so as not to affect scene rendering.
  145755. *
  145756. * @private
  145757. */
  145758. this.fromLightSource = defaultValue(options.fromLightSource, true);
  145759. /**
  145760. * Determines the darkness of the shadows.
  145761. *
  145762. * @type {Number}
  145763. * @default 0.3
  145764. */
  145765. this.darkness = defaultValue(options.darkness, 0.3);
  145766. this._darkness = this.darkness;
  145767. /**
  145768. * Determines the maximum distance of the shadow map. Only applicable for cascaded shadows. Larger distances may result in lower quality shadows.
  145769. *
  145770. * @type {Number}
  145771. * @default 5000.0
  145772. */
  145773. this.maximumDistance = defaultValue(options.maximumDistance, 5000.0);
  145774. this._outOfView = false;
  145775. this._outOfViewPrevious = false;
  145776. this._needsUpdate = true;
  145777. // In IE11 and Edge polygon offset is not functional.
  145778. // TODO : Also disabled for instances of Firefox and Chrome running ANGLE that do not support depth textures.
  145779. // Re-enable once https://github.com/AnalyticalGraphicsInc/cesium/issues/4560 is resolved.
  145780. var polygonOffsetSupported = true;
  145781. if (FeatureDetection.isInternetExplorer() || FeatureDetection.isEdge() || ((FeatureDetection.isChrome() || FeatureDetection.isFirefox()) && FeatureDetection.isWindows() && !context.depthTexture)) {
  145782. polygonOffsetSupported = false;
  145783. }
  145784. this._polygonOffsetSupported = polygonOffsetSupported;
  145785. this._terrainBias = {
  145786. polygonOffset : polygonOffsetSupported,
  145787. polygonOffsetFactor : 1.1,
  145788. polygonOffsetUnits : 4.0,
  145789. normalOffset : true,
  145790. normalOffsetScale : 0.5,
  145791. normalShading : true,
  145792. normalShadingSmooth : 0.3,
  145793. depthBias : 0.0001
  145794. };
  145795. this._primitiveBias = {
  145796. polygonOffset : polygonOffsetSupported,
  145797. polygonOffsetFactor : 1.1,
  145798. polygonOffsetUnits : 4.0,
  145799. normalOffset : true,
  145800. normalOffsetScale : 0.1,
  145801. normalShading : true,
  145802. normalShadingSmooth : 0.05,
  145803. depthBias : 0.00002
  145804. };
  145805. this._pointBias = {
  145806. polygonOffset : false,
  145807. polygonOffsetFactor : 1.1,
  145808. polygonOffsetUnits : 4.0,
  145809. normalOffset : false,
  145810. normalOffsetScale : 0.0,
  145811. normalShading : true,
  145812. normalShadingSmooth : 0.1,
  145813. depthBias : 0.0005
  145814. };
  145815. // Framebuffer resources
  145816. this._depthAttachment = undefined;
  145817. this._colorAttachment = undefined;
  145818. // Uniforms
  145819. this._shadowMapMatrix = new Matrix4();
  145820. this._shadowMapTexture = undefined;
  145821. this._lightDirectionEC = new Cartesian3();
  145822. this._lightPositionEC = new Cartesian4();
  145823. this._distance = 0.0;
  145824. this._lightCamera = options.lightCamera;
  145825. this._shadowMapCamera = new ShadowMapCamera();
  145826. this._shadowMapCullingVolume = undefined;
  145827. this._sceneCamera = undefined;
  145828. this._boundingSphere = new BoundingSphere();
  145829. this._isPointLight = defaultValue(options.isPointLight, false);
  145830. this._pointLightRadius = defaultValue(options.pointLightRadius, 100.0);
  145831. this._cascadesEnabled = this._isPointLight ? false : defaultValue(options.cascadesEnabled, true);
  145832. this._numberOfCascades = !this._cascadesEnabled ? 0 : defaultValue(options.numberOfCascades, 4);
  145833. this._fitNearFar = true;
  145834. this._maximumCascadeDistances = [25.0, 150.0, 700.0, Number.MAX_VALUE];
  145835. this._textureSize = new Cartesian2();
  145836. this._isSpotLight = false;
  145837. if (this._cascadesEnabled) {
  145838. // Cascaded shadows are always orthographic. The frustum dimensions are calculated on the fly.
  145839. this._shadowMapCamera.frustum = new OrthographicFrustum();
  145840. } else if (defined(this._lightCamera.frustum.fov)) {
  145841. // If the light camera uses a perspective frustum, then the light source is a spot light
  145842. this._isSpotLight = true;
  145843. }
  145844. // Uniforms
  145845. this._cascadeSplits = [new Cartesian4(), new Cartesian4()];
  145846. this._cascadeMatrices = [new Matrix4(), new Matrix4(), new Matrix4(), new Matrix4()];
  145847. this._cascadeDistances = new Cartesian4();
  145848. var numberOfPasses;
  145849. if (this._isPointLight) {
  145850. numberOfPasses = 6; // One shadow map for each direction
  145851. } else if (!this._cascadesEnabled) {
  145852. numberOfPasses = 1;
  145853. } else {
  145854. numberOfPasses = this._numberOfCascades;
  145855. }
  145856. this._passes = new Array(numberOfPasses);
  145857. for (var i = 0; i < numberOfPasses; ++i) {
  145858. this._passes[i] = new ShadowPass(context);
  145859. }
  145860. this.debugShow = false;
  145861. this.debugFreezeFrame = false;
  145862. this._debugFreezeFrame = false;
  145863. this._debugCascadeColors = false;
  145864. this._debugLightFrustum = undefined;
  145865. this._debugCameraFrustum = undefined;
  145866. this._debugCascadeFrustums = new Array(this._numberOfCascades);
  145867. this._debugShadowViewCommand = undefined;
  145868. this._usesDepthTexture = context.depthTexture;
  145869. if (this._isPointLight) {
  145870. this._usesDepthTexture = false;
  145871. }
  145872. // Create render states for shadow casters
  145873. this._primitiveRenderState = undefined;
  145874. this._terrainRenderState = undefined;
  145875. this._pointRenderState = undefined;
  145876. createRenderStates(this);
  145877. // For clearing the shadow map texture every frame
  145878. this._clearCommand = new ClearCommand({
  145879. depth : 1.0,
  145880. color : new Color()
  145881. });
  145882. this._clearPassState = new PassState(context);
  145883. this._size = defaultValue(options.size, 2048);
  145884. this.size = this._size;
  145885. }
  145886. /**
  145887. * Global maximum shadow distance used to prevent far off receivers from extending
  145888. * the shadow far plane. This helps set a tighter near/far when viewing objects from space.
  145889. *
  145890. * @private
  145891. */
  145892. ShadowMap.MAXIMUM_DISTANCE = 20000.0;
  145893. function ShadowPass(context) {
  145894. this.camera = new ShadowMapCamera();
  145895. this.passState = new PassState(context);
  145896. this.framebuffer = undefined;
  145897. this.textureOffsets = undefined;
  145898. this.commandList = [];
  145899. this.cullingVolume = undefined;
  145900. }
  145901. function createRenderState(colorMask, bias) {
  145902. return RenderState.fromCache({
  145903. cull : {
  145904. enabled : true,
  145905. face : CullFace.BACK
  145906. },
  145907. depthTest : {
  145908. enabled : true
  145909. },
  145910. colorMask : {
  145911. red : colorMask,
  145912. green : colorMask,
  145913. blue : colorMask,
  145914. alpha : colorMask
  145915. },
  145916. depthMask : true,
  145917. polygonOffset : {
  145918. enabled : bias.polygonOffset,
  145919. factor : bias.polygonOffsetFactor,
  145920. units : bias.polygonOffsetUnits
  145921. }
  145922. });
  145923. }
  145924. function createRenderStates(shadowMap) {
  145925. // Enable the color mask if the shadow map is backed by a color texture, e.g. when depth textures aren't supported
  145926. var colorMask = !shadowMap._usesDepthTexture;
  145927. shadowMap._primitiveRenderState = createRenderState(colorMask, shadowMap._primitiveBias);
  145928. shadowMap._terrainRenderState = createRenderState(colorMask, shadowMap._terrainBias);
  145929. shadowMap._pointRenderState = createRenderState(colorMask, shadowMap._pointBias);
  145930. }
  145931. /**
  145932. * @private
  145933. */
  145934. ShadowMap.prototype.debugCreateRenderStates = function() {
  145935. createRenderStates(this);
  145936. };
  145937. defineProperties(ShadowMap.prototype, {
  145938. /**
  145939. * Determines if the shadow map will be shown.
  145940. *
  145941. * @memberof ShadowMap.prototype
  145942. * @type {Boolean}
  145943. * @default true
  145944. */
  145945. enabled : {
  145946. get : function() {
  145947. return this._enabled;
  145948. },
  145949. set : function(value) {
  145950. this.dirty = this._enabled !== value;
  145951. this._enabled = value;
  145952. }
  145953. },
  145954. /**
  145955. * Determines if soft shadows are enabled. Uses pcf filtering which requires more texture reads and may hurt performance.
  145956. *
  145957. * @memberof ShadowMap.prototype
  145958. * @type {Boolean}
  145959. * @default false
  145960. */
  145961. softShadows : {
  145962. get : function() {
  145963. return this._softShadows;
  145964. },
  145965. set : function(value) {
  145966. this.dirty = this._softShadows !== value;
  145967. this._softShadows = value;
  145968. }
  145969. },
  145970. /**
  145971. * The width and height, in pixels, of each shadow map.
  145972. *
  145973. * @memberof ShadowMap.prototype
  145974. * @type {Number}
  145975. * @default 2048
  145976. */
  145977. size : {
  145978. get : function() {
  145979. return this._size;
  145980. },
  145981. set : function(value) {
  145982. resize(this, value);
  145983. }
  145984. },
  145985. /**
  145986. * Whether the shadow map is out of view of the scene camera.
  145987. *
  145988. * @memberof ShadowMap.prototype
  145989. * @type {Boolean}
  145990. * @readonly
  145991. * @private
  145992. */
  145993. outOfView : {
  145994. get : function() {
  145995. return this._outOfView;
  145996. }
  145997. },
  145998. /**
  145999. * The culling volume of the shadow frustum.
  146000. *
  146001. * @memberof ShadowMap.prototype
  146002. * @type {CullingVolume}
  146003. * @readonly
  146004. * @private
  146005. */
  146006. shadowMapCullingVolume : {
  146007. get : function() {
  146008. return this._shadowMapCullingVolume;
  146009. }
  146010. },
  146011. /**
  146012. * The passes used for rendering shadows. Each face of a point light or each cascade for a cascaded shadow map is a separate pass.
  146013. *
  146014. * @memberof ShadowMap.prototype
  146015. * @type {ShadowPass[]}
  146016. * @readonly
  146017. * @private
  146018. */
  146019. passes : {
  146020. get : function() {
  146021. return this._passes;
  146022. }
  146023. },
  146024. /**
  146025. * Whether the light source is a point light.
  146026. *
  146027. * @memberof ShadowMap.prototype
  146028. * @type {Boolean}
  146029. * @readonly
  146030. * @private
  146031. */
  146032. isPointLight : {
  146033. get : function() {
  146034. return this._isPointLight;
  146035. }
  146036. },
  146037. /**
  146038. * Debug option for visualizing the cascades by color.
  146039. *
  146040. * @memberof ShadowMap.prototype
  146041. * @type {Boolean}
  146042. * @default false
  146043. * @private
  146044. */
  146045. debugCascadeColors : {
  146046. get : function() {
  146047. return this._debugCascadeColors;
  146048. },
  146049. set : function(value) {
  146050. this.dirty = this._debugCascadeColors !== value;
  146051. this._debugCascadeColors = value;
  146052. }
  146053. }
  146054. });
  146055. function destroyFramebuffer(shadowMap) {
  146056. var length = shadowMap._passes.length;
  146057. for (var i = 0; i < length; ++i) {
  146058. var pass = shadowMap._passes[i];
  146059. var framebuffer = pass.framebuffer;
  146060. if (defined(framebuffer) && !framebuffer.isDestroyed()) {
  146061. framebuffer.destroy();
  146062. }
  146063. pass.framebuffer = undefined;
  146064. }
  146065. // Destroy the framebuffer attachments
  146066. shadowMap._depthAttachment = shadowMap._depthAttachment && shadowMap._depthAttachment.destroy();
  146067. shadowMap._colorAttachment = shadowMap._colorAttachment && shadowMap._colorAttachment.destroy();
  146068. }
  146069. function createSampler() {
  146070. return new Sampler({
  146071. wrapS : TextureWrap.CLAMP_TO_EDGE,
  146072. wrapT : TextureWrap.CLAMP_TO_EDGE,
  146073. minificationFilter : TextureMinificationFilter.NEAREST,
  146074. magnificationFilter : TextureMagnificationFilter.NEAREST
  146075. });
  146076. }
  146077. function createFramebufferColor(shadowMap, context) {
  146078. var depthRenderbuffer = new Renderbuffer({
  146079. context : context,
  146080. width : shadowMap._textureSize.x,
  146081. height : shadowMap._textureSize.y,
  146082. format : RenderbufferFormat.DEPTH_COMPONENT16
  146083. });
  146084. var colorTexture = new Texture({
  146085. context : context,
  146086. width : shadowMap._textureSize.x,
  146087. height : shadowMap._textureSize.y,
  146088. pixelFormat : PixelFormat.RGBA,
  146089. pixelDatatype : PixelDatatype.UNSIGNED_BYTE,
  146090. sampler : createSampler()
  146091. });
  146092. var framebuffer = new Framebuffer({
  146093. context : context,
  146094. depthRenderbuffer : depthRenderbuffer,
  146095. colorTextures : [colorTexture],
  146096. destroyAttachments : false
  146097. });
  146098. var length = shadowMap._passes.length;
  146099. for (var i = 0; i < length; ++i) {
  146100. var pass = shadowMap._passes[i];
  146101. pass.framebuffer = framebuffer;
  146102. pass.passState.framebuffer = framebuffer;
  146103. }
  146104. shadowMap._shadowMapTexture = colorTexture;
  146105. shadowMap._depthAttachment = depthRenderbuffer;
  146106. shadowMap._colorAttachment = colorTexture;
  146107. }
  146108. function createFramebufferDepth(shadowMap, context) {
  146109. var depthStencilTexture = new Texture({
  146110. context : context,
  146111. width : shadowMap._textureSize.x,
  146112. height : shadowMap._textureSize.y,
  146113. pixelFormat : PixelFormat.DEPTH_STENCIL,
  146114. pixelDatatype : PixelDatatype.UNSIGNED_INT_24_8,
  146115. sampler : createSampler()
  146116. });
  146117. var framebuffer = new Framebuffer({
  146118. context : context,
  146119. depthStencilTexture : depthStencilTexture,
  146120. destroyAttachments : false
  146121. });
  146122. var length = shadowMap._passes.length;
  146123. for (var i = 0; i < length; ++i) {
  146124. var pass = shadowMap._passes[i];
  146125. pass.framebuffer = framebuffer;
  146126. pass.passState.framebuffer = framebuffer;
  146127. }
  146128. shadowMap._shadowMapTexture = depthStencilTexture;
  146129. shadowMap._depthAttachment = depthStencilTexture;
  146130. }
  146131. function createFramebufferCube(shadowMap, context) {
  146132. var depthRenderbuffer = new Renderbuffer({
  146133. context : context,
  146134. width : shadowMap._textureSize.x,
  146135. height : shadowMap._textureSize.y,
  146136. format : RenderbufferFormat.DEPTH_COMPONENT16
  146137. });
  146138. var cubeMap = new CubeMap({
  146139. context : context,
  146140. width : shadowMap._textureSize.x,
  146141. height : shadowMap._textureSize.y,
  146142. pixelFormat : PixelFormat.RGBA,
  146143. pixelDatatype : PixelDatatype.UNSIGNED_BYTE,
  146144. sampler : createSampler()
  146145. });
  146146. var faces = [cubeMap.negativeX, cubeMap.negativeY, cubeMap.negativeZ, cubeMap.positiveX, cubeMap.positiveY, cubeMap.positiveZ];
  146147. for (var i = 0; i < 6; ++i) {
  146148. var framebuffer = new Framebuffer({
  146149. context : context,
  146150. depthRenderbuffer : depthRenderbuffer,
  146151. colorTextures : [faces[i]],
  146152. destroyAttachments : false
  146153. });
  146154. var pass = shadowMap._passes[i];
  146155. pass.framebuffer = framebuffer;
  146156. pass.passState.framebuffer = framebuffer;
  146157. }
  146158. shadowMap._shadowMapTexture = cubeMap;
  146159. shadowMap._depthAttachment = depthRenderbuffer;
  146160. shadowMap._colorAttachment = cubeMap;
  146161. }
  146162. function createFramebuffer(shadowMap, context) {
  146163. if (shadowMap._isPointLight) {
  146164. createFramebufferCube(shadowMap, context);
  146165. } else if (shadowMap._usesDepthTexture) {
  146166. createFramebufferDepth(shadowMap, context);
  146167. } else {
  146168. createFramebufferColor(shadowMap, context);
  146169. }
  146170. }
  146171. function checkFramebuffer(shadowMap, context) {
  146172. // Attempt to make an FBO with only a depth texture. If it fails, fallback to a color texture.
  146173. if (shadowMap._usesDepthTexture && (shadowMap._passes[0].framebuffer.status !== WebGLConstants.FRAMEBUFFER_COMPLETE)) {
  146174. shadowMap._usesDepthTexture = false;
  146175. createRenderStates(shadowMap);
  146176. destroyFramebuffer(shadowMap);
  146177. createFramebuffer(shadowMap, context);
  146178. }
  146179. }
  146180. function updateFramebuffer(shadowMap, context) {
  146181. if (!defined(shadowMap._passes[0].framebuffer) || (shadowMap._shadowMapTexture.width !== shadowMap._textureSize.x)) {
  146182. destroyFramebuffer(shadowMap);
  146183. createFramebuffer(shadowMap, context);
  146184. checkFramebuffer(shadowMap, context);
  146185. clearFramebuffer(shadowMap, context);
  146186. }
  146187. }
  146188. function clearFramebuffer(shadowMap, context, shadowPass) {
  146189. shadowPass = defaultValue(shadowPass, 0);
  146190. if (shadowMap._isPointLight || (shadowPass === 0)) {
  146191. shadowMap._clearCommand.framebuffer = shadowMap._passes[shadowPass].framebuffer;
  146192. shadowMap._clearCommand.execute(context, shadowMap._clearPassState);
  146193. }
  146194. }
  146195. function resize(shadowMap, size) {
  146196. shadowMap._size = size;
  146197. var passes = shadowMap._passes;
  146198. var numberOfPasses = passes.length;
  146199. var textureSize = shadowMap._textureSize;
  146200. if (shadowMap._isPointLight) {
  146201. size = (ContextLimits.maximumCubeMapSize >= size) ? size : ContextLimits.maximumCubeMapSize;
  146202. textureSize.x = size;
  146203. textureSize.y = size;
  146204. var faceViewport = new BoundingRectangle(0, 0, size, size);
  146205. passes[0].passState.viewport = faceViewport;
  146206. passes[1].passState.viewport = faceViewport;
  146207. passes[2].passState.viewport = faceViewport;
  146208. passes[3].passState.viewport = faceViewport;
  146209. passes[4].passState.viewport = faceViewport;
  146210. passes[5].passState.viewport = faceViewport;
  146211. } else if (numberOfPasses === 1) {
  146212. // +----+
  146213. // | 1 |
  146214. // +----+
  146215. size = (ContextLimits.maximumTextureSize >= size) ? size : ContextLimits.maximumTextureSize;
  146216. textureSize.x = size;
  146217. textureSize.y = size;
  146218. passes[0].passState.viewport = new BoundingRectangle(0, 0, size, size);
  146219. } else if (numberOfPasses === 4) {
  146220. // +----+----+
  146221. // | 3 | 4 |
  146222. // +----+----+
  146223. // | 1 | 2 |
  146224. // +----+----+
  146225. size = (ContextLimits.maximumTextureSize >= size * 2) ? size : ContextLimits.maximumTextureSize / 2;
  146226. textureSize.x = size * 2;
  146227. textureSize.y = size * 2;
  146228. passes[0].passState.viewport = new BoundingRectangle(0, 0, size, size);
  146229. passes[1].passState.viewport = new BoundingRectangle(size, 0, size, size);
  146230. passes[2].passState.viewport = new BoundingRectangle(0, size, size, size);
  146231. passes[3].passState.viewport = new BoundingRectangle(size, size, size, size);
  146232. }
  146233. // Update clear pass state
  146234. shadowMap._clearPassState.viewport = new BoundingRectangle(0, 0, textureSize.x, textureSize.y);
  146235. // Transforms shadow coordinates [0, 1] into the pass's region of the texture
  146236. for (var i = 0; i < numberOfPasses; ++i) {
  146237. var pass = passes[i];
  146238. var viewport = pass.passState.viewport;
  146239. var biasX = viewport.x / textureSize.x;
  146240. var biasY = viewport.y / textureSize.y;
  146241. var scaleX = viewport.width / textureSize.x;
  146242. var scaleY = viewport.height / textureSize.y;
  146243. pass.textureOffsets = new Matrix4(scaleX, 0.0, 0.0, biasX, 0.0, scaleY, 0.0, biasY, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);
  146244. }
  146245. }
  146246. var scratchViewport = new BoundingRectangle();
  146247. function createDebugShadowViewCommand(shadowMap, context) {
  146248. var fs;
  146249. if (shadowMap._isPointLight) {
  146250. fs = 'uniform samplerCube shadowMap_textureCube; \n' +
  146251. 'varying vec2 v_textureCoordinates; \n' +
  146252. 'void main() \n' +
  146253. '{ \n' +
  146254. ' vec2 uv = v_textureCoordinates; \n' +
  146255. ' vec3 dir; \n' +
  146256. ' \n' +
  146257. ' if (uv.y < 0.5) \n' +
  146258. ' { \n' +
  146259. ' if (uv.x < 0.333) \n' +
  146260. ' { \n' +
  146261. ' dir.x = -1.0; \n' +
  146262. ' dir.y = uv.x * 6.0 - 1.0; \n' +
  146263. ' dir.z = uv.y * 4.0 - 1.0; \n' +
  146264. ' } \n' +
  146265. ' else if (uv.x < 0.666) \n' +
  146266. ' { \n' +
  146267. ' dir.y = -1.0; \n' +
  146268. ' dir.x = uv.x * 6.0 - 3.0; \n' +
  146269. ' dir.z = uv.y * 4.0 - 1.0; \n' +
  146270. ' } \n' +
  146271. ' else \n' +
  146272. ' { \n' +
  146273. ' dir.z = -1.0; \n' +
  146274. ' dir.x = uv.x * 6.0 - 5.0; \n' +
  146275. ' dir.y = uv.y * 4.0 - 1.0; \n' +
  146276. ' } \n' +
  146277. ' } \n' +
  146278. ' else \n' +
  146279. ' { \n' +
  146280. ' if (uv.x < 0.333) \n' +
  146281. ' { \n' +
  146282. ' dir.x = 1.0; \n' +
  146283. ' dir.y = uv.x * 6.0 - 1.0; \n' +
  146284. ' dir.z = uv.y * 4.0 - 3.0; \n' +
  146285. ' } \n' +
  146286. ' else if (uv.x < 0.666) \n' +
  146287. ' { \n' +
  146288. ' dir.y = 1.0; \n' +
  146289. ' dir.x = uv.x * 6.0 - 3.0; \n' +
  146290. ' dir.z = uv.y * 4.0 - 3.0; \n' +
  146291. ' } \n' +
  146292. ' else \n' +
  146293. ' { \n' +
  146294. ' dir.z = 1.0; \n' +
  146295. ' dir.x = uv.x * 6.0 - 5.0; \n' +
  146296. ' dir.y = uv.y * 4.0 - 3.0; \n' +
  146297. ' } \n' +
  146298. ' } \n' +
  146299. ' \n' +
  146300. ' float shadow = czm_unpackDepth(textureCube(shadowMap_textureCube, dir)); \n' +
  146301. ' gl_FragColor = vec4(vec3(shadow), 1.0); \n' +
  146302. '} \n';
  146303. } else {
  146304. fs = 'uniform sampler2D shadowMap_texture; \n' +
  146305. 'varying vec2 v_textureCoordinates; \n' +
  146306. 'void main() \n' +
  146307. '{ \n' +
  146308. (shadowMap._usesDepthTexture ?
  146309. ' float shadow = texture2D(shadowMap_texture, v_textureCoordinates).r; \n' :
  146310. ' float shadow = czm_unpackDepth(texture2D(shadowMap_texture, v_textureCoordinates)); \n') +
  146311. ' gl_FragColor = vec4(vec3(shadow), 1.0); \n' +
  146312. '} \n';
  146313. }
  146314. var drawCommand = context.createViewportQuadCommand(fs, {
  146315. uniformMap : {
  146316. shadowMap_texture : function() {
  146317. return shadowMap._shadowMapTexture;
  146318. },
  146319. shadowMap_textureCube : function() {
  146320. return shadowMap._shadowMapTexture;
  146321. }
  146322. }
  146323. });
  146324. drawCommand.pass = Pass.OVERLAY;
  146325. return drawCommand;
  146326. }
  146327. function updateDebugShadowViewCommand(shadowMap, frameState) {
  146328. // Draws the shadow map on the bottom-right corner of the screen
  146329. var context = frameState.context;
  146330. var screenWidth = frameState.context.drawingBufferWidth;
  146331. var screenHeight = frameState.context.drawingBufferHeight;
  146332. var size = Math.min(screenWidth, screenHeight) * 0.3;
  146333. var viewport = scratchViewport;
  146334. viewport.x = screenWidth - size;
  146335. viewport.y = 0;
  146336. viewport.width = size;
  146337. viewport.height = size;
  146338. var debugCommand = shadowMap._debugShadowViewCommand;
  146339. if (!defined(debugCommand)) {
  146340. debugCommand = createDebugShadowViewCommand(shadowMap, context);
  146341. shadowMap._debugShadowViewCommand = debugCommand;
  146342. }
  146343. // Get a new RenderState for the updated viewport size
  146344. if (!defined(debugCommand.renderState) || !BoundingRectangle.equals(debugCommand.renderState.viewport, viewport)) {
  146345. debugCommand.renderState = RenderState.fromCache({
  146346. viewport : BoundingRectangle.clone(viewport)
  146347. });
  146348. }
  146349. frameState.commandList.push(shadowMap._debugShadowViewCommand);
  146350. }
  146351. var frustumCornersNDC = new Array(8);
  146352. frustumCornersNDC[0] = new Cartesian4(-1.0, -1.0, -1.0, 1.0);
  146353. frustumCornersNDC[1] = new Cartesian4(1.0, -1.0, -1.0, 1.0);
  146354. frustumCornersNDC[2] = new Cartesian4(1.0, 1.0, -1.0, 1.0);
  146355. frustumCornersNDC[3] = new Cartesian4(-1.0, 1.0, -1.0, 1.0);
  146356. frustumCornersNDC[4] = new Cartesian4(-1.0, -1.0, 1.0, 1.0);
  146357. frustumCornersNDC[5] = new Cartesian4(1.0, -1.0, 1.0, 1.0);
  146358. frustumCornersNDC[6] = new Cartesian4(1.0, 1.0, 1.0, 1.0);
  146359. frustumCornersNDC[7] = new Cartesian4(-1.0, 1.0, 1.0, 1.0);
  146360. var scratchMatrix = new Matrix4();
  146361. var scratchFrustumCorners = new Array(8);
  146362. for (var i = 0; i < 8; ++i) {
  146363. scratchFrustumCorners[i] = new Cartesian4();
  146364. }
  146365. function createDebugPointLight(modelMatrix, color) {
  146366. var box = new GeometryInstance({
  146367. geometry : new BoxOutlineGeometry({
  146368. minimum : new Cartesian3(-0.5, -0.5, -0.5),
  146369. maximum : new Cartesian3(0.5, 0.5, 0.5)
  146370. }),
  146371. attributes : {
  146372. color : ColorGeometryInstanceAttribute.fromColor(color)
  146373. }
  146374. });
  146375. var sphere = new GeometryInstance({
  146376. geometry : new SphereOutlineGeometry({
  146377. radius : 0.5
  146378. }),
  146379. attributes : {
  146380. color : ColorGeometryInstanceAttribute.fromColor(color)
  146381. }
  146382. });
  146383. return new Primitive({
  146384. geometryInstances : [box, sphere],
  146385. appearance : new PerInstanceColorAppearance({
  146386. translucent : false,
  146387. flat : true
  146388. }),
  146389. asynchronous : false,
  146390. modelMatrix : modelMatrix
  146391. });
  146392. }
  146393. var debugOutlineColors = [Color.RED, Color.GREEN, Color.BLUE, Color.MAGENTA];
  146394. var scratchScale = new Cartesian3();
  146395. function applyDebugSettings(shadowMap, frameState) {
  146396. updateDebugShadowViewCommand(shadowMap, frameState);
  146397. var enterFreezeFrame = shadowMap.debugFreezeFrame && !shadowMap._debugFreezeFrame;
  146398. shadowMap._debugFreezeFrame = shadowMap.debugFreezeFrame;
  146399. // Draw scene camera in freeze frame mode
  146400. if (shadowMap.debugFreezeFrame) {
  146401. if (enterFreezeFrame) {
  146402. // Recreate debug camera when entering freeze frame mode
  146403. shadowMap._debugCameraFrustum = shadowMap._debugCameraFrustum && shadowMap._debugCameraFrustum.destroy();
  146404. shadowMap._debugCameraFrustum = new DebugCameraPrimitive({
  146405. camera : shadowMap._sceneCamera,
  146406. color : Color.CYAN,
  146407. updateOnChange : false
  146408. });
  146409. }
  146410. shadowMap._debugCameraFrustum.update(frameState);
  146411. }
  146412. if (shadowMap._cascadesEnabled) {
  146413. // Draw cascades only in freeze frame mode
  146414. if (shadowMap.debugFreezeFrame) {
  146415. if (enterFreezeFrame) {
  146416. // Recreate debug frustum when entering freeze frame mode
  146417. shadowMap._debugLightFrustum = shadowMap._debugLightFrustum && shadowMap._debugLightFrustum.destroy();
  146418. shadowMap._debugLightFrustum = new DebugCameraPrimitive({
  146419. camera : shadowMap._shadowMapCamera,
  146420. color : Color.YELLOW,
  146421. updateOnChange : false
  146422. });
  146423. }
  146424. shadowMap._debugLightFrustum.update(frameState);
  146425. for (var i = 0; i < shadowMap._numberOfCascades; ++i) {
  146426. if (enterFreezeFrame) {
  146427. // Recreate debug frustum when entering freeze frame mode
  146428. shadowMap._debugCascadeFrustums[i] = shadowMap._debugCascadeFrustums[i] && shadowMap._debugCascadeFrustums[i].destroy();
  146429. shadowMap._debugCascadeFrustums[i] = new DebugCameraPrimitive({
  146430. camera : shadowMap._passes[i].camera,
  146431. color : debugOutlineColors[i],
  146432. updateOnChange : false
  146433. });
  146434. }
  146435. shadowMap._debugCascadeFrustums[i].update(frameState);
  146436. }
  146437. }
  146438. } else if (shadowMap._isPointLight) {
  146439. if (!defined(shadowMap._debugLightFrustum) || shadowMap._needsUpdate) {
  146440. var translation = shadowMap._shadowMapCamera.positionWC;
  146441. var rotation = Quaternion.IDENTITY;
  146442. var uniformScale = shadowMap._pointLightRadius * 2.0;
  146443. var scale = Cartesian3.fromElements(uniformScale, uniformScale, uniformScale, scratchScale);
  146444. var modelMatrix = Matrix4.fromTranslationQuaternionRotationScale(translation, rotation, scale, scratchMatrix);
  146445. shadowMap._debugLightFrustum = shadowMap._debugLightFrustum && shadowMap._debugLightFrustum.destroy();
  146446. shadowMap._debugLightFrustum = createDebugPointLight(modelMatrix, Color.YELLOW);
  146447. }
  146448. shadowMap._debugLightFrustum.update(frameState);
  146449. } else {
  146450. if (!defined(shadowMap._debugLightFrustum) || shadowMap._needsUpdate) {
  146451. shadowMap._debugLightFrustum = new DebugCameraPrimitive({
  146452. camera : shadowMap._shadowMapCamera,
  146453. color : Color.YELLOW,
  146454. updateOnChange : false
  146455. });
  146456. }
  146457. shadowMap._debugLightFrustum.update(frameState);
  146458. }
  146459. }
  146460. function ShadowMapCamera() {
  146461. this.viewMatrix = new Matrix4();
  146462. this.inverseViewMatrix = new Matrix4();
  146463. this.frustum = undefined;
  146464. this.positionCartographic = new Cartographic();
  146465. this.positionWC = new Cartesian3();
  146466. this.directionWC = Cartesian3.clone(Cartesian3.UNIT_Z);
  146467. this.upWC = Cartesian3.clone(Cartesian3.UNIT_Y);
  146468. this.rightWC = Cartesian3.clone(Cartesian3.UNIT_X);
  146469. this.viewProjectionMatrix = new Matrix4();
  146470. }
  146471. ShadowMapCamera.prototype.clone = function(camera) {
  146472. Matrix4.clone(camera.viewMatrix, this.viewMatrix);
  146473. Matrix4.clone(camera.inverseViewMatrix, this.inverseViewMatrix);
  146474. this.frustum = camera.frustum.clone(this.frustum);
  146475. Cartographic.clone(camera.positionCartographic, this.positionCartographic);
  146476. Cartesian3.clone(camera.positionWC, this.positionWC);
  146477. Cartesian3.clone(camera.directionWC, this.directionWC);
  146478. Cartesian3.clone(camera.upWC, this.upWC);
  146479. Cartesian3.clone(camera.rightWC, this.rightWC);
  146480. };
  146481. // Converts from NDC space to texture space
  146482. var scaleBiasMatrix = new Matrix4(0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0);
  146483. ShadowMapCamera.prototype.getViewProjection = function() {
  146484. var view = this.viewMatrix;
  146485. var projection = this.frustum.projectionMatrix;
  146486. Matrix4.multiply(projection, view, this.viewProjectionMatrix);
  146487. Matrix4.multiply(scaleBiasMatrix, this.viewProjectionMatrix, this.viewProjectionMatrix);
  146488. return this.viewProjectionMatrix;
  146489. };
  146490. var scratchSplits = new Array(5);
  146491. var scratchFrustum = new PerspectiveFrustum();
  146492. var scratchCascadeDistances = new Array(4);
  146493. function computeCascades(shadowMap, frameState) {
  146494. var shadowMapCamera = shadowMap._shadowMapCamera;
  146495. var sceneCamera = shadowMap._sceneCamera;
  146496. var cameraNear = sceneCamera.frustum.near;
  146497. var cameraFar = sceneCamera.frustum.far;
  146498. var numberOfCascades = shadowMap._numberOfCascades;
  146499. // Split cascades. Use a mix of linear and log splits.
  146500. var i;
  146501. var range = cameraFar - cameraNear;
  146502. var ratio = cameraFar / cameraNear;
  146503. var lambda = 0.9;
  146504. var clampCascadeDistances = false;
  146505. // When the camera is close to a relatively small model, provide more detail in the closer cascades.
  146506. // If the camera is near or inside a large model, such as the root tile of a city, then use the default values.
  146507. // To get the most accurate cascade splits we would need to find the min and max values from the depth texture.
  146508. if (frameState.shadowHints.closestObjectSize < 200.0) {
  146509. clampCascadeDistances = true;
  146510. lambda = 0.9;
  146511. }
  146512. var cascadeDistances = scratchCascadeDistances;
  146513. var splits = scratchSplits;
  146514. splits[0] = cameraNear;
  146515. splits[numberOfCascades] = cameraFar;
  146516. // Find initial splits
  146517. for (i = 0; i < numberOfCascades; ++i) {
  146518. var p = (i + 1) / numberOfCascades;
  146519. var logScale = cameraNear * Math.pow(ratio, p);
  146520. var uniformScale = cameraNear + range * p;
  146521. var split = CesiumMath.lerp(uniformScale, logScale, lambda);
  146522. splits[i + 1] = split;
  146523. cascadeDistances[i] = split - splits[i];
  146524. }
  146525. if (clampCascadeDistances) {
  146526. // Clamp each cascade to its maximum distance
  146527. for (i = 0; i < numberOfCascades; ++i) {
  146528. cascadeDistances[i] = Math.min(cascadeDistances[i], shadowMap._maximumCascadeDistances[i]);
  146529. }
  146530. // Recompute splits
  146531. var distance = splits[0];
  146532. for (i = 0; i < numberOfCascades - 1; ++i) {
  146533. distance += cascadeDistances[i];
  146534. splits[i + 1] = distance;
  146535. }
  146536. }
  146537. Cartesian4.unpack(splits, 0, shadowMap._cascadeSplits[0]);
  146538. Cartesian4.unpack(splits, 1, shadowMap._cascadeSplits[1]);
  146539. Cartesian4.unpack(cascadeDistances, 0, shadowMap._cascadeDistances);
  146540. var shadowFrustum = shadowMapCamera.frustum;
  146541. var left = shadowFrustum.left;
  146542. var right = shadowFrustum.right;
  146543. var bottom = shadowFrustum.bottom;
  146544. var top = shadowFrustum.top;
  146545. var near = shadowFrustum.near;
  146546. var far = shadowFrustum.far;
  146547. var position = shadowMapCamera.positionWC;
  146548. var direction = shadowMapCamera.directionWC;
  146549. var up = shadowMapCamera.upWC;
  146550. var cascadeSubFrustum = sceneCamera.frustum.clone(scratchFrustum);
  146551. var shadowViewProjection = shadowMapCamera.getViewProjection();
  146552. for (i = 0; i < numberOfCascades; ++i) {
  146553. // Find the bounding box of the camera sub-frustum in shadow map texture space
  146554. cascadeSubFrustum.near = splits[i];
  146555. cascadeSubFrustum.far = splits[i + 1];
  146556. var viewProjection = Matrix4.multiply(cascadeSubFrustum.projectionMatrix, sceneCamera.viewMatrix, scratchMatrix);
  146557. var inverseViewProjection = Matrix4.inverse(viewProjection, scratchMatrix);
  146558. var shadowMapMatrix = Matrix4.multiply(shadowViewProjection, inverseViewProjection, scratchMatrix);
  146559. // Project each corner from camera NDC space to shadow map texture space. Min and max will be from 0 to 1.
  146560. var min = Cartesian3.fromElements(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE, scratchMin);
  146561. var max = Cartesian3.fromElements(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE, scratchMax);
  146562. for (var k = 0; k < 8; ++k) {
  146563. var corner = Cartesian4.clone(frustumCornersNDC[k], scratchFrustumCorners[k]);
  146564. Matrix4.multiplyByVector(shadowMapMatrix, corner, corner);
  146565. Cartesian3.divideByScalar(corner, corner.w, corner); // Handle the perspective divide
  146566. Cartesian3.minimumByComponent(corner, min, min);
  146567. Cartesian3.maximumByComponent(corner, max, max);
  146568. }
  146569. // Limit light-space coordinates to the [0, 1] range
  146570. min.x = Math.max(min.x, 0.0);
  146571. min.y = Math.max(min.y, 0.0);
  146572. min.z = 0.0; // Always start cascade frustum at the top of the light frustum to capture objects in the light's path
  146573. max.x = Math.min(max.x, 1.0);
  146574. max.y = Math.min(max.y, 1.0);
  146575. max.z = Math.min(max.z, 1.0);
  146576. var pass = shadowMap._passes[i];
  146577. var cascadeCamera = pass.camera;
  146578. cascadeCamera.clone(shadowMapCamera); // PERFORMANCE_IDEA : could do a shallow clone for all properties except the frustum
  146579. var frustum = cascadeCamera.frustum;
  146580. frustum.left = left + min.x * (right - left);
  146581. frustum.right = left + max.x * (right - left);
  146582. frustum.bottom = bottom + min.y * (top - bottom);
  146583. frustum.top = bottom + max.y * (top - bottom);
  146584. frustum.near = near + min.z * (far - near);
  146585. frustum.far = near + max.z * (far - near);
  146586. pass.cullingVolume = cascadeCamera.frustum.computeCullingVolume(position, direction, up);
  146587. // Transforms from eye space to the cascade's texture space
  146588. var cascadeMatrix = shadowMap._cascadeMatrices[i];
  146589. Matrix4.multiply(cascadeCamera.getViewProjection(), sceneCamera.inverseViewMatrix, cascadeMatrix);
  146590. Matrix4.multiply(pass.textureOffsets, cascadeMatrix, cascadeMatrix);
  146591. }
  146592. }
  146593. var scratchLightView = new Matrix4();
  146594. var scratchRight = new Cartesian3();
  146595. var scratchUp = new Cartesian3();
  146596. var scratchMin = new Cartesian3();
  146597. var scratchMax = new Cartesian3();
  146598. var scratchTranslation = new Cartesian3();
  146599. function fitShadowMapToScene(shadowMap, frameState) {
  146600. var shadowMapCamera = shadowMap._shadowMapCamera;
  146601. var sceneCamera = shadowMap._sceneCamera;
  146602. // 1. First find a tight bounding box in light space that contains the entire camera frustum.
  146603. var viewProjection = Matrix4.multiply(sceneCamera.frustum.projectionMatrix, sceneCamera.viewMatrix, scratchMatrix);
  146604. var inverseViewProjection = Matrix4.inverse(viewProjection, scratchMatrix);
  146605. // Start to construct the light view matrix. Set translation later once the bounding box is found.
  146606. var lightDir = shadowMapCamera.directionWC;
  146607. var lightUp = sceneCamera.directionWC; // Align shadows to the camera view.
  146608. var lightRight = Cartesian3.cross(lightDir, lightUp, scratchRight);
  146609. lightUp = Cartesian3.cross(lightRight, lightDir, scratchUp); // Recalculate up now that right is derived
  146610. Cartesian3.normalize(lightUp, lightUp);
  146611. Cartesian3.normalize(lightRight, lightRight);
  146612. var lightPosition = Cartesian3.fromElements(0.0, 0.0, 0.0, scratchTranslation);
  146613. var lightView = Matrix4.computeView(lightPosition, lightDir, lightUp, lightRight, scratchLightView);
  146614. var cameraToLight = Matrix4.multiply(lightView, inverseViewProjection, scratchMatrix);
  146615. // Project each corner from NDC space to light view space, and calculate a min and max in light view space
  146616. var min = Cartesian3.fromElements(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE, scratchMin);
  146617. var max = Cartesian3.fromElements(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE, scratchMax);
  146618. for (var i = 0; i < 8; ++i) {
  146619. var corner = Cartesian4.clone(frustumCornersNDC[i], scratchFrustumCorners[i]);
  146620. Matrix4.multiplyByVector(cameraToLight, corner, corner);
  146621. Cartesian3.divideByScalar(corner, corner.w, corner); // Handle the perspective divide
  146622. Cartesian3.minimumByComponent(corner, min, min);
  146623. Cartesian3.maximumByComponent(corner, max, max);
  146624. }
  146625. // 2. Set bounding box back to include objects in the light's view
  146626. max.z += 1000.0; // Note: in light space, a positive number is behind the camera
  146627. min.z -= 10.0; // Extend the shadow volume forward slightly to avoid problems right at the edge
  146628. // 3. Adjust light view matrix so that it is centered on the bounding volume
  146629. var translation = scratchTranslation;
  146630. translation.x = -(0.5 * (min.x + max.x));
  146631. translation.y = -(0.5 * (min.y + max.y));
  146632. translation.z = -max.z;
  146633. var translationMatrix = Matrix4.fromTranslation(translation, scratchMatrix);
  146634. lightView = Matrix4.multiply(translationMatrix, lightView, lightView);
  146635. // 4. Create an orthographic frustum that covers the bounding box extents
  146636. var halfWidth = 0.5 * (max.x - min.x);
  146637. var halfHeight = 0.5 * (max.y - min.y);
  146638. var depth = max.z - min.z;
  146639. var frustum = shadowMapCamera.frustum;
  146640. frustum.left = -halfWidth;
  146641. frustum.right = halfWidth;
  146642. frustum.bottom = -halfHeight;
  146643. frustum.top = halfHeight;
  146644. frustum.near = 0.01;
  146645. frustum.far = depth;
  146646. // 5. Update the shadow map camera
  146647. Matrix4.clone(lightView, shadowMapCamera.viewMatrix);
  146648. Matrix4.inverse(lightView, shadowMapCamera.inverseViewMatrix);
  146649. Matrix4.getTranslation(shadowMapCamera.inverseViewMatrix, shadowMapCamera.positionWC);
  146650. frameState.mapProjection.ellipsoid.cartesianToCartographic(shadowMapCamera.positionWC, shadowMapCamera.positionCartographic);
  146651. Cartesian3.clone(lightDir, shadowMapCamera.directionWC);
  146652. Cartesian3.clone(lightUp, shadowMapCamera.upWC);
  146653. Cartesian3.clone(lightRight, shadowMapCamera.rightWC);
  146654. }
  146655. var directions = [
  146656. new Cartesian3(-1.0, 0.0, 0.0),
  146657. new Cartesian3(0.0, -1.0, 0.0),
  146658. new Cartesian3(0.0, 0.0, -1.0),
  146659. new Cartesian3(1.0, 0.0, 0.0),
  146660. new Cartesian3(0.0, 1.0, 0.0),
  146661. new Cartesian3(0.0, 0.0, 1.0)
  146662. ];
  146663. var ups = [
  146664. new Cartesian3(0.0, -1.0, 0.0),
  146665. new Cartesian3(0.0, 0.0, -1.0),
  146666. new Cartesian3(0.0, -1.0, 0.0),
  146667. new Cartesian3(0.0, -1.0, 0.0),
  146668. new Cartesian3(0.0, 0.0, 1.0),
  146669. new Cartesian3(0.0, -1.0, 0.0)
  146670. ];
  146671. var rights = [
  146672. new Cartesian3(0.0, 0.0, 1.0),
  146673. new Cartesian3(1.0, 0.0, 0.0),
  146674. new Cartesian3(-1.0, 0.0, 0.0),
  146675. new Cartesian3(0.0, 0.0, -1.0),
  146676. new Cartesian3(1.0, 0.0, 0.0),
  146677. new Cartesian3(1.0, 0.0, 0.0)
  146678. ];
  146679. function computeOmnidirectional(shadowMap, frameState) {
  146680. // All sides share the same frustum
  146681. var frustum = new PerspectiveFrustum();
  146682. frustum.fov = CesiumMath.PI_OVER_TWO;
  146683. frustum.near = 1.0;
  146684. frustum.far = shadowMap._pointLightRadius;
  146685. frustum.aspectRatio = 1.0;
  146686. for (var i = 0; i < 6; ++i) {
  146687. var camera = shadowMap._passes[i].camera;
  146688. camera.positionWC = shadowMap._shadowMapCamera.positionWC;
  146689. camera.positionCartographic = frameState.mapProjection.ellipsoid.cartesianToCartographic(camera.positionWC, camera.positionCartographic);
  146690. camera.directionWC = directions[i];
  146691. camera.upWC = ups[i];
  146692. camera.rightWC = rights[i];
  146693. Matrix4.computeView(camera.positionWC, camera.directionWC, camera.upWC, camera.rightWC, camera.viewMatrix);
  146694. Matrix4.inverse(camera.viewMatrix, camera.inverseViewMatrix);
  146695. camera.frustum = frustum;
  146696. }
  146697. }
  146698. var scratchCartesian1 = new Cartesian3();
  146699. var scratchCartesian2 = new Cartesian3();
  146700. var scratchBoundingSphere = new BoundingSphere();
  146701. var scratchCenter = scratchBoundingSphere.center;
  146702. function checkVisibility(shadowMap, frameState) {
  146703. var sceneCamera = shadowMap._sceneCamera;
  146704. var shadowMapCamera = shadowMap._shadowMapCamera;
  146705. var boundingSphere = scratchBoundingSphere;
  146706. // Check whether the shadow map is in view and needs to be updated
  146707. if (shadowMap._cascadesEnabled) {
  146708. // If the nearest shadow receiver is further than the shadow map's maximum distance then the shadow map is out of view.
  146709. if (sceneCamera.frustum.near >= shadowMap.maximumDistance) {
  146710. shadowMap._outOfView = true;
  146711. shadowMap._needsUpdate = false;
  146712. return;
  146713. }
  146714. // If the light source is below the horizon then the shadow map is out of view
  146715. var surfaceNormal = frameState.mapProjection.ellipsoid.geodeticSurfaceNormal(sceneCamera.positionWC, scratchCartesian1);
  146716. var lightDirection = Cartesian3.negate(shadowMapCamera.directionWC, scratchCartesian2);
  146717. var dot = Cartesian3.dot(surfaceNormal, lightDirection);
  146718. // Shadows start to fade out once the light gets closer to the horizon.
  146719. // At this point the globe uses vertex lighting alone to darken the surface.
  146720. var darknessAmount = CesiumMath.clamp(dot / 0.1, 0.0, 1.0);
  146721. shadowMap._darkness = CesiumMath.lerp(1.0, shadowMap.darkness, darknessAmount);
  146722. if (dot < 0.0) {
  146723. shadowMap._outOfView = true;
  146724. shadowMap._needsUpdate = false;
  146725. return;
  146726. }
  146727. // By default cascaded shadows need to update and are always in view
  146728. shadowMap._needsUpdate = true;
  146729. shadowMap._outOfView = false;
  146730. } else if (shadowMap._isPointLight) {
  146731. // Sphere-frustum intersection test
  146732. boundingSphere.center = shadowMapCamera.positionWC;
  146733. boundingSphere.radius = shadowMap._pointLightRadius;
  146734. shadowMap._outOfView = frameState.cullingVolume.computeVisibility(boundingSphere) === Intersect.OUTSIDE;
  146735. shadowMap._needsUpdate = !shadowMap._outOfView && !shadowMap._boundingSphere.equals(boundingSphere);
  146736. BoundingSphere.clone(boundingSphere, shadowMap._boundingSphere);
  146737. } else {
  146738. // Simplify frustum-frustum intersection test as a sphere-frustum test
  146739. var frustumRadius = shadowMapCamera.frustum.far / 2.0;
  146740. var frustumCenter = Cartesian3.add(shadowMapCamera.positionWC, Cartesian3.multiplyByScalar(shadowMapCamera.directionWC, frustumRadius, scratchCenter), scratchCenter);
  146741. boundingSphere.center = frustumCenter;
  146742. boundingSphere.radius = frustumRadius;
  146743. shadowMap._outOfView = frameState.cullingVolume.computeVisibility(boundingSphere) === Intersect.OUTSIDE;
  146744. shadowMap._needsUpdate = !shadowMap._outOfView && !shadowMap._boundingSphere.equals(boundingSphere);
  146745. BoundingSphere.clone(boundingSphere, shadowMap._boundingSphere);
  146746. }
  146747. }
  146748. function updateCameras(shadowMap, frameState) {
  146749. var camera = frameState.camera; // The actual camera in the scene
  146750. var lightCamera = shadowMap._lightCamera; // The external camera representing the light source
  146751. var sceneCamera = shadowMap._sceneCamera; // Clone of camera, with clamped near and far planes
  146752. var shadowMapCamera = shadowMap._shadowMapCamera; // Camera representing the shadow volume, initially cloned from lightCamera
  146753. // Clone light camera into the shadow map camera
  146754. if (shadowMap._cascadesEnabled) {
  146755. Cartesian3.clone(lightCamera.directionWC, shadowMapCamera.directionWC);
  146756. } else if (shadowMap._isPointLight) {
  146757. Cartesian3.clone(lightCamera.positionWC, shadowMapCamera.positionWC);
  146758. } else {
  146759. shadowMapCamera.clone(lightCamera);
  146760. }
  146761. // Get the light direction in eye coordinates
  146762. var lightDirection = shadowMap._lightDirectionEC;
  146763. Matrix4.multiplyByPointAsVector(camera.viewMatrix, shadowMapCamera.directionWC, lightDirection);
  146764. Cartesian3.normalize(lightDirection, lightDirection);
  146765. Cartesian3.negate(lightDirection, lightDirection);
  146766. // Get the light position in eye coordinates
  146767. Matrix4.multiplyByPoint(camera.viewMatrix, shadowMapCamera.positionWC, shadowMap._lightPositionEC);
  146768. shadowMap._lightPositionEC.w = shadowMap._pointLightRadius;
  146769. // Get the near and far of the scene camera
  146770. var near;
  146771. var far;
  146772. if (shadowMap._fitNearFar) {
  146773. // shadowFar can be very large, so limit to shadowMap.maximumDistance
  146774. // Push the far plane slightly further than the near plane to avoid degenerate frustum
  146775. near = Math.min(frameState.shadowHints.nearPlane, shadowMap.maximumDistance);
  146776. far = Math.min(frameState.shadowHints.farPlane, shadowMap.maximumDistance + 1.0);
  146777. } else {
  146778. near = camera.frustum.near;
  146779. far = shadowMap.maximumDistance;
  146780. }
  146781. shadowMap._sceneCamera = Camera.clone(camera, sceneCamera);
  146782. camera.frustum.clone(shadowMap._sceneCamera.frustum);
  146783. shadowMap._sceneCamera.frustum.near = near;
  146784. shadowMap._sceneCamera.frustum.far = far;
  146785. shadowMap._distance = far - near;
  146786. checkVisibility(shadowMap, frameState);
  146787. if (!shadowMap._outOfViewPrevious && shadowMap._outOfView) {
  146788. shadowMap._needsUpdate = true;
  146789. }
  146790. shadowMap._outOfViewPrevious = shadowMap._outOfView;
  146791. }
  146792. /**
  146793. * @private
  146794. */
  146795. ShadowMap.prototype.update = function(frameState) {
  146796. updateCameras(this, frameState);
  146797. if (this._needsUpdate) {
  146798. updateFramebuffer(this, frameState.context);
  146799. if (this._isPointLight) {
  146800. computeOmnidirectional(this, frameState);
  146801. }
  146802. if (this._cascadesEnabled) {
  146803. fitShadowMapToScene(this, frameState);
  146804. if (this._numberOfCascades > 1) {
  146805. computeCascades(this, frameState);
  146806. }
  146807. }
  146808. if (!this._isPointLight) {
  146809. // Compute the culling volume
  146810. var shadowMapCamera = this._shadowMapCamera;
  146811. var position = shadowMapCamera.positionWC;
  146812. var direction = shadowMapCamera.directionWC;
  146813. var up = shadowMapCamera.upWC;
  146814. this._shadowMapCullingVolume = shadowMapCamera.frustum.computeCullingVolume(position, direction, up);
  146815. if (this._passes.length === 1) {
  146816. // Since there is only one pass, use the shadow map camera as the pass camera.
  146817. this._passes[0].camera.clone(shadowMapCamera);
  146818. }
  146819. } else {
  146820. this._shadowMapCullingVolume = CullingVolume.fromBoundingSphere(this._boundingSphere);
  146821. }
  146822. }
  146823. if (this._passes.length === 1) {
  146824. // Transforms from eye space to shadow texture space.
  146825. // Always requires an update since the scene camera constantly changes.
  146826. var inverseView = this._sceneCamera.inverseViewMatrix;
  146827. Matrix4.multiply(this._shadowMapCamera.getViewProjection(), inverseView, this._shadowMapMatrix);
  146828. }
  146829. if (this.debugShow) {
  146830. applyDebugSettings(this, frameState);
  146831. }
  146832. };
  146833. /**
  146834. * @private
  146835. */
  146836. ShadowMap.prototype.updatePass = function(context, shadowPass) {
  146837. clearFramebuffer(this, context, shadowPass);
  146838. };
  146839. var scratchTexelStepSize = new Cartesian2();
  146840. function combineUniforms(shadowMap, uniforms, isTerrain) {
  146841. var bias = shadowMap._isPointLight ? shadowMap._pointBias : (isTerrain ? shadowMap._terrainBias : shadowMap._primitiveBias);
  146842. var mapUniforms = {
  146843. shadowMap_texture :function() {
  146844. return shadowMap._shadowMapTexture;
  146845. },
  146846. shadowMap_textureCube : function() {
  146847. return shadowMap._shadowMapTexture;
  146848. },
  146849. shadowMap_matrix : function() {
  146850. return shadowMap._shadowMapMatrix;
  146851. },
  146852. shadowMap_cascadeSplits : function() {
  146853. return shadowMap._cascadeSplits;
  146854. },
  146855. shadowMap_cascadeMatrices : function() {
  146856. return shadowMap._cascadeMatrices;
  146857. },
  146858. shadowMap_lightDirectionEC : function() {
  146859. return shadowMap._lightDirectionEC;
  146860. },
  146861. shadowMap_lightPositionEC : function() {
  146862. return shadowMap._lightPositionEC;
  146863. },
  146864. shadowMap_cascadeDistances : function() {
  146865. return shadowMap._cascadeDistances;
  146866. },
  146867. shadowMap_texelSizeDepthBiasAndNormalShadingSmooth : function() {
  146868. var texelStepSize = scratchTexelStepSize;
  146869. texelStepSize.x = 1.0 / shadowMap._textureSize.x;
  146870. texelStepSize.y = 1.0 / shadowMap._textureSize.y;
  146871. return Cartesian4.fromElements(texelStepSize.x, texelStepSize.y, bias.depthBias, bias.normalShadingSmooth, this.combinedUniforms1);
  146872. },
  146873. shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness : function() {
  146874. return Cartesian4.fromElements(bias.normalOffsetScale, shadowMap._distance, shadowMap.maximumDistance, shadowMap._darkness, this.combinedUniforms2);
  146875. },
  146876. combinedUniforms1 : new Cartesian4(),
  146877. combinedUniforms2 : new Cartesian4()
  146878. };
  146879. return combine(uniforms, mapUniforms, false);
  146880. }
  146881. function createCastDerivedCommand(shadowMap, shadowsDirty, command, context, oldShaderId, result) {
  146882. var castShader;
  146883. var castRenderState;
  146884. var castUniformMap;
  146885. if (defined(result)) {
  146886. castShader = result.shaderProgram;
  146887. castRenderState = result.renderState;
  146888. castUniformMap = result.uniformMap;
  146889. }
  146890. result = DrawCommand.shallowClone(command, result);
  146891. result.castShadows = true;
  146892. result.receiveShadows = false;
  146893. if (!defined(castShader) || oldShaderId !== command.shaderProgram.id || shadowsDirty) {
  146894. if (defined(castShader)) {
  146895. castShader.destroy();
  146896. }
  146897. var shaderProgram = command.shaderProgram;
  146898. var vertexShaderSource = shaderProgram.vertexShaderSource;
  146899. var fragmentShaderSource = shaderProgram.fragmentShaderSource;
  146900. var isTerrain = command.pass === Pass.GLOBE;
  146901. var isOpaque = command.pass !== Pass.TRANSLUCENT;
  146902. var isPointLight = shadowMap._isPointLight;
  146903. var usesDepthTexture= shadowMap._usesDepthTexture;
  146904. var castVS = ShadowMapShader.createShadowCastVertexShader(vertexShaderSource, isPointLight, isTerrain);
  146905. var castFS = ShadowMapShader.createShadowCastFragmentShader(fragmentShaderSource, isPointLight, usesDepthTexture, isOpaque);
  146906. castShader = ShaderProgram.fromCache({
  146907. context : context,
  146908. vertexShaderSource : castVS,
  146909. fragmentShaderSource : castFS,
  146910. attributeLocations : shaderProgram._attributeLocations
  146911. });
  146912. castRenderState = shadowMap._primitiveRenderState;
  146913. if (isPointLight) {
  146914. castRenderState = shadowMap._pointRenderState;
  146915. } else if (isTerrain) {
  146916. castRenderState = shadowMap._terrainRenderState;
  146917. }
  146918. // Modify the render state for commands that do not use back-face culling, e.g. flat textured walls
  146919. var cullEnabled = command.renderState.cull.enabled;
  146920. if (!cullEnabled) {
  146921. castRenderState = clone(castRenderState, false);
  146922. castRenderState.cull.enabled = false;
  146923. castRenderState = RenderState.fromCache(castRenderState);
  146924. }
  146925. castUniformMap = combineUniforms(shadowMap, command.uniformMap, isTerrain);
  146926. }
  146927. result.shaderProgram = castShader;
  146928. result.renderState = castRenderState;
  146929. result.uniformMap = castUniformMap;
  146930. return result;
  146931. }
  146932. ShadowMap.createDerivedCommands = function(shadowMaps, lightShadowMaps, command, shadowsDirty, context, result) {
  146933. if (!defined(result)) {
  146934. result = {};
  146935. }
  146936. var lightShadowMapsEnabled = (lightShadowMaps.length > 0);
  146937. var shaderProgram = command.shaderProgram;
  146938. var vertexShaderSource = shaderProgram.vertexShaderSource;
  146939. var fragmentShaderSource = shaderProgram.fragmentShaderSource;
  146940. var isTerrain = command.pass === Pass.GLOBE;
  146941. var hasTerrainNormal = false;
  146942. if (isTerrain) {
  146943. hasTerrainNormal = command.owner.data.pickTerrain.mesh.encoding.hasVertexNormals;
  146944. }
  146945. if (command.castShadows) {
  146946. var castCommands = result.castCommands;
  146947. if (!defined(castCommands)) {
  146948. castCommands = result.castCommands = [];
  146949. }
  146950. var oldShaderId = result.castShaderProgramId;
  146951. var shadowMapLength = shadowMaps.length;
  146952. castCommands.length = shadowMapLength;
  146953. for (var i = 0; i < shadowMapLength; ++i) {
  146954. castCommands[i] = createCastDerivedCommand(shadowMaps[i], shadowsDirty, command, context, oldShaderId, castCommands[i]);
  146955. }
  146956. result.castShaderProgramId = command.shaderProgram.id;
  146957. }
  146958. if (command.receiveShadows && lightShadowMapsEnabled) {
  146959. // Only generate a receiveCommand if there is a shadow map originating from a light source.
  146960. var receiveShader;
  146961. var receiveUniformMap;
  146962. if (defined(result.receiveCommand)) {
  146963. receiveShader = result.receiveCommand.shaderProgram;
  146964. receiveUniformMap = result.receiveCommand.uniformMap;
  146965. }
  146966. result.receiveCommand = DrawCommand.shallowClone(command, result.receiveCommand);
  146967. result.castShadows = false;
  146968. result.receiveShadows = true;
  146969. // If castShadows changed, recompile the receive shadows shader. The normal shading technique simulates
  146970. // self-shadowing so it should be turned off if castShadows is false.
  146971. var castShadowsDirty = result.receiveShaderCastShadows !== command.castShadows;
  146972. var shaderDirty = result.receiveShaderProgramId !== command.shaderProgram.id;
  146973. if (!defined(receiveShader) || shaderDirty || shadowsDirty || castShadowsDirty) {
  146974. if (defined(receiveShader)) {
  146975. receiveShader.destroy();
  146976. }
  146977. var receiveVS = ShadowMapShader.createShadowReceiveVertexShader(vertexShaderSource, isTerrain, hasTerrainNormal);
  146978. var receiveFS = ShadowMapShader.createShadowReceiveFragmentShader(fragmentShaderSource, lightShadowMaps[0], command.castShadows, isTerrain, hasTerrainNormal);
  146979. receiveShader = ShaderProgram.fromCache({
  146980. context : context,
  146981. vertexShaderSource : receiveVS,
  146982. fragmentShaderSource : receiveFS,
  146983. attributeLocations : shaderProgram._attributeLocations
  146984. });
  146985. receiveUniformMap = combineUniforms(lightShadowMaps[0], command.uniformMap, isTerrain);
  146986. }
  146987. result.receiveCommand.shaderProgram = receiveShader;
  146988. result.receiveCommand.uniformMap = receiveUniformMap;
  146989. result.receiveShaderProgramId = command.shaderProgram.id;
  146990. result.receiveShaderCastShadows = command.castShadows;
  146991. }
  146992. return result;
  146993. };
  146994. /**
  146995. * @private
  146996. */
  146997. ShadowMap.prototype.isDestroyed = function() {
  146998. return false;
  146999. };
  147000. /**
  147001. * @private
  147002. */
  147003. ShadowMap.prototype.destroy = function() {
  147004. destroyFramebuffer(this);
  147005. this._debugLightFrustum = this._debugLightFrustum && this._debugLightFrustum.destroy();
  147006. this._debugCameraFrustum = this._debugCameraFrustum && this._debugCameraFrustum.destroy();
  147007. this._debugShadowViewCommand = this._debugShadowViewCommand && this._debugShadowViewCommand.shaderProgram && this._debugShadowViewCommand.shaderProgram.destroy();
  147008. for (var i = 0; i < this._numberOfCascades; ++i) {
  147009. this._debugCascadeFrustums[i] = this._debugCascadeFrustums[i] && this._debugCascadeFrustums[i].destroy();
  147010. }
  147011. return destroyObject(this);
  147012. };
  147013. return ShadowMap;
  147014. });
  147015. //This file is automatically rebuilt by the Cesium build process.
  147016. /*global define*/
  147017. define('Shaders/PostProcessFilters/AdditiveBlend',[],function() {
  147018. 'use strict';
  147019. return "uniform sampler2D u_texture0;\n\
  147020. uniform sampler2D u_texture1;\n\
  147021. uniform vec2 u_center;\n\
  147022. uniform float u_radius;\n\
  147023. varying vec2 v_textureCoordinates;\n\
  147024. void main()\n\
  147025. {\n\
  147026. vec4 color0 = texture2D(u_texture0, v_textureCoordinates);\n\
  147027. vec4 color1 = texture2D(u_texture1, v_textureCoordinates);\n\
  147028. float x = length(gl_FragCoord.xy - u_center) / u_radius;\n\
  147029. float t = smoothstep(0.5, 0.8, x);\n\
  147030. gl_FragColor = mix(color0 + color1, color0, t);\n\
  147031. }\n\
  147032. ";
  147033. });
  147034. //This file is automatically rebuilt by the Cesium build process.
  147035. /*global define*/
  147036. define('Shaders/PostProcessFilters/BrightPass',[],function() {
  147037. 'use strict';
  147038. return "uniform sampler2D u_texture;\n\
  147039. uniform float u_avgLuminance;\n\
  147040. uniform float u_threshold;\n\
  147041. uniform float u_offset;\n\
  147042. varying vec2 v_textureCoordinates;\n\
  147043. float key(float avg)\n\
  147044. {\n\
  147045. float guess = 1.5 - (1.5 / (avg * 0.1 + 1.0));\n\
  147046. return max(0.0, guess) + 0.1;\n\
  147047. }\n\
  147048. void main()\n\
  147049. {\n\
  147050. vec4 color = texture2D(u_texture, v_textureCoordinates);\n\
  147051. vec3 xyz = czm_RGBToXYZ(color.rgb);\n\
  147052. float luminance = xyz.r;\n\
  147053. float scaledLum = key(u_avgLuminance) * luminance / u_avgLuminance;\n\
  147054. float brightLum = max(scaledLum - u_threshold, 0.0);\n\
  147055. float brightness = brightLum / (u_offset + brightLum);\n\
  147056. xyz.r = brightness;\n\
  147057. gl_FragColor = vec4(czm_XYZToRGB(xyz), 1.0);\n\
  147058. }\n\
  147059. ";
  147060. });
  147061. //This file is automatically rebuilt by the Cesium build process.
  147062. /*global define*/
  147063. define('Shaders/PostProcessFilters/GaussianBlur1D',[],function() {
  147064. 'use strict';
  147065. return "#define SAMPLES 8\n\
  147066. uniform float delta;\n\
  147067. uniform float sigma;\n\
  147068. uniform float direction;\n\
  147069. uniform sampler2D u_texture;\n\
  147070. uniform vec2 u_step;\n\
  147071. varying vec2 v_textureCoordinates;\n\
  147072. void main()\n\
  147073. {\n\
  147074. vec2 st = v_textureCoordinates;\n\
  147075. vec2 dir = vec2(1.0 - direction, direction);\n\
  147076. vec3 g;\n\
  147077. g.x = 1.0 / (sqrt(czm_twoPi) * sigma);\n\
  147078. g.y = exp((-0.5 * delta * delta) / (sigma * sigma));\n\
  147079. g.z = g.y * g.y;\n\
  147080. vec4 result = texture2D(u_texture, st) * g.x;\n\
  147081. for (int i = 1; i < SAMPLES; ++i)\n\
  147082. {\n\
  147083. g.xy *= g.yz;\n\
  147084. vec2 offset = float(i) * dir * u_step;\n\
  147085. result += texture2D(u_texture, st - offset) * g.x;\n\
  147086. result += texture2D(u_texture, st + offset) * g.x;\n\
  147087. }\n\
  147088. gl_FragColor = result;\n\
  147089. }\n\
  147090. ";
  147091. });
  147092. /*global define*/
  147093. define('Scene/SunPostProcess',[
  147094. '../Core/BoundingRectangle',
  147095. '../Core/Cartesian2',
  147096. '../Core/Cartesian4',
  147097. '../Core/Color',
  147098. '../Core/defaultValue',
  147099. '../Core/defined',
  147100. '../Core/destroyObject',
  147101. '../Core/Math',
  147102. '../Core/Matrix4',
  147103. '../Core/PixelFormat',
  147104. '../Core/Transforms',
  147105. '../Renderer/ClearCommand',
  147106. '../Renderer/Framebuffer',
  147107. '../Renderer/PassState',
  147108. '../Renderer/PixelDatatype',
  147109. '../Renderer/Renderbuffer',
  147110. '../Renderer/RenderbufferFormat',
  147111. '../Renderer/RenderState',
  147112. '../Renderer/Texture',
  147113. '../Shaders/PostProcessFilters/AdditiveBlend',
  147114. '../Shaders/PostProcessFilters/BrightPass',
  147115. '../Shaders/PostProcessFilters/GaussianBlur1D',
  147116. '../Shaders/PostProcessFilters/PassThrough'
  147117. ], function(
  147118. BoundingRectangle,
  147119. Cartesian2,
  147120. Cartesian4,
  147121. Color,
  147122. defaultValue,
  147123. defined,
  147124. destroyObject,
  147125. CesiumMath,
  147126. Matrix4,
  147127. PixelFormat,
  147128. Transforms,
  147129. ClearCommand,
  147130. Framebuffer,
  147131. PassState,
  147132. PixelDatatype,
  147133. Renderbuffer,
  147134. RenderbufferFormat,
  147135. RenderState,
  147136. Texture,
  147137. AdditiveBlend,
  147138. BrightPass,
  147139. GaussianBlur1D,
  147140. PassThrough) {
  147141. 'use strict';
  147142. function SunPostProcess() {
  147143. this._fbo = undefined;
  147144. this._downSampleFBO1 = undefined;
  147145. this._downSampleFBO2 = undefined;
  147146. this._clearFBO1Command = undefined;
  147147. this._clearFBO2Command = undefined;
  147148. this._downSampleCommand = undefined;
  147149. this._brightPassCommand = undefined;
  147150. this._blurXCommand = undefined;
  147151. this._blurYCommand = undefined;
  147152. this._blendCommand = undefined;
  147153. this._fullScreenCommand = undefined;
  147154. this._downSamplePassState = new PassState();
  147155. this._downSamplePassState.scissorTest = {
  147156. enable : true,
  147157. rectangle : new BoundingRectangle()
  147158. };
  147159. this._upSamplePassState = new PassState();
  147160. this._upSamplePassState.scissorTest = {
  147161. enabled : true,
  147162. rectangle : new BoundingRectangle()
  147163. };
  147164. this._uCenter = new Cartesian2();
  147165. this._uRadius = undefined;
  147166. this._blurStep = new Cartesian2();
  147167. }
  147168. SunPostProcess.prototype.clear = function(context, color) {
  147169. var clear = this._clearFBO1Command;
  147170. Color.clone(defaultValue(color, Color.BLACK), clear.color);
  147171. clear.execute(context);
  147172. clear = this._clearFBO2Command;
  147173. Color.clone(defaultValue(color, Color.BLACK), clear.color);
  147174. clear.execute(context);
  147175. };
  147176. SunPostProcess.prototype.execute = function(context, framebuffer) {
  147177. this._downSampleCommand.execute(context, this._downSamplePassState);
  147178. this._brightPassCommand.execute(context, this._downSamplePassState);
  147179. this._blurXCommand.execute(context, this._downSamplePassState);
  147180. this._blurYCommand.execute(context, this._downSamplePassState);
  147181. this._fullScreenCommand.framebuffer = framebuffer;
  147182. this._blendCommand.framebuffer = framebuffer;
  147183. this._fullScreenCommand.execute(context);
  147184. this._blendCommand.execute(context, this._upSamplePassState);
  147185. };
  147186. var viewportBoundingRectangle = new BoundingRectangle();
  147187. var downSampleViewportBoundingRectangle = new BoundingRectangle();
  147188. var sunPositionECScratch = new Cartesian4();
  147189. var sunPositionWCScratch = new Cartesian2();
  147190. var sizeScratch = new Cartesian2();
  147191. var postProcessMatrix4Scratch= new Matrix4();
  147192. SunPostProcess.prototype.update = function(passState) {
  147193. var context = passState.context;
  147194. var viewport = passState.viewport;
  147195. var width = context.drawingBufferWidth;
  147196. var height = context.drawingBufferHeight;
  147197. var that = this;
  147198. if (!defined(this._downSampleCommand)) {
  147199. this._clearFBO1Command = new ClearCommand({
  147200. color : new Color()
  147201. });
  147202. this._clearFBO2Command = new ClearCommand({
  147203. color : new Color()
  147204. });
  147205. var uniformMap = {};
  147206. this._downSampleCommand = context.createViewportQuadCommand(PassThrough, {
  147207. uniformMap : uniformMap,
  147208. owner : this
  147209. });
  147210. uniformMap = {
  147211. u_avgLuminance : function() {
  147212. // A guess at the average luminance across the entire scene
  147213. return 0.5;
  147214. },
  147215. u_threshold : function() {
  147216. return 0.25;
  147217. },
  147218. u_offset : function() {
  147219. return 0.1;
  147220. }
  147221. };
  147222. this._brightPassCommand = context.createViewportQuadCommand(BrightPass, {
  147223. uniformMap : uniformMap,
  147224. owner : this
  147225. });
  147226. var delta = 1.0;
  147227. var sigma = 2.0;
  147228. uniformMap = {
  147229. delta : function() {
  147230. return delta;
  147231. },
  147232. sigma : function() {
  147233. return sigma;
  147234. },
  147235. direction : function() {
  147236. return 0.0;
  147237. }
  147238. };
  147239. this._blurXCommand = context.createViewportQuadCommand(GaussianBlur1D, {
  147240. uniformMap : uniformMap,
  147241. owner : this
  147242. });
  147243. uniformMap = {
  147244. delta : function() {
  147245. return delta;
  147246. },
  147247. sigma : function() {
  147248. return sigma;
  147249. },
  147250. direction : function() {
  147251. return 1.0;
  147252. }
  147253. };
  147254. this._blurYCommand = context.createViewportQuadCommand(GaussianBlur1D, {
  147255. uniformMap : uniformMap,
  147256. owner : this
  147257. });
  147258. uniformMap = {
  147259. u_center : function() {
  147260. return that._uCenter;
  147261. },
  147262. u_radius : function() {
  147263. return that._uRadius;
  147264. }
  147265. };
  147266. this._blendCommand = context.createViewportQuadCommand(AdditiveBlend, {
  147267. uniformMap : uniformMap,
  147268. owner : this
  147269. });
  147270. uniformMap = {};
  147271. this._fullScreenCommand = context.createViewportQuadCommand(PassThrough, {
  147272. uniformMap : uniformMap,
  147273. owner : this
  147274. });
  147275. }
  147276. var downSampleWidth = Math.pow(2.0, Math.ceil(Math.log(width) / Math.log(2)) - 2.0);
  147277. var downSampleHeight = Math.pow(2.0, Math.ceil(Math.log(height) / Math.log(2)) - 2.0);
  147278. // The size computed above can be less than 1.0 if size < 4.0. This will probably
  147279. // never happen in practice, but does in the tests. Clamp to 1.0 to prevent WebGL
  147280. // errors in the tests.
  147281. var downSampleSize = Math.max(1.0, downSampleWidth, downSampleHeight);
  147282. var downSampleViewport = downSampleViewportBoundingRectangle;
  147283. downSampleViewport.width = downSampleSize;
  147284. downSampleViewport.height = downSampleSize;
  147285. var fbo = this._fbo;
  147286. var colorTexture = (defined(fbo) && fbo.getColorTexture(0)) || undefined;
  147287. if (!defined(colorTexture) || colorTexture.width !== width || colorTexture.height !== height) {
  147288. fbo = fbo && fbo.destroy();
  147289. this._downSampleFBO1 = this._downSampleFBO1 && this._downSampleFBO1.destroy();
  147290. this._downSampleFBO2 = this._downSampleFBO2 && this._downSampleFBO2.destroy();
  147291. this._blurStep.x = this._blurStep.y = 1.0 / downSampleSize;
  147292. var colorTextures = [new Texture({
  147293. context : context,
  147294. width : width,
  147295. height : height
  147296. })];
  147297. if (context.depthTexture) {
  147298. fbo = this._fbo = new Framebuffer({
  147299. context : context,
  147300. colorTextures :colorTextures,
  147301. depthTexture : new Texture({
  147302. context : context,
  147303. width : width,
  147304. height : height,
  147305. pixelFormat : PixelFormat.DEPTH_COMPONENT,
  147306. pixelDatatype : PixelDatatype.UNSIGNED_SHORT
  147307. })
  147308. });
  147309. } else {
  147310. fbo = this._fbo = new Framebuffer({
  147311. context : context,
  147312. colorTextures : colorTextures,
  147313. depthRenderbuffer : new Renderbuffer({
  147314. context : context,
  147315. format : RenderbufferFormat.DEPTH_COMPONENT16
  147316. })
  147317. });
  147318. }
  147319. this._downSampleFBO1 = new Framebuffer({
  147320. context : context,
  147321. colorTextures : [new Texture({
  147322. context : context,
  147323. width : downSampleSize,
  147324. height : downSampleSize
  147325. })]
  147326. });
  147327. this._downSampleFBO2 = new Framebuffer({
  147328. context : context,
  147329. colorTextures : [new Texture({
  147330. context : context,
  147331. width : downSampleSize,
  147332. height : downSampleSize
  147333. })]
  147334. });
  147335. this._clearFBO1Command.framebuffer = this._downSampleFBO1;
  147336. this._clearFBO2Command.framebuffer = this._downSampleFBO2;
  147337. this._downSampleCommand.framebuffer = this._downSampleFBO1;
  147338. this._brightPassCommand.framebuffer = this._downSampleFBO2;
  147339. this._blurXCommand.framebuffer = this._downSampleFBO1;
  147340. this._blurYCommand.framebuffer = this._downSampleFBO2;
  147341. var downSampleRenderState = RenderState.fromCache({
  147342. viewport : downSampleViewport
  147343. });
  147344. this._downSampleCommand.uniformMap.u_texture = function() {
  147345. return fbo.getColorTexture(0);
  147346. };
  147347. this._downSampleCommand.renderState = downSampleRenderState;
  147348. this._brightPassCommand.uniformMap.u_texture = function() {
  147349. return that._downSampleFBO1.getColorTexture(0);
  147350. };
  147351. this._brightPassCommand.renderState = downSampleRenderState;
  147352. this._blurXCommand.uniformMap.u_texture = function() {
  147353. return that._downSampleFBO2.getColorTexture(0);
  147354. };
  147355. this._blurXCommand.uniformMap.u_step = function() {
  147356. return that._blurStep;
  147357. };
  147358. this._blurXCommand.renderState = downSampleRenderState;
  147359. this._blurYCommand.uniformMap.u_texture = function() {
  147360. return that._downSampleFBO1.getColorTexture(0);
  147361. };
  147362. this._blurYCommand.uniformMap.u_step = function() {
  147363. return that._blurStep;
  147364. };
  147365. this._blurYCommand.renderState = downSampleRenderState;
  147366. var upSampledViewport = viewportBoundingRectangle;
  147367. upSampledViewport.width = width;
  147368. upSampledViewport.height = height;
  147369. var upSampleRenderState = RenderState.fromCache({ viewport : upSampledViewport });
  147370. this._blendCommand.uniformMap.u_texture0 = function() {
  147371. return fbo.getColorTexture(0);
  147372. };
  147373. this._blendCommand.uniformMap.u_texture1 = function() {
  147374. return that._downSampleFBO2.getColorTexture(0);
  147375. };
  147376. this._blendCommand.renderState = upSampleRenderState;
  147377. this._fullScreenCommand.uniformMap.u_texture = function() {
  147378. return fbo.getColorTexture(0);
  147379. };
  147380. this._fullScreenCommand.renderState = upSampleRenderState;
  147381. }
  147382. var us = context.uniformState;
  147383. var sunPosition = us.sunPositionWC;
  147384. var viewMatrix = us.view;
  147385. var viewProjectionMatrix = us.viewProjection;
  147386. var projectionMatrix = us.projection;
  147387. // create up sampled render state
  147388. var viewportTransformation = Matrix4.computeViewportTransformation(viewport, 0.0, 1.0, postProcessMatrix4Scratch);
  147389. var sunPositionEC = Matrix4.multiplyByPoint(viewMatrix, sunPosition, sunPositionECScratch);
  147390. var sunPositionWC = Transforms.pointToGLWindowCoordinates(viewProjectionMatrix, viewportTransformation, sunPosition, sunPositionWCScratch);
  147391. sunPositionEC.x += CesiumMath.SOLAR_RADIUS;
  147392. var limbWC = Transforms.pointToGLWindowCoordinates(projectionMatrix, viewportTransformation, sunPositionEC, sunPositionEC);
  147393. var sunSize = Cartesian2.magnitude(Cartesian2.subtract(limbWC, sunPositionWC, limbWC)) * 30.0 * 2.0;
  147394. var size = sizeScratch;
  147395. size.x = sunSize;
  147396. size.y = sunSize;
  147397. var scissorRectangle = this._upSamplePassState.scissorTest.rectangle;
  147398. scissorRectangle.x = Math.max(sunPositionWC.x - size.x * 0.5, 0.0);
  147399. scissorRectangle.y = Math.max(sunPositionWC.y - size.y * 0.5, 0.0);
  147400. scissorRectangle.width = Math.min(size.x, width);
  147401. scissorRectangle.height = Math.min(size.y, height);
  147402. this._uCenter = Cartesian2.clone(sunPositionWC, this._uCenter);
  147403. this._uRadius = Math.max(size.x, size.y) * 0.5;
  147404. // create down sampled render state
  147405. viewportTransformation = Matrix4.computeViewportTransformation(downSampleViewport, 0.0, 1.0, postProcessMatrix4Scratch);
  147406. sunPositionWC = Transforms.pointToGLWindowCoordinates(viewProjectionMatrix, viewportTransformation, sunPosition, sunPositionWCScratch);
  147407. size.x *= downSampleWidth / width;
  147408. size.y *= downSampleHeight / height;
  147409. scissorRectangle = this._downSamplePassState.scissorTest.rectangle;
  147410. scissorRectangle.x = Math.max(sunPositionWC.x - size.x * 0.5, 0.0);
  147411. scissorRectangle.y = Math.max(sunPositionWC.y - size.y * 0.5, 0.0);
  147412. scissorRectangle.width = Math.min(size.x, width);
  147413. scissorRectangle.height = Math.min(size.y, height);
  147414. this._downSamplePassState.context = context;
  147415. this._upSamplePassState.context = context;
  147416. return this._fbo;
  147417. };
  147418. SunPostProcess.prototype.isDestroyed = function() {
  147419. return false;
  147420. };
  147421. SunPostProcess.prototype.destroy = function() {
  147422. this._fbo = this._fbo && this._fbo.destroy();
  147423. this._downSampleFBO1 = this._downSampleFBO1 && this._downSampleFBO1.destroy();
  147424. this._downSampleFBO2 = this._downSampleFBO2 && this._downSampleFBO2.destroy();
  147425. this._downSampleCommand = this._downSampleCommand && this._downSampleCommand.shaderProgram && this._downSampleCommand.shaderProgram.destroy();
  147426. this._brightPassCommand = this._brightPassCommand && this._brightPassCommand.shaderProgram && this._brightPassCommand.shaderProgram.destroy();
  147427. this._blurXCommand = this._blurXCommand && this._blurXCommand.shaderProgram && this._blurXCommand.shaderProgram.destroy();
  147428. this._blurYCommand = this._blurYCommand && this._blurYCommand.shaderProgram && this._blurYCommand.shaderProgram.destroy();
  147429. this._blendCommand = this._blendCommand && this._blendCommand.shaderProgram && this._blendCommand.shaderProgram.destroy();
  147430. this._fullScreenCommand = this._fullScreenCommand && this._fullScreenCommand.shaderProgram && this._fullScreenCommand.shaderProgram.destroy();
  147431. return destroyObject(this);
  147432. };
  147433. return SunPostProcess;
  147434. });
  147435. /*global define*/
  147436. define('Scene/Scene',[
  147437. '../Core/BoundingRectangle',
  147438. '../Core/BoundingSphere',
  147439. '../Core/BoxGeometry',
  147440. '../Core/Cartesian2',
  147441. '../Core/Cartesian3',
  147442. '../Core/Cartesian4',
  147443. '../Core/Cartographic',
  147444. '../Core/Color',
  147445. '../Core/ColorGeometryInstanceAttribute',
  147446. '../Core/createGuid',
  147447. '../Core/defaultValue',
  147448. '../Core/defined',
  147449. '../Core/defineProperties',
  147450. '../Core/destroyObject',
  147451. '../Core/DeveloperError',
  147452. '../Core/EllipsoidGeometry',
  147453. '../Core/Event',
  147454. '../Core/GeographicProjection',
  147455. '../Core/GeometryInstance',
  147456. '../Core/GeometryPipeline',
  147457. '../Core/getTimestamp',
  147458. '../Core/Intersect',
  147459. '../Core/Interval',
  147460. '../Core/JulianDate',
  147461. '../Core/Math',
  147462. '../Core/Matrix4',
  147463. '../Core/mergeSort',
  147464. '../Core/Occluder',
  147465. '../Core/ShowGeometryInstanceAttribute',
  147466. '../Core/Transforms',
  147467. '../Renderer/ClearCommand',
  147468. '../Renderer/ComputeEngine',
  147469. '../Renderer/Context',
  147470. '../Renderer/ContextLimits',
  147471. '../Renderer/DrawCommand',
  147472. '../Renderer/Pass',
  147473. '../Renderer/PassState',
  147474. '../Renderer/ShaderProgram',
  147475. '../Renderer/ShaderSource',
  147476. './Camera',
  147477. './CreditDisplay',
  147478. './CullingVolume',
  147479. './DepthPlane',
  147480. './DeviceOrientationCameraController',
  147481. './Fog',
  147482. './FrameState',
  147483. './FrustumCommands',
  147484. './FXAA',
  147485. './GlobeDepth',
  147486. './MapMode2D',
  147487. './OIT',
  147488. './OrthographicFrustum',
  147489. './PerformanceDisplay',
  147490. './PerInstanceColorAppearance',
  147491. './PerspectiveFrustum',
  147492. './PerspectiveOffCenterFrustum',
  147493. './PickDepth',
  147494. './Primitive',
  147495. './PrimitiveCollection',
  147496. './SceneMode',
  147497. './SceneTransforms',
  147498. './SceneTransitioner',
  147499. './ScreenSpaceCameraController',
  147500. './ShadowMap',
  147501. './SunPostProcess',
  147502. './TweenCollection'
  147503. ], function(
  147504. BoundingRectangle,
  147505. BoundingSphere,
  147506. BoxGeometry,
  147507. Cartesian2,
  147508. Cartesian3,
  147509. Cartesian4,
  147510. Cartographic,
  147511. Color,
  147512. ColorGeometryInstanceAttribute,
  147513. createGuid,
  147514. defaultValue,
  147515. defined,
  147516. defineProperties,
  147517. destroyObject,
  147518. DeveloperError,
  147519. EllipsoidGeometry,
  147520. Event,
  147521. GeographicProjection,
  147522. GeometryInstance,
  147523. GeometryPipeline,
  147524. getTimestamp,
  147525. Intersect,
  147526. Interval,
  147527. JulianDate,
  147528. CesiumMath,
  147529. Matrix4,
  147530. mergeSort,
  147531. Occluder,
  147532. ShowGeometryInstanceAttribute,
  147533. Transforms,
  147534. ClearCommand,
  147535. ComputeEngine,
  147536. Context,
  147537. ContextLimits,
  147538. DrawCommand,
  147539. Pass,
  147540. PassState,
  147541. ShaderProgram,
  147542. ShaderSource,
  147543. Camera,
  147544. CreditDisplay,
  147545. CullingVolume,
  147546. DepthPlane,
  147547. DeviceOrientationCameraController,
  147548. Fog,
  147549. FrameState,
  147550. FrustumCommands,
  147551. FXAA,
  147552. GlobeDepth,
  147553. MapMode2D,
  147554. OIT,
  147555. OrthographicFrustum,
  147556. PerformanceDisplay,
  147557. PerInstanceColorAppearance,
  147558. PerspectiveFrustum,
  147559. PerspectiveOffCenterFrustum,
  147560. PickDepth,
  147561. Primitive,
  147562. PrimitiveCollection,
  147563. SceneMode,
  147564. SceneTransforms,
  147565. SceneTransitioner,
  147566. ScreenSpaceCameraController,
  147567. ShadowMap,
  147568. SunPostProcess,
  147569. TweenCollection) {
  147570. 'use strict';
  147571. /**
  147572. * The container for all 3D graphical objects and state in a Cesium virtual scene. Generally,
  147573. * a scene is not created directly; instead, it is implicitly created by {@link CesiumWidget}.
  147574. * <p>
  147575. * <em><code>contextOptions</code> parameter details:</em>
  147576. * </p>
  147577. * <p>
  147578. * The default values are:
  147579. * <code>
  147580. * {
  147581. * webgl : {
  147582. * alpha : false,
  147583. * depth : true,
  147584. * stencil : false,
  147585. * antialias : true,
  147586. * premultipliedAlpha : true,
  147587. * preserveDrawingBuffer : false,
  147588. * failIfMajorPerformanceCaveat : false
  147589. * },
  147590. * allowTextureFilterAnisotropic : true
  147591. * }
  147592. * </code>
  147593. * </p>
  147594. * <p>
  147595. * The <code>webgl</code> property corresponds to the {@link http://www.khronos.org/registry/webgl/specs/latest/#5.2|WebGLContextAttributes}
  147596. * object used to create the WebGL context.
  147597. * </p>
  147598. * <p>
  147599. * <code>webgl.alpha</code> defaults to false, which can improve performance compared to the standard WebGL default
  147600. * of true. If an application needs to composite Cesium above other HTML elements using alpha-blending, set
  147601. * <code>webgl.alpha</code> to true.
  147602. * </p>
  147603. * <p>
  147604. * The other <code>webgl</code> properties match the WebGL defaults for {@link http://www.khronos.org/registry/webgl/specs/latest/#5.2|WebGLContextAttributes}.
  147605. * </p>
  147606. * <p>
  147607. * <code>allowTextureFilterAnisotropic</code> defaults to true, which enables anisotropic texture filtering when the
  147608. * WebGL extension is supported. Setting this to false will improve performance, but hurt visual quality, especially for horizon views.
  147609. * </p>
  147610. *
  147611. * @alias Scene
  147612. * @constructor
  147613. *
  147614. * @param {Object} [options] Object with the following properties:
  147615. * @param {Canvas} options.canvas The HTML canvas element to create the scene for.
  147616. * @param {Object} [options.contextOptions] Context and WebGL creation properties. See details above.
  147617. * @param {Element} [options.creditContainer] The HTML element in which the credits will be displayed.
  147618. * @param {MapProjection} [options.mapProjection=new GeographicProjection()] The map projection to use in 2D and Columbus View modes.
  147619. * @param {Boolean} [options.orderIndependentTranslucency=true] If true and the configuration supports it, use order independent translucency.
  147620. * @param {Boolean} [options.scene3DOnly=false] If true, optimizes memory use and performance for 3D mode but disables the ability to use 2D or Columbus View.
  147621. * @param {Number} [options.terrainExaggeration=1.0] A scalar used to exaggerate the terrain. Note that terrain exaggeration will not modify any other primitive as they are positioned relative to the ellipsoid.
  147622. * @param {Boolean} [options.shadows=false] Determines if shadows are cast by the sun.
  147623. * @param {MapMode2D} [options.mapMode2D=MapMode2D.INFINITE_SCROLL] Determines if the 2D map is rotatable or can be scrolled infinitely in the horizontal direction.
  147624. *
  147625. * @see CesiumWidget
  147626. * @see {@link http://www.khronos.org/registry/webgl/specs/latest/#5.2|WebGLContextAttributes}
  147627. *
  147628. * @exception {DeveloperError} options and options.canvas are required.
  147629. *
  147630. * @example
  147631. * // Create scene without anisotropic texture filtering
  147632. * var scene = new Cesium.Scene({
  147633. * canvas : canvas,
  147634. * contextOptions : {
  147635. * allowTextureFilterAnisotropic : false
  147636. * }
  147637. * });
  147638. */
  147639. function Scene(options) {
  147640. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  147641. var canvas = options.canvas;
  147642. var contextOptions = options.contextOptions;
  147643. var creditContainer = options.creditContainer;
  147644. if (!defined(canvas)) {
  147645. throw new DeveloperError('options and options.canvas are required.');
  147646. }
  147647. var context = new Context(canvas, contextOptions);
  147648. if (!defined(creditContainer)) {
  147649. creditContainer = document.createElement('div');
  147650. creditContainer.style.position = 'absolute';
  147651. creditContainer.style.bottom = '0';
  147652. creditContainer.style['text-shadow'] = '0 0 2px #000000';
  147653. creditContainer.style.color = '#ffffff';
  147654. creditContainer.style['font-size'] = '10px';
  147655. creditContainer.style['padding-right'] = '5px';
  147656. canvas.parentNode.appendChild(creditContainer);
  147657. }
  147658. this._id = createGuid();
  147659. this._frameState = new FrameState(context, new CreditDisplay(creditContainer));
  147660. this._frameState.scene3DOnly = defaultValue(options.scene3DOnly, false);
  147661. var ps = new PassState(context);
  147662. ps.viewport = new BoundingRectangle();
  147663. ps.viewport.x = 0;
  147664. ps.viewport.y = 0;
  147665. ps.viewport.width = context.drawingBufferWidth;
  147666. ps.viewport.height = context.drawingBufferHeight;
  147667. this._passState = ps;
  147668. this._canvas = canvas;
  147669. this._context = context;
  147670. this._computeEngine = new ComputeEngine(context);
  147671. this._globe = undefined;
  147672. this._primitives = new PrimitiveCollection();
  147673. this._groundPrimitives = new PrimitiveCollection();
  147674. this._tweens = new TweenCollection();
  147675. this._shaderFrameCount = 0;
  147676. this._sunPostProcess = undefined;
  147677. this._computeCommandList = [];
  147678. this._frustumCommandsList = [];
  147679. this._overlayCommandList = [];
  147680. this._pickFramebuffer = undefined;
  147681. this._useOIT = defaultValue(options.orderIndependentTranslucency, true);
  147682. this._executeOITFunction = undefined;
  147683. var globeDepth;
  147684. if (context.depthTexture) {
  147685. globeDepth = new GlobeDepth();
  147686. }
  147687. var oit;
  147688. if (this._useOIT && defined(globeDepth)) {
  147689. oit = new OIT(context);
  147690. }
  147691. this._globeDepth = globeDepth;
  147692. this._depthPlane = new DepthPlane();
  147693. this._oit = oit;
  147694. this._fxaa = new FXAA();
  147695. this._clearColorCommand = new ClearCommand({
  147696. color : new Color(),
  147697. stencil : 0,
  147698. owner : this
  147699. });
  147700. this._depthClearCommand = new ClearCommand({
  147701. depth : 1.0,
  147702. owner : this
  147703. });
  147704. this._stencilClearCommand = new ClearCommand({
  147705. stencil : 0
  147706. });
  147707. this._pickDepths = [];
  147708. this._debugGlobeDepths = [];
  147709. this._transitioner = new SceneTransitioner(this);
  147710. this._renderError = new Event();
  147711. this._preRender = new Event();
  147712. this._postRender = new Event();
  147713. this._cameraStartFired = false;
  147714. this._cameraMovedTime = undefined;
  147715. /**
  147716. * Exceptions occurring in <code>render</code> are always caught in order to raise the
  147717. * <code>renderError</code> event. If this property is true, the error is rethrown
  147718. * after the event is raised. If this property is false, the <code>render</code> function
  147719. * returns normally after raising the event.
  147720. *
  147721. * @type {Boolean}
  147722. * @default false
  147723. */
  147724. this.rethrowRenderErrors = false;
  147725. /**
  147726. * Determines whether or not to instantly complete the
  147727. * scene transition animation on user input.
  147728. *
  147729. * @type {Boolean}
  147730. * @default true
  147731. */
  147732. this.completeMorphOnUserInput = true;
  147733. /**
  147734. * The event fired at the beginning of a scene transition.
  147735. * @type {Event}
  147736. * @default Event()
  147737. */
  147738. this.morphStart = new Event();
  147739. /**
  147740. * The event fired at the completion of a scene transition.
  147741. * @type {Event}
  147742. * @default Event()
  147743. */
  147744. this.morphComplete = new Event();
  147745. /**
  147746. * The {@link SkyBox} used to draw the stars.
  147747. *
  147748. * @type {SkyBox}
  147749. * @default undefined
  147750. *
  147751. * @see Scene#backgroundColor
  147752. */
  147753. this.skyBox = undefined;
  147754. /**
  147755. * The sky atmosphere drawn around the globe.
  147756. *
  147757. * @type {SkyAtmosphere}
  147758. * @default undefined
  147759. */
  147760. this.skyAtmosphere = undefined;
  147761. /**
  147762. * The {@link Sun}.
  147763. *
  147764. * @type {Sun}
  147765. * @default undefined
  147766. */
  147767. this.sun = undefined;
  147768. /**
  147769. * Uses a bloom filter on the sun when enabled.
  147770. *
  147771. * @type {Boolean}
  147772. * @default true
  147773. */
  147774. this.sunBloom = true;
  147775. this._sunBloom = undefined;
  147776. /**
  147777. * The {@link Moon}
  147778. *
  147779. * @type Moon
  147780. * @default undefined
  147781. */
  147782. this.moon = undefined;
  147783. /**
  147784. * The background color, which is only visible if there is no sky box, i.e., {@link Scene#skyBox} is undefined.
  147785. *
  147786. * @type {Color}
  147787. * @default {@link Color.BLACK}
  147788. *
  147789. * @see Scene#skyBox
  147790. */
  147791. this.backgroundColor = Color.clone(Color.BLACK);
  147792. this._mode = SceneMode.SCENE3D;
  147793. this._mapProjection = defined(options.mapProjection) ? options.mapProjection : new GeographicProjection();
  147794. /**
  147795. * The current morph transition time between 2D/Columbus View and 3D,
  147796. * with 0.0 being 2D or Columbus View and 1.0 being 3D.
  147797. *
  147798. * @type {Number}
  147799. * @default 1.0
  147800. */
  147801. this.morphTime = 1.0;
  147802. /**
  147803. * The far-to-near ratio of the multi-frustum. The default is 1,000.0.
  147804. *
  147805. * @type {Number}
  147806. * @default 1000.0
  147807. */
  147808. this.farToNearRatio = 1000.0;
  147809. /**
  147810. * Determines the uniform depth size in meters of each frustum of the multifrustum in 2D. If a primitive or model close
  147811. * to the surface shows z-fighting, decreasing this will eliminate the artifact, but decrease performance. On the
  147812. * other hand, increasing this will increase performance but may cause z-fighting among primitives close to thesurface.
  147813. * @type {Number}
  147814. * @default 1.75e6
  147815. */
  147816. this.nearToFarDistance2D = 1.75e6;
  147817. /**
  147818. * This property is for debugging only; it is not for production use.
  147819. * <p>
  147820. * A function that determines what commands are executed. As shown in the examples below,
  147821. * the function receives the command's <code>owner</code> as an argument, and returns a boolean indicating if the
  147822. * command should be executed.
  147823. * </p>
  147824. * <p>
  147825. * The default is <code>undefined</code>, indicating that all commands are executed.
  147826. * </p>
  147827. *
  147828. * @type Function
  147829. *
  147830. * @default undefined
  147831. *
  147832. * @example
  147833. * // Do not execute any commands.
  147834. * scene.debugCommandFilter = function(command) {
  147835. * return false;
  147836. * };
  147837. *
  147838. * // Execute only the billboard's commands. That is, only draw the billboard.
  147839. * var billboards = new Cesium.BillboardCollection();
  147840. * scene.debugCommandFilter = function(command) {
  147841. * return command.owner === billboards;
  147842. * };
  147843. */
  147844. this.debugCommandFilter = undefined;
  147845. /**
  147846. * This property is for debugging only; it is not for production use.
  147847. * <p>
  147848. * When <code>true</code>, commands are randomly shaded. This is useful
  147849. * for performance analysis to see what parts of a scene or model are
  147850. * command-dense and could benefit from batching.
  147851. * </p>
  147852. *
  147853. * @type Boolean
  147854. *
  147855. * @default false
  147856. */
  147857. this.debugShowCommands = false;
  147858. /**
  147859. * This property is for debugging only; it is not for production use.
  147860. * <p>
  147861. * When <code>true</code>, commands are shaded based on the frustums they
  147862. * overlap. Commands in the closest frustum are tinted red, commands in
  147863. * the next closest are green, and commands in the farthest frustum are
  147864. * blue. If a command overlaps more than one frustum, the color components
  147865. * are combined, e.g., a command overlapping the first two frustums is tinted
  147866. * yellow.
  147867. * </p>
  147868. *
  147869. * @type Boolean
  147870. *
  147871. * @default false
  147872. */
  147873. this.debugShowFrustums = false;
  147874. this._debugFrustumStatistics = undefined;
  147875. /**
  147876. * This property is for debugging only; it is not for production use.
  147877. * <p>
  147878. * Displays frames per second and time between frames.
  147879. * </p>
  147880. *
  147881. * @type Boolean
  147882. *
  147883. * @default false
  147884. */
  147885. this.debugShowFramesPerSecond = false;
  147886. /**
  147887. * This property is for debugging only; it is not for production use.
  147888. * <p>
  147889. * Displays depth information for the indicated frustum.
  147890. * </p>
  147891. *
  147892. * @type Boolean
  147893. *
  147894. * @default false
  147895. */
  147896. this.debugShowGlobeDepth = false;
  147897. /**
  147898. * This property is for debugging only; it is not for production use.
  147899. * <p>
  147900. * Indicates which frustum will have depth information displayed.
  147901. * </p>
  147902. *
  147903. * @type Number
  147904. *
  147905. * @default 1
  147906. */
  147907. this.debugShowDepthFrustum = 1;
  147908. /**
  147909. * When <code>true</code>, enables Fast Approximate Anti-aliasing even when order independent translucency
  147910. * is unsupported.
  147911. *
  147912. * @type Boolean
  147913. * @default true
  147914. */
  147915. this.fxaa = true;
  147916. /**
  147917. * When <code>true</code>, enables picking using the depth buffer.
  147918. *
  147919. * @type Boolean
  147920. * @default true
  147921. */
  147922. this.useDepthPicking = true;
  147923. /**
  147924. * The time in milliseconds to wait before checking if the camera has not moved and fire the cameraMoveEnd event.
  147925. * @type {Number}
  147926. * @default 500.0
  147927. * @private
  147928. */
  147929. this.cameraEventWaitTime = 500.0;
  147930. /**
  147931. * Set to true to copy the depth texture after rendering the globe. Makes czm_globeDepthTexture valid.
  147932. * @type {Boolean}
  147933. * @default false
  147934. * @private
  147935. */
  147936. this.copyGlobeDepth = false;
  147937. /**
  147938. * Blends the atmosphere to geometry far from the camera for horizon views. Allows for additional
  147939. * performance improvements by rendering less geometry and dispatching less terrain requests.
  147940. * @type {Fog}
  147941. */
  147942. this.fog = new Fog();
  147943. this._sunCamera = new Camera(this);
  147944. /**
  147945. * The shadow map in the scene. When enabled, models, primitives, and the globe may cast and receive shadows.
  147946. * By default the light source of the shadow map is the sun.
  147947. * @type {ShadowMap}
  147948. */
  147949. this.shadowMap = new ShadowMap({
  147950. context : context,
  147951. lightCamera : this._sunCamera,
  147952. enabled : defaultValue(options.shadows, false)
  147953. });
  147954. this._terrainExaggeration = defaultValue(options.terrainExaggeration, 1.0);
  147955. this._performanceDisplay = undefined;
  147956. this._debugVolume = undefined;
  147957. var camera = new Camera(this);
  147958. this._camera = camera;
  147959. this._cameraClone = Camera.clone(camera);
  147960. this._screenSpaceCameraController = new ScreenSpaceCameraController(this);
  147961. this._mapMode2D = defaultValue(options.mapMode2D, MapMode2D.INFINITE_SCROLL);
  147962. // Keeps track of the state of a frame. FrameState is the state across
  147963. // the primitives of the scene. This state is for internally keeping track
  147964. // of celestial and environment effects that need to be updated/rendered in
  147965. // a certain order as well as updating/tracking framebuffer usage.
  147966. this._environmentState = {
  147967. skyBoxCommand : undefined,
  147968. skyAtmosphereCommand : undefined,
  147969. sunDrawCommand : undefined,
  147970. sunComputeCommand : undefined,
  147971. moonCommand : undefined,
  147972. isSunVisible : false,
  147973. isMoonVisible : false,
  147974. isReadyForAtmosphere : false,
  147975. isSkyAtmosphereVisible : false,
  147976. clearGlobeDepth : false,
  147977. useDepthPlane : false,
  147978. originalFramebuffer : undefined,
  147979. useGlobeDepthFramebuffer : false,
  147980. useOIT : false,
  147981. useFXAA : false
  147982. };
  147983. this._useWebVR = false;
  147984. this._cameraVR = undefined;
  147985. this._aspectRatioVR = undefined;
  147986. // initial guess at frustums.
  147987. var near = camera.frustum.near;
  147988. var far = camera.frustum.far;
  147989. var numFrustums = Math.ceil(Math.log(far / near) / Math.log(this.farToNearRatio));
  147990. updateFrustums(near, far, this.farToNearRatio, numFrustums, this._frustumCommandsList, false, undefined);
  147991. // give frameState, camera, and screen space camera controller initial state before rendering
  147992. updateFrameState(this, 0.0, JulianDate.now());
  147993. this.initializeFrame();
  147994. }
  147995. var OPAQUE_FRUSTUM_NEAR_OFFSET = 0.99;
  147996. defineProperties(Scene.prototype, {
  147997. /**
  147998. * Gets the canvas element to which this scene is bound.
  147999. * @memberof Scene.prototype
  148000. *
  148001. * @type {Canvas}
  148002. * @readonly
  148003. */
  148004. canvas : {
  148005. get : function() {
  148006. return this._canvas;
  148007. }
  148008. },
  148009. /**
  148010. * The drawingBufferWidth of the underlying GL context.
  148011. * @memberof Scene.prototype
  148012. *
  148013. * @type {Number}
  148014. * @readonly
  148015. *
  148016. * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferWidth|drawingBufferWidth}
  148017. */
  148018. drawingBufferHeight : {
  148019. get : function() {
  148020. return this._context.drawingBufferHeight;
  148021. }
  148022. },
  148023. /**
  148024. * The drawingBufferHeight of the underlying GL context.
  148025. * @memberof Scene.prototype
  148026. *
  148027. * @type {Number}
  148028. * @readonly
  148029. *
  148030. * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferHeight|drawingBufferHeight}
  148031. */
  148032. drawingBufferWidth : {
  148033. get : function() {
  148034. return this._context.drawingBufferWidth;
  148035. }
  148036. },
  148037. /**
  148038. * The maximum aliased line width, in pixels, supported by this WebGL implementation. It will be at least one.
  148039. * @memberof Scene.prototype
  148040. *
  148041. * @type {Number}
  148042. * @readonly
  148043. *
  148044. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>ALIASED_LINE_WIDTH_RANGE</code>.
  148045. */
  148046. maximumAliasedLineWidth : {
  148047. get : function() {
  148048. return ContextLimits.maximumAliasedLineWidth;
  148049. }
  148050. },
  148051. /**
  148052. * The maximum length in pixels of one edge of a cube map, supported by this WebGL implementation. It will be at least 16.
  148053. * @memberof Scene.prototype
  148054. *
  148055. * @type {Number}
  148056. * @readonly
  148057. *
  148058. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>GL_MAX_CUBE_MAP_TEXTURE_SIZE</code>.
  148059. */
  148060. maximumCubeMapSize : {
  148061. get : function() {
  148062. return ContextLimits.maximumCubeMapSize;
  148063. }
  148064. },
  148065. /**
  148066. * Returns true if the pickPosition function is supported.
  148067. * @memberof Scene.prototype
  148068. *
  148069. * @type {Boolean}
  148070. * @readonly
  148071. */
  148072. pickPositionSupported : {
  148073. get : function() {
  148074. return this._context.depthTexture;
  148075. }
  148076. },
  148077. /**
  148078. * Gets or sets the depth-test ellipsoid.
  148079. * @memberof Scene.prototype
  148080. *
  148081. * @type {Globe}
  148082. */
  148083. globe : {
  148084. get: function() {
  148085. return this._globe;
  148086. },
  148087. set: function(globe) {
  148088. this._globe = this._globe && this._globe.destroy();
  148089. this._globe = globe;
  148090. }
  148091. },
  148092. /**
  148093. * Gets the collection of primitives.
  148094. * @memberof Scene.prototype
  148095. *
  148096. * @type {PrimitiveCollection}
  148097. * @readonly
  148098. */
  148099. primitives : {
  148100. get : function() {
  148101. return this._primitives;
  148102. }
  148103. },
  148104. /**
  148105. * Gets the collection of ground primitives.
  148106. * @memberof Scene.prototype
  148107. *
  148108. * @type {PrimitiveCollection}
  148109. * @readonly
  148110. */
  148111. groundPrimitives : {
  148112. get : function() {
  148113. return this._groundPrimitives;
  148114. }
  148115. },
  148116. /**
  148117. * Gets the camera.
  148118. * @memberof Scene.prototype
  148119. *
  148120. * @type {Camera}
  148121. * @readonly
  148122. */
  148123. camera : {
  148124. get : function() {
  148125. return this._camera;
  148126. }
  148127. },
  148128. // TODO: setCamera
  148129. /**
  148130. * Gets the controller for camera input handling.
  148131. * @memberof Scene.prototype
  148132. *
  148133. * @type {ScreenSpaceCameraController}
  148134. * @readonly
  148135. */
  148136. screenSpaceCameraController : {
  148137. get : function() {
  148138. return this._screenSpaceCameraController;
  148139. }
  148140. },
  148141. /**
  148142. * Get the map projection to use in 2D and Columbus View modes.
  148143. * @memberof Scene.prototype
  148144. *
  148145. * @type {MapProjection}
  148146. * @readonly
  148147. *
  148148. * @default new GeographicProjection()
  148149. */
  148150. mapProjection : {
  148151. get: function() {
  148152. return this._mapProjection;
  148153. }
  148154. },
  148155. /**
  148156. * Gets state information about the current scene. If called outside of a primitive's <code>update</code>
  148157. * function, the previous frame's state is returned.
  148158. * @memberof Scene.prototype
  148159. *
  148160. * @type {FrameState}
  148161. * @readonly
  148162. *
  148163. * @private
  148164. */
  148165. frameState : {
  148166. get: function() {
  148167. return this._frameState;
  148168. }
  148169. },
  148170. /**
  148171. * Gets the collection of tweens taking place in the scene.
  148172. * @memberof Scene.prototype
  148173. *
  148174. * @type {TweenCollection}
  148175. * @readonly
  148176. *
  148177. * @private
  148178. */
  148179. tweens : {
  148180. get : function() {
  148181. return this._tweens;
  148182. }
  148183. },
  148184. /**
  148185. * Gets the collection of image layers that will be rendered on the globe.
  148186. * @memberof Scene.prototype
  148187. *
  148188. * @type {ImageryLayerCollection}
  148189. * @readonly
  148190. */
  148191. imageryLayers : {
  148192. get : function() {
  148193. return this.globe.imageryLayers;
  148194. }
  148195. },
  148196. /**
  148197. * The terrain provider providing surface geometry for the globe.
  148198. * @memberof Scene.prototype
  148199. *
  148200. * @type {TerrainProvider}
  148201. */
  148202. terrainProvider : {
  148203. get : function() {
  148204. return this.globe.terrainProvider;
  148205. },
  148206. set : function(terrainProvider) {
  148207. this.globe.terrainProvider = terrainProvider;
  148208. }
  148209. },
  148210. /**
  148211. * Gets an event that's raised when the terrain provider is changed
  148212. * @memberof Scene.prototype
  148213. *
  148214. * @type {Event}
  148215. * @readonly
  148216. */
  148217. terrainProviderChanged : {
  148218. get : function() {
  148219. return this.globe.terrainProviderChanged;
  148220. }
  148221. },
  148222. /**
  148223. * Gets the event that will be raised when an error is thrown inside the <code>render</code> function.
  148224. * The Scene instance and the thrown error are the only two parameters passed to the event handler.
  148225. * By default, errors are not rethrown after this event is raised, but that can be changed by setting
  148226. * the <code>rethrowRenderErrors</code> property.
  148227. * @memberof Scene.prototype
  148228. *
  148229. * @type {Event}
  148230. * @readonly
  148231. */
  148232. renderError : {
  148233. get : function() {
  148234. return this._renderError;
  148235. }
  148236. },
  148237. /**
  148238. * Gets the event that will be raised at the start of each call to <code>render</code>. Subscribers to the event
  148239. * receive the Scene instance as the first parameter and the current time as the second parameter.
  148240. * @memberof Scene.prototype
  148241. *
  148242. * @type {Event}
  148243. * @readonly
  148244. */
  148245. preRender : {
  148246. get : function() {
  148247. return this._preRender;
  148248. }
  148249. },
  148250. /**
  148251. * Gets the event that will be raised at the end of each call to <code>render</code>. Subscribers to the event
  148252. * receive the Scene instance as the first parameter and the current time as the second parameter.
  148253. * @memberof Scene.prototype
  148254. *
  148255. * @type {Event}
  148256. * @readonly
  148257. */
  148258. postRender : {
  148259. get : function() {
  148260. return this._postRender;
  148261. }
  148262. },
  148263. /**
  148264. * @memberof Scene.prototype
  148265. * @private
  148266. * @readonly
  148267. */
  148268. context : {
  148269. get : function() {
  148270. return this._context;
  148271. }
  148272. },
  148273. /**
  148274. * This property is for debugging only; it is not for production use.
  148275. * <p>
  148276. * When {@link Scene.debugShowFrustums} is <code>true</code>, this contains
  148277. * properties with statistics about the number of command execute per frustum.
  148278. * <code>totalCommands</code> is the total number of commands executed, ignoring
  148279. * overlap. <code>commandsInFrustums</code> is an array with the number of times
  148280. * commands are executed redundantly, e.g., how many commands overlap two or
  148281. * three frustums.
  148282. * </p>
  148283. *
  148284. * @memberof Scene.prototype
  148285. *
  148286. * @type {Object}
  148287. * @readonly
  148288. *
  148289. * @default undefined
  148290. */
  148291. debugFrustumStatistics : {
  148292. get : function() {
  148293. return this._debugFrustumStatistics;
  148294. }
  148295. },
  148296. /**
  148297. * Gets whether or not the scene is optimized for 3D only viewing.
  148298. * @memberof Scene.prototype
  148299. * @type {Boolean}
  148300. * @readonly
  148301. */
  148302. scene3DOnly : {
  148303. get : function() {
  148304. return this._frameState.scene3DOnly;
  148305. }
  148306. },
  148307. /**
  148308. * Gets whether or not the scene has order independent translucency enabled.
  148309. * Note that this only reflects the original construction option, and there are
  148310. * other factors that could prevent OIT from functioning on a given system configuration.
  148311. * @memberof Scene.prototype
  148312. * @type {Boolean}
  148313. * @readonly
  148314. */
  148315. orderIndependentTranslucency : {
  148316. get : function() {
  148317. return defined(this._oit);
  148318. }
  148319. },
  148320. /**
  148321. * Gets the unique identifier for this scene.
  148322. * @memberof Scene.prototype
  148323. * @type {String}
  148324. * @readonly
  148325. */
  148326. id : {
  148327. get : function() {
  148328. return this._id;
  148329. }
  148330. },
  148331. /**
  148332. * Gets or sets the current mode of the scene.
  148333. * @memberof Scene.prototype
  148334. * @type {SceneMode}
  148335. * @default {@link SceneMode.SCENE3D}
  148336. */
  148337. mode : {
  148338. get : function() {
  148339. return this._mode;
  148340. },
  148341. set : function(value) {
  148342. if (this.scene3DOnly && value !== SceneMode.SCENE3D) {
  148343. throw new DeveloperError('Only SceneMode.SCENE3D is valid when scene3DOnly is true.');
  148344. }
  148345. if (value === SceneMode.SCENE2D) {
  148346. this.morphTo2D(0);
  148347. } else if (value === SceneMode.SCENE3D) {
  148348. this.morphTo3D(0);
  148349. } else if (value === SceneMode.COLUMBUS_VIEW) {
  148350. this.morphToColumbusView(0);
  148351. } else {
  148352. throw new DeveloperError('value must be a valid SceneMode enumeration.');
  148353. }
  148354. this._mode = value;
  148355. }
  148356. },
  148357. /**
  148358. * Gets the number of frustums used in the last frame.
  148359. * @memberof Scene.prototype
  148360. * @type {Number}
  148361. *
  148362. * @private
  148363. */
  148364. numberOfFrustums : {
  148365. get : function() {
  148366. return this._frustumCommandsList.length;
  148367. }
  148368. },
  148369. /**
  148370. * Gets the scalar used to exaggerate the terrain.
  148371. * @memberof Scene.prototype
  148372. * @type {Number}
  148373. */
  148374. terrainExaggeration : {
  148375. get : function() {
  148376. return this._terrainExaggeration;
  148377. }
  148378. },
  148379. /**
  148380. * When <code>true</code>, splits the scene into two viewports with steroscopic views for the left and right eyes.
  148381. * Used for cardboard and WebVR.
  148382. * @memberof Scene.prototype
  148383. * @type {Boolean}
  148384. * @default false
  148385. */
  148386. useWebVR : {
  148387. get : function() {
  148388. return this._useWebVR;
  148389. },
  148390. set : function(value) {
  148391. this._useWebVR = value;
  148392. if (this._useWebVR) {
  148393. this._frameState.creditDisplay.container.style.visibility = 'hidden';
  148394. this._cameraVR = new Camera(this);
  148395. if (!defined(this._deviceOrientationCameraController)) {
  148396. this._deviceOrientationCameraController = new DeviceOrientationCameraController(this);
  148397. }
  148398. this._aspectRatioVR = this._camera.frustum.aspectRatio;
  148399. } else {
  148400. this._frameState.creditDisplay.container.style.visibility = 'visible';
  148401. this._cameraVR = undefined;
  148402. this._deviceOrientationCameraController = this._deviceOrientationCameraController && !this._deviceOrientationCameraController.isDestroyed() && this._deviceOrientationCameraController.destroy();
  148403. this._camera.frustum.aspectRatio = this._aspectRatioVR;
  148404. this._camera.frustum.xOffset = 0.0;
  148405. }
  148406. }
  148407. },
  148408. /**
  148409. * Determines if the 2D map is rotatable or can be scrolled infinitely in the horizontal direction.
  148410. * @memberof Scene.prototype
  148411. * @type {Boolean}
  148412. */
  148413. mapMode2D : {
  148414. get : function() {
  148415. return this._mapMode2D;
  148416. }
  148417. }
  148418. });
  148419. var scratchPosition0 = new Cartesian3();
  148420. var scratchPosition1 = new Cartesian3();
  148421. function maxComponent(a, b) {
  148422. var x = Math.max(Math.abs(a.x), Math.abs(b.x));
  148423. var y = Math.max(Math.abs(a.y), Math.abs(b.y));
  148424. var z = Math.max(Math.abs(a.z), Math.abs(b.z));
  148425. return Math.max(Math.max(x, y), z);
  148426. }
  148427. function cameraEqual(camera0, camera1, epsilon) {
  148428. var scalar = 1 / Math.max(1, maxComponent(camera0.position, camera1.position));
  148429. Cartesian3.multiplyByScalar(camera0.position, scalar, scratchPosition0);
  148430. Cartesian3.multiplyByScalar(camera1.position, scalar, scratchPosition1);
  148431. return Cartesian3.equalsEpsilon(scratchPosition0, scratchPosition1, epsilon) &&
  148432. Cartesian3.equalsEpsilon(camera0.direction, camera1.direction, epsilon) &&
  148433. Cartesian3.equalsEpsilon(camera0.up, camera1.up, epsilon) &&
  148434. Cartesian3.equalsEpsilon(camera0.right, camera1.right, epsilon) &&
  148435. Matrix4.equalsEpsilon(camera0.transform, camera1.transform, epsilon);
  148436. }
  148437. function updateDerivedCommands(scene, command) {
  148438. var frameState = scene.frameState;
  148439. var context = scene._context;
  148440. var shadowsEnabled = frameState.shadowHints.shadowsEnabled;
  148441. var shadowMaps = frameState.shadowHints.shadowMaps;
  148442. var lightShadowMaps = frameState.shadowHints.lightShadowMaps;
  148443. var lightShadowsEnabled = shadowsEnabled && (lightShadowMaps.length > 0);
  148444. // Update derived commands when any shadow maps become dirty
  148445. var shadowsDirty = false;
  148446. var lastDirtyTime = frameState.shadowHints.lastDirtyTime;
  148447. if (command.lastDirtyTime !== lastDirtyTime) {
  148448. command.lastDirtyTime = lastDirtyTime;
  148449. command.dirty = true;
  148450. shadowsDirty = true;
  148451. }
  148452. if (command.dirty) {
  148453. command.dirty = false;
  148454. var derivedCommands = command.derivedCommands;
  148455. if (shadowsEnabled && (command.receiveShadows || command.castShadows)) {
  148456. derivedCommands.shadows = ShadowMap.createDerivedCommands(shadowMaps, lightShadowMaps, command, shadowsDirty, context, derivedCommands.shadows);
  148457. }
  148458. var oit = scene._oit;
  148459. if (command.pass === Pass.TRANSLUCENT && defined(oit) && oit.isSupported()) {
  148460. if (lightShadowsEnabled && command.receiveShadows) {
  148461. derivedCommands.oit = defined(derivedCommands.oit) ? derivedCommands.oit : {};
  148462. derivedCommands.oit.shadows = oit.createDerivedCommands(command.derivedCommands.shadows.receiveCommand, context, derivedCommands.oit.shadows);
  148463. } else {
  148464. derivedCommands.oit = oit.createDerivedCommands(command, context, derivedCommands.oit);
  148465. }
  148466. }
  148467. }
  148468. }
  148469. var scratchOccluderBoundingSphere = new BoundingSphere();
  148470. var scratchOccluder;
  148471. function getOccluder(scene) {
  148472. // TODO: The occluder is the top-level globe. When we add
  148473. // support for multiple central bodies, this should be the closest one.
  148474. var globe = scene.globe;
  148475. if (scene._mode === SceneMode.SCENE3D && defined(globe)) {
  148476. var ellipsoid = globe.ellipsoid;
  148477. scratchOccluderBoundingSphere.radius = ellipsoid.minimumRadius;
  148478. scratchOccluder = Occluder.fromBoundingSphere(scratchOccluderBoundingSphere, scene._camera.positionWC, scratchOccluder);
  148479. return scratchOccluder;
  148480. }
  148481. return undefined;
  148482. }
  148483. function clearPasses(passes) {
  148484. passes.render = false;
  148485. passes.pick = false;
  148486. }
  148487. function updateFrameState(scene, frameNumber, time) {
  148488. var camera = scene._camera;
  148489. var frameState = scene._frameState;
  148490. frameState.commandList.length = 0;
  148491. frameState.shadowMaps.length = 0;
  148492. frameState.mode = scene._mode;
  148493. frameState.morphTime = scene.morphTime;
  148494. frameState.mapProjection = scene.mapProjection;
  148495. frameState.frameNumber = frameNumber;
  148496. frameState.time = JulianDate.clone(time, frameState.time);
  148497. frameState.camera = camera;
  148498. frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  148499. frameState.occluder = getOccluder(scene);
  148500. frameState.terrainExaggeration = scene._terrainExaggeration;
  148501. clearPasses(frameState.passes);
  148502. }
  148503. function updateFrustums(near, far, farToNearRatio, numFrustums, frustumCommandsList, is2D, nearToFarDistance2D) {
  148504. frustumCommandsList.length = numFrustums;
  148505. for (var m = 0; m < numFrustums; ++m) {
  148506. var curNear;
  148507. var curFar;
  148508. if (!is2D) {
  148509. curNear = Math.max(near, Math.pow(farToNearRatio, m) * near);
  148510. curFar = Math.min(far, farToNearRatio * curNear);
  148511. } else {
  148512. curNear = Math.min(far - nearToFarDistance2D, near + m * nearToFarDistance2D);
  148513. curFar = Math.min(far, curNear + nearToFarDistance2D);
  148514. }
  148515. var frustumCommands = frustumCommandsList[m];
  148516. if (!defined(frustumCommands)) {
  148517. frustumCommands = frustumCommandsList[m] = new FrustumCommands(curNear, curFar);
  148518. } else {
  148519. frustumCommands.near = curNear;
  148520. frustumCommands.far = curFar;
  148521. }
  148522. }
  148523. }
  148524. function insertIntoBin(scene, command, distance) {
  148525. if (scene.debugShowFrustums) {
  148526. command.debugOverlappingFrustums = 0;
  148527. }
  148528. if (!scene.frameState.passes.pick) {
  148529. updateDerivedCommands(scene, command);
  148530. }
  148531. var frustumCommandsList = scene._frustumCommandsList;
  148532. var length = frustumCommandsList.length;
  148533. for (var i = 0; i < length; ++i) {
  148534. var frustumCommands = frustumCommandsList[i];
  148535. var curNear = frustumCommands.near;
  148536. var curFar = frustumCommands.far;
  148537. if (distance.start > curFar) {
  148538. continue;
  148539. }
  148540. if (distance.stop < curNear) {
  148541. break;
  148542. }
  148543. var pass = command instanceof ClearCommand ? Pass.OPAQUE : command.pass;
  148544. var index = frustumCommands.indices[pass]++;
  148545. frustumCommands.commands[pass][index] = command;
  148546. if (scene.debugShowFrustums) {
  148547. command.debugOverlappingFrustums |= (1 << i);
  148548. }
  148549. if (command.executeInClosestFrustum) {
  148550. break;
  148551. }
  148552. }
  148553. if (scene.debugShowFrustums) {
  148554. var cf = scene._debugFrustumStatistics.commandsInFrustums;
  148555. cf[command.debugOverlappingFrustums] = defined(cf[command.debugOverlappingFrustums]) ? cf[command.debugOverlappingFrustums] + 1 : 1;
  148556. ++scene._debugFrustumStatistics.totalCommands;
  148557. }
  148558. }
  148559. var scratchCullingVolume = new CullingVolume();
  148560. var distances = new Interval();
  148561. function isVisible(command, cullingVolume, occluder) {
  148562. return ((defined(command)) &&
  148563. ((!defined(command.boundingVolume)) ||
  148564. !command.cull ||
  148565. ((cullingVolume.computeVisibility(command.boundingVolume) !== Intersect.OUTSIDE) &&
  148566. (!defined(occluder) || !command.boundingVolume.isOccluded(occluder)))));
  148567. }
  148568. function createPotentiallyVisibleSet(scene) {
  148569. var frameState = scene._frameState;
  148570. var camera = frameState.camera;
  148571. var direction = camera.directionWC;
  148572. var position = camera.positionWC;
  148573. var computeList = scene._computeCommandList;
  148574. var overlayList = scene._overlayCommandList;
  148575. var commandList = frameState.commandList;
  148576. if (scene.debugShowFrustums) {
  148577. scene._debugFrustumStatistics = {
  148578. totalCommands : 0,
  148579. commandsInFrustums : {}
  148580. };
  148581. }
  148582. var frustumCommandsList = scene._frustumCommandsList;
  148583. var numberOfFrustums = frustumCommandsList.length;
  148584. var numberOfPasses = Pass.NUMBER_OF_PASSES;
  148585. for (var n = 0; n < numberOfFrustums; ++n) {
  148586. for (var p = 0; p < numberOfPasses; ++p) {
  148587. frustumCommandsList[n].indices[p] = 0;
  148588. }
  148589. }
  148590. computeList.length = 0;
  148591. overlayList.length = 0;
  148592. var near = Number.MAX_VALUE;
  148593. var far = -Number.MAX_VALUE;
  148594. var undefBV = false;
  148595. var shadowsEnabled = frameState.shadowHints.shadowsEnabled;
  148596. var shadowNear = Number.MAX_VALUE;
  148597. var shadowFar = -Number.MAX_VALUE;
  148598. var shadowClosestObjectSize = Number.MAX_VALUE;
  148599. var occluder = (frameState.mode === SceneMode.SCENE3D) ? frameState.occluder: undefined;
  148600. var cullingVolume = frameState.cullingVolume;
  148601. // get user culling volume minus the far plane.
  148602. var planes = scratchCullingVolume.planes;
  148603. for (var k = 0; k < 5; ++k) {
  148604. planes[k] = cullingVolume.planes[k];
  148605. }
  148606. cullingVolume = scratchCullingVolume;
  148607. // Determine visibility of celestial and terrestrial environment effects.
  148608. var environmentState = scene._environmentState;
  148609. environmentState.isSkyAtmosphereVisible = defined(environmentState.skyAtmosphereCommand) && environmentState.isReadyForAtmosphere;
  148610. environmentState.isSunVisible = isVisible(environmentState.sunDrawCommand, cullingVolume, occluder);
  148611. environmentState.isMoonVisible = isVisible(environmentState.moonCommand, cullingVolume, occluder);
  148612. var length = commandList.length;
  148613. for (var i = 0; i < length; ++i) {
  148614. var command = commandList[i];
  148615. var pass = command.pass;
  148616. if (pass === Pass.COMPUTE) {
  148617. computeList.push(command);
  148618. } else if (pass === Pass.OVERLAY) {
  148619. overlayList.push(command);
  148620. } else {
  148621. var boundingVolume = command.boundingVolume;
  148622. if (defined(boundingVolume)) {
  148623. if (!isVisible(command, cullingVolume, occluder)) {
  148624. continue;
  148625. }
  148626. distances = boundingVolume.computePlaneDistances(position, direction, distances);
  148627. near = Math.min(near, distances.start);
  148628. far = Math.max(far, distances.stop);
  148629. // Compute a tight near and far plane for commands that receive shadows. This helps compute
  148630. // good splits for cascaded shadow maps. Ignore commands that exceed the maximum distance.
  148631. // When moving the camera low LOD globe tiles begin to load, whose bounding volumes
  148632. // throw off the near/far fitting for the shadow map. Only update for globe tiles that the
  148633. // camera isn't inside.
  148634. if (shadowsEnabled && command.receiveShadows && (distances.start < ShadowMap.MAXIMUM_DISTANCE) &&
  148635. !((pass === Pass.GLOBE) && (distances.start < -100.0) && (distances.stop > 100.0))) {
  148636. // Get the smallest bounding volume the camera is near. This is used to place more shadow detail near the object.
  148637. var size = distances.stop - distances.start;
  148638. if ((pass !== Pass.GLOBE) && (distances.start < 100.0)) {
  148639. shadowClosestObjectSize = Math.min(shadowClosestObjectSize, size);
  148640. }
  148641. shadowNear = Math.min(shadowNear, distances.start);
  148642. shadowFar = Math.max(shadowFar, distances.stop);
  148643. }
  148644. } else {
  148645. // Clear commands don't need a bounding volume - just add the clear to all frustums.
  148646. // If another command has no bounding volume, though, we need to use the camera's
  148647. // worst-case near and far planes to avoid clipping something important.
  148648. distances.start = camera.frustum.near;
  148649. distances.stop = camera.frustum.far;
  148650. undefBV = !(command instanceof ClearCommand);
  148651. }
  148652. insertIntoBin(scene, command, distances);
  148653. }
  148654. }
  148655. if (undefBV) {
  148656. near = camera.frustum.near;
  148657. far = camera.frustum.far;
  148658. } else {
  148659. // The computed near plane must be between the user defined near and far planes.
  148660. // The computed far plane must between the user defined far and computed near.
  148661. // This will handle the case where the computed near plane is further than the user defined far plane.
  148662. near = Math.min(Math.max(near, camera.frustum.near), camera.frustum.far);
  148663. far = Math.max(Math.min(far, camera.frustum.far), near);
  148664. if (shadowsEnabled) {
  148665. shadowNear = Math.min(Math.max(shadowNear, camera.frustum.near), camera.frustum.far);
  148666. shadowFar = Math.max(Math.min(shadowFar, camera.frustum.far), shadowNear);
  148667. }
  148668. }
  148669. // Use the computed near and far for shadows
  148670. if (shadowsEnabled) {
  148671. frameState.shadowHints.nearPlane = shadowNear;
  148672. frameState.shadowHints.farPlane = shadowFar;
  148673. frameState.shadowHints.closestObjectSize = shadowClosestObjectSize;
  148674. }
  148675. // Exploit temporal coherence. If the frustums haven't changed much, use the frustums computed
  148676. // last frame, else compute the new frustums and sort them by frustum again.
  148677. var is2D = scene.mode === SceneMode.SCENE2D;
  148678. var farToNearRatio = scene.farToNearRatio;
  148679. var numFrustums;
  148680. if (!is2D) {
  148681. // The multifrustum for 3D/CV is non-uniformly distributed.
  148682. numFrustums = Math.ceil(Math.log(far / near) / Math.log(farToNearRatio));
  148683. } else {
  148684. // The multifrustum for 2D is uniformly distributed. To avoid z-fighting in 2D,
  148685. // the camera i smoved to just before the frustum and the frustum depth is scaled
  148686. // to be in [1.0, nearToFarDistance2D].
  148687. far = Math.min(far, camera.position.z + scene.nearToFarDistance2D);
  148688. near = Math.min(near, far);
  148689. numFrustums = Math.ceil(Math.max(1.0, far - near) / scene.nearToFarDistance2D);
  148690. }
  148691. if (near !== Number.MAX_VALUE && (numFrustums !== numberOfFrustums || (frustumCommandsList.length !== 0 &&
  148692. (near < frustumCommandsList[0].near || far > frustumCommandsList[numberOfFrustums - 1].far)))) {
  148693. updateFrustums(near, far, farToNearRatio, numFrustums, frustumCommandsList, is2D, scene.nearToFarDistance2D);
  148694. createPotentiallyVisibleSet(scene);
  148695. }
  148696. }
  148697. function getAttributeLocations(shaderProgram) {
  148698. var attributeLocations = {};
  148699. var attributes = shaderProgram.vertexAttributes;
  148700. for (var a in attributes) {
  148701. if (attributes.hasOwnProperty(a)) {
  148702. attributeLocations[a] = attributes[a].index;
  148703. }
  148704. }
  148705. return attributeLocations;
  148706. }
  148707. function createDebugFragmentShaderProgram(command, scene, shaderProgram) {
  148708. var context = scene.context;
  148709. var sp = defaultValue(shaderProgram, command.shaderProgram);
  148710. var fs = sp.fragmentShaderSource.clone();
  148711. fs.sources = fs.sources.map(function(source) {
  148712. source = ShaderSource.replaceMain(source, 'czm_Debug_main');
  148713. return source;
  148714. });
  148715. var newMain =
  148716. 'void main() \n' +
  148717. '{ \n' +
  148718. ' czm_Debug_main(); \n';
  148719. if (scene.debugShowCommands) {
  148720. if (!defined(command._debugColor)) {
  148721. command._debugColor = Color.fromRandom();
  148722. }
  148723. var c = command._debugColor;
  148724. newMain += ' gl_FragColor.rgb *= vec3(' + c.red + ', ' + c.green + ', ' + c.blue + '); \n';
  148725. }
  148726. if (scene.debugShowFrustums) {
  148727. // Support up to three frustums. If a command overlaps all
  148728. // three, it's code is not changed.
  148729. var r = (command.debugOverlappingFrustums & (1 << 0)) ? '1.0' : '0.0';
  148730. var g = (command.debugOverlappingFrustums & (1 << 1)) ? '1.0' : '0.0';
  148731. var b = (command.debugOverlappingFrustums & (1 << 2)) ? '1.0' : '0.0';
  148732. newMain += ' gl_FragColor.rgb *= vec3(' + r + ', ' + g + ', ' + b + '); \n';
  148733. }
  148734. newMain += '}';
  148735. fs.sources.push(newMain);
  148736. var attributeLocations = getAttributeLocations(sp);
  148737. return ShaderProgram.fromCache({
  148738. context : context,
  148739. vertexShaderSource : sp.vertexShaderSource,
  148740. fragmentShaderSource : fs,
  148741. attributeLocations : attributeLocations
  148742. });
  148743. }
  148744. function executeDebugCommand(command, scene, passState) {
  148745. var debugCommand = DrawCommand.shallowClone(command);
  148746. debugCommand.shaderProgram = createDebugFragmentShaderProgram(command, scene);
  148747. debugCommand.execute(scene.context, passState);
  148748. debugCommand.shaderProgram.destroy();
  148749. }
  148750. var transformFrom2D = new Matrix4(0.0, 0.0, 1.0, 0.0,
  148751. 1.0, 0.0, 0.0, 0.0,
  148752. 0.0, 1.0, 0.0, 0.0,
  148753. 0.0, 0.0, 0.0, 1.0);
  148754. transformFrom2D = Matrix4.inverseTransformation(transformFrom2D, transformFrom2D);
  148755. function executeCommand(command, scene, context, passState, debugFramebuffer) {
  148756. if ((defined(scene.debugCommandFilter)) && !scene.debugCommandFilter(command)) {
  148757. return;
  148758. }
  148759. var shadowsEnabled = scene.frameState.shadowHints.shadowsEnabled;
  148760. var lightShadowsEnabled = shadowsEnabled && (scene.frameState.shadowHints.lightShadowMaps.length > 0);
  148761. if (scene.debugShowCommands || scene.debugShowFrustums) {
  148762. executeDebugCommand(command, scene, passState);
  148763. } else if (lightShadowsEnabled && command.receiveShadows && defined(command.derivedCommands.shadows)) {
  148764. // If the command receives shadows, execute the derived shadows command.
  148765. // Some commands, such as OIT derived commands, do not have derived shadow commands themselves
  148766. // and instead shadowing is built-in. In this case execute the command regularly below.
  148767. command.derivedCommands.shadows.receiveCommand.execute(context, passState);
  148768. } else {
  148769. command.execute(context, passState);
  148770. }
  148771. if (command.debugShowBoundingVolume && (defined(command.boundingVolume))) {
  148772. // Debug code to draw bounding volume for command. Not optimized!
  148773. // Assumes bounding volume is a bounding sphere or box
  148774. var frameState = scene._frameState;
  148775. var boundingVolume = command.boundingVolume;
  148776. if (defined(scene._debugVolume)) {
  148777. scene._debugVolume.destroy();
  148778. }
  148779. var geometry;
  148780. var center = Cartesian3.clone(boundingVolume.center);
  148781. if (frameState.mode !== SceneMode.SCENE3D) {
  148782. center = Matrix4.multiplyByPoint(transformFrom2D, center, center);
  148783. var projection = frameState.mapProjection;
  148784. var centerCartographic = projection.unproject(center);
  148785. center = projection.ellipsoid.cartographicToCartesian(centerCartographic);
  148786. }
  148787. if (defined(boundingVolume.radius)) {
  148788. var radius = boundingVolume.radius;
  148789. geometry = GeometryPipeline.toWireframe(EllipsoidGeometry.createGeometry(new EllipsoidGeometry({
  148790. radii : new Cartesian3(radius, radius, radius),
  148791. vertexFormat : PerInstanceColorAppearance.FLAT_VERTEX_FORMAT
  148792. })));
  148793. scene._debugVolume = new Primitive({
  148794. geometryInstances : new GeometryInstance({
  148795. geometry : geometry,
  148796. modelMatrix : Matrix4.multiplyByTranslation(Matrix4.IDENTITY, center, new Matrix4()),
  148797. attributes : {
  148798. color : new ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 1.0)
  148799. }
  148800. }),
  148801. appearance : new PerInstanceColorAppearance({
  148802. flat : true,
  148803. translucent : false
  148804. }),
  148805. asynchronous : false
  148806. });
  148807. } else {
  148808. var halfAxes = boundingVolume.halfAxes;
  148809. geometry = GeometryPipeline.toWireframe(BoxGeometry.createGeometry(BoxGeometry.fromDimensions({
  148810. dimensions : new Cartesian3(2.0, 2.0, 2.0),
  148811. vertexFormat : PerInstanceColorAppearance.FLAT_VERTEX_FORMAT
  148812. })));
  148813. scene._debugVolume = new Primitive({
  148814. geometryInstances : new GeometryInstance({
  148815. geometry : geometry,
  148816. modelMatrix : Matrix4.fromRotationTranslation(halfAxes, center, new Matrix4()),
  148817. attributes : {
  148818. color : new ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 1.0)
  148819. }
  148820. }),
  148821. appearance : new PerInstanceColorAppearance({
  148822. flat : true,
  148823. translucent : false
  148824. }),
  148825. asynchronous : false
  148826. });
  148827. }
  148828. var savedCommandList = frameState.commandList;
  148829. var commandList = frameState.commandList = [];
  148830. scene._debugVolume.update(frameState);
  148831. var framebuffer;
  148832. if (defined(debugFramebuffer)) {
  148833. framebuffer = passState.framebuffer;
  148834. passState.framebuffer = debugFramebuffer;
  148835. }
  148836. commandList[0].execute(context, passState);
  148837. if (defined(framebuffer)) {
  148838. passState.framebuffer = framebuffer;
  148839. }
  148840. frameState.commandList = savedCommandList;
  148841. }
  148842. }
  148843. function translucentCompare(a, b, position) {
  148844. return b.boundingVolume.distanceSquaredTo(position) - a.boundingVolume.distanceSquaredTo(position);
  148845. }
  148846. function executeTranslucentCommandsSorted(scene, executeFunction, passState, commands) {
  148847. var context = scene.context;
  148848. mergeSort(commands, translucentCompare, scene._camera.positionWC);
  148849. var length = commands.length;
  148850. for (var j = 0; j < length; ++j) {
  148851. executeFunction(commands[j], scene, context, passState);
  148852. }
  148853. }
  148854. function getDebugGlobeDepth(scene, index) {
  148855. var globeDepth = scene._debugGlobeDepths[index];
  148856. if (!defined(globeDepth) && scene.context.depthTexture) {
  148857. globeDepth = new GlobeDepth();
  148858. scene._debugGlobeDepths[index] = globeDepth;
  148859. }
  148860. return globeDepth;
  148861. }
  148862. function getPickDepth(scene, index) {
  148863. var pickDepth = scene._pickDepths[index];
  148864. if (!defined(pickDepth)) {
  148865. pickDepth = new PickDepth();
  148866. scene._pickDepths[index] = pickDepth;
  148867. }
  148868. return pickDepth;
  148869. }
  148870. var scratchPerspectiveFrustum = new PerspectiveFrustum();
  148871. var scratchPerspectiveOffCenterFrustum = new PerspectiveOffCenterFrustum();
  148872. var scratchOrthographicFrustum = new OrthographicFrustum();
  148873. function executeCommands(scene, passState) {
  148874. var camera = scene._camera;
  148875. var context = scene.context;
  148876. var us = context.uniformState;
  148877. us.updateCamera(camera);
  148878. // Create a working frustum from the original camera frustum.
  148879. var frustum;
  148880. if (defined(camera.frustum.fov)) {
  148881. frustum = camera.frustum.clone(scratchPerspectiveFrustum);
  148882. } else if (defined(camera.frustum.infiniteProjectionMatrix)){
  148883. frustum = camera.frustum.clone(scratchPerspectiveOffCenterFrustum);
  148884. } else {
  148885. frustum = camera.frustum.clone(scratchOrthographicFrustum);
  148886. }
  148887. // Ideally, we would render the sky box and atmosphere last for
  148888. // early-z, but we would have to draw it in each frustum
  148889. frustum.near = camera.frustum.near;
  148890. frustum.far = camera.frustum.far;
  148891. us.updateFrustum(frustum);
  148892. us.updatePass(Pass.ENVIRONMENT);
  148893. var environmentState = scene._environmentState;
  148894. var skyBoxCommand = environmentState.skyBoxCommand;
  148895. if (defined(skyBoxCommand)) {
  148896. executeCommand(skyBoxCommand, scene, context, passState);
  148897. }
  148898. if (environmentState.isSkyAtmosphereVisible) {
  148899. executeCommand(environmentState.skyAtmosphereCommand, scene, context, passState);
  148900. }
  148901. var useWebVR = scene._useWebVR && scene.mode !== SceneMode.SCENE2D;
  148902. if (environmentState.isSunVisible) {
  148903. environmentState.sunDrawCommand.execute(context, passState);
  148904. if (scene.sunBloom && !useWebVR) {
  148905. var framebuffer;
  148906. if (environmentState.useGlobeDepthFramebuffer) {
  148907. framebuffer = scene._globeDepth.framebuffer;
  148908. } else if (environmentState.useFXAA) {
  148909. framebuffer = scene._fxaa.getColorFramebuffer();
  148910. } else {
  148911. framebuffer = environmentState.originalFramebuffer;
  148912. }
  148913. scene._sunPostProcess.execute(context, framebuffer);
  148914. passState.framebuffer = framebuffer;
  148915. }
  148916. }
  148917. // Moon can be seen through the atmosphere, since the sun is rendered after the atmosphere.
  148918. if (environmentState.isMoonVisible) {
  148919. environmentState.moonCommand.execute(context, passState);
  148920. }
  148921. // Determine how translucent surfaces will be handled.
  148922. var executeTranslucentCommands;
  148923. if (environmentState.useOIT) {
  148924. if (!defined(scene._executeOITFunction)) {
  148925. scene._executeOITFunction = function(scene, executeFunction, passState, commands) {
  148926. scene._oit.executeCommands(scene, executeFunction, passState, commands);
  148927. };
  148928. }
  148929. executeTranslucentCommands = scene._executeOITFunction;
  148930. } else {
  148931. executeTranslucentCommands = executeTranslucentCommandsSorted;
  148932. }
  148933. var clearGlobeDepth = environmentState.clearGlobeDepth;
  148934. var useDepthPlane = environmentState.useDepthPlane;
  148935. var clearDepth = scene._depthClearCommand;
  148936. var depthPlane = scene._depthPlane;
  148937. var height2D = camera.position.z;
  148938. // Execute commands in each frustum in back to front order
  148939. var j;
  148940. var frustumCommandsList = scene._frustumCommandsList;
  148941. var numFrustums = frustumCommandsList.length;
  148942. for (var i = 0; i < numFrustums; ++i) {
  148943. var index = numFrustums - i - 1;
  148944. var frustumCommands = frustumCommandsList[index];
  148945. if (scene.mode === SceneMode.SCENE2D) {
  148946. // To avoid z-fighting in 2D, move the camera to just before the frustum
  148947. // and scale the frustum depth to be in [1.0, nearToFarDistance2D].
  148948. camera.position.z = height2D - frustumCommands.near + 1.0;
  148949. frustum.far = Math.max(1.0, frustumCommands.far - frustumCommands.near);
  148950. frustum.near = 1.0;
  148951. us.update(scene.frameState);
  148952. us.updateFrustum(frustum);
  148953. } else {
  148954. // Avoid tearing artifacts between adjacent frustums in the opaque passes
  148955. frustum.near = index !== 0 ? frustumCommands.near * OPAQUE_FRUSTUM_NEAR_OFFSET : frustumCommands.near;
  148956. frustum.far = frustumCommands.far;
  148957. us.updateFrustum(frustum);
  148958. }
  148959. var globeDepth = scene.debugShowGlobeDepth ? getDebugGlobeDepth(scene, index) : scene._globeDepth;
  148960. var fb;
  148961. if (scene.debugShowGlobeDepth && defined(globeDepth) && environmentState.useGlobeDepthFramebuffer) {
  148962. fb = passState.framebuffer;
  148963. passState.framebuffer = globeDepth.framebuffer;
  148964. }
  148965. clearDepth.execute(context, passState);
  148966. us.updatePass(Pass.GLOBE);
  148967. var commands = frustumCommands.commands[Pass.GLOBE];
  148968. var length = frustumCommands.indices[Pass.GLOBE];
  148969. for (j = 0; j < length; ++j) {
  148970. executeCommand(commands[j], scene, context, passState);
  148971. }
  148972. if (defined(globeDepth) && environmentState.useGlobeDepthFramebuffer && (scene.copyGlobeDepth || scene.debugShowGlobeDepth)) {
  148973. globeDepth.update(context);
  148974. globeDepth.executeCopyDepth(context, passState);
  148975. }
  148976. if (scene.debugShowGlobeDepth && defined(globeDepth) && environmentState.useGlobeDepthFramebuffer) {
  148977. passState.framebuffer = fb;
  148978. }
  148979. us.updatePass(Pass.GROUND);
  148980. commands = frustumCommands.commands[Pass.GROUND];
  148981. length = frustumCommands.indices[Pass.GROUND];
  148982. for (j = 0; j < length; ++j) {
  148983. executeCommand(commands[j], scene, context, passState);
  148984. }
  148985. // Clear the stencil after the ground pass
  148986. if (length > 0 && context.stencilBuffer) {
  148987. scene._stencilClearCommand.execute(context, passState);
  148988. }
  148989. if (clearGlobeDepth) {
  148990. clearDepth.execute(context, passState);
  148991. if (useDepthPlane) {
  148992. depthPlane.execute(context, passState);
  148993. }
  148994. }
  148995. // Execute commands in order by pass up to the translucent pass.
  148996. // Translucent geometry needs special handling (sorting/OIT).
  148997. var startPass = Pass.GROUND + 1;
  148998. var endPass = Pass.TRANSLUCENT;
  148999. for (var pass = startPass; pass < endPass; ++pass) {
  149000. us.updatePass(pass);
  149001. commands = frustumCommands.commands[pass];
  149002. length = frustumCommands.indices[pass];
  149003. for (j = 0; j < length; ++j) {
  149004. executeCommand(commands[j], scene, context, passState);
  149005. }
  149006. }
  149007. if (index !== 0 && scene.mode !== SceneMode.SCENE2D) {
  149008. // Do not overlap frustums in the translucent pass to avoid blending artifacts
  149009. frustum.near = frustumCommands.near;
  149010. us.updateFrustum(frustum);
  149011. }
  149012. us.updatePass(Pass.TRANSLUCENT);
  149013. commands = frustumCommands.commands[Pass.TRANSLUCENT];
  149014. commands.length = frustumCommands.indices[Pass.TRANSLUCENT];
  149015. executeTranslucentCommands(scene, executeCommand, passState, commands);
  149016. if (defined(globeDepth) && environmentState.useGlobeDepthFramebuffer && scene.useDepthPicking) {
  149017. // PERFORMANCE_IDEA: Use MRT to avoid the extra copy.
  149018. var pickDepth = getPickDepth(scene, index);
  149019. pickDepth.update(context, globeDepth.framebuffer.depthStencilTexture);
  149020. pickDepth.executeCopyDepth(context, passState);
  149021. }
  149022. }
  149023. }
  149024. function executeComputeCommands(scene) {
  149025. var us = scene.context.uniformState;
  149026. us.updatePass(Pass.COMPUTE);
  149027. var sunComputeCommand = scene._environmentState.sunComputeCommand;
  149028. if (defined(sunComputeCommand)) {
  149029. sunComputeCommand.execute(scene._computeEngine);
  149030. }
  149031. var commandList = scene._computeCommandList;
  149032. var length = commandList.length;
  149033. for (var i = 0; i < length; ++i) {
  149034. commandList[i].execute(scene._computeEngine);
  149035. }
  149036. }
  149037. function executeOverlayCommands(scene, passState) {
  149038. var us = scene.context.uniformState;
  149039. us.updatePass(Pass.OVERLAY);
  149040. var context = scene.context;
  149041. var commandList = scene._overlayCommandList;
  149042. var length = commandList.length;
  149043. for (var i = 0; i < length; ++i) {
  149044. commandList[i].execute(context, passState);
  149045. }
  149046. }
  149047. function insertShadowCastCommands(scene, commandList, shadowMap) {
  149048. var shadowVolume = shadowMap.shadowMapCullingVolume;
  149049. var isPointLight = shadowMap.isPointLight;
  149050. var passes = shadowMap.passes;
  149051. var numberOfPasses = passes.length;
  149052. var length = commandList.length;
  149053. for (var i = 0; i < length; ++i) {
  149054. var command = commandList[i];
  149055. updateDerivedCommands(scene, command);
  149056. if (command.castShadows && (command.pass === Pass.GLOBE || command.pass === Pass.OPAQUE || command.pass === Pass.TRANSLUCENT)) {
  149057. if (isVisible(command, shadowVolume)) {
  149058. if (isPointLight) {
  149059. for (var k = 0; k < numberOfPasses; ++k) {
  149060. passes[k].commandList.push(command);
  149061. }
  149062. } else if (numberOfPasses === 1) {
  149063. passes[0].commandList.push(command);
  149064. } else {
  149065. var wasVisible = false;
  149066. // Loop over cascades from largest to smallest
  149067. for (var j = numberOfPasses - 1; j >= 0; --j) {
  149068. var cascadeVolume = passes[j].cullingVolume;
  149069. if (isVisible(command, cascadeVolume)) {
  149070. passes[j].commandList.push(command);
  149071. wasVisible = true;
  149072. } else if (wasVisible) {
  149073. // If it was visible in the previous cascade but now isn't
  149074. // then there is no need to check any more cascades
  149075. break;
  149076. }
  149077. }
  149078. }
  149079. }
  149080. }
  149081. }
  149082. }
  149083. function executeShadowMapCastCommands(scene) {
  149084. var frameState = scene.frameState;
  149085. var shadowMaps = frameState.shadowHints.shadowMaps;
  149086. var shadowMapLength = shadowMaps.length;
  149087. if (!frameState.shadowHints.shadowsEnabled) {
  149088. return;
  149089. }
  149090. var context = scene.context;
  149091. var uniformState = context.uniformState;
  149092. for (var i = 0; i < shadowMapLength; ++i) {
  149093. var shadowMap = shadowMaps[i];
  149094. if (shadowMap.outOfView) {
  149095. continue;
  149096. }
  149097. // Reset the command lists
  149098. var j;
  149099. var passes = shadowMap.passes;
  149100. var numberOfPasses = passes.length;
  149101. for (j = 0; j < numberOfPasses; ++j) {
  149102. passes[j].commandList.length = 0;
  149103. }
  149104. // Insert the primitive/model commands into the command lists
  149105. var sceneCommands = scene.frameState.commandList;
  149106. insertShadowCastCommands(scene, sceneCommands, shadowMap);
  149107. for (j = 0; j < numberOfPasses; ++j) {
  149108. var pass = shadowMap.passes[j];
  149109. uniformState.updateCamera(pass.camera);
  149110. shadowMap.updatePass(context, j);
  149111. var numberOfCommands = pass.commandList.length;
  149112. for (var k = 0; k < numberOfCommands; ++k) {
  149113. var command = pass.commandList[k];
  149114. // Set the correct pass before rendering into the shadow map because some shaders
  149115. // conditionally render based on whether the pass is translucent or opaque.
  149116. uniformState.updatePass(command.pass);
  149117. executeCommand(command.derivedCommands.shadows.castCommands[i], scene, context, pass.passState);
  149118. }
  149119. }
  149120. }
  149121. }
  149122. function updateAndExecuteCommands(scene, passState, backgroundColor, picking) {
  149123. var context = scene._context;
  149124. var viewport = passState.viewport;
  149125. var frameState = scene._frameState;
  149126. var camera = frameState.camera;
  149127. var mode = frameState.mode;
  149128. if (scene._useWebVR && mode !== SceneMode.SCENE2D) {
  149129. updatePrimitives(scene);
  149130. createPotentiallyVisibleSet(scene);
  149131. updateAndClearFramebuffers(scene, passState, backgroundColor, picking);
  149132. executeComputeCommands(scene);
  149133. executeShadowMapCastCommands(scene);
  149134. // Based on Calculating Stereo pairs by Paul Bourke
  149135. // http://paulbourke.net/stereographics/stereorender/
  149136. viewport.x = 0;
  149137. viewport.y = 0;
  149138. viewport.width = context.drawingBufferWidth * 0.5;
  149139. viewport.height = context.drawingBufferHeight;
  149140. var savedCamera = Camera.clone(camera, scene._cameraVR);
  149141. var near = camera.frustum.near;
  149142. var fo = near * 5.0;
  149143. var eyeSeparation = fo / 30.0;
  149144. var eyeTranslation = Cartesian3.multiplyByScalar(savedCamera.right, eyeSeparation * 0.5, scratchEyeTranslation);
  149145. camera.frustum.aspectRatio = viewport.width / viewport.height;
  149146. var offset = 0.5 * eyeSeparation * near / fo;
  149147. Cartesian3.add(savedCamera.position, eyeTranslation, camera.position);
  149148. camera.frustum.xOffset = offset;
  149149. executeCommands(scene, passState);
  149150. viewport.x = passState.viewport.width;
  149151. Cartesian3.subtract(savedCamera.position, eyeTranslation, camera.position);
  149152. camera.frustum.xOffset = -offset;
  149153. executeCommands(scene, passState);
  149154. Camera.clone(savedCamera, camera);
  149155. } else {
  149156. viewport.x = 0;
  149157. viewport.y = 0;
  149158. viewport.width = context.drawingBufferWidth;
  149159. viewport.height = context.drawingBufferHeight;
  149160. if (mode !== SceneMode.SCENE2D || scene._mapMode2D === MapMode2D.ROTATE) {
  149161. executeCommandsInViewport(true, scene, passState, backgroundColor, picking);
  149162. } else {
  149163. execute2DViewportCommands(scene, passState, backgroundColor, picking);
  149164. }
  149165. }
  149166. }
  149167. var scratch2DViewportCartographic = new Cartographic(Math.PI, CesiumMath.PI_OVER_TWO);
  149168. var scratch2DViewportMaxCoord = new Cartesian3();
  149169. var scratch2DViewportSavedPosition = new Cartesian3();
  149170. var scratch2DViewportTransform = new Matrix4();
  149171. var scratch2DViewportCameraTransform = new Matrix4();
  149172. var scratch2DViewportEyePoint = new Cartesian3();
  149173. var scratch2DViewportWindowCoords = new Cartesian3();
  149174. function execute2DViewportCommands(scene, passState, backgroundColor, picking) {
  149175. var context = scene.context;
  149176. var frameState = scene.frameState;
  149177. var camera = scene.camera;
  149178. var viewport = passState.viewport;
  149179. var maxCartographic = scratch2DViewportCartographic;
  149180. var maxCoord = scratch2DViewportMaxCoord;
  149181. var projection = scene.mapProjection;
  149182. projection.project(maxCartographic, maxCoord);
  149183. var position = Cartesian3.clone(camera.position, scratch2DViewportSavedPosition);
  149184. var transform = Matrix4.clone(camera.transform, scratch2DViewportCameraTransform);
  149185. var frustum = camera.frustum.clone();
  149186. camera._setTransform(Matrix4.IDENTITY);
  149187. var viewportTransformation = Matrix4.computeViewportTransformation(viewport, 0.0, 1.0, scratch2DViewportTransform);
  149188. var projectionMatrix = camera.frustum.projectionMatrix;
  149189. var x = camera.positionWC.y;
  149190. var eyePoint = Cartesian3.fromElements(CesiumMath.sign(x) * maxCoord.x - x, 0.0, -camera.positionWC.x, scratch2DViewportEyePoint);
  149191. var windowCoordinates = Transforms.pointToGLWindowCoordinates(projectionMatrix, viewportTransformation, eyePoint, scratch2DViewportWindowCoords);
  149192. windowCoordinates.x = Math.floor(windowCoordinates.x);
  149193. var viewportX = viewport.x;
  149194. var viewportWidth = viewport.width;
  149195. if (x === 0.0 || windowCoordinates.x <= 0.0 || windowCoordinates.x >= context.drawingBufferWidth) {
  149196. executeCommandsInViewport(true, scene, passState, backgroundColor, picking);
  149197. } else if (Math.abs(context.drawingBufferWidth * 0.5 - windowCoordinates.x) < 1.0) {
  149198. viewport.width = windowCoordinates.x;
  149199. camera.position.x *= CesiumMath.sign(camera.position.x);
  149200. camera.frustum.right = 0.0;
  149201. frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  149202. context.uniformState.update(frameState);
  149203. executeCommandsInViewport(true, scene, passState, backgroundColor, picking);
  149204. viewport.x = viewport.width;
  149205. camera.position.x = -camera.position.x;
  149206. camera.frustum.right = -camera.frustum.left;
  149207. camera.frustum.left = 0.0;
  149208. frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  149209. context.uniformState.update(frameState);
  149210. executeCommandsInViewport(false, scene, passState, backgroundColor, picking);
  149211. } else if (windowCoordinates.x > context.drawingBufferWidth * 0.5) {
  149212. viewport.width = windowCoordinates.x;
  149213. var right = camera.frustum.right;
  149214. camera.frustum.right = maxCoord.x - x;
  149215. frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  149216. context.uniformState.update(frameState);
  149217. executeCommandsInViewport(true, scene, passState, backgroundColor, picking);
  149218. viewport.x += windowCoordinates.x;
  149219. viewport.width = context.drawingBufferWidth - windowCoordinates.x;
  149220. camera.position.x = -camera.position.x;
  149221. camera.frustum.left = -camera.frustum.right;
  149222. camera.frustum.right = right - camera.frustum.right * 2.0;
  149223. frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  149224. context.uniformState.update(frameState);
  149225. executeCommandsInViewport(false, scene, passState, backgroundColor, picking);
  149226. } else {
  149227. viewport.x = windowCoordinates.x;
  149228. viewport.width = context.drawingBufferWidth - windowCoordinates.x;
  149229. var left = camera.frustum.left;
  149230. camera.frustum.left = -maxCoord.x - x;
  149231. frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  149232. context.uniformState.update(frameState);
  149233. executeCommandsInViewport(true, scene, passState, backgroundColor, picking);
  149234. viewport.x = 0;
  149235. viewport.width = windowCoordinates.x;
  149236. camera.position.x = -camera.position.x;
  149237. camera.frustum.right = -camera.frustum.left;
  149238. camera.frustum.left = left - camera.frustum.left * 2.0;
  149239. frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  149240. context.uniformState.update(frameState);
  149241. executeCommandsInViewport(false, scene, passState, backgroundColor, picking);
  149242. }
  149243. camera._setTransform(transform);
  149244. Cartesian3.clone(position, camera.position);
  149245. camera.frustum = frustum.clone();
  149246. viewport.x = viewportX;
  149247. viewport.width = viewportWidth;
  149248. }
  149249. function executeCommandsInViewport(firstViewport, scene, passState, backgroundColor, picking) {
  149250. if (!firstViewport) {
  149251. scene.frameState.commandList.length = 0;
  149252. }
  149253. updatePrimitives(scene);
  149254. createPotentiallyVisibleSet(scene);
  149255. if (firstViewport) {
  149256. updateAndClearFramebuffers(scene, passState, backgroundColor, picking);
  149257. executeComputeCommands(scene);
  149258. executeShadowMapCastCommands(scene);
  149259. }
  149260. executeCommands(scene, passState);
  149261. }
  149262. function updateEnvironment(scene) {
  149263. var frameState = scene._frameState;
  149264. // Update celestial and terrestrial environment effects.
  149265. var environmentState = scene._environmentState;
  149266. var renderPass = frameState.passes.render;
  149267. environmentState.skyBoxCommand = (renderPass && defined(scene.skyBox)) ? scene.skyBox.update(frameState) : undefined;
  149268. var skyAtmosphere = scene.skyAtmosphere;
  149269. var globe = scene.globe;
  149270. if (defined(skyAtmosphere) && defined(globe)) {
  149271. skyAtmosphere.setDynamicAtmosphereColor(globe.enableLighting);
  149272. environmentState.isReadyForAtmosphere = environmentState.isReadyForAtmosphere || globe._surface._tilesToRender.length > 0;
  149273. }
  149274. environmentState.skyAtmosphereCommand = (renderPass && defined(skyAtmosphere)) ? skyAtmosphere.update(frameState) : undefined;
  149275. var sunCommands = (renderPass && defined(scene.sun)) ? scene.sun.update(scene) : undefined;
  149276. environmentState.sunDrawCommand = defined(sunCommands) ? sunCommands.drawCommand : undefined;
  149277. environmentState.sunComputeCommand = defined(sunCommands) ? sunCommands.computeCommand : undefined;
  149278. environmentState.moonCommand = (renderPass && defined(scene.moon)) ? scene.moon.update(frameState) : undefined;
  149279. var clearGlobeDepth = environmentState.clearGlobeDepth = defined(globe) && (!globe.depthTestAgainstTerrain || scene.mode === SceneMode.SCENE2D);
  149280. var useDepthPlane = environmentState.useDepthPlane = clearGlobeDepth && scene.mode === SceneMode.SCENE3D;
  149281. if (useDepthPlane) {
  149282. // Update the depth plane that is rendered in 3D when the primitives are
  149283. // not depth tested against terrain so primitives on the backface
  149284. // of the globe are not picked.
  149285. scene._depthPlane.update(frameState);
  149286. }
  149287. }
  149288. function updateShadowMaps(scene) {
  149289. var frameState = scene._frameState;
  149290. var shadowMaps = frameState.shadowMaps;
  149291. var length = shadowMaps.length;
  149292. var shadowsEnabled = (length > 0) && !frameState.passes.pick && (scene.mode === SceneMode.SCENE3D);
  149293. if (shadowsEnabled !== frameState.shadowHints.shadowsEnabled) {
  149294. // Update derived commands when shadowsEnabled changes
  149295. ++frameState.shadowHints.lastDirtyTime;
  149296. frameState.shadowHints.shadowsEnabled = shadowsEnabled;
  149297. }
  149298. if (!shadowsEnabled) {
  149299. return;
  149300. }
  149301. // Check if the shadow maps are different than the shadow maps last frame.
  149302. // If so, the derived commands need to be updated.
  149303. for (var j = 0; j < length; ++j) {
  149304. if (shadowMaps[j] !== frameState.shadowHints.shadowMaps[j]) {
  149305. ++frameState.shadowHints.lastDirtyTime;
  149306. break;
  149307. }
  149308. }
  149309. frameState.shadowHints.shadowMaps.length = 0;
  149310. frameState.shadowHints.lightShadowMaps.length = 0;
  149311. for (var i = 0; i < length; ++i) {
  149312. var shadowMap = shadowMaps[i];
  149313. shadowMap.update(frameState);
  149314. frameState.shadowHints.shadowMaps.push(shadowMap);
  149315. if (shadowMap.fromLightSource) {
  149316. frameState.shadowHints.lightShadowMaps.push(shadowMap);
  149317. }
  149318. if (shadowMap.dirty) {
  149319. ++frameState.shadowHints.lastDirtyTime;
  149320. shadowMap.dirty = false;
  149321. }
  149322. }
  149323. }
  149324. function updatePrimitives(scene) {
  149325. var frameState = scene._frameState;
  149326. scene._groundPrimitives.update(frameState);
  149327. scene._primitives.update(frameState);
  149328. updateShadowMaps(scene);
  149329. if (scene._globe) {
  149330. scene._globe.update(frameState);
  149331. }
  149332. }
  149333. function updateAndClearFramebuffers(scene, passState, clearColor, picking) {
  149334. var context = scene._context;
  149335. var environmentState = scene._environmentState;
  149336. var useWebVR = scene._useWebVR && scene.mode !== SceneMode.SCENE2D;
  149337. // Preserve the reference to the original framebuffer.
  149338. environmentState.originalFramebuffer = passState.framebuffer;
  149339. // Manage sun bloom post-processing effect.
  149340. if (defined(scene.sun) && scene.sunBloom !== scene._sunBloom) {
  149341. if (scene.sunBloom && !useWebVR) {
  149342. scene._sunPostProcess = new SunPostProcess();
  149343. } else if(defined(scene._sunPostProcess)){
  149344. scene._sunPostProcess = scene._sunPostProcess.destroy();
  149345. }
  149346. scene._sunBloom = scene.sunBloom;
  149347. } else if (!defined(scene.sun) && defined(scene._sunPostProcess)) {
  149348. scene._sunPostProcess = scene._sunPostProcess.destroy();
  149349. scene._sunBloom = false;
  149350. }
  149351. // Clear the pass state framebuffer.
  149352. var clear = scene._clearColorCommand;
  149353. Color.clone(clearColor, clear.color);
  149354. clear.execute(context, passState);
  149355. // Update globe depth rendering based on the current context and clear the globe depth framebuffer.
  149356. var useGlobeDepthFramebuffer = environmentState.useGlobeDepthFramebuffer = !picking && defined(scene._globeDepth);
  149357. if (useGlobeDepthFramebuffer) {
  149358. scene._globeDepth.update(context);
  149359. scene._globeDepth.clear(context, passState, clearColor);
  149360. }
  149361. // Determine if there are any translucent surfaces in any of the frustums.
  149362. var renderTranslucentCommands = false;
  149363. var frustumCommandsList = scene._frustumCommandsList;
  149364. var numFrustums = frustumCommandsList.length;
  149365. for (var i = 0; i < numFrustums; ++i) {
  149366. if (frustumCommandsList[i].indices[Pass.TRANSLUCENT] > 0) {
  149367. renderTranslucentCommands = true;
  149368. break;
  149369. }
  149370. }
  149371. // If supported, configure OIT to use the globe depth framebuffer and clear the OIT framebuffer.
  149372. var useOIT = environmentState.useOIT = !picking && renderTranslucentCommands && defined(scene._oit) && scene._oit.isSupported();
  149373. if (useOIT) {
  149374. scene._oit.update(context, scene._globeDepth.framebuffer);
  149375. scene._oit.clear(context, passState, clearColor);
  149376. environmentState.useOIT = scene._oit.isSupported();
  149377. }
  149378. // If supported, configure FXAA to use the globe depth color texture and clear the FXAA framebuffer.
  149379. var useFXAA = environmentState.useFXAA = !picking && scene.fxaa;
  149380. if (useFXAA) {
  149381. scene._fxaa.update(context);
  149382. scene._fxaa.clear(context, passState, clearColor);
  149383. }
  149384. if (environmentState.isSunVisible && scene.sunBloom && !useWebVR) {
  149385. passState.framebuffer = scene._sunPostProcess.update(passState);
  149386. } else if (useGlobeDepthFramebuffer) {
  149387. passState.framebuffer = scene._globeDepth.framebuffer;
  149388. } else if (useFXAA) {
  149389. passState.framebuffer = scene._fxaa.getColorFramebuffer();
  149390. }
  149391. if (defined(passState.framebuffer)) {
  149392. clear.execute(context, passState);
  149393. }
  149394. }
  149395. function resolveFramebuffers(scene, passState) {
  149396. var context = scene._context;
  149397. var environmentState = scene._environmentState;
  149398. var useGlobeDepthFramebuffer = environmentState.useGlobeDepthFramebuffer;
  149399. if (scene.debugShowGlobeDepth && useGlobeDepthFramebuffer) {
  149400. var gd = getDebugGlobeDepth(scene, scene.debugShowDepthFrustum - 1);
  149401. gd.executeDebugGlobeDepth(context, passState);
  149402. }
  149403. if (scene.debugShowPickDepth && useGlobeDepthFramebuffer) {
  149404. var pd = getPickDepth(scene, scene.debugShowDepthFrustum - 1);
  149405. pd.executeDebugPickDepth(context, passState);
  149406. }
  149407. var useOIT = environmentState.useOIT;
  149408. var useFXAA = environmentState.useFXAA;
  149409. if (useOIT) {
  149410. passState.framebuffer = useFXAA ? scene._fxaa.getColorFramebuffer() : undefined;
  149411. scene._oit.execute(context, passState);
  149412. }
  149413. if (useFXAA) {
  149414. if (!useOIT && useGlobeDepthFramebuffer) {
  149415. passState.framebuffer = scene._fxaa.getColorFramebuffer();
  149416. scene._globeDepth.executeCopyColor(context, passState);
  149417. }
  149418. passState.framebuffer = environmentState.originalFramebuffer;
  149419. scene._fxaa.execute(context, passState);
  149420. }
  149421. if (!useOIT && !useFXAA && useGlobeDepthFramebuffer) {
  149422. passState.framebuffer = environmentState.originalFramebuffer;
  149423. scene._globeDepth.executeCopyColor(context, passState);
  149424. }
  149425. }
  149426. function callAfterRenderFunctions(frameState) {
  149427. // Functions are queued up during primitive update and executed here in case
  149428. // the function modifies scene state that should remain constant over the frame.
  149429. var functions = frameState.afterRender;
  149430. for (var i = 0, length = functions.length; i < length; ++i) {
  149431. functions[i]();
  149432. }
  149433. functions.length = 0;
  149434. }
  149435. /**
  149436. * @private
  149437. */
  149438. Scene.prototype.initializeFrame = function() {
  149439. // Destroy released shaders once every 120 frames to avoid thrashing the cache
  149440. if (this._shaderFrameCount++ === 120) {
  149441. this._shaderFrameCount = 0;
  149442. this._context.shaderCache.destroyReleasedShaderPrograms();
  149443. }
  149444. this._tweens.update();
  149445. this._screenSpaceCameraController.update();
  149446. if (defined(this._deviceOrientationCameraController)) {
  149447. this._deviceOrientationCameraController.update();
  149448. }
  149449. this._camera.update(this._mode);
  149450. this._camera._updateCameraChanged();
  149451. };
  149452. var scratchEyeTranslation = new Cartesian3();
  149453. function render(scene, time) {
  149454. if (!defined(time)) {
  149455. time = JulianDate.now();
  149456. }
  149457. var camera = scene._camera;
  149458. if (!cameraEqual(camera, scene._cameraClone, CesiumMath.EPSILON6)) {
  149459. if (!scene._cameraStartFired) {
  149460. camera.moveStart.raiseEvent();
  149461. scene._cameraStartFired = true;
  149462. }
  149463. scene._cameraMovedTime = getTimestamp();
  149464. Camera.clone(camera, scene._cameraClone);
  149465. } else if (scene._cameraStartFired && getTimestamp() - scene._cameraMovedTime > scene.cameraEventWaitTime) {
  149466. camera.moveEnd.raiseEvent();
  149467. scene._cameraStartFired = false;
  149468. }
  149469. scene._preRender.raiseEvent(scene, time);
  149470. var context = scene.context;
  149471. var us = context.uniformState;
  149472. var frameState = scene._frameState;
  149473. var frameNumber = CesiumMath.incrementWrap(frameState.frameNumber, 15000000.0, 1.0);
  149474. updateFrameState(scene, frameNumber, time);
  149475. frameState.passes.render = true;
  149476. frameState.creditDisplay.beginFrame();
  149477. scene.fog.update(frameState);
  149478. us.update(frameState);
  149479. var shadowMap = scene.shadowMap;
  149480. if (defined(shadowMap) && shadowMap.enabled) {
  149481. // Update the sun's direction
  149482. Cartesian3.negate(us.sunDirectionWC, scene._sunCamera.direction);
  149483. frameState.shadowMaps.push(shadowMap);
  149484. }
  149485. scene._computeCommandList.length = 0;
  149486. scene._overlayCommandList.length = 0;
  149487. var passState = scene._passState;
  149488. passState.framebuffer = undefined;
  149489. passState.blendingEnabled = undefined;
  149490. passState.scissorTest = undefined;
  149491. if (defined(scene.globe)) {
  149492. scene.globe.beginFrame(frameState);
  149493. }
  149494. updateEnvironment(scene);
  149495. updateAndExecuteCommands(scene, passState, defaultValue(scene.backgroundColor, Color.BLACK));
  149496. resolveFramebuffers(scene, passState);
  149497. executeOverlayCommands(scene, passState);
  149498. if (defined(scene.globe)) {
  149499. scene.globe.endFrame(frameState);
  149500. }
  149501. frameState.creditDisplay.endFrame();
  149502. if (scene.debugShowFramesPerSecond) {
  149503. if (!defined(scene._performanceDisplay)) {
  149504. var performanceContainer = document.createElement('div');
  149505. performanceContainer.className = 'cesium-performanceDisplay-defaultContainer';
  149506. var container = scene._canvas.parentNode;
  149507. container.appendChild(performanceContainer);
  149508. var performanceDisplay = new PerformanceDisplay({container: performanceContainer});
  149509. scene._performanceDisplay = performanceDisplay;
  149510. scene._performanceContainer = performanceContainer;
  149511. }
  149512. scene._performanceDisplay.update();
  149513. } else if (defined(scene._performanceDisplay)) {
  149514. scene._performanceDisplay = scene._performanceDisplay && scene._performanceDisplay.destroy();
  149515. scene._performanceContainer.parentNode.removeChild(scene._performanceContainer);
  149516. }
  149517. context.endFrame();
  149518. callAfterRenderFunctions(frameState);
  149519. scene._postRender.raiseEvent(scene, time);
  149520. }
  149521. /**
  149522. * @private
  149523. */
  149524. Scene.prototype.render = function(time) {
  149525. try {
  149526. render(this, time);
  149527. } catch (error) {
  149528. this._renderError.raiseEvent(this, error);
  149529. if (this.rethrowRenderErrors) {
  149530. throw error;
  149531. }
  149532. }
  149533. };
  149534. /**
  149535. * @private
  149536. */
  149537. Scene.prototype.clampLineWidth = function(width) {
  149538. return Math.max(ContextLimits.minimumAliasedLineWidth, Math.min(width, ContextLimits.maximumAliasedLineWidth));
  149539. };
  149540. var orthoPickingFrustum = new OrthographicFrustum();
  149541. var scratchOrigin = new Cartesian3();
  149542. var scratchDirection = new Cartesian3();
  149543. var scratchPixelSize = new Cartesian2();
  149544. var scratchPickVolumeMatrix4 = new Matrix4();
  149545. function getPickOrthographicCullingVolume(scene, drawingBufferPosition, width, height) {
  149546. var camera = scene._camera;
  149547. var frustum = camera.frustum;
  149548. var viewport = scene._passState.viewport;
  149549. var x = 2.0 * (drawingBufferPosition.x - viewport.x) / viewport.width - 1.0;
  149550. x *= (frustum.right - frustum.left) * 0.5;
  149551. var y = 2.0 * (viewport.height - drawingBufferPosition.y - viewport.y) / viewport.height - 1.0;
  149552. y *= (frustum.top - frustum.bottom) * 0.5;
  149553. var transform = Matrix4.clone(camera.transform, scratchPickVolumeMatrix4);
  149554. camera._setTransform(Matrix4.IDENTITY);
  149555. var origin = Cartesian3.clone(camera.position, scratchOrigin);
  149556. Cartesian3.multiplyByScalar(camera.right, x, scratchDirection);
  149557. Cartesian3.add(scratchDirection, origin, origin);
  149558. Cartesian3.multiplyByScalar(camera.up, y, scratchDirection);
  149559. Cartesian3.add(scratchDirection, origin, origin);
  149560. camera._setTransform(transform);
  149561. Cartesian3.fromElements(origin.z, origin.x, origin.y, origin);
  149562. var pixelSize = frustum.getPixelDimensions(viewport.width, viewport.height, 1.0, scratchPixelSize);
  149563. var ortho = orthoPickingFrustum;
  149564. ortho.right = pixelSize.x * 0.5;
  149565. ortho.left = -ortho.right;
  149566. ortho.top = pixelSize.y * 0.5;
  149567. ortho.bottom = -ortho.top;
  149568. ortho.near = frustum.near;
  149569. ortho.far = frustum.far;
  149570. return ortho.computeCullingVolume(origin, camera.directionWC, camera.upWC);
  149571. }
  149572. var perspPickingFrustum = new PerspectiveOffCenterFrustum();
  149573. function getPickPerspectiveCullingVolume(scene, drawingBufferPosition, width, height) {
  149574. var camera = scene._camera;
  149575. var frustum = camera.frustum;
  149576. var near = frustum.near;
  149577. var tanPhi = Math.tan(frustum.fovy * 0.5);
  149578. var tanTheta = frustum.aspectRatio * tanPhi;
  149579. var viewport = scene._passState.viewport;
  149580. var x = 2.0 * (drawingBufferPosition.x - viewport.x) / viewport.width - 1.0;
  149581. var y = 2.0 * (viewport.height - drawingBufferPosition.y - viewport.y) / viewport.height - 1.0;
  149582. var xDir = x * near * tanTheta;
  149583. var yDir = y * near * tanPhi;
  149584. var pixelSize = frustum.getPixelDimensions(viewport.width, viewport.height, 1.0, scratchPixelSize);
  149585. var pickWidth = pixelSize.x * width * 0.5;
  149586. var pickHeight = pixelSize.y * height * 0.5;
  149587. var offCenter = perspPickingFrustum;
  149588. offCenter.top = yDir + pickHeight;
  149589. offCenter.bottom = yDir - pickHeight;
  149590. offCenter.right = xDir + pickWidth;
  149591. offCenter.left = xDir - pickWidth;
  149592. offCenter.near = near;
  149593. offCenter.far = frustum.far;
  149594. return offCenter.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  149595. }
  149596. function getPickCullingVolume(scene, drawingBufferPosition, width, height) {
  149597. if (scene._mode === SceneMode.SCENE2D) {
  149598. return getPickOrthographicCullingVolume(scene, drawingBufferPosition, width, height);
  149599. }
  149600. return getPickPerspectiveCullingVolume(scene, drawingBufferPosition, width, height);
  149601. }
  149602. // pick rectangle width and height, assumed odd
  149603. var rectangleWidth = 3.0;
  149604. var rectangleHeight = 3.0;
  149605. var scratchRectangle = new BoundingRectangle(0.0, 0.0, rectangleWidth, rectangleHeight);
  149606. var scratchColorZero = new Color(0.0, 0.0, 0.0, 0.0);
  149607. var scratchPosition = new Cartesian2();
  149608. /**
  149609. * Returns an object with a `primitive` property that contains the first (top) primitive in the scene
  149610. * at a particular window coordinate or undefined if nothing is at the location. Other properties may
  149611. * potentially be set depending on the type of primitive.
  149612. *
  149613. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  149614. * @returns {Object} Object containing the picked primitive.
  149615. *
  149616. * @exception {DeveloperError} windowPosition is undefined.
  149617. */
  149618. Scene.prototype.pick = function(windowPosition) {
  149619. if(!defined(windowPosition)) {
  149620. throw new DeveloperError('windowPosition is undefined.');
  149621. }
  149622. var context = this._context;
  149623. var us = context.uniformState;
  149624. var frameState = this._frameState;
  149625. var drawingBufferPosition = SceneTransforms.transformWindowToDrawingBuffer(this, windowPosition, scratchPosition);
  149626. if (!defined(this._pickFramebuffer)) {
  149627. this._pickFramebuffer = context.createPickFramebuffer();
  149628. }
  149629. // Update with previous frame's number and time, assuming that render is called before picking.
  149630. updateFrameState(this, frameState.frameNumber, frameState.time);
  149631. frameState.cullingVolume = getPickCullingVolume(this, drawingBufferPosition, rectangleWidth, rectangleHeight);
  149632. frameState.passes.pick = true;
  149633. us.update(frameState);
  149634. scratchRectangle.x = drawingBufferPosition.x - ((rectangleWidth - 1.0) * 0.5);
  149635. scratchRectangle.y = (this.drawingBufferHeight - drawingBufferPosition.y) - ((rectangleHeight - 1.0) * 0.5);
  149636. var passState = this._pickFramebuffer.begin(scratchRectangle);
  149637. updateAndExecuteCommands(this, passState, scratchColorZero, true);
  149638. resolveFramebuffers(this, passState);
  149639. var object = this._pickFramebuffer.end(scratchRectangle);
  149640. context.endFrame();
  149641. callAfterRenderFunctions(frameState);
  149642. return object;
  149643. };
  149644. var scratchPackedDepth = new Cartesian4();
  149645. var packedDepthScale = new Cartesian4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0);
  149646. /**
  149647. * Returns the cartesian position reconstructed from the depth buffer and window position.
  149648. *
  149649. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  149650. * @param {Cartesian3} [result] The object on which to restore the result.
  149651. * @returns {Cartesian3} The cartesian position.
  149652. *
  149653. * @exception {DeveloperError} Picking from the depth buffer is not supported. Check pickPositionSupported.
  149654. * @exception {DeveloperError} 2D is not supported. An orthographic projection matrix is not invertible.
  149655. */
  149656. Scene.prototype.pickPosition = function(windowPosition, result) {
  149657. if (!this.useDepthPicking) {
  149658. return undefined;
  149659. }
  149660. if(!defined(windowPosition)) {
  149661. throw new DeveloperError('windowPosition is undefined.');
  149662. }
  149663. if (!defined(this._globeDepth)) {
  149664. throw new DeveloperError('Picking from the depth buffer is not supported. Check pickPositionSupported.');
  149665. }
  149666. var context = this._context;
  149667. var uniformState = context.uniformState;
  149668. var drawingBufferPosition = SceneTransforms.transformWindowToDrawingBuffer(this, windowPosition, scratchPosition);
  149669. drawingBufferPosition.y = this.drawingBufferHeight - drawingBufferPosition.y;
  149670. var camera = this._camera;
  149671. // Create a working frustum from the original camera frustum.
  149672. var frustum;
  149673. if (defined(camera.frustum.fov)) {
  149674. frustum = camera.frustum.clone(scratchPerspectiveFrustum);
  149675. } else if (defined(camera.frustum.infiniteProjectionMatrix)){
  149676. frustum = camera.frustum.clone(scratchPerspectiveOffCenterFrustum);
  149677. } else {
  149678. throw new DeveloperError('2D is not supported. An orthographic projection matrix is not invertible.');
  149679. }
  149680. var numFrustums = this.numberOfFrustums;
  149681. for (var i = 0; i < numFrustums; ++i) {
  149682. var pickDepth = getPickDepth(this, i);
  149683. var pixels = context.readPixels({
  149684. x : drawingBufferPosition.x,
  149685. y : drawingBufferPosition.y,
  149686. width : 1,
  149687. height : 1,
  149688. framebuffer : pickDepth.framebuffer
  149689. });
  149690. var packedDepth = Cartesian4.unpack(pixels, 0, scratchPackedDepth);
  149691. Cartesian4.divideByScalar(packedDepth, 255.0, packedDepth);
  149692. var depth = Cartesian4.dot(packedDepth, packedDepthScale);
  149693. if (depth > 0.0 && depth < 1.0) {
  149694. var renderedFrustum = this._frustumCommandsList[i];
  149695. frustum.near = renderedFrustum.near * (i !== 0 ? OPAQUE_FRUSTUM_NEAR_OFFSET : 1.0);
  149696. frustum.far = renderedFrustum.far;
  149697. uniformState.updateFrustum(frustum);
  149698. return SceneTransforms.drawingBufferToWgs84Coordinates(this, drawingBufferPosition, depth, result);
  149699. }
  149700. }
  149701. return undefined;
  149702. };
  149703. /**
  149704. * Returns a list of objects, each containing a `primitive` property, for all primitives at
  149705. * a particular window coordinate position. Other properties may also be set depending on the
  149706. * type of primitive. The primitives in the list are ordered by their visual order in the
  149707. * scene (front to back).
  149708. *
  149709. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  149710. * @param {Number} [limit] If supplied, stop drilling after collecting this many picks.
  149711. * @returns {Object[]} Array of objects, each containing 1 picked primitives.
  149712. *
  149713. * @exception {DeveloperError} windowPosition is undefined.
  149714. *
  149715. * @example
  149716. * var pickedObjects = scene.drillPick(new Cesium.Cartesian2(100.0, 200.0));
  149717. */
  149718. Scene.prototype.drillPick = function(windowPosition, limit) {
  149719. // PERFORMANCE_IDEA: This function calls each primitive's update for each pass. Instead
  149720. // we could update the primitive once, and then just execute their commands for each pass,
  149721. // and cull commands for picked primitives. e.g., base on the command's owner.
  149722. if (!defined(windowPosition)) {
  149723. throw new DeveloperError('windowPosition is undefined.');
  149724. }
  149725. var i;
  149726. var attributes;
  149727. var result = [];
  149728. var pickedPrimitives = [];
  149729. var pickedAttributes = [];
  149730. if (!defined(limit)) {
  149731. limit = Number.MAX_VALUE;
  149732. }
  149733. var pickedResult = this.pick(windowPosition);
  149734. while (defined(pickedResult) && defined(pickedResult.primitive)) {
  149735. result.push(pickedResult);
  149736. if (0 >= --limit) {
  149737. break;
  149738. }
  149739. var primitive = pickedResult.primitive;
  149740. var hasShowAttribute = false;
  149741. //If the picked object has a show attribute, use it.
  149742. if (typeof primitive.getGeometryInstanceAttributes === 'function') {
  149743. if (defined(pickedResult.id)) {
  149744. attributes = primitive.getGeometryInstanceAttributes(pickedResult.id);
  149745. if (defined(attributes) && defined(attributes.show)) {
  149746. hasShowAttribute = true;
  149747. attributes.show = ShowGeometryInstanceAttribute.toValue(false, attributes.show);
  149748. pickedAttributes.push(attributes);
  149749. }
  149750. }
  149751. }
  149752. //Otherwise, hide the entire primitive
  149753. if (!hasShowAttribute) {
  149754. primitive.show = false;
  149755. pickedPrimitives.push(primitive);
  149756. }
  149757. pickedResult = this.pick(windowPosition);
  149758. }
  149759. // unhide everything we hid while drill picking
  149760. for (i = 0; i < pickedPrimitives.length; ++i) {
  149761. pickedPrimitives[i].show = true;
  149762. }
  149763. for (i = 0; i < pickedAttributes.length; ++i) {
  149764. attributes = pickedAttributes[i];
  149765. attributes.show = ShowGeometryInstanceAttribute.toValue(true, attributes.show);
  149766. }
  149767. return result;
  149768. };
  149769. /**
  149770. * Instantly completes an active transition.
  149771. */
  149772. Scene.prototype.completeMorph = function(){
  149773. this._transitioner.completeMorph();
  149774. };
  149775. /**
  149776. * Asynchronously transitions the scene to 2D.
  149777. * @param {Number} [duration=2.0] The amount of time, in seconds, for transition animations to complete.
  149778. */
  149779. Scene.prototype.morphTo2D = function(duration) {
  149780. var ellipsoid;
  149781. var globe = this.globe;
  149782. if (defined(globe)) {
  149783. ellipsoid = globe.ellipsoid;
  149784. } else {
  149785. ellipsoid = this.mapProjection.ellipsoid;
  149786. }
  149787. duration = defaultValue(duration, 2.0);
  149788. this._transitioner.morphTo2D(duration, ellipsoid);
  149789. };
  149790. /**
  149791. * Asynchronously transitions the scene to Columbus View.
  149792. * @param {Number} [duration=2.0] The amount of time, in seconds, for transition animations to complete.
  149793. */
  149794. Scene.prototype.morphToColumbusView = function(duration) {
  149795. var ellipsoid;
  149796. var globe = this.globe;
  149797. if (defined(globe)) {
  149798. ellipsoid = globe.ellipsoid;
  149799. } else {
  149800. ellipsoid = this.mapProjection.ellipsoid;
  149801. }
  149802. duration = defaultValue(duration, 2.0);
  149803. this._transitioner.morphToColumbusView(duration, ellipsoid);
  149804. };
  149805. /**
  149806. * Asynchronously transitions the scene to 3D.
  149807. * @param {Number} [duration=2.0] The amount of time, in seconds, for transition animations to complete.
  149808. */
  149809. Scene.prototype.morphTo3D = function(duration) {
  149810. var ellipsoid;
  149811. var globe = this.globe;
  149812. if (defined(globe)) {
  149813. ellipsoid = globe.ellipsoid;
  149814. } else {
  149815. ellipsoid = this.mapProjection.ellipsoid;
  149816. }
  149817. duration = defaultValue(duration, 2.0);
  149818. this._transitioner.morphTo3D(duration, ellipsoid);
  149819. };
  149820. /**
  149821. * Returns true if this object was destroyed; otherwise, false.
  149822. * <br /><br />
  149823. * If this object was destroyed, it should not be used; calling any function other than
  149824. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  149825. *
  149826. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  149827. *
  149828. * @see Scene#destroy
  149829. */
  149830. Scene.prototype.isDestroyed = function() {
  149831. return false;
  149832. };
  149833. /**
  149834. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  149835. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  149836. * <br /><br />
  149837. * Once an object is destroyed, it should not be used; calling any function other than
  149838. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  149839. * assign the return value (<code>undefined</code>) to the object as done in the example.
  149840. *
  149841. * @returns {undefined}
  149842. *
  149843. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  149844. *
  149845. *
  149846. * @example
  149847. * scene = scene && scene.destroy();
  149848. *
  149849. * @see Scene#isDestroyed
  149850. */
  149851. Scene.prototype.destroy = function() {
  149852. this._tweens.removeAll();
  149853. this._computeEngine = this._computeEngine && this._computeEngine.destroy();
  149854. this._screenSpaceCameraController = this._screenSpaceCameraController && this._screenSpaceCameraController.destroy();
  149855. this._deviceOrientationCameraController = this._deviceOrientationCameraController && !this._deviceOrientationCameraController.isDestroyed() && this._deviceOrientationCameraController.destroy();
  149856. this._pickFramebuffer = this._pickFramebuffer && this._pickFramebuffer.destroy();
  149857. this._primitives = this._primitives && this._primitives.destroy();
  149858. this._groundPrimitives = this._groundPrimitives && this._groundPrimitives.destroy();
  149859. this._globe = this._globe && this._globe.destroy();
  149860. this.skyBox = this.skyBox && this.skyBox.destroy();
  149861. this.skyAtmosphere = this.skyAtmosphere && this.skyAtmosphere.destroy();
  149862. this._debugSphere = this._debugSphere && this._debugSphere.destroy();
  149863. this.sun = this.sun && this.sun.destroy();
  149864. this._sunPostProcess = this._sunPostProcess && this._sunPostProcess.destroy();
  149865. this._depthPlane = this._depthPlane && this._depthPlane.destroy();
  149866. this._transitioner.destroy();
  149867. if (defined(this._globeDepth)) {
  149868. this._globeDepth.destroy();
  149869. }
  149870. if (defined(this._oit)) {
  149871. this._oit.destroy();
  149872. }
  149873. this._fxaa.destroy();
  149874. this._context = this._context && this._context.destroy();
  149875. this._frameState.creditDisplay.destroy();
  149876. if (defined(this._performanceDisplay)){
  149877. this._performanceDisplay = this._performanceDisplay && this._performanceDisplay.destroy();
  149878. this._performanceContainer.parentNode.removeChild(this._performanceContainer);
  149879. }
  149880. return destroyObject(this);
  149881. };
  149882. return Scene;
  149883. });
  149884. /*global define*/
  149885. define('Scene/SingleTileImageryProvider',[
  149886. '../Core/Credit',
  149887. '../Core/defaultValue',
  149888. '../Core/defined',
  149889. '../Core/defineProperties',
  149890. '../Core/DeveloperError',
  149891. '../Core/Event',
  149892. '../Core/GeographicTilingScheme',
  149893. '../Core/loadImage',
  149894. '../Core/Rectangle',
  149895. '../Core/RuntimeError',
  149896. '../Core/TileProviderError',
  149897. '../ThirdParty/when'
  149898. ], function(
  149899. Credit,
  149900. defaultValue,
  149901. defined,
  149902. defineProperties,
  149903. DeveloperError,
  149904. Event,
  149905. GeographicTilingScheme,
  149906. loadImage,
  149907. Rectangle,
  149908. RuntimeError,
  149909. TileProviderError,
  149910. when) {
  149911. 'use strict';
  149912. /**
  149913. * Provides a single, top-level imagery tile. The single image is assumed to use a
  149914. * {@link GeographicTilingScheme}.
  149915. *
  149916. * @alias SingleTileImageryProvider
  149917. * @constructor
  149918. *
  149919. * @param {Object} options Object with the following properties:
  149920. * @param {String} options.url The url for the tile.
  149921. * @param {Rectangle} [options.rectangle=Rectangle.MAX_VALUE] The rectangle, in radians, covered by the image.
  149922. * @param {Credit|String} [options.credit] A credit for the data source, which is displayed on the canvas.
  149923. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If not specified, the WGS84 ellipsoid is used.
  149924. * @param {Object} [options.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL, if needed.
  149925. *
  149926. * @see ArcGisMapServerImageryProvider
  149927. * @see BingMapsImageryProvider
  149928. * @see GoogleEarthImageryProvider
  149929. * @see createOpenStreetMapImageryProvider
  149930. * @see createTileMapServiceImageryProvider
  149931. * @see WebMapServiceImageryProvider
  149932. * @see WebMapTileServiceImageryProvider
  149933. * @see UrlTemplateImageryProvider
  149934. */
  149935. function SingleTileImageryProvider(options) {
  149936. options = defaultValue(options, {});
  149937. var url = options.url;
  149938. if (!defined(url)) {
  149939. throw new DeveloperError('url is required.');
  149940. }
  149941. this._url = url;
  149942. var proxy = options.proxy;
  149943. this._proxy = proxy;
  149944. var rectangle = defaultValue(options.rectangle, Rectangle.MAX_VALUE);
  149945. var tilingScheme = new GeographicTilingScheme({
  149946. rectangle : rectangle,
  149947. numberOfLevelZeroTilesX : 1,
  149948. numberOfLevelZeroTilesY : 1,
  149949. ellipsoid : options.ellipsoid
  149950. });
  149951. this._tilingScheme = tilingScheme;
  149952. this._image = undefined;
  149953. this._texture = undefined;
  149954. this._tileWidth = 0;
  149955. this._tileHeight = 0;
  149956. this._errorEvent = new Event();
  149957. this._ready = false;
  149958. this._readyPromise = when.defer();
  149959. var imageUrl = url;
  149960. if (defined(proxy)) {
  149961. imageUrl = proxy.getURL(imageUrl);
  149962. }
  149963. var credit = options.credit;
  149964. if (typeof credit === 'string') {
  149965. credit = new Credit(credit);
  149966. }
  149967. this._credit = credit;
  149968. var that = this;
  149969. var error;
  149970. function success(image) {
  149971. that._image = image;
  149972. that._tileWidth = image.width;
  149973. that._tileHeight = image.height;
  149974. that._ready = true;
  149975. that._readyPromise.resolve(true);
  149976. TileProviderError.handleSuccess(that._errorEvent);
  149977. }
  149978. function failure(e) {
  149979. var message = 'Failed to load image ' + imageUrl + '.';
  149980. error = TileProviderError.handleError(
  149981. error,
  149982. that,
  149983. that._errorEvent,
  149984. message,
  149985. 0, 0, 0,
  149986. doRequest,
  149987. e);
  149988. that._readyPromise.reject(new RuntimeError(message));
  149989. }
  149990. function doRequest() {
  149991. when(loadImage(imageUrl), success, failure);
  149992. }
  149993. doRequest();
  149994. }
  149995. defineProperties(SingleTileImageryProvider.prototype, {
  149996. /**
  149997. * Gets the URL of the single, top-level imagery tile.
  149998. * @memberof SingleTileImageryProvider.prototype
  149999. * @type {String}
  150000. * @readonly
  150001. */
  150002. url : {
  150003. get : function() {
  150004. return this._url;
  150005. }
  150006. },
  150007. /**
  150008. * Gets the proxy used by this provider.
  150009. * @memberof SingleTileImageryProvider.prototype
  150010. * @type {Proxy}
  150011. * @readonly
  150012. */
  150013. proxy : {
  150014. get : function() {
  150015. return this._proxy;
  150016. }
  150017. },
  150018. /**
  150019. * Gets the width of each tile, in pixels. This function should
  150020. * not be called before {@link SingleTileImageryProvider#ready} returns true.
  150021. * @memberof SingleTileImageryProvider.prototype
  150022. * @type {Number}
  150023. * @readonly
  150024. */
  150025. tileWidth : {
  150026. get : function() {
  150027. if (!this._ready) {
  150028. throw new DeveloperError('tileWidth must not be called before the imagery provider is ready.');
  150029. }
  150030. return this._tileWidth;
  150031. }
  150032. },
  150033. /**
  150034. * Gets the height of each tile, in pixels. This function should
  150035. * not be called before {@link SingleTileImageryProvider#ready} returns true.
  150036. * @memberof SingleTileImageryProvider.prototype
  150037. * @type {Number}
  150038. * @readonly
  150039. */
  150040. tileHeight: {
  150041. get : function() {
  150042. if (!this._ready) {
  150043. throw new DeveloperError('tileHeight must not be called before the imagery provider is ready.');
  150044. }
  150045. return this._tileHeight;
  150046. }
  150047. },
  150048. /**
  150049. * Gets the maximum level-of-detail that can be requested. This function should
  150050. * not be called before {@link SingleTileImageryProvider#ready} returns true.
  150051. * @memberof SingleTileImageryProvider.prototype
  150052. * @type {Number}
  150053. * @readonly
  150054. */
  150055. maximumLevel : {
  150056. get : function() {
  150057. if (!this._ready) {
  150058. throw new DeveloperError('maximumLevel must not be called before the imagery provider is ready.');
  150059. }
  150060. return 0;
  150061. }
  150062. },
  150063. /**
  150064. * Gets the minimum level-of-detail that can be requested. This function should
  150065. * not be called before {@link SingleTileImageryProvider#ready} returns true.
  150066. * @memberof SingleTileImageryProvider.prototype
  150067. * @type {Number}
  150068. * @readonly
  150069. */
  150070. minimumLevel : {
  150071. get : function() {
  150072. if (!this._ready) {
  150073. throw new DeveloperError('minimumLevel must not be called before the imagery provider is ready.');
  150074. }
  150075. return 0;
  150076. }
  150077. },
  150078. /**
  150079. * Gets the tiling scheme used by this provider. This function should
  150080. * not be called before {@link SingleTileImageryProvider#ready} returns true.
  150081. * @memberof SingleTileImageryProvider.prototype
  150082. * @type {TilingScheme}
  150083. * @readonly
  150084. */
  150085. tilingScheme : {
  150086. get : function() {
  150087. if (!this._ready) {
  150088. throw new DeveloperError('tilingScheme must not be called before the imagery provider is ready.');
  150089. }
  150090. return this._tilingScheme;
  150091. }
  150092. },
  150093. /**
  150094. * Gets the rectangle, in radians, of the imagery provided by this instance. This function should
  150095. * not be called before {@link SingleTileImageryProvider#ready} returns true.
  150096. * @memberof SingleTileImageryProvider.prototype
  150097. * @type {Rectangle}
  150098. * @readonly
  150099. */
  150100. rectangle : {
  150101. get : function() {
  150102. return this._tilingScheme.rectangle;
  150103. }
  150104. },
  150105. /**
  150106. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  150107. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  150108. * returns undefined, no tiles are filtered. This function should
  150109. * not be called before {@link SingleTileImageryProvider#ready} returns true.
  150110. * @memberof SingleTileImageryProvider.prototype
  150111. * @type {TileDiscardPolicy}
  150112. * @readonly
  150113. */
  150114. tileDiscardPolicy : {
  150115. get : function() {
  150116. if (!this._ready) {
  150117. throw new DeveloperError('tileDiscardPolicy must not be called before the imagery provider is ready.');
  150118. }
  150119. return undefined;
  150120. }
  150121. },
  150122. /**
  150123. * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
  150124. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  150125. * are passed an instance of {@link TileProviderError}.
  150126. * @memberof SingleTileImageryProvider.prototype
  150127. * @type {Event}
  150128. * @readonly
  150129. */
  150130. errorEvent : {
  150131. get : function() {
  150132. return this._errorEvent;
  150133. }
  150134. },
  150135. /**
  150136. * Gets a value indicating whether or not the provider is ready for use.
  150137. * @memberof SingleTileImageryProvider.prototype
  150138. * @type {Boolean}
  150139. * @readonly
  150140. */
  150141. ready : {
  150142. get : function() {
  150143. return this._ready;
  150144. }
  150145. },
  150146. /**
  150147. * Gets a promise that resolves to true when the provider is ready for use.
  150148. * @memberof SingleTileImageryProvider.prototype
  150149. * @type {Promise.<Boolean>}
  150150. * @readonly
  150151. */
  150152. readyPromise : {
  150153. get : function() {
  150154. return this._readyPromise.promise;
  150155. }
  150156. },
  150157. /**
  150158. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  150159. * the source of the imagery. This function should not be called before {@link SingleTileImageryProvider#ready} returns true.
  150160. * @memberof SingleTileImageryProvider.prototype
  150161. * @type {Credit}
  150162. * @readonly
  150163. */
  150164. credit : {
  150165. get : function() {
  150166. return this._credit;
  150167. }
  150168. },
  150169. /**
  150170. * Gets a value indicating whether or not the images provided by this imagery provider
  150171. * include an alpha channel. If this property is false, an alpha channel, if present, will
  150172. * be ignored. If this property is true, any images without an alpha channel will be treated
  150173. * as if their alpha is 1.0 everywhere. When this property is false, memory usage
  150174. * and texture upload time are reduced.
  150175. * @memberof SingleTileImageryProvider.prototype
  150176. * @type {Boolean}
  150177. * @readonly
  150178. */
  150179. hasAlphaChannel : {
  150180. get : function() {
  150181. return true;
  150182. }
  150183. }
  150184. });
  150185. /**
  150186. * Gets the credits to be displayed when a given tile is displayed.
  150187. *
  150188. * @param {Number} x The tile X coordinate.
  150189. * @param {Number} y The tile Y coordinate.
  150190. * @param {Number} level The tile level;
  150191. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  150192. *
  150193. * @exception {DeveloperError} <code>getTileCredits</code> must not be called before the imagery provider is ready.
  150194. */
  150195. SingleTileImageryProvider.prototype.getTileCredits = function(x, y, level) {
  150196. return undefined;
  150197. };
  150198. /**
  150199. * Requests the image for a given tile. This function should
  150200. * not be called before {@link SingleTileImageryProvider#ready} returns true.
  150201. *
  150202. * @param {Number} x The tile X coordinate.
  150203. * @param {Number} y The tile Y coordinate.
  150204. * @param {Number} level The tile level.
  150205. * @returns {Promise.<Image|Canvas>|undefined} A promise for the image that will resolve when the image is available, or
  150206. * undefined if there are too many active requests to the server, and the request
  150207. * should be retried later. The resolved image may be either an
  150208. * Image or a Canvas DOM object.
  150209. *
  150210. * @exception {DeveloperError} <code>requestImage</code> must not be called before the imagery provider is ready.
  150211. */
  150212. SingleTileImageryProvider.prototype.requestImage = function(x, y, level) {
  150213. if (!this._ready) {
  150214. throw new DeveloperError('requestImage must not be called before the imagery provider is ready.');
  150215. }
  150216. return this._image;
  150217. };
  150218. /**
  150219. * Picking features is not currently supported by this imagery provider, so this function simply returns
  150220. * undefined.
  150221. *
  150222. * @param {Number} x The tile X coordinate.
  150223. * @param {Number} y The tile Y coordinate.
  150224. * @param {Number} level The tile level.
  150225. * @param {Number} longitude The longitude at which to pick features.
  150226. * @param {Number} latitude The latitude at which to pick features.
  150227. * @return {Promise.<ImageryLayerFeatureInfo[]>|undefined} A promise for the picked features that will resolve when the asynchronous
  150228. * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
  150229. * instances. The array may be empty if no features are found at the given location.
  150230. * It may also be undefined if picking is not supported.
  150231. */
  150232. SingleTileImageryProvider.prototype.pickFeatures = function() {
  150233. return undefined;
  150234. };
  150235. return SingleTileImageryProvider;
  150236. });
  150237. /**
  150238. * @license
  150239. * Copyright (c) 2000-2005, Sean O'Neil (s_p_oneil@hotmail.com)
  150240. * All rights reserved.
  150241. *
  150242. * Redistribution and use in source and binary forms, with or without
  150243. * modification, are permitted provided that the following conditions
  150244. * are met:
  150245. *
  150246. * * Redistributions of source code must retain the above copyright notice,
  150247. * this list of conditions and the following disclaimer.
  150248. * * Redistributions in binary form must reproduce the above copyright notice,
  150249. * this list of conditions and the following disclaimer in the documentation
  150250. * and/or other materials provided with the distribution.
  150251. * * Neither the name of the project nor the names of its contributors may be
  150252. * used to endorse or promote products derived from this software without
  150253. * specific prior written permission.
  150254. *
  150255. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  150256. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  150257. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  150258. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  150259. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  150260. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  150261. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  150262. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  150263. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  150264. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  150265. *
  150266. * Modifications made by Analytical Graphics, Inc.
  150267. */
  150268. //This file is automatically rebuilt by the Cesium build process.
  150269. /*global define*/
  150270. define('Shaders/SkyAtmosphereFS',[],function() {
  150271. 'use strict';
  150272. return "#ifdef COLOR_CORRECT\n\
  150273. uniform vec3 u_hsbShift;\n\
  150274. #endif\n\
  150275. const float g = -0.95;\n\
  150276. const float g2 = g * g;\n\
  150277. const vec4 K_RGB2HSB = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n\
  150278. const vec4 K_HSB2RGB = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n\
  150279. varying vec3 v_rayleighColor;\n\
  150280. varying vec3 v_mieColor;\n\
  150281. varying vec3 v_toCamera;\n\
  150282. varying vec3 v_positionEC;\n\
  150283. #ifdef COLOR_CORRECT\n\
  150284. vec3 rgb2hsb(vec3 rgbColor)\n\
  150285. {\n\
  150286. vec4 p = mix(vec4(rgbColor.bg, K_RGB2HSB.wz), vec4(rgbColor.gb, K_RGB2HSB.xy), step(rgbColor.b, rgbColor.g));\n\
  150287. vec4 q = mix(vec4(p.xyw, rgbColor.r), vec4(rgbColor.r, p.yzx), step(p.x, rgbColor.r));\n\
  150288. float d = q.x - min(q.w, q.y);\n\
  150289. return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + czm_epsilon7)), d / (q.x + czm_epsilon7), q.x);\n\
  150290. }\n\
  150291. vec3 hsb2rgb(vec3 hsbColor)\n\
  150292. {\n\
  150293. vec3 p = abs(fract(hsbColor.xxx + K_HSB2RGB.xyz) * 6.0 - K_HSB2RGB.www);\n\
  150294. return hsbColor.z * mix(K_HSB2RGB.xxx, clamp(p - K_HSB2RGB.xxx, 0.0, 1.0), hsbColor.y);\n\
  150295. }\n\
  150296. #endif\n\
  150297. void main (void)\n\
  150298. {\n\
  150299. float cosAngle = dot(czm_sunDirectionWC, normalize(v_toCamera)) / length(v_toCamera);\n\
  150300. float rayleighPhase = 0.75 * (1.0 + cosAngle * cosAngle);\n\
  150301. float miePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + cosAngle * cosAngle) / pow(1.0 + g2 - 2.0 * g * cosAngle, 1.5);\n\
  150302. const float exposure = 2.0;\n\
  150303. vec3 rgb = rayleighPhase * v_rayleighColor + miePhase * v_mieColor;\n\
  150304. rgb = vec3(1.0) - exp(-exposure * rgb);\n\
  150305. float l = czm_luminance(rgb);\n\
  150306. #ifdef COLOR_CORRECT\n\
  150307. vec3 hsb = rgb2hsb(rgb);\n\
  150308. hsb.x += u_hsbShift.x;\n\
  150309. hsb.y = clamp(hsb.y + u_hsbShift.y, 0.0, 1.0);\n\
  150310. hsb.z = hsb.z > czm_epsilon7 ? hsb.z + u_hsbShift.z : 0.0;\n\
  150311. rgb = hsb2rgb(hsb);\n\
  150312. l = min(l, czm_luminance(rgb));\n\
  150313. #endif\n\
  150314. gl_FragColor = vec4(rgb, min(smoothstep(0.0, 0.1, l), 1.0) * smoothstep(0.0, 1.0, czm_morphTime));\n\
  150315. }\n\
  150316. ";
  150317. });
  150318. /**
  150319. * @license
  150320. * Copyright (c) 2000-2005, Sean O'Neil (s_p_oneil@hotmail.com)
  150321. * All rights reserved.
  150322. *
  150323. * Redistribution and use in source and binary forms, with or without
  150324. * modification, are permitted provided that the following conditions
  150325. * are met:
  150326. *
  150327. * * Redistributions of source code must retain the above copyright notice,
  150328. * this list of conditions and the following disclaimer.
  150329. * * Redistributions in binary form must reproduce the above copyright notice,
  150330. * this list of conditions and the following disclaimer in the documentation
  150331. * and/or other materials provided with the distribution.
  150332. * * Neither the name of the project nor the names of its contributors may be
  150333. * used to endorse or promote products derived from this software without
  150334. * specific prior written permission.
  150335. *
  150336. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  150337. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  150338. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  150339. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  150340. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  150341. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  150342. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  150343. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  150344. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  150345. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  150346. *
  150347. * Modifications made by Analytical Graphics, Inc.
  150348. */
  150349. //This file is automatically rebuilt by the Cesium build process.
  150350. /*global define*/
  150351. define('Shaders/SkyAtmosphereVS',[],function() {
  150352. 'use strict';
  150353. return "attribute vec4 position;\n\
  150354. uniform vec4 u_cameraAndRadiiAndDynamicAtmosphereColor;\n\
  150355. const float Kr = 0.0025;\n\
  150356. const float Kr4PI = Kr * 4.0 * czm_pi;\n\
  150357. const float Km = 0.0015;\n\
  150358. const float Km4PI = Km * 4.0 * czm_pi;\n\
  150359. const float ESun = 15.0;\n\
  150360. const float KmESun = Km * ESun;\n\
  150361. const float KrESun = Kr * ESun;\n\
  150362. const vec3 InvWavelength = vec3(\n\
  150363. 5.60204474633241,\n\
  150364. 9.473284437923038,\n\
  150365. 19.643802610477206);\n\
  150366. const float rayleighScaleDepth = 0.25;\n\
  150367. const int nSamples = 2;\n\
  150368. const float fSamples = 2.0;\n\
  150369. varying vec3 v_rayleighColor;\n\
  150370. varying vec3 v_mieColor;\n\
  150371. varying vec3 v_toCamera;\n\
  150372. float scale(float cosAngle)\n\
  150373. {\n\
  150374. float x = 1.0 - cosAngle;\n\
  150375. return rayleighScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));\n\
  150376. }\n\
  150377. void main(void)\n\
  150378. {\n\
  150379. float cameraHeight = u_cameraAndRadiiAndDynamicAtmosphereColor.x;\n\
  150380. float outerRadius = u_cameraAndRadiiAndDynamicAtmosphereColor.y;\n\
  150381. float innerRadius = u_cameraAndRadiiAndDynamicAtmosphereColor.z;\n\
  150382. vec3 positionV3 = position.xyz;\n\
  150383. vec3 ray = positionV3 - czm_viewerPositionWC;\n\
  150384. float far = length(ray);\n\
  150385. ray /= far;\n\
  150386. float atmosphereScale = 1.0 / (outerRadius - innerRadius);\n\
  150387. #ifdef SKY_FROM_SPACE\n\
  150388. float B = 2.0 * dot(czm_viewerPositionWC, ray);\n\
  150389. float C = cameraHeight * cameraHeight - outerRadius * outerRadius;\n\
  150390. float det = max(0.0, B*B - 4.0 * C);\n\
  150391. float near = 0.5 * (-B - sqrt(det));\n\
  150392. vec3 start = czm_viewerPositionWC + ray * near;\n\
  150393. far -= near;\n\
  150394. float startAngle = dot(ray, start) / outerRadius;\n\
  150395. float startDepth = exp(-1.0 / rayleighScaleDepth );\n\
  150396. float startOffset = startDepth*scale(startAngle);\n\
  150397. #else // SKY_FROM_ATMOSPHERE\n\
  150398. vec3 start = czm_viewerPositionWC;\n\
  150399. float height = length(start);\n\
  150400. float depth = exp((atmosphereScale / rayleighScaleDepth ) * (innerRadius - cameraHeight));\n\
  150401. float startAngle = dot(ray, start) / height;\n\
  150402. float startOffset = depth*scale(startAngle);\n\
  150403. #endif\n\
  150404. float sampleLength = far / fSamples;\n\
  150405. float scaledLength = sampleLength * atmosphereScale;\n\
  150406. vec3 sampleRay = ray * sampleLength;\n\
  150407. vec3 samplePoint = start + sampleRay * 0.5;\n\
  150408. vec3 frontColor = vec3(0.0, 0.0, 0.0);\n\
  150409. vec3 lightDir = (u_cameraAndRadiiAndDynamicAtmosphereColor.w > 0.0) ? czm_sunPositionWC - czm_viewerPositionWC : czm_viewerPositionWC;\n\
  150410. lightDir = normalize(lightDir);\n\
  150411. for(int i=0; i<nSamples; i++)\n\
  150412. {\n\
  150413. float height = length(samplePoint);\n\
  150414. float depth = exp((atmosphereScale / rayleighScaleDepth ) * (innerRadius - height));\n\
  150415. float fLightAngle = dot(lightDir, samplePoint) / height;\n\
  150416. float fCameraAngle = dot(ray, samplePoint) / height;\n\
  150417. float fScatter = (startOffset + depth*(scale(fLightAngle) - scale(fCameraAngle)));\n\
  150418. vec3 attenuate = exp(-fScatter * (InvWavelength * Kr4PI + Km4PI));\n\
  150419. frontColor += attenuate * (depth * scaledLength);\n\
  150420. samplePoint += sampleRay;\n\
  150421. }\n\
  150422. v_mieColor = frontColor * KmESun;\n\
  150423. v_rayleighColor = frontColor * (InvWavelength * KrESun);\n\
  150424. v_toCamera = czm_viewerPositionWC - positionV3;\n\
  150425. gl_Position = czm_modelViewProjection * position;\n\
  150426. }\n\
  150427. ";
  150428. });
  150429. /*global define*/
  150430. define('Scene/SkyAtmosphere',[
  150431. '../Core/Cartesian3',
  150432. '../Core/Cartesian4',
  150433. '../Core/defaultValue',
  150434. '../Core/defined',
  150435. '../Core/defineProperties',
  150436. '../Core/destroyObject',
  150437. '../Core/Ellipsoid',
  150438. '../Core/EllipsoidGeometry',
  150439. '../Core/GeometryPipeline',
  150440. '../Core/Math',
  150441. '../Core/VertexFormat',
  150442. '../Renderer/BufferUsage',
  150443. '../Renderer/DrawCommand',
  150444. '../Renderer/RenderState',
  150445. '../Renderer/ShaderProgram',
  150446. '../Renderer/ShaderSource',
  150447. '../Renderer/VertexArray',
  150448. '../Shaders/SkyAtmosphereFS',
  150449. '../Shaders/SkyAtmosphereVS',
  150450. './BlendingState',
  150451. './CullFace',
  150452. './SceneMode'
  150453. ], function(
  150454. Cartesian3,
  150455. Cartesian4,
  150456. defaultValue,
  150457. defined,
  150458. defineProperties,
  150459. destroyObject,
  150460. Ellipsoid,
  150461. EllipsoidGeometry,
  150462. GeometryPipeline,
  150463. CesiumMath,
  150464. VertexFormat,
  150465. BufferUsage,
  150466. DrawCommand,
  150467. RenderState,
  150468. ShaderProgram,
  150469. ShaderSource,
  150470. VertexArray,
  150471. SkyAtmosphereFS,
  150472. SkyAtmosphereVS,
  150473. BlendingState,
  150474. CullFace,
  150475. SceneMode) {
  150476. 'use strict';
  150477. /**
  150478. * An atmosphere drawn around the limb of the provided ellipsoid. Based on
  150479. * {@link http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html|Accurate Atmospheric Scattering}
  150480. * in GPU Gems 2.
  150481. * <p>
  150482. * This is only supported in 3D. atmosphere is faded out when morphing to 2D or Columbus view.
  150483. * </p>
  150484. *
  150485. * @alias SkyAtmosphere
  150486. * @constructor
  150487. *
  150488. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid that the atmosphere is drawn around.
  150489. *
  150490. * @example
  150491. * scene.skyAtmosphere = new Cesium.SkyAtmosphere();
  150492. *
  150493. * @see Scene.skyAtmosphere
  150494. */
  150495. function SkyAtmosphere(ellipsoid) {
  150496. ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
  150497. /**
  150498. * Determines if the atmosphere is shown.
  150499. *
  150500. * @type {Boolean}
  150501. * @default true
  150502. */
  150503. this.show = true;
  150504. this._ellipsoid = ellipsoid;
  150505. this._command = new DrawCommand({
  150506. owner : this
  150507. });
  150508. this._spSkyFromSpace = undefined;
  150509. this._spSkyFromAtmosphere = undefined;
  150510. this._spSkyFromSpaceColorCorrect = undefined;
  150511. this._spSkyFromAtmosphereColorCorrect = undefined;
  150512. /**
  150513. * The hue shift to apply to the atmosphere. Defaults to 0.0 (no shift).
  150514. * A hue shift of 1.0 indicates a complete rotation of the hues available.
  150515. * @type {Number}
  150516. * @default 0.0
  150517. */
  150518. this.hueShift = 0.0;
  150519. /**
  150520. * The saturation shift to apply to the atmosphere. Defaults to 0.0 (no shift).
  150521. * A saturation shift of -1.0 is monochrome.
  150522. * @type {Number}
  150523. * @default 0.0
  150524. */
  150525. this.saturationShift = 0.0;
  150526. /**
  150527. * The brightness shift to apply to the atmosphere. Defaults to 0.0 (no shift).
  150528. * A brightness shift of -1.0 is complete darkness, which will let space show through.
  150529. * @type {Number}
  150530. * @default 0.0
  150531. */
  150532. this.brightnessShift = 0.0;
  150533. this._hueSaturationBrightness = new Cartesian3();
  150534. // camera height, outer radius, inner radius, dynamic atmosphere color flag
  150535. var cameraAndRadiiAndDynamicAtmosphereColor = new Cartesian4();
  150536. // Toggles whether the sun position is used. 0 treats the sun as always directly overhead.
  150537. cameraAndRadiiAndDynamicAtmosphereColor.w = 0;
  150538. cameraAndRadiiAndDynamicAtmosphereColor.y = Cartesian3.maximumComponent(Cartesian3.multiplyByScalar(ellipsoid.radii, 1.025, new Cartesian3()));
  150539. cameraAndRadiiAndDynamicAtmosphereColor.z = ellipsoid.maximumRadius;
  150540. this._cameraAndRadiiAndDynamicAtmosphereColor = cameraAndRadiiAndDynamicAtmosphereColor;
  150541. var that = this;
  150542. this._command.uniformMap = {
  150543. u_cameraAndRadiiAndDynamicAtmosphereColor : function() {
  150544. return that._cameraAndRadiiAndDynamicAtmosphereColor;
  150545. },
  150546. u_hsbShift : function() {
  150547. that._hueSaturationBrightness.x = that.hueShift;
  150548. that._hueSaturationBrightness.y = that.saturationShift;
  150549. that._hueSaturationBrightness.z = that.brightnessShift;
  150550. return that._hueSaturationBrightness;
  150551. }
  150552. };
  150553. }
  150554. defineProperties(SkyAtmosphere.prototype, {
  150555. /**
  150556. * Gets the ellipsoid the atmosphere is drawn around.
  150557. * @memberof SkyAtmosphere.prototype
  150558. *
  150559. * @type {Ellipsoid}
  150560. * @readonly
  150561. */
  150562. ellipsoid : {
  150563. get : function() {
  150564. return this._ellipsoid;
  150565. }
  150566. }
  150567. });
  150568. /**
  150569. * @private
  150570. */
  150571. SkyAtmosphere.prototype.setDynamicAtmosphereColor = function(enableLighting) {
  150572. this._cameraAndRadiiAndDynamicAtmosphereColor.w = enableLighting ? 1 : 0;
  150573. };
  150574. /**
  150575. * @private
  150576. */
  150577. SkyAtmosphere.prototype.update = function(frameState) {
  150578. if (!this.show) {
  150579. return undefined;
  150580. }
  150581. if ((frameState.mode !== SceneMode.SCENE3D) &&
  150582. (frameState.mode !== SceneMode.MORPHING)) {
  150583. return undefined;
  150584. }
  150585. // The atmosphere is only rendered during the render pass; it is not pickable, it doesn't cast shadows, etc.
  150586. if (!frameState.passes.render) {
  150587. return undefined;
  150588. }
  150589. var command = this._command;
  150590. if (!defined(command.vertexArray)) {
  150591. var context = frameState.context;
  150592. var geometry = EllipsoidGeometry.createGeometry(new EllipsoidGeometry({
  150593. radii : Cartesian3.multiplyByScalar(this._ellipsoid.radii, 1.025, new Cartesian3()),
  150594. slicePartitions : 256,
  150595. stackPartitions : 256,
  150596. vertexFormat : VertexFormat.POSITION_ONLY
  150597. }));
  150598. command.vertexArray = VertexArray.fromGeometry({
  150599. context : context,
  150600. geometry : geometry,
  150601. attributeLocations : GeometryPipeline.createAttributeLocations(geometry),
  150602. bufferUsage : BufferUsage.STATIC_DRAW
  150603. });
  150604. command.renderState = RenderState.fromCache({
  150605. cull : {
  150606. enabled : true,
  150607. face : CullFace.FRONT
  150608. },
  150609. blending : BlendingState.ALPHA_BLEND
  150610. });
  150611. var vs = new ShaderSource({
  150612. defines : ['SKY_FROM_SPACE'],
  150613. sources : [SkyAtmosphereVS]
  150614. });
  150615. this._spSkyFromSpace = ShaderProgram.fromCache({
  150616. context : context,
  150617. vertexShaderSource : vs,
  150618. fragmentShaderSource : SkyAtmosphereFS
  150619. });
  150620. vs = new ShaderSource({
  150621. defines : ['SKY_FROM_ATMOSPHERE'],
  150622. sources : [SkyAtmosphereVS]
  150623. });
  150624. this._spSkyFromAtmosphere = ShaderProgram.fromCache({
  150625. context : context,
  150626. vertexShaderSource : vs,
  150627. fragmentShaderSource : SkyAtmosphereFS
  150628. });
  150629. }
  150630. // Compile the color correcting versions of the shader on demand
  150631. var useColorCorrect = colorCorrect(this);
  150632. if (useColorCorrect && (!defined(this._spSkyFromSpaceColorCorrect) || !defined(this._spSkyFromAtmosphereColorCorrect))) {
  150633. var contextColorCorrect = frameState.context;
  150634. var vsColorCorrect = new ShaderSource({
  150635. defines : ['SKY_FROM_SPACE'],
  150636. sources : [SkyAtmosphereVS]
  150637. });
  150638. var fsColorCorrect = new ShaderSource({
  150639. defines : ['COLOR_CORRECT'],
  150640. sources : [SkyAtmosphereFS]
  150641. });
  150642. this._spSkyFromSpaceColorCorrect = ShaderProgram.fromCache({
  150643. context : contextColorCorrect,
  150644. vertexShaderSource : vsColorCorrect,
  150645. fragmentShaderSource : fsColorCorrect
  150646. });
  150647. vsColorCorrect = new ShaderSource({
  150648. defines : ['SKY_FROM_ATMOSPHERE'],
  150649. sources : [SkyAtmosphereVS]
  150650. });
  150651. this._spSkyFromAtmosphereColorCorrect = ShaderProgram.fromCache({
  150652. context : contextColorCorrect,
  150653. vertexShaderSource : vsColorCorrect,
  150654. fragmentShaderSource : fsColorCorrect
  150655. });
  150656. }
  150657. var cameraPosition = frameState.camera.positionWC;
  150658. var cameraHeight = Cartesian3.magnitude(cameraPosition);
  150659. this._cameraAndRadiiAndDynamicAtmosphereColor.x = cameraHeight;
  150660. if (cameraHeight > this._cameraAndRadiiAndDynamicAtmosphereColor.y) {
  150661. // Camera in space
  150662. command.shaderProgram = useColorCorrect ? this._spSkyFromSpaceColorCorrect : this._spSkyFromSpace;
  150663. } else {
  150664. // Camera in atmosphere
  150665. command.shaderProgram = useColorCorrect ? this._spSkyFromAtmosphereColorCorrect : this._spSkyFromAtmosphere;
  150666. }
  150667. return command;
  150668. };
  150669. function colorCorrect(skyAtmosphere) {
  150670. return !(CesiumMath.equalsEpsilon(skyAtmosphere.hueShift, 0.0, CesiumMath.EPSILON7) &&
  150671. CesiumMath.equalsEpsilon(skyAtmosphere.saturationShift, 0.0, CesiumMath.EPSILON7) &&
  150672. CesiumMath.equalsEpsilon(skyAtmosphere.brightnessShift, 0.0, CesiumMath.EPSILON7));
  150673. }
  150674. /**
  150675. * Returns true if this object was destroyed; otherwise, false.
  150676. * <br /><br />
  150677. * If this object was destroyed, it should not be used; calling any function other than
  150678. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  150679. *
  150680. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  150681. *
  150682. * @see SkyAtmosphere#destroy
  150683. */
  150684. SkyAtmosphere.prototype.isDestroyed = function() {
  150685. return false;
  150686. };
  150687. /**
  150688. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  150689. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  150690. * <br /><br />
  150691. * Once an object is destroyed, it should not be used; calling any function other than
  150692. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  150693. * assign the return value (<code>undefined</code>) to the object as done in the example.
  150694. *
  150695. * @returns {undefined}
  150696. *
  150697. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  150698. *
  150699. *
  150700. * @example
  150701. * skyAtmosphere = skyAtmosphere && skyAtmosphere.destroy();
  150702. *
  150703. * @see SkyAtmosphere#isDestroyed
  150704. */
  150705. SkyAtmosphere.prototype.destroy = function() {
  150706. var command = this._command;
  150707. command.vertexArray = command.vertexArray && command.vertexArray.destroy();
  150708. this._spSkyFromSpace = this._spSkyFromSpace && this._spSkyFromSpace.destroy();
  150709. this._spSkyFromAtmosphere = this._spSkyFromAtmosphere && this._spSkyFromAtmosphere.destroy();
  150710. this._spSkyFromSpaceColorCorrect = this._spSkyFromSpaceColorCorrect && this._spSkyFromSpaceColorCorrect.destroy();
  150711. this._spSkyFromAtmosphereColorCorrect = this._spSkyFromAtmosphereColorCorrect && this._spSkyFromAtmosphereColorCorrect.destroy();
  150712. return destroyObject(this);
  150713. };
  150714. return SkyAtmosphere;
  150715. });
  150716. //This file is automatically rebuilt by the Cesium build process.
  150717. /*global define*/
  150718. define('Shaders/SkyBoxFS',[],function() {
  150719. 'use strict';
  150720. return "uniform samplerCube u_cubeMap;\n\
  150721. varying vec3 v_texCoord;\n\
  150722. void main()\n\
  150723. {\n\
  150724. vec3 rgb = textureCube(u_cubeMap, normalize(v_texCoord)).rgb;\n\
  150725. gl_FragColor = vec4(rgb, czm_morphTime);\n\
  150726. }\n\
  150727. ";
  150728. });
  150729. //This file is automatically rebuilt by the Cesium build process.
  150730. /*global define*/
  150731. define('Shaders/SkyBoxVS',[],function() {
  150732. 'use strict';
  150733. return "attribute vec3 position;\n\
  150734. varying vec3 v_texCoord;\n\
  150735. void main()\n\
  150736. {\n\
  150737. vec3 p = czm_viewRotation * (czm_temeToPseudoFixed * (czm_entireFrustum.y * position));\n\
  150738. gl_Position = czm_projection * vec4(p, 1.0);\n\
  150739. v_texCoord = position.xyz;\n\
  150740. }\n\
  150741. ";
  150742. });
  150743. /*global define*/
  150744. define('Scene/SkyBox',[
  150745. '../Core/BoxGeometry',
  150746. '../Core/Cartesian3',
  150747. '../Core/defaultValue',
  150748. '../Core/defined',
  150749. '../Core/destroyObject',
  150750. '../Core/DeveloperError',
  150751. '../Core/GeometryPipeline',
  150752. '../Core/Matrix4',
  150753. '../Core/VertexFormat',
  150754. '../Renderer/BufferUsage',
  150755. '../Renderer/CubeMap',
  150756. '../Renderer/DrawCommand',
  150757. '../Renderer/loadCubeMap',
  150758. '../Renderer/RenderState',
  150759. '../Renderer/ShaderProgram',
  150760. '../Renderer/VertexArray',
  150761. '../Shaders/SkyBoxFS',
  150762. '../Shaders/SkyBoxVS',
  150763. './BlendingState',
  150764. './SceneMode'
  150765. ], function(
  150766. BoxGeometry,
  150767. Cartesian3,
  150768. defaultValue,
  150769. defined,
  150770. destroyObject,
  150771. DeveloperError,
  150772. GeometryPipeline,
  150773. Matrix4,
  150774. VertexFormat,
  150775. BufferUsage,
  150776. CubeMap,
  150777. DrawCommand,
  150778. loadCubeMap,
  150779. RenderState,
  150780. ShaderProgram,
  150781. VertexArray,
  150782. SkyBoxFS,
  150783. SkyBoxVS,
  150784. BlendingState,
  150785. SceneMode) {
  150786. 'use strict';
  150787. /**
  150788. * A sky box around the scene to draw stars. The sky box is defined using the True Equator Mean Equinox (TEME) axes.
  150789. * <p>
  150790. * This is only supported in 3D. The sky box is faded out when morphing to 2D or Columbus view. The size of
  150791. * the sky box must not exceed {@link Scene#maximumCubeMapSize}.
  150792. * </p>
  150793. *
  150794. * @alias SkyBox
  150795. * @constructor
  150796. *
  150797. * @param {Object} options Object with the following properties:
  150798. * @param {Object} [options.sources] The source URL or <code>Image</code> object for each of the six cube map faces. See the example below.
  150799. * @param {Boolean} [options.show=true] Determines if this primitive will be shown.
  150800. *
  150801. *
  150802. * @example
  150803. * scene.skyBox = new Cesium.SkyBox({
  150804. * sources : {
  150805. * positiveX : 'skybox_px.png',
  150806. * negativeX : 'skybox_nx.png',
  150807. * positiveY : 'skybox_py.png',
  150808. * negativeY : 'skybox_ny.png',
  150809. * positiveZ : 'skybox_pz.png',
  150810. * negativeZ : 'skybox_nz.png'
  150811. * }
  150812. * });
  150813. *
  150814. * @see Scene#skyBox
  150815. * @see Transforms.computeTemeToPseudoFixedMatrix
  150816. */
  150817. function SkyBox(options) {
  150818. /**
  150819. * The sources used to create the cube map faces: an object
  150820. * with <code>positiveX</code>, <code>negativeX</code>, <code>positiveY</code>,
  150821. * <code>negativeY</code>, <code>positiveZ</code>, and <code>negativeZ</code> properties.
  150822. * These can be either URLs or <code>Image</code> objects.
  150823. *
  150824. * @type Object
  150825. * @default undefined
  150826. */
  150827. this.sources = options.sources;
  150828. this._sources = undefined;
  150829. /**
  150830. * Determines if the sky box will be shown.
  150831. *
  150832. * @type {Boolean}
  150833. * @default true
  150834. */
  150835. this.show = defaultValue(options.show, true);
  150836. this._command = new DrawCommand({
  150837. modelMatrix : Matrix4.clone(Matrix4.IDENTITY),
  150838. owner : this
  150839. });
  150840. this._cubeMap = undefined;
  150841. }
  150842. /**
  150843. * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
  150844. * get the draw commands needed to render this primitive.
  150845. * <p>
  150846. * Do not call this function directly. This is documented just to
  150847. * list the exceptions that may be propagated when the scene is rendered:
  150848. * </p>
  150849. *
  150850. * @exception {DeveloperError} this.sources is required and must have positiveX, negativeX, positiveY, negativeY, positiveZ, and negativeZ properties.
  150851. * @exception {DeveloperError} this.sources properties must all be the same type.
  150852. */
  150853. SkyBox.prototype.update = function(frameState) {
  150854. if (!this.show) {
  150855. return undefined;
  150856. }
  150857. if ((frameState.mode !== SceneMode.SCENE3D) &&
  150858. (frameState.mode !== SceneMode.MORPHING)) {
  150859. return undefined;
  150860. }
  150861. // The sky box is only rendered during the render pass; it is not pickable, it doesn't cast shadows, etc.
  150862. if (!frameState.passes.render) {
  150863. return undefined;
  150864. }
  150865. var context = frameState.context;
  150866. if (this._sources !== this.sources) {
  150867. this._sources = this.sources;
  150868. var sources = this.sources;
  150869. if ((!defined(sources.positiveX)) ||
  150870. (!defined(sources.negativeX)) ||
  150871. (!defined(sources.positiveY)) ||
  150872. (!defined(sources.negativeY)) ||
  150873. (!defined(sources.positiveZ)) ||
  150874. (!defined(sources.negativeZ))) {
  150875. throw new DeveloperError('this.sources is required and must have positiveX, negativeX, positiveY, negativeY, positiveZ, and negativeZ properties.');
  150876. }
  150877. if ((typeof sources.positiveX !== typeof sources.negativeX) ||
  150878. (typeof sources.positiveX !== typeof sources.positiveY) ||
  150879. (typeof sources.positiveX !== typeof sources.negativeY) ||
  150880. (typeof sources.positiveX !== typeof sources.positiveZ) ||
  150881. (typeof sources.positiveX !== typeof sources.negativeZ)) {
  150882. throw new DeveloperError('this.sources properties must all be the same type.');
  150883. }
  150884. if (typeof sources.positiveX === 'string') {
  150885. // Given urls for cube-map images. Load them.
  150886. loadCubeMap(context, this._sources).then(function(cubeMap) {
  150887. that._cubeMap = that._cubeMap && that._cubeMap.destroy();
  150888. that._cubeMap = cubeMap;
  150889. });
  150890. } else {
  150891. this._cubeMap = this._cubeMap && this._cubeMap.destroy();
  150892. this._cubeMap = new CubeMap({
  150893. context : context,
  150894. source : sources
  150895. });
  150896. }
  150897. }
  150898. var command = this._command;
  150899. if (!defined(command.vertexArray)) {
  150900. var that = this;
  150901. command.uniformMap = {
  150902. u_cubeMap: function() {
  150903. return that._cubeMap;
  150904. }
  150905. };
  150906. var geometry = BoxGeometry.createGeometry(BoxGeometry.fromDimensions({
  150907. dimensions : new Cartesian3(2.0, 2.0, 2.0),
  150908. vertexFormat : VertexFormat.POSITION_ONLY
  150909. }));
  150910. var attributeLocations = GeometryPipeline.createAttributeLocations(geometry);
  150911. command.vertexArray = VertexArray.fromGeometry({
  150912. context : context,
  150913. geometry : geometry,
  150914. attributeLocations : attributeLocations,
  150915. bufferUsage : BufferUsage.STATIC_DRAW
  150916. });
  150917. command.shaderProgram = ShaderProgram.fromCache({
  150918. context : context,
  150919. vertexShaderSource : SkyBoxVS,
  150920. fragmentShaderSource : SkyBoxFS,
  150921. attributeLocations : attributeLocations
  150922. });
  150923. command.renderState = RenderState.fromCache({
  150924. blending : BlendingState.ALPHA_BLEND
  150925. });
  150926. }
  150927. if (!defined(this._cubeMap)) {
  150928. return undefined;
  150929. }
  150930. return command;
  150931. };
  150932. /**
  150933. * Returns true if this object was destroyed; otherwise, false.
  150934. * <br /><br />
  150935. * If this object was destroyed, it should not be used; calling any function other than
  150936. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  150937. *
  150938. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  150939. *
  150940. * @see SkyBox#destroy
  150941. */
  150942. SkyBox.prototype.isDestroyed = function() {
  150943. return false;
  150944. };
  150945. /**
  150946. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  150947. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  150948. * <br /><br />
  150949. * Once an object is destroyed, it should not be used; calling any function other than
  150950. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  150951. * assign the return value (<code>undefined</code>) to the object as done in the example.
  150952. *
  150953. * @returns {undefined}
  150954. *
  150955. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  150956. *
  150957. *
  150958. * @example
  150959. * skyBox = skyBox && skyBox.destroy();
  150960. *
  150961. * @see SkyBox#isDestroyed
  150962. */
  150963. SkyBox.prototype.destroy = function() {
  150964. var command = this._command;
  150965. command.vertexArray = command.vertexArray && command.vertexArray.destroy();
  150966. command.shaderProgram = command.shaderProgram && command.shaderProgram.destroy();
  150967. this._cubeMap = this._cubeMap && this._cubeMap.destroy();
  150968. return destroyObject(this);
  150969. };
  150970. return SkyBox;
  150971. });
  150972. //This file is automatically rebuilt by the Cesium build process.
  150973. /*global define*/
  150974. define('Shaders/SunFS',[],function() {
  150975. 'use strict';
  150976. return "uniform sampler2D u_texture;\n\
  150977. varying vec2 v_textureCoordinates;\n\
  150978. void main()\n\
  150979. {\n\
  150980. gl_FragColor = texture2D(u_texture, v_textureCoordinates);\n\
  150981. }\n\
  150982. ";
  150983. });
  150984. //This file is automatically rebuilt by the Cesium build process.
  150985. /*global define*/
  150986. define('Shaders/SunTextureFS',[],function() {
  150987. 'use strict';
  150988. return "uniform float u_glowLengthTS;\n\
  150989. uniform float u_radiusTS;\n\
  150990. varying vec2 v_textureCoordinates;\n\
  150991. vec2 rotate(vec2 p, vec2 direction)\n\
  150992. {\n\
  150993. return vec2(p.x * direction.x - p.y * direction.y, p.x * direction.y + p.y * direction.x);\n\
  150994. }\n\
  150995. vec4 addBurst(vec2 position, vec2 direction)\n\
  150996. {\n\
  150997. vec2 rotatedPosition = rotate(position, direction) * vec2(25.0, 0.75);\n\
  150998. float radius = length(rotatedPosition);\n\
  150999. float burst = 1.0 - smoothstep(0.0, 0.55, radius);\n\
  151000. return vec4(burst);\n\
  151001. }\n\
  151002. void main()\n\
  151003. {\n\
  151004. vec2 position = v_textureCoordinates - vec2(0.5);\n\
  151005. float radius = length(position);\n\
  151006. float surface = step(radius, u_radiusTS);\n\
  151007. vec4 color = vec4(1.0, 1.0, surface + 0.2, surface);\n\
  151008. float glow = 1.0 - smoothstep(0.0, 0.55, radius);\n\
  151009. color.ba += mix(vec2(0.0), vec2(1.0), glow) * 0.75;\n\
  151010. vec4 burst = vec4(0.0);\n\
  151011. burst += 0.4 * addBurst(position, vec2(0.38942, 0.92106));\n\
  151012. burst += 0.4 * addBurst(position, vec2(0.99235, 0.12348));\n\
  151013. burst += 0.4 * addBurst(position, vec2(0.60327, -0.79754));\n\
  151014. burst += 0.3 * addBurst(position, vec2(0.31457, 0.94924));\n\
  151015. burst += 0.3 * addBurst(position, vec2(0.97931, 0.20239));\n\
  151016. burst += 0.3 * addBurst(position, vec2(0.66507, -0.74678));\n\
  151017. color += clamp(burst, vec4(0.0), vec4(1.0)) * 0.15;\n\
  151018. gl_FragColor = clamp(color, vec4(0.0), vec4(1.0));\n\
  151019. }\n\
  151020. ";
  151021. });
  151022. //This file is automatically rebuilt by the Cesium build process.
  151023. /*global define*/
  151024. define('Shaders/SunVS',[],function() {
  151025. 'use strict';
  151026. return "attribute vec2 direction;\n\
  151027. uniform float u_size;\n\
  151028. varying vec2 v_textureCoordinates;\n\
  151029. void main()\n\
  151030. {\n\
  151031. vec4 position;\n\
  151032. if (czm_morphTime == 1.0)\n\
  151033. {\n\
  151034. position = vec4(czm_sunPositionWC, 1.0);\n\
  151035. }\n\
  151036. else\n\
  151037. {\n\
  151038. position = vec4(czm_sunPositionColumbusView.zxy, 1.0);\n\
  151039. }\n\
  151040. vec4 positionEC = czm_view * position;\n\
  151041. vec4 positionWC = czm_eyeToWindowCoordinates(positionEC);\n\
  151042. vec2 halfSize = vec2(u_size * 0.5);\n\
  151043. halfSize *= ((direction * 2.0) - 1.0);\n\
  151044. gl_Position = czm_viewportOrthographic * vec4(positionWC.xy + halfSize, -positionWC.z, 1.0);\n\
  151045. v_textureCoordinates = direction;\n\
  151046. }\n\
  151047. ";
  151048. });
  151049. /*global define*/
  151050. define('Scene/Sun',[
  151051. '../Core/BoundingSphere',
  151052. '../Core/Cartesian2',
  151053. '../Core/Cartesian3',
  151054. '../Core/Cartesian4',
  151055. '../Core/ComponentDatatype',
  151056. '../Core/defined',
  151057. '../Core/defineProperties',
  151058. '../Core/destroyObject',
  151059. '../Core/IndexDatatype',
  151060. '../Core/Math',
  151061. '../Core/Matrix4',
  151062. '../Core/PixelFormat',
  151063. '../Core/PrimitiveType',
  151064. '../Renderer/Buffer',
  151065. '../Renderer/BufferUsage',
  151066. '../Renderer/ComputeCommand',
  151067. '../Renderer/DrawCommand',
  151068. '../Renderer/RenderState',
  151069. '../Renderer/ShaderProgram',
  151070. '../Renderer/Texture',
  151071. '../Renderer/VertexArray',
  151072. '../Shaders/SunFS',
  151073. '../Shaders/SunTextureFS',
  151074. '../Shaders/SunVS',
  151075. './BlendingState',
  151076. './SceneMode',
  151077. './SceneTransforms'
  151078. ], function(
  151079. BoundingSphere,
  151080. Cartesian2,
  151081. Cartesian3,
  151082. Cartesian4,
  151083. ComponentDatatype,
  151084. defined,
  151085. defineProperties,
  151086. destroyObject,
  151087. IndexDatatype,
  151088. CesiumMath,
  151089. Matrix4,
  151090. PixelFormat,
  151091. PrimitiveType,
  151092. Buffer,
  151093. BufferUsage,
  151094. ComputeCommand,
  151095. DrawCommand,
  151096. RenderState,
  151097. ShaderProgram,
  151098. Texture,
  151099. VertexArray,
  151100. SunFS,
  151101. SunTextureFS,
  151102. SunVS,
  151103. BlendingState,
  151104. SceneMode,
  151105. SceneTransforms) {
  151106. 'use strict';
  151107. /**
  151108. * Draws a sun billboard.
  151109. * <p>This is only supported in 3D and Columbus view.</p>
  151110. *
  151111. * @alias Sun
  151112. * @constructor
  151113. *
  151114. *
  151115. * @example
  151116. * scene.sun = new Cesium.Sun();
  151117. *
  151118. * @see Scene#sun
  151119. */
  151120. function Sun() {
  151121. /**
  151122. * Determines if the sun will be shown.
  151123. *
  151124. * @type {Boolean}
  151125. * @default true
  151126. */
  151127. this.show = true;
  151128. this._drawCommand = new DrawCommand({
  151129. primitiveType : PrimitiveType.TRIANGLES,
  151130. boundingVolume : new BoundingSphere(),
  151131. owner : this
  151132. });
  151133. this._commands = {
  151134. drawCommand : this._drawCommand,
  151135. computeCommand : undefined
  151136. };
  151137. this._boundingVolume = new BoundingSphere();
  151138. this._boundingVolume2D = new BoundingSphere();
  151139. this._texture = undefined;
  151140. this._drawingBufferWidth = undefined;
  151141. this._drawingBufferHeight = undefined;
  151142. this._radiusTS = undefined;
  151143. this._size = undefined;
  151144. this.glowFactor = 1.0;
  151145. this._glowFactorDirty = false;
  151146. var that = this;
  151147. this._uniformMap = {
  151148. u_texture : function() {
  151149. return that._texture;
  151150. },
  151151. u_size : function() {
  151152. return that._size;
  151153. }
  151154. };
  151155. }
  151156. defineProperties(Sun.prototype, {
  151157. /**
  151158. * Gets or sets a number that controls how "bright" the Sun's lens flare appears
  151159. * to be. Zero shows just the Sun's disc without any flare.
  151160. * Use larger values for a more pronounced flare around the Sun.
  151161. *
  151162. * @memberof Sun.prototype
  151163. * @type {Number}
  151164. * @default 1.0
  151165. */
  151166. glowFactor : {
  151167. get : function () { return this._glowFactor; },
  151168. set : function (glowFactor) {
  151169. glowFactor = Math.max(glowFactor, 0.0);
  151170. this._glowFactor = glowFactor;
  151171. this._glowFactorDirty = true;
  151172. }
  151173. }
  151174. });
  151175. var scratchPositionWC = new Cartesian2();
  151176. var scratchLimbWC = new Cartesian2();
  151177. var scratchPositionEC = new Cartesian4();
  151178. var scratchCartesian4 = new Cartesian4();
  151179. /**
  151180. * @private
  151181. */
  151182. Sun.prototype.update = function(scene) {
  151183. var passState = scene._passState;
  151184. var frameState = scene.frameState;
  151185. var context = scene.context;
  151186. if (!this.show) {
  151187. return undefined;
  151188. }
  151189. var mode = frameState.mode;
  151190. if (mode === SceneMode.SCENE2D || mode === SceneMode.MORPHING) {
  151191. return undefined;
  151192. }
  151193. if (!frameState.passes.render) {
  151194. return undefined;
  151195. }
  151196. var drawingBufferWidth = passState.viewport.width;
  151197. var drawingBufferHeight = passState.viewport.height;
  151198. if (!defined(this._texture) ||
  151199. drawingBufferWidth !== this._drawingBufferWidth ||
  151200. drawingBufferHeight !== this._drawingBufferHeight ||
  151201. this._glowFactorDirty) {
  151202. this._texture = this._texture && this._texture.destroy();
  151203. this._drawingBufferWidth = drawingBufferWidth;
  151204. this._drawingBufferHeight = drawingBufferHeight;
  151205. this._glowFactorDirty = false;
  151206. var size = Math.max(drawingBufferWidth, drawingBufferHeight);
  151207. size = Math.pow(2.0, Math.ceil(Math.log(size) / Math.log(2.0)) - 2.0);
  151208. // The size computed above can be less than 1.0 if size < 4.0. This will probably
  151209. // never happen in practice, but does in the tests. Clamp to 1.0 to prevent WebGL
  151210. // errors in the tests.
  151211. size = Math.max(1.0, size);
  151212. this._texture = new Texture({
  151213. context : context,
  151214. width : size,
  151215. height : size,
  151216. pixelFormat : PixelFormat.RGBA
  151217. });
  151218. this._glowLengthTS = this._glowFactor * 5.0;
  151219. this._radiusTS = (1.0 / (1.0 + 2.0 * this._glowLengthTS)) * 0.5;
  151220. var that = this;
  151221. var uniformMap = {
  151222. u_glowLengthTS : function() {
  151223. return that._glowLengthTS;
  151224. },
  151225. u_radiusTS : function() {
  151226. return that._radiusTS;
  151227. }
  151228. };
  151229. this._commands.computeCommand = new ComputeCommand({
  151230. fragmentShaderSource : SunTextureFS,
  151231. outputTexture : this._texture,
  151232. uniformMap : uniformMap,
  151233. persists : false,
  151234. owner : this,
  151235. postExecute : function() {
  151236. that._commands.computeCommand = undefined;
  151237. }
  151238. });
  151239. }
  151240. var drawCommand = this._drawCommand;
  151241. if (!defined(drawCommand.vertexArray)) {
  151242. var attributeLocations = {
  151243. direction : 0
  151244. };
  151245. var directions = new Uint8Array(4 * 2);
  151246. directions[0] = 0;
  151247. directions[1] = 0;
  151248. directions[2] = 255;
  151249. directions[3] = 0.0;
  151250. directions[4] = 255;
  151251. directions[5] = 255;
  151252. directions[6] = 0.0;
  151253. directions[7] = 255;
  151254. var vertexBuffer = Buffer.createVertexBuffer({
  151255. context : context,
  151256. typedArray : directions,
  151257. usage : BufferUsage.STATIC_DRAW
  151258. });
  151259. var attributes = [{
  151260. index : attributeLocations.direction,
  151261. vertexBuffer : vertexBuffer,
  151262. componentsPerAttribute : 2,
  151263. normalize : true,
  151264. componentDatatype : ComponentDatatype.UNSIGNED_BYTE
  151265. }];
  151266. // Workaround Internet Explorer 11.0.8 lack of TRIANGLE_FAN
  151267. var indexBuffer = Buffer.createIndexBuffer({
  151268. context : context,
  151269. typedArray : new Uint16Array([0, 1, 2, 0, 2, 3]),
  151270. usage : BufferUsage.STATIC_DRAW,
  151271. indexDatatype : IndexDatatype.UNSIGNED_SHORT
  151272. });
  151273. drawCommand.vertexArray = new VertexArray({
  151274. context : context,
  151275. attributes : attributes,
  151276. indexBuffer : indexBuffer
  151277. });
  151278. drawCommand.shaderProgram = ShaderProgram.fromCache({
  151279. context : context,
  151280. vertexShaderSource : SunVS,
  151281. fragmentShaderSource : SunFS,
  151282. attributeLocations : attributeLocations
  151283. });
  151284. drawCommand.renderState = RenderState.fromCache({
  151285. blending : BlendingState.ALPHA_BLEND
  151286. });
  151287. drawCommand.uniformMap = this._uniformMap;
  151288. }
  151289. var sunPosition = context.uniformState.sunPositionWC;
  151290. var sunPositionCV = context.uniformState.sunPositionColumbusView;
  151291. var boundingVolume = this._boundingVolume;
  151292. var boundingVolume2D = this._boundingVolume2D;
  151293. Cartesian3.clone(sunPosition, boundingVolume.center);
  151294. boundingVolume2D.center.x = sunPositionCV.z;
  151295. boundingVolume2D.center.y = sunPositionCV.x;
  151296. boundingVolume2D.center.z = sunPositionCV.y;
  151297. boundingVolume.radius = CesiumMath.SOLAR_RADIUS + CesiumMath.SOLAR_RADIUS * this._glowLengthTS;
  151298. boundingVolume2D.radius = boundingVolume.radius;
  151299. if (mode === SceneMode.SCENE3D) {
  151300. BoundingSphere.clone(boundingVolume, drawCommand.boundingVolume);
  151301. } else if (mode === SceneMode.COLUMBUS_VIEW) {
  151302. BoundingSphere.clone(boundingVolume2D, drawCommand.boundingVolume);
  151303. }
  151304. var position = SceneTransforms.computeActualWgs84Position(frameState, sunPosition, scratchCartesian4);
  151305. var dist = Cartesian3.magnitude(Cartesian3.subtract(position, scene.camera.position, scratchCartesian4));
  151306. var projMatrix = context.uniformState.projection;
  151307. var positionEC = scratchPositionEC;
  151308. positionEC.x = 0;
  151309. positionEC.y = 0;
  151310. positionEC.z = -dist;
  151311. positionEC.w = 1;
  151312. var positionCC = Matrix4.multiplyByVector(projMatrix, positionEC, scratchCartesian4);
  151313. var positionWC = SceneTransforms.clipToDrawingBufferCoordinates(passState.viewport, positionCC, scratchPositionWC);
  151314. positionEC.x = CesiumMath.SOLAR_RADIUS;
  151315. var limbCC = Matrix4.multiplyByVector(projMatrix, positionEC, scratchCartesian4);
  151316. var limbWC = SceneTransforms.clipToDrawingBufferCoordinates(passState.viewport, limbCC, scratchLimbWC);
  151317. this._size = Math.ceil(Cartesian2.magnitude(Cartesian2.subtract(limbWC, positionWC, scratchCartesian4)));
  151318. this._size = 2.0 * this._size * (1.0 + 2.0 * this._glowLengthTS);
  151319. return this._commands;
  151320. };
  151321. /**
  151322. * Returns true if this object was destroyed; otherwise, false.
  151323. * <br /><br />
  151324. * If this object was destroyed, it should not be used; calling any function other than
  151325. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  151326. *
  151327. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  151328. *
  151329. * @see Sun#destroy
  151330. */
  151331. Sun.prototype.isDestroyed = function() {
  151332. return false;
  151333. };
  151334. /**
  151335. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  151336. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  151337. * <br /><br />
  151338. * Once an object is destroyed, it should not be used; calling any function other than
  151339. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  151340. * assign the return value (<code>undefined</code>) to the object as done in the example.
  151341. *
  151342. * @returns {undefined}
  151343. *
  151344. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  151345. *
  151346. *
  151347. * @example
  151348. * sun = sun && sun.destroy();
  151349. *
  151350. * @see Sun#isDestroyed
  151351. */
  151352. Sun.prototype.destroy = function() {
  151353. var command = this._drawCommand;
  151354. command.vertexArray = command.vertexArray && command.vertexArray.destroy();
  151355. command.shaderProgram = command.shaderProgram && command.shaderProgram.destroy();
  151356. this._texture = this._texture && this._texture.destroy();
  151357. return destroyObject(this);
  151358. };
  151359. return Sun;
  151360. });
  151361. /*global define*/
  151362. define('Scene/TileCoordinatesImageryProvider',[
  151363. '../Core/Color',
  151364. '../Core/defaultValue',
  151365. '../Core/defined',
  151366. '../Core/defineProperties',
  151367. '../Core/Event',
  151368. '../Core/GeographicTilingScheme',
  151369. '../ThirdParty/when'
  151370. ], function(
  151371. Color,
  151372. defaultValue,
  151373. defined,
  151374. defineProperties,
  151375. Event,
  151376. GeographicTilingScheme,
  151377. when) {
  151378. 'use strict';
  151379. /**
  151380. * An {@link ImageryProvider} that draws a box around every rendered tile in the tiling scheme, and draws
  151381. * a label inside it indicating the X, Y, Level coordinates of the tile. This is mostly useful for
  151382. * debugging terrain and imagery rendering problems.
  151383. *
  151384. * @alias TileCoordinatesImageryProvider
  151385. * @constructor
  151386. *
  151387. * @param {Object} [options] Object with the following properties:
  151388. * @param {TilingScheme} [options.tilingScheme=new GeographicTilingScheme()] The tiling scheme for which to draw tiles.
  151389. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If the tilingScheme is specified,
  151390. * this parameter is ignored and the tiling scheme's ellipsoid is used instead. If neither
  151391. * parameter is specified, the WGS84 ellipsoid is used.
  151392. * @param {Color} [options.color=Color.YELLOW] The color to draw the tile box and label.
  151393. * @param {Number} [options.tileWidth=256] The width of the tile for level-of-detail selection purposes.
  151394. * @param {Number} [options.tileHeight=256] The height of the tile for level-of-detail selection purposes.
  151395. */
  151396. function TileCoordinatesImageryProvider(options) {
  151397. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  151398. this._tilingScheme = defined(options.tilingScheme) ? options.tilingScheme : new GeographicTilingScheme({ ellipsoid : options.ellipsoid });
  151399. this._color = defaultValue(options.color, Color.YELLOW);
  151400. this._errorEvent = new Event();
  151401. this._tileWidth = defaultValue(options.tileWidth, 256);
  151402. this._tileHeight = defaultValue(options.tileHeight, 256);
  151403. this._readyPromise = when.resolve(true);
  151404. }
  151405. defineProperties(TileCoordinatesImageryProvider.prototype, {
  151406. /**
  151407. * Gets the proxy used by this provider.
  151408. * @memberof TileCoordinatesImageryProvider.prototype
  151409. * @type {Proxy}
  151410. * @readonly
  151411. */
  151412. proxy : {
  151413. get : function() {
  151414. return undefined;
  151415. }
  151416. },
  151417. /**
  151418. * Gets the width of each tile, in pixels. This function should
  151419. * not be called before {@link TileCoordinatesImageryProvider#ready} returns true.
  151420. * @memberof TileCoordinatesImageryProvider.prototype
  151421. * @type {Number}
  151422. * @readonly
  151423. */
  151424. tileWidth : {
  151425. get : function() {
  151426. return this._tileWidth;
  151427. }
  151428. },
  151429. /**
  151430. * Gets the height of each tile, in pixels. This function should
  151431. * not be called before {@link TileCoordinatesImageryProvider#ready} returns true.
  151432. * @memberof TileCoordinatesImageryProvider.prototype
  151433. * @type {Number}
  151434. * @readonly
  151435. */
  151436. tileHeight: {
  151437. get : function() {
  151438. return this._tileHeight;
  151439. }
  151440. },
  151441. /**
  151442. * Gets the maximum level-of-detail that can be requested. This function should
  151443. * not be called before {@link TileCoordinatesImageryProvider#ready} returns true.
  151444. * @memberof TileCoordinatesImageryProvider.prototype
  151445. * @type {Number}
  151446. * @readonly
  151447. */
  151448. maximumLevel : {
  151449. get : function() {
  151450. return undefined;
  151451. }
  151452. },
  151453. /**
  151454. * Gets the minimum level-of-detail that can be requested. This function should
  151455. * not be called before {@link TileCoordinatesImageryProvider#ready} returns true.
  151456. * @memberof TileCoordinatesImageryProvider.prototype
  151457. * @type {Number}
  151458. * @readonly
  151459. */
  151460. minimumLevel : {
  151461. get : function() {
  151462. return undefined;
  151463. }
  151464. },
  151465. /**
  151466. * Gets the tiling scheme used by this provider. This function should
  151467. * not be called before {@link TileCoordinatesImageryProvider#ready} returns true.
  151468. * @memberof TileCoordinatesImageryProvider.prototype
  151469. * @type {TilingScheme}
  151470. * @readonly
  151471. */
  151472. tilingScheme : {
  151473. get : function() {
  151474. return this._tilingScheme;
  151475. }
  151476. },
  151477. /**
  151478. * Gets the rectangle, in radians, of the imagery provided by this instance. This function should
  151479. * not be called before {@link TileCoordinatesImageryProvider#ready} returns true.
  151480. * @memberof TileCoordinatesImageryProvider.prototype
  151481. * @type {Rectangle}
  151482. * @readonly
  151483. */
  151484. rectangle : {
  151485. get : function() {
  151486. return this._tilingScheme.rectangle;
  151487. }
  151488. },
  151489. /**
  151490. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  151491. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  151492. * returns undefined, no tiles are filtered. This function should
  151493. * not be called before {@link TileCoordinatesImageryProvider#ready} returns true.
  151494. * @memberof TileCoordinatesImageryProvider.prototype
  151495. * @type {TileDiscardPolicy}
  151496. * @readonly
  151497. */
  151498. tileDiscardPolicy : {
  151499. get : function() {
  151500. return undefined;
  151501. }
  151502. },
  151503. /**
  151504. * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
  151505. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  151506. * are passed an instance of {@link TileProviderError}.
  151507. * @memberof TileCoordinatesImageryProvider.prototype
  151508. * @type {Event}
  151509. * @readonly
  151510. */
  151511. errorEvent : {
  151512. get : function() {
  151513. return this._errorEvent;
  151514. }
  151515. },
  151516. /**
  151517. * Gets a value indicating whether or not the provider is ready for use.
  151518. * @memberof TileCoordinatesImageryProvider.prototype
  151519. * @type {Boolean}
  151520. * @readonly
  151521. */
  151522. ready : {
  151523. get : function() {
  151524. return true;
  151525. }
  151526. },
  151527. /**
  151528. * Gets a promise that resolves to true when the provider is ready for use.
  151529. * @memberof TileCoordinatesImageryProvider.prototype
  151530. * @type {Promise.<Boolean>}
  151531. * @readonly
  151532. */
  151533. readyPromise : {
  151534. get : function() {
  151535. return this._readyPromise;
  151536. }
  151537. },
  151538. /**
  151539. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  151540. * the source of the imagery. This function should not be called before {@link TileCoordinatesImageryProvider#ready} returns true.
  151541. * @memberof TileCoordinatesImageryProvider.prototype
  151542. * @type {Credit}
  151543. * @readonly
  151544. */
  151545. credit : {
  151546. get : function() {
  151547. return undefined;
  151548. }
  151549. },
  151550. /**
  151551. * Gets a value indicating whether or not the images provided by this imagery provider
  151552. * include an alpha channel. If this property is false, an alpha channel, if present, will
  151553. * be ignored. If this property is true, any images without an alpha channel will be treated
  151554. * as if their alpha is 1.0 everywhere. Setting this property to false reduces memory usage
  151555. * and texture upload time.
  151556. * @memberof TileCoordinatesImageryProvider.prototype
  151557. * @type {Boolean}
  151558. * @readonly
  151559. */
  151560. hasAlphaChannel : {
  151561. get : function() {
  151562. return true;
  151563. }
  151564. }
  151565. });
  151566. /**
  151567. * Gets the credits to be displayed when a given tile is displayed.
  151568. *
  151569. * @param {Number} x The tile X coordinate.
  151570. * @param {Number} y The tile Y coordinate.
  151571. * @param {Number} level The tile level;
  151572. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  151573. *
  151574. * @exception {DeveloperError} <code>getTileCredits</code> must not be called before the imagery provider is ready.
  151575. */
  151576. TileCoordinatesImageryProvider.prototype.getTileCredits = function(x, y, level) {
  151577. return undefined;
  151578. };
  151579. /**
  151580. * Requests the image for a given tile. This function should
  151581. * not be called before {@link TileCoordinatesImageryProvider#ready} returns true.
  151582. *
  151583. * @param {Number} x The tile X coordinate.
  151584. * @param {Number} y The tile Y coordinate.
  151585. * @param {Number} level The tile level.
  151586. * @returns {Promise.<Image|Canvas>|undefined} A promise for the image that will resolve when the image is available, or
  151587. * undefined if there are too many active requests to the server, and the request
  151588. * should be retried later. The resolved image may be either an
  151589. * Image or a Canvas DOM object.
  151590. */
  151591. TileCoordinatesImageryProvider.prototype.requestImage = function(x, y, level) {
  151592. var canvas = document.createElement('canvas');
  151593. canvas.width = 256;
  151594. canvas.height = 256;
  151595. var context = canvas.getContext('2d');
  151596. var cssColor = this._color.toCssColorString();
  151597. context.strokeStyle = cssColor;
  151598. context.lineWidth = 2;
  151599. context.strokeRect(1, 1, 255, 255);
  151600. var label = 'L' + level + 'X' + x + 'Y' + y;
  151601. context.font = 'bold 25px Arial';
  151602. context.textAlign = 'center';
  151603. context.fillStyle = 'black';
  151604. context.fillText(label, 127, 127);
  151605. context.fillStyle = cssColor;
  151606. context.fillText(label, 124, 124);
  151607. return canvas;
  151608. };
  151609. /**
  151610. * Picking features is not currently supported by this imagery provider, so this function simply returns
  151611. * undefined.
  151612. *
  151613. * @param {Number} x The tile X coordinate.
  151614. * @param {Number} y The tile Y coordinate.
  151615. * @param {Number} level The tile level.
  151616. * @param {Number} longitude The longitude at which to pick features.
  151617. * @param {Number} latitude The latitude at which to pick features.
  151618. * @return {Promise.<ImageryLayerFeatureInfo[]>|undefined} A promise for the picked features that will resolve when the asynchronous
  151619. * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
  151620. * instances. The array may be empty if no features are found at the given location.
  151621. * It may also be undefined if picking is not supported.
  151622. */
  151623. TileCoordinatesImageryProvider.prototype.pickFeatures = function() {
  151624. return undefined;
  151625. };
  151626. return TileCoordinatesImageryProvider;
  151627. });
  151628. /*global define*/
  151629. define('Scene/TileDiscardPolicy',[
  151630. '../Core/DeveloperError'
  151631. ], function(
  151632. DeveloperError) {
  151633. 'use strict';
  151634. /**
  151635. * A policy for discarding tile images according to some criteria. This type describes an
  151636. * interface and is not intended to be instantiated directly.
  151637. *
  151638. * @alias TileDiscardPolicy
  151639. * @constructor
  151640. *
  151641. * @see DiscardMissingTileImagePolicy
  151642. * @see NeverTileDiscardPolicy
  151643. */
  151644. function TileDiscardPolicy(options) {
  151645. DeveloperError.throwInstantiationError();
  151646. }
  151647. /**
  151648. * Determines if the discard policy is ready to process images.
  151649. * @function
  151650. *
  151651. * @returns {Boolean} True if the discard policy is ready to process images; otherwise, false.
  151652. */
  151653. TileDiscardPolicy.prototype.isReady = DeveloperError.throwInstantiationError;
  151654. /**
  151655. * Given a tile image, decide whether to discard that image.
  151656. * @function
  151657. *
  151658. * @param {Image} image An image to test.
  151659. * @returns {Boolean} True if the image should be discarded; otherwise, false.
  151660. */
  151661. TileDiscardPolicy.prototype.shouldDiscardImage = DeveloperError.throwInstantiationError;
  151662. return TileDiscardPolicy;
  151663. });
  151664. /*global define*/
  151665. define('Scene/TileState',[
  151666. '../Core/freezeObject'
  151667. ], function(
  151668. freezeObject) {
  151669. 'use strict';
  151670. /**
  151671. * @private
  151672. */
  151673. var TileState = {
  151674. START : 0,
  151675. LOADING : 1,
  151676. READY : 2,
  151677. UPSAMPLED_ONLY : 3
  151678. };
  151679. return freezeObject(TileState);
  151680. });
  151681. //This file is automatically rebuilt by the Cesium build process.
  151682. /*global define*/
  151683. define('Shaders/ViewportQuadFS',[],function() {
  151684. 'use strict';
  151685. return "varying vec2 v_textureCoordinates;\n\
  151686. void main()\n\
  151687. {\n\
  151688. czm_materialInput materialInput;\n\
  151689. materialInput.s = v_textureCoordinates.s;\n\
  151690. materialInput.st = v_textureCoordinates;\n\
  151691. materialInput.str = vec3(v_textureCoordinates, 0.0);\n\
  151692. materialInput.normalEC = vec3(0.0, 0.0, -1.0);\n\
  151693. czm_material material = czm_getMaterial(materialInput);\n\
  151694. gl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n\
  151695. }\n\
  151696. ";
  151697. });
  151698. /*global define*/
  151699. define('Scene/ViewportQuad',[
  151700. '../Core/BoundingRectangle',
  151701. '../Core/Color',
  151702. '../Core/defined',
  151703. '../Core/destroyObject',
  151704. '../Core/DeveloperError',
  151705. '../Renderer/Pass',
  151706. '../Renderer/RenderState',
  151707. '../Renderer/ShaderSource',
  151708. '../Shaders/ViewportQuadFS',
  151709. './BlendingState',
  151710. './Material'
  151711. ], function(
  151712. BoundingRectangle,
  151713. Color,
  151714. defined,
  151715. destroyObject,
  151716. DeveloperError,
  151717. Pass,
  151718. RenderState,
  151719. ShaderSource,
  151720. ViewportQuadFS,
  151721. BlendingState,
  151722. Material) {
  151723. 'use strict';
  151724. /**
  151725. * A viewport aligned quad.
  151726. *
  151727. * @alias ViewportQuad
  151728. * @constructor
  151729. *
  151730. * @param {BoundingRectangle} [rectangle] The {@link BoundingRectangle} defining the quad's position within the viewport.
  151731. * @param {Material} [material] The {@link Material} defining the surface appearance of the viewport quad.
  151732. *
  151733. * @example
  151734. * var viewportQuad = new Cesium.ViewportQuad(new Cesium.BoundingRectangle(0, 0, 80, 40));
  151735. * viewportQuad.material.uniforms.color = new Cesium.Color(1.0, 0.0, 0.0, 1.0);
  151736. */
  151737. function ViewportQuad(rectangle, material) {
  151738. /**
  151739. * Determines if the viewport quad primitive will be shown.
  151740. *
  151741. * @type {Boolean}
  151742. * @default true
  151743. */
  151744. this.show = true;
  151745. if (!defined(rectangle)) {
  151746. rectangle = new BoundingRectangle();
  151747. }
  151748. /**
  151749. * The BoundingRectangle defining the quad's position within the viewport.
  151750. *
  151751. * @type {BoundingRectangle}
  151752. *
  151753. * @example
  151754. * viewportQuad.rectangle = new Cesium.BoundingRectangle(0, 0, 80, 40);
  151755. */
  151756. this.rectangle = BoundingRectangle.clone(rectangle);
  151757. if (!defined(material)) {
  151758. material = Material.fromType(Material.ColorType, {
  151759. color : new Color(1.0, 1.0, 1.0, 1.0)
  151760. });
  151761. }
  151762. /**
  151763. * The surface appearance of the viewport quad. This can be one of several built-in {@link Material} objects or a custom material, scripted with
  151764. * {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}.
  151765. * <p>
  151766. * The default material is <code>Material.ColorType</code>.
  151767. * </p>
  151768. *
  151769. * @type Material
  151770. *
  151771. * @example
  151772. * // 1. Change the color of the default material to yellow
  151773. * viewportQuad.material.uniforms.color = new Cesium.Color(1.0, 1.0, 0.0, 1.0);
  151774. *
  151775. * // 2. Change material to horizontal stripes
  151776. * viewportQuad.material = Cesium.Material.fromType(Cesium.Material.StripeType);
  151777. *
  151778. * @see {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}
  151779. */
  151780. this.material = material;
  151781. this._material = undefined;
  151782. this._overlayCommand = undefined;
  151783. this._rs = undefined;
  151784. }
  151785. /**
  151786. * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
  151787. * get the draw commands needed to render this primitive.
  151788. * <p>
  151789. * Do not call this function directly. This is documented just to
  151790. * list the exceptions that may be propagated when the scene is rendered:
  151791. * </p>
  151792. *
  151793. * @exception {DeveloperError} this.material must be defined.
  151794. * @exception {DeveloperError} this.rectangle must be defined.
  151795. */
  151796. ViewportQuad.prototype.update = function(frameState) {
  151797. if (!this.show) {
  151798. return;
  151799. }
  151800. if (!defined(this.material)) {
  151801. throw new DeveloperError('this.material must be defined.');
  151802. }
  151803. if (!defined(this.rectangle)) {
  151804. throw new DeveloperError('this.rectangle must be defined.');
  151805. }
  151806. var rs = this._rs;
  151807. if ((!defined(rs)) || !BoundingRectangle.equals(rs.viewport, this.rectangle)) {
  151808. this._rs = RenderState.fromCache({
  151809. blending : BlendingState.ALPHA_BLEND,
  151810. viewport : this.rectangle
  151811. });
  151812. }
  151813. var pass = frameState.passes;
  151814. if (pass.render) {
  151815. var context = frameState.context;
  151816. if (this._material !== this.material || !defined(this._overlayCommand)) {
  151817. // Recompile shader when material changes
  151818. this._material = this.material;
  151819. if (defined(this._overlayCommand)) {
  151820. this._overlayCommand.shaderProgram.destroy();
  151821. }
  151822. var fs = new ShaderSource({
  151823. sources : [this._material.shaderSource, ViewportQuadFS]
  151824. });
  151825. this._overlayCommand = context.createViewportQuadCommand(fs, {
  151826. renderState : this._rs,
  151827. uniformMap : this._material._uniforms,
  151828. owner : this
  151829. });
  151830. this._overlayCommand.pass = Pass.OVERLAY;
  151831. }
  151832. this._material.update(context);
  151833. this._overlayCommand.uniformMap = this._material._uniforms;
  151834. frameState.commandList.push(this._overlayCommand);
  151835. }
  151836. };
  151837. /**
  151838. * Returns true if this object was destroyed; otherwise, false.
  151839. * <br /><br />
  151840. * If this object was destroyed, it should not be used; calling any function other than
  151841. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  151842. *
  151843. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  151844. *
  151845. * @see ViewportQuad#destroy
  151846. */
  151847. ViewportQuad.prototype.isDestroyed = function() {
  151848. return false;
  151849. };
  151850. /**
  151851. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  151852. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  151853. * <br /><br />
  151854. * Once an object is destroyed, it should not be used; calling any function other than
  151855. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  151856. * assign the return value (<code>undefined</code>) to the object as done in the example.
  151857. *
  151858. * @returns {undefined}
  151859. *
  151860. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  151861. *
  151862. *
  151863. * @example
  151864. * quad = quad && quad.destroy();
  151865. *
  151866. * @see ViewportQuad#isDestroyed
  151867. */
  151868. ViewportQuad.prototype.destroy = function() {
  151869. if (defined(this._overlayCommand)) {
  151870. this._overlayCommand.shaderProgram = this._overlayCommand.shaderProgram && this._overlayCommand.shaderProgram.destroy();
  151871. }
  151872. return destroyObject(this);
  151873. };
  151874. return ViewportQuad;
  151875. });
  151876. /*global define*/
  151877. define('Scene/WebMapServiceImageryProvider',[
  151878. '../Core/combine',
  151879. '../Core/defaultValue',
  151880. '../Core/defined',
  151881. '../Core/defineProperties',
  151882. '../Core/DeveloperError',
  151883. '../Core/freezeObject',
  151884. '../Core/GeographicTilingScheme',
  151885. '../Core/objectToQuery',
  151886. '../Core/queryToObject',
  151887. '../Core/WebMercatorTilingScheme',
  151888. '../ThirdParty/Uri',
  151889. './GetFeatureInfoFormat',
  151890. './UrlTemplateImageryProvider'
  151891. ], function(
  151892. combine,
  151893. defaultValue,
  151894. defined,
  151895. defineProperties,
  151896. DeveloperError,
  151897. freezeObject,
  151898. GeographicTilingScheme,
  151899. objectToQuery,
  151900. queryToObject,
  151901. WebMercatorTilingScheme,
  151902. Uri,
  151903. GetFeatureInfoFormat,
  151904. UrlTemplateImageryProvider) {
  151905. 'use strict';
  151906. /**
  151907. * Provides tiled imagery hosted by a Web Map Service (WMS) server.
  151908. *
  151909. * @alias WebMapServiceImageryProvider
  151910. * @constructor
  151911. *
  151912. * @param {Object} options Object with the following properties:
  151913. * @param {String} options.url The URL of the WMS service. The URL supports the same keywords as the {@link UrlTemplateImageryProvider}.
  151914. * @param {String} options.layers The layers to include, separated by commas.
  151915. * @param {Object} [options.parameters=WebMapServiceImageryProvider.DefaultParameters] Additional parameters
  151916. * to pass to the WMS server in the GetMap URL.
  151917. * @param {Object} [options.getFeatureInfoParameters=WebMapServiceImageryProvider.GetFeatureInfoDefaultParameters] Additional
  151918. * parameters to pass to the WMS server in the GetFeatureInfo URL.
  151919. * @param {Boolean} [options.enablePickFeatures=true] If true, {@link WebMapServiceImageryProvider#pickFeatures} will invoke
  151920. * the GetFeatureInfo operation on the WMS server and return the features included in the response. If false,
  151921. * {@link WebMapServiceImageryProvider#pickFeatures} will immediately return undefined (indicating no pickable features)
  151922. * without communicating with the server. Set this property to false if you know your WMS server does not support
  151923. * GetFeatureInfo or if you don't want this provider's features to be pickable. Note that this can be dynamically
  151924. * overridden by modifying the WebMapServiceImageryProvider#enablePickFeatures property.
  151925. * @param {GetFeatureInfoFormat[]} [options.getFeatureInfoFormats=WebMapServiceImageryProvider.DefaultGetFeatureInfoFormats] The formats
  151926. * in which to try WMS GetFeatureInfo requests.
  151927. * @param {Rectangle} [options.rectangle=Rectangle.MAX_VALUE] The rectangle of the layer.
  151928. * @param {TilingScheme} [options.tilingScheme=new GeographicTilingScheme()] The tiling scheme to use to divide the world into tiles.
  151929. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If the tilingScheme is specified,
  151930. * this parameter is ignored and the tiling scheme's ellipsoid is used instead. If neither
  151931. * parameter is specified, the WGS84 ellipsoid is used.
  151932. * @param {Number} [options.tileWidth=256] The width of each tile in pixels.
  151933. * @param {Number} [options.tileHeight=256] The height of each tile in pixels.
  151934. * @param {Number} [options.minimumLevel=0] The minimum level-of-detail supported by the imagery provider. Take care when
  151935. * specifying this that the number of tiles at the minimum level is small, such as four or less. A larger number is
  151936. * likely to result in rendering problems.
  151937. * @param {Number} [options.maximumLevel] The maximum level-of-detail supported by the imagery provider, or undefined if there is no limit.
  151938. * If not specified, there is no limit.
  151939. * @param {Credit|String} [options.credit] A credit for the data source, which is displayed on the canvas.
  151940. * @param {Object} [options.proxy] A proxy to use for requests. This object is
  151941. * expected to have a getURL function which returns the proxied URL, if needed.
  151942. * @param {String|String[]} [options.subdomains='abc'] The subdomains to use for the <code>{s}</code> placeholder in the URL template.
  151943. * If this parameter is a single string, each character in the string is a subdomain. If it is
  151944. * an array, each element in the array is a subdomain.
  151945. *
  151946. * @see ArcGisMapServerImageryProvider
  151947. * @see BingMapsImageryProvider
  151948. * @see GoogleEarthImageryProvider
  151949. * @see createOpenStreetMapImageryProvider
  151950. * @see SingleTileImageryProvider
  151951. * @see createTileMapServiceImageryProvider
  151952. * @see WebMapTileServiceImageryProvider
  151953. * @see UrlTemplateImageryProvider
  151954. *
  151955. * @see {@link http://resources.esri.com/help/9.3/arcgisserver/apis/rest/|ArcGIS Server REST API}
  151956. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  151957. *
  151958. * @example
  151959. * var provider = new Cesium.WebMapServiceImageryProvider({
  151960. * url : 'https://sampleserver1.arcgisonline.com/ArcGIS/services/Specialty/ESRI_StatesCitiesRivers_USA/MapServer/WMSServer',
  151961. * layers : '0',
  151962. * proxy: new Cesium.DefaultProxy('/proxy/')
  151963. * });
  151964. *
  151965. * viewer.imageryLayers.addImageryProvider(provider);
  151966. */
  151967. function WebMapServiceImageryProvider(options) {
  151968. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  151969. if (!defined(options.url)) {
  151970. throw new DeveloperError('options.url is required.');
  151971. }
  151972. if (!defined(options.layers)) {
  151973. throw new DeveloperError('options.layers is required.');
  151974. }
  151975. this._url = options.url;
  151976. this._layers = options.layers;
  151977. var getFeatureInfoFormats = defaultValue(options.getFeatureInfoFormats, WebMapServiceImageryProvider.DefaultGetFeatureInfoFormats);
  151978. // Build the template URLs for tiles and pickFeatures.
  151979. var uri = new Uri(options.url);
  151980. var queryOptions = queryToObject(defaultValue(uri.query, ''));
  151981. var parameters = combine(objectToLowercase(defaultValue(options.parameters, defaultValue.EMPTY_OBJECT)), WebMapServiceImageryProvider.DefaultParameters);
  151982. queryOptions = combine(parameters, queryOptions);
  151983. var pickFeaturesUri;
  151984. var pickFeaturesQueryOptions;
  151985. pickFeaturesUri = new Uri(options.url);
  151986. pickFeaturesQueryOptions = queryToObject(defaultValue(pickFeaturesUri.query, ''));
  151987. var pickFeaturesParameters = combine(objectToLowercase(defaultValue(options.getFeatureInfoParameters, defaultValue.EMPTY_OBJECT)), WebMapServiceImageryProvider.GetFeatureInfoDefaultParameters);
  151988. pickFeaturesQueryOptions = combine(pickFeaturesParameters, pickFeaturesQueryOptions);
  151989. function setParameter(name, value) {
  151990. if (!defined(queryOptions[name])) {
  151991. queryOptions[name] = value;
  151992. }
  151993. if (defined(pickFeaturesQueryOptions) && !defined(pickFeaturesQueryOptions[name])) {
  151994. pickFeaturesQueryOptions[name] = value;
  151995. }
  151996. }
  151997. setParameter('layers', options.layers);
  151998. setParameter('srs', options.tilingScheme instanceof WebMercatorTilingScheme ? 'EPSG:3857' : 'EPSG:4326');
  151999. setParameter('bbox', '{westProjected},{southProjected},{eastProjected},{northProjected}');
  152000. setParameter('width', '{width}');
  152001. setParameter('height', '{height}');
  152002. uri.query = objectToQuery(queryOptions);
  152003. // objectToQuery escapes the placeholders. Undo that.
  152004. var templateUrl = uri.toString().replace(/%7B/g, '{').replace(/%7D/g, '}');
  152005. var pickFeaturesTemplateUrl;
  152006. if (defined(pickFeaturesQueryOptions)) {
  152007. if (!defined(pickFeaturesQueryOptions.query_layers)) {
  152008. pickFeaturesQueryOptions.query_layers = options.layers;
  152009. }
  152010. if (!defined(pickFeaturesQueryOptions.x)) {
  152011. pickFeaturesQueryOptions.x = '{i}';
  152012. }
  152013. if (!defined(pickFeaturesQueryOptions.y)) {
  152014. pickFeaturesQueryOptions.y = '{j}';
  152015. }
  152016. if (!defined(pickFeaturesQueryOptions.info_format)) {
  152017. pickFeaturesQueryOptions.info_format = '{format}';
  152018. }
  152019. pickFeaturesUri.query = objectToQuery(pickFeaturesQueryOptions);
  152020. pickFeaturesTemplateUrl = pickFeaturesUri.toString().replace(/%7B/g, '{').replace(/%7D/g, '}');
  152021. }
  152022. // Let UrlTemplateImageryProvider do the actual URL building.
  152023. this._tileProvider = new UrlTemplateImageryProvider({
  152024. url : templateUrl,
  152025. pickFeaturesUrl : pickFeaturesTemplateUrl,
  152026. tilingScheme : defaultValue(options.tilingScheme, new GeographicTilingScheme({ ellipsoid : options.ellipsoid})),
  152027. rectangle : options.rectangle,
  152028. tileWidth : options.tileWidth,
  152029. tileHeight : options.tileHeight,
  152030. minimumLevel : options.minimumLevel,
  152031. maximumLevel : options.maximumLevel,
  152032. proxy : options.proxy,
  152033. subdomains: options.subdomains,
  152034. tileDiscardPolicy : options.tileDiscardPolicy,
  152035. credit : options.credit,
  152036. getFeatureInfoFormats : getFeatureInfoFormats,
  152037. enablePickFeatures: options.enablePickFeatures
  152038. });
  152039. }
  152040. defineProperties(WebMapServiceImageryProvider.prototype, {
  152041. /**
  152042. * Gets the URL of the WMS server.
  152043. * @memberof WebMapServiceImageryProvider.prototype
  152044. * @type {String}
  152045. * @readonly
  152046. */
  152047. url : {
  152048. get : function() {
  152049. return this._url;
  152050. }
  152051. },
  152052. /**
  152053. * Gets the proxy used by this provider.
  152054. * @memberof WebMapServiceImageryProvider.prototype
  152055. * @type {Proxy}
  152056. * @readonly
  152057. */
  152058. proxy : {
  152059. get : function() {
  152060. return this._tileProvider.proxy;
  152061. }
  152062. },
  152063. /**
  152064. * Gets the names of the WMS layers, separated by commas.
  152065. * @memberof WebMapServiceImageryProvider.prototype
  152066. * @type {String}
  152067. * @readonly
  152068. */
  152069. layers : {
  152070. get : function() {
  152071. return this._layers;
  152072. }
  152073. },
  152074. /**
  152075. * Gets the width of each tile, in pixels. This function should
  152076. * not be called before {@link WebMapServiceImageryProvider#ready} returns true.
  152077. * @memberof WebMapServiceImageryProvider.prototype
  152078. * @type {Number}
  152079. * @readonly
  152080. */
  152081. tileWidth : {
  152082. get : function() {
  152083. return this._tileProvider.tileWidth;
  152084. }
  152085. },
  152086. /**
  152087. * Gets the height of each tile, in pixels. This function should
  152088. * not be called before {@link WebMapServiceImageryProvider#ready} returns true.
  152089. * @memberof WebMapServiceImageryProvider.prototype
  152090. * @type {Number}
  152091. * @readonly
  152092. */
  152093. tileHeight : {
  152094. get : function() {
  152095. return this._tileProvider.tileHeight;
  152096. }
  152097. },
  152098. /**
  152099. * Gets the maximum level-of-detail that can be requested. This function should
  152100. * not be called before {@link WebMapServiceImageryProvider#ready} returns true.
  152101. * @memberof WebMapServiceImageryProvider.prototype
  152102. * @type {Number}
  152103. * @readonly
  152104. */
  152105. maximumLevel : {
  152106. get : function() {
  152107. return this._tileProvider.maximumLevel;
  152108. }
  152109. },
  152110. /**
  152111. * Gets the minimum level-of-detail that can be requested. This function should
  152112. * not be called before {@link WebMapServiceImageryProvider#ready} returns true.
  152113. * @memberof WebMapServiceImageryProvider.prototype
  152114. * @type {Number}
  152115. * @readonly
  152116. */
  152117. minimumLevel : {
  152118. get : function() {
  152119. return this._tileProvider.minimumLevel;
  152120. }
  152121. },
  152122. /**
  152123. * Gets the tiling scheme used by this provider. This function should
  152124. * not be called before {@link WebMapServiceImageryProvider#ready} returns true.
  152125. * @memberof WebMapServiceImageryProvider.prototype
  152126. * @type {TilingScheme}
  152127. * @readonly
  152128. */
  152129. tilingScheme : {
  152130. get : function() {
  152131. return this._tileProvider.tilingScheme;
  152132. }
  152133. },
  152134. /**
  152135. * Gets the rectangle, in radians, of the imagery provided by this instance. This function should
  152136. * not be called before {@link WebMapServiceImageryProvider#ready} returns true.
  152137. * @memberof WebMapServiceImageryProvider.prototype
  152138. * @type {Rectangle}
  152139. * @readonly
  152140. */
  152141. rectangle : {
  152142. get : function() {
  152143. return this._tileProvider.rectangle;
  152144. }
  152145. },
  152146. /**
  152147. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  152148. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  152149. * returns undefined, no tiles are filtered. This function should
  152150. * not be called before {@link WebMapServiceImageryProvider#ready} returns true.
  152151. * @memberof WebMapServiceImageryProvider.prototype
  152152. * @type {TileDiscardPolicy}
  152153. * @readonly
  152154. */
  152155. tileDiscardPolicy : {
  152156. get : function() {
  152157. return this._tileProvider.tileDiscardPolicy;
  152158. }
  152159. },
  152160. /**
  152161. * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
  152162. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  152163. * are passed an instance of {@link TileProviderError}.
  152164. * @memberof WebMapServiceImageryProvider.prototype
  152165. * @type {Event}
  152166. * @readonly
  152167. */
  152168. errorEvent : {
  152169. get : function() {
  152170. return this._tileProvider.errorEvent;
  152171. }
  152172. },
  152173. /**
  152174. * Gets a value indicating whether or not the provider is ready for use.
  152175. * @memberof WebMapServiceImageryProvider.prototype
  152176. * @type {Boolean}
  152177. * @readonly
  152178. */
  152179. ready : {
  152180. get : function() {
  152181. return this._tileProvider.ready;
  152182. }
  152183. },
  152184. /**
  152185. * Gets a promise that resolves to true when the provider is ready for use.
  152186. * @memberof WebMapServiceImageryProvider.prototype
  152187. * @type {Promise.<Boolean>}
  152188. * @readonly
  152189. */
  152190. readyPromise : {
  152191. get : function() {
  152192. return this._tileProvider.readyPromise;
  152193. }
  152194. },
  152195. /**
  152196. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  152197. * the source of the imagery. This function should not be called before {@link WebMapServiceImageryProvider#ready} returns true.
  152198. * @memberof WebMapServiceImageryProvider.prototype
  152199. * @type {Credit}
  152200. * @readonly
  152201. */
  152202. credit : {
  152203. get : function() {
  152204. return this._tileProvider.credit;
  152205. }
  152206. },
  152207. /**
  152208. * Gets a value indicating whether or not the images provided by this imagery provider
  152209. * include an alpha channel. If this property is false, an alpha channel, if present, will
  152210. * be ignored. If this property is true, any images without an alpha channel will be treated
  152211. * as if their alpha is 1.0 everywhere. When this property is false, memory usage
  152212. * and texture upload time are reduced.
  152213. * @memberof WebMapServiceImageryProvider.prototype
  152214. * @type {Boolean}
  152215. * @readonly
  152216. */
  152217. hasAlphaChannel : {
  152218. get : function() {
  152219. return this._tileProvider.hasAlphaChannel;
  152220. }
  152221. },
  152222. /**
  152223. * Gets or sets a value indicating whether feature picking is enabled. If true, {@link WebMapServiceImageryProvider#pickFeatures} will
  152224. * invoke the <code>GetFeatureInfo</code> service on the WMS server and attempt to interpret the features included in the response. If false,
  152225. * {@link WebMapServiceImageryProvider#pickFeatures} will immediately return undefined (indicating no pickable
  152226. * features) without communicating with the server. Set this property to false if you know your data
  152227. * source does not support picking features or if you don't want this provider's features to be pickable.
  152228. * @memberof WebMapServiceImageryProvider.prototype
  152229. * @type {Boolean}
  152230. * @default true
  152231. */
  152232. enablePickFeatures : {
  152233. get : function() {
  152234. return this._tileProvider.enablePickFeatures;
  152235. },
  152236. set : function(enablePickFeatures) {
  152237. this._tileProvider.enablePickFeatures = enablePickFeatures;
  152238. }
  152239. }
  152240. });
  152241. /**
  152242. * Gets the credits to be displayed when a given tile is displayed.
  152243. *
  152244. * @param {Number} x The tile X coordinate.
  152245. * @param {Number} y The tile Y coordinate.
  152246. * @param {Number} level The tile level;
  152247. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  152248. *
  152249. * @exception {DeveloperError} <code>getTileCredits</code> must not be called before the imagery provider is ready.
  152250. */
  152251. WebMapServiceImageryProvider.prototype.getTileCredits = function(x, y, level) {
  152252. return this._tileProvider.getTileCredits(x, y, level);
  152253. };
  152254. /**
  152255. * Requests the image for a given tile. This function should
  152256. * not be called before {@link WebMapServiceImageryProvider#ready} returns true.
  152257. *
  152258. * @param {Number} x The tile X coordinate.
  152259. * @param {Number} y The tile Y coordinate.
  152260. * @param {Number} level The tile level.
  152261. * @returns {Promise.<Image|Canvas>|undefined} A promise for the image that will resolve when the image is available, or
  152262. * undefined if there are too many active requests to the server, and the request
  152263. * should be retried later. The resolved image may be either an
  152264. * Image or a Canvas DOM object.
  152265. *
  152266. * @exception {DeveloperError} <code>requestImage</code> must not be called before the imagery provider is ready.
  152267. */
  152268. WebMapServiceImageryProvider.prototype.requestImage = function(x, y, level) {
  152269. return this._tileProvider.requestImage(x, y, level);
  152270. };
  152271. /**
  152272. * Asynchronously determines what features, if any, are located at a given longitude and latitude within
  152273. * a tile. This function should not be called before {@link ImageryProvider#ready} returns true.
  152274. *
  152275. * @param {Number} x The tile X coordinate.
  152276. * @param {Number} y The tile Y coordinate.
  152277. * @param {Number} level The tile level.
  152278. * @param {Number} longitude The longitude at which to pick features.
  152279. * @param {Number} latitude The latitude at which to pick features.
  152280. * @return {Promise.<ImageryLayerFeatureInfo[]>|undefined} A promise for the picked features that will resolve when the asynchronous
  152281. * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
  152282. * instances. The array may be empty if no features are found at the given location.
  152283. *
  152284. * @exception {DeveloperError} <code>pickFeatures</code> must not be called before the imagery provider is ready.
  152285. */
  152286. WebMapServiceImageryProvider.prototype.pickFeatures = function(x, y, level, longitude, latitude) {
  152287. return this._tileProvider.pickFeatures(x, y, level, longitude, latitude);
  152288. };
  152289. /**
  152290. * The default parameters to include in the WMS URL to obtain images. The values are as follows:
  152291. * service=WMS
  152292. * version=1.1.1
  152293. * request=GetMap
  152294. * styles=
  152295. * format=image/jpeg
  152296. *
  152297. * @constant
  152298. */
  152299. WebMapServiceImageryProvider.DefaultParameters = freezeObject({
  152300. service : 'WMS',
  152301. version : '1.1.1',
  152302. request : 'GetMap',
  152303. styles : '',
  152304. format : 'image/jpeg'
  152305. });
  152306. /**
  152307. * The default parameters to include in the WMS URL to get feature information. The values are as follows:
  152308. * service=WMS
  152309. * version=1.1.1
  152310. * request=GetFeatureInfo
  152311. *
  152312. * @constant
  152313. */
  152314. WebMapServiceImageryProvider.GetFeatureInfoDefaultParameters = freezeObject({
  152315. service : 'WMS',
  152316. version : '1.1.1',
  152317. request : 'GetFeatureInfo'
  152318. });
  152319. WebMapServiceImageryProvider.DefaultGetFeatureInfoFormats = freezeObject([
  152320. freezeObject(new GetFeatureInfoFormat('json', 'application/json')),
  152321. freezeObject(new GetFeatureInfoFormat('xml', 'text/xml')),
  152322. freezeObject(new GetFeatureInfoFormat('text', 'text/html'))
  152323. ]);
  152324. function objectToLowercase(obj) {
  152325. var result = {};
  152326. for ( var key in obj) {
  152327. if (obj.hasOwnProperty(key)) {
  152328. result[key.toLowerCase()] = obj[key];
  152329. }
  152330. }
  152331. return result;
  152332. }
  152333. return WebMapServiceImageryProvider;
  152334. });
  152335. /*global define*/
  152336. define('Scene/WebMapTileServiceImageryProvider',[
  152337. '../Core/combine',
  152338. '../Core/Credit',
  152339. '../Core/defaultValue',
  152340. '../Core/defined',
  152341. '../Core/defineProperties',
  152342. '../Core/DeveloperError',
  152343. '../Core/Event',
  152344. '../Core/freezeObject',
  152345. '../Core/isArray',
  152346. '../Core/objectToQuery',
  152347. '../Core/queryToObject',
  152348. '../Core/Rectangle',
  152349. '../Core/WebMercatorTilingScheme',
  152350. '../ThirdParty/Uri',
  152351. '../ThirdParty/when',
  152352. './ImageryProvider'
  152353. ], function(
  152354. combine,
  152355. Credit,
  152356. defaultValue,
  152357. defined,
  152358. defineProperties,
  152359. DeveloperError,
  152360. Event,
  152361. freezeObject,
  152362. isArray,
  152363. objectToQuery,
  152364. queryToObject,
  152365. Rectangle,
  152366. WebMercatorTilingScheme,
  152367. Uri,
  152368. when,
  152369. ImageryProvider) {
  152370. 'use strict';
  152371. /**
  152372. * Provides tiled imagery served by {@link http://www.opengeospatial.org/standards/wmts|WMTS 1.0.0} compliant servers.
  152373. * This provider supports HTTP KVP-encoded and RESTful GetTile requests, but does not yet support the SOAP encoding.
  152374. *
  152375. * @alias WebMapTileServiceImageryProvider
  152376. * @constructor
  152377. *
  152378. * @param {Object} options Object with the following properties:
  152379. * @param {String} options.url The base URL for the WMTS GetTile operation (for KVP-encoded requests) or the tile-URL template (for RESTful requests). The tile-URL template should contain the following variables: &#123;style&#125;, &#123;TileMatrixSet&#125;, &#123;TileMatrix&#125;, &#123;TileRow&#125;, &#123;TileCol&#125;. The first two are optional if actual values are hardcoded or not required by the server. The &#123;s&#125; keyword may be used to specify subdomains.
  152380. * @param {String} [options.format='image/jpeg'] The MIME type for images to retrieve from the server.
  152381. * @param {String} options.layer The layer name for WMTS requests.
  152382. * @param {String} options.style The style name for WMTS requests.
  152383. * @param {String} options.tileMatrixSetID The identifier of the TileMatrixSet to use for WMTS requests.
  152384. * @param {Array} [options.tileMatrixLabels] A list of identifiers in the TileMatrix to use for WMTS requests, one per TileMatrix level.
  152385. * @param {Number} [options.tileWidth=256] The tile width in pixels.
  152386. * @param {Number} [options.tileHeight=256] The tile height in pixels.
  152387. * @param {TilingScheme} [options.tilingScheme] The tiling scheme corresponding to the organization of the tiles in the TileMatrixSet.
  152388. * @param {Object} [options.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL.
  152389. * @param {Rectangle} [options.rectangle=Rectangle.MAX_VALUE] The rectangle covered by the layer.
  152390. * @param {Number} [options.minimumLevel=0] The minimum level-of-detail supported by the imagery provider.
  152391. * @param {Number} [options.maximumLevel] The maximum level-of-detail supported by the imagery provider, or undefined if there is no limit.
  152392. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If not specified, the WGS84 ellipsoid is used.
  152393. * @param {Credit|String} [options.credit] A credit for the data source, which is displayed on the canvas.
  152394. * @param {String|String[]} [options.subdomains='abc'] The subdomains to use for the <code>{s}</code> placeholder in the URL template.
  152395. * If this parameter is a single string, each character in the string is a subdomain. If it is
  152396. * an array, each element in the array is a subdomain.
  152397. *
  152398. *
  152399. * @example
  152400. * // Example 1. USGS shaded relief tiles (KVP)
  152401. * var shadedRelief1 = new Cesium.WebMapTileServiceImageryProvider({
  152402. * url : 'http://basemap.nationalmap.gov/arcgis/rest/services/USGSShadedReliefOnly/MapServer/WMTS',
  152403. * layer : 'USGSShadedReliefOnly',
  152404. * style : 'default',
  152405. * format : 'image/jpeg',
  152406. * tileMatrixSetID : 'default028mm',
  152407. * // tileMatrixLabels : ['default028mm:0', 'default028mm:1', 'default028mm:2' ...],
  152408. * maximumLevel: 19,
  152409. * credit : new Cesium.Credit('U. S. Geological Survey')
  152410. * });
  152411. * viewer.imageryLayers.addImageryProvider(shadedRelief1);
  152412. *
  152413. * @example
  152414. * // Example 2. USGS shaded relief tiles (RESTful)
  152415. * var shadedRelief2 = new Cesium.WebMapTileServiceImageryProvider({
  152416. * url : 'http://basemap.nationalmap.gov/arcgis/rest/services/USGSShadedReliefOnly/MapServer/WMTS/tile/1.0.0/USGSShadedReliefOnly/{Style}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.jpg',
  152417. * layer : 'USGSShadedReliefOnly',
  152418. * style : 'default',
  152419. * format : 'image/jpeg',
  152420. * tileMatrixSetID : 'default028mm',
  152421. * maximumLevel: 19,
  152422. * credit : new Cesium.Credit('U. S. Geological Survey')
  152423. * });
  152424. * viewer.imageryLayers.addImageryProvider(shadedRelief2);
  152425. *
  152426. * @see ArcGisMapServerImageryProvider
  152427. * @see BingMapsImageryProvider
  152428. * @see GoogleEarthImageryProvider
  152429. * @see createOpenStreetMapImageryProvider
  152430. * @see SingleTileImageryProvider
  152431. * @see createTileMapServiceImageryProvider
  152432. * @see WebMapServiceImageryProvider
  152433. * @see UrlTemplateImageryProvider
  152434. */
  152435. function WebMapTileServiceImageryProvider(options) {
  152436. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  152437. if (!defined(options.url)) {
  152438. throw new DeveloperError('options.url is required.');
  152439. }
  152440. if (!defined(options.layer)) {
  152441. throw new DeveloperError('options.layer is required.');
  152442. }
  152443. if (!defined(options.style)) {
  152444. throw new DeveloperError('options.style is required.');
  152445. }
  152446. if (!defined(options.tileMatrixSetID)) {
  152447. throw new DeveloperError('options.tileMatrixSetID is required.');
  152448. }
  152449. this._url = options.url;
  152450. this._layer = options.layer;
  152451. this._style = options.style;
  152452. this._tileMatrixSetID = options.tileMatrixSetID;
  152453. this._tileMatrixLabels = options.tileMatrixLabels;
  152454. this._format = defaultValue(options.format, 'image/jpeg');
  152455. this._proxy = options.proxy;
  152456. this._tileDiscardPolicy = options.tileDiscardPolicy;
  152457. this._tilingScheme = defined(options.tilingScheme) ? options.tilingScheme : new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid });
  152458. this._tileWidth = defaultValue(options.tileWidth, 256);
  152459. this._tileHeight = defaultValue(options.tileHeight, 256);
  152460. this._minimumLevel = defaultValue(options.minimumLevel, 0);
  152461. this._maximumLevel = options.maximumLevel;
  152462. this._rectangle = defaultValue(options.rectangle, this._tilingScheme.rectangle);
  152463. this._readyPromise = when.resolve(true);
  152464. // Check the number of tiles at the minimum level. If it's more than four,
  152465. // throw an exception, because starting at the higher minimum
  152466. // level will cause too many tiles to be downloaded and rendered.
  152467. var swTile = this._tilingScheme.positionToTileXY(Rectangle.southwest(this._rectangle), this._minimumLevel);
  152468. var neTile = this._tilingScheme.positionToTileXY(Rectangle.northeast(this._rectangle), this._minimumLevel);
  152469. var tileCount = (Math.abs(neTile.x - swTile.x) + 1) * (Math.abs(neTile.y - swTile.y) + 1);
  152470. if (tileCount > 4) {
  152471. throw new DeveloperError('The imagery provider\'s rectangle and minimumLevel indicate that there are ' + tileCount + ' tiles at the minimum level. Imagery providers with more than four tiles at the minimum level are not supported.');
  152472. }
  152473. this._errorEvent = new Event();
  152474. var credit = options.credit;
  152475. this._credit = typeof credit === 'string' ? new Credit(credit) : credit;
  152476. this._subdomains = options.subdomains;
  152477. if (isArray(this._subdomains)) {
  152478. this._subdomains = this._subdomains.slice();
  152479. } else if (defined(this._subdomains) && this._subdomains.length > 0) {
  152480. this._subdomains = this._subdomains.split('');
  152481. } else {
  152482. this._subdomains = ['a', 'b', 'c'];
  152483. }
  152484. }
  152485. var defaultParameters = freezeObject({
  152486. service : 'WMTS',
  152487. version : '1.0.0',
  152488. request : 'GetTile'
  152489. });
  152490. function buildImageUrl(imageryProvider, col, row, level) {
  152491. var labels = imageryProvider._tileMatrixLabels;
  152492. var tileMatrix = defined(labels) ? labels[level] : level.toString();
  152493. var subdomains = imageryProvider._subdomains;
  152494. var url;
  152495. if (imageryProvider._url.indexOf('{') >= 0) {
  152496. // resolve tile-URL template
  152497. url = imageryProvider._url
  152498. .replace('{style}', imageryProvider._style)
  152499. .replace('{Style}', imageryProvider._style)
  152500. .replace('{TileMatrixSet}', imageryProvider._tileMatrixSetID)
  152501. .replace('{TileMatrix}', tileMatrix)
  152502. .replace('{TileRow}', row.toString())
  152503. .replace('{TileCol}', col.toString())
  152504. .replace('{s}', subdomains[(col + row + level) % subdomains.length]);
  152505. }
  152506. else {
  152507. // build KVP request
  152508. var uri = new Uri(imageryProvider._url);
  152509. var queryOptions = queryToObject(defaultValue(uri.query, ''));
  152510. queryOptions = combine(defaultParameters, queryOptions);
  152511. queryOptions.tilematrix = tileMatrix;
  152512. queryOptions.layer = imageryProvider._layer;
  152513. queryOptions.style = imageryProvider._style;
  152514. queryOptions.tilerow = row;
  152515. queryOptions.tilecol = col;
  152516. queryOptions.tilematrixset = imageryProvider._tileMatrixSetID;
  152517. queryOptions.format = imageryProvider._format;
  152518. uri.query = objectToQuery(queryOptions);
  152519. url = uri.toString();
  152520. }
  152521. var proxy = imageryProvider._proxy;
  152522. if (defined(proxy)) {
  152523. url = proxy.getURL(url);
  152524. }
  152525. return url;
  152526. }
  152527. defineProperties(WebMapTileServiceImageryProvider.prototype, {
  152528. /**
  152529. * Gets the URL of the service hosting the imagery.
  152530. * @memberof WebMapTileServiceImageryProvider.prototype
  152531. * @type {String}
  152532. * @readonly
  152533. */
  152534. url : {
  152535. get : function() {
  152536. return this._url;
  152537. }
  152538. },
  152539. /**
  152540. * Gets the proxy used by this provider.
  152541. * @memberof WebMapTileServiceImageryProvider.prototype
  152542. * @type {Proxy}
  152543. * @readonly
  152544. */
  152545. proxy : {
  152546. get : function() {
  152547. return this._proxy;
  152548. }
  152549. },
  152550. /**
  152551. * Gets the width of each tile, in pixels. This function should
  152552. * not be called before {@link WebMapTileServiceImageryProvider#ready} returns true.
  152553. * @memberof WebMapTileServiceImageryProvider.prototype
  152554. * @type {Number}
  152555. * @readonly
  152556. */
  152557. tileWidth : {
  152558. get : function() {
  152559. return this._tileWidth;
  152560. }
  152561. },
  152562. /**
  152563. * Gets the height of each tile, in pixels. This function should
  152564. * not be called before {@link WebMapTileServiceImageryProvider#ready} returns true.
  152565. * @memberof WebMapTileServiceImageryProvider.prototype
  152566. * @type {Number}
  152567. * @readonly
  152568. */
  152569. tileHeight : {
  152570. get : function() {
  152571. return this._tileHeight;
  152572. }
  152573. },
  152574. /**
  152575. * Gets the maximum level-of-detail that can be requested. This function should
  152576. * not be called before {@link WebMapTileServiceImageryProvider#ready} returns true.
  152577. * @memberof WebMapTileServiceImageryProvider.prototype
  152578. * @type {Number}
  152579. * @readonly
  152580. */
  152581. maximumLevel : {
  152582. get : function() {
  152583. return this._maximumLevel;
  152584. }
  152585. },
  152586. /**
  152587. * Gets the minimum level-of-detail that can be requested. This function should
  152588. * not be called before {@link WebMapTileServiceImageryProvider#ready} returns true.
  152589. * @memberof WebMapTileServiceImageryProvider.prototype
  152590. * @type {Number}
  152591. * @readonly
  152592. */
  152593. minimumLevel : {
  152594. get : function() {
  152595. return this._minimumLevel;
  152596. }
  152597. },
  152598. /**
  152599. * Gets the tiling scheme used by this provider. This function should
  152600. * not be called before {@link WebMapTileServiceImageryProvider#ready} returns true.
  152601. * @memberof WebMapTileServiceImageryProvider.prototype
  152602. * @type {TilingScheme}
  152603. * @readonly
  152604. */
  152605. tilingScheme : {
  152606. get : function() {
  152607. return this._tilingScheme;
  152608. }
  152609. },
  152610. /**
  152611. * Gets the rectangle, in radians, of the imagery provided by this instance. This function should
  152612. * not be called before {@link WebMapTileServiceImageryProvider#ready} returns true.
  152613. * @memberof WebMapTileServiceImageryProvider.prototype
  152614. * @type {Rectangle}
  152615. * @readonly
  152616. */
  152617. rectangle : {
  152618. get : function() {
  152619. return this._rectangle;
  152620. }
  152621. },
  152622. /**
  152623. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  152624. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  152625. * returns undefined, no tiles are filtered. This function should
  152626. * not be called before {@link WebMapTileServiceImageryProvider#ready} returns true.
  152627. * @memberof WebMapTileServiceImageryProvider.prototype
  152628. * @type {TileDiscardPolicy}
  152629. * @readonly
  152630. */
  152631. tileDiscardPolicy : {
  152632. get : function() {
  152633. return this._tileDiscardPolicy;
  152634. }
  152635. },
  152636. /**
  152637. * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
  152638. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  152639. * are passed an instance of {@link TileProviderError}.
  152640. * @memberof WebMapTileServiceImageryProvider.prototype
  152641. * @type {Event}
  152642. * @readonly
  152643. */
  152644. errorEvent : {
  152645. get : function() {
  152646. return this._errorEvent;
  152647. }
  152648. },
  152649. /**
  152650. * Gets the mime type of images returned by this imagery provider.
  152651. * @memberof WebMapTileServiceImageryProvider.prototype
  152652. * @type {String}
  152653. * @readonly
  152654. */
  152655. format : {
  152656. get : function() {
  152657. return this._format;
  152658. }
  152659. },
  152660. /**
  152661. * Gets a value indicating whether or not the provider is ready for use.
  152662. * @memberof WebMapTileServiceImageryProvider.prototype
  152663. * @type {Boolean}
  152664. * @readonly
  152665. */
  152666. ready : {
  152667. value: true
  152668. },
  152669. /**
  152670. * Gets a promise that resolves to true when the provider is ready for use.
  152671. * @memberof WebMapTileServiceImageryProvider.prototype
  152672. * @type {Promise.<Boolean>}
  152673. * @readonly
  152674. */
  152675. readyPromise : {
  152676. get : function() {
  152677. return this._readyPromise;
  152678. }
  152679. },
  152680. /**
  152681. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  152682. * the source of the imagery. This function should not be called before {@link WebMapTileServiceImageryProvider#ready} returns true.
  152683. * @memberof WebMapTileServiceImageryProvider.prototype
  152684. * @type {Credit}
  152685. * @readonly
  152686. */
  152687. credit : {
  152688. get : function() {
  152689. return this._credit;
  152690. }
  152691. },
  152692. /**
  152693. * Gets a value indicating whether or not the images provided by this imagery provider
  152694. * include an alpha channel. If this property is false, an alpha channel, if present, will
  152695. * be ignored. If this property is true, any images without an alpha channel will be treated
  152696. * as if their alpha is 1.0 everywhere. When this property is false, memory usage
  152697. * and texture upload time are reduced.
  152698. * @memberof WebMapTileServiceImageryProvider.prototype
  152699. * @type {Boolean}
  152700. * @readonly
  152701. */
  152702. hasAlphaChannel : {
  152703. get : function() {
  152704. return true;
  152705. }
  152706. }
  152707. });
  152708. /**
  152709. * Gets the credits to be displayed when a given tile is displayed.
  152710. *
  152711. * @param {Number} x The tile X coordinate.
  152712. * @param {Number} y The tile Y coordinate.
  152713. * @param {Number} level The tile level;
  152714. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  152715. *
  152716. * @exception {DeveloperError} <code>getTileCredits</code> must not be called before the imagery provider is ready.
  152717. */
  152718. WebMapTileServiceImageryProvider.prototype.getTileCredits = function(x, y, level) {
  152719. return undefined;
  152720. };
  152721. /**
  152722. * Requests the image for a given tile. This function should
  152723. * not be called before {@link WebMapTileServiceImageryProvider#ready} returns true.
  152724. *
  152725. * @param {Number} x The tile X coordinate.
  152726. * @param {Number} y The tile Y coordinate.
  152727. * @param {Number} level The tile level.
  152728. * @returns {Promise.<Image|Canvas>|undefined} A promise for the image that will resolve when the image is available, or
  152729. * undefined if there are too many active requests to the server, and the request
  152730. * should be retried later. The resolved image may be either an
  152731. * Image or a Canvas DOM object.
  152732. *
  152733. * @exception {DeveloperError} <code>requestImage</code> must not be called before the imagery provider is ready.
  152734. */
  152735. WebMapTileServiceImageryProvider.prototype.requestImage = function(x, y, level) {
  152736. var url = buildImageUrl(this, x, y, level);
  152737. return ImageryProvider.loadImage(this, url);
  152738. };
  152739. /**
  152740. * Picking features is not currently supported by this imagery provider, so this function simply returns
  152741. * undefined.
  152742. *
  152743. * @param {Number} x The tile X coordinate.
  152744. * @param {Number} y The tile Y coordinate.
  152745. * @param {Number} level The tile level.
  152746. * @param {Number} longitude The longitude at which to pick features.
  152747. * @param {Number} latitude The latitude at which to pick features.
  152748. * @return {Promise.<ImageryLayerFeatureInfo[]>|undefined} A promise for the picked features that will resolve when the asynchronous
  152749. * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
  152750. * instances. The array may be empty if no features are found at the given location.
  152751. * It may also be undefined if picking is not supported.
  152752. */
  152753. WebMapTileServiceImageryProvider.prototype.pickFeatures = function() {
  152754. return undefined;
  152755. };
  152756. return WebMapTileServiceImageryProvider;
  152757. });
  152758. /*!
  152759. * Knockout JavaScript library v3.4.0
  152760. * (c) Steven Sanderson - http://knockoutjs.com/
  152761. * License: MIT (http://www.opensource.org/licenses/mit-license.php)
  152762. */
  152763. (function() {(function(n){var x=this||(0,eval)("this"),u=x.document,M=x.navigator,v=x.jQuery,F=x.JSON;(function(n){"function"===typeof define&&define.amd?define('ThirdParty/knockout-3.4.0',["exports","require"],n):"object"===typeof exports&&"object"===typeof module?n(module.exports||exports):n(x.ko={})})(function(N,O){function J(a,c){return null===a||typeof a in T?a===c:!1}function U(b,c){var d;return function(){d||(d=a.a.setTimeout(function(){d=n;b()},c))}}function V(b,c){var d;return function(){clearTimeout(d);d=a.a.setTimeout(b,c)}}function W(a,
  152764. c){c&&c!==I?"beforeChange"===c?this.Kb(a):this.Ha(a,c):this.Lb(a)}function X(a,c){null!==c&&c.k&&c.k()}function Y(a,c){var d=this.Hc,e=d[s];e.R||(this.lb&&this.Ma[c]?(d.Pb(c,a,this.Ma[c]),this.Ma[c]=null,--this.lb):e.r[c]||d.Pb(c,a,e.s?{ia:a}:d.uc(a)))}function K(b,c,d,e){a.d[b]={init:function(b,g,k,l,m){var h,r;a.m(function(){var q=a.a.c(g()),p=!d!==!q,A=!r;if(A||c||p!==h)A&&a.va.Aa()&&(r=a.a.ua(a.f.childNodes(b),!0)),p?(A||a.f.da(b,a.a.ua(r)),a.eb(e?e(m,q):m,b)):a.f.xa(b),h=p},null,{i:b});return{controlsDescendantBindings:!0}}};
  152765. a.h.ta[b]=!1;a.f.Z[b]=!0}var a="undefined"!==typeof N?N:{};a.b=function(b,c){for(var d=b.split("."),e=a,f=0;f<d.length-1;f++)e=e[d[f]];e[d[d.length-1]]=c};a.G=function(a,c,d){a[c]=d};a.version="3.4.0";a.b("version",a.version);a.options={deferUpdates:!1,useOnlyNativeEvents:!1};a.a=function(){function b(a,b){for(var c in a)a.hasOwnProperty(c)&&b(c,a[c])}function c(a,b){if(b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}function d(a,b){a.__proto__=b;return a}function e(b,c,d,e){var h=b[c].match(r)||
  152766. [];a.a.q(d.match(r),function(b){a.a.pa(h,b,e)});b[c]=h.join(" ")}var f={__proto__:[]}instanceof Array,g="function"===typeof Symbol,k={},l={};k[M&&/Firefox\/2/i.test(M.userAgent)?"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];k.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" ");b(k,function(a,b){if(b.length)for(var c=0,d=b.length;c<d;c++)l[b[c]]=a});var m={propertychange:!0},h=u&&function(){for(var a=3,b=u.createElement("div"),c=
  152767. b.getElementsByTagName("i");b.innerHTML="\x3c!--[if gt IE "+ ++a+"]><i></i><![endif]--\x3e",c[0];);return 4<a?a:n}(),r=/\S+/g;return{cc:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],q:function(a,b){for(var c=0,d=a.length;c<d;c++)b(a[c],c)},o:function(a,b){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(a,b);for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},Sb:function(a,b,c){for(var d=0,e=a.length;d<e;d++)if(b.call(c,a[d],d))return a[d];
  152768. return null},La:function(b,c){var d=a.a.o(b,c);0<d?b.splice(d,1):0===d&&b.shift()},Tb:function(b){b=b||[];for(var c=[],d=0,e=b.length;d<e;d++)0>a.a.o(c,b[d])&&c.push(b[d]);return c},fb:function(a,b){a=a||[];for(var c=[],d=0,e=a.length;d<e;d++)c.push(b(a[d],d));return c},Ka:function(a,b){a=a||[];for(var c=[],d=0,e=a.length;d<e;d++)b(a[d],d)&&c.push(a[d]);return c},ra:function(a,b){if(b instanceof Array)a.push.apply(a,b);else for(var c=0,d=b.length;c<d;c++)a.push(b[c]);return a},pa:function(b,c,d){var e=
  152769. a.a.o(a.a.zb(b),c);0>e?d&&b.push(c):d||b.splice(e,1)},ka:f,extend:c,Xa:d,Ya:f?d:c,D:b,Ca:function(a,b){if(!a)return a;var c={},d;for(d in a)a.hasOwnProperty(d)&&(c[d]=b(a[d],d,a));return c},ob:function(b){for(;b.firstChild;)a.removeNode(b.firstChild)},jc:function(b){b=a.a.V(b);for(var c=(b[0]&&b[0].ownerDocument||u).createElement("div"),d=0,e=b.length;d<e;d++)c.appendChild(a.$(b[d]));return c},ua:function(b,c){for(var d=0,e=b.length,h=[];d<e;d++){var m=b[d].cloneNode(!0);h.push(c?a.$(m):m)}return h},
  152770. da:function(b,c){a.a.ob(b);if(c)for(var d=0,e=c.length;d<e;d++)b.appendChild(c[d])},qc:function(b,c){var d=b.nodeType?[b]:b;if(0<d.length){for(var e=d[0],h=e.parentNode,m=0,l=c.length;m<l;m++)h.insertBefore(c[m],e);m=0;for(l=d.length;m<l;m++)a.removeNode(d[m])}},za:function(a,b){if(a.length){for(b=8===b.nodeType&&b.parentNode||b;a.length&&a[0].parentNode!==b;)a.splice(0,1);for(;1<a.length&&a[a.length-1].parentNode!==b;)a.length--;if(1<a.length){var c=a[0],d=a[a.length-1];for(a.length=0;c!==d;)a.push(c),
  152771. c=c.nextSibling;a.push(d)}}return a},sc:function(a,b){7>h?a.setAttribute("selected",b):a.selected=b},$a:function(a){return null===a||a===n?"":a.trim?a.trim():a.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},nd:function(a,b){a=a||"";return b.length>a.length?!1:a.substring(0,b.length)===b},Mc:function(a,b){if(a===b)return!0;if(11===a.nodeType)return!1;if(b.contains)return b.contains(3===a.nodeType?a.parentNode:a);if(b.compareDocumentPosition)return 16==(b.compareDocumentPosition(a)&16);for(;a&&a!=
  152772. b;)a=a.parentNode;return!!a},nb:function(b){return a.a.Mc(b,b.ownerDocument.documentElement)},Qb:function(b){return!!a.a.Sb(b,a.a.nb)},A:function(a){return a&&a.tagName&&a.tagName.toLowerCase()},Wb:function(b){return a.onError?function(){try{return b.apply(this,arguments)}catch(c){throw a.onError&&a.onError(c),c;}}:b},setTimeout:function(b,c){return setTimeout(a.a.Wb(b),c)},$b:function(b){setTimeout(function(){a.onError&&a.onError(b);throw b;},0)},p:function(b,c,d){var e=a.a.Wb(d);d=h&&m[c];if(a.options.useOnlyNativeEvents||
  152773. d||!v)if(d||"function"!=typeof b.addEventListener)if("undefined"!=typeof b.attachEvent){var l=function(a){e.call(b,a)},f="on"+c;b.attachEvent(f,l);a.a.F.oa(b,function(){b.detachEvent(f,l)})}else throw Error("Browser doesn't support addEventListener or attachEvent");else b.addEventListener(c,e,!1);else v(b).bind(c,e)},Da:function(b,c){if(!b||!b.nodeType)throw Error("element must be a DOM node when calling triggerEvent");var d;"input"===a.a.A(b)&&b.type&&"click"==c.toLowerCase()?(d=b.type,d="checkbox"==
  152774. d||"radio"==d):d=!1;if(a.options.useOnlyNativeEvents||!v||d)if("function"==typeof u.createEvent)if("function"==typeof b.dispatchEvent)d=u.createEvent(l[c]||"HTMLEvents"),d.initEvent(c,!0,!0,x,0,0,0,0,0,!1,!1,!1,!1,0,b),b.dispatchEvent(d);else throw Error("The supplied element doesn't support dispatchEvent");else if(d&&b.click)b.click();else if("undefined"!=typeof b.fireEvent)b.fireEvent("on"+c);else throw Error("Browser doesn't support triggering events");else v(b).trigger(c)},c:function(b){return a.H(b)?
  152775. b():b},zb:function(b){return a.H(b)?b.t():b},bb:function(b,c,d){var h;c&&("object"===typeof b.classList?(h=b.classList[d?"add":"remove"],a.a.q(c.match(r),function(a){h.call(b.classList,a)})):"string"===typeof b.className.baseVal?e(b.className,"baseVal",c,d):e(b,"className",c,d))},Za:function(b,c){var d=a.a.c(c);if(null===d||d===n)d="";var e=a.f.firstChild(b);!e||3!=e.nodeType||a.f.nextSibling(e)?a.f.da(b,[b.ownerDocument.createTextNode(d)]):e.data=d;a.a.Rc(b)},rc:function(a,b){a.name=b;if(7>=h)try{a.mergeAttributes(u.createElement("<input name='"+
  152776. a.name+"'/>"),!1)}catch(c){}},Rc:function(a){9<=h&&(a=1==a.nodeType?a:a.parentNode,a.style&&(a.style.zoom=a.style.zoom))},Nc:function(a){if(h){var b=a.style.width;a.style.width=0;a.style.width=b}},hd:function(b,c){b=a.a.c(b);c=a.a.c(c);for(var d=[],e=b;e<=c;e++)d.push(e);return d},V:function(a){for(var b=[],c=0,d=a.length;c<d;c++)b.push(a[c]);return b},Yb:function(a){return g?Symbol(a):a},rd:6===h,sd:7===h,C:h,ec:function(b,c){for(var d=a.a.V(b.getElementsByTagName("input")).concat(a.a.V(b.getElementsByTagName("textarea"))),
  152777. e="string"==typeof c?function(a){return a.name===c}:function(a){return c.test(a.name)},h=[],m=d.length-1;0<=m;m--)e(d[m])&&h.push(d[m]);return h},ed:function(b){return"string"==typeof b&&(b=a.a.$a(b))?F&&F.parse?F.parse(b):(new Function("return "+b))():null},Eb:function(b,c,d){if(!F||!F.stringify)throw Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
  152778. return F.stringify(a.a.c(b),c,d)},fd:function(c,d,e){e=e||{};var h=e.params||{},m=e.includeFields||this.cc,l=c;if("object"==typeof c&&"form"===a.a.A(c))for(var l=c.action,f=m.length-1;0<=f;f--)for(var g=a.a.ec(c,m[f]),k=g.length-1;0<=k;k--)h[g[k].name]=g[k].value;d=a.a.c(d);var r=u.createElement("form");r.style.display="none";r.action=l;r.method="post";for(var n in d)c=u.createElement("input"),c.type="hidden",c.name=n,c.value=a.a.Eb(a.a.c(d[n])),r.appendChild(c);b(h,function(a,b){var c=u.createElement("input");
  152779. c.type="hidden";c.name=a;c.value=b;r.appendChild(c)});u.body.appendChild(r);e.submitter?e.submitter(r):r.submit();setTimeout(function(){r.parentNode.removeChild(r)},0)}}}();a.b("utils",a.a);a.b("utils.arrayForEach",a.a.q);a.b("utils.arrayFirst",a.a.Sb);a.b("utils.arrayFilter",a.a.Ka);a.b("utils.arrayGetDistinctValues",a.a.Tb);a.b("utils.arrayIndexOf",a.a.o);a.b("utils.arrayMap",a.a.fb);a.b("utils.arrayPushAll",a.a.ra);a.b("utils.arrayRemoveItem",a.a.La);a.b("utils.extend",a.a.extend);a.b("utils.fieldsIncludedWithJsonPost",
  152780. a.a.cc);a.b("utils.getFormFields",a.a.ec);a.b("utils.peekObservable",a.a.zb);a.b("utils.postJson",a.a.fd);a.b("utils.parseJson",a.a.ed);a.b("utils.registerEventHandler",a.a.p);a.b("utils.stringifyJson",a.a.Eb);a.b("utils.range",a.a.hd);a.b("utils.toggleDomNodeCssClass",a.a.bb);a.b("utils.triggerEvent",a.a.Da);a.b("utils.unwrapObservable",a.a.c);a.b("utils.objectForEach",a.a.D);a.b("utils.addOrRemoveItem",a.a.pa);a.b("utils.setTextContent",a.a.Za);a.b("unwrap",a.a.c);Function.prototype.bind||(Function.prototype.bind=
  152781. function(a){var c=this;if(1===arguments.length)return function(){return c.apply(a,arguments)};var d=Array.prototype.slice.call(arguments,1);return function(){var e=d.slice(0);e.push.apply(e,arguments);return c.apply(a,e)}});a.a.e=new function(){function a(b,g){var k=b[d];if(!k||"null"===k||!e[k]){if(!g)return n;k=b[d]="ko"+c++;e[k]={}}return e[k]}var c=0,d="__ko__"+(new Date).getTime(),e={};return{get:function(c,d){var e=a(c,!1);return e===n?n:e[d]},set:function(c,d,e){if(e!==n||a(c,!1)!==n)a(c,!0)[d]=
  152782. e},clear:function(a){var b=a[d];return b?(delete e[b],a[d]=null,!0):!1},I:function(){return c++ +d}}};a.b("utils.domData",a.a.e);a.b("utils.domData.clear",a.a.e.clear);a.a.F=new function(){function b(b,c){var e=a.a.e.get(b,d);e===n&&c&&(e=[],a.a.e.set(b,d,e));return e}function c(d){var e=b(d,!1);if(e)for(var e=e.slice(0),l=0;l<e.length;l++)e[l](d);a.a.e.clear(d);a.a.F.cleanExternalData(d);if(f[d.nodeType])for(e=d.firstChild;d=e;)e=d.nextSibling,8===d.nodeType&&c(d)}var d=a.a.e.I(),e={1:!0,8:!0,9:!0},
  152783. f={1:!0,9:!0};return{oa:function(a,c){if("function"!=typeof c)throw Error("Callback must be a function");b(a,!0).push(c)},pc:function(c,e){var l=b(c,!1);l&&(a.a.La(l,e),0==l.length&&a.a.e.set(c,d,n))},$:function(b){if(e[b.nodeType]&&(c(b),f[b.nodeType])){var d=[];a.a.ra(d,b.getElementsByTagName("*"));for(var l=0,m=d.length;l<m;l++)c(d[l])}return b},removeNode:function(b){a.$(b);b.parentNode&&b.parentNode.removeChild(b)},cleanExternalData:function(a){v&&"function"==typeof v.cleanData&&v.cleanData([a])}}};
  152784. a.$=a.a.F.$;a.removeNode=a.a.F.removeNode;a.b("cleanNode",a.$);a.b("removeNode",a.removeNode);a.b("utils.domNodeDisposal",a.a.F);a.b("utils.domNodeDisposal.addDisposeCallback",a.a.F.oa);a.b("utils.domNodeDisposal.removeDisposeCallback",a.a.F.pc);(function(){var b=[0,"",""],c=[1,"<table>","</table>"],d=[3,"<table><tbody><tr>","</tr></tbody></table>"],e=[1,"<select multiple='multiple'>","</select>"],f={thead:c,tbody:c,tfoot:c,tr:[2,"<table><tbody>","</tbody></table>"],td:d,th:d,option:e,optgroup:e},
  152785. g=8>=a.a.C;a.a.ma=function(c,d){var e;if(v)if(v.parseHTML)e=v.parseHTML(c,d)||[];else{if((e=v.clean([c],d))&&e[0]){for(var h=e[0];h.parentNode&&11!==h.parentNode.nodeType;)h=h.parentNode;h.parentNode&&h.parentNode.removeChild(h)}}else{(e=d)||(e=u);var h=e.parentWindow||e.defaultView||x,r=a.a.$a(c).toLowerCase(),q=e.createElement("div"),p;p=(r=r.match(/^<([a-z]+)[ >]/))&&f[r[1]]||b;r=p[0];p="ignored<div>"+p[1]+c+p[2]+"</div>";"function"==typeof h.innerShiv?q.appendChild(h.innerShiv(p)):(g&&e.appendChild(q),
  152786. q.innerHTML=p,g&&q.parentNode.removeChild(q));for(;r--;)q=q.lastChild;e=a.a.V(q.lastChild.childNodes)}return e};a.a.Cb=function(b,c){a.a.ob(b);c=a.a.c(c);if(null!==c&&c!==n)if("string"!=typeof c&&(c=c.toString()),v)v(b).html(c);else for(var d=a.a.ma(c,b.ownerDocument),e=0;e<d.length;e++)b.appendChild(d[e])}})();a.b("utils.parseHtmlFragment",a.a.ma);a.b("utils.setHtml",a.a.Cb);a.M=function(){function b(c,e){if(c)if(8==c.nodeType){var f=a.M.lc(c.nodeValue);null!=f&&e.push({Lc:c,cd:f})}else if(1==c.nodeType)for(var f=
  152787. 0,g=c.childNodes,k=g.length;f<k;f++)b(g[f],e)}var c={};return{wb:function(a){if("function"!=typeof a)throw Error("You can only pass a function to ko.memoization.memoize()");var b=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);c[b]=a;return"\x3c!--[ko_memo:"+b+"]--\x3e"},xc:function(a,b){var f=c[a];if(f===n)throw Error("Couldn't find any memo with ID "+a+". Perhaps it's already been unmemoized.");try{return f.apply(null,b||[]),
  152788. !0}finally{delete c[a]}},yc:function(c,e){var f=[];b(c,f);for(var g=0,k=f.length;g<k;g++){var l=f[g].Lc,m=[l];e&&a.a.ra(m,e);a.M.xc(f[g].cd,m);l.nodeValue="";l.parentNode&&l.parentNode.removeChild(l)}},lc:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:null}}}();a.b("memoization",a.M);a.b("memoization.memoize",a.M.wb);a.b("memoization.unmemoize",a.M.xc);a.b("memoization.parseMemoText",a.M.lc);a.b("memoization.unmemoizeDomNodeAndDescendants",a.M.yc);a.Y=function(){function b(){if(e)for(var b=
  152789. e,c=0,m;g<e;)if(m=d[g++]){if(g>b){if(5E3<=++c){g=e;a.a.$b(Error("'Too much recursion' after processing "+c+" task groups."));break}b=e}try{m()}catch(h){a.a.$b(h)}}}function c(){b();g=e=d.length=0}var d=[],e=0,f=1,g=0;return{scheduler:x.MutationObserver?function(a){var b=u.createElement("div");(new MutationObserver(a)).observe(b,{attributes:!0});return function(){b.classList.toggle("foo")}}(c):u&&"onreadystatechange"in u.createElement("script")?function(a){var b=u.createElement("script");b.onreadystatechange=
  152790. function(){b.onreadystatechange=null;u.documentElement.removeChild(b);b=null;a()};u.documentElement.appendChild(b)}:function(a){setTimeout(a,0)},Wa:function(b){e||a.Y.scheduler(c);d[e++]=b;return f++},cancel:function(a){a-=f-e;a>=g&&a<e&&(d[a]=null)},resetForTesting:function(){var a=e-g;g=e=d.length=0;return a},md:b}}();a.b("tasks",a.Y);a.b("tasks.schedule",a.Y.Wa);a.b("tasks.runEarly",a.Y.md);a.ya={throttle:function(b,c){b.throttleEvaluation=c;var d=null;return a.B({read:b,write:function(e){clearTimeout(d);
  152791. d=a.a.setTimeout(function(){b(e)},c)}})},rateLimit:function(a,c){var d,e,f;"number"==typeof c?d=c:(d=c.timeout,e=c.method);a.cb=!1;f="notifyWhenChangesStop"==e?V:U;a.Ta(function(a){return f(a,d)})},deferred:function(b,c){if(!0!==c)throw Error("The 'deferred' extender only accepts the value 'true', because it is not supported to turn deferral off once enabled.");b.cb||(b.cb=!0,b.Ta(function(c){var e;return function(){a.Y.cancel(e);e=a.Y.Wa(c);b.notifySubscribers(n,"dirty")}}))},notify:function(a,c){a.equalityComparer=
  152792. "always"==c?null:J}};var T={undefined:1,"boolean":1,number:1,string:1};a.b("extenders",a.ya);a.vc=function(b,c,d){this.ia=b;this.gb=c;this.Kc=d;this.R=!1;a.G(this,"dispose",this.k)};a.vc.prototype.k=function(){this.R=!0;this.Kc()};a.J=function(){a.a.Ya(this,D);D.rb(this)};var I="change",D={rb:function(a){a.K={};a.Nb=1},X:function(b,c,d){var e=this;d=d||I;var f=new a.vc(e,c?b.bind(c):b,function(){a.a.La(e.K[d],f);e.Ia&&e.Ia(d)});e.sa&&e.sa(d);e.K[d]||(e.K[d]=[]);e.K[d].push(f);return f},notifySubscribers:function(b,
  152793. c){c=c||I;c===I&&this.zc();if(this.Pa(c))try{a.l.Ub();for(var d=this.K[c].slice(0),e=0,f;f=d[e];++e)f.R||f.gb(b)}finally{a.l.end()}},Na:function(){return this.Nb},Uc:function(a){return this.Na()!==a},zc:function(){++this.Nb},Ta:function(b){var c=this,d=a.H(c),e,f,g;c.Ha||(c.Ha=c.notifySubscribers,c.notifySubscribers=W);var k=b(function(){c.Mb=!1;d&&g===c&&(g=c());e=!1;c.tb(f,g)&&c.Ha(f=g)});c.Lb=function(a){c.Mb=e=!0;g=a;k()};c.Kb=function(a){e||(f=a,c.Ha(a,"beforeChange"))}},Pa:function(a){return this.K[a]&&
  152794. this.K[a].length},Sc:function(b){if(b)return this.K[b]&&this.K[b].length||0;var c=0;a.a.D(this.K,function(a,b){"dirty"!==a&&(c+=b.length)});return c},tb:function(a,c){return!this.equalityComparer||!this.equalityComparer(a,c)},extend:function(b){var c=this;b&&a.a.D(b,function(b,e){var f=a.ya[b];"function"==typeof f&&(c=f(c,e)||c)});return c}};a.G(D,"subscribe",D.X);a.G(D,"extend",D.extend);a.G(D,"getSubscriptionsCount",D.Sc);a.a.ka&&a.a.Xa(D,Function.prototype);a.J.fn=D;a.hc=function(a){return null!=
  152795. a&&"function"==typeof a.X&&"function"==typeof a.notifySubscribers};a.b("subscribable",a.J);a.b("isSubscribable",a.hc);a.va=a.l=function(){function b(a){d.push(e);e=a}function c(){e=d.pop()}var d=[],e,f=0;return{Ub:b,end:c,oc:function(b){if(e){if(!a.hc(b))throw Error("Only subscribable things can act as dependencies");e.gb.call(e.Gc,b,b.Cc||(b.Cc=++f))}},w:function(a,d,e){try{return b(),a.apply(d,e||[])}finally{c()}},Aa:function(){if(e)return e.m.Aa()},Sa:function(){if(e)return e.Sa}}}();a.b("computedContext",
  152796. a.va);a.b("computedContext.getDependenciesCount",a.va.Aa);a.b("computedContext.isInitial",a.va.Sa);a.b("ignoreDependencies",a.qd=a.l.w);var E=a.a.Yb("_latestValue");a.N=function(b){function c(){if(0<arguments.length)return c.tb(c[E],arguments[0])&&(c.ga(),c[E]=arguments[0],c.fa()),this;a.l.oc(c);return c[E]}c[E]=b;a.a.ka||a.a.extend(c,a.J.fn);a.J.fn.rb(c);a.a.Ya(c,B);a.options.deferUpdates&&a.ya.deferred(c,!0);return c};var B={equalityComparer:J,t:function(){return this[E]},fa:function(){this.notifySubscribers(this[E])},
  152797. ga:function(){this.notifySubscribers(this[E],"beforeChange")}};a.a.ka&&a.a.Xa(B,a.J.fn);var H=a.N.gd="__ko_proto__";B[H]=a.N;a.Oa=function(b,c){return null===b||b===n||b[H]===n?!1:b[H]===c?!0:a.Oa(b[H],c)};a.H=function(b){return a.Oa(b,a.N)};a.Ba=function(b){return"function"==typeof b&&b[H]===a.N||"function"==typeof b&&b[H]===a.B&&b.Vc?!0:!1};a.b("observable",a.N);a.b("isObservable",a.H);a.b("isWriteableObservable",a.Ba);a.b("isWritableObservable",a.Ba);a.b("observable.fn",B);a.G(B,"peek",B.t);a.G(B,
  152798. "valueHasMutated",B.fa);a.G(B,"valueWillMutate",B.ga);a.la=function(b){b=b||[];if("object"!=typeof b||!("length"in b))throw Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");b=a.N(b);a.a.Ya(b,a.la.fn);return b.extend({trackArrayChanges:!0})};a.la.fn={remove:function(b){for(var c=this.t(),d=[],e="function"!=typeof b||a.H(b)?function(a){return a===b}:b,f=0;f<c.length;f++){var g=c[f];e(g)&&(0===d.length&&this.ga(),d.push(g),c.splice(f,1),f--)}d.length&&
  152799. this.fa();return d},removeAll:function(b){if(b===n){var c=this.t(),d=c.slice(0);this.ga();c.splice(0,c.length);this.fa();return d}return b?this.remove(function(c){return 0<=a.a.o(b,c)}):[]},destroy:function(b){var c=this.t(),d="function"!=typeof b||a.H(b)?function(a){return a===b}:b;this.ga();for(var e=c.length-1;0<=e;e--)d(c[e])&&(c[e]._destroy=!0);this.fa()},destroyAll:function(b){return b===n?this.destroy(function(){return!0}):b?this.destroy(function(c){return 0<=a.a.o(b,c)}):[]},indexOf:function(b){var c=
  152800. this();return a.a.o(c,b)},replace:function(a,c){var d=this.indexOf(a);0<=d&&(this.ga(),this.t()[d]=c,this.fa())}};a.a.ka&&a.a.Xa(a.la.fn,a.N.fn);a.a.q("pop push reverse shift sort splice unshift".split(" "),function(b){a.la.fn[b]=function(){var a=this.t();this.ga();this.Vb(a,b,arguments);var d=a[b].apply(a,arguments);this.fa();return d===a?this:d}});a.a.q(["slice"],function(b){a.la.fn[b]=function(){var a=this();return a[b].apply(a,arguments)}});a.b("observableArray",a.la);a.ya.trackArrayChanges=function(b,
  152801. c){function d(){if(!e){e=!0;var c=b.notifySubscribers;b.notifySubscribers=function(a,b){b&&b!==I||++k;return c.apply(this,arguments)};var d=[].concat(b.t()||[]);f=null;g=b.X(function(c){c=[].concat(c||[]);if(b.Pa("arrayChange")){var e;if(!f||1<k)f=a.a.ib(d,c,b.hb);e=f}d=c;f=null;k=0;e&&e.length&&b.notifySubscribers(e,"arrayChange")})}}b.hb={};c&&"object"==typeof c&&a.a.extend(b.hb,c);b.hb.sparse=!0;if(!b.Vb){var e=!1,f=null,g,k=0,l=b.sa,m=b.Ia;b.sa=function(a){l&&l.call(b,a);"arrayChange"===a&&d()};
  152802. b.Ia=function(a){m&&m.call(b,a);"arrayChange"!==a||b.Pa("arrayChange")||(g.k(),e=!1)};b.Vb=function(b,c,d){function m(a,b,c){return l[l.length]={status:a,value:b,index:c}}if(e&&!k){var l=[],g=b.length,t=d.length,G=0;switch(c){case "push":G=g;case "unshift":for(c=0;c<t;c++)m("added",d[c],G+c);break;case "pop":G=g-1;case "shift":g&&m("deleted",b[G],G);break;case "splice":c=Math.min(Math.max(0,0>d[0]?g+d[0]:d[0]),g);for(var g=1===t?g:Math.min(c+(d[1]||0),g),t=c+t-2,G=Math.max(g,t),P=[],n=[],Q=2;c<G;++c,
  152803. ++Q)c<g&&n.push(m("deleted",b[c],c)),c<t&&P.push(m("added",d[Q],c));a.a.dc(n,P);break;default:return}f=l}}}};var s=a.a.Yb("_state");a.m=a.B=function(b,c,d){function e(){if(0<arguments.length){if("function"===typeof f)f.apply(g.pb,arguments);else throw Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");return this}a.l.oc(e);(g.S||g.s&&e.Qa())&&e.aa();return g.T}"object"===typeof b?d=b:(d=d||{},b&&(d.read=
  152804. b));if("function"!=typeof d.read)throw Error("Pass a function that returns the value of the ko.computed");var f=d.write,g={T:n,S:!0,Ra:!1,Fb:!1,R:!1,Va:!1,s:!1,jd:d.read,pb:c||d.owner,i:d.disposeWhenNodeIsRemoved||d.i||null,wa:d.disposeWhen||d.wa,mb:null,r:{},L:0,bc:null};e[s]=g;e.Vc="function"===typeof f;a.a.ka||a.a.extend(e,a.J.fn);a.J.fn.rb(e);a.a.Ya(e,z);d.pure?(g.Va=!0,g.s=!0,a.a.extend(e,$)):d.deferEvaluation&&a.a.extend(e,aa);a.options.deferUpdates&&a.ya.deferred(e,!0);g.i&&(g.Fb=!0,g.i.nodeType||
  152805. (g.i=null));g.s||d.deferEvaluation||e.aa();g.i&&e.ba()&&a.a.F.oa(g.i,g.mb=function(){e.k()});return e};var z={equalityComparer:J,Aa:function(){return this[s].L},Pb:function(a,c,d){if(this[s].Va&&c===this)throw Error("A 'pure' computed must not be called recursively");this[s].r[a]=d;d.Ga=this[s].L++;d.na=c.Na()},Qa:function(){var a,c,d=this[s].r;for(a in d)if(d.hasOwnProperty(a)&&(c=d[a],c.ia.Uc(c.na)))return!0},bd:function(){this.Fa&&!this[s].Ra&&this.Fa()},ba:function(){return this[s].S||0<this[s].L},
  152806. ld:function(){this.Mb||this.ac()},uc:function(a){if(a.cb&&!this[s].i){var c=a.X(this.bd,this,"dirty"),d=a.X(this.ld,this);return{ia:a,k:function(){c.k();d.k()}}}return a.X(this.ac,this)},ac:function(){var b=this,c=b.throttleEvaluation;c&&0<=c?(clearTimeout(this[s].bc),this[s].bc=a.a.setTimeout(function(){b.aa(!0)},c)):b.Fa?b.Fa():b.aa(!0)},aa:function(b){var c=this[s],d=c.wa;if(!c.Ra&&!c.R){if(c.i&&!a.a.nb(c.i)||d&&d()){if(!c.Fb){this.k();return}}else c.Fb=!1;c.Ra=!0;try{this.Qc(b)}finally{c.Ra=!1}c.L||
  152807. this.k()}},Qc:function(b){var c=this[s],d=c.Va?n:!c.L,e={Hc:this,Ma:c.r,lb:c.L};a.l.Ub({Gc:e,gb:Y,m:this,Sa:d});c.r={};c.L=0;e=this.Pc(c,e);this.tb(c.T,e)&&(c.s||this.notifySubscribers(c.T,"beforeChange"),c.T=e,c.s?this.zc():b&&this.notifySubscribers(c.T));d&&this.notifySubscribers(c.T,"awake")},Pc:function(b,c){try{var d=b.jd;return b.pb?d.call(b.pb):d()}finally{a.l.end(),c.lb&&!b.s&&a.a.D(c.Ma,X),b.S=!1}},t:function(){var a=this[s];(a.S&&!a.L||a.s&&this.Qa())&&this.aa();return a.T},Ta:function(b){a.J.fn.Ta.call(this,
  152808. b);this.Fa=function(){this.Kb(this[s].T);this[s].S=!0;this.Lb(this)}},k:function(){var b=this[s];!b.s&&b.r&&a.a.D(b.r,function(a,b){b.k&&b.k()});b.i&&b.mb&&a.a.F.pc(b.i,b.mb);b.r=null;b.L=0;b.R=!0;b.S=!1;b.s=!1;b.i=null}},$={sa:function(b){var c=this,d=c[s];if(!d.R&&d.s&&"change"==b){d.s=!1;if(d.S||c.Qa())d.r=null,d.L=0,d.S=!0,c.aa();else{var e=[];a.a.D(d.r,function(a,b){e[b.Ga]=a});a.a.q(e,function(a,b){var e=d.r[a],l=c.uc(e.ia);l.Ga=b;l.na=e.na;d.r[a]=l})}d.R||c.notifySubscribers(d.T,"awake")}},
  152809. Ia:function(b){var c=this[s];c.R||"change"!=b||this.Pa("change")||(a.a.D(c.r,function(a,b){b.k&&(c.r[a]={ia:b.ia,Ga:b.Ga,na:b.na},b.k())}),c.s=!0,this.notifySubscribers(n,"asleep"))},Na:function(){var b=this[s];b.s&&(b.S||this.Qa())&&this.aa();return a.J.fn.Na.call(this)}},aa={sa:function(a){"change"!=a&&"beforeChange"!=a||this.t()}};a.a.ka&&a.a.Xa(z,a.J.fn);var R=a.N.gd;a.m[R]=a.N;z[R]=a.m;a.Xc=function(b){return a.Oa(b,a.m)};a.Yc=function(b){return a.Oa(b,a.m)&&b[s]&&b[s].Va};a.b("computed",a.m);
  152810. a.b("dependentObservable",a.m);a.b("isComputed",a.Xc);a.b("isPureComputed",a.Yc);a.b("computed.fn",z);a.G(z,"peek",z.t);a.G(z,"dispose",z.k);a.G(z,"isActive",z.ba);a.G(z,"getDependenciesCount",z.Aa);a.nc=function(b,c){if("function"===typeof b)return a.m(b,c,{pure:!0});b=a.a.extend({},b);b.pure=!0;return a.m(b,c)};a.b("pureComputed",a.nc);(function(){function b(a,f,g){g=g||new d;a=f(a);if("object"!=typeof a||null===a||a===n||a instanceof RegExp||a instanceof Date||a instanceof String||a instanceof
  152811. Number||a instanceof Boolean)return a;var k=a instanceof Array?[]:{};g.save(a,k);c(a,function(c){var d=f(a[c]);switch(typeof d){case "boolean":case "number":case "string":case "function":k[c]=d;break;case "object":case "undefined":var h=g.get(d);k[c]=h!==n?h:b(d,f,g)}});return k}function c(a,b){if(a instanceof Array){for(var c=0;c<a.length;c++)b(c);"function"==typeof a.toJSON&&b("toJSON")}else for(c in a)b(c)}function d(){this.keys=[];this.Ib=[]}a.wc=function(c){if(0==arguments.length)throw Error("When calling ko.toJS, pass the object you want to convert.");
  152812. return b(c,function(b){for(var c=0;a.H(b)&&10>c;c++)b=b();return b})};a.toJSON=function(b,c,d){b=a.wc(b);return a.a.Eb(b,c,d)};d.prototype={save:function(b,c){var d=a.a.o(this.keys,b);0<=d?this.Ib[d]=c:(this.keys.push(b),this.Ib.push(c))},get:function(b){b=a.a.o(this.keys,b);return 0<=b?this.Ib[b]:n}}})();a.b("toJS",a.wc);a.b("toJSON",a.toJSON);(function(){a.j={u:function(b){switch(a.a.A(b)){case "option":return!0===b.__ko__hasDomDataOptionValue__?a.a.e.get(b,a.d.options.xb):7>=a.a.C?b.getAttributeNode("value")&&
  152813. b.getAttributeNode("value").specified?b.value:b.text:b.value;case "select":return 0<=b.selectedIndex?a.j.u(b.options[b.selectedIndex]):n;default:return b.value}},ha:function(b,c,d){switch(a.a.A(b)){case "option":switch(typeof c){case "string":a.a.e.set(b,a.d.options.xb,n);"__ko__hasDomDataOptionValue__"in b&&delete b.__ko__hasDomDataOptionValue__;b.value=c;break;default:a.a.e.set(b,a.d.options.xb,c),b.__ko__hasDomDataOptionValue__=!0,b.value="number"===typeof c?c:""}break;case "select":if(""===c||
  152814. null===c)c=n;for(var e=-1,f=0,g=b.options.length,k;f<g;++f)if(k=a.j.u(b.options[f]),k==c||""==k&&c===n){e=f;break}if(d||0<=e||c===n&&1<b.size)b.selectedIndex=e;break;default:if(null===c||c===n)c="";b.value=c}}}})();a.b("selectExtensions",a.j);a.b("selectExtensions.readValue",a.j.u);a.b("selectExtensions.writeValue",a.j.ha);a.h=function(){function b(b){b=a.a.$a(b);123===b.charCodeAt(0)&&(b=b.slice(1,-1));var c=[],d=b.match(e),r,k=[],p=0;if(d){d.push(",");for(var A=0,y;y=d[A];++A){var t=y.charCodeAt(0);
  152815. if(44===t){if(0>=p){c.push(r&&k.length?{key:r,value:k.join("")}:{unknown:r||k.join("")});r=p=0;k=[];continue}}else if(58===t){if(!p&&!r&&1===k.length){r=k.pop();continue}}else 47===t&&A&&1<y.length?(t=d[A-1].match(f))&&!g[t[0]]&&(b=b.substr(b.indexOf(y)+1),d=b.match(e),d.push(","),A=-1,y="/"):40===t||123===t||91===t?++p:41===t||125===t||93===t?--p:r||k.length||34!==t&&39!==t||(y=y.slice(1,-1));k.push(y)}}return c}var c=["true","false","null","undefined"],d=/^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i,
  152816. e=RegExp("\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*'|/(?:[^/\\\\]|\\\\.)*/w*|[^\\s:,/][^,\"'{}()/:[\\]]*[^\\s,\"'{}()/:[\\]]|[^\\s]","g"),f=/[\])"'A-Za-z0-9_$]+$/,g={"in":1,"return":1,"typeof":1},k={};return{ta:[],ea:k,yb:b,Ua:function(e,m){function h(b,e){var m;if(!A){var l=a.getBindingHandler(b);if(l&&l.preprocess&&!(e=l.preprocess(e,b,h)))return;if(l=k[b])m=e,0<=a.a.o(c,m)?m=!1:(l=m.match(d),m=null===l?!1:l[1]?"Object("+l[1]+")"+l[2]:m),l=m;l&&g.push("'"+b+"':function(_z){"+m+"=_z}")}p&&(e=
  152817. "function(){return "+e+" }");f.push("'"+b+"':"+e)}m=m||{};var f=[],g=[],p=m.valueAccessors,A=m.bindingParams,y="string"===typeof e?b(e):e;a.a.q(y,function(a){h(a.key||a.unknown,a.value)});g.length&&h("_ko_property_writers","{"+g.join(",")+" }");return f.join(",")},ad:function(a,b){for(var c=0;c<a.length;c++)if(a[c].key==b)return!0;return!1},Ea:function(b,c,d,e,f){if(b&&a.H(b))!a.Ba(b)||f&&b.t()===e||b(e);else if((b=c.get("_ko_property_writers"))&&b[d])b[d](e)}}}();a.b("expressionRewriting",a.h);a.b("expressionRewriting.bindingRewriteValidators",
  152818. a.h.ta);a.b("expressionRewriting.parseObjectLiteral",a.h.yb);a.b("expressionRewriting.preProcessBindings",a.h.Ua);a.b("expressionRewriting._twoWayBindings",a.h.ea);a.b("jsonExpressionRewriting",a.h);a.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",a.h.Ua);(function(){function b(a){return 8==a.nodeType&&g.test(f?a.text:a.nodeValue)}function c(a){return 8==a.nodeType&&k.test(f?a.text:a.nodeValue)}function d(a,d){for(var e=a,f=1,l=[];e=e.nextSibling;){if(c(e)&&(f--,0===f))return l;l.push(e);
  152819. b(e)&&f++}if(!d)throw Error("Cannot find closing comment tag to match: "+a.nodeValue);return null}function e(a,b){var c=d(a,b);return c?0<c.length?c[c.length-1].nextSibling:a.nextSibling:null}var f=u&&"\x3c!--test--\x3e"===u.createComment("test").text,g=f?/^\x3c!--\s*ko(?:\s+([\s\S]+))?\s*--\x3e$/:/^\s*ko(?:\s+([\s\S]+))?\s*$/,k=f?/^\x3c!--\s*\/ko\s*--\x3e$/:/^\s*\/ko\s*$/,l={ul:!0,ol:!0};a.f={Z:{},childNodes:function(a){return b(a)?d(a):a.childNodes},xa:function(c){if(b(c)){c=a.f.childNodes(c);for(var d=
  152820. 0,e=c.length;d<e;d++)a.removeNode(c[d])}else a.a.ob(c)},da:function(c,d){if(b(c)){a.f.xa(c);for(var e=c.nextSibling,f=0,l=d.length;f<l;f++)e.parentNode.insertBefore(d[f],e)}else a.a.da(c,d)},mc:function(a,c){b(a)?a.parentNode.insertBefore(c,a.nextSibling):a.firstChild?a.insertBefore(c,a.firstChild):a.appendChild(c)},gc:function(c,d,e){e?b(c)?c.parentNode.insertBefore(d,e.nextSibling):e.nextSibling?c.insertBefore(d,e.nextSibling):c.appendChild(d):a.f.mc(c,d)},firstChild:function(a){return b(a)?!a.nextSibling||
  152821. c(a.nextSibling)?null:a.nextSibling:a.firstChild},nextSibling:function(a){b(a)&&(a=e(a));return a.nextSibling&&c(a.nextSibling)?null:a.nextSibling},Tc:b,pd:function(a){return(a=(f?a.text:a.nodeValue).match(g))?a[1]:null},kc:function(d){if(l[a.a.A(d)]){var h=d.firstChild;if(h){do if(1===h.nodeType){var f;f=h.firstChild;var g=null;if(f){do if(g)g.push(f);else if(b(f)){var k=e(f,!0);k?f=k:g=[f]}else c(f)&&(g=[f]);while(f=f.nextSibling)}if(f=g)for(g=h.nextSibling,k=0;k<f.length;k++)g?d.insertBefore(f[k],
  152822. g):d.appendChild(f[k])}while(h=h.nextSibling)}}}}})();a.b("virtualElements",a.f);a.b("virtualElements.allowedBindings",a.f.Z);a.b("virtualElements.emptyNode",a.f.xa);a.b("virtualElements.insertAfter",a.f.gc);a.b("virtualElements.prepend",a.f.mc);a.b("virtualElements.setDomNodeChildren",a.f.da);(function(){a.Q=function(){this.Fc={}};a.a.extend(a.Q.prototype,{nodeHasBindings:function(b){switch(b.nodeType){case 1:return null!=b.getAttribute("data-bind")||a.g.getComponentNameForNode(b);case 8:return a.f.Tc(b);
  152823. default:return!1}},getBindings:function(b,c){var d=this.getBindingsString(b,c),d=d?this.parseBindingsString(d,c,b):null;return a.g.Ob(d,b,c,!1)},getBindingAccessors:function(b,c){var d=this.getBindingsString(b,c),d=d?this.parseBindingsString(d,c,b,{valueAccessors:!0}):null;return a.g.Ob(d,b,c,!0)},getBindingsString:function(b){switch(b.nodeType){case 1:return b.getAttribute("data-bind");case 8:return a.f.pd(b);default:return null}},parseBindingsString:function(b,c,d,e){try{var f=this.Fc,g=b+(e&&e.valueAccessors||
  152824. ""),k;if(!(k=f[g])){var l,m="with($context){with($data||{}){return{"+a.h.Ua(b,e)+"}}}";l=new Function("$context","$element",m);k=f[g]=l}return k(c,d)}catch(h){throw h.message="Unable to parse bindings.\nBindings value: "+b+"\nMessage: "+h.message,h;}}});a.Q.instance=new a.Q})();a.b("bindingProvider",a.Q);(function(){function b(a){return function(){return a}}function c(a){return a()}function d(b){return a.a.Ca(a.l.w(b),function(a,c){return function(){return b()[c]}})}function e(c,e,h){return"function"===
  152825. typeof c?d(c.bind(null,e,h)):a.a.Ca(c,b)}function f(a,b){return d(this.getBindings.bind(this,a,b))}function g(b,c,d){var e,h=a.f.firstChild(c),f=a.Q.instance,m=f.preprocessNode;if(m){for(;e=h;)h=a.f.nextSibling(e),m.call(f,e);h=a.f.firstChild(c)}for(;e=h;)h=a.f.nextSibling(e),k(b,e,d)}function k(b,c,d){var e=!0,h=1===c.nodeType;h&&a.f.kc(c);if(h&&d||a.Q.instance.nodeHasBindings(c))e=m(c,null,b,d).shouldBindDescendants;e&&!r[a.a.A(c)]&&g(b,c,!h)}function l(b){var c=[],d={},e=[];a.a.D(b,function Z(h){if(!d[h]){var f=
  152826. a.getBindingHandler(h);f&&(f.after&&(e.push(h),a.a.q(f.after,function(c){if(b[c]){if(-1!==a.a.o(e,c))throw Error("Cannot combine the following bindings, because they have a cyclic dependency: "+e.join(", "));Z(c)}}),e.length--),c.push({key:h,fc:f}));d[h]=!0}});return c}function m(b,d,e,h){var m=a.a.e.get(b,q);if(!d){if(m)throw Error("You cannot apply bindings multiple times to the same element.");a.a.e.set(b,q,!0)}!m&&h&&a.tc(b,e);var g;if(d&&"function"!==typeof d)g=d;else{var k=a.Q.instance,r=k.getBindingAccessors||
  152827. f,p=a.B(function(){(g=d?d(e,b):r.call(k,b,e))&&e.P&&e.P();return g},null,{i:b});g&&p.ba()||(p=null)}var u;if(g){var v=p?function(a){return function(){return c(p()[a])}}:function(a){return g[a]},s=function(){return a.a.Ca(p?p():g,c)};s.get=function(a){return g[a]&&c(v(a))};s.has=function(a){return a in g};h=l(g);a.a.q(h,function(c){var d=c.fc.init,h=c.fc.update,f=c.key;if(8===b.nodeType&&!a.f.Z[f])throw Error("The binding '"+f+"' cannot be used with virtual elements");try{"function"==typeof d&&a.l.w(function(){var a=
  152828. d(b,v(f),s,e.$data,e);if(a&&a.controlsDescendantBindings){if(u!==n)throw Error("Multiple bindings ("+u+" and "+f+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");u=f}}),"function"==typeof h&&a.B(function(){h(b,v(f),s,e.$data,e)},null,{i:b})}catch(m){throw m.message='Unable to process binding "'+f+": "+g[f]+'"\nMessage: '+m.message,m;}})}return{shouldBindDescendants:u===n}}function h(b){return b&&b instanceof a.U?b:new a.U(b)}
  152829. a.d={};var r={script:!0,textarea:!0,template:!0};a.getBindingHandler=function(b){return a.d[b]};a.U=function(b,c,d,e){var h=this,f="function"==typeof b&&!a.H(b),m,g=a.B(function(){var m=f?b():b,l=a.a.c(m);c?(c.P&&c.P(),a.a.extend(h,c),g&&(h.P=g)):(h.$parents=[],h.$root=l,h.ko=a);h.$rawData=m;h.$data=l;d&&(h[d]=l);e&&e(h,c,l);return h.$data},null,{wa:function(){return m&&!a.a.Qb(m)},i:!0});g.ba()&&(h.P=g,g.equalityComparer=null,m=[],g.Ac=function(b){m.push(b);a.a.F.oa(b,function(b){a.a.La(m,b);m.length||
  152830. (g.k(),h.P=g=n)})})};a.U.prototype.createChildContext=function(b,c,d){return new a.U(b,this,c,function(a,b){a.$parentContext=b;a.$parent=b.$data;a.$parents=(b.$parents||[]).slice(0);a.$parents.unshift(a.$parent);d&&d(a)})};a.U.prototype.extend=function(b){return new a.U(this.P||this.$data,this,null,function(c,d){c.$rawData=d.$rawData;a.a.extend(c,"function"==typeof b?b():b)})};var q=a.a.e.I(),p=a.a.e.I();a.tc=function(b,c){if(2==arguments.length)a.a.e.set(b,p,c),c.P&&c.P.Ac(b);else return a.a.e.get(b,
  152831. p)};a.Ja=function(b,c,d){1===b.nodeType&&a.f.kc(b);return m(b,c,h(d),!0)};a.Dc=function(b,c,d){d=h(d);return a.Ja(b,e(c,d,b),d)};a.eb=function(a,b){1!==b.nodeType&&8!==b.nodeType||g(h(a),b,!0)};a.Rb=function(a,b){!v&&x.jQuery&&(v=x.jQuery);if(b&&1!==b.nodeType&&8!==b.nodeType)throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");b=b||x.document.body;k(h(a),b,!0)};a.kb=function(b){switch(b.nodeType){case 1:case 8:var c=a.tc(b);if(c)return c;
  152832. if(b.parentNode)return a.kb(b.parentNode)}return n};a.Jc=function(b){return(b=a.kb(b))?b.$data:n};a.b("bindingHandlers",a.d);a.b("applyBindings",a.Rb);a.b("applyBindingsToDescendants",a.eb);a.b("applyBindingAccessorsToNode",a.Ja);a.b("applyBindingsToNode",a.Dc);a.b("contextFor",a.kb);a.b("dataFor",a.Jc)})();(function(b){function c(c,e){var m=f.hasOwnProperty(c)?f[c]:b,h;m?m.X(e):(m=f[c]=new a.J,m.X(e),d(c,function(b,d){var e=!(!d||!d.synchronous);g[c]={definition:b,Zc:e};delete f[c];h||e?m.notifySubscribers(b):
  152833. a.Y.Wa(function(){m.notifySubscribers(b)})}),h=!0)}function d(a,b){e("getConfig",[a],function(c){c?e("loadComponent",[a,c],function(a){b(a,c)}):b(null,null)})}function e(c,d,f,h){h||(h=a.g.loaders.slice(0));var g=h.shift();if(g){var q=g[c];if(q){var p=!1;if(q.apply(g,d.concat(function(a){p?f(null):null!==a?f(a):e(c,d,f,h)}))!==b&&(p=!0,!g.suppressLoaderExceptions))throw Error("Component loaders must supply values by invoking the callback, not by returning values synchronously.");}else e(c,d,f,h)}else f(null)}
  152834. var f={},g={};a.g={get:function(d,e){var f=g.hasOwnProperty(d)?g[d]:b;f?f.Zc?a.l.w(function(){e(f.definition)}):a.Y.Wa(function(){e(f.definition)}):c(d,e)},Xb:function(a){delete g[a]},Jb:e};a.g.loaders=[];a.b("components",a.g);a.b("components.get",a.g.get);a.b("components.clearCachedDefinition",a.g.Xb)})();(function(){function b(b,c,d,e){function g(){0===--y&&e(k)}var k={},y=2,t=d.template;d=d.viewModel;t?f(c,t,function(c){a.g.Jb("loadTemplate",[b,c],function(a){k.template=a;g()})}):g();d?f(c,d,function(c){a.g.Jb("loadViewModel",
  152835. [b,c],function(a){k[l]=a;g()})}):g()}function c(a,b,d){if("function"===typeof b)d(function(a){return new b(a)});else if("function"===typeof b[l])d(b[l]);else if("instance"in b){var e=b.instance;d(function(){return e})}else"viewModel"in b?c(a,b.viewModel,d):a("Unknown viewModel value: "+b)}function d(b){switch(a.a.A(b)){case "script":return a.a.ma(b.text);case "textarea":return a.a.ma(b.value);case "template":if(e(b.content))return a.a.ua(b.content.childNodes)}return a.a.ua(b.childNodes)}function e(a){return x.DocumentFragment?
  152836. a instanceof DocumentFragment:a&&11===a.nodeType}function f(a,b,c){"string"===typeof b.require?O||x.require?(O||x.require)([b.require],c):a("Uses require, but no AMD loader is present"):c(b)}function g(a){return function(b){throw Error("Component '"+a+"': "+b);}}var k={};a.g.register=function(b,c){if(!c)throw Error("Invalid configuration for "+b);if(a.g.ub(b))throw Error("Component "+b+" is already registered");k[b]=c};a.g.ub=function(a){return k.hasOwnProperty(a)};a.g.od=function(b){delete k[b];
  152837. a.g.Xb(b)};a.g.Zb={getConfig:function(a,b){b(k.hasOwnProperty(a)?k[a]:null)},loadComponent:function(a,c,d){var e=g(a);f(e,c,function(c){b(a,e,c,d)})},loadTemplate:function(b,c,f){b=g(b);if("string"===typeof c)f(a.a.ma(c));else if(c instanceof Array)f(c);else if(e(c))f(a.a.V(c.childNodes));else if(c.element)if(c=c.element,x.HTMLElement?c instanceof HTMLElement:c&&c.tagName&&1===c.nodeType)f(d(c));else if("string"===typeof c){var l=u.getElementById(c);l?f(d(l)):b("Cannot find element with ID "+c)}else b("Unknown element type: "+
  152838. c);else b("Unknown template value: "+c)},loadViewModel:function(a,b,d){c(g(a),b,d)}};var l="createViewModel";a.b("components.register",a.g.register);a.b("components.isRegistered",a.g.ub);a.b("components.unregister",a.g.od);a.b("components.defaultLoader",a.g.Zb);a.g.loaders.push(a.g.Zb);a.g.Bc=k})();(function(){function b(b,e){var f=b.getAttribute("params");if(f){var f=c.parseBindingsString(f,e,b,{valueAccessors:!0,bindingParams:!0}),f=a.a.Ca(f,function(c){return a.m(c,null,{i:b})}),g=a.a.Ca(f,function(c){var e=
  152839. c.t();return c.ba()?a.m({read:function(){return a.a.c(c())},write:a.Ba(e)&&function(a){c()(a)},i:b}):e});g.hasOwnProperty("$raw")||(g.$raw=f);return g}return{$raw:{}}}a.g.getComponentNameForNode=function(b){var c=a.a.A(b);if(a.g.ub(c)&&(-1!=c.indexOf("-")||"[object HTMLUnknownElement]"==""+b||8>=a.a.C&&b.tagName===c))return c};a.g.Ob=function(c,e,f,g){if(1===e.nodeType){var k=a.g.getComponentNameForNode(e);if(k){c=c||{};if(c.component)throw Error('Cannot use the "component" binding on a custom element matching a component');
  152840. var l={name:k,params:b(e,f)};c.component=g?function(){return l}:l}}return c};var c=new a.Q;9>a.a.C&&(a.g.register=function(a){return function(b){u.createElement(b);return a.apply(this,arguments)}}(a.g.register),u.createDocumentFragment=function(b){return function(){var c=b(),f=a.g.Bc,g;for(g in f)f.hasOwnProperty(g)&&c.createElement(g);return c}}(u.createDocumentFragment))})();(function(b){function c(b,c,d){c=c.template;if(!c)throw Error("Component '"+b+"' has no template");b=a.a.ua(c);a.f.da(d,b)}
  152841. function d(a,b,c,d){var e=a.createViewModel;return e?e.call(a,d,{element:b,templateNodes:c}):d}var e=0;a.d.component={init:function(f,g,k,l,m){function h(){var a=r&&r.dispose;"function"===typeof a&&a.call(r);q=r=null}var r,q,p=a.a.V(a.f.childNodes(f));a.a.F.oa(f,h);a.m(function(){var l=a.a.c(g()),k,t;"string"===typeof l?k=l:(k=a.a.c(l.name),t=a.a.c(l.params));if(!k)throw Error("No component name specified");var n=q=++e;a.g.get(k,function(e){if(q===n){h();if(!e)throw Error("Unknown component '"+k+
  152842. "'");c(k,e,f);var g=d(e,f,p,t);e=m.createChildContext(g,b,function(a){a.$component=g;a.$componentTemplateNodes=p});r=g;a.eb(e,f)}})},null,{i:f});return{controlsDescendantBindings:!0}}};a.f.Z.component=!0})();var S={"class":"className","for":"htmlFor"};a.d.attr={update:function(b,c){var d=a.a.c(c())||{};a.a.D(d,function(c,d){d=a.a.c(d);var g=!1===d||null===d||d===n;g&&b.removeAttribute(c);8>=a.a.C&&c in S?(c=S[c],g?b.removeAttribute(c):b[c]=d):g||b.setAttribute(c,d.toString());"name"===c&&a.a.rc(b,
  152843. g?"":d.toString())})}};(function(){a.d.checked={after:["value","attr"],init:function(b,c,d){function e(){var e=b.checked,f=p?g():e;if(!a.va.Sa()&&(!l||e)){var m=a.l.w(c);if(h){var k=r?m.t():m;q!==f?(e&&(a.a.pa(k,f,!0),a.a.pa(k,q,!1)),q=f):a.a.pa(k,f,e);r&&a.Ba(m)&&m(k)}else a.h.Ea(m,d,"checked",f,!0)}}function f(){var d=a.a.c(c());b.checked=h?0<=a.a.o(d,g()):k?d:g()===d}var g=a.nc(function(){return d.has("checkedValue")?a.a.c(d.get("checkedValue")):d.has("value")?a.a.c(d.get("value")):b.value}),k=
  152844. "checkbox"==b.type,l="radio"==b.type;if(k||l){var m=c(),h=k&&a.a.c(m)instanceof Array,r=!(h&&m.push&&m.splice),q=h?g():n,p=l||h;l&&!b.name&&a.d.uniqueName.init(b,function(){return!0});a.m(e,null,{i:b});a.a.p(b,"click",e);a.m(f,null,{i:b});m=n}}};a.h.ea.checked=!0;a.d.checkedValue={update:function(b,c){b.value=a.a.c(c())}}})();a.d.css={update:function(b,c){var d=a.a.c(c());null!==d&&"object"==typeof d?a.a.D(d,function(c,d){d=a.a.c(d);a.a.bb(b,c,d)}):(d=a.a.$a(String(d||"")),a.a.bb(b,b.__ko__cssValue,
  152845. !1),b.__ko__cssValue=d,a.a.bb(b,d,!0))}};a.d.enable={update:function(b,c){var d=a.a.c(c());d&&b.disabled?b.removeAttribute("disabled"):d||b.disabled||(b.disabled=!0)}};a.d.disable={update:function(b,c){a.d.enable.update(b,function(){return!a.a.c(c())})}};a.d.event={init:function(b,c,d,e,f){var g=c()||{};a.a.D(g,function(g){"string"==typeof g&&a.a.p(b,g,function(b){var m,h=c()[g];if(h){try{var r=a.a.V(arguments);e=f.$data;r.unshift(e);m=h.apply(e,r)}finally{!0!==m&&(b.preventDefault?b.preventDefault():
  152846. b.returnValue=!1)}!1===d.get(g+"Bubble")&&(b.cancelBubble=!0,b.stopPropagation&&b.stopPropagation())}})})}};a.d.foreach={ic:function(b){return function(){var c=b(),d=a.a.zb(c);if(!d||"number"==typeof d.length)return{foreach:c,templateEngine:a.W.sb};a.a.c(c);return{foreach:d.data,as:d.as,includeDestroyed:d.includeDestroyed,afterAdd:d.afterAdd,beforeRemove:d.beforeRemove,afterRender:d.afterRender,beforeMove:d.beforeMove,afterMove:d.afterMove,templateEngine:a.W.sb}}},init:function(b,c){return a.d.template.init(b,
  152847. a.d.foreach.ic(c))},update:function(b,c,d,e,f){return a.d.template.update(b,a.d.foreach.ic(c),d,e,f)}};a.h.ta.foreach=!1;a.f.Z.foreach=!0;a.d.hasfocus={init:function(b,c,d){function e(e){b.__ko_hasfocusUpdating=!0;var f=b.ownerDocument;if("activeElement"in f){var g;try{g=f.activeElement}catch(h){g=f.body}e=g===b}f=c();a.h.Ea(f,d,"hasfocus",e,!0);b.__ko_hasfocusLastValue=e;b.__ko_hasfocusUpdating=!1}var f=e.bind(null,!0),g=e.bind(null,!1);a.a.p(b,"focus",f);a.a.p(b,"focusin",f);a.a.p(b,"blur",g);a.a.p(b,
  152848. "focusout",g)},update:function(b,c){var d=!!a.a.c(c());b.__ko_hasfocusUpdating||b.__ko_hasfocusLastValue===d||(d?b.focus():b.blur(),!d&&b.__ko_hasfocusLastValue&&b.ownerDocument.body.focus(),a.l.w(a.a.Da,null,[b,d?"focusin":"focusout"]))}};a.h.ea.hasfocus=!0;a.d.hasFocus=a.d.hasfocus;a.h.ea.hasFocus=!0;a.d.html={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.Cb(b,c())}};K("if");K("ifnot",!1,!0);K("with",!0,!1,function(a,c){return a.createChildContext(c)});var L={};
  152849. a.d.options={init:function(b){if("select"!==a.a.A(b))throw Error("options binding applies only to SELECT elements");for(;0<b.length;)b.remove(0);return{controlsDescendantBindings:!0}},update:function(b,c,d){function e(){return a.a.Ka(b.options,function(a){return a.selected})}function f(a,b,c){var d=typeof b;return"function"==d?b(a):"string"==d?a[b]:c}function g(c,e){if(A&&h)a.j.ha(b,a.a.c(d.get("value")),!0);else if(p.length){var f=0<=a.a.o(p,a.j.u(e[0]));a.a.sc(e[0],f);A&&!f&&a.l.w(a.a.Da,null,[b,
  152850. "change"])}}var k=b.multiple,l=0!=b.length&&k?b.scrollTop:null,m=a.a.c(c()),h=d.get("valueAllowUnset")&&d.has("value"),r=d.get("optionsIncludeDestroyed");c={};var q,p=[];h||(k?p=a.a.fb(e(),a.j.u):0<=b.selectedIndex&&p.push(a.j.u(b.options[b.selectedIndex])));m&&("undefined"==typeof m.length&&(m=[m]),q=a.a.Ka(m,function(b){return r||b===n||null===b||!a.a.c(b._destroy)}),d.has("optionsCaption")&&(m=a.a.c(d.get("optionsCaption")),null!==m&&m!==n&&q.unshift(L)));var A=!1;c.beforeRemove=function(a){b.removeChild(a)};
  152851. m=g;d.has("optionsAfterRender")&&"function"==typeof d.get("optionsAfterRender")&&(m=function(b,c){g(0,c);a.l.w(d.get("optionsAfterRender"),null,[c[0],b!==L?b:n])});a.a.Bb(b,q,function(c,e,g){g.length&&(p=!h&&g[0].selected?[a.j.u(g[0])]:[],A=!0);e=b.ownerDocument.createElement("option");c===L?(a.a.Za(e,d.get("optionsCaption")),a.j.ha(e,n)):(g=f(c,d.get("optionsValue"),c),a.j.ha(e,a.a.c(g)),c=f(c,d.get("optionsText"),g),a.a.Za(e,c));return[e]},c,m);a.l.w(function(){h?a.j.ha(b,a.a.c(d.get("value")),
  152852. !0):(k?p.length&&e().length<p.length:p.length&&0<=b.selectedIndex?a.j.u(b.options[b.selectedIndex])!==p[0]:p.length||0<=b.selectedIndex)&&a.a.Da(b,"change")});a.a.Nc(b);l&&20<Math.abs(l-b.scrollTop)&&(b.scrollTop=l)}};a.d.options.xb=a.a.e.I();a.d.selectedOptions={after:["options","foreach"],init:function(b,c,d){a.a.p(b,"change",function(){var e=c(),f=[];a.a.q(b.getElementsByTagName("option"),function(b){b.selected&&f.push(a.j.u(b))});a.h.Ea(e,d,"selectedOptions",f)})},update:function(b,c){if("select"!=
  152853. a.a.A(b))throw Error("values binding applies only to SELECT elements");var d=a.a.c(c()),e=b.scrollTop;d&&"number"==typeof d.length&&a.a.q(b.getElementsByTagName("option"),function(b){var c=0<=a.a.o(d,a.j.u(b));b.selected!=c&&a.a.sc(b,c)});b.scrollTop=e}};a.h.ea.selectedOptions=!0;a.d.style={update:function(b,c){var d=a.a.c(c()||{});a.a.D(d,function(c,d){d=a.a.c(d);if(null===d||d===n||!1===d)d="";b.style[c]=d})}};a.d.submit={init:function(b,c,d,e,f){if("function"!=typeof c())throw Error("The value for a submit binding must be a function");
  152854. a.a.p(b,"submit",function(a){var d,e=c();try{d=e.call(f.$data,b)}finally{!0!==d&&(a.preventDefault?a.preventDefault():a.returnValue=!1)}})}};a.d.text={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.Za(b,c())}};a.f.Z.text=!0;(function(){if(x&&x.navigator)var b=function(a){if(a)return parseFloat(a[1])},c=x.opera&&x.opera.version&&parseInt(x.opera.version()),d=x.navigator.userAgent,e=b(d.match(/^(?:(?!chrome).)*version\/([^ ]*) safari/i)),f=b(d.match(/Firefox\/([^ ]*)/));
  152855. if(10>a.a.C)var g=a.a.e.I(),k=a.a.e.I(),l=function(b){var c=this.activeElement;(c=c&&a.a.e.get(c,k))&&c(b)},m=function(b,c){var d=b.ownerDocument;a.a.e.get(d,g)||(a.a.e.set(d,g,!0),a.a.p(d,"selectionchange",l));a.a.e.set(b,k,c)};a.d.textInput={init:function(b,d,g){function l(c,d){a.a.p(b,c,d)}function k(){var c=a.a.c(d());if(null===c||c===n)c="";v!==n&&c===v?a.a.setTimeout(k,4):b.value!==c&&(u=c,b.value=c)}function y(){s||(v=b.value,s=a.a.setTimeout(t,4))}function t(){clearTimeout(s);v=s=n;var c=
  152856. b.value;u!==c&&(u=c,a.h.Ea(d(),g,"textInput",c))}var u=b.value,s,v,x=9==a.a.C?y:t;10>a.a.C?(l("propertychange",function(a){"value"===a.propertyName&&x(a)}),8==a.a.C&&(l("keyup",t),l("keydown",t)),8<=a.a.C&&(m(b,x),l("dragend",y))):(l("input",t),5>e&&"textarea"===a.a.A(b)?(l("keydown",y),l("paste",y),l("cut",y)):11>c?l("keydown",y):4>f&&(l("DOMAutoComplete",t),l("dragdrop",t),l("drop",t)));l("change",t);a.m(k,null,{i:b})}};a.h.ea.textInput=!0;a.d.textinput={preprocess:function(a,b,c){c("textInput",
  152857. a)}}})();a.d.uniqueName={init:function(b,c){if(c()){var d="ko_unique_"+ ++a.d.uniqueName.Ic;a.a.rc(b,d)}}};a.d.uniqueName.Ic=0;a.d.value={after:["options","foreach"],init:function(b,c,d){if("input"!=b.tagName.toLowerCase()||"checkbox"!=b.type&&"radio"!=b.type){var e=["change"],f=d.get("valueUpdate"),g=!1,k=null;f&&("string"==typeof f&&(f=[f]),a.a.ra(e,f),e=a.a.Tb(e));var l=function(){k=null;g=!1;var e=c(),f=a.j.u(b);a.h.Ea(e,d,"value",f)};!a.a.C||"input"!=b.tagName.toLowerCase()||"text"!=b.type||
  152858. "off"==b.autocomplete||b.form&&"off"==b.form.autocomplete||-1!=a.a.o(e,"propertychange")||(a.a.p(b,"propertychange",function(){g=!0}),a.a.p(b,"focus",function(){g=!1}),a.a.p(b,"blur",function(){g&&l()}));a.a.q(e,function(c){var d=l;a.a.nd(c,"after")&&(d=function(){k=a.j.u(b);a.a.setTimeout(l,0)},c=c.substring(5));a.a.p(b,c,d)});var m=function(){var e=a.a.c(c()),f=a.j.u(b);if(null!==k&&e===k)a.a.setTimeout(m,0);else if(e!==f)if("select"===a.a.A(b)){var g=d.get("valueAllowUnset"),f=function(){a.j.ha(b,
  152859. e,g)};f();g||e===a.j.u(b)?a.a.setTimeout(f,0):a.l.w(a.a.Da,null,[b,"change"])}else a.j.ha(b,e)};a.m(m,null,{i:b})}else a.Ja(b,{checkedValue:c})},update:function(){}};a.h.ea.value=!0;a.d.visible={update:function(b,c){var d=a.a.c(c()),e="none"!=b.style.display;d&&!e?b.style.display="":!d&&e&&(b.style.display="none")}};(function(b){a.d[b]={init:function(c,d,e,f,g){return a.d.event.init.call(this,c,function(){var a={};a[b]=d();return a},e,f,g)}}})("click");a.O=function(){};a.O.prototype.renderTemplateSource=
  152860. function(){throw Error("Override renderTemplateSource");};a.O.prototype.createJavaScriptEvaluatorBlock=function(){throw Error("Override createJavaScriptEvaluatorBlock");};a.O.prototype.makeTemplateSource=function(b,c){if("string"==typeof b){c=c||u;var d=c.getElementById(b);if(!d)throw Error("Cannot find template with ID "+b);return new a.v.n(d)}if(1==b.nodeType||8==b.nodeType)return new a.v.qa(b);throw Error("Unknown template type: "+b);};a.O.prototype.renderTemplate=function(a,c,d,e){a=this.makeTemplateSource(a,
  152861. e);return this.renderTemplateSource(a,c,d,e)};a.O.prototype.isTemplateRewritten=function(a,c){return!1===this.allowTemplateRewriting?!0:this.makeTemplateSource(a,c).data("isRewritten")};a.O.prototype.rewriteTemplate=function(a,c,d){a=this.makeTemplateSource(a,d);c=c(a.text());a.text(c);a.data("isRewritten",!0)};a.b("templateEngine",a.O);a.Gb=function(){function b(b,c,d,k){b=a.h.yb(b);for(var l=a.h.ta,m=0;m<b.length;m++){var h=b[m].key;if(l.hasOwnProperty(h)){var r=l[h];if("function"===typeof r){if(h=
  152862. r(b[m].value))throw Error(h);}else if(!r)throw Error("This template engine does not support the '"+h+"' binding within its templates");}}d="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+a.h.Ua(b,{valueAccessors:!0})+" } })()},'"+d.toLowerCase()+"')";return k.createJavaScriptEvaluatorBlock(d)+c}var c=/(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'|[^>]*))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi,d=/\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;return{Oc:function(b,
  152863. c,d){c.isTemplateRewritten(b,d)||c.rewriteTemplate(b,function(b){return a.Gb.dd(b,c)},d)},dd:function(a,f){return a.replace(c,function(a,c,d,e,h){return b(h,c,d,f)}).replace(d,function(a,c){return b(c,"\x3c!-- ko --\x3e","#comment",f)})},Ec:function(b,c){return a.M.wb(function(d,k){var l=d.nextSibling;l&&l.nodeName.toLowerCase()===c&&a.Ja(l,b,k)})}}}();a.b("__tr_ambtns",a.Gb.Ec);(function(){a.v={};a.v.n=function(b){if(this.n=b){var c=a.a.A(b);this.ab="script"===c?1:"textarea"===c?2:"template"==c&&
  152864. b.content&&11===b.content.nodeType?3:4}};a.v.n.prototype.text=function(){var b=1===this.ab?"text":2===this.ab?"value":"innerHTML";if(0==arguments.length)return this.n[b];var c=arguments[0];"innerHTML"===b?a.a.Cb(this.n,c):this.n[b]=c};var b=a.a.e.I()+"_";a.v.n.prototype.data=function(c){if(1===arguments.length)return a.a.e.get(this.n,b+c);a.a.e.set(this.n,b+c,arguments[1])};var c=a.a.e.I();a.v.n.prototype.nodes=function(){var b=this.n;if(0==arguments.length)return(a.a.e.get(b,c)||{}).jb||(3===this.ab?
  152865. b.content:4===this.ab?b:n);a.a.e.set(b,c,{jb:arguments[0]})};a.v.qa=function(a){this.n=a};a.v.qa.prototype=new a.v.n;a.v.qa.prototype.text=function(){if(0==arguments.length){var b=a.a.e.get(this.n,c)||{};b.Hb===n&&b.jb&&(b.Hb=b.jb.innerHTML);return b.Hb}a.a.e.set(this.n,c,{Hb:arguments[0]})};a.b("templateSources",a.v);a.b("templateSources.domElement",a.v.n);a.b("templateSources.anonymousTemplate",a.v.qa)})();(function(){function b(b,c,d){var e;for(c=a.f.nextSibling(c);b&&(e=b)!==c;)b=a.f.nextSibling(e),
  152866. d(e,b)}function c(c,d){if(c.length){var e=c[0],f=c[c.length-1],g=e.parentNode,k=a.Q.instance,n=k.preprocessNode;if(n){b(e,f,function(a,b){var c=a.previousSibling,d=n.call(k,a);d&&(a===e&&(e=d[0]||b),a===f&&(f=d[d.length-1]||c))});c.length=0;if(!e)return;e===f?c.push(e):(c.push(e,f),a.a.za(c,g))}b(e,f,function(b){1!==b.nodeType&&8!==b.nodeType||a.Rb(d,b)});b(e,f,function(b){1!==b.nodeType&&8!==b.nodeType||a.M.yc(b,[d])});a.a.za(c,g)}}function d(a){return a.nodeType?a:0<a.length?a[0]:null}function e(b,
  152867. e,f,k,q){q=q||{};var p=(b&&d(b)||f||{}).ownerDocument,n=q.templateEngine||g;a.Gb.Oc(f,n,p);f=n.renderTemplate(f,k,q,p);if("number"!=typeof f.length||0<f.length&&"number"!=typeof f[0].nodeType)throw Error("Template engine must return an array of DOM nodes");p=!1;switch(e){case "replaceChildren":a.f.da(b,f);p=!0;break;case "replaceNode":a.a.qc(b,f);p=!0;break;case "ignoreTargetNode":break;default:throw Error("Unknown renderMode: "+e);}p&&(c(f,k),q.afterRender&&a.l.w(q.afterRender,null,[f,k.$data]));
  152868. return f}function f(b,c,d){return a.H(b)?b():"function"===typeof b?b(c,d):b}var g;a.Db=function(b){if(b!=n&&!(b instanceof a.O))throw Error("templateEngine must inherit from ko.templateEngine");g=b};a.Ab=function(b,c,h,k,q){h=h||{};if((h.templateEngine||g)==n)throw Error("Set a template engine before calling renderTemplate");q=q||"replaceChildren";if(k){var p=d(k);return a.B(function(){var g=c&&c instanceof a.U?c:new a.U(a.a.c(c)),n=f(b,g.$data,g),g=e(k,q,n,g,h);"replaceNode"==q&&(k=g,p=d(k))},null,
  152869. {wa:function(){return!p||!a.a.nb(p)},i:p&&"replaceNode"==q?p.parentNode:p})}return a.M.wb(function(d){a.Ab(b,c,h,d,"replaceNode")})};a.kd=function(b,d,g,k,q){function p(a,b){c(b,s);g.afterRender&&g.afterRender(b,a);s=null}function u(a,c){s=q.createChildContext(a,g.as,function(a){a.$index=c});var d=f(b,a,s);return e(null,"ignoreTargetNode",d,s,g)}var s;return a.B(function(){var b=a.a.c(d)||[];"undefined"==typeof b.length&&(b=[b]);b=a.a.Ka(b,function(b){return g.includeDestroyed||b===n||null===b||!a.a.c(b._destroy)});
  152870. a.l.w(a.a.Bb,null,[k,b,u,g,p])},null,{i:k})};var k=a.a.e.I();a.d.template={init:function(b,c){var d=a.a.c(c());if("string"==typeof d||d.name)a.f.xa(b);else{if("nodes"in d){if(d=d.nodes||[],a.H(d))throw Error('The "nodes" option must be a plain, non-observable array.');}else d=a.f.childNodes(b);d=a.a.jc(d);(new a.v.qa(b)).nodes(d)}return{controlsDescendantBindings:!0}},update:function(b,c,d,e,f){var g=c(),s;c=a.a.c(g);d=!0;e=null;"string"==typeof c?c={}:(g=c.name,"if"in c&&(d=a.a.c(c["if"])),d&&"ifnot"in
  152871. c&&(d=!a.a.c(c.ifnot)),s=a.a.c(c.data));"foreach"in c?e=a.kd(g||b,d&&c.foreach||[],c,b,f):d?(f="data"in c?f.createChildContext(s,c.as):f,e=a.Ab(g||b,f,c,b)):a.f.xa(b);f=e;(s=a.a.e.get(b,k))&&"function"==typeof s.k&&s.k();a.a.e.set(b,k,f&&f.ba()?f:n)}};a.h.ta.template=function(b){b=a.h.yb(b);return 1==b.length&&b[0].unknown||a.h.ad(b,"name")?null:"This template engine does not support anonymous templates nested within its templates"};a.f.Z.template=!0})();a.b("setTemplateEngine",a.Db);a.b("renderTemplate",
  152872. a.Ab);a.a.dc=function(a,c,d){if(a.length&&c.length){var e,f,g,k,l;for(e=f=0;(!d||e<d)&&(k=a[f]);++f){for(g=0;l=c[g];++g)if(k.value===l.value){k.moved=l.index;l.moved=k.index;c.splice(g,1);e=g=0;break}e+=g}}};a.a.ib=function(){function b(b,d,e,f,g){var k=Math.min,l=Math.max,m=[],h,n=b.length,q,p=d.length,s=p-n||1,u=n+p+1,t,v,x;for(h=0;h<=n;h++)for(v=t,m.push(t=[]),x=k(p,h+s),q=l(0,h-1);q<=x;q++)t[q]=q?h?b[h-1]===d[q-1]?v[q-1]:k(v[q]||u,t[q-1]||u)+1:q+1:h+1;k=[];l=[];s=[];h=n;for(q=p;h||q;)p=m[h][q]-
  152873. 1,q&&p===m[h][q-1]?l.push(k[k.length]={status:e,value:d[--q],index:q}):h&&p===m[h-1][q]?s.push(k[k.length]={status:f,value:b[--h],index:h}):(--q,--h,g.sparse||k.push({status:"retained",value:d[q]}));a.a.dc(s,l,!g.dontLimitMoves&&10*n);return k.reverse()}return function(a,d,e){e="boolean"===typeof e?{dontLimitMoves:e}:e||{};a=a||[];d=d||[];return a.length<d.length?b(a,d,"added","deleted",e):b(d,a,"deleted","added",e)}}();a.b("utils.compareArrays",a.a.ib);(function(){function b(b,c,d,k,l){var m=[],
  152874. h=a.B(function(){var h=c(d,l,a.a.za(m,b))||[];0<m.length&&(a.a.qc(m,h),k&&a.l.w(k,null,[d,h,l]));m.length=0;a.a.ra(m,h)},null,{i:b,wa:function(){return!a.a.Qb(m)}});return{ca:m,B:h.ba()?h:n}}var c=a.a.e.I(),d=a.a.e.I();a.a.Bb=function(e,f,g,k,l){function m(b,c){w=q[c];v!==c&&(D[b]=w);w.qb(v++);a.a.za(w.ca,e);u.push(w);z.push(w)}function h(b,c){if(b)for(var d=0,e=c.length;d<e;d++)c[d]&&a.a.q(c[d].ca,function(a){b(a,d,c[d].ja)})}f=f||[];k=k||{};var r=a.a.e.get(e,c)===n,q=a.a.e.get(e,c)||[],p=a.a.fb(q,
  152875. function(a){return a.ja}),s=a.a.ib(p,f,k.dontLimitMoves),u=[],t=0,v=0,x=[],z=[];f=[];for(var D=[],p=[],w,C=0,B,E;B=s[C];C++)switch(E=B.moved,B.status){case "deleted":E===n&&(w=q[t],w.B&&(w.B.k(),w.B=n),a.a.za(w.ca,e).length&&(k.beforeRemove&&(u.push(w),z.push(w),w.ja===d?w=null:f[C]=w),w&&x.push.apply(x,w.ca)));t++;break;case "retained":m(C,t++);break;case "added":E!==n?m(C,E):(w={ja:B.value,qb:a.N(v++)},u.push(w),z.push(w),r||(p[C]=w))}a.a.e.set(e,c,u);h(k.beforeMove,D);a.a.q(x,k.beforeRemove?a.$:
  152876. a.removeNode);for(var C=0,r=a.f.firstChild(e),F;w=z[C];C++){w.ca||a.a.extend(w,b(e,g,w.ja,l,w.qb));for(t=0;s=w.ca[t];r=s.nextSibling,F=s,t++)s!==r&&a.f.gc(e,s,F);!w.Wc&&l&&(l(w.ja,w.ca,w.qb),w.Wc=!0)}h(k.beforeRemove,f);for(C=0;C<f.length;++C)f[C]&&(f[C].ja=d);h(k.afterMove,D);h(k.afterAdd,p)}})();a.b("utils.setDomNodeChildrenFromArrayMapping",a.a.Bb);a.W=function(){this.allowTemplateRewriting=!1};a.W.prototype=new a.O;a.W.prototype.renderTemplateSource=function(b,c,d,e){if(c=(9>a.a.C?0:b.nodes)?
  152877. b.nodes():null)return a.a.V(c.cloneNode(!0).childNodes);b=b.text();return a.a.ma(b,e)};a.W.sb=new a.W;a.Db(a.W.sb);a.b("nativeTemplateEngine",a.W);(function(){a.vb=function(){var a=this.$c=function(){if(!v||!v.tmpl)return 0;try{if(0<=v.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();this.renderTemplateSource=function(b,e,f,g){g=g||u;f=f||{};if(2>a)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var k=b.data("precompiled");
  152878. k||(k=b.text()||"",k=v.template(null,"{{ko_with $item.koBindingContext}}"+k+"{{/ko_with}}"),b.data("precompiled",k));b=[e.$data];e=v.extend({koBindingContext:e},f.templateOptions);e=v.tmpl(k,b,e);e.appendTo(g.createElement("div"));v.fragments={};return e};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+a+" })()) }}"};this.addTemplate=function(a,b){u.write("<script type='text/html' id='"+a+"'>"+b+"\x3c/script>")};0<a&&(v.tmpl.tag.ko_code={open:"__.push($1 || '');"},
  152879. v.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};a.vb.prototype=new a.O;var b=new a.vb;0<b.$c&&a.Db(b);a.b("jqueryTmplTemplateEngine",a.vb)})()})})();})();
  152880. /**
  152881. * @license
  152882. * Knockout ES5 plugin - https://github.com/SteveSanderson/knockout-es5
  152883. * Copyright (c) Steve Sanderson
  152884. * MIT license
  152885. */
  152886. define('ThirdParty/knockout-es5',[],function() {
  152887. 'use strict';
  152888. var OBSERVABLES_PROPERTY = '__knockoutObservables';
  152889. var SUBSCRIBABLE_PROPERTY = '__knockoutSubscribable';
  152890. // Model tracking
  152891. // --------------
  152892. //
  152893. // This is the central feature of Knockout-ES5. We augment model objects by converting properties
  152894. // into ES5 getter/setter pairs that read/write an underlying Knockout observable. This means you can
  152895. // use plain JavaScript syntax to read/write the property while still getting the full benefits of
  152896. // Knockout's automatic dependency detection and notification triggering.
  152897. //
  152898. // For comparison, here's Knockout ES3-compatible syntax:
  152899. //
  152900. // var firstNameLength = myModel.user().firstName().length; // Read
  152901. // myModel.user().firstName('Bert'); // Write
  152902. //
  152903. // ... versus Knockout-ES5 syntax:
  152904. //
  152905. // var firstNameLength = myModel.user.firstName.length; // Read
  152906. // myModel.user.firstName = 'Bert'; // Write
  152907. // `ko.track(model)` converts each property on the given model object into a getter/setter pair that
  152908. // wraps a Knockout observable. Optionally specify an array of property names to wrap; otherwise we
  152909. // wrap all properties. If any of the properties are already observables, we replace them with
  152910. // ES5 getter/setter pairs that wrap your original observable instances. In the case of readonly
  152911. // ko.computed properties, we simply do not define a setter (so attempted writes will be ignored,
  152912. // which is how ES5 readonly properties normally behave).
  152913. //
  152914. // By design, this does *not* recursively walk child object properties, because making literally
  152915. // everything everywhere independently observable is usually unhelpful. When you do want to track
  152916. // child object properties independently, define your own class for those child objects and put
  152917. // a separate ko.track call into its constructor --- this gives you far more control.
  152918. function track(obj, propertyNames) {
  152919. if (!obj /*|| typeof obj !== 'object'*/) {
  152920. throw new Error('When calling ko.track, you must pass an object as the first parameter.');
  152921. }
  152922. var ko = this,
  152923. allObservablesForObject = getAllObservablesForObject(obj, true);
  152924. propertyNames = propertyNames || Object.getOwnPropertyNames(obj);
  152925. propertyNames.forEach(function(propertyName) {
  152926. // Skip storage properties
  152927. if (propertyName === OBSERVABLES_PROPERTY || propertyName === SUBSCRIBABLE_PROPERTY) {
  152928. return;
  152929. }
  152930. // Skip properties that are already tracked
  152931. if (propertyName in allObservablesForObject) {
  152932. return;
  152933. }
  152934. var origValue = obj[propertyName],
  152935. isArray = origValue instanceof Array,
  152936. observable = ko.isObservable(origValue) ? origValue
  152937. : isArray ? ko.observableArray(origValue)
  152938. : ko.observable(origValue);
  152939. Object.defineProperty(obj, propertyName, {
  152940. configurable: true,
  152941. enumerable: true,
  152942. get: observable,
  152943. set: ko.isWriteableObservable(observable) ? observable : undefined
  152944. });
  152945. allObservablesForObject[propertyName] = observable;
  152946. if (isArray) {
  152947. notifyWhenPresentOrFutureArrayValuesMutate(ko, observable);
  152948. }
  152949. });
  152950. return obj;
  152951. }
  152952. // Gets or creates the hidden internal key-value collection of observables corresponding to
  152953. // properties on the model object.
  152954. function getAllObservablesForObject(obj, createIfNotDefined) {
  152955. var result = obj[OBSERVABLES_PROPERTY];
  152956. if (!result && createIfNotDefined) {
  152957. result = {};
  152958. Object.defineProperty(obj, OBSERVABLES_PROPERTY, {
  152959. value : result
  152960. });
  152961. }
  152962. return result;
  152963. }
  152964. // Computed properties
  152965. // -------------------
  152966. //
  152967. // The preceding code is already sufficient to upgrade ko.computed model properties to ES5
  152968. // getter/setter pairs (or in the case of readonly ko.computed properties, just a getter).
  152969. // These then behave like a regular property with a getter function, except they are smarter:
  152970. // your evaluator is only invoked when one of its dependencies changes. The result is cached
  152971. // and used for all evaluations until the next time a dependency changes).
  152972. //
  152973. // However, instead of forcing developers to declare a ko.computed property explicitly, it's
  152974. // nice to offer a utility function that declares a computed getter directly.
  152975. // Implements `ko.defineProperty`
  152976. function defineComputedProperty(obj, propertyName, evaluatorOrOptions) {
  152977. var ko = this,
  152978. computedOptions = { owner: obj, deferEvaluation: true };
  152979. if (typeof evaluatorOrOptions === 'function') {
  152980. computedOptions.read = evaluatorOrOptions;
  152981. } else {
  152982. if ('value' in evaluatorOrOptions) {
  152983. throw new Error('For ko.defineProperty, you must not specify a "value" for the property. You must provide a "get" function.');
  152984. }
  152985. if (typeof evaluatorOrOptions.get !== 'function') {
  152986. throw new Error('For ko.defineProperty, the third parameter must be either an evaluator function, or an options object containing a function called "get".');
  152987. }
  152988. computedOptions.read = evaluatorOrOptions.get;
  152989. computedOptions.write = evaluatorOrOptions.set;
  152990. }
  152991. obj[propertyName] = ko.computed(computedOptions);
  152992. track.call(ko, obj, [propertyName]);
  152993. return obj;
  152994. }
  152995. // Array handling
  152996. // --------------
  152997. //
  152998. // Arrays are special, because unlike other property types, they have standard mutator functions
  152999. // (`push`/`pop`/`splice`/etc.) and it's desirable to trigger a change notification whenever one of
  153000. // those mutator functions is invoked.
  153001. //
  153002. // Traditionally, Knockout handles this by putting special versions of `push`/`pop`/etc. on observable
  153003. // arrays that mutate the underlying array and then trigger a notification. That approach doesn't
  153004. // work for Knockout-ES5 because properties now return the underlying arrays, so the mutator runs
  153005. // in the context of the underlying array, not any particular observable:
  153006. //
  153007. // // Operates on the underlying array value
  153008. // myModel.someCollection.push('New value');
  153009. //
  153010. // To solve this, Knockout-ES5 detects array values, and modifies them as follows:
  153011. // 1. Associates a hidden subscribable with each array instance that it encounters
  153012. // 2. Intercepts standard mutators (`push`/`pop`/etc.) and makes them trigger the subscribable
  153013. // Then, for model properties whose values are arrays, the property's underlying observable
  153014. // subscribes to the array subscribable, so it can trigger a change notification after mutation.
  153015. // Given an observable that underlies a model property, watch for any array value that might
  153016. // be assigned as the property value, and hook into its change events
  153017. function notifyWhenPresentOrFutureArrayValuesMutate(ko, observable) {
  153018. var watchingArraySubscription = null;
  153019. ko.computed(function () {
  153020. // Unsubscribe to any earlier array instance
  153021. if (watchingArraySubscription) {
  153022. watchingArraySubscription.dispose();
  153023. watchingArraySubscription = null;
  153024. }
  153025. // Subscribe to the new array instance
  153026. var newArrayInstance = observable();
  153027. if (newArrayInstance instanceof Array) {
  153028. watchingArraySubscription = startWatchingArrayInstance(ko, observable, newArrayInstance);
  153029. }
  153030. });
  153031. }
  153032. // Listens for array mutations, and when they happen, cause the observable to fire notifications.
  153033. // This is used to make model properties of type array fire notifications when the array changes.
  153034. // Returns a subscribable that can later be disposed.
  153035. function startWatchingArrayInstance(ko, observable, arrayInstance) {
  153036. var subscribable = getSubscribableForArray(ko, arrayInstance);
  153037. return subscribable.subscribe(observable);
  153038. }
  153039. // Gets or creates a subscribable that fires after each array mutation
  153040. function getSubscribableForArray(ko, arrayInstance) {
  153041. var subscribable = arrayInstance[SUBSCRIBABLE_PROPERTY];
  153042. if (!subscribable) {
  153043. subscribable = new ko.subscribable();
  153044. Object.defineProperty(arrayInstance, SUBSCRIBABLE_PROPERTY, {
  153045. value : subscribable
  153046. });
  153047. var notificationPauseSignal = {};
  153048. wrapStandardArrayMutators(arrayInstance, subscribable, notificationPauseSignal);
  153049. addKnockoutArrayMutators(ko, arrayInstance, subscribable, notificationPauseSignal);
  153050. }
  153051. return subscribable;
  153052. }
  153053. // After each array mutation, fires a notification on the given subscribable
  153054. function wrapStandardArrayMutators(arrayInstance, subscribable, notificationPauseSignal) {
  153055. ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'].forEach(function(fnName) {
  153056. var origMutator = arrayInstance[fnName];
  153057. arrayInstance[fnName] = function() {
  153058. var result = origMutator.apply(this, arguments);
  153059. if (notificationPauseSignal.pause !== true) {
  153060. subscribable.notifySubscribers(this);
  153061. }
  153062. return result;
  153063. };
  153064. });
  153065. }
  153066. // Adds Knockout's additional array mutation functions to the array
  153067. function addKnockoutArrayMutators(ko, arrayInstance, subscribable, notificationPauseSignal) {
  153068. ['remove', 'removeAll', 'destroy', 'destroyAll', 'replace'].forEach(function(fnName) {
  153069. // Make it a non-enumerable property for consistency with standard Array functions
  153070. Object.defineProperty(arrayInstance, fnName, {
  153071. enumerable: false,
  153072. value: function() {
  153073. var result;
  153074. // These additional array mutators are built using the underlying push/pop/etc.
  153075. // mutators, which are wrapped to trigger notifications. But we don't want to
  153076. // trigger multiple notifications, so pause the push/pop/etc. wrappers and
  153077. // delivery only one notification at the end of the process.
  153078. notificationPauseSignal.pause = true;
  153079. try {
  153080. // Creates a temporary observableArray that can perform the operation.
  153081. result = ko.observableArray.fn[fnName].apply(ko.observableArray(arrayInstance), arguments);
  153082. }
  153083. finally {
  153084. notificationPauseSignal.pause = false;
  153085. }
  153086. subscribable.notifySubscribers(arrayInstance);
  153087. return result;
  153088. }
  153089. });
  153090. });
  153091. }
  153092. // Static utility functions
  153093. // ------------------------
  153094. //
  153095. // Since Knockout-ES5 sets up properties that return values, not observables, you can't
  153096. // trivially subscribe to the underlying observables (e.g., `someProperty.subscribe(...)`),
  153097. // or tell them that object values have mutated, etc. To handle this, we set up some
  153098. // extra utility functions that can return or work with the underlying observables.
  153099. // Returns the underlying observable associated with a model property (or `null` if the
  153100. // model or property doesn't exist, or isn't associated with an observable). This means
  153101. // you can subscribe to the property, e.g.:
  153102. //
  153103. // ko.getObservable(model, 'propertyName')
  153104. // .subscribe(function(newValue) { ... });
  153105. function getObservable(obj, propertyName) {
  153106. if (!obj /*|| typeof obj !== 'object'*/) {
  153107. return null;
  153108. }
  153109. var allObservablesForObject = getAllObservablesForObject(obj, false);
  153110. return (allObservablesForObject && allObservablesForObject[propertyName]) || null;
  153111. }
  153112. // Causes a property's associated observable to fire a change notification. Useful when
  153113. // the property value is a complex object and you've modified a child property.
  153114. function valueHasMutated(obj, propertyName) {
  153115. var observable = getObservable(obj, propertyName);
  153116. if (observable) {
  153117. observable.valueHasMutated();
  153118. }
  153119. }
  153120. // Extends a Knockout instance with Knockout-ES5 functionality
  153121. function attachToKo(ko) {
  153122. ko.track = track;
  153123. ko.getObservable = getObservable;
  153124. ko.valueHasMutated = valueHasMutated;
  153125. ko.defineProperty = defineComputedProperty;
  153126. }
  153127. return {
  153128. attachToKo : attachToKo
  153129. };
  153130. });
  153131. /*global define*/
  153132. define('Widgets/SvgPathBindingHandler',[],function() {
  153133. 'use strict';
  153134. var svgNS = 'http://www.w3.org/2000/svg';
  153135. var svgClassName = 'cesium-svgPath-svg';
  153136. /**
  153137. * A Knockout binding handler that creates a DOM element for a single SVG path.
  153138. * This binding handler will be registered as cesiumSvgPath.
  153139. *
  153140. * <p>
  153141. * The parameter to this binding is an object with the following properties:
  153142. * </p>
  153143. *
  153144. * <ul>
  153145. * <li>path: The SVG path as a string.</li>
  153146. * <li>width: The width of the SVG path with no transformations applied.</li>
  153147. * <li>height: The height of the SVG path with no transformations applied.</li>
  153148. * <li>css: Optional. A string containing additional CSS classes to apply to the SVG. 'cesium-svgPath-svg' is always applied.</li>
  153149. * </ul>
  153150. *
  153151. * @exports SvgPathBindingHandler
  153152. *
  153153. * @example
  153154. * // Create an SVG as a child of a div
  153155. * <div data-bind="cesiumSvgPath: { path: 'M 100 100 L 300 100 L 200 300 z', width: 28, height: 28 }"></div>
  153156. *
  153157. * // parameters can be observable from the view model
  153158. * <div data-bind="cesiumSvgPath: { path: currentPath, width: currentWidth, height: currentHeight }"></div>
  153159. *
  153160. * // or the whole object can be observable from the view model
  153161. * <div data-bind="cesiumSvgPath: svgPathOptions"></div>
  153162. */
  153163. var SvgPathBindingHandler = {
  153164. register : function(knockout) {
  153165. knockout.bindingHandlers.cesiumSvgPath = {
  153166. init : function(element, valueAccessor) {
  153167. var svg = document.createElementNS(svgNS, 'svg:svg');
  153168. svg.setAttribute('class', svgClassName);
  153169. var pathElement = document.createElementNS(svgNS, 'path');
  153170. svg.appendChild(pathElement);
  153171. knockout.virtualElements.setDomNodeChildren(element, [svg]);
  153172. knockout.computed({
  153173. read : function() {
  153174. var value = knockout.unwrap(valueAccessor());
  153175. pathElement.setAttribute('d', knockout.unwrap(value.path));
  153176. var pathWidth = knockout.unwrap(value.width);
  153177. var pathHeight = knockout.unwrap(value.height);
  153178. svg.setAttribute('width', pathWidth);
  153179. svg.setAttribute('height', pathHeight);
  153180. svg.setAttribute('viewBox', '0 0 ' + pathWidth + ' ' + pathHeight);
  153181. if (value.css) {
  153182. svg.setAttribute('class', svgClassName + ' ' + knockout.unwrap(value.css));
  153183. }
  153184. },
  153185. disposeWhenNodeIsRemoved : element
  153186. });
  153187. return {
  153188. controlsDescendantBindings : true
  153189. };
  153190. }
  153191. };
  153192. knockout.virtualElements.allowedBindings.cesiumSvgPath = true;
  153193. }
  153194. };
  153195. return SvgPathBindingHandler;
  153196. });
  153197. /*global define*/
  153198. define('ThirdParty/knockout',[
  153199. './knockout-3.4.0',
  153200. './knockout-es5',
  153201. '../Widgets/SvgPathBindingHandler'
  153202. ], function(
  153203. knockout,
  153204. knockout_es5,
  153205. SvgPathBindingHandler) {
  153206. "use strict";
  153207. // install the Knockout-ES5 plugin
  153208. knockout_es5.attachToKo(knockout);
  153209. // Register all Cesium binding handlers
  153210. SvgPathBindingHandler.register(knockout);
  153211. return knockout;
  153212. });
  153213. /**
  153214. * @license
  153215. * NoSleep.js v0.5.0 - git.io/vfn01
  153216. * Rich Tibbett
  153217. * MIT license
  153218. **/
  153219. /*global define*/
  153220. define('ThirdParty/NoSleep',[],function() {
  153221. "use strict";
  153222. // UA matching
  153223. var ua = {
  153224. Android: typeof navigator !== 'undefined' && /Android/ig.test(navigator.userAgent),
  153225. iOS: typeof navigator !== 'undefined' && /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent)
  153226. };
  153227. var media = {
  153228. WebM: "data:video/webm;base64,GkXfo0AgQoaBAUL3gQFC8oEEQvOBCEKCQAR3ZWJtQoeBAkKFgQIYU4BnQI0VSalmQCgq17FAAw9CQE2AQAZ3aGFtbXlXQUAGd2hhbW15RIlACECPQAAAAAAAFlSua0AxrkAu14EBY8WBAZyBACK1nEADdW5khkAFVl9WUDglhohAA1ZQOIOBAeBABrCBCLqBCB9DtnVAIueBAKNAHIEAAIAwAQCdASoIAAgAAUAmJaQAA3AA/vz0AAA=",
  153229. MP4: "data:video/mp4;base64,AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAAhmcmVlAAAAG21kYXQAAAGzABAHAAABthADAowdbb9/AAAC6W1vb3YAAABsbXZoZAAAAAB8JbCAfCWwgAAAA+gAAAAAAAEAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIVdHJhawAAAFx0a2hkAAAAD3wlsIB8JbCAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAIAAAACAAAAAABsW1kaWEAAAAgbWRoZAAAAAB8JbCAfCWwgAAAA+gAAAAAVcQAAAAAAC1oZGxyAAAAAAAAAAB2aWRlAAAAAAAAAAAAAAAAVmlkZW9IYW5kbGVyAAAAAVxtaW5mAAAAFHZtaGQAAAABAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAAEcc3RibAAAALhzdHNkAAAAAAAAAAEAAACobXA0dgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAIAAgASAAAAEgAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABj//wAAAFJlc2RzAAAAAANEAAEABDwgEQAAAAADDUAAAAAABS0AAAGwAQAAAbWJEwAAAQAAAAEgAMSNiB9FAEQBFGMAAAGyTGF2YzUyLjg3LjQGAQIAAAAYc3R0cwAAAAAAAAABAAAAAQAAAAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAEAAAABAAAAFHN0c3oAAAAAAAAAEwAAAAEAAAAUc3RjbwAAAAAAAAABAAAALAAAAGB1ZHRhAAAAWG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAK2lsc3QAAAAjqXRvbwAAABtkYXRhAAAAAQAAAABMYXZmNTIuNzguMw=="
  153230. };
  153231. function addSourceToVideo(element, type, dataURI) {
  153232. var source = document.createElement('source');
  153233. source.src = dataURI;
  153234. source.type = "video/" + type;
  153235. element.appendChild(source);
  153236. }
  153237. // NoSleep instance constructor
  153238. var NoSleep = function() {
  153239. if (ua.iOS) {
  153240. this.noSleepTimer = null;
  153241. } else if (ua.Android) {
  153242. // Set up no sleep video element
  153243. this.noSleepVideo = document.createElement('video');
  153244. this.noSleepVideo.setAttribute("loop", "");
  153245. // Append nosleep video sources
  153246. addSourceToVideo(this.noSleepVideo, "webm", media.WebM);
  153247. addSourceToVideo(this.noSleepVideo, "mp4", media.MP4);
  153248. }
  153249. return this;
  153250. };
  153251. // Enable NoSleep instance
  153252. NoSleep.prototype.enable = function(duration) {
  153253. if (ua.iOS) {
  153254. this.disable();
  153255. this.noSleepTimer = window.setInterval(function() {
  153256. window.location = window.location;
  153257. window.setTimeout(window.stop, 0);
  153258. }, duration || 15000);
  153259. } else if (ua.Android) {
  153260. this.noSleepVideo.play();
  153261. }
  153262. };
  153263. // Disable NoSleep instance
  153264. NoSleep.prototype.disable = function() {
  153265. if (ua.iOS) {
  153266. if (this.noSleepTimer) {
  153267. window.clearInterval(this.noSleepTimer);
  153268. this.noSleepTimer = null;
  153269. }
  153270. } else if (ua.Android) {
  153271. this.noSleepVideo.pause();
  153272. }
  153273. };
  153274. // Append NoSleep API to root object
  153275. //root.NoSleep = NoSleep;
  153276. return NoSleep;
  153277. });
  153278. /*global define*/
  153279. define('Widgets/subscribeAndEvaluate',[
  153280. '../ThirdParty/knockout'
  153281. ], function(
  153282. knockout) {
  153283. 'use strict';
  153284. /**
  153285. * Subscribe to a Knockout observable ES5 property, and immediately fire
  153286. * the callback with the current value of the property.
  153287. *
  153288. * @private
  153289. *
  153290. * @exports subscribeAndEvaluate
  153291. *
  153292. * @param {Object} owner The object containing the observable property.
  153293. * @param {String} observablePropertyName The name of the observable property.
  153294. * @param {Function} callback The callback function.
  153295. * @param {Object} [target] The value of this in the callback function.
  153296. * @param {String} [event='change'] The name of the event to receive notification for.
  153297. * @returns The subscription object from Knockout which can be used to dispose the subscription later.
  153298. */
  153299. function subscribeAndEvaluate(owner, observablePropertyName, callback, target, event) {
  153300. callback.call(target, owner[observablePropertyName]);
  153301. return knockout.getObservable(owner, observablePropertyName).subscribe(callback, target, event);
  153302. }
  153303. return subscribeAndEvaluate;
  153304. });
  153305. /*global define*/
  153306. define('Widgets/Animation/Animation',[
  153307. '../../Core/Color',
  153308. '../../Core/defined',
  153309. '../../Core/defineProperties',
  153310. '../../Core/destroyObject',
  153311. '../../Core/DeveloperError',
  153312. '../getElement',
  153313. '../subscribeAndEvaluate'
  153314. ], function(
  153315. Color,
  153316. defined,
  153317. defineProperties,
  153318. destroyObject,
  153319. DeveloperError,
  153320. getElement,
  153321. subscribeAndEvaluate) {
  153322. 'use strict';
  153323. var svgNS = "http://www.w3.org/2000/svg";
  153324. var xlinkNS = "http://www.w3.org/1999/xlink";
  153325. var widgetForDrag;
  153326. var gradientEnabledColor0 = Color.fromCssColorString('rgba(247,250,255,0.384)');
  153327. var gradientEnabledColor1 = Color.fromCssColorString('rgba(143,191,255,0.216)');
  153328. var gradientEnabledColor2 = Color.fromCssColorString('rgba(153,197,255,0.098)');
  153329. var gradientEnabledColor3 = Color.fromCssColorString('rgba(255,255,255,0.086)');
  153330. var gradientDisabledColor0 = Color.fromCssColorString('rgba(255,255,255,0.267)');
  153331. var gradientDisabledColor1 = Color.fromCssColorString('rgba(255,255,255,0)');
  153332. var gradientKnobColor = Color.fromCssColorString('rgba(66,67,68,0.3)');
  153333. var gradientPointerColor = Color.fromCssColorString('rgba(0,0,0,0.5)');
  153334. function getElementColor(element) {
  153335. return Color.fromCssColorString(window.getComputedStyle(element).getPropertyValue('color'));
  153336. }
  153337. //Dynamically builds an SVG element from a JSON object.
  153338. function svgFromObject(obj) {
  153339. var ele = document.createElementNS(svgNS, obj.tagName);
  153340. for ( var field in obj) {
  153341. if (obj.hasOwnProperty(field) && field !== 'tagName') {
  153342. if (field === 'children') {
  153343. var i;
  153344. var len = obj.children.length;
  153345. for (i = 0; i < len; ++i) {
  153346. ele.appendChild(svgFromObject(obj.children[i]));
  153347. }
  153348. } else if (field.indexOf('xlink:') === 0) {
  153349. ele.setAttributeNS(xlinkNS, field.substring(6), obj[field]);
  153350. } else if (field === 'textContent') {
  153351. ele.textContent = obj[field];
  153352. } else {
  153353. ele.setAttribute(field, obj[field]);
  153354. }
  153355. }
  153356. }
  153357. return ele;
  153358. }
  153359. function svgText(x, y, msg) {
  153360. var text = document.createElementNS(svgNS, 'text');
  153361. text.setAttribute('x', x);
  153362. text.setAttribute('y', y);
  153363. text.setAttribute('class', 'cesium-animation-svgText');
  153364. var tspan = document.createElementNS(svgNS, 'tspan');
  153365. tspan.textContent = msg;
  153366. text.appendChild(tspan);
  153367. return text;
  153368. }
  153369. function setShuttleRingPointer(shuttleRingPointer, knobOuter, angle) {
  153370. shuttleRingPointer.setAttribute('transform', 'translate(100,100) rotate(' + angle + ')');
  153371. knobOuter.setAttribute('transform', 'rotate(' + angle + ')');
  153372. }
  153373. var makeColorStringScratch = new Color();
  153374. function makeColorString(background, gradient) {
  153375. var gradientAlpha = gradient.alpha;
  153376. var backgroundAlpha = 1.0 - gradientAlpha;
  153377. makeColorStringScratch.red = (background.red * backgroundAlpha) + (gradient.red * gradientAlpha);
  153378. makeColorStringScratch.green = (background.green * backgroundAlpha) + (gradient.green * gradientAlpha);
  153379. makeColorStringScratch.blue = (background.blue * backgroundAlpha) + (gradient.blue * gradientAlpha);
  153380. return makeColorStringScratch.toCssColorString();
  153381. }
  153382. function rectButton(x, y, path) {
  153383. var button = {
  153384. tagName : 'g',
  153385. 'class' : 'cesium-animation-rectButton',
  153386. transform : 'translate(' + x + ',' + y + ')',
  153387. children : [{
  153388. tagName : 'rect',
  153389. 'class' : 'cesium-animation-buttonGlow',
  153390. width : 32,
  153391. height : 32,
  153392. rx : 2,
  153393. ry : 2
  153394. }, {
  153395. tagName : 'rect',
  153396. 'class' : 'cesium-animation-buttonMain',
  153397. width : 32,
  153398. height : 32,
  153399. rx : 4,
  153400. ry : 4
  153401. }, {
  153402. tagName : 'use',
  153403. 'class' : 'cesium-animation-buttonPath',
  153404. 'xlink:href' : path
  153405. }, {
  153406. tagName : 'title',
  153407. textContent : ''
  153408. }]
  153409. };
  153410. return svgFromObject(button);
  153411. }
  153412. function wingButton(x, y, path) {
  153413. var button = {
  153414. tagName : 'g',
  153415. 'class' : 'cesium-animation-rectButton',
  153416. transform : 'translate(' + x + ',' + y + ')',
  153417. children : [{
  153418. tagName : 'use',
  153419. 'class' : 'cesium-animation-buttonGlow',
  153420. 'xlink:href' : '#animation_pathWingButton'
  153421. }, {
  153422. tagName : 'use',
  153423. 'class' : 'cesium-animation-buttonMain',
  153424. 'xlink:href' : '#animation_pathWingButton'
  153425. }, {
  153426. tagName : 'use',
  153427. 'class' : 'cesium-animation-buttonPath',
  153428. 'xlink:href' : path
  153429. }, {
  153430. tagName : 'title',
  153431. textContent : ''
  153432. }]
  153433. };
  153434. return svgFromObject(button);
  153435. }
  153436. function setShuttleRingFromMouseOrTouch(widget, e) {
  153437. var viewModel = widget._viewModel;
  153438. var shuttleRingDragging = viewModel.shuttleRingDragging;
  153439. if (shuttleRingDragging && (widgetForDrag !== widget)) {
  153440. return;
  153441. }
  153442. if (e.type === 'mousedown' || (shuttleRingDragging && e.type === 'mousemove') ||
  153443. (e.type === 'touchstart' && e.touches.length === 1) ||
  153444. (shuttleRingDragging && e.type === 'touchmove' && e.touches.length === 1)) {
  153445. var centerX = widget._centerX;
  153446. var centerY = widget._centerY;
  153447. var svg = widget._svgNode;
  153448. var rect = svg.getBoundingClientRect();
  153449. var clientX;
  153450. var clientY;
  153451. if (e.type === 'touchstart' || e.type === 'touchmove') {
  153452. clientX = e.touches[0].clientX;
  153453. clientY = e.touches[0].clientY;
  153454. } else {
  153455. clientX = e.clientX;
  153456. clientY = e.clientY;
  153457. }
  153458. if (!shuttleRingDragging &&
  153459. (clientX > rect.right ||
  153460. clientX < rect.left ||
  153461. clientY < rect.top ||
  153462. clientY > rect.bottom)) {
  153463. return;
  153464. }
  153465. var pointerRect = widget._shuttleRingPointer.getBoundingClientRect();
  153466. var x = clientX - centerX - rect.left;
  153467. var y = clientY - centerY - rect.top;
  153468. var angle = Math.atan2(y, x) * 180 / Math.PI + 90;
  153469. if (angle > 180) {
  153470. angle -= 360;
  153471. }
  153472. var shuttleRingAngle = viewModel.shuttleRingAngle;
  153473. if (shuttleRingDragging || (clientX < pointerRect.right && clientX > pointerRect.left && clientY > pointerRect.top && clientY < pointerRect.bottom)) {
  153474. widgetForDrag = widget;
  153475. viewModel.shuttleRingDragging = true;
  153476. viewModel.shuttleRingAngle = angle;
  153477. } else if (angle < shuttleRingAngle) {
  153478. viewModel.slower();
  153479. } else if (angle > shuttleRingAngle) {
  153480. viewModel.faster();
  153481. }
  153482. e.preventDefault();
  153483. } else {
  153484. if (widget === widgetForDrag) {
  153485. widgetForDrag = undefined;
  153486. }
  153487. viewModel.shuttleRingDragging = false;
  153488. }
  153489. }
  153490. //This is a private class for treating an SVG element like a button.
  153491. //If we ever need a general purpose SVG button, we can make this generic.
  153492. function SvgButton(svgElement, viewModel) {
  153493. this._viewModel = viewModel;
  153494. this.svgElement = svgElement;
  153495. this._enabled = undefined;
  153496. this._toggled = undefined;
  153497. var that = this;
  153498. this._clickFunction = function() {
  153499. var command = that._viewModel.command;
  153500. if (command.canExecute) {
  153501. command();
  153502. }
  153503. };
  153504. svgElement.addEventListener('click', this._clickFunction, true);
  153505. //TODO: Since the animation widget uses SVG and has no HTML backing,
  153506. //we need to wire everything up manually. Knockout can supposedly
  153507. //bind to SVG, so we we figure that out we can modify our SVG
  153508. //to include the binding information directly.
  153509. this._subscriptions = [//
  153510. subscribeAndEvaluate(viewModel, 'toggled', this.setToggled, this),//
  153511. subscribeAndEvaluate(viewModel, 'tooltip', this.setTooltip, this),//
  153512. subscribeAndEvaluate(viewModel.command, 'canExecute', this.setEnabled, this)];
  153513. }
  153514. SvgButton.prototype.destroy = function() {
  153515. this.svgElement.removeEventListener('click', this._clickFunction, true);
  153516. var subscriptions = this._subscriptions;
  153517. for ( var i = 0, len = subscriptions.length; i < len; i++) {
  153518. subscriptions[i].dispose();
  153519. }
  153520. destroyObject(this);
  153521. };
  153522. SvgButton.prototype.isDestroyed = function() {
  153523. return false;
  153524. };
  153525. SvgButton.prototype.setEnabled = function(enabled) {
  153526. if (this._enabled !== enabled) {
  153527. this._enabled = enabled;
  153528. if (!enabled) {
  153529. this.svgElement.setAttribute('class', 'cesium-animation-buttonDisabled');
  153530. return;
  153531. }
  153532. if (this._toggled) {
  153533. this.svgElement.setAttribute('class', 'cesium-animation-rectButton cesium-animation-buttonToggled');
  153534. return;
  153535. }
  153536. this.svgElement.setAttribute('class', 'cesium-animation-rectButton');
  153537. }
  153538. };
  153539. SvgButton.prototype.setToggled = function(toggled) {
  153540. if (this._toggled !== toggled) {
  153541. this._toggled = toggled;
  153542. if (this._enabled) {
  153543. if (toggled) {
  153544. this.svgElement.setAttribute('class', 'cesium-animation-rectButton cesium-animation-buttonToggled');
  153545. } else {
  153546. this.svgElement.setAttribute('class', 'cesium-animation-rectButton');
  153547. }
  153548. }
  153549. }
  153550. };
  153551. SvgButton.prototype.setTooltip = function(tooltip) {
  153552. this.svgElement.getElementsByTagName('title')[0].textContent = tooltip;
  153553. };
  153554. /**
  153555. * <span style="display: block; text-align: center;">
  153556. * <img src="images/AnimationWidget.png" width="211" height="142" alt="" />
  153557. * <br />Animation widget
  153558. * </span>
  153559. * <br /><br />
  153560. * The Animation widget provides buttons for play, pause, and reverse, along with the
  153561. * current time and date, surrounded by a "shuttle ring" for controlling the speed of animation.
  153562. * <br /><br />
  153563. * The "shuttle ring" concept is borrowed from video editing, where typically a
  153564. * "jog wheel" can be rotated to move past individual animation frames very slowly, and
  153565. * a surrounding shuttle ring can be twisted to control direction and speed of fast playback.
  153566. * Cesium typically treats time as continuous (not broken into pre-defined animation frames),
  153567. * so this widget offers no jog wheel. Instead, the shuttle ring is capable of both fast and
  153568. * very slow playback. Click and drag the shuttle ring pointer itself (shown above in green),
  153569. * or click in the rest of the ring area to nudge the pointer to the next preset speed in that direction.
  153570. * <br /><br />
  153571. * The Animation widget also provides a "realtime" button (in the upper-left) that keeps
  153572. * animation time in sync with the end user's system clock, typically displaying
  153573. * "today" or "right now." This mode is not available in {@link ClockRange.CLAMPED} or
  153574. * {@link ClockRange.LOOP_STOP} mode if the current time is outside of {@link Clock}'s startTime and endTime.
  153575. *
  153576. * @alias Animation
  153577. * @constructor
  153578. *
  153579. * @param {Element|String} container The DOM element or ID that will contain the widget.
  153580. * @param {AnimationViewModel} viewModel The view model used by this widget.
  153581. *
  153582. * @exception {DeveloperError} Element with id "container" does not exist in the document.
  153583. *
  153584. *
  153585. * @example
  153586. * // In HTML head, include a link to Animation.css stylesheet,
  153587. * // and in the body, include: <div id="animationContainer"></div>
  153588. *
  153589. * var clock = new Cesium.Clock();
  153590. * var clockViewModel = new Cesium.ClockViewModel(clock);
  153591. * var viewModel = new Cesium.AnimationViewModel(clockViewModel);
  153592. * var widget = new Cesium.Animation('animationContainer', viewModel);
  153593. *
  153594. * function tick() {
  153595. * clock.tick();
  153596. * Cesium.requestAnimationFrame(tick);
  153597. * }
  153598. * Cesium.requestAnimationFrame(tick);
  153599. *
  153600. * @see AnimationViewModel
  153601. * @see Clock
  153602. */
  153603. function Animation(container, viewModel) {
  153604. if (!defined(container)) {
  153605. throw new DeveloperError('container is required.');
  153606. }
  153607. if (!defined(viewModel)) {
  153608. throw new DeveloperError('viewModel is required.');
  153609. }
  153610. container = getElement(container);
  153611. this._viewModel = viewModel;
  153612. this._container = container;
  153613. this._centerX = 0;
  153614. this._centerY = 0;
  153615. this._defsElement = undefined;
  153616. this._svgNode = undefined;
  153617. this._topG = undefined;
  153618. this._lastHeight = undefined;
  153619. this._lastWidth = undefined;
  153620. // Firefox requires SVG references to be included directly, not imported from external CSS.
  153621. // Also, CSS minifiers get confused by this being in an external CSS file.
  153622. var cssStyle = document.createElement('style');
  153623. cssStyle.textContent = '.cesium-animation-rectButton .cesium-animation-buttonGlow { filter: url(#animation_blurred); }\
  153624. .cesium-animation-rectButton .cesium-animation-buttonMain { fill: url(#animation_buttonNormal); }\
  153625. .cesium-animation-buttonToggled .cesium-animation-buttonMain { fill: url(#animation_buttonToggled); }\
  153626. .cesium-animation-rectButton:hover .cesium-animation-buttonMain { fill: url(#animation_buttonHovered); }\
  153627. .cesium-animation-buttonDisabled .cesium-animation-buttonMain { fill: url(#animation_buttonDisabled); }\
  153628. .cesium-animation-shuttleRingG .cesium-animation-shuttleRingSwoosh { fill: url(#animation_shuttleRingSwooshGradient); }\
  153629. .cesium-animation-shuttleRingG:hover .cesium-animation-shuttleRingSwoosh { fill: url(#animation_shuttleRingSwooshHovered); }\
  153630. .cesium-animation-shuttleRingPointer { fill: url(#animation_shuttleRingPointerGradient); }\
  153631. .cesium-animation-shuttleRingPausePointer { fill: url(#animation_shuttleRingPointerPaused); }\
  153632. .cesium-animation-knobOuter { fill: url(#animation_knobOuter); }\
  153633. .cesium-animation-knobInner { fill: url(#animation_knobInner); }';
  153634. document.head.insertBefore(cssStyle, document.head.childNodes[0]);
  153635. var themeEle = document.createElement('div');
  153636. themeEle.className = 'cesium-animation-theme';
  153637. themeEle.innerHTML = '<div class="cesium-animation-themeNormal"></div>\
  153638. <div class="cesium-animation-themeHover"></div>\
  153639. <div class="cesium-animation-themeSelect"></div>\
  153640. <div class="cesium-animation-themeDisabled"></div>\
  153641. <div class="cesium-animation-themeKnob"></div>\
  153642. <div class="cesium-animation-themePointer"></div>\
  153643. <div class="cesium-animation-themeSwoosh"></div>\
  153644. <div class="cesium-animation-themeSwooshHover"></div>';
  153645. this._theme = themeEle;
  153646. this._themeNormal = themeEle.childNodes[0];
  153647. this._themeHover = themeEle.childNodes[1];
  153648. this._themeSelect = themeEle.childNodes[2];
  153649. this._themeDisabled = themeEle.childNodes[3];
  153650. this._themeKnob = themeEle.childNodes[4];
  153651. this._themePointer = themeEle.childNodes[5];
  153652. this._themeSwoosh = themeEle.childNodes[6];
  153653. this._themeSwooshHover = themeEle.childNodes[7];
  153654. var svg = document.createElementNS(svgNS, 'svg:svg');
  153655. this._svgNode = svg;
  153656. // Define the XLink namespace that SVG uses
  153657. svg.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', xlinkNS);
  153658. var topG = document.createElementNS(svgNS, 'g');
  153659. this._topG = topG;
  153660. this._realtimeSVG = new SvgButton(wingButton(3, 4, '#animation_pathClock'), viewModel.playRealtimeViewModel);
  153661. this._playReverseSVG = new SvgButton(rectButton(44, 99, '#animation_pathPlayReverse'), viewModel.playReverseViewModel);
  153662. this._playForwardSVG = new SvgButton(rectButton(124, 99, '#animation_pathPlay'), viewModel.playForwardViewModel);
  153663. this._pauseSVG = new SvgButton(rectButton(84, 99, '#animation_pathPause'), viewModel.pauseViewModel);
  153664. var buttonsG = document.createElementNS(svgNS, 'g');
  153665. buttonsG.appendChild(this._realtimeSVG.svgElement);
  153666. buttonsG.appendChild(this._playReverseSVG.svgElement);
  153667. buttonsG.appendChild(this._playForwardSVG.svgElement);
  153668. buttonsG.appendChild(this._pauseSVG.svgElement);
  153669. var shuttleRingBackPanel = svgFromObject({
  153670. tagName : 'circle',
  153671. 'class' : 'cesium-animation-shuttleRingBack',
  153672. cx : 100,
  153673. cy : 100,
  153674. r : 99
  153675. });
  153676. this._shuttleRingBackPanel = shuttleRingBackPanel;
  153677. var shuttleRingSwooshG = svgFromObject({
  153678. tagName : 'g',
  153679. 'class' : 'cesium-animation-shuttleRingSwoosh',
  153680. children : [{
  153681. tagName : 'use',
  153682. transform : 'translate(100,97) scale(-1,1)',
  153683. 'xlink:href' : '#animation_pathSwooshFX'
  153684. }, {
  153685. tagName : 'use',
  153686. transform : 'translate(100,97)',
  153687. 'xlink:href' : '#animation_pathSwooshFX'
  153688. }, {
  153689. tagName : 'line',
  153690. x1 : 100,
  153691. y1 : 8,
  153692. x2 : 100,
  153693. y2 : 22
  153694. }]
  153695. });
  153696. this._shuttleRingSwooshG = shuttleRingSwooshG;
  153697. this._shuttleRingPointer = svgFromObject({
  153698. tagName : 'use',
  153699. 'class' : 'cesium-animation-shuttleRingPointer',
  153700. 'xlink:href' : '#animation_pathPointer'
  153701. });
  153702. var knobG = svgFromObject({
  153703. tagName : 'g',
  153704. transform : 'translate(100,100)'
  153705. });
  153706. this._knobOuter = svgFromObject({
  153707. tagName : 'circle',
  153708. 'class' : 'cesium-animation-knobOuter',
  153709. cx : 0,
  153710. cy : 0,
  153711. r : 71
  153712. });
  153713. var knobInnerAndShieldSize = 61;
  153714. var knobInner = svgFromObject({
  153715. tagName : 'circle',
  153716. 'class' : 'cesium-animation-knobInner',
  153717. cx : 0,
  153718. cy : 0,
  153719. r : knobInnerAndShieldSize
  153720. });
  153721. this._knobDate = svgText(0, -24, '');
  153722. this._knobTime = svgText(0, -7, '');
  153723. this._knobStatus = svgText(0, -41, '');
  153724. // widget shield catches clicks on the knob itself (even while DOM elements underneath are changing).
  153725. var knobShield = svgFromObject({
  153726. tagName : 'circle',
  153727. 'class' : 'cesium-animation-blank',
  153728. cx : 0,
  153729. cy : 0,
  153730. r : knobInnerAndShieldSize
  153731. });
  153732. var shuttleRingBackG = document.createElementNS(svgNS, 'g');
  153733. shuttleRingBackG.setAttribute('class', 'cesium-animation-shuttleRingG');
  153734. container.appendChild(themeEle);
  153735. topG.appendChild(shuttleRingBackG);
  153736. topG.appendChild(knobG);
  153737. topG.appendChild(buttonsG);
  153738. shuttleRingBackG.appendChild(shuttleRingBackPanel);
  153739. shuttleRingBackG.appendChild(shuttleRingSwooshG);
  153740. shuttleRingBackG.appendChild(this._shuttleRingPointer);
  153741. knobG.appendChild(this._knobOuter);
  153742. knobG.appendChild(knobInner);
  153743. knobG.appendChild(this._knobDate);
  153744. knobG.appendChild(this._knobTime);
  153745. knobG.appendChild(this._knobStatus);
  153746. knobG.appendChild(knobShield);
  153747. svg.appendChild(topG);
  153748. container.appendChild(svg);
  153749. var that = this;
  153750. function mouseCallback(e) {
  153751. setShuttleRingFromMouseOrTouch(that, e);
  153752. }
  153753. this._mouseCallback = mouseCallback;
  153754. shuttleRingBackPanel.addEventListener('mousedown', mouseCallback, true);
  153755. shuttleRingBackPanel.addEventListener('touchstart', mouseCallback, true);
  153756. shuttleRingSwooshG.addEventListener('mousedown', mouseCallback, true);
  153757. shuttleRingSwooshG.addEventListener('touchstart', mouseCallback, true);
  153758. document.addEventListener('mousemove', mouseCallback, true);
  153759. document.addEventListener('touchmove', mouseCallback, true);
  153760. document.addEventListener('mouseup', mouseCallback, true);
  153761. document.addEventListener('touchend', mouseCallback, true);
  153762. document.addEventListener('touchcancel', mouseCallback, true);
  153763. this._shuttleRingPointer.addEventListener('mousedown', mouseCallback, true);
  153764. this._shuttleRingPointer.addEventListener('touchstart', mouseCallback, true);
  153765. this._knobOuter.addEventListener('mousedown', mouseCallback, true);
  153766. this._knobOuter.addEventListener('touchstart', mouseCallback, true);
  153767. //TODO: Since the animation widget uses SVG and has no HTML backing,
  153768. //we need to wire everything up manually. Knockout can supposedly
  153769. //bind to SVG, so we we figure that out we can modify our SVG
  153770. //to include the binding information directly.
  153771. var timeNode = this._knobTime.childNodes[0];
  153772. var dateNode = this._knobDate.childNodes[0];
  153773. var statusNode = this._knobStatus.childNodes[0];
  153774. var isPaused;
  153775. this._subscriptions = [//
  153776. subscribeAndEvaluate(viewModel.pauseViewModel, 'toggled', function(value) {
  153777. if (isPaused !== value) {
  153778. isPaused = value;
  153779. if (isPaused) {
  153780. that._shuttleRingPointer.setAttribute('class', 'cesium-animation-shuttleRingPausePointer');
  153781. } else {
  153782. that._shuttleRingPointer.setAttribute('class', 'cesium-animation-shuttleRingPointer');
  153783. }
  153784. }
  153785. }),
  153786. subscribeAndEvaluate(viewModel, 'shuttleRingAngle', function(value) {
  153787. setShuttleRingPointer(that._shuttleRingPointer, that._knobOuter, value);
  153788. }),
  153789. subscribeAndEvaluate(viewModel, 'dateLabel', function(value) {
  153790. if (dateNode.textContent !== value) {
  153791. dateNode.textContent = value;
  153792. }
  153793. }),
  153794. subscribeAndEvaluate(viewModel, 'timeLabel', function(value) {
  153795. if (timeNode.textContent !== value) {
  153796. timeNode.textContent = value;
  153797. }
  153798. }),
  153799. subscribeAndEvaluate(viewModel, 'multiplierLabel', function(value) {
  153800. if (statusNode.textContent !== value) {
  153801. statusNode.textContent = value;
  153802. }
  153803. })];
  153804. this.applyThemeChanges();
  153805. this.resize();
  153806. }
  153807. defineProperties(Animation.prototype, {
  153808. /**
  153809. * Gets the parent container.
  153810. *
  153811. * @memberof Animation.prototype
  153812. * @type {Element}
  153813. * @readonly
  153814. */
  153815. container : {
  153816. get : function() {
  153817. return this._container;
  153818. }
  153819. },
  153820. /**
  153821. * Gets the view model.
  153822. *
  153823. * @memberof Animation.prototype
  153824. * @type {AnimationViewModel}
  153825. * @readonly
  153826. */
  153827. viewModel : {
  153828. get : function() {
  153829. return this._viewModel;
  153830. }
  153831. }
  153832. });
  153833. /**
  153834. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  153835. */
  153836. Animation.prototype.isDestroyed = function() {
  153837. return false;
  153838. };
  153839. /**
  153840. * Destroys the animation widget. Should be called if permanently
  153841. * removing the widget from layout.
  153842. */
  153843. Animation.prototype.destroy = function() {
  153844. var mouseCallback = this._mouseCallback;
  153845. this._shuttleRingBackPanel.removeEventListener('mousedown', mouseCallback, true);
  153846. this._shuttleRingBackPanel.removeEventListener('touchstart', mouseCallback, true);
  153847. this._shuttleRingSwooshG.removeEventListener('mousedown', mouseCallback, true);
  153848. this._shuttleRingSwooshG.removeEventListener('touchstart', mouseCallback, true);
  153849. document.removeEventListener('mousemove', mouseCallback, true);
  153850. document.removeEventListener('touchmove', mouseCallback, true);
  153851. document.removeEventListener('mouseup', mouseCallback, true);
  153852. document.removeEventListener('touchend', mouseCallback, true);
  153853. document.removeEventListener('touchcancel', mouseCallback, true);
  153854. this._shuttleRingPointer.removeEventListener('mousedown', mouseCallback, true);
  153855. this._shuttleRingPointer.removeEventListener('touchstart', mouseCallback, true);
  153856. this._knobOuter.removeEventListener('mousedown', mouseCallback, true);
  153857. this._knobOuter.removeEventListener('touchstart', mouseCallback, true);
  153858. this._container.removeChild(this._svgNode);
  153859. this._container.removeChild(this._theme);
  153860. this._realtimeSVG.destroy();
  153861. this._playReverseSVG.destroy();
  153862. this._playForwardSVG.destroy();
  153863. this._pauseSVG.destroy();
  153864. var subscriptions = this._subscriptions;
  153865. for ( var i = 0, len = subscriptions.length; i < len; i++) {
  153866. subscriptions[i].dispose();
  153867. }
  153868. return destroyObject(this);
  153869. };
  153870. /**
  153871. * Resizes the widget to match the container size.
  153872. * This function should be called whenever the container size is changed.
  153873. */
  153874. Animation.prototype.resize = function() {
  153875. var parentWidth = this._container.clientWidth;
  153876. var parentHeight = this._container.clientHeight;
  153877. if (parentWidth === this._lastWidth && parentHeight === this._lastHeight) {
  153878. return;
  153879. }
  153880. var svg = this._svgNode;
  153881. //The width and height as the SVG was originally drawn.
  153882. var baseWidth = 200;
  153883. var baseHeight = 132;
  153884. var width = parentWidth;
  153885. var height = parentHeight;
  153886. if (parentWidth === 0 && parentHeight === 0) {
  153887. width = baseWidth;
  153888. height = baseHeight;
  153889. } else if (parentWidth === 0) {
  153890. height = parentHeight;
  153891. width = baseWidth * (parentHeight / baseHeight);
  153892. } else if (parentHeight === 0) {
  153893. width = parentWidth;
  153894. height = baseHeight * (parentWidth / baseWidth);
  153895. }
  153896. var scaleX = width / baseWidth;
  153897. var scaleY = height / baseHeight;
  153898. svg.style.cssText = 'width: ' + width + 'px; height: ' + height + 'px; position: absolute; bottom: 0; left: 0; overflow: hidden;';
  153899. svg.setAttribute('width', width);
  153900. svg.setAttribute('height', height);
  153901. svg.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
  153902. this._topG.setAttribute('transform', 'scale(' + scaleX + ',' + scaleY + ')');
  153903. this._centerX = Math.max(1, 100.0 * scaleX);
  153904. this._centerY = Math.max(1, 100.0 * scaleY);
  153905. this._lastHeight = parentWidth;
  153906. this._lastWidth = parentHeight;
  153907. };
  153908. /**
  153909. * Updates the widget to reflect any modified CSS rules for theming.
  153910. *
  153911. * @example
  153912. * //Switch to the cesium-lighter theme.
  153913. * document.body.className = 'cesium-lighter';
  153914. * animation.applyThemeChanges();
  153915. */
  153916. Animation.prototype.applyThemeChanges = function() {
  153917. var buttonNormalBackColor = getElementColor(this._themeNormal);
  153918. var buttonHoverBackColor = getElementColor(this._themeHover);
  153919. var buttonToggledBackColor = getElementColor(this._themeSelect);
  153920. var buttonDisabledBackColor = getElementColor(this._themeDisabled);
  153921. var knobBackColor = getElementColor(this._themeKnob);
  153922. var pointerColor = getElementColor(this._themePointer);
  153923. var swooshColor = getElementColor(this._themeSwoosh);
  153924. var swooshHoverColor = getElementColor(this._themeSwooshHover);
  153925. var defsElement = svgFromObject({
  153926. tagName : 'defs',
  153927. children : [{
  153928. id : 'animation_buttonNormal',
  153929. tagName : 'linearGradient',
  153930. x1 : '50%',
  153931. y1 : '0%',
  153932. x2 : '50%',
  153933. y2 : '100%',
  153934. children : [
  153935. //add a 'stop-opacity' field to make translucent.
  153936. {
  153937. tagName : 'stop',
  153938. offset : '0%',
  153939. 'stop-color' : makeColorString(buttonNormalBackColor, gradientEnabledColor0)
  153940. }, {
  153941. tagName : 'stop',
  153942. offset : '12%',
  153943. 'stop-color' : makeColorString(buttonNormalBackColor, gradientEnabledColor1)
  153944. }, {
  153945. tagName : 'stop',
  153946. offset : '46%',
  153947. 'stop-color' : makeColorString(buttonNormalBackColor, gradientEnabledColor2)
  153948. }, {
  153949. tagName : 'stop',
  153950. offset : '81%',
  153951. 'stop-color' : makeColorString(buttonNormalBackColor, gradientEnabledColor3)
  153952. }]
  153953. }, {
  153954. id : 'animation_buttonHovered',
  153955. tagName : 'linearGradient',
  153956. x1 : '50%',
  153957. y1 : '0%',
  153958. x2 : '50%',
  153959. y2 : '100%',
  153960. children : [{
  153961. tagName : 'stop',
  153962. offset : '0%',
  153963. 'stop-color' : makeColorString(buttonHoverBackColor, gradientEnabledColor0)
  153964. }, {
  153965. tagName : 'stop',
  153966. offset : '12%',
  153967. 'stop-color' : makeColorString(buttonHoverBackColor, gradientEnabledColor1)
  153968. }, {
  153969. tagName : 'stop',
  153970. offset : '46%',
  153971. 'stop-color' : makeColorString(buttonHoverBackColor, gradientEnabledColor2)
  153972. }, {
  153973. tagName : 'stop',
  153974. offset : '81%',
  153975. 'stop-color' : makeColorString(buttonHoverBackColor, gradientEnabledColor3)
  153976. }]
  153977. }, {
  153978. id : 'animation_buttonToggled',
  153979. tagName : 'linearGradient',
  153980. x1 : '50%',
  153981. y1 : '0%',
  153982. x2 : '50%',
  153983. y2 : '100%',
  153984. children : [{
  153985. tagName : 'stop',
  153986. offset : '0%',
  153987. 'stop-color' : makeColorString(buttonToggledBackColor, gradientEnabledColor0)
  153988. }, {
  153989. tagName : 'stop',
  153990. offset : '12%',
  153991. 'stop-color' : makeColorString(buttonToggledBackColor, gradientEnabledColor1)
  153992. }, {
  153993. tagName : 'stop',
  153994. offset : '46%',
  153995. 'stop-color' : makeColorString(buttonToggledBackColor, gradientEnabledColor2)
  153996. }, {
  153997. tagName : 'stop',
  153998. offset : '81%',
  153999. 'stop-color' : makeColorString(buttonToggledBackColor, gradientEnabledColor3)
  154000. }]
  154001. }, {
  154002. id : 'animation_buttonDisabled',
  154003. tagName : 'linearGradient',
  154004. x1 : '50%',
  154005. y1 : '0%',
  154006. x2 : '50%',
  154007. y2 : '100%',
  154008. children : [{
  154009. tagName : 'stop',
  154010. offset : '0%',
  154011. 'stop-color' : makeColorString(buttonDisabledBackColor, gradientDisabledColor0)
  154012. }, {
  154013. tagName : 'stop',
  154014. offset : '75%',
  154015. 'stop-color' : makeColorString(buttonDisabledBackColor, gradientDisabledColor1)
  154016. }]
  154017. }, {
  154018. id : 'animation_blurred',
  154019. tagName : 'filter',
  154020. width : '200%',
  154021. height : '200%',
  154022. x : '-50%',
  154023. y : '-50%',
  154024. children : [{
  154025. tagName : 'feGaussianBlur',
  154026. stdDeviation : 4,
  154027. 'in' : 'SourceGraphic'
  154028. }]
  154029. }, {
  154030. id : 'animation_shuttleRingSwooshGradient',
  154031. tagName : 'linearGradient',
  154032. x1 : '50%',
  154033. y1 : '0%',
  154034. x2 : '50%',
  154035. y2 : '100%',
  154036. children : [{
  154037. tagName : 'stop',
  154038. offset : '0%',
  154039. 'stop-opacity' : 0.2,
  154040. 'stop-color' : swooshColor.toCssColorString()
  154041. }, {
  154042. tagName : 'stop',
  154043. offset : '85%',
  154044. 'stop-opacity' : 0.85,
  154045. 'stop-color' : swooshColor.toCssColorString()
  154046. }, {
  154047. tagName : 'stop',
  154048. offset : '95%',
  154049. 'stop-opacity' : 0.05,
  154050. 'stop-color' : swooshColor.toCssColorString()
  154051. }]
  154052. }, {
  154053. id : 'animation_shuttleRingSwooshHovered',
  154054. tagName : 'linearGradient',
  154055. x1 : '50%',
  154056. y1 : '0%',
  154057. x2 : '50%',
  154058. y2 : '100%',
  154059. children : [{
  154060. tagName : 'stop',
  154061. offset : '0%',
  154062. 'stop-opacity' : 0.2,
  154063. 'stop-color' : swooshHoverColor.toCssColorString()
  154064. }, {
  154065. tagName : 'stop',
  154066. offset : '85%',
  154067. 'stop-opacity' : 0.85,
  154068. 'stop-color' : swooshHoverColor.toCssColorString()
  154069. }, {
  154070. tagName : 'stop',
  154071. offset : '95%',
  154072. 'stop-opacity' : 0.05,
  154073. 'stop-color' : swooshHoverColor.toCssColorString()
  154074. }]
  154075. }, {
  154076. id : 'animation_shuttleRingPointerGradient',
  154077. tagName : 'linearGradient',
  154078. x1 : '0%',
  154079. y1 : '50%',
  154080. x2 : '100%',
  154081. y2 : '50%',
  154082. children : [{
  154083. tagName : 'stop',
  154084. offset : '0%',
  154085. 'stop-color' : pointerColor.toCssColorString()
  154086. }, {
  154087. tagName : 'stop',
  154088. offset : '40%',
  154089. 'stop-color' : pointerColor.toCssColorString()
  154090. }, {
  154091. tagName : 'stop',
  154092. offset : '60%',
  154093. 'stop-color' : makeColorString(pointerColor, gradientPointerColor)
  154094. }, {
  154095. tagName : 'stop',
  154096. offset : '100%',
  154097. 'stop-color' : makeColorString(pointerColor, gradientPointerColor)
  154098. }]
  154099. }, {
  154100. id : 'animation_shuttleRingPointerPaused',
  154101. tagName : 'linearGradient',
  154102. x1 : '0%',
  154103. y1 : '50%',
  154104. x2 : '100%',
  154105. y2 : '50%',
  154106. children : [{
  154107. tagName : 'stop',
  154108. offset : '0%',
  154109. 'stop-color' : '#CCC'
  154110. }, {
  154111. tagName : 'stop',
  154112. offset : '40%',
  154113. 'stop-color' : '#CCC'
  154114. }, {
  154115. tagName : 'stop',
  154116. offset : '60%',
  154117. 'stop-color' : '#555'
  154118. }, {
  154119. tagName : 'stop',
  154120. offset : '100%',
  154121. 'stop-color' : '#555'
  154122. }]
  154123. }, {
  154124. id : 'animation_knobOuter',
  154125. tagName : 'linearGradient',
  154126. x1 : '20%',
  154127. y1 : '0%',
  154128. x2 : '90%',
  154129. y2 : '100%',
  154130. children : [{
  154131. tagName : 'stop',
  154132. offset : '5%',
  154133. 'stop-color' : makeColorString(knobBackColor, gradientEnabledColor0)
  154134. }, {
  154135. tagName : 'stop',
  154136. offset : '60%',
  154137. 'stop-color' : makeColorString(knobBackColor, gradientKnobColor)
  154138. }, {
  154139. tagName : 'stop',
  154140. offset : '85%',
  154141. 'stop-color' : makeColorString(knobBackColor, gradientEnabledColor1)
  154142. }]
  154143. }, {
  154144. id : 'animation_knobInner',
  154145. tagName : 'linearGradient',
  154146. x1 : '20%',
  154147. y1 : '0%',
  154148. x2 : '90%',
  154149. y2 : '100%',
  154150. children : [{
  154151. tagName : 'stop',
  154152. offset : '5%',
  154153. 'stop-color' : makeColorString(knobBackColor, gradientKnobColor)
  154154. }, {
  154155. tagName : 'stop',
  154156. offset : '60%',
  154157. 'stop-color' : makeColorString(knobBackColor, gradientEnabledColor0)
  154158. }, {
  154159. tagName : 'stop',
  154160. offset : '85%',
  154161. 'stop-color' : makeColorString(knobBackColor, gradientEnabledColor3)
  154162. }]
  154163. }, {
  154164. id : 'animation_pathReset',
  154165. tagName : 'path',
  154166. transform : 'translate(16,16) scale(0.85) translate(-16,-16)',
  154167. d : 'M24.316,5.318,9.833,13.682,9.833,5.5,5.5,5.5,5.5,25.5,9.833,25.5,9.833,17.318,24.316,25.682z'
  154168. }, {
  154169. id : 'animation_pathPause',
  154170. tagName : 'path',
  154171. transform : 'translate(16,16) scale(0.85) translate(-16,-16)',
  154172. d : 'M13,5.5,7.5,5.5,7.5,25.5,13,25.5zM24.5,5.5,19,5.5,19,25.5,24.5,25.5z'
  154173. }, {
  154174. id : 'animation_pathPlay',
  154175. tagName : 'path',
  154176. transform : 'translate(16,16) scale(0.85) translate(-16,-16)',
  154177. d : 'M6.684,25.682L24.316,15.5L6.684,5.318V25.682z'
  154178. }, {
  154179. id : 'animation_pathPlayReverse',
  154180. tagName : 'path',
  154181. transform : 'translate(16,16) scale(-0.85,0.85) translate(-16,-16)',
  154182. d : 'M6.684,25.682L24.316,15.5L6.684,5.318V25.682z'
  154183. }, {
  154184. id : 'animation_pathLoop',
  154185. tagName : 'path',
  154186. transform : 'translate(16,16) scale(0.85) translate(-16,-16)',
  154187. d : 'M24.249,15.499c-0.009,4.832-3.918,8.741-8.75,8.75c-2.515,0-4.768-1.064-6.365-2.763l2.068-1.442l-7.901-3.703l0.744,8.694l2.193-1.529c2.244,2.594,5.562,4.242,9.26,4.242c6.767,0,12.249-5.482,12.249-12.249H24.249zM15.499,6.75c2.516,0,4.769,1.065,6.367,2.764l-2.068,1.443l7.901,3.701l-0.746-8.693l-2.192,1.529c-2.245-2.594-5.562-4.245-9.262-4.245C8.734,3.25,3.25,8.734,3.249,15.499H6.75C6.758,10.668,10.668,6.758,15.499,6.75z'
  154188. }, {
  154189. id : 'animation_pathClock',
  154190. tagName : 'path',
  154191. transform : 'translate(16,16) scale(0.85) translate(-16,-15.5)',
  154192. d : 'M15.5,2.374C8.251,2.375,2.376,8.251,2.374,15.5C2.376,22.748,8.251,28.623,15.5,28.627c7.249-0.004,13.124-5.879,13.125-13.127C28.624,8.251,22.749,2.375,15.5,2.374zM15.5,25.623C9.909,25.615,5.385,21.09,5.375,15.5C5.385,9.909,9.909,5.384,15.5,5.374c5.59,0.01,10.115,4.535,10.124,10.125C25.615,21.09,21.091,25.615,15.5,25.623zM8.625,15.5c-0.001-0.552-0.448-0.999-1.001-1c-0.553,0-1,0.448-1,1c0,0.553,0.449,1,1,1C8.176,16.5,8.624,16.053,8.625,15.5zM8.179,18.572c-0.478,0.277-0.642,0.889-0.365,1.367c0.275,0.479,0.889,0.641,1.365,0.365c0.479-0.275,0.643-0.887,0.367-1.367C9.27,18.461,8.658,18.297,8.179,18.572zM9.18,10.696c-0.479-0.276-1.09-0.112-1.366,0.366s-0.111,1.09,0.365,1.366c0.479,0.276,1.09,0.113,1.367-0.366C9.821,11.584,9.657,10.973,9.18,10.696zM22.822,12.428c0.478-0.275,0.643-0.888,0.366-1.366c-0.275-0.478-0.89-0.642-1.366-0.366c-0.479,0.278-0.642,0.89-0.366,1.367C21.732,12.54,22.344,12.705,22.822,12.428zM12.062,21.455c-0.478-0.275-1.089-0.111-1.366,0.367c-0.275,0.479-0.111,1.09,0.366,1.365c0.478,0.277,1.091,0.111,1.365-0.365C12.704,22.344,12.54,21.732,12.062,21.455zM12.062,9.545c0.479-0.276,0.642-0.888,0.366-1.366c-0.276-0.478-0.888-0.642-1.366-0.366s-0.642,0.888-0.366,1.366C10.973,9.658,11.584,9.822,12.062,9.545zM22.823,18.572c-0.48-0.275-1.092-0.111-1.367,0.365c-0.275,0.479-0.112,1.092,0.367,1.367c0.477,0.275,1.089,0.113,1.365-0.365C23.464,19.461,23.3,18.848,22.823,18.572zM19.938,7.813c-0.477-0.276-1.091-0.111-1.365,0.366c-0.275,0.48-0.111,1.091,0.366,1.367s1.089,0.112,1.366-0.366C20.581,8.702,20.418,8.089,19.938,7.813zM23.378,14.5c-0.554,0.002-1.001,0.45-1.001,1c0.001,0.552,0.448,1,1.001,1c0.551,0,1-0.447,1-1C24.378,14.949,23.929,14.5,23.378,14.5zM15.501,6.624c-0.552,0-1,0.448-1,1l-0.466,7.343l-3.004,1.96c-0.478,0.277-0.642,0.889-0.365,1.365c0.275,0.479,0.889,0.643,1.365,0.367l3.305-1.676C15.39,16.99,15.444,17,15.501,17c0.828,0,1.5-0.671,1.5-1.5l-0.5-7.876C16.501,7.072,16.053,6.624,15.501,6.624zM15.501,22.377c-0.552,0-1,0.447-1,1s0.448,1,1,1s1-0.447,1-1S16.053,22.377,15.501,22.377zM18.939,21.455c-0.479,0.277-0.643,0.889-0.366,1.367c0.275,0.477,0.888,0.643,1.366,0.365c0.478-0.275,0.642-0.889,0.366-1.365C20.028,21.344,19.417,21.18,18.939,21.455z'
  154193. }, {
  154194. id : 'animation_pathWingButton',
  154195. tagName : 'path',
  154196. d : 'm 4.5,0.5 c -2.216,0 -4,1.784 -4,4 l 0,24 c 0,2.216 1.784,4 4,4 l 13.71875,0 C 22.478584,27.272785 27.273681,22.511272 32.5,18.25 l 0,-13.75 c 0,-2.216 -1.784,-4 -4,-4 l -24,0 z'
  154197. }, {
  154198. id : 'animation_pathPointer',
  154199. tagName : 'path',
  154200. d : 'M-15,-65,-15,-55,15,-55,15,-65,0,-95z'
  154201. }, {
  154202. id : 'animation_pathSwooshFX',
  154203. tagName : 'path',
  154204. d : 'm 85,0 c 0,16.617 -4.813944,35.356 -13.131081,48.4508 h 6.099803 c 8.317138,-13.0948 13.13322,-28.5955 13.13322,-45.2124 0,-46.94483 -38.402714,-85.00262 -85.7743869,-85.00262 -1.0218522,0 -2.0373001,0.0241 -3.0506131,0.0589 45.958443,1.59437 82.723058,35.77285 82.723058,81.70532 z'
  154205. }]
  154206. });
  154207. if (!defined(this._defsElement)) {
  154208. this._svgNode.appendChild(defsElement);
  154209. } else {
  154210. this._svgNode.replaceChild(defsElement, this._defsElement);
  154211. }
  154212. this._defsElement = defsElement;
  154213. };
  154214. return Animation;
  154215. });
  154216. /*global define*/
  154217. define('Widgets/createCommand',[
  154218. '../Core/defaultValue',
  154219. '../Core/defined',
  154220. '../Core/defineProperties',
  154221. '../Core/DeveloperError',
  154222. '../Core/Event',
  154223. '../ThirdParty/knockout'
  154224. ], function(
  154225. defaultValue,
  154226. defined,
  154227. defineProperties,
  154228. DeveloperError,
  154229. Event,
  154230. knockout) {
  154231. 'use strict';
  154232. /**
  154233. * Create a Command from a given function, for use with ViewModels.
  154234. *
  154235. * A Command is a function with an extra <code>canExecute</code> observable property to determine
  154236. * whether the command can be executed. When executed, a Command function will check the
  154237. * value of <code>canExecute</code> and throw if false. It also provides events for when
  154238. * a command has been or is about to be executed.
  154239. *
  154240. * @exports createCommand
  154241. *
  154242. * @param {Function} func The function to execute.
  154243. * @param {Boolean} [canExecute=true] A boolean indicating whether the function can currently be executed.
  154244. */
  154245. function createCommand(func, canExecute) {
  154246. if (!defined(func)) {
  154247. throw new DeveloperError('func is required.');
  154248. }
  154249. canExecute = defaultValue(canExecute, true);
  154250. var beforeExecute = new Event();
  154251. var afterExecute = new Event();
  154252. function command() {
  154253. if (!command.canExecute) {
  154254. throw new DeveloperError('Cannot execute command, canExecute is false.');
  154255. }
  154256. var commandInfo = {
  154257. args : arguments,
  154258. cancel : false
  154259. };
  154260. var result;
  154261. beforeExecute.raiseEvent(commandInfo);
  154262. if (!commandInfo.cancel) {
  154263. result = func.apply(null, arguments);
  154264. afterExecute.raiseEvent(result);
  154265. }
  154266. return result;
  154267. }
  154268. command.canExecute = canExecute;
  154269. knockout.track(command, ['canExecute']);
  154270. defineProperties(command, {
  154271. beforeExecute : {
  154272. value : beforeExecute
  154273. },
  154274. afterExecute : {
  154275. value : afterExecute
  154276. }
  154277. });
  154278. return command;
  154279. }
  154280. return createCommand;
  154281. });
  154282. /*global define*/
  154283. define('Widgets/ToggleButtonViewModel',[
  154284. '../Core/defaultValue',
  154285. '../Core/defined',
  154286. '../Core/defineProperties',
  154287. '../Core/DeveloperError',
  154288. '../ThirdParty/knockout'
  154289. ], function(
  154290. defaultValue,
  154291. defined,
  154292. defineProperties,
  154293. DeveloperError,
  154294. knockout) {
  154295. 'use strict';
  154296. /**
  154297. * A view model which exposes the properties of a toggle button.
  154298. * @alias ToggleButtonViewModel
  154299. * @constructor
  154300. *
  154301. * @param {Command} command The command which will be executed when the button is toggled.
  154302. * @param {Object} [options] Object with the following properties:
  154303. * @param {Boolean} [options.toggled=false] A boolean indicating whether the button should be initially toggled.
  154304. * @param {String} [options.tooltip=''] A string containing the button's tooltip.
  154305. */
  154306. function ToggleButtonViewModel(command, options) {
  154307. if (!defined(command)) {
  154308. throw new DeveloperError('command is required.');
  154309. }
  154310. this._command = command;
  154311. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  154312. /**
  154313. * Gets or sets whether the button is currently toggled. This property is observable.
  154314. * @type {Boolean}
  154315. * @default false
  154316. */
  154317. this.toggled = defaultValue(options.toggled, false);
  154318. /**
  154319. * Gets or sets the button's tooltip. This property is observable.
  154320. * @type {String}
  154321. * @default ''
  154322. */
  154323. this.tooltip = defaultValue(options.tooltip, '');
  154324. knockout.track(this, ['toggled', 'tooltip']);
  154325. }
  154326. defineProperties(ToggleButtonViewModel.prototype, {
  154327. /**
  154328. * Gets the command which will be executed when the button is toggled.
  154329. * @memberof ToggleButtonViewModel.prototype
  154330. * @type {Command}
  154331. */
  154332. command : {
  154333. get : function() {
  154334. return this._command;
  154335. }
  154336. }
  154337. });
  154338. return ToggleButtonViewModel;
  154339. });
  154340. /*global define*/
  154341. define('Widgets/Animation/AnimationViewModel',[
  154342. '../../Core/binarySearch',
  154343. '../../Core/ClockRange',
  154344. '../../Core/ClockStep',
  154345. '../../Core/defined',
  154346. '../../Core/defineProperties',
  154347. '../../Core/DeveloperError',
  154348. '../../Core/JulianDate',
  154349. '../../ThirdParty/knockout',
  154350. '../../ThirdParty/sprintf',
  154351. '../createCommand',
  154352. '../ToggleButtonViewModel'
  154353. ], function(
  154354. binarySearch,
  154355. ClockRange,
  154356. ClockStep,
  154357. defined,
  154358. defineProperties,
  154359. DeveloperError,
  154360. JulianDate,
  154361. knockout,
  154362. sprintf,
  154363. createCommand,
  154364. ToggleButtonViewModel) {
  154365. 'use strict';
  154366. var monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  154367. var realtimeShuttleRingAngle = 15;
  154368. var maxShuttleRingAngle = 105;
  154369. function numberComparator(left, right) {
  154370. return left - right;
  154371. }
  154372. function getTypicalMultiplierIndex(multiplier, shuttleRingTicks) {
  154373. var index = binarySearch(shuttleRingTicks, multiplier, numberComparator);
  154374. return index < 0 ? ~index : index;
  154375. }
  154376. function angleToMultiplier(angle, shuttleRingTicks) {
  154377. //Use a linear scale for -1 to 1 between -15 < angle < 15 degrees
  154378. if (Math.abs(angle) <= realtimeShuttleRingAngle) {
  154379. return angle / realtimeShuttleRingAngle;
  154380. }
  154381. var minp = realtimeShuttleRingAngle;
  154382. var maxp = maxShuttleRingAngle;
  154383. var maxv;
  154384. var minv = 0;
  154385. var scale;
  154386. if (angle > 0) {
  154387. maxv = Math.log(shuttleRingTicks[shuttleRingTicks.length - 1]);
  154388. scale = (maxv - minv) / (maxp - minp);
  154389. return Math.exp(minv + scale * (angle - minp));
  154390. }
  154391. maxv = Math.log(-shuttleRingTicks[0]);
  154392. scale = (maxv - minv) / (maxp - minp);
  154393. return -Math.exp(minv + scale * (Math.abs(angle) - minp));
  154394. }
  154395. function multiplierToAngle(multiplier, shuttleRingTicks, clockViewModel) {
  154396. if (clockViewModel.clockStep === ClockStep.SYSTEM_CLOCK) {
  154397. return realtimeShuttleRingAngle;
  154398. }
  154399. if (Math.abs(multiplier) <= 1) {
  154400. return multiplier * realtimeShuttleRingAngle;
  154401. }
  154402. var fastedMultipler = shuttleRingTicks[shuttleRingTicks.length - 1];
  154403. if(multiplier > fastedMultipler){
  154404. multiplier = fastedMultipler;
  154405. } else if(multiplier < -fastedMultipler){
  154406. multiplier = -fastedMultipler;
  154407. }
  154408. var minp = realtimeShuttleRingAngle;
  154409. var maxp = maxShuttleRingAngle;
  154410. var maxv;
  154411. var minv = 0;
  154412. var scale;
  154413. if (multiplier > 0) {
  154414. maxv = Math.log(fastedMultipler);
  154415. scale = (maxv - minv) / (maxp - minp);
  154416. return (Math.log(multiplier) - minv) / scale + minp;
  154417. }
  154418. maxv = Math.log(-shuttleRingTicks[0]);
  154419. scale = (maxv - minv) / (maxp - minp);
  154420. return -((Math.log(Math.abs(multiplier)) - minv) / scale + minp);
  154421. }
  154422. /**
  154423. * The view model for the {@link Animation} widget.
  154424. * @alias AnimationViewModel
  154425. * @constructor
  154426. *
  154427. * @param {ClockViewModel} clockViewModel The ClockViewModel instance to use.
  154428. *
  154429. * @see Animation
  154430. */
  154431. function AnimationViewModel(clockViewModel) {
  154432. if (!defined(clockViewModel)) {
  154433. throw new DeveloperError('clockViewModel is required.');
  154434. }
  154435. var that = this;
  154436. this._clockViewModel = clockViewModel;
  154437. this._allShuttleRingTicks = [];
  154438. this._dateFormatter = AnimationViewModel.defaultDateFormatter;
  154439. this._timeFormatter = AnimationViewModel.defaultTimeFormatter;
  154440. /**
  154441. * Gets or sets whether the shuttle ring is currently being dragged. This property is observable.
  154442. * @type {Boolean}
  154443. * @default false
  154444. */
  154445. this.shuttleRingDragging = false;
  154446. /**
  154447. * Gets or sets whether dragging the shuttle ring should cause the multiplier
  154448. * to snap to the defined tick values rather than interpolating between them.
  154449. * This property is observable.
  154450. * @type {Boolean}
  154451. * @default false
  154452. */
  154453. this.snapToTicks = false;
  154454. knockout.track(this, ['_allShuttleRingTicks', '_dateFormatter', '_timeFormatter', 'shuttleRingDragging', 'snapToTicks']);
  154455. this._sortedFilteredPositiveTicks = [];
  154456. this.setShuttleRingTicks(AnimationViewModel.defaultTicks);
  154457. /**
  154458. * Gets the string representation of the current time. This property is observable.
  154459. * @type {String}
  154460. */
  154461. this.timeLabel = undefined;
  154462. knockout.defineProperty(this, 'timeLabel', function() {
  154463. return that._timeFormatter(that._clockViewModel.currentTime, that);
  154464. });
  154465. /**
  154466. * Gets the string representation of the current date. This property is observable.
  154467. * @type {String}
  154468. */
  154469. this.dateLabel = undefined;
  154470. knockout.defineProperty(this, 'dateLabel', function() {
  154471. return that._dateFormatter(that._clockViewModel.currentTime, that);
  154472. });
  154473. /**
  154474. * Gets the string representation of the current multiplier. This property is observable.
  154475. * @type {String}
  154476. */
  154477. this.multiplierLabel = undefined;
  154478. knockout.defineProperty(this, 'multiplierLabel', function() {
  154479. var clockViewModel = that._clockViewModel;
  154480. if (clockViewModel.clockStep === ClockStep.SYSTEM_CLOCK) {
  154481. return 'Today';
  154482. }
  154483. var multiplier = clockViewModel.multiplier;
  154484. //If it's a whole number, just return it.
  154485. if (multiplier % 1 === 0) {
  154486. return multiplier.toFixed(0) + 'x';
  154487. }
  154488. //Convert to decimal string and remove any trailing zeroes
  154489. return multiplier.toFixed(3).replace(/0{0,3}$/, "") + 'x';
  154490. });
  154491. /**
  154492. * Gets or sets the current shuttle ring angle. This property is observable.
  154493. * @type {Number}
  154494. */
  154495. this.shuttleRingAngle = undefined;
  154496. knockout.defineProperty(this, 'shuttleRingAngle', {
  154497. get : function() {
  154498. return multiplierToAngle(clockViewModel.multiplier, that._allShuttleRingTicks, clockViewModel);
  154499. },
  154500. set : function(angle) {
  154501. angle = Math.max(Math.min(angle, maxShuttleRingAngle), -maxShuttleRingAngle);
  154502. var ticks = that._allShuttleRingTicks;
  154503. var clockViewModel = that._clockViewModel;
  154504. clockViewModel.clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER;
  154505. //If we are at the max angle, simply return the max value in either direction.
  154506. if (Math.abs(angle) === maxShuttleRingAngle) {
  154507. clockViewModel.multiplier = angle > 0 ? ticks[ticks.length - 1] : ticks[0];
  154508. return;
  154509. }
  154510. var multiplier = angleToMultiplier(angle, ticks);
  154511. if (that.snapToTicks) {
  154512. multiplier = ticks[getTypicalMultiplierIndex(multiplier, ticks)];
  154513. } else {
  154514. if (multiplier !== 0) {
  154515. var positiveMultiplier = Math.abs(multiplier);
  154516. if (positiveMultiplier > 100) {
  154517. var numDigits = positiveMultiplier.toFixed(0).length - 2;
  154518. var divisor = Math.pow(10, numDigits);
  154519. multiplier = (Math.round(multiplier / divisor) * divisor) | 0;
  154520. } else if (positiveMultiplier > realtimeShuttleRingAngle) {
  154521. multiplier = Math.round(multiplier);
  154522. } else if (positiveMultiplier > 1) {
  154523. multiplier = +multiplier.toFixed(1);
  154524. } else if (positiveMultiplier > 0) {
  154525. multiplier = +multiplier.toFixed(2);
  154526. }
  154527. }
  154528. }
  154529. clockViewModel.multiplier = multiplier;
  154530. }
  154531. });
  154532. this._canAnimate = undefined;
  154533. knockout.defineProperty(this, '_canAnimate', function() {
  154534. var clockViewModel = that._clockViewModel;
  154535. var clockRange = clockViewModel.clockRange;
  154536. if (that.shuttleRingDragging || clockRange === ClockRange.UNBOUNDED) {
  154537. return true;
  154538. }
  154539. var multiplier = clockViewModel.multiplier;
  154540. var currentTime = clockViewModel.currentTime;
  154541. var startTime = clockViewModel.startTime;
  154542. var result = false;
  154543. if (clockRange === ClockRange.LOOP_STOP) {
  154544. result = JulianDate.greaterThan(currentTime, startTime) || (currentTime.equals(startTime) && multiplier > 0);
  154545. } else {
  154546. var stopTime = clockViewModel.stopTime;
  154547. result = (JulianDate.greaterThan(currentTime, startTime) && JulianDate.lessThan(currentTime, stopTime)) || //
  154548. (currentTime.equals(startTime) && multiplier > 0) || //
  154549. (currentTime.equals(stopTime) && multiplier < 0);
  154550. }
  154551. if (!result) {
  154552. clockViewModel.shouldAnimate = false;
  154553. }
  154554. return result;
  154555. });
  154556. this._isSystemTimeAvailable = undefined;
  154557. knockout.defineProperty(this, '_isSystemTimeAvailable', function() {
  154558. var clockViewModel = that._clockViewModel;
  154559. var clockRange = clockViewModel.clockRange;
  154560. if (clockRange === ClockRange.UNBOUNDED) {
  154561. return true;
  154562. }
  154563. var systemTime = clockViewModel.systemTime;
  154564. return JulianDate.greaterThanOrEquals(systemTime, clockViewModel.startTime) && JulianDate.lessThanOrEquals(systemTime, clockViewModel.stopTime);
  154565. });
  154566. this._isAnimating = undefined;
  154567. knockout.defineProperty(this, '_isAnimating', function() {
  154568. return that._clockViewModel.shouldAnimate && (that._canAnimate || that.shuttleRingDragging);
  154569. });
  154570. var pauseCommand = createCommand(function() {
  154571. var clockViewModel = that._clockViewModel;
  154572. if (clockViewModel.shouldAnimate) {
  154573. clockViewModel.shouldAnimate = false;
  154574. } else if (that._canAnimate) {
  154575. clockViewModel.shouldAnimate = true;
  154576. }
  154577. });
  154578. this._pauseViewModel = new ToggleButtonViewModel(pauseCommand, {
  154579. toggled : knockout.computed(function() {
  154580. return !that._isAnimating;
  154581. }),
  154582. tooltip : 'Pause'
  154583. });
  154584. var playReverseCommand = createCommand(function() {
  154585. var clockViewModel = that._clockViewModel;
  154586. var multiplier = clockViewModel.multiplier;
  154587. if (multiplier > 0) {
  154588. clockViewModel.multiplier = -multiplier;
  154589. }
  154590. clockViewModel.shouldAnimate = true;
  154591. });
  154592. this._playReverseViewModel = new ToggleButtonViewModel(playReverseCommand, {
  154593. toggled : knockout.computed(function() {
  154594. return that._isAnimating && (clockViewModel.multiplier < 0);
  154595. }),
  154596. tooltip : 'Play Reverse'
  154597. });
  154598. var playForwardCommand = createCommand(function() {
  154599. var clockViewModel = that._clockViewModel;
  154600. var multiplier = clockViewModel.multiplier;
  154601. if (multiplier < 0) {
  154602. clockViewModel.multiplier = -multiplier;
  154603. }
  154604. clockViewModel.shouldAnimate = true;
  154605. });
  154606. this._playForwardViewModel = new ToggleButtonViewModel(playForwardCommand, {
  154607. toggled : knockout.computed(function() {
  154608. return that._isAnimating && clockViewModel.multiplier > 0 && clockViewModel.clockStep !== ClockStep.SYSTEM_CLOCK;
  154609. }),
  154610. tooltip : 'Play Forward'
  154611. });
  154612. var playRealtimeCommand = createCommand(function() {
  154613. that._clockViewModel.clockStep = ClockStep.SYSTEM_CLOCK;
  154614. }, knockout.getObservable(this, '_isSystemTimeAvailable'));
  154615. this._playRealtimeViewModel = new ToggleButtonViewModel(playRealtimeCommand, {
  154616. toggled : knockout.computed(function() {
  154617. return clockViewModel.clockStep === ClockStep.SYSTEM_CLOCK;
  154618. }),
  154619. tooltip : knockout.computed(function() {
  154620. return that._isSystemTimeAvailable ? 'Today (real-time)' : 'Current time not in range';
  154621. })
  154622. });
  154623. this._slower = createCommand(function() {
  154624. var clockViewModel = that._clockViewModel;
  154625. var shuttleRingTicks = that._allShuttleRingTicks;
  154626. var multiplier = clockViewModel.multiplier;
  154627. var index = getTypicalMultiplierIndex(multiplier, shuttleRingTicks) - 1;
  154628. if (index >= 0) {
  154629. clockViewModel.multiplier = shuttleRingTicks[index];
  154630. }
  154631. });
  154632. this._faster = createCommand(function() {
  154633. var clockViewModel = that._clockViewModel;
  154634. var shuttleRingTicks = that._allShuttleRingTicks;
  154635. var multiplier = clockViewModel.multiplier;
  154636. var index = getTypicalMultiplierIndex(multiplier, shuttleRingTicks) + 1;
  154637. if (index < shuttleRingTicks.length) {
  154638. clockViewModel.multiplier = shuttleRingTicks[index];
  154639. }
  154640. });
  154641. }
  154642. /**
  154643. * Gets or sets the default date formatter used by new instances.
  154644. *
  154645. * @member
  154646. * @type {AnimationViewModel~DateFormatter}
  154647. */
  154648. AnimationViewModel.defaultDateFormatter = function(date, viewModel) {
  154649. var gregorianDate = JulianDate.toGregorianDate(date);
  154650. return monthNames[gregorianDate.month - 1] + ' ' + gregorianDate.day + ' ' + gregorianDate.year;
  154651. };
  154652. /**
  154653. * Gets or sets the default array of known clock multipliers associated with new instances of the shuttle ring.
  154654. * @type {Number[]}
  154655. */
  154656. AnimationViewModel.defaultTicks = [//
  154657. 0.001, 0.002, 0.005, 0.01, 0.02, 0.05, 0.1, 0.25, 0.5, 1.0, 2.0, 5.0, 10.0,//
  154658. 15.0, 30.0, 60.0, 120.0, 300.0, 600.0, 900.0, 1800.0, 3600.0, 7200.0, 14400.0,//
  154659. 21600.0, 43200.0, 86400.0, 172800.0, 345600.0, 604800.0];
  154660. /**
  154661. * Gets or sets the default time formatter used by new instances.
  154662. *
  154663. * @member
  154664. * @type {AnimationViewModel~TimeFormatter}
  154665. */
  154666. AnimationViewModel.defaultTimeFormatter = function(date, viewModel) {
  154667. var gregorianDate = JulianDate.toGregorianDate(date);
  154668. var millisecond = Math.round(gregorianDate.millisecond);
  154669. if (Math.abs(viewModel._clockViewModel.multiplier) < 1) {
  154670. return sprintf("%02d:%02d:%02d.%03d", gregorianDate.hour, gregorianDate.minute, gregorianDate.second, millisecond);
  154671. }
  154672. return sprintf("%02d:%02d:%02d UTC", gregorianDate.hour, gregorianDate.minute, gregorianDate.second);
  154673. };
  154674. /**
  154675. * Gets a copy of the array of positive known clock multipliers to associate with the shuttle ring.
  154676. *
  154677. * @returns {Number[]} The array of known clock multipliers associated with the shuttle ring.
  154678. */
  154679. AnimationViewModel.prototype.getShuttleRingTicks = function() {
  154680. return this._sortedFilteredPositiveTicks.slice(0);
  154681. };
  154682. /**
  154683. * Sets the array of positive known clock multipliers to associate with the shuttle ring.
  154684. * These values will have negative equivalents created for them and sets both the minimum
  154685. * and maximum range of values for the shuttle ring as well as the values that are snapped
  154686. * to when a single click is made. The values need not be in order, as they will be sorted
  154687. * automatically, and duplicate values will be removed.
  154688. *
  154689. * @param {Number[]} positiveTicks The list of known positive clock multipliers to associate with the shuttle ring.
  154690. */
  154691. AnimationViewModel.prototype.setShuttleRingTicks = function(positiveTicks) {
  154692. if (!defined(positiveTicks)) {
  154693. throw new DeveloperError('positiveTicks is required.');
  154694. }
  154695. var i;
  154696. var len;
  154697. var tick;
  154698. var hash = {};
  154699. var sortedFilteredPositiveTicks = this._sortedFilteredPositiveTicks;
  154700. sortedFilteredPositiveTicks.length = 0;
  154701. for (i = 0, len = positiveTicks.length; i < len; ++i) {
  154702. tick = positiveTicks[i];
  154703. //filter duplicates
  154704. if (!hash.hasOwnProperty(tick)) {
  154705. hash[tick] = true;
  154706. sortedFilteredPositiveTicks.push(tick);
  154707. }
  154708. }
  154709. sortedFilteredPositiveTicks.sort(numberComparator);
  154710. var allTicks = [];
  154711. for (len = sortedFilteredPositiveTicks.length, i = len - 1; i >= 0; --i) {
  154712. tick = sortedFilteredPositiveTicks[i];
  154713. if (tick !== 0) {
  154714. allTicks.push(-tick);
  154715. }
  154716. }
  154717. Array.prototype.push.apply(allTicks, sortedFilteredPositiveTicks);
  154718. this._allShuttleRingTicks = allTicks;
  154719. };
  154720. defineProperties(AnimationViewModel.prototype, {
  154721. /**
  154722. * Gets a command that decreases the speed of animation.
  154723. * @memberof AnimationViewModel.prototype
  154724. * @type {Command}
  154725. */
  154726. slower : {
  154727. get : function() {
  154728. return this._slower;
  154729. }
  154730. },
  154731. /**
  154732. * Gets a command that increases the speed of animation.
  154733. * @memberof AnimationViewModel.prototype
  154734. * @type {Command}
  154735. */
  154736. faster : {
  154737. get : function() {
  154738. return this._faster;
  154739. }
  154740. },
  154741. /**
  154742. * Gets the clock view model.
  154743. * @memberof AnimationViewModel.prototype
  154744. *
  154745. * @type {ClockViewModel}
  154746. */
  154747. clockViewModel : {
  154748. get : function() {
  154749. return this._clockViewModel;
  154750. }
  154751. },
  154752. /**
  154753. * Gets the pause toggle button view model.
  154754. * @memberof AnimationViewModel.prototype
  154755. *
  154756. * @type {ToggleButtonViewModel}
  154757. */
  154758. pauseViewModel : {
  154759. get : function() {
  154760. return this._pauseViewModel;
  154761. }
  154762. },
  154763. /**
  154764. * Gets the reverse toggle button view model.
  154765. * @memberof AnimationViewModel.prototype
  154766. *
  154767. * @type {ToggleButtonViewModel}
  154768. */
  154769. playReverseViewModel : {
  154770. get : function() {
  154771. return this._playReverseViewModel;
  154772. }
  154773. },
  154774. /**
  154775. * Gets the play toggle button view model.
  154776. * @memberof AnimationViewModel.prototype
  154777. *
  154778. * @type {ToggleButtonViewModel}
  154779. */
  154780. playForwardViewModel : {
  154781. get : function() {
  154782. return this._playForwardViewModel;
  154783. }
  154784. },
  154785. /**
  154786. * Gets the realtime toggle button view model.
  154787. * @memberof AnimationViewModel.prototype
  154788. *
  154789. * @type {ToggleButtonViewModel}
  154790. */
  154791. playRealtimeViewModel : {
  154792. get : function() {
  154793. return this._playRealtimeViewModel;
  154794. }
  154795. },
  154796. /**
  154797. * Gets or sets the function which formats a date for display.
  154798. * @memberof AnimationViewModel.prototype
  154799. *
  154800. * @type {AnimationViewModel~DateFormatter}
  154801. * @default AnimationViewModel.defaultDateFormatter
  154802. */
  154803. dateFormatter : {
  154804. //TODO:@exception {DeveloperError} dateFormatter must be a function.
  154805. get : function() {
  154806. return this._dateFormatter;
  154807. },
  154808. set : function(dateFormatter) {
  154809. if (typeof dateFormatter !== 'function') {
  154810. throw new DeveloperError('dateFormatter must be a function');
  154811. }
  154812. this._dateFormatter = dateFormatter;
  154813. }
  154814. },
  154815. /**
  154816. * Gets or sets the function which formats a time for display.
  154817. * @memberof AnimationViewModel.prototype
  154818. *
  154819. * @type {AnimationViewModel~TimeFormatter}
  154820. * @default AnimationViewModel.defaultTimeFormatter
  154821. */
  154822. timeFormatter : {
  154823. //TODO:@exception {DeveloperError} timeFormatter must be a function.
  154824. get : function() {
  154825. return this._timeFormatter;
  154826. },
  154827. set : function(timeFormatter) {
  154828. if (typeof timeFormatter !== 'function') {
  154829. throw new DeveloperError('timeFormatter must be a function');
  154830. }
  154831. this._timeFormatter = timeFormatter;
  154832. }
  154833. }
  154834. });
  154835. //Currently exposed for tests.
  154836. AnimationViewModel._maxShuttleRingAngle = maxShuttleRingAngle;
  154837. AnimationViewModel._realtimeShuttleRingAngle = realtimeShuttleRingAngle;
  154838. /**
  154839. * A function that formats a date for display.
  154840. * @callback AnimationViewModel~DateFormatter
  154841. *
  154842. * @param {JulianDate} date The date to be formatted
  154843. * @param {AnimationViewModel} viewModel The AnimationViewModel instance requesting formatting.
  154844. * @returns {String} The string representation of the calendar date portion of the provided date.
  154845. */
  154846. /**
  154847. * A function that formats a time for display.
  154848. * @callback AnimationViewModel~TimeFormatter
  154849. *
  154850. * @param {JulianDate} date The date to be formatted
  154851. * @param {AnimationViewModel} viewModel The AnimationViewModel instance requesting formatting.
  154852. * @returns {String} The string representation of the time portion of the provided date.
  154853. */
  154854. return AnimationViewModel;
  154855. });
  154856. /*global define*/
  154857. define('Widgets/BaseLayerPicker/BaseLayerPickerViewModel',[
  154858. '../../Core/defaultValue',
  154859. '../../Core/defined',
  154860. '../../Core/defineProperties',
  154861. '../../Core/DeveloperError',
  154862. '../../Core/EllipsoidTerrainProvider',
  154863. '../../Core/isArray',
  154864. '../../ThirdParty/knockout',
  154865. '../createCommand'
  154866. ], function(
  154867. defaultValue,
  154868. defined,
  154869. defineProperties,
  154870. DeveloperError,
  154871. EllipsoidTerrainProvider,
  154872. isArray,
  154873. knockout,
  154874. createCommand) {
  154875. 'use strict';
  154876. /**
  154877. * The view model for {@link BaseLayerPicker}.
  154878. * @alias BaseLayerPickerViewModel
  154879. * @constructor
  154880. *
  154881. * @param {Object} options Object with the following properties:
  154882. * @param {Globe} options.globe The Globe to use.
  154883. * @param {ProviderViewModel[]} [options.imageryProviderViewModels=[]] The array of ProviderViewModel instances to use for imagery.
  154884. * @param {ProviderViewModel} [options.selectedImageryProviderViewModel] The view model for the current base imagery layer, if not supplied the first available imagery layer is used.
  154885. * @param {ProviderViewModel[]} [options.terrainProviderViewModels=[]] The array of ProviderViewModel instances to use for terrain.
  154886. * @param {ProviderViewModel} [options.selectedTerrainProviderViewModel] The view model for the current base terrain layer, if not supplied the first available terrain layer is used.
  154887. *
  154888. * @exception {DeveloperError} imageryProviderViewModels must be an array.
  154889. * @exception {DeveloperError} terrainProviderViewModels must be an array.
  154890. */
  154891. function BaseLayerPickerViewModel(options) {
  154892. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  154893. var globe = options.globe;
  154894. var imageryProviderViewModels = defaultValue(options.imageryProviderViewModels, []);
  154895. var terrainProviderViewModels = defaultValue(options.terrainProviderViewModels, []);
  154896. if (!defined(globe)) {
  154897. throw new DeveloperError('globe is required');
  154898. }
  154899. this._globe = globe;
  154900. /**
  154901. * Gets or sets an array of ProviderViewModel instances available for imagery selection.
  154902. * This property is observable.
  154903. * @type {ProviderViewModel[]}
  154904. */
  154905. this.imageryProviderViewModels = imageryProviderViewModels.slice(0);
  154906. /**
  154907. * Gets or sets an array of ProviderViewModel instances available for terrain selection.
  154908. * This property is observable.
  154909. * @type {ProviderViewModel[]}
  154910. */
  154911. this.terrainProviderViewModels = terrainProviderViewModels.slice(0);
  154912. /**
  154913. * Gets or sets whether the imagery selection drop-down is currently visible.
  154914. * @type {Boolean}
  154915. * @default false
  154916. */
  154917. this.dropDownVisible = false;
  154918. knockout.track(this, ['imageryProviderViewModels', 'terrainProviderViewModels', 'dropDownVisible']);
  154919. /**
  154920. * Gets the button tooltip. This property is observable.
  154921. * @type {String}
  154922. */
  154923. this.buttonTooltip = undefined;
  154924. knockout.defineProperty(this, 'buttonTooltip', function() {
  154925. var selectedImagery = this.selectedImagery;
  154926. var selectedTerrain = this.selectedTerrain;
  154927. var imageryTip = defined(selectedImagery) ? selectedImagery.name : undefined;
  154928. var terrainTip = defined(selectedTerrain) ? selectedTerrain.name : undefined;
  154929. if (defined(imageryTip) && defined(terrainTip)) {
  154930. return imageryTip + '\n' + terrainTip;
  154931. } else if (defined(imageryTip)) {
  154932. return imageryTip;
  154933. }
  154934. return terrainTip;
  154935. });
  154936. /**
  154937. * Gets the button background image. This property is observable.
  154938. * @type {String}
  154939. */
  154940. this.buttonImageUrl = undefined;
  154941. knockout.defineProperty(this, 'buttonImageUrl', function() {
  154942. var viewModel = this.selectedImagery;
  154943. return defined(viewModel) ? viewModel.iconUrl : undefined;
  154944. });
  154945. /**
  154946. * Gets or sets the currently selected imagery. This property is observable.
  154947. * @type {ProviderViewModel}
  154948. * @default undefined
  154949. */
  154950. this.selectedImagery = undefined;
  154951. var selectedImageryViewModel = knockout.observable();
  154952. this._currentImageryProviders = [];
  154953. knockout.defineProperty(this, 'selectedImagery', {
  154954. get : function() {
  154955. return selectedImageryViewModel();
  154956. },
  154957. set : function(value) {
  154958. if (selectedImageryViewModel() === value) {
  154959. this.dropDownVisible = false;
  154960. return;
  154961. }
  154962. var i;
  154963. var currentImageryProviders = this._currentImageryProviders;
  154964. var currentImageryProvidersLength = currentImageryProviders.length;
  154965. var imageryLayers = this._globe.imageryLayers;
  154966. for (i = 0; i < currentImageryProvidersLength; i++) {
  154967. var layersLength = imageryLayers.length;
  154968. for ( var x = 0; x < layersLength; x++) {
  154969. var layer = imageryLayers.get(x);
  154970. if (layer.imageryProvider === currentImageryProviders[i]) {
  154971. imageryLayers.remove(layer);
  154972. break;
  154973. }
  154974. }
  154975. }
  154976. if (defined(value)) {
  154977. var newProviders = value.creationCommand();
  154978. if (isArray(newProviders)) {
  154979. var newProvidersLength = newProviders.length;
  154980. for (i = newProvidersLength - 1; i >= 0; i--) {
  154981. imageryLayers.addImageryProvider(newProviders[i], 0);
  154982. }
  154983. this._currentImageryProviders = newProviders.slice(0);
  154984. } else {
  154985. this._currentImageryProviders = [newProviders];
  154986. imageryLayers.addImageryProvider(newProviders, 0);
  154987. }
  154988. }
  154989. selectedImageryViewModel(value);
  154990. this.dropDownVisible = false;
  154991. }
  154992. });
  154993. /**
  154994. * Gets or sets the currently selected terrain. This property is observable.
  154995. * @type {ProviderViewModel}
  154996. * @default undefined
  154997. */
  154998. this.selectedTerrain = undefined;
  154999. var selectedTerrainViewModel = knockout.observable();
  155000. knockout.defineProperty(this, 'selectedTerrain', {
  155001. get : function() {
  155002. return selectedTerrainViewModel();
  155003. },
  155004. set : function(value) {
  155005. if (selectedTerrainViewModel() === value) {
  155006. this.dropDownVisible = false;
  155007. return;
  155008. }
  155009. var newProvider;
  155010. if (defined(value)) {
  155011. newProvider = value.creationCommand();
  155012. }
  155013. this._globe.depthTestAgainstTerrain = !(newProvider instanceof EllipsoidTerrainProvider);
  155014. this._globe.terrainProvider = newProvider;
  155015. selectedTerrainViewModel(value);
  155016. this.dropDownVisible = false;
  155017. }
  155018. });
  155019. var that = this;
  155020. this._toggleDropDown = createCommand(function() {
  155021. that.dropDownVisible = !that.dropDownVisible;
  155022. });
  155023. this.selectedImagery = defaultValue(options.selectedImageryProviderViewModel, imageryProviderViewModels[0]);
  155024. this.selectedTerrain = defaultValue(options.selectedTerrainProviderViewModel, terrainProviderViewModels[0]);
  155025. }
  155026. defineProperties(BaseLayerPickerViewModel.prototype, {
  155027. /**
  155028. * Gets the command to toggle the visibility of the drop down.
  155029. * @memberof BaseLayerPickerViewModel.prototype
  155030. *
  155031. * @type {Command}
  155032. */
  155033. toggleDropDown : {
  155034. get : function() {
  155035. return this._toggleDropDown;
  155036. }
  155037. },
  155038. /**
  155039. * Gets the globe.
  155040. * @memberof BaseLayerPickerViewModel.prototype
  155041. *
  155042. * @type {Globe}
  155043. */
  155044. globe : {
  155045. get : function() {
  155046. return this._globe;
  155047. }
  155048. }
  155049. });
  155050. return BaseLayerPickerViewModel;
  155051. });
  155052. /*global define*/
  155053. define('Widgets/BaseLayerPicker/BaseLayerPicker',[
  155054. '../../Core/defined',
  155055. '../../Core/defineProperties',
  155056. '../../Core/destroyObject',
  155057. '../../Core/DeveloperError',
  155058. '../../Core/FeatureDetection',
  155059. '../../ThirdParty/knockout',
  155060. '../getElement',
  155061. './BaseLayerPickerViewModel'
  155062. ], function(
  155063. defined,
  155064. defineProperties,
  155065. destroyObject,
  155066. DeveloperError,
  155067. FeatureDetection,
  155068. knockout,
  155069. getElement,
  155070. BaseLayerPickerViewModel) {
  155071. 'use strict';
  155072. /**
  155073. * <span style="display: block; text-align: center;">
  155074. * <img src="images/BaseLayerPicker.png" width="264" height="287" alt="" />
  155075. * <br />BaseLayerPicker with its drop-panel open.
  155076. * </span>
  155077. * <br /><br />
  155078. * The BaseLayerPicker is a single button widget that displays a panel of available imagery and
  155079. * terrain providers. When imagery is selected, the corresponding imagery layer is created and inserted
  155080. * as the base layer of the imagery collection; removing the existing base. When terrain is selected,
  155081. * it replaces the current terrain provider. Each item in the available providers list contains a name,
  155082. * a representative icon, and a tooltip to display more information when hovered. The list is initially
  155083. * empty, and must be configured before use, as illustrated in the below example.
  155084. *
  155085. * @alias BaseLayerPicker
  155086. * @constructor
  155087. *
  155088. * @param {Element|String} container The parent HTML container node or ID for this widget.
  155089. * @param {Object} options Object with the following properties:
  155090. * @param {Globe} options.globe The Globe to use.
  155091. * @param {ProviderViewModel[]} [options.imageryProviderViewModels=[]] The array of ProviderViewModel instances to use for imagery.
  155092. * @param {ProviderViewModel} [options.selectedImageryProviderViewModel] The view model for the current base imagery layer, if not supplied the first available imagery layer is used.
  155093. * @param {ProviderViewModel[]} [options.terrainProviderViewModels=[]] The array of ProviderViewModel instances to use for terrain.
  155094. * @param {ProviderViewModel} [options.selectedTerrainProviderViewModel] The view model for the current base terrain layer, if not supplied the first available terrain layer is used.
  155095. *
  155096. * @exception {DeveloperError} Element with id "container" does not exist in the document.
  155097. *
  155098. *
  155099. * @example
  155100. * // In HTML head, include a link to the BaseLayerPicker.css stylesheet,
  155101. * // and in the body, include: <div id="baseLayerPickerContainer"
  155102. * // style="position:absolute;top:24px;right:24px;width:38px;height:38px;"></div>
  155103. *
  155104. * //Create the list of available providers we would like the user to select from.
  155105. * //This example uses 3, OpenStreetMap, The Black Marble, and a single, non-streaming world image.
  155106. * var imageryViewModels = [];
  155107. * imageryViewModels.push(new Cesium.ProviderViewModel({
  155108. * name : 'Open\u00adStreet\u00adMap',
  155109. * iconUrl : Cesium.buildModuleUrl('Widgets/Images/ImageryProviders/openStreetMap.png'),
  155110. * tooltip : 'OpenStreetMap (OSM) is a collaborative project to create a free editable \
  155111. * map of the world.\nhttp://www.openstreetmap.org',
  155112. * creationFunction : function() {
  155113. * return Cesium.createOpenStreetMapImageryProvider({
  155114. * url : 'https://a.tile.openstreetmap.org/'
  155115. * });
  155116. * }
  155117. * }));
  155118. *
  155119. * imageryViewModels.push(new Cesium.ProviderViewModel({
  155120. * name : 'Black Marble',
  155121. * iconUrl : Cesium.buildModuleUrl('Widgets/Images/ImageryProviders/blackMarble.png'),
  155122. * tooltip : 'The lights of cities and villages trace the outlines of civilization \
  155123. * in this global view of the Earth at night as seen by NASA/NOAA\'s Suomi NPP satellite.',
  155124. * creationFunction : function() {
  155125. * return Cesium.createTileMapServiceImageryProvider({
  155126. * url : 'https://cesiumjs.org/blackmarble',
  155127. * credit : 'Black Marble imagery courtesy NASA Earth Observatory',
  155128. * flipXY : true
  155129. * });
  155130. * }
  155131. * }));
  155132. *
  155133. * imageryViewModels.push(new Cesium.ProviderViewModel({
  155134. * name : 'Natural Earth\u00a0II',
  155135. * iconUrl : Cesium.buildModuleUrl('Widgets/Images/ImageryProviders/naturalEarthII.png'),
  155136. * tooltip : 'Natural Earth II, darkened for contrast.\nhttp://www.naturalearthdata.com/',
  155137. * creationFunction : function() {
  155138. * return Cesium.createTileMapServiceImageryProvider({
  155139. * url : Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII')
  155140. * });
  155141. * }
  155142. * }));
  155143. *
  155144. * //Create a CesiumWidget without imagery, if you haven't already done so.
  155145. * var cesiumWidget = new Cesium.CesiumWidget('cesiumContainer', { imageryProvider: false });
  155146. *
  155147. * //Finally, create the baseLayerPicker widget using our view models.
  155148. * var layers = cesiumWidget.imageryLayers;
  155149. * var baseLayerPicker = new Cesium.BaseLayerPicker('baseLayerPickerContainer', {
  155150. * globe : cesiumWidget.scene.globe,
  155151. * imageryProviderViewModels : imageryViewModels
  155152. * });
  155153. *
  155154. * @see TerrainProvider
  155155. * @see ImageryProvider
  155156. * @see ImageryLayerCollection
  155157. */
  155158. function BaseLayerPicker(container, options) {
  155159. if (!defined(container)) {
  155160. throw new DeveloperError('container is required.');
  155161. }
  155162. container = getElement(container);
  155163. var viewModel = new BaseLayerPickerViewModel(options);
  155164. var element = document.createElement('button');
  155165. element.type = 'button';
  155166. element.className = 'cesium-button cesium-toolbar-button';
  155167. element.setAttribute('data-bind', '\
  155168. attr: { title: buttonTooltip },\
  155169. click: toggleDropDown');
  155170. container.appendChild(element);
  155171. var imgElement = document.createElement('img');
  155172. imgElement.setAttribute('draggable', 'false');
  155173. imgElement.className = 'cesium-baseLayerPicker-selected';
  155174. imgElement.setAttribute('data-bind', '\
  155175. attr: { src: buttonImageUrl }');
  155176. element.appendChild(imgElement);
  155177. var dropPanel = document.createElement('div');
  155178. dropPanel.className = 'cesium-baseLayerPicker-dropDown';
  155179. dropPanel.setAttribute('data-bind', '\
  155180. css: { "cesium-baseLayerPicker-dropDown-visible" : dropDownVisible }');
  155181. container.appendChild(dropPanel);
  155182. var imageryTitle = document.createElement('div');
  155183. imageryTitle.className = 'cesium-baseLayerPicker-sectionTitle';
  155184. imageryTitle.setAttribute('data-bind', 'visible: imageryProviderViewModels.length > 0');
  155185. imageryTitle.innerHTML = 'Imagery';
  155186. dropPanel.appendChild(imageryTitle);
  155187. var imageryChoices = document.createElement('div');
  155188. imageryChoices.className = 'cesium-baseLayerPicker-choices';
  155189. imageryChoices.setAttribute('data-bind', 'foreach: imageryProviderViewModels');
  155190. dropPanel.appendChild(imageryChoices);
  155191. var imageryProvider = document.createElement('div');
  155192. imageryProvider.className = 'cesium-baseLayerPicker-item';
  155193. imageryProvider.setAttribute('data-bind', '\
  155194. css: { "cesium-baseLayerPicker-selectedItem" : $data === $parent.selectedImagery },\
  155195. attr: { title: tooltip },\
  155196. visible: creationCommand.canExecute,\
  155197. click: function($data) { $parent.selectedImagery = $data; }');
  155198. imageryChoices.appendChild(imageryProvider);
  155199. var providerIcon = document.createElement('img');
  155200. providerIcon.className = 'cesium-baseLayerPicker-itemIcon';
  155201. providerIcon.setAttribute('data-bind', 'attr: { src: iconUrl }');
  155202. providerIcon.setAttribute('draggable', 'false');
  155203. imageryProvider.appendChild(providerIcon);
  155204. var providerLabel = document.createElement('div');
  155205. providerLabel.className = 'cesium-baseLayerPicker-itemLabel';
  155206. providerLabel.setAttribute('data-bind', 'text: name');
  155207. imageryProvider.appendChild(providerLabel);
  155208. var terrainTitle = document.createElement('div');
  155209. terrainTitle.className = 'cesium-baseLayerPicker-sectionTitle';
  155210. terrainTitle.setAttribute('data-bind', 'visible: terrainProviderViewModels.length > 0');
  155211. terrainTitle.innerHTML = 'Terrain';
  155212. dropPanel.appendChild(terrainTitle);
  155213. var terrainChoices = document.createElement('div');
  155214. terrainChoices.className = 'cesium-baseLayerPicker-choices';
  155215. terrainChoices.setAttribute('data-bind', 'foreach: terrainProviderViewModels');
  155216. dropPanel.appendChild(terrainChoices);
  155217. var terrainProvider = document.createElement('div');
  155218. terrainProvider.className = 'cesium-baseLayerPicker-item';
  155219. terrainProvider.setAttribute('data-bind', '\
  155220. css: { "cesium-baseLayerPicker-selectedItem" : $data === $parent.selectedTerrain },\
  155221. attr: { title: tooltip },\
  155222. visible: creationCommand.canExecute,\
  155223. click: function($data) { $parent.selectedTerrain = $data; }');
  155224. terrainChoices.appendChild(terrainProvider);
  155225. var terrainProviderIcon = document.createElement('img');
  155226. terrainProviderIcon.className = 'cesium-baseLayerPicker-itemIcon';
  155227. terrainProviderIcon.setAttribute('data-bind', 'attr: { src: iconUrl }');
  155228. terrainProviderIcon.setAttribute('draggable', 'false');
  155229. terrainProvider.appendChild(terrainProviderIcon);
  155230. var terrainProviderLabel = document.createElement('div');
  155231. terrainProviderLabel.className = 'cesium-baseLayerPicker-itemLabel';
  155232. terrainProviderLabel.setAttribute('data-bind', 'text: name');
  155233. terrainProvider.appendChild(terrainProviderLabel);
  155234. knockout.applyBindings(viewModel, element);
  155235. knockout.applyBindings(viewModel, dropPanel);
  155236. this._viewModel = viewModel;
  155237. this._container = container;
  155238. this._element = element;
  155239. this._dropPanel = dropPanel;
  155240. this._closeDropDown = function(e) {
  155241. if (!(element.contains(e.target) || dropPanel.contains(e.target))) {
  155242. viewModel.dropDownVisible = false;
  155243. }
  155244. };
  155245. if (FeatureDetection.supportsPointerEvents()) {
  155246. document.addEventListener('pointerdown', this._closeDropDown, true);
  155247. } else {
  155248. document.addEventListener('mousedown', this._closeDropDown, true);
  155249. document.addEventListener('touchstart', this._closeDropDown, true);
  155250. }
  155251. }
  155252. defineProperties(BaseLayerPicker.prototype, {
  155253. /**
  155254. * Gets the parent container.
  155255. * @memberof BaseLayerPicker.prototype
  155256. *
  155257. * @type {Element}
  155258. */
  155259. container : {
  155260. get : function() {
  155261. return this._container;
  155262. }
  155263. },
  155264. /**
  155265. * Gets the view model.
  155266. * @memberof BaseLayerPicker.prototype
  155267. *
  155268. * @type {BaseLayerPickerViewModel}
  155269. */
  155270. viewModel : {
  155271. get : function() {
  155272. return this._viewModel;
  155273. }
  155274. }
  155275. });
  155276. /**
  155277. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  155278. */
  155279. BaseLayerPicker.prototype.isDestroyed = function() {
  155280. return false;
  155281. };
  155282. /**
  155283. * Destroys the widget. Should be called if permanently
  155284. * removing the widget from layout.
  155285. */
  155286. BaseLayerPicker.prototype.destroy = function() {
  155287. if (FeatureDetection.supportsPointerEvents()) {
  155288. document.removeEventListener('pointerdown', this._closeDropDown, true);
  155289. } else {
  155290. document.removeEventListener('mousedown', this._closeDropDown, true);
  155291. document.removeEventListener('touchstart', this._closeDropDown, true);
  155292. }
  155293. knockout.cleanNode(this._element);
  155294. knockout.cleanNode(this._dropPanel);
  155295. this._container.removeChild(this._element);
  155296. this._container.removeChild(this._dropPanel);
  155297. return destroyObject(this);
  155298. };
  155299. return BaseLayerPicker;
  155300. });
  155301. /*global define*/
  155302. define('Widgets/BaseLayerPicker/ProviderViewModel',[
  155303. '../../Core/defined',
  155304. '../../Core/defineProperties',
  155305. '../../Core/DeveloperError',
  155306. '../../ThirdParty/knockout',
  155307. '../createCommand'
  155308. ], function(
  155309. defined,
  155310. defineProperties,
  155311. DeveloperError,
  155312. knockout,
  155313. createCommand) {
  155314. 'use strict';
  155315. /**
  155316. * A view model that represents each item in the {@link BaseLayerPicker}.
  155317. *
  155318. * @alias ProviderViewModel
  155319. * @constructor
  155320. *
  155321. * @param {Object} options The object containing all parameters.
  155322. * @param {String} options.name The name of the layer.
  155323. * @param {String} options.tooltip The tooltip to show when the item is moused over.
  155324. * @param {String} options.iconUrl An icon representing the layer.
  155325. * @param {ProviderViewModel~CreationFunction|Command} options.creationFunction A function or Command
  155326. * that creates one or more providers which will be added to the globe when this item is selected.
  155327. *
  155328. * @see BaseLayerPicker
  155329. * @see ImageryProvider
  155330. * @see TerrainProvider
  155331. */
  155332. function ProviderViewModel(options) {
  155333. if (!defined(options.name)) {
  155334. throw new DeveloperError('options.name is required.');
  155335. }
  155336. if (!defined(options.tooltip)) {
  155337. throw new DeveloperError('options.tooltip is required.');
  155338. }
  155339. if (!defined(options.iconUrl)) {
  155340. throw new DeveloperError('options.iconUrl is required.');
  155341. }
  155342. if (typeof options.creationFunction !== 'function') {
  155343. throw new DeveloperError('options.creationFunction is required.');
  155344. }
  155345. var creationCommand = options.creationFunction;
  155346. if (!defined(creationCommand.canExecute)) {
  155347. creationCommand = createCommand(creationCommand);
  155348. }
  155349. this._creationCommand = creationCommand;
  155350. /**
  155351. * Gets the display name. This property is observable.
  155352. * @type {String}
  155353. */
  155354. this.name = options.name;
  155355. /**
  155356. * Gets the tooltip. This property is observable.
  155357. * @type {String}
  155358. */
  155359. this.tooltip = options.tooltip;
  155360. /**
  155361. * Gets the icon. This property is observable.
  155362. * @type {String}
  155363. */
  155364. this.iconUrl = options.iconUrl;
  155365. knockout.track(this, ['name', 'tooltip', 'iconUrl']);
  155366. }
  155367. defineProperties(ProviderViewModel.prototype, {
  155368. /**
  155369. * Gets the Command that creates one or more providers which will be added to
  155370. * the globe when this item is selected.
  155371. * @memberof ProviderViewModel.prototype
  155372. *
  155373. * @type {Command}
  155374. */
  155375. creationCommand : {
  155376. get : function() {
  155377. return this._creationCommand;
  155378. }
  155379. }
  155380. });
  155381. /**
  155382. * A function which creates one or more providers.
  155383. * @callback ProviderViewModel~CreationFunction
  155384. * @returns {ImageryProvider|TerrainProvider|ImageryProvider[]|TerrainProvider[]}
  155385. * The ImageryProvider or TerrainProvider, or array of providers, to be added
  155386. * to the globe.
  155387. */
  155388. return ProviderViewModel;
  155389. });
  155390. /*global define*/
  155391. define('Widgets/BaseLayerPicker/createDefaultImageryProviderViewModels',[
  155392. '../../Core/buildModuleUrl',
  155393. '../../Scene/ArcGisMapServerImageryProvider',
  155394. '../../Scene/BingMapsImageryProvider',
  155395. '../../Scene/BingMapsStyle',
  155396. '../../Scene/createOpenStreetMapImageryProvider',
  155397. '../../Scene/createTileMapServiceImageryProvider',
  155398. '../../Scene/MapboxImageryProvider',
  155399. '../BaseLayerPicker/ProviderViewModel'
  155400. ], function(
  155401. buildModuleUrl,
  155402. ArcGisMapServerImageryProvider,
  155403. BingMapsImageryProvider,
  155404. BingMapsStyle,
  155405. createOpenStreetMapImageryProvider,
  155406. createTileMapServiceImageryProvider,
  155407. MapboxImageryProvider,
  155408. ProviderViewModel) {
  155409. 'use strict';
  155410. /**
  155411. * @private
  155412. */
  155413. function createDefaultImageryProviderViewModels() {
  155414. var providerViewModels = [];
  155415. providerViewModels.push(new ProviderViewModel({
  155416. name : 'Bing Maps Aerial',
  155417. iconUrl : buildModuleUrl('Widgets/Images/ImageryProviders/bingAerial.png'),
  155418. tooltip : 'Bing Maps aerial imagery \nhttp://www.bing.com/maps',
  155419. creationFunction : function() {
  155420. return new BingMapsImageryProvider({
  155421. url : 'https://dev.virtualearth.net',
  155422. mapStyle : BingMapsStyle.AERIAL
  155423. });
  155424. }
  155425. }));
  155426. providerViewModels.push(new ProviderViewModel({
  155427. name : 'Bing Maps Aerial with Labels',
  155428. iconUrl : buildModuleUrl('Widgets/Images/ImageryProviders/bingAerialLabels.png'),
  155429. tooltip : 'Bing Maps aerial imagery with label overlays \nhttp://www.bing.com/maps',
  155430. creationFunction : function() {
  155431. return new BingMapsImageryProvider({
  155432. url : 'https://dev.virtualearth.net',
  155433. mapStyle : BingMapsStyle.AERIAL_WITH_LABELS
  155434. });
  155435. }
  155436. }));
  155437. providerViewModels.push(new ProviderViewModel({
  155438. name : 'Bing Maps Roads',
  155439. iconUrl : buildModuleUrl('Widgets/Images/ImageryProviders/bingRoads.png'),
  155440. tooltip : 'Bing Maps standard road maps\nhttp://www.bing.com/maps',
  155441. creationFunction : function() {
  155442. return new BingMapsImageryProvider({
  155443. url : 'https://dev.virtualearth.net',
  155444. mapStyle : BingMapsStyle.ROAD
  155445. });
  155446. }
  155447. }));
  155448. providerViewModels.push(new ProviderViewModel({
  155449. name: 'Mapbox Satellite',
  155450. tooltip: 'Mapbox satellite imagery https://www.mapbox.com/maps/',
  155451. iconUrl: buildModuleUrl('Widgets/Images/ImageryProviders/mapboxSatellite.png'),
  155452. creationFunction: function() {
  155453. return new MapboxImageryProvider({
  155454. mapId: 'mapbox.satellite'
  155455. });
  155456. }
  155457. }));
  155458. providerViewModels.push(new ProviderViewModel({
  155459. name: 'Mapbox Streets',
  155460. tooltip: 'Mapbox streets imagery https://www.mapbox.com/maps/',
  155461. iconUrl: buildModuleUrl('Widgets/Images/ImageryProviders/mapboxTerrain.png'),
  155462. creationFunction: function() {
  155463. return new MapboxImageryProvider({
  155464. mapId: 'mapbox.streets'
  155465. });
  155466. }
  155467. }));
  155468. providerViewModels.push(new ProviderViewModel({
  155469. name: 'Mapbox Streets Classic',
  155470. tooltip: 'Mapbox streets basic imagery https://www.mapbox.com/maps/',
  155471. iconUrl: buildModuleUrl('Widgets/Images/ImageryProviders/mapboxStreets.png'),
  155472. creationFunction: function() {
  155473. return new MapboxImageryProvider({
  155474. mapId: 'mapbox.streets-basic'
  155475. });
  155476. }
  155477. }));
  155478. providerViewModels.push(new ProviderViewModel({
  155479. name : 'ESRI World Imagery',
  155480. iconUrl : buildModuleUrl('Widgets/Images/ImageryProviders/esriWorldImagery.png'),
  155481. tooltip : '\
  155482. World Imagery provides one meter or better satellite and aerial imagery in many parts of the world and lower resolution \
  155483. satellite imagery worldwide. The map includes NASA Blue Marble: Next Generation 500m resolution imagery at small scales \
  155484. (above 1:1,000,000), i-cubed 15m eSAT imagery at medium-to-large scales (down to 1:70,000) for the world, and USGS 15m Landsat \
  155485. imagery for Antarctica. The map features 0.3m resolution imagery in the continental United States and 0.6m resolution imagery in \
  155486. parts of Western Europe from DigitalGlobe. In other parts of the world, 1 meter resolution imagery is available from GeoEye IKONOS, \
  155487. i-cubed Nationwide Prime, Getmapping, AeroGRID, IGN Spain, and IGP Portugal. Additionally, imagery at different resolutions has been \
  155488. contributed by the GIS User Community.\nhttp://www.esri.com',
  155489. creationFunction : function() {
  155490. return new ArcGisMapServerImageryProvider({
  155491. url : 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer',
  155492. enablePickFeatures : false
  155493. });
  155494. }
  155495. }));
  155496. providerViewModels.push(new ProviderViewModel({
  155497. name : 'ESRI World Street Map',
  155498. iconUrl : buildModuleUrl('Widgets/Images/ImageryProviders/esriWorldStreetMap.png'),
  155499. tooltip : '\
  155500. This worldwide street map presents highway-level data for the world. Street-level data includes the United States; much of \
  155501. Canada; Japan; most countries in Europe; Australia and New Zealand; India; parts of South America including Argentina, Brazil, \
  155502. Chile, Colombia, and Venezuela; Ghana; and parts of southern Africa including Botswana, Lesotho, Namibia, South Africa, and Swaziland.\n\
  155503. http://www.esri.com',
  155504. creationFunction : function() {
  155505. return new ArcGisMapServerImageryProvider({
  155506. url : 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer',
  155507. enablePickFeatures : false
  155508. });
  155509. }
  155510. }));
  155511. providerViewModels.push(new ProviderViewModel({
  155512. name : 'ESRI National Geographic',
  155513. iconUrl : buildModuleUrl('Widgets/Images/ImageryProviders/esriNationalGeographic.png'),
  155514. tooltip : '\
  155515. This web map contains the National Geographic World Map service. This map service is designed to be used as a general reference map \
  155516. for informational and educational purposes as well as a basemap by GIS professionals and other users for creating web maps and web \
  155517. mapping applications.\nhttp://www.esri.com',
  155518. creationFunction : function() {
  155519. return new ArcGisMapServerImageryProvider({
  155520. url : 'https://services.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/',
  155521. enablePickFeatures : false
  155522. });
  155523. }
  155524. }));
  155525. providerViewModels.push(new ProviderViewModel({
  155526. name : 'Open\u00adStreet\u00adMap',
  155527. iconUrl : buildModuleUrl('Widgets/Images/ImageryProviders/openStreetMap.png'),
  155528. tooltip : 'OpenStreetMap (OSM) is a collaborative project to create a free editable map \
  155529. of the world.\nhttp://www.openstreetmap.org',
  155530. creationFunction : function() {
  155531. return createOpenStreetMapImageryProvider({
  155532. url : 'https://a.tile.openstreetmap.org/'
  155533. });
  155534. }
  155535. }));
  155536. providerViewModels.push(new ProviderViewModel({
  155537. name : 'Stamen Watercolor',
  155538. iconUrl : buildModuleUrl('Widgets/Images/ImageryProviders/stamenWatercolor.png'),
  155539. tooltip : 'Reminiscent of hand drawn maps, Stamen watercolor maps apply raster effect \
  155540. area washes and organic edges over a paper texture to add warm pop to any map.\nhttp://maps.stamen.com',
  155541. creationFunction : function() {
  155542. return createOpenStreetMapImageryProvider({
  155543. url : 'https://stamen-tiles.a.ssl.fastly.net/watercolor/',
  155544. credit : 'Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA.'
  155545. });
  155546. }
  155547. }));
  155548. providerViewModels.push(new ProviderViewModel({
  155549. name : 'Stamen Toner',
  155550. iconUrl : buildModuleUrl('Widgets/Images/ImageryProviders/stamenToner.png'),
  155551. tooltip : 'A high contrast black and white map.\nhttp://maps.stamen.com',
  155552. creationFunction : function() {
  155553. return createOpenStreetMapImageryProvider({
  155554. url : 'https://stamen-tiles.a.ssl.fastly.net/toner/',
  155555. credit : 'Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA.'
  155556. });
  155557. }
  155558. }));
  155559. providerViewModels.push(new ProviderViewModel({
  155560. name : 'The Black Marble',
  155561. iconUrl : buildModuleUrl('Widgets/Images/ImageryProviders/blackMarble.png'),
  155562. tooltip : 'The lights of cities and villages trace the outlines of civilization in this global view of the \
  155563. Earth at night as seen by NASA/NOAA\'s Suomi NPP satellite.',
  155564. creationFunction : function() {
  155565. return createTileMapServiceImageryProvider({
  155566. url : 'https://cesiumjs.org/blackmarble',
  155567. flipXY : true,
  155568. credit : 'Black Marble imagery courtesy NASA Earth Observatory'
  155569. });
  155570. }
  155571. }));
  155572. providerViewModels.push(new ProviderViewModel({
  155573. name : 'Natural Earth\u00a0II',
  155574. iconUrl : buildModuleUrl('Widgets/Images/ImageryProviders/naturalEarthII.png'),
  155575. tooltip : 'Natural Earth II, darkened for contrast.\nhttp://www.naturalearthdata.com/',
  155576. creationFunction : function() {
  155577. return createTileMapServiceImageryProvider({
  155578. url : buildModuleUrl('Assets/Textures/NaturalEarthII')
  155579. });
  155580. }
  155581. }));
  155582. return providerViewModels;
  155583. }
  155584. return createDefaultImageryProviderViewModels;
  155585. });
  155586. /*global define*/
  155587. define('Widgets/BaseLayerPicker/createDefaultTerrainProviderViewModels',[
  155588. '../../Core/buildModuleUrl',
  155589. '../../Core/CesiumTerrainProvider',
  155590. '../../Core/EllipsoidTerrainProvider',
  155591. '../BaseLayerPicker/ProviderViewModel'
  155592. ], function(
  155593. buildModuleUrl,
  155594. CesiumTerrainProvider,
  155595. EllipsoidTerrainProvider,
  155596. ProviderViewModel) {
  155597. 'use strict';
  155598. /**
  155599. * @private
  155600. */
  155601. function createDefaultTerrainProviderViewModels() {
  155602. var providerViewModels = [];
  155603. providerViewModels.push(new ProviderViewModel({
  155604. name : 'WGS84 Ellipsoid',
  155605. iconUrl : buildModuleUrl('Widgets/Images/TerrainProviders/Ellipsoid.png'),
  155606. tooltip : 'WGS84 standard ellipsoid, also known as EPSG:4326',
  155607. creationFunction : function() {
  155608. return new EllipsoidTerrainProvider();
  155609. }
  155610. }));
  155611. providerViewModels.push(new ProviderViewModel({
  155612. name : 'STK World Terrain meshes',
  155613. iconUrl : buildModuleUrl('Widgets/Images/TerrainProviders/STK.png'),
  155614. tooltip : 'High-resolution, mesh-based terrain for the entire globe. Free for use on the Internet. Closed-network options are available.\nhttp://www.agi.com',
  155615. creationFunction : function() {
  155616. return new CesiumTerrainProvider({
  155617. url : 'https://assets.agi.com/stk-terrain/world',
  155618. requestWaterMask : true,
  155619. requestVertexNormals : true
  155620. });
  155621. }
  155622. }));
  155623. return providerViewModels;
  155624. }
  155625. return createDefaultTerrainProviderViewModels;
  155626. });
  155627. /*global define*/
  155628. define('Widgets/CesiumInspector/CesiumInspectorViewModel',[
  155629. '../../Core/defined',
  155630. '../../Core/defineProperties',
  155631. '../../Core/destroyObject',
  155632. '../../Core/DeveloperError',
  155633. '../../Core/Rectangle',
  155634. '../../Core/ScreenSpaceEventHandler',
  155635. '../../Core/ScreenSpaceEventType',
  155636. '../../Scene/DebugModelMatrixPrimitive',
  155637. '../../Scene/PerformanceDisplay',
  155638. '../../Scene/TileCoordinatesImageryProvider',
  155639. '../../ThirdParty/knockout',
  155640. '../createCommand'
  155641. ], function(
  155642. defined,
  155643. defineProperties,
  155644. destroyObject,
  155645. DeveloperError,
  155646. Rectangle,
  155647. ScreenSpaceEventHandler,
  155648. ScreenSpaceEventType,
  155649. DebugModelMatrixPrimitive,
  155650. PerformanceDisplay,
  155651. TileCoordinatesImageryProvider,
  155652. knockout,
  155653. createCommand) {
  155654. 'use strict';
  155655. function frustumStatsToString(stats) {
  155656. var str;
  155657. if (defined(stats)) {
  155658. str = 'Command Statistics';
  155659. var com = stats.commandsInFrustums;
  155660. for (var n in com) {
  155661. if (com.hasOwnProperty(n)) {
  155662. var num = parseInt(n, 10);
  155663. var s;
  155664. if (num === 7) {
  155665. s = '1, 2 and 3';
  155666. } else {
  155667. var f = [];
  155668. for (var i = 2; i >= 0; i--) {
  155669. var p = Math.pow(2, i);
  155670. if (num >= p) {
  155671. f.push(i + 1);
  155672. num -= p;
  155673. }
  155674. }
  155675. s = f.reverse().join(' and ');
  155676. }
  155677. str += '<br>&nbsp;&nbsp;&nbsp;&nbsp;' + com[n] + ' in frustum ' + s;
  155678. }
  155679. }
  155680. str += '<br>Total: ' + stats.totalCommands;
  155681. }
  155682. return str;
  155683. }
  155684. function boundDepthFrustum(lower, upper, proposed) {
  155685. var bounded = Math.min(proposed, upper);
  155686. bounded = Math.max(bounded, lower);
  155687. return bounded;
  155688. }
  155689. /**
  155690. * The view model for {@link CesiumInspector}.
  155691. * @alias CesiumInspectorViewModel
  155692. * @constructor
  155693. *
  155694. * @param {Scene} scene The scene instance to use.
  155695. *
  155696. * @exception {DeveloperError} scene is required.
  155697. */
  155698. function CesiumInspectorViewModel(scene, performanceContainer) {
  155699. if (!defined(scene)) {
  155700. throw new DeveloperError('scene is required');
  155701. }
  155702. if (!defined(performanceContainer)) {
  155703. throw new DeveloperError('performanceContainer is required');
  155704. }
  155705. var that = this;
  155706. var canvas = scene.canvas;
  155707. var eventHandler = new ScreenSpaceEventHandler(canvas);
  155708. this._eventHandler = eventHandler;
  155709. this._scene = scene;
  155710. this._canvas = canvas;
  155711. this._primitive = undefined;
  155712. this._tile = undefined;
  155713. this._modelMatrixPrimitive = undefined;
  155714. this._performanceDisplay = undefined;
  155715. this._performanceContainer = performanceContainer;
  155716. var globe = this._scene.globe;
  155717. globe.depthTestAgainstTerrain = true;
  155718. /**
  155719. * Gets or sets the show frustums state. This property is observable.
  155720. * @type {Boolean}
  155721. * @default false
  155722. */
  155723. this.frustums = false;
  155724. /**
  155725. * Gets or sets the show performance display state. This property is observable.
  155726. * @type {Boolean}
  155727. * @default false
  155728. */
  155729. this.performance = false;
  155730. /**
  155731. * Gets or sets the shader cache text. This property is observable.
  155732. * @type {String}
  155733. * @default ''
  155734. */
  155735. this.shaderCacheText = '';
  155736. /**
  155737. * Gets or sets the show primitive bounding sphere state. This property is observable.
  155738. * @type {Boolean}
  155739. * @default false
  155740. */
  155741. this.primitiveBoundingSphere = false;
  155742. /**
  155743. * Gets or sets the show primitive reference frame state. This property is observable.
  155744. * @type {Boolean}
  155745. * @default false
  155746. */
  155747. this.primitiveReferenceFrame = false;
  155748. /**
  155749. * Gets or sets the filter primitive state. This property is observable.
  155750. * @type {Boolean}
  155751. * @default false
  155752. */
  155753. this.filterPrimitive = false;
  155754. /**
  155755. * Gets or sets the show tile bounding sphere state. This property is observable.
  155756. * @type {Boolean}
  155757. * @default false
  155758. */
  155759. this.tileBoundingSphere = false;
  155760. /**
  155761. * Gets or sets the filter tile state. This property is observable.
  155762. * @type {Boolean}
  155763. * @default false
  155764. */
  155765. this.filterTile = false;
  155766. /**
  155767. * Gets or sets the show wireframe state. This property is observable.
  155768. * @type {Boolean}
  155769. * @default false
  155770. */
  155771. this.wireframe = false;
  155772. /**
  155773. * Gets or sets the show globe depth state. This property is observable.
  155774. * @type {Boolean}
  155775. * @default false
  155776. */
  155777. this.globeDepth = false;
  155778. /**
  155779. * Gets or sets the show pick depth state. This property is observable.
  155780. * @type {Boolean}
  155781. * @default false
  155782. */
  155783. this.pickDepth = false;
  155784. /**
  155785. * Gets or sets the index of the depth frustum to display. This property is observable.
  155786. * @type {Number}
  155787. * @default 1
  155788. */
  155789. this.depthFrustum = 1;
  155790. this._numberOfFrustums = 1;
  155791. /**
  155792. * Gets or sets the index of the depth frustum text. This property is observable.
  155793. * @type {String}
  155794. * @default '1 of 1'
  155795. */
  155796. this.depthFrustumText = '1 of 1';
  155797. /**
  155798. * Gets or sets the suspend updates state. This property is observable.
  155799. * @type {Boolean}
  155800. * @default false
  155801. */
  155802. this.suspendUpdates = false;
  155803. /**
  155804. * Gets or sets the show tile coordinates state. This property is observable.
  155805. * @type {Boolean}
  155806. * @default false
  155807. */
  155808. this.tileCoordinates = false;
  155809. /**
  155810. * Gets or sets the frustum statistic text. This property is observable.
  155811. * @type {String}
  155812. * @default ''
  155813. */
  155814. this.frustumStatisticText = '';
  155815. /**
  155816. * Gets or sets the selected tile information text. This property is observable.
  155817. * @type {String}
  155818. * @default ''
  155819. */
  155820. this.tileText = '';
  155821. /**
  155822. * Gets if a primitive has been selected. This property is observable.
  155823. * @type {Boolean}
  155824. * @default false
  155825. */
  155826. this.hasPickedPrimitive = false;
  155827. /**
  155828. * Gets if a tile has been selected. This property is observable
  155829. * @type {Boolean}
  155830. * @default false
  155831. */
  155832. this.hasPickedTile = false;
  155833. /**
  155834. * Gets if the picking primitive command is active. This property is observable.
  155835. * @type {Boolean}
  155836. * @default false
  155837. */
  155838. this.pickPimitiveActive = false;
  155839. /**
  155840. * Gets if the picking tile command is active. This property is observable.
  155841. * @type {Boolean}
  155842. * @default false
  155843. */
  155844. this.pickTileActive = false;
  155845. /**
  155846. * Gets or sets if the cesium inspector drop down is visible. This property is observable.
  155847. * @type {Boolean}
  155848. * @default true
  155849. */
  155850. this.dropDownVisible = true;
  155851. /**
  155852. * Gets or sets if the general section is visible. This property is observable.
  155853. * @type {Boolean}
  155854. * @default true
  155855. */
  155856. this.generalVisible = true;
  155857. /**
  155858. * Gets or sets if the primitive section is visible. This property is observable.
  155859. * @type {Boolean}
  155860. * @default false
  155861. */
  155862. this.primitivesVisible = false;
  155863. /**
  155864. * Gets or sets if the terrain section is visible. This property is observable.
  155865. * @type {Boolean}
  155866. * @default false
  155867. */
  155868. this.terrainVisible = false;
  155869. /**
  155870. * Gets or sets if the text on the general section expand button. This property is observable.
  155871. * @type {String}
  155872. * @default '-'
  155873. */
  155874. this.generalSwitchText = '-';
  155875. /**
  155876. * Gets or sets if the text on the primitive section expand button. This property is observable.
  155877. * @type {String}
  155878. * @default '+'
  155879. */
  155880. this.primitivesSwitchText = '+';
  155881. /**
  155882. * Gets or sets if the text on the terrain section expand button. This property is observable.
  155883. * @type {String}
  155884. * @default '+'
  155885. */
  155886. this.terrainSwitchText = '+';
  155887. knockout.track(this, ['filterTile', 'suspendUpdates', 'dropDownVisible', 'shaderCacheText', 'frustums',
  155888. 'frustumStatisticText', 'pickTileActive', 'pickPrimitiveActive', 'hasPickedPrimitive',
  155889. 'hasPickedTile', 'tileText', 'generalVisible', 'generalSwitchText',
  155890. 'primitivesVisible', 'primitivesSwitchText', 'terrainVisible', 'terrainSwitchText', 'depthFrustumText']);
  155891. this._toggleDropDown = createCommand(function() {
  155892. that.dropDownVisible = !that.dropDownVisible;
  155893. });
  155894. this._toggleGeneral = createCommand(function() {
  155895. that.generalVisible = !that.generalVisible;
  155896. that.generalSwitchText = that.generalVisible ? '-' : '+';
  155897. });
  155898. this._togglePrimitives = createCommand(function() {
  155899. that.primitivesVisible = !that.primitivesVisible;
  155900. that.primitivesSwitchText = that.primitivesVisible ? '-' : '+';
  155901. });
  155902. this._toggleTerrain = createCommand(function() {
  155903. that.terrainVisible = !that.terrainVisible;
  155904. that.terrainSwitchText = that.terrainVisible ? '-' : '+';
  155905. });
  155906. this._showFrustums = createCommand(function() {
  155907. if (that.frustums) {
  155908. that._scene.debugShowFrustums = true;
  155909. } else {
  155910. that._scene.debugShowFrustums = false;
  155911. }
  155912. return true;
  155913. });
  155914. this._showPerformance = createCommand(function() {
  155915. if (that.performance) {
  155916. that._performanceDisplay = new PerformanceDisplay({
  155917. container : that._performanceContainer
  155918. });
  155919. } else {
  155920. that._performanceContainer.innerHTML = '';
  155921. }
  155922. return true;
  155923. });
  155924. this._showPrimitiveBoundingSphere = createCommand(function() {
  155925. that._primitive.debugShowBoundingVolume = that.primitiveBoundingSphere;
  155926. return true;
  155927. });
  155928. this._showPrimitiveReferenceFrame = createCommand(function() {
  155929. if (that.primitiveReferenceFrame) {
  155930. var modelMatrix = that._primitive.modelMatrix;
  155931. that._modelMatrixPrimitive = new DebugModelMatrixPrimitive({
  155932. modelMatrix : modelMatrix
  155933. });
  155934. that._scene.primitives.add(that._modelMatrixPrimitive);
  155935. } else if (defined(that._modelMatrixPrimitive)) {
  155936. that._scene.primitives.remove(that._modelMatrixPrimitive);
  155937. that._modelMatrixPrimitive = undefined;
  155938. }
  155939. return true;
  155940. });
  155941. this._doFilterPrimitive = createCommand(function() {
  155942. if (that.filterPrimitive) {
  155943. that._scene.debugCommandFilter = function(command) {
  155944. if (defined(that._modelMatrixPrimitive) && command.owner === that._modelMatrixPrimitive._primitive) {
  155945. return true;
  155946. } else if (defined(that._primitive)) {
  155947. return command.owner === that._primitive || command.owner === that._primitive._billboardCollection || command.owner.primitive === that._primitive;
  155948. }
  155949. return false;
  155950. };
  155951. } else {
  155952. that._scene.debugCommandFilter = undefined;
  155953. }
  155954. return true;
  155955. });
  155956. this._showWireframe = createCommand(function() {
  155957. globe._surface.tileProvider._debug.wireframe = that.wireframe;
  155958. return true;
  155959. });
  155960. this._showGlobeDepth = createCommand(function() {
  155961. that._scene.debugShowGlobeDepth = that.globeDepth;
  155962. return true;
  155963. });
  155964. this._showPickDepth = createCommand(function() {
  155965. that._scene.debugShowPickDepth = that.pickDepth;
  155966. return true;
  155967. });
  155968. this._incrementDepthFrustum = createCommand(function() {
  155969. var next = that.depthFrustum + 1;
  155970. that.depthFrustum = boundDepthFrustum(1, that._numberOfFrustums, next);
  155971. that.scene.debugShowDepthFrustum = that.depthFrustum;
  155972. return true;
  155973. });
  155974. this._decrementDepthFrustum = createCommand(function() {
  155975. var next = that.depthFrustum - 1;
  155976. that.depthFrustum = boundDepthFrustum(1, that._numberOfFrustums, next);
  155977. that.scene.debugShowDepthFrustum = that.depthFrustum;
  155978. return true;
  155979. });
  155980. this._doSuspendUpdates = createCommand(function() {
  155981. globe._surface._debug.suspendLodUpdate = that.suspendUpdates;
  155982. if (!that.suspendUpdates) {
  155983. that.filterTile = false;
  155984. }
  155985. return true;
  155986. });
  155987. var tileBoundariesLayer;
  155988. this._showTileCoordinates = createCommand(function() {
  155989. if (that.tileCoordinates && !defined(tileBoundariesLayer)) {
  155990. tileBoundariesLayer = scene.imageryLayers.addImageryProvider(new TileCoordinatesImageryProvider({
  155991. tilingScheme : scene.terrainProvider.tilingScheme
  155992. }));
  155993. } else if (!that.tileCoordinates && defined(tileBoundariesLayer)) {
  155994. scene.imageryLayers.remove(tileBoundariesLayer);
  155995. tileBoundariesLayer = undefined;
  155996. }
  155997. return true;
  155998. });
  155999. this._showTileBoundingSphere = createCommand(function() {
  156000. if (that.tileBoundingSphere) {
  156001. globe._surface.tileProvider._debug.boundingSphereTile = that._tile;
  156002. } else {
  156003. globe._surface.tileProvider._debug.boundingSphereTile = undefined;
  156004. }
  156005. return true;
  156006. });
  156007. this._doFilterTile = createCommand(function() {
  156008. if (!that.filterTile) {
  156009. that.suspendUpdates = false;
  156010. that.doSuspendUpdates();
  156011. } else {
  156012. that.suspendUpdates = true;
  156013. that.doSuspendUpdates();
  156014. globe._surface._tilesToRender = [];
  156015. if (defined(that._tile)) {
  156016. globe._surface._tilesToRender.push(that._tile);
  156017. }
  156018. }
  156019. return true;
  156020. });
  156021. function pickPrimitive(e) {
  156022. eventHandler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK);
  156023. that.pickPrimitiveActive = false;
  156024. var newPick = that._scene.pick({
  156025. x : e.position.x,
  156026. y : e.position.y
  156027. });
  156028. if (defined(newPick)) {
  156029. that.primitive = defined(newPick.collection) ? newPick.collection : newPick.primitive;
  156030. }
  156031. }
  156032. this._pickPrimitive = createCommand(function() {
  156033. that.pickPrimitiveActive = !that.pickPrimitiveActive;
  156034. if (that.pickPrimitiveActive) {
  156035. eventHandler.setInputAction(pickPrimitive, ScreenSpaceEventType.LEFT_CLICK);
  156036. } else {
  156037. eventHandler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK);
  156038. }
  156039. });
  156040. function selectTile(e) {
  156041. var selectedTile;
  156042. var ellipsoid = globe.ellipsoid;
  156043. var cartesian = that._scene.camera.pickEllipsoid({
  156044. x : e.position.x,
  156045. y : e.position.y
  156046. }, ellipsoid);
  156047. if (defined(cartesian)) {
  156048. var cartographic = ellipsoid.cartesianToCartographic(cartesian);
  156049. var tilesRendered = globe._surface.tileProvider._tilesToRenderByTextureCount;
  156050. for (var textureCount = 0; !selectedTile && textureCount < tilesRendered.length; ++textureCount) {
  156051. var tilesRenderedByTextureCount = tilesRendered[textureCount];
  156052. if (!defined(tilesRenderedByTextureCount)) {
  156053. continue;
  156054. }
  156055. for (var tileIndex = 0; !selectedTile && tileIndex < tilesRenderedByTextureCount.length; ++tileIndex) {
  156056. var tile = tilesRenderedByTextureCount[tileIndex];
  156057. if (Rectangle.contains(tile.rectangle, cartographic)) {
  156058. selectedTile = tile;
  156059. }
  156060. }
  156061. }
  156062. }
  156063. that.tile = selectedTile;
  156064. eventHandler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK);
  156065. that.pickTileActive = false;
  156066. }
  156067. this._pickTile = createCommand(function() {
  156068. that.pickTileActive = !that.pickTileActive;
  156069. if (that.pickTileActive) {
  156070. eventHandler.setInputAction(selectTile, ScreenSpaceEventType.LEFT_CLICK);
  156071. } else {
  156072. eventHandler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK);
  156073. }
  156074. });
  156075. }
  156076. defineProperties(CesiumInspectorViewModel.prototype, {
  156077. /**
  156078. * Gets the scene to control.
  156079. * @memberof CesiumInspectorViewModel.prototype
  156080. *
  156081. * @type {Scene}
  156082. */
  156083. scene : {
  156084. get : function() {
  156085. return this._scene;
  156086. }
  156087. },
  156088. /**
  156089. * Gets the container of the PerformanceDisplay
  156090. * @memberof CesiumInspectorViewModel.prototype
  156091. *
  156092. * @type {Element}
  156093. */
  156094. performanceContainer : {
  156095. get : function() {
  156096. return this._performanceContainer;
  156097. }
  156098. },
  156099. /**
  156100. * Gets the command to toggle the visibility of the drop down.
  156101. * @memberof CesiumInspectorViewModel.prototype
  156102. *
  156103. * @type {Command}
  156104. */
  156105. toggleDropDown : {
  156106. get : function() {
  156107. return this._toggleDropDown;
  156108. }
  156109. },
  156110. /**
  156111. * Gets the command to toggle {@link Scene.debugShowFrustums}
  156112. * @memberof CesiumInspectorViewModel.prototype
  156113. *
  156114. * @type {Command}
  156115. */
  156116. showFrustums : {
  156117. get : function() {
  156118. return this._showFrustums;
  156119. }
  156120. },
  156121. /**
  156122. * Gets the command to toggle the visibility of the performance display.
  156123. * @memberof CesiumInspectorViewModel.prototype
  156124. *
  156125. * @type {Command}
  156126. */
  156127. showPerformance : {
  156128. get : function() {
  156129. return this._showPerformance;
  156130. }
  156131. },
  156132. /**
  156133. * Gets the command to toggle the visibility of a BoundingSphere for a primitive
  156134. * @memberof CesiumInspectorViewModel.prototype
  156135. *
  156136. * @type {Command}
  156137. */
  156138. showPrimitiveBoundingSphere : {
  156139. get : function() {
  156140. return this._showPrimitiveBoundingSphere;
  156141. }
  156142. },
  156143. /**
  156144. * Gets the command to toggle the visibility of a {@link DebugModelMatrixPrimitive} for the model matrix of a primitive
  156145. * @memberof CesiumInspectorViewModel.prototype
  156146. *
  156147. * @type {Command}
  156148. */
  156149. showPrimitiveReferenceFrame : {
  156150. get : function() {
  156151. return this._showPrimitiveReferenceFrame;
  156152. }
  156153. },
  156154. /**
  156155. * Gets the command to toggle a filter that renders only a selected primitive
  156156. * @memberof CesiumInspectorViewModel.prototype
  156157. *
  156158. * @type {Command}
  156159. */
  156160. doFilterPrimitive : {
  156161. get : function() {
  156162. return this._doFilterPrimitive;
  156163. }
  156164. },
  156165. /**
  156166. * Gets the command to toggle the view of the Globe as a wireframe
  156167. * @memberof CesiumInspectorViewModel.prototype
  156168. *
  156169. * @type {Command}
  156170. */
  156171. showWireframe : {
  156172. get : function() {
  156173. return this._showWireframe;
  156174. }
  156175. },
  156176. /**
  156177. * Gets the command to toggle the view of the Globe depth buffer
  156178. * @memberof CesiumInspectorViewModel.prototype
  156179. *
  156180. * @type {Command}
  156181. */
  156182. showGlobeDepth : {
  156183. get : function() {
  156184. return this._showGlobeDepth;
  156185. }
  156186. },
  156187. /**
  156188. * Gets the command to toggle the view of the pick depth buffer
  156189. * @memberof CesiumInspectorViewModel.prototype
  156190. *
  156191. * @type {Command}
  156192. */
  156193. showPickDepth : {
  156194. get : function() {
  156195. return this._showPickDepth;
  156196. }
  156197. },
  156198. /**
  156199. * Gets the command to increment the depth frustum index to be shown
  156200. * @memberof CesiumInspectorViewModel.prototype
  156201. *
  156202. * @type {Command}
  156203. */
  156204. incrementDepthFrustum : {
  156205. get : function() {
  156206. return this._incrementDepthFrustum;
  156207. }
  156208. },
  156209. /**
  156210. * Gets the command to decrement the depth frustum index to be shown
  156211. * @memberof CesiumInspectorViewModel.prototype
  156212. *
  156213. * @type {Command}
  156214. */
  156215. decrementDepthFrustum : {
  156216. get : function() {
  156217. return this._decrementDepthFrustum;
  156218. }
  156219. },
  156220. /**
  156221. * Gets the command to toggle whether to suspend tile updates
  156222. * @memberof CesiumInspectorViewModel.prototype
  156223. *
  156224. * @type {Command}
  156225. */
  156226. doSuspendUpdates : {
  156227. get : function() {
  156228. return this._doSuspendUpdates;
  156229. }
  156230. },
  156231. /**
  156232. * Gets the command to toggle the visibility of tile coordinates
  156233. * @memberof CesiumInspectorViewModel.prototype
  156234. *
  156235. * @type {Command}
  156236. */
  156237. showTileCoordinates : {
  156238. get : function() {
  156239. return this._showTileCoordinates;
  156240. }
  156241. },
  156242. /**
  156243. * Gets the command to toggle the visibility of a BoundingSphere for a selected tile
  156244. * @memberof CesiumInspectorViewModel.prototype
  156245. *
  156246. * @type {Command}
  156247. */
  156248. showTileBoundingSphere : {
  156249. get : function() {
  156250. return this._showTileBoundingSphere;
  156251. }
  156252. },
  156253. /**
  156254. * Gets the command to toggle a filter that renders only a selected tile
  156255. * @memberof CesiumInspectorViewModel.prototype
  156256. *
  156257. * @type {Command}
  156258. */
  156259. doFilterTile : {
  156260. get : function() {
  156261. return this._doFilterTile;
  156262. }
  156263. },
  156264. /**
  156265. * Gets the command to expand and collapse the general section
  156266. * @memberof CesiumInspectorViewModel.prototype
  156267. *
  156268. * @type {Command}
  156269. */
  156270. toggleGeneral : {
  156271. get : function() {
  156272. return this._toggleGeneral;
  156273. }
  156274. },
  156275. /**
  156276. * Gets the command to expand and collapse the primitives section
  156277. * @memberof CesiumInspectorViewModel.prototype
  156278. *
  156279. * @type {Command}
  156280. */
  156281. togglePrimitives : {
  156282. get : function() {
  156283. return this._togglePrimitives;
  156284. }
  156285. },
  156286. /**
  156287. * Gets the command to expand and collapse the terrain section
  156288. * @memberof CesiumInspectorViewModel.prototype
  156289. *
  156290. * @type {Command}
  156291. */
  156292. toggleTerrain : {
  156293. get : function() {
  156294. return this._toggleTerrain;
  156295. }
  156296. },
  156297. /**
  156298. * Gets the command to pick a primitive
  156299. * @memberof CesiumInspectorViewModel.prototype
  156300. *
  156301. * @type {Command}
  156302. */
  156303. pickPrimitive : {
  156304. get : function() {
  156305. return this._pickPrimitive;
  156306. }
  156307. },
  156308. /**
  156309. * Gets the command to pick a tile
  156310. * @memberof CesiumInspectorViewModel.prototype
  156311. *
  156312. * @type {Command}
  156313. */
  156314. pickTile : {
  156315. get : function() {
  156316. return this._pickTile;
  156317. }
  156318. },
  156319. /**
  156320. * Gets the command to pick a tile
  156321. * @memberof CesiumInspectorViewModel.prototype
  156322. *
  156323. * @type {Command}
  156324. */
  156325. selectParent : {
  156326. get : function() {
  156327. var that = this;
  156328. return createCommand(function() {
  156329. that.tile = that.tile.parent;
  156330. });
  156331. }
  156332. },
  156333. /**
  156334. * Gets the command to pick a tile
  156335. * @memberof CesiumInspectorViewModel.prototype
  156336. *
  156337. * @type {Command}
  156338. */
  156339. selectNW : {
  156340. get : function() {
  156341. var that = this;
  156342. return createCommand(function() {
  156343. that.tile = that.tile.northwestChild;
  156344. });
  156345. }
  156346. },
  156347. /**
  156348. * Gets the command to pick a tile
  156349. * @memberof CesiumInspectorViewModel.prototype
  156350. *
  156351. * @type {Command}
  156352. */
  156353. selectNE : {
  156354. get : function() {
  156355. var that = this;
  156356. return createCommand(function() {
  156357. that.tile = that.tile.northeastChild;
  156358. });
  156359. }
  156360. },
  156361. /**
  156362. * Gets the command to pick a tile
  156363. * @memberof CesiumInspectorViewModel.prototype
  156364. *
  156365. * @type {Command}
  156366. */
  156367. selectSW : {
  156368. get : function() {
  156369. var that = this;
  156370. return createCommand(function() {
  156371. that.tile = that.tile.southwestChild;
  156372. });
  156373. }
  156374. },
  156375. /**
  156376. * Gets the command to pick a tile
  156377. * @memberof CesiumInspectorViewModel.prototype
  156378. *
  156379. * @type {Command}
  156380. */
  156381. selectSE : {
  156382. get : function() {
  156383. var that = this;
  156384. return createCommand(function() {
  156385. that.tile = that.tile.southeastChild;
  156386. });
  156387. }
  156388. },
  156389. /**
  156390. * Gets or sets the current selected primitive
  156391. * @memberof CesiumInspectorViewModel.prototype
  156392. *
  156393. * @type {Command}
  156394. */
  156395. primitive : {
  156396. set : function(newPrimitive) {
  156397. var oldPrimitive = this._primitive;
  156398. if (newPrimitive !== oldPrimitive) {
  156399. this.hasPickedPrimitive = true;
  156400. if (defined(oldPrimitive)) {
  156401. oldPrimitive.debugShowBoundingVolume = false;
  156402. }
  156403. this._scene.debugCommandFilter = undefined;
  156404. if (defined(this._modelMatrixPrimitive)) {
  156405. this._scene.primitives.remove(this._modelMatrixPrimitive);
  156406. this._modelMatrixPrimitive = undefined;
  156407. }
  156408. this._primitive = newPrimitive;
  156409. newPrimitive.show = false;
  156410. setTimeout(function() {
  156411. newPrimitive.show = true;
  156412. }, 50);
  156413. this.showPrimitiveBoundingSphere();
  156414. this.showPrimitiveReferenceFrame();
  156415. this.doFilterPrimitive();
  156416. }
  156417. },
  156418. get : function() {
  156419. return this._primitive;
  156420. }
  156421. },
  156422. /**
  156423. * Gets or sets the current selected tile
  156424. * @memberof CesiumInspectorViewModel.prototype
  156425. *
  156426. * @type {Command}
  156427. */
  156428. tile : {
  156429. set : function(newTile) {
  156430. if (defined(newTile)) {
  156431. this.hasPickedTile = true;
  156432. var oldTile = this._tile;
  156433. if (newTile !== oldTile) {
  156434. this.tileText = 'L: ' + newTile.level + ' X: ' + newTile.x + ' Y: ' + newTile.y;
  156435. this.tileText += '<br>SW corner: ' + newTile.rectangle.west + ', ' + newTile.rectangle.south;
  156436. this.tileText += '<br>NE corner: ' + newTile.rectangle.east + ', ' + newTile.rectangle.north;
  156437. this.tileText += '<br>Min: ' + newTile.data.minimumHeight + ' Max: ' + newTile.data.maximumHeight;
  156438. }
  156439. this._tile = newTile;
  156440. this.showTileBoundingSphere();
  156441. this.doFilterTile();
  156442. } else {
  156443. this.hasPickedTile = false;
  156444. this._tile = undefined;
  156445. }
  156446. },
  156447. get : function() {
  156448. return this._tile;
  156449. }
  156450. },
  156451. update : {
  156452. get : function() {
  156453. var that = this;
  156454. return function() {
  156455. if (that.frustums) {
  156456. that.frustumStatisticText = frustumStatsToString(that._scene.debugFrustumStatistics);
  156457. }
  156458. // Determine the number of frustums being used.
  156459. var numberOfFrustums = that._scene.numberOfFrustums;
  156460. that._numberOfFrustums = numberOfFrustums;
  156461. // Bound the frustum to be displayed.
  156462. var depthFrustum = boundDepthFrustum(1, numberOfFrustums, that.depthFrustum);
  156463. that.depthFrustum = depthFrustum;
  156464. that.scene.debugShowDepthFrustum = depthFrustum;
  156465. // Update the displayed text.
  156466. that.depthFrustumText = depthFrustum + ' of ' + numberOfFrustums;
  156467. if (that.performance) {
  156468. that._performanceDisplay.update();
  156469. }
  156470. if (that.primitiveReferenceFrame) {
  156471. that._modelMatrixPrimitive.modelMatrix = that._primitive.modelMatrix;
  156472. }
  156473. that.shaderCacheText = 'Cached shaders: ' + that._scene.context.shaderCache.numberOfShaders;
  156474. };
  156475. }
  156476. }
  156477. });
  156478. /**
  156479. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  156480. */
  156481. CesiumInspectorViewModel.prototype.isDestroyed = function() {
  156482. return false;
  156483. };
  156484. /**
  156485. * Destroys the widget. Should be called if permanently
  156486. * removing the widget from layout.
  156487. */
  156488. CesiumInspectorViewModel.prototype.destroy = function() {
  156489. this._eventHandler.destroy();
  156490. return destroyObject(this);
  156491. };
  156492. return CesiumInspectorViewModel;
  156493. });
  156494. /*global define*/
  156495. define('Widgets/CesiumInspector/CesiumInspector',[
  156496. '../../Core/defined',
  156497. '../../Core/defineProperties',
  156498. '../../Core/destroyObject',
  156499. '../../Core/DeveloperError',
  156500. '../../ThirdParty/knockout',
  156501. '../getElement',
  156502. './CesiumInspectorViewModel'
  156503. ], function(
  156504. defined,
  156505. defineProperties,
  156506. destroyObject,
  156507. DeveloperError,
  156508. knockout,
  156509. getElement,
  156510. CesiumInspectorViewModel) {
  156511. 'use strict';
  156512. /**
  156513. * Inspector widget to aid in debugging
  156514. *
  156515. * @alias CesiumInspector
  156516. * @constructor
  156517. *
  156518. * @param {Element|String} container The DOM element or ID that will contain the widget.
  156519. * @param {Scene} scene The Scene instance to use.
  156520. *
  156521. * @exception {DeveloperError} container is required.
  156522. * @exception {DeveloperError} scene is required.
  156523. *
  156524. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Cesium%20Inspector.html|Cesium Sandcastle Cesium Inspector Demo}
  156525. */
  156526. function CesiumInspector(container, scene) {
  156527. if (!defined(container)) {
  156528. throw new DeveloperError('container is required.');
  156529. }
  156530. if (!defined(scene)) {
  156531. throw new DeveloperError('scene is required.');
  156532. }
  156533. container = getElement(container);
  156534. var performanceContainer = document.createElement('div');
  156535. var viewModel = new CesiumInspectorViewModel(scene, performanceContainer);
  156536. this._viewModel = viewModel;
  156537. this._container = container;
  156538. var element = document.createElement('div');
  156539. this._element = element;
  156540. var text = document.createElement('div');
  156541. text.textContent = 'Cesium Inspector';
  156542. text.className = 'cesium-cesiumInspector-button';
  156543. text.setAttribute('data-bind', 'click: toggleDropDown');
  156544. element.appendChild(text);
  156545. element.className = 'cesium-cesiumInspector';
  156546. element.setAttribute('data-bind', 'css: { "cesium-cesiumInspector-visible" : dropDownVisible, "cesium-cesiumInspector-hidden" : !dropDownVisible }');
  156547. container.appendChild(this._element);
  156548. var panel = document.createElement('div');
  156549. this._panel = panel;
  156550. panel.className = 'cesium-cesiumInspector-dropDown';
  156551. element.appendChild(panel);
  156552. // General
  156553. var general = document.createElement('div');
  156554. general.className = 'cesium-cesiumInspector-sectionHeader';
  156555. var plus = document.createElement('span');
  156556. plus.className = 'cesium-cesiumInspector-toggleSwitch';
  156557. plus.setAttribute('data-bind', 'click: toggleGeneral, text: generalSwitchText');
  156558. general.appendChild(plus);
  156559. general.appendChild(document.createTextNode('General'));
  156560. panel.appendChild(general);
  156561. var generalSection = document.createElement('div');
  156562. generalSection.className = 'cesium-cesiumInspector-section';
  156563. generalSection.setAttribute('data-bind', 'css: {"cesium-cesiumInspector-show" : generalVisible, "cesium-cesiumInspector-hide" : !generalVisible}');
  156564. panel.appendChild(generalSection);
  156565. var debugShowFrustums = document.createElement('div');
  156566. generalSection.appendChild(debugShowFrustums);
  156567. var frustumStats = document.createElement('div');
  156568. frustumStats.className = 'cesium-cesiumInspector-frustumStats';
  156569. frustumStats.setAttribute('data-bind', 'css: {"cesium-cesiumInspector-show" : frustums, "cesium-cesiumInspector-hide" : !frustums}, html: frustumStatisticText');
  156570. var frustumsCheckbox = document.createElement('input');
  156571. frustumsCheckbox.type = 'checkbox';
  156572. frustumsCheckbox.setAttribute('data-bind', 'checked: frustums, click: showFrustums');
  156573. debugShowFrustums.appendChild(frustumsCheckbox);
  156574. debugShowFrustums.appendChild(document.createTextNode('Show Frustums'));
  156575. debugShowFrustums.appendChild(frustumStats);
  156576. var performanceDisplay = document.createElement('div');
  156577. generalSection.appendChild(performanceDisplay);
  156578. var pdCheckbox = document.createElement('input');
  156579. pdCheckbox.type = 'checkbox';
  156580. pdCheckbox.setAttribute('data-bind', 'checked: performance, click: showPerformance');
  156581. performanceDisplay.appendChild(pdCheckbox);
  156582. performanceDisplay.appendChild(document.createTextNode('Performance Display'));
  156583. performanceContainer.className = 'cesium-cesiumInspector-performanceDisplay';
  156584. generalSection.appendChild(performanceContainer);
  156585. var shaderCacheDisplay = document.createElement('div');
  156586. shaderCacheDisplay.className = 'cesium-cesiumInspector-shaderCache';
  156587. shaderCacheDisplay.setAttribute('data-bind', 'html: shaderCacheText');
  156588. generalSection.appendChild(shaderCacheDisplay);
  156589. var globeDepth = document.createElement('div');
  156590. generalSection.appendChild(globeDepth);
  156591. var gCheckbox = document.createElement('input');
  156592. gCheckbox.type = 'checkbox';
  156593. gCheckbox.setAttribute('data-bind', 'checked: globeDepth, click: showGlobeDepth');
  156594. globeDepth.appendChild(gCheckbox);
  156595. globeDepth.appendChild(document.createTextNode('Show globe depth'));
  156596. var globeDepthFrustum = document.createElement('div');
  156597. globeDepth.appendChild(globeDepthFrustum);
  156598. var pickDepth = document.createElement('div');
  156599. generalSection.appendChild(pickDepth);
  156600. var pCheckbox = document.createElement('input');
  156601. pCheckbox.type = 'checkbox';
  156602. pCheckbox.setAttribute('data-bind', 'checked: pickDepth, click: showPickDepth');
  156603. pickDepth.appendChild(pCheckbox);
  156604. pickDepth.appendChild(document.createTextNode('Show pick depth'));
  156605. var depthFrustum = document.createElement('div');
  156606. generalSection.appendChild(depthFrustum);
  156607. // Use a span with HTML binding so that we can indent with non-breaking spaces.
  156608. var gLabel = document.createElement('span');
  156609. gLabel.setAttribute('data-bind', 'html: "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Frustum:"');
  156610. depthFrustum.appendChild(gLabel);
  156611. var gText = document.createElement('span');
  156612. gText.setAttribute('data-bind', 'text: depthFrustumText');
  156613. depthFrustum.appendChild(gText);
  156614. var gMinusButton = document.createElement('input');
  156615. gMinusButton.type = 'button';
  156616. gMinusButton.value = '-';
  156617. gMinusButton.className = 'cesium-cesiumInspector-pickButton';
  156618. gMinusButton.setAttribute('data-bind', 'click: decrementDepthFrustum');
  156619. depthFrustum.appendChild(gMinusButton);
  156620. var gPlusButton = document.createElement('input');
  156621. gPlusButton.type = 'button';
  156622. gPlusButton.value = '+';
  156623. gPlusButton.className = 'cesium-cesiumInspector-pickButton';
  156624. gPlusButton.setAttribute('data-bind', 'click: incrementDepthFrustum');
  156625. depthFrustum.appendChild(gPlusButton);
  156626. // Primitives
  156627. var prim = document.createElement('div');
  156628. prim.className = 'cesium-cesiumInspector-sectionHeader';
  156629. plus = document.createElement('span');
  156630. plus.className = 'cesium-cesiumInspector-toggleSwitch';
  156631. plus.setAttribute('data-bind', 'click: togglePrimitives, text: primitivesSwitchText');
  156632. prim.appendChild(plus);
  156633. prim.appendChild(document.createTextNode('Primitives'));
  156634. panel.appendChild(prim);
  156635. var primitivesSection = document.createElement('div');
  156636. primitivesSection.className = 'cesium-cesiumInspector-section';
  156637. primitivesSection.setAttribute('data-bind', 'css: {"cesium-cesiumInspector-show" : primitivesVisible, "cesium-cesiumInspector-hide" : !primitivesVisible}');
  156638. panel.appendChild(primitivesSection);
  156639. var pickPrimRequired = document.createElement('div');
  156640. pickPrimRequired.className = 'cesium-cesiumInspector-pickSection';
  156641. primitivesSection.appendChild(pickPrimRequired);
  156642. var pickPrimitiveButton = document.createElement('input');
  156643. pickPrimitiveButton.type = 'button';
  156644. pickPrimitiveButton.value = 'Pick a primitive';
  156645. pickPrimitiveButton.className = 'cesium-cesiumInspector-pickButton';
  156646. pickPrimitiveButton.setAttribute('data-bind', 'css: {"cesium-cesiumInspector-pickButtonHighlight" : pickPrimitiveActive}, click: pickPrimitive');
  156647. var buttonWrap = document.createElement('div');
  156648. buttonWrap.className = 'cesium-cesiumInspector-center';
  156649. buttonWrap.appendChild(pickPrimitiveButton);
  156650. pickPrimRequired.appendChild(buttonWrap);
  156651. var debugSphere = document.createElement('div');
  156652. pickPrimRequired.appendChild(debugSphere);
  156653. var bsCheckbox = document.createElement('input');
  156654. bsCheckbox.type = 'checkbox';
  156655. bsCheckbox.setAttribute('data-bind', 'checked: primitiveBoundingSphere, click: showPrimitiveBoundingSphere, enable: hasPickedPrimitive');
  156656. debugSphere.appendChild(bsCheckbox);
  156657. debugSphere.appendChild(document.createTextNode('Show bounding sphere'));
  156658. var refFrame = document.createElement('div');
  156659. pickPrimRequired.appendChild(refFrame);
  156660. var rfCheckbox = document.createElement('input');
  156661. rfCheckbox.type = 'checkbox';
  156662. rfCheckbox.setAttribute('data-bind', 'checked: primitiveReferenceFrame, click: showPrimitiveReferenceFrame, enable: hasPickedPrimitive');
  156663. refFrame.appendChild(rfCheckbox);
  156664. refFrame.appendChild(document.createTextNode('Show reference frame'));
  156665. var primitiveOnly = document.createElement('div');
  156666. this._primitiveOnly = primitiveOnly;
  156667. pickPrimRequired.appendChild(primitiveOnly);
  156668. var primitiveOnlyCheckbox = document.createElement('input');
  156669. primitiveOnlyCheckbox.type = 'checkbox';
  156670. primitiveOnlyCheckbox.setAttribute('data-bind', 'checked: filterPrimitive, click: doFilterPrimitive, enable: hasPickedPrimitive');
  156671. primitiveOnly.appendChild(primitiveOnlyCheckbox);
  156672. primitiveOnly.appendChild(document.createTextNode('Show only selected'));
  156673. // Terrain
  156674. var terrain = document.createElement('div');
  156675. terrain.className = 'cesium-cesiumInspector-sectionHeader';
  156676. plus = document.createElement('span');
  156677. plus.className = 'cesium-cesiumInspector-toggleSwitch';
  156678. plus.setAttribute('data-bind', 'click: toggleTerrain, text: terrainSwitchText');
  156679. terrain.appendChild(plus);
  156680. terrain.appendChild(document.createTextNode('Terrain'));
  156681. panel.appendChild(terrain);
  156682. var terrainSection = document.createElement('div');
  156683. terrainSection.className = 'cesium-cesiumInspector-section';
  156684. terrainSection.setAttribute('data-bind', 'css: {"cesium-cesiumInspector-show" : terrainVisible, "cesium-cesiumInspector-hide" : !terrainVisible}');
  156685. panel.appendChild(terrainSection);
  156686. var pickTileRequired = document.createElement('div');
  156687. pickTileRequired.className = 'cesium-cesiumInspector-pickSection';
  156688. terrainSection.appendChild(pickTileRequired);
  156689. var pickTileButton = document.createElement('input');
  156690. pickTileButton.type = 'button';
  156691. pickTileButton.value = 'Pick a tile';
  156692. pickTileButton.className = 'cesium-cesiumInspector-pickButton';
  156693. pickTileButton.setAttribute('data-bind', 'css: {"cesium-cesiumInspector-pickButtonHighlight" : pickTileActive}, click: pickTile');
  156694. buttonWrap = document.createElement('div');
  156695. buttonWrap.appendChild(pickTileButton);
  156696. buttonWrap.className = 'cesium-cesiumInspector-center';
  156697. pickTileRequired.appendChild(buttonWrap);
  156698. var tileInfo = document.createElement('div');
  156699. pickTileRequired.appendChild(tileInfo);
  156700. var parentTile = document.createElement('input');
  156701. parentTile.type = 'button';
  156702. parentTile.value = 'Parent';
  156703. parentTile.className = 'cesium-cesiumInspector-pickButton';
  156704. parentTile.setAttribute('data-bind', 'click: selectParent');
  156705. var nwTile = document.createElement('input');
  156706. nwTile.type = 'button';
  156707. nwTile.value = 'NW';
  156708. nwTile.className = 'cesium-cesiumInspector-pickButton';
  156709. nwTile.setAttribute('data-bind', 'click: selectNW');
  156710. var neTile = document.createElement('input');
  156711. neTile.type = 'button';
  156712. neTile.value = 'NE';
  156713. neTile.className = 'cesium-cesiumInspector-pickButton';
  156714. neTile.setAttribute('data-bind', 'click: selectNE');
  156715. var swTile = document.createElement('input');
  156716. swTile.type = 'button';
  156717. swTile.value = 'SW';
  156718. swTile.className = 'cesium-cesiumInspector-pickButton';
  156719. swTile.setAttribute('data-bind', 'click: selectSW');
  156720. var seTile = document.createElement('input');
  156721. seTile.type = 'button';
  156722. seTile.value = 'SE';
  156723. seTile.className = 'cesium-cesiumInspector-pickButton';
  156724. seTile.setAttribute('data-bind', 'click: selectSE');
  156725. var tileText = document.createElement('div');
  156726. tileText.className = 'cesium-cesiumInspector-tileText';
  156727. tileInfo.className = 'cesium-cesiumInspector-frustumStats';
  156728. tileInfo.appendChild(tileText);
  156729. tileInfo.setAttribute('data-bind', 'css: {"cesium-cesiumInspector-show" : hasPickedTile, "cesium-cesiumInspector-hide" : !hasPickedTile}');
  156730. tileText.setAttribute('data-bind', 'html: tileText');
  156731. var relativeText = document.createElement('div');
  156732. relativeText.className = 'cesium-cesiumInspector-relativeText';
  156733. relativeText.textContent = 'Select relative:';
  156734. tileInfo.appendChild(relativeText);
  156735. var table = document.createElement('table');
  156736. var tr1 = document.createElement('tr');
  156737. var tr2 = document.createElement('tr');
  156738. var td1 = document.createElement('td');
  156739. td1.appendChild(parentTile);
  156740. var td2 = document.createElement('td');
  156741. td2.appendChild(nwTile);
  156742. var td3 = document.createElement('td');
  156743. td3.appendChild(neTile);
  156744. tr1.appendChild(td1);
  156745. tr1.appendChild(td2);
  156746. tr1.appendChild(td3);
  156747. var td4 = document.createElement('td');
  156748. var td5 = document.createElement('td');
  156749. td5.appendChild(swTile);
  156750. var td6 = document.createElement('td');
  156751. td6.appendChild(seTile);
  156752. tr2.appendChild(td4);
  156753. tr2.appendChild(td5);
  156754. tr2.appendChild(td6);
  156755. table.appendChild(tr1);
  156756. table.appendChild(tr2);
  156757. tileInfo.appendChild(table);
  156758. var tileBoundingSphere = document.createElement('div');
  156759. pickTileRequired.appendChild(tileBoundingSphere);
  156760. var tbsCheck = document.createElement('input');
  156761. tbsCheck.type = 'checkbox';
  156762. tbsCheck.setAttribute('data-bind', 'checked: tileBoundingSphere, enable: hasPickedTile, click: showTileBoundingSphere');
  156763. tileBoundingSphere.appendChild(tbsCheck);
  156764. tileBoundingSphere.appendChild(document.createTextNode('Show bounding volume'));
  156765. var renderTile = document.createElement('div');
  156766. pickTileRequired.appendChild(renderTile);
  156767. var rCheck = document.createElement('input');
  156768. rCheck.type = 'checkbox';
  156769. rCheck.setAttribute('data-bind', 'checked: filterTile, enable: hasPickedTile, click: doFilterTile');
  156770. renderTile.appendChild(rCheck);
  156771. renderTile.appendChild(document.createTextNode('Show only selected'));
  156772. var wireframe = document.createElement('div');
  156773. terrainSection.appendChild(wireframe);
  156774. var wCheckbox = document.createElement('input');
  156775. wCheckbox.type = 'checkbox';
  156776. wCheckbox.setAttribute('data-bind', 'checked: wireframe, click: showWireframe');
  156777. wireframe.appendChild(wCheckbox);
  156778. wireframe.appendChild(document.createTextNode('Wireframe'));
  156779. var suspendUpdates = document.createElement('div');
  156780. terrainSection.appendChild(suspendUpdates);
  156781. var upCheckbox = document.createElement('input');
  156782. upCheckbox.type = 'checkbox';
  156783. upCheckbox.setAttribute('data-bind', 'checked: suspendUpdates, click: doSuspendUpdates');
  156784. suspendUpdates.appendChild(upCheckbox);
  156785. suspendUpdates.appendChild(document.createTextNode('Suspend LOD update'));
  156786. var tileCoords = document.createElement('div');
  156787. terrainSection.appendChild(tileCoords);
  156788. var coordCheck = document.createElement('input');
  156789. coordCheck.type = 'checkbox';
  156790. coordCheck.setAttribute('data-bind', 'checked: tileCoordinates, click: showTileCoordinates');
  156791. tileCoords.appendChild(coordCheck);
  156792. tileCoords.appendChild(document.createTextNode('Show tile coordinates'));
  156793. knockout.applyBindings(viewModel, this._element);
  156794. }
  156795. defineProperties(CesiumInspector.prototype, {
  156796. /**
  156797. * Gets the parent container.
  156798. * @memberof CesiumInspector.prototype
  156799. *
  156800. * @type {Element}
  156801. */
  156802. container : {
  156803. get : function() {
  156804. return this._container;
  156805. }
  156806. },
  156807. /**
  156808. * Gets the view model.
  156809. * @memberof CesiumInspector.prototype
  156810. *
  156811. * @type {CesiumInspectorViewModel}
  156812. */
  156813. viewModel : {
  156814. get : function() {
  156815. return this._viewModel;
  156816. }
  156817. }
  156818. });
  156819. /**
  156820. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  156821. */
  156822. CesiumInspector.prototype.isDestroyed = function() {
  156823. return false;
  156824. };
  156825. /**
  156826. * Destroys the widget. Should be called if permanently
  156827. * removing the widget from layout.
  156828. */
  156829. CesiumInspector.prototype.destroy = function() {
  156830. knockout.cleanNode(this._element);
  156831. this._container.removeChild(this._element);
  156832. this.viewModel.destroy();
  156833. return destroyObject(this);
  156834. };
  156835. return CesiumInspector;
  156836. });
  156837. /*global define*/
  156838. define('Widgets/CesiumWidget/CesiumWidget',[
  156839. '../../Core/buildModuleUrl',
  156840. '../../Core/Cartesian3',
  156841. '../../Core/Clock',
  156842. '../../Core/Credit',
  156843. '../../Core/defaultValue',
  156844. '../../Core/defined',
  156845. '../../Core/defineProperties',
  156846. '../../Core/destroyObject',
  156847. '../../Core/DeveloperError',
  156848. '../../Core/Ellipsoid',
  156849. '../../Core/FeatureDetection',
  156850. '../../Core/formatError',
  156851. '../../Core/requestAnimationFrame',
  156852. '../../Core/ScreenSpaceEventHandler',
  156853. '../../Scene/BingMapsImageryProvider',
  156854. '../../Scene/Globe',
  156855. '../../Scene/Moon',
  156856. '../../Scene/Scene',
  156857. '../../Scene/SceneMode',
  156858. '../../Scene/ShadowMode',
  156859. '../../Scene/SkyAtmosphere',
  156860. '../../Scene/SkyBox',
  156861. '../../Scene/Sun',
  156862. '../getElement'
  156863. ], function(
  156864. buildModuleUrl,
  156865. Cartesian3,
  156866. Clock,
  156867. Credit,
  156868. defaultValue,
  156869. defined,
  156870. defineProperties,
  156871. destroyObject,
  156872. DeveloperError,
  156873. Ellipsoid,
  156874. FeatureDetection,
  156875. formatError,
  156876. requestAnimationFrame,
  156877. ScreenSpaceEventHandler,
  156878. BingMapsImageryProvider,
  156879. Globe,
  156880. Moon,
  156881. Scene,
  156882. SceneMode,
  156883. ShadowMode,
  156884. SkyAtmosphere,
  156885. SkyBox,
  156886. Sun,
  156887. getElement) {
  156888. 'use strict';
  156889. function getDefaultSkyBoxUrl(suffix) {
  156890. return buildModuleUrl('Assets/Textures/SkyBox/tycho2t3_80_' + suffix + '.jpg');
  156891. }
  156892. function startRenderLoop(widget) {
  156893. widget._renderLoopRunning = true;
  156894. var lastFrameTime = 0;
  156895. function render(frameTime) {
  156896. if (widget.isDestroyed()) {
  156897. return;
  156898. }
  156899. if (widget._useDefaultRenderLoop) {
  156900. try {
  156901. var targetFrameRate = widget._targetFrameRate;
  156902. if (!defined(targetFrameRate)) {
  156903. widget.resize();
  156904. widget.render();
  156905. requestAnimationFrame(render);
  156906. } else {
  156907. var interval = 1000.0 / targetFrameRate;
  156908. var delta = frameTime - lastFrameTime;
  156909. if (delta > interval) {
  156910. widget.resize();
  156911. widget.render();
  156912. lastFrameTime = frameTime - (delta % interval);
  156913. }
  156914. requestAnimationFrame(render);
  156915. }
  156916. } catch (error) {
  156917. widget._useDefaultRenderLoop = false;
  156918. widget._renderLoopRunning = false;
  156919. if (widget._showRenderLoopErrors) {
  156920. var title = 'An error occurred while rendering. Rendering has stopped.';
  156921. widget.showErrorPanel(title, undefined, error);
  156922. }
  156923. }
  156924. } else {
  156925. widget._renderLoopRunning = false;
  156926. }
  156927. }
  156928. requestAnimationFrame(render);
  156929. }
  156930. function configureCanvasSize(widget) {
  156931. var canvas = widget._canvas;
  156932. var width = canvas.clientWidth;
  156933. var height = canvas.clientHeight;
  156934. var resolutionScale = widget._resolutionScale;
  156935. if (!widget._supportsImageRenderingPixelated) {
  156936. resolutionScale *= defaultValue(window.devicePixelRatio, 1.0);
  156937. }
  156938. widget._canvasWidth = width;
  156939. widget._canvasHeight = height;
  156940. width *= resolutionScale;
  156941. height *= resolutionScale;
  156942. canvas.width = width;
  156943. canvas.height = height;
  156944. widget._canRender = width !== 0 && height !== 0;
  156945. }
  156946. function configureCameraFrustum(widget) {
  156947. var canvas = widget._canvas;
  156948. var width = canvas.width;
  156949. var height = canvas.height;
  156950. if (width !== 0 && height !== 0) {
  156951. var frustum = widget._scene.camera.frustum;
  156952. if (defined(frustum.aspectRatio)) {
  156953. frustum.aspectRatio = width / height;
  156954. } else {
  156955. frustum.top = frustum.right * (height / width);
  156956. frustum.bottom = -frustum.top;
  156957. }
  156958. }
  156959. }
  156960. var cesiumLogoData = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHYAAAAeCAYAAAD5AOomAAAQWUlEQVR42u1beXxOxxpudrEktkbUkriI4lZpq5JbW6pJuFG0qrFeexVRak3TBm3RUgS1hFhrCdKgQWKLrUGQBiVBJMgiq0Qiuyxzn/fzTu74ZPnS9nfrj4zf8/ty5sw7M+c8824zx0svVa3oAfqAAWAIGAHGCoy43oDb6TGqywta9JgsIq4GUAswB+oDDRXU5/ragCm3N6gm+MUkVJ+1kAg1AyyA5oAN8BrQCXiTfzsArwLWgCVQF6jJBOtXk/tikWrMGkiEtgTeAOyBfsAQS0vL8YMHD/aws7ObiuthwAeAA/A20AZozAvCRNHe6vI3k2rCprUp8DoR1qVLF1c/P7+A5OTkhyUlJaKwuETkPSkRBUUlgkpmZmbW2bNnQyZOnLgA7Z2BzkALNtM1qsl9MTSVSLUCugADAwMDTxKZVI7cfCw8DiWK6fselMLtlwSxJyxDPM4vFsXFxSWRkZFRkBsOdAdaAw2qyf37ij77RDMm1a5evXojY2NjH5BW7ruaIab4xotPd8cJV/xO0cKkPXGae97n0kR6TpHIzs7O7d279xdsvoncemwJqn3u/1lbDTnqfYXN6JCUlJS03CfFwt0/4TkiK8IEEBydWiBIy21tbaejr24cWJlpBVT6ShpVFvS10iddZP6MbFkyqpw2Kor6K5P9M33onG1Iv0omsz3Q//79+7HpuUViDsys697KyZy89ynk9Wc/x4u7DwvE48ePs2mRcARtqUTLRjxmDa6rpYWanDqZKHmyzJ+lTFlyUrZGGbIm3GdF49VQcnMjZUwTJW83Ua4NtayQmlEYKW1NlOc11RrLoAxLpqdYUSmnPlOlbk1qa21OZ7ovX758E/lTz1MpOmvp5gvp4qeL6c8sAjLNOQXF4sKFC6Hotw+nSrR46rAfb8hkN+WxVTTlyPplNuNmDArGGgFNgGZloClbHQtua8bj1eW+GnObZspY2nL1WKaOkreraKDk7jXLsEJGXG+u1b4Bz/0VZayyUkO5f2DCc5DvyZL/1inb0ONVU5+1dSBMcHrIvRwNMbqQ6u6fKGSZ4POszFaQDZNc0q9fvzkcjFkzKf/gfJjSo3c40OrBoL+7cvvXeUFYM17l1MuOTbxEV8a/uE8pZ8Ww4bouPJ62bFlyzXmebRg2jLY8jxa8WGopxEiX9jLff1Vp357zfluefyeOPxpp9WHAGl2fn/k1do+Ef/K86lYWs+hzJ7SSbXv06OFGAfAMRLtlBUjkPyfuidMyw3Fi37UM8TMCLFVj6W9qW1BYIg4ePBjEWkukdCTyZsyYMcvX13f7iRMnDv36669B0OxTBKRNx4OCggIPHDiwa+XKld+j7Xv84v/l4+Oz6PLlywHnzp07Su0gdyw4OPgYXQNHzp8/f+TixYuHw8LCDuDeGiaLXqLj6tWrlyLC9ztz5gy1PwEcV3AU89i3detWT2NjYyeWedvLy2va77//7hcREeHfsWPH91HX6/r16/7h4eH+6H+ZVtQvN3ToujXm9wPJYS6+FhYWzggmh4eGhh6hsTHnE/j7eN++fQczWY1Yc6WrIVJb0SLEu9iJ93I0JCTkKMY+PHLkSGe2MLV5TL3ytgxr88pwuHLlyvXY9CcaH6mSR5HwwRuPRWZekTgXnfPcfW0QqfMDk0Qc+nqCnDc+Pj6FNzJoE+PfeDEXhQ6FtD0rKyu9Tp06LpAbBN9/S+hYEJmnck79EazQA5myVTKeyM/Pp7jgI2AAXv4JeW/AgAGzUTdKXj969CiOF04T1jhj/qXrzrgfQ+0KUdq1azdt6tSpntrjxcTEUGroyBrdkLmoy3x0HT9+vIe2zIoVK9y5fT0eU688/2rOJqY/bTRcjsl5hqRPYF5P38nSdJrwMErzezMpX1NfHrELjiQ9fbl56SIjO5leViH6nwwMnjZt2gL5EmWh/Lf4f+U5BtauXbsJshPu3LkTLQl/+PBhVmpqagZ+HxHS0tLSCShpGRkZqXhp12i8RYsWrVP7wr1ctM9E2wy0lch88uRJoWwTFRV1A7JjoVnBss7BwWEJ6ubIa/SRgOt32VybKduvZILtMbd4JraoZcuWC8eMGbNN+7noWTt06DCVXUIL9rtNOdj8uABFW+bbb7/9js34y4o5fo5YI14h7QwNDV1yc3MLAsIfP0PS9kvpmg6Db+wXn6/pKrwOztBcn7mTXWbEPHlPvMguKBFFxYXiq819hZu3k6Y9xpgFjN+xY8cBOcmkpKQ0rh8HDCUieHNjHExgmGwHQomkKbdu3bpP10VFRcU2NjZ7UbcKWATMB74C3IBpSn8jTp48eVb2k5iYSNq4BVjJcl8zFrq5ue3Py8vLB/Kg4USa6+nTp0OkLNwUmfYFckGiTRJZH1YKc3Zp5mye+yQnJydQOyyYImtr65XDhw/3lX2B7BJlgaSxhXiL+6K99z4wwadkG/RRLP/28PBYxpaiES+mcokllW4PczcUz1Twy++ZpSTRrhJtUCSnx4gvNzkL9419xBfevUVIxEHNIEuDUp4j90ZCHjSqUHj+/AnaOmnkmFgyIa6Y8Hk5SScnp6VMwLs82Tc5wOkJv9Tfz89v3f79+73xMPTyJyrEloCI8+PGjTs0adIkX1dXVx+Yuu2ff/75tlmzZm1A+xUDBw6kHHo4/GqQHA8Lt9DT0/OSu7v70SlTpuwdMmTIFhC2tlmzZivQ9geAtOFLgLRoGhbFJSnbrVu3DahbrEXs+4pZrMm/FGj1xaJNlMRaWVmtGTZs2D7ZV3R0dA6sWJG8Riayhd1GNzbNo0nTpWWbP3/+dYXY5fyOLCsjti5Hbh/hwfODbmeVkkS5rCgpFgt2DNaQKjHTy16kZsRpBpp1IKE0uNoSkqapO3llp2YBUFuPLf01Jgf9007UFAQCv8lJmpubf4Y6J478rNgMWfHL6cRBE+1e9SXTKInVpdy7d+8KmbOhQ4d+rasMLRjML5xMLlkSBFShCrEbiXxJLDQymQ8/2rN/lKkJXQ+AdUiSxDZv3nydSuzNmzczQWaEvIZbeESuhhf5mLt375Y+Z0BAQDQW7Dl5PXfu3KW6EGvIfoEisL6Ya+p1aBz5z/N3czQdbQ5w12ieSizhu13DEPHmajYiKDXyPJmiaX8t6pSYs8FB04bM8ObAL2ijIg/9zyCtU4lFBDqJA6p2nE/KPLMVmyRbToGcq0osAq0rrFEu8Eve5IfJhOsiCxN8FXJzjx07FqYQ6426JZJYaGQKu463eO4W/EvXLiqx0Ni1MMV+ig9PR5ut0PosWbd582bKHL50cXHZIOMMGqtJkybrQWZpEDdv3rwfdCHWgCM5yo3s/f39j9G8H2Y/tRKXbgUItw2Oz5EqSfMJWvT0dCefA5PsVPHNTx+VtpkFzb4Ve0ncuHHjLq/I0UhJSv1W27Zt57F/6cpp0Gv8awfz6Lxq1ar5P/7448KxY8eSH/5UNcUffPBBQKdOnTZ37tx5la2t7VI7O7vv33nnnYUwrR6Ojo7TEIm6sFkjckfxwvIAaMyvTE1NPRC4LEFQtAH9+yOVSFYiXvLFC48ePXpF1nXv3n09mWqF2Ie4/oTHeIM19Q2+/iQhISFVIXb1iBEj9irWhCL2pXPmzPlF9aOoW4+gL13W7d69+ywtMASApe1glhez2yqXWJnH1uDVRv5tpMY0PE4Qu4IWlkmoNlb6TRKRcaHiQoS/+Ir9sMTCnYM1q27NmjW+tIqJxMOHDwfISe7bty8YdZ8pZ7r9aZOEruE7F2lFqZ+pwRNI8WG/SGTNZuKm8gIawlrusGDBgi+wsEJ+Q8Fq38W+fg7LkHv4hoKwUaNGlWoFLEwuEatqrL29PQVq86TW5+Tk5LP8aDK9PN4AvnaXPhKBbSEW6bLRo0fvkH3FxsYmcaA3m6JzWR8ZGVlKKmUoHAhORFywSysqfqui4Enbz1JE5nz16tXwrNx0nUh9Gkw5QTPfFbPX93pWo6Hpp6740EqkVOc/lNzTZgM0cKVq9qAdmSlPS5IEHjaN8h7Z5iAKpUt48LsyTYCGPcBc7+L3DvLi2xEREYSbt2/fDkdwci0sLOwwRZfbt29frmhFIdpEgehIkqFfRN9RQAzmkSvbQdvIzLqdOnWqNN+GFaAoeircVYr68rHoohG138KYN+mXji1Rny1NKeKWXDMzM/cJEyZskHIPUMiX0ntp06aNm5riSYsA0+zLpn6Ql5fXRnl/8eLFX7NVsygv3VHNcU3ev+xC23800NlrvqUBUFVBckv3jNZMBNHnSvajr/OEHLDaM3X1lSCjoFGjRmRKhyGoiKziBgWZRWf0kSeqUGbOnOlJmod44Iys+/DDD8kiuMAULlMXXWUFUfkhIhB9LpZ1WBwxHBDSexmIBXFTlcHCeMQuqidh586dK+S91atXu3EkXp83KPQrOt0xZq2loMVh2bJlmmT6+OVt0MT3qkiqk1jsM0LkFWQL0iI2rx2UjXfyo73gPzZCu64iyIhHYJMMJU2RoJ0ikBiOiNBn0KBBY/gB7UNDQ3/B/QTcT1SRmpqaQEA/D3A/HtoXGxcXd07uy3bt2nUQSPKHJkbLthIsnwifGY/5/oZ0gnxwb5ojTPG6jIyMGCySBCz4gTJKnz59+szg4OBAjBEFkuIg+wxQojHXszD983hx9Zw8efI4EBZHgFYHsjnV7JdjfkMw50R+hnikauM4QKJspb23t/dkuAeaR9ySJUuG8Lusw9ZWr7KvEU15N4P2Lt9HZKjZdTkeuk3MRcpSVmT8DKEbe2vaePlPFyX4B8IoHfiYH6AJJ+/m7PRtuL47r9revJfch/92YDK78Hxas0xHDrTeU2R6c8rkWIZcK/5mqx1vondnWUeWUdGL++7EL9SG5Tooc2ihFbH3VPpzVOZgz4ugI6durVjLpNV6lRd5Y/5tx3Puxv3Kzf5G3KaFcpjQvCqfHKmH7Y15An3hqDeRWaZo1+fkIjFjXQ9NKiNNNJFJvpR87JLdI8X95HCNj6CjOtrJ4uituXLUZKwk8pbKCUpr5fSkNZNhxe6hIbeXR3bNFBlttOKX0Izb1mfZhtyXFcu20kFOfmZrwQteHtXJI8AmvKfbUulPLiRrTtvk8WFdPhyw4P4b8DupxZrXgOfXTHnmOvyu5P6x/NxX7nIZVuXA3Yg7asyrxoG+RER4HoMorzj/SY64ijw18OIm4Xd2uTh4fq04f+OASEy7pyGUvrqYPXv2CvYfb/JEzbUOlA342lR5MDNFo+UZam1+MBPlgNuU69X25mXI1lIO6qVsTUXWrAK5GloH49qH3Ophf21l/mZlzL2G1gG9aTkfEJgoHwDU1LpvqIxZ0eG8TuTKM8VWbCKcoYGj1q1btwehegJtPVIuSVEmnd8iQDhtbW3tamxs/CGbs7a8OOooDr68z1QMlQdUH0b7kxX1sxbDSmBQzqcoBpXIGJQjo/1ZSmVzqaivyvozqOB96f+Z78b0lLPFumwabFgDe3K+NpDz0kH8rXEvNrttWUvr6/DRuJ6O+CMyf0a2Ku+pqn390Xt/6QduBopPNFe2zFrJaI2dfmv2XZbsz2op5qL6v3m8oF8vqv9/R/oB+Q1RPf41U3yT0R+x/9Xlryn/BY268qsf3smdAAAAAElFTkSuQmCC';
  156961. /**
  156962. * A widget containing a Cesium scene.
  156963. *
  156964. * @alias CesiumWidget
  156965. * @constructor
  156966. *
  156967. * @param {Element|String} container The DOM element or ID that will contain the widget.
  156968. * @param {Object} [options] Object with the following properties:
  156969. * @param {Clock} [options.clock=new Clock()] The clock to use to control current time.
  156970. * @param {ImageryProvider} [options.imageryProvider=new BingMapsImageryProvider()] The imagery provider to serve as the base layer. If set to <code>false</code>, no imagery provider will be added.
  156971. * @param {TerrainProvider} [options.terrainProvider=new EllipsoidTerrainProvider] The terrain provider.
  156972. * @param {SkyBox} [options.skyBox] The skybox used to render the stars. When <code>undefined</code>, the default stars are used. If set to <code>false</code>, no skyBox, Sun, or Moon will be added.
  156973. * @param {SkyAtmosphere} [options.skyAtmosphere] Blue sky, and the glow around the Earth's limb. Set to <code>false</code> to turn it off.
  156974. * @param {SceneMode} [options.sceneMode=SceneMode.SCENE3D] The initial scene mode.
  156975. * @param {Boolean} [options.scene3DOnly=false] When <code>true</code>, each geometry instance will only be rendered in 3D to save GPU memory.
  156976. * @param {Boolean} [options.orderIndependentTranslucency=true] If true and the configuration supports it, use order independent translucency.
  156977. * @param {MapProjection} [options.mapProjection=new GeographicProjection()] The map projection to use in 2D and Columbus View modes.
  156978. * @param {Globe} [options.globe=new Globe(mapProjection.ellipsoid)] The globe to use in the scene. If set to <code>false</code>, no globe will be added.
  156979. * @param {Boolean} [options.useDefaultRenderLoop=true] True if this widget should control the render loop, false otherwise.
  156980. * @param {Number} [options.targetFrameRate] The target frame rate when using the default render loop.
  156981. * @param {Boolean} [options.showRenderLoopErrors=true] If true, this widget will automatically display an HTML panel to the user containing the error, if a render loop error occurs.
  156982. * @param {Object} [options.contextOptions] Context and WebGL creation properties corresponding to <code>options</code> passed to {@link Scene}.
  156983. * @param {Element|String} [options.creditContainer] The DOM element or ID that will contain the {@link CreditDisplay}. If not specified, the credits are added
  156984. * to the bottom of the widget itself.
  156985. * @param {Number} [options.terrainExaggeration=1.0] A scalar used to exaggerate the terrain. Note that terrain exaggeration will not modify any other primitive as they are positioned relative to the ellipsoid.
  156986. * @param {Boolean} [options.shadows=false] Determines if shadows are cast by the sun.
  156987. * @param {ShadowMode} [options.terrainShadows=ShadowMode.RECEIVE_ONLY] Determines if the terrain casts or receives shadows from the sun.
  156988. * @param {MapMode2D} [options.mapMode2D=MapMode2D.INFINITE_SCROLL] Determines if the 2D map is rotatable or can be scrolled infinitely in the horizontal direction.
  156989. *
  156990. * @exception {DeveloperError} Element with id "container" does not exist in the document.
  156991. *
  156992. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Cesium%20Widget.html|Cesium Sandcastle Cesium Widget Demo}
  156993. *
  156994. * @example
  156995. * // For each example, include a link to CesiumWidget.css stylesheet in HTML head,
  156996. * // and in the body, include: <div id="cesiumContainer"></div>
  156997. *
  156998. * //Widget with no terrain and default Bing Maps imagery provider.
  156999. * var widget = new Cesium.CesiumWidget('cesiumContainer');
  157000. *
  157001. * //Widget with OpenStreetMaps imagery provider and Cesium terrain provider hosted by AGI.
  157002. * var widget = new Cesium.CesiumWidget('cesiumContainer', {
  157003. * imageryProvider : Cesium.createOpenStreetMapImageryProvider(),
  157004. * terrainProvider : new Cesium.CesiumTerrainProvider({
  157005. * url : 'https://assets.agi.com/stk-terrain/world'
  157006. * }),
  157007. * // Use high-res stars downloaded from https://github.com/AnalyticalGraphicsInc/cesium-assets
  157008. * skyBox : new Cesium.SkyBox({
  157009. * sources : {
  157010. * positiveX : 'stars/TychoSkymapII.t3_08192x04096_80_px.jpg',
  157011. * negativeX : 'stars/TychoSkymapII.t3_08192x04096_80_mx.jpg',
  157012. * positiveY : 'stars/TychoSkymapII.t3_08192x04096_80_py.jpg',
  157013. * negativeY : 'stars/TychoSkymapII.t3_08192x04096_80_my.jpg',
  157014. * positiveZ : 'stars/TychoSkymapII.t3_08192x04096_80_pz.jpg',
  157015. * negativeZ : 'stars/TychoSkymapII.t3_08192x04096_80_mz.jpg'
  157016. * }
  157017. * }),
  157018. * // Show Columbus View map with Web Mercator projection
  157019. * sceneMode : Cesium.SceneMode.COLUMBUS_VIEW,
  157020. * mapProjection : new Cesium.WebMercatorProjection()
  157021. * });
  157022. */
  157023. function CesiumWidget(container, options) {
  157024. if (!defined(container)) {
  157025. throw new DeveloperError('container is required.');
  157026. }
  157027. container = getElement(container);
  157028. options = defaultValue(options, {});
  157029. //Configure the widget DOM elements
  157030. var element = document.createElement('div');
  157031. element.className = 'cesium-widget';
  157032. container.appendChild(element);
  157033. var canvas = document.createElement('canvas');
  157034. var supportsImageRenderingPixelated = FeatureDetection.supportsImageRenderingPixelated();
  157035. this._supportsImageRenderingPixelated = supportsImageRenderingPixelated;
  157036. if (supportsImageRenderingPixelated) {
  157037. canvas.style.imageRendering = FeatureDetection.imageRenderingValue();
  157038. }
  157039. canvas.oncontextmenu = function() {
  157040. return false;
  157041. };
  157042. canvas.onselectstart = function() {
  157043. return false;
  157044. };
  157045. element.appendChild(canvas);
  157046. var creditContainer = document.createElement('div');
  157047. creditContainer.className = 'cesium-widget-credits';
  157048. var creditContainerContainer = defined(options.creditContainer) ? getElement(options.creditContainer) : element;
  157049. creditContainerContainer.appendChild(creditContainer);
  157050. var showRenderLoopErrors = defaultValue(options.showRenderLoopErrors, true);
  157051. this._element = element;
  157052. this._container = container;
  157053. this._canvas = canvas;
  157054. this._canvasWidth = 0;
  157055. this._canvasHeight = 0;
  157056. this._creditContainer = creditContainer;
  157057. this._canRender = false;
  157058. this._renderLoopRunning = false;
  157059. this._showRenderLoopErrors = showRenderLoopErrors;
  157060. this._resolutionScale = 1.0;
  157061. this._forceResize = false;
  157062. this._clock = defined(options.clock) ? options.clock : new Clock();
  157063. configureCanvasSize(this);
  157064. try {
  157065. var scene = new Scene({
  157066. canvas : canvas,
  157067. contextOptions : options.contextOptions,
  157068. creditContainer : creditContainer,
  157069. mapProjection : options.mapProjection,
  157070. orderIndependentTranslucency : options.orderIndependentTranslucency,
  157071. scene3DOnly : defaultValue(options.scene3DOnly, false),
  157072. terrainExaggeration : options.terrainExaggeration,
  157073. shadows : options.shadows,
  157074. mapMode2D : options.mapMode2D
  157075. });
  157076. this._scene = scene;
  157077. scene.camera.constrainedAxis = Cartesian3.UNIT_Z;
  157078. configureCameraFrustum(this);
  157079. var ellipsoid = defaultValue(scene.mapProjection.ellipsoid, Ellipsoid.WGS84);
  157080. var creditDisplay = scene.frameState.creditDisplay;
  157081. var cesiumCredit = new Credit('Cesium', cesiumLogoData, 'http://cesiumjs.org/');
  157082. creditDisplay.addDefaultCredit(cesiumCredit);
  157083. var globe = options.globe;
  157084. if (!defined(globe)) {
  157085. globe = new Globe(ellipsoid);
  157086. }
  157087. if (globe !== false) {
  157088. scene.globe = globe;
  157089. scene.globe.shadows = defaultValue(options.terrainShadows, ShadowMode.RECEIVE_ONLY);
  157090. }
  157091. var skyBox = options.skyBox;
  157092. if (!defined(skyBox)) {
  157093. skyBox = new SkyBox({
  157094. sources : {
  157095. positiveX : getDefaultSkyBoxUrl('px'),
  157096. negativeX : getDefaultSkyBoxUrl('mx'),
  157097. positiveY : getDefaultSkyBoxUrl('py'),
  157098. negativeY : getDefaultSkyBoxUrl('my'),
  157099. positiveZ : getDefaultSkyBoxUrl('pz'),
  157100. negativeZ : getDefaultSkyBoxUrl('mz')
  157101. }
  157102. });
  157103. }
  157104. if (skyBox !== false) {
  157105. scene.skyBox = skyBox;
  157106. scene.sun = new Sun();
  157107. scene.moon = new Moon();
  157108. }
  157109. // Blue sky, and the glow around the Earth's limb.
  157110. var skyAtmosphere = options.skyAtmosphere;
  157111. if (!defined(skyAtmosphere)) {
  157112. skyAtmosphere = new SkyAtmosphere(ellipsoid);
  157113. }
  157114. if (skyAtmosphere !== false) {
  157115. scene.skyAtmosphere = skyAtmosphere;
  157116. }
  157117. //Set the base imagery layer
  157118. var imageryProvider = (options.globe === false) ? false : options.imageryProvider;
  157119. if (!defined(imageryProvider)) {
  157120. imageryProvider = new BingMapsImageryProvider({
  157121. url : 'https://dev.virtualearth.net'
  157122. });
  157123. }
  157124. if (imageryProvider !== false) {
  157125. scene.imageryLayers.addImageryProvider(imageryProvider);
  157126. }
  157127. //Set the terrain provider if one is provided.
  157128. if (defined(options.terrainProvider) && options.globe !== false) {
  157129. scene.terrainProvider = options.terrainProvider;
  157130. }
  157131. this._screenSpaceEventHandler = new ScreenSpaceEventHandler(canvas, false);
  157132. if (defined(options.sceneMode)) {
  157133. if (options.sceneMode === SceneMode.SCENE2D) {
  157134. this._scene.morphTo2D(0);
  157135. }
  157136. if (options.sceneMode === SceneMode.COLUMBUS_VIEW) {
  157137. this._scene.morphToColumbusView(0);
  157138. }
  157139. }
  157140. this._useDefaultRenderLoop = undefined;
  157141. this.useDefaultRenderLoop = defaultValue(options.useDefaultRenderLoop, true);
  157142. this._targetFrameRate = undefined;
  157143. this.targetFrameRate = options.targetFrameRate;
  157144. var that = this;
  157145. scene.renderError.addEventListener(function(scene, error) {
  157146. that._useDefaultRenderLoop = false;
  157147. that._renderLoopRunning = false;
  157148. if (that._showRenderLoopErrors) {
  157149. var title = 'An error occurred while rendering. Rendering has stopped.';
  157150. that.showErrorPanel(title, undefined, error);
  157151. }
  157152. });
  157153. } catch (error) {
  157154. if (showRenderLoopErrors) {
  157155. var title = 'Error constructing CesiumWidget.';
  157156. var message = 'Visit <a href="http://get.webgl.org">http://get.webgl.org</a> to verify that your web browser and hardware support WebGL. Consider trying a different web browser or updating your video drivers. Detailed error information is below:';
  157157. this.showErrorPanel(title, message, error);
  157158. }
  157159. throw error;
  157160. }
  157161. }
  157162. defineProperties(CesiumWidget.prototype, {
  157163. /**
  157164. * Gets the parent container.
  157165. * @memberof CesiumWidget.prototype
  157166. *
  157167. * @type {Element}
  157168. */
  157169. container : {
  157170. get : function() {
  157171. return this._container;
  157172. }
  157173. },
  157174. /**
  157175. * Gets the canvas.
  157176. * @memberof CesiumWidget.prototype
  157177. *
  157178. * @type {Canvas}
  157179. */
  157180. canvas : {
  157181. get : function() {
  157182. return this._canvas;
  157183. }
  157184. },
  157185. /**
  157186. * Gets the credit container.
  157187. * @memberof CesiumWidget.prototype
  157188. *
  157189. * @type {Element}
  157190. */
  157191. creditContainer: {
  157192. get : function() {
  157193. return this._creditContainer;
  157194. }
  157195. },
  157196. /**
  157197. * Gets the scene.
  157198. * @memberof CesiumWidget.prototype
  157199. *
  157200. * @type {Scene}
  157201. */
  157202. scene : {
  157203. get : function() {
  157204. return this._scene;
  157205. }
  157206. },
  157207. /**
  157208. * Gets the collection of image layers that will be rendered on the globe.
  157209. * @memberof CesiumWidget.prototype
  157210. *
  157211. * @type {ImageryLayerCollection}
  157212. * @readonly
  157213. */
  157214. imageryLayers : {
  157215. get : function() {
  157216. return this._scene.imageryLayers;
  157217. }
  157218. },
  157219. /**
  157220. * The terrain provider providing surface geometry for the globe.
  157221. * @memberof CesiumWidget.prototype
  157222. *
  157223. * @type {TerrainProvider}
  157224. */
  157225. terrainProvider : {
  157226. get : function() {
  157227. return this._scene.terrainProvider;
  157228. },
  157229. set : function(terrainProvider) {
  157230. this._scene.terrainProvider = terrainProvider;
  157231. }
  157232. },
  157233. /**
  157234. * Gets the camera.
  157235. * @memberof CesiumWidget.prototype
  157236. *
  157237. * @type {Camera}
  157238. * @readonly
  157239. */
  157240. camera : {
  157241. get : function() {
  157242. return this._scene.camera;
  157243. }
  157244. },
  157245. /**
  157246. * Gets the clock.
  157247. * @memberof CesiumWidget.prototype
  157248. *
  157249. * @type {Clock}
  157250. */
  157251. clock : {
  157252. get : function() {
  157253. return this._clock;
  157254. }
  157255. },
  157256. /**
  157257. * Gets the screen space event handler.
  157258. * @memberof CesiumWidget.prototype
  157259. *
  157260. * @type {ScreenSpaceEventHandler}
  157261. */
  157262. screenSpaceEventHandler : {
  157263. get : function() {
  157264. return this._screenSpaceEventHandler;
  157265. }
  157266. },
  157267. /**
  157268. * Gets or sets the target frame rate of the widget when <code>useDefaultRenderLoop</code>
  157269. * is true. If undefined, the browser's {@link requestAnimationFrame} implementation
  157270. * determines the frame rate. If defined, this value must be greater than 0. A value higher
  157271. * than the underlying requestAnimationFrame implementation will have no effect.
  157272. * @memberof CesiumWidget.prototype
  157273. *
  157274. * @type {Number}
  157275. */
  157276. targetFrameRate : {
  157277. get : function() {
  157278. return this._targetFrameRate;
  157279. },
  157280. set : function(value) {
  157281. if (value <= 0) {
  157282. throw new DeveloperError('targetFrameRate must be greater than 0, or undefined.');
  157283. }
  157284. this._targetFrameRate = value;
  157285. }
  157286. },
  157287. /**
  157288. * Gets or sets whether or not this widget should control the render loop.
  157289. * If set to true the widget will use {@link requestAnimationFrame} to
  157290. * perform rendering and resizing of the widget, as well as drive the
  157291. * simulation clock. If set to false, you must manually call the
  157292. * <code>resize</code>, <code>render</code> methods as part of a custom
  157293. * render loop. If an error occurs during rendering, {@link Scene}'s
  157294. * <code>renderError</code> event will be raised and this property
  157295. * will be set to false. It must be set back to true to continue rendering
  157296. * after the error.
  157297. * @memberof CesiumWidget.prototype
  157298. *
  157299. * @type {Boolean}
  157300. */
  157301. useDefaultRenderLoop : {
  157302. get : function() {
  157303. return this._useDefaultRenderLoop;
  157304. },
  157305. set : function(value) {
  157306. if (this._useDefaultRenderLoop !== value) {
  157307. this._useDefaultRenderLoop = value;
  157308. if (value && !this._renderLoopRunning) {
  157309. startRenderLoop(this);
  157310. }
  157311. }
  157312. }
  157313. },
  157314. /**
  157315. * Gets or sets a scaling factor for rendering resolution. Values less than 1.0 can improve
  157316. * performance on less powerful devices while values greater than 1.0 will render at a higher
  157317. * resolution and then scale down, resulting in improved visual fidelity.
  157318. * For example, if the widget is laid out at a size of 640x480, setting this value to 0.5
  157319. * will cause the scene to be rendered at 320x240 and then scaled up while setting
  157320. * it to 2.0 will cause the scene to be rendered at 1280x960 and then scaled down.
  157321. * @memberof CesiumWidget.prototype
  157322. *
  157323. * @type {Number}
  157324. * @default 1.0
  157325. */
  157326. resolutionScale : {
  157327. get : function() {
  157328. return this._resolutionScale;
  157329. },
  157330. set : function(value) {
  157331. if (value <= 0) {
  157332. throw new DeveloperError('resolutionScale must be greater than 0.');
  157333. }
  157334. this._resolutionScale = value;
  157335. this._forceResize = true;
  157336. }
  157337. }
  157338. });
  157339. /**
  157340. * Show an error panel to the user containing a title and a longer error message,
  157341. * which can be dismissed using an OK button. This panel is displayed automatically
  157342. * when a render loop error occurs, if showRenderLoopErrors was not false when the
  157343. * widget was constructed.
  157344. *
  157345. * @param {String} title The title to be displayed on the error panel. This string is interpreted as text.
  157346. * @param {String} message A helpful, user-facing message to display prior to the detailed error information. This string is interpreted as HTML.
  157347. * @param {String} [error] The error to be displayed on the error panel. This string is formatted using {@link formatError} and then displayed as text.
  157348. */
  157349. CesiumWidget.prototype.showErrorPanel = function(title, message, error) {
  157350. var element = this._element;
  157351. var overlay = document.createElement('div');
  157352. overlay.className = 'cesium-widget-errorPanel';
  157353. var content = document.createElement('div');
  157354. content.className = 'cesium-widget-errorPanel-content';
  157355. overlay.appendChild(content);
  157356. var errorHeader = document.createElement('div');
  157357. errorHeader.className = 'cesium-widget-errorPanel-header';
  157358. errorHeader.appendChild(document.createTextNode(title));
  157359. content.appendChild(errorHeader);
  157360. var errorPanelScroller = document.createElement('div');
  157361. errorPanelScroller.className = 'cesium-widget-errorPanel-scroll';
  157362. content.appendChild(errorPanelScroller);
  157363. function resizeCallback() {
  157364. errorPanelScroller.style.maxHeight = Math.max(Math.round(element.clientHeight * 0.9 - 100), 30) + 'px';
  157365. }
  157366. resizeCallback();
  157367. if (defined(window.addEventListener)) {
  157368. window.addEventListener('resize', resizeCallback, false);
  157369. }
  157370. if (defined(message)) {
  157371. var errorMessage = document.createElement('div');
  157372. errorMessage.className = 'cesium-widget-errorPanel-message';
  157373. errorMessage.innerHTML = '<p>' + message + '</p>';
  157374. errorPanelScroller.appendChild(errorMessage);
  157375. }
  157376. var errorDetails = '(no error details available)';
  157377. if (defined(error)) {
  157378. errorDetails = formatError(error);
  157379. }
  157380. var errorMessageDetails = document.createElement('div');
  157381. errorMessageDetails.className = 'cesium-widget-errorPanel-message';
  157382. errorMessageDetails.appendChild(document.createTextNode(errorDetails));
  157383. errorPanelScroller.appendChild(errorMessageDetails);
  157384. var buttonPanel = document.createElement('div');
  157385. buttonPanel.className = 'cesium-widget-errorPanel-buttonPanel';
  157386. content.appendChild(buttonPanel);
  157387. var okButton = document.createElement('button');
  157388. okButton.setAttribute('type', 'button');
  157389. okButton.className = 'cesium-button';
  157390. okButton.appendChild(document.createTextNode('OK'));
  157391. okButton.onclick = function() {
  157392. if (defined(resizeCallback) && defined(window.removeEventListener)) {
  157393. window.removeEventListener('resize', resizeCallback, false);
  157394. }
  157395. element.removeChild(overlay);
  157396. };
  157397. buttonPanel.appendChild(okButton);
  157398. element.appendChild(overlay);
  157399. //IE8 does not have a console object unless the dev tools are open.
  157400. if (typeof console !== 'undefined') {
  157401. console.error(title + '\n' + message + '\n' + errorDetails);
  157402. }
  157403. };
  157404. /**
  157405. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  157406. */
  157407. CesiumWidget.prototype.isDestroyed = function() {
  157408. return false;
  157409. };
  157410. /**
  157411. * Destroys the widget. Should be called if permanently
  157412. * removing the widget from layout.
  157413. */
  157414. CesiumWidget.prototype.destroy = function() {
  157415. this._scene = this._scene && this._scene.destroy();
  157416. this._container.removeChild(this._element);
  157417. destroyObject(this);
  157418. };
  157419. /**
  157420. * Updates the canvas size, camera aspect ratio, and viewport size.
  157421. * This function is called automatically as needed unless
  157422. * <code>useDefaultRenderLoop</code> is set to false.
  157423. */
  157424. CesiumWidget.prototype.resize = function() {
  157425. var canvas = this._canvas;
  157426. var width = canvas.clientWidth;
  157427. var height = canvas.clientHeight;
  157428. if (!this._forceResize && this._canvasWidth === width && this._canvasHeight === height) {
  157429. return;
  157430. }
  157431. this._forceResize = false;
  157432. configureCanvasSize(this);
  157433. configureCameraFrustum(this);
  157434. };
  157435. /**
  157436. * Renders the scene. This function is called automatically
  157437. * unless <code>useDefaultRenderLoop</code> is set to false;
  157438. */
  157439. CesiumWidget.prototype.render = function() {
  157440. if (this._canRender) {
  157441. this._scene.initializeFrame();
  157442. var currentTime = this._clock.tick();
  157443. this._scene.render(currentTime);
  157444. } else {
  157445. this._clock.tick();
  157446. }
  157447. };
  157448. return CesiumWidget;
  157449. });
  157450. /*global define*/
  157451. define('Widgets/ClockViewModel',[
  157452. '../Core/Clock',
  157453. '../Core/defined',
  157454. '../Core/defineProperties',
  157455. '../Core/destroyObject',
  157456. '../Core/EventHelper',
  157457. '../Core/JulianDate',
  157458. '../ThirdParty/knockout'
  157459. ], function(
  157460. Clock,
  157461. defined,
  157462. defineProperties,
  157463. destroyObject,
  157464. EventHelper,
  157465. JulianDate,
  157466. knockout) {
  157467. 'use strict';
  157468. /**
  157469. * A view model which exposes a {@link Clock} for user interfaces.
  157470. * @alias ClockViewModel
  157471. * @constructor
  157472. *
  157473. * @param {Clock} [clock] The clock object wrapped by this view model, if undefined a new instance will be created.
  157474. *
  157475. * @see Clock
  157476. */
  157477. function ClockViewModel(clock) {
  157478. if (!defined(clock)) {
  157479. clock = new Clock();
  157480. }
  157481. this._clock = clock;
  157482. this._eventHelper = new EventHelper();
  157483. this._eventHelper.add(clock.onTick, this.synchronize, this);
  157484. /**
  157485. * Gets the current system time.
  157486. * This property is observable.
  157487. * @type {JulianDate}
  157488. */
  157489. this.systemTime = knockout.observable(JulianDate.now());
  157490. this.systemTime.equalityComparer = JulianDate.equals;
  157491. /**
  157492. * Gets or sets the start time of the clock.
  157493. * See {@link Clock#startTime}.
  157494. * This property is observable.
  157495. * @type {JulianDate}
  157496. */
  157497. this.startTime = knockout.observable(clock.startTime);
  157498. this.startTime.equalityComparer = JulianDate.equals;
  157499. this.startTime.subscribe(function(value) {
  157500. clock.startTime = value;
  157501. this.synchronize();
  157502. }, this);
  157503. /**
  157504. * Gets or sets the stop time of the clock.
  157505. * See {@link Clock#stopTime}.
  157506. * This property is observable.
  157507. * @type {JulianDate}
  157508. */
  157509. this.stopTime = knockout.observable(clock.stopTime);
  157510. this.stopTime.equalityComparer = JulianDate.equals;
  157511. this.stopTime.subscribe(function(value) {
  157512. clock.stopTime = value;
  157513. this.synchronize();
  157514. }, this);
  157515. /**
  157516. * Gets or sets the current time.
  157517. * See {@link Clock#currentTime}.
  157518. * This property is observable.
  157519. * @type {JulianDate}
  157520. */
  157521. this.currentTime = knockout.observable(clock.currentTime);
  157522. this.currentTime.equalityComparer = JulianDate.equals;
  157523. this.currentTime.subscribe(function(value) {
  157524. clock.currentTime = value;
  157525. this.synchronize();
  157526. }, this);
  157527. /**
  157528. * Gets or sets the clock multiplier.
  157529. * See {@link Clock#multiplier}.
  157530. * This property is observable.
  157531. * @type {Number}
  157532. */
  157533. this.multiplier = knockout.observable(clock.multiplier);
  157534. this.multiplier.subscribe(function(value) {
  157535. clock.multiplier = value;
  157536. this.synchronize();
  157537. }, this);
  157538. /**
  157539. * Gets or sets the clock step setting.
  157540. * See {@link Clock#clockStep}.
  157541. * This property is observable.
  157542. * @type {ClockStep}
  157543. */
  157544. this.clockStep = knockout.observable(clock.clockStep);
  157545. this.clockStep.subscribe(function(value) {
  157546. clock.clockStep = value;
  157547. this.synchronize();
  157548. }, this);
  157549. /**
  157550. * Gets or sets the clock range setting.
  157551. * See {@link Clock#clockRange}.
  157552. * This property is observable.
  157553. * @type {ClockRange}
  157554. */
  157555. this.clockRange = knockout.observable(clock.clockRange);
  157556. this.clockRange.subscribe(function(value) {
  157557. clock.clockRange = value;
  157558. this.synchronize();
  157559. }, this);
  157560. /**
  157561. * Gets or sets whether the clock can animate.
  157562. * See {@link Clock#canAnimate}.
  157563. * This property is observable.
  157564. * @type {Boolean}
  157565. */
  157566. this.canAnimate = knockout.observable(clock.canAnimate);
  157567. this.canAnimate.subscribe(function(value) {
  157568. clock.canAnimate = value;
  157569. this.synchronize();
  157570. }, this);
  157571. /**
  157572. * Gets or sets whether the clock should animate.
  157573. * See {@link Clock#shouldAnimate}.
  157574. * This property is observable.
  157575. * @type {Boolean}
  157576. */
  157577. this.shouldAnimate = knockout.observable(clock.shouldAnimate);
  157578. this.shouldAnimate.subscribe(function(value) {
  157579. clock.shouldAnimate = value;
  157580. this.synchronize();
  157581. }, this);
  157582. knockout.track(this, ['systemTime', 'startTime', 'stopTime', 'currentTime', 'multiplier', 'clockStep', 'clockRange', 'canAnimate', 'shouldAnimate']);
  157583. }
  157584. defineProperties(ClockViewModel.prototype, {
  157585. /**
  157586. * Gets the underlying Clock.
  157587. * @memberof ClockViewModel.prototype
  157588. * @type {Clock}
  157589. */
  157590. clock : {
  157591. get : function() {
  157592. return this._clock;
  157593. }
  157594. }
  157595. });
  157596. /**
  157597. * Updates the view model with the contents of the underlying clock.
  157598. * Can be called to force an update of the viewModel if the underlying
  157599. * clock has changed and <code>Clock.tick</code> has not yet been called.
  157600. */
  157601. ClockViewModel.prototype.synchronize = function() {
  157602. var clock = this._clock;
  157603. this.systemTime = JulianDate.now();
  157604. this.startTime = clock.startTime;
  157605. this.stopTime = clock.stopTime;
  157606. this.currentTime = clock.currentTime;
  157607. this.multiplier = clock.multiplier;
  157608. this.clockStep = clock.clockStep;
  157609. this.clockRange = clock.clockRange;
  157610. this.canAnimate = clock.canAnimate;
  157611. this.shouldAnimate = clock.shouldAnimate;
  157612. };
  157613. /**
  157614. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  157615. */
  157616. ClockViewModel.prototype.isDestroyed = function() {
  157617. return false;
  157618. };
  157619. /**
  157620. * Destroys the view model. Should be called to
  157621. * properly clean up the view model when it is no longer needed.
  157622. */
  157623. ClockViewModel.prototype.destroy = function() {
  157624. this._eventHelper.removeAll();
  157625. destroyObject(this);
  157626. };
  157627. return ClockViewModel;
  157628. });
  157629. /*global define*/
  157630. define('Widgets/Command',[
  157631. '../Core/DeveloperError'
  157632. ], function(
  157633. DeveloperError) {
  157634. 'use strict';
  157635. /**
  157636. * A Command is a function with an extra <code>canExecute</code> observable property to determine
  157637. * whether the command can be executed. When executed, a Command function will check the
  157638. * value of <code>canExecute</code> and throw if false.
  157639. *
  157640. * This type describes an interface and is not intended to be instantiated directly.
  157641. * See {@link createCommand} to create a command from a function.
  157642. *
  157643. * @alias Command
  157644. * @constructor
  157645. */
  157646. function Command() {
  157647. /**
  157648. * Gets whether this command can currently be executed. This property is observable.
  157649. * @type {Boolean}
  157650. * @default undefined
  157651. */
  157652. this.canExecute = undefined;
  157653. /**
  157654. * Gets an event which is raised before the command executes, the event
  157655. * is raised with an object containing two properties: a <code>cancel</code> property,
  157656. * which if set to false by the listener will prevent the command from being executed, and
  157657. * an <code>args</code> property, which is the array of arguments being passed to the command.
  157658. * @type {Event}
  157659. * @default undefined
  157660. */
  157661. this.beforeExecute = undefined;
  157662. /**
  157663. * Gets an event which is raised after the command executes, the event
  157664. * is raised with the return value of the command as its only parameter.
  157665. * @type {Event}
  157666. * @default undefined
  157667. */
  157668. this.afterExecute = undefined;
  157669. DeveloperError.throwInstantiationError();
  157670. }
  157671. return Command;
  157672. });
  157673. /*global define*/
  157674. define('Widgets/FullscreenButton/FullscreenButtonViewModel',[
  157675. '../../Core/defaultValue',
  157676. '../../Core/defineProperties',
  157677. '../../Core/destroyObject',
  157678. '../../Core/DeveloperError',
  157679. '../../Core/Fullscreen',
  157680. '../../ThirdParty/knockout',
  157681. '../createCommand',
  157682. '../getElement'
  157683. ], function(
  157684. defaultValue,
  157685. defineProperties,
  157686. destroyObject,
  157687. DeveloperError,
  157688. Fullscreen,
  157689. knockout,
  157690. createCommand,
  157691. getElement) {
  157692. 'use strict';
  157693. /**
  157694. * The view model for {@link FullscreenButton}.
  157695. * @alias FullscreenButtonViewModel
  157696. * @constructor
  157697. *
  157698. * @param {Element|String} [fullscreenElement=document.body] The element or id to be placed into fullscreen mode.
  157699. */
  157700. function FullscreenButtonViewModel(fullscreenElement) {
  157701. var that = this;
  157702. var tmpIsFullscreen = knockout.observable(Fullscreen.fullscreen);
  157703. var tmpIsEnabled = knockout.observable(Fullscreen.enabled);
  157704. /**
  157705. * Gets whether or not fullscreen mode is active. This property is observable.
  157706. *
  157707. * @type {Boolean}
  157708. */
  157709. this.isFullscreen = undefined;
  157710. knockout.defineProperty(this, 'isFullscreen', {
  157711. get : function() {
  157712. return tmpIsFullscreen();
  157713. }
  157714. });
  157715. /**
  157716. * Gets or sets whether or not fullscreen functionality should be enabled. This property is observable.
  157717. *
  157718. * @type {Boolean}
  157719. * @see Fullscreen.enabled
  157720. */
  157721. this.isFullscreenEnabled = undefined;
  157722. knockout.defineProperty(this, 'isFullscreenEnabled', {
  157723. get : function() {
  157724. return tmpIsEnabled();
  157725. },
  157726. set : function(value) {
  157727. tmpIsEnabled(value && Fullscreen.enabled);
  157728. }
  157729. });
  157730. /**
  157731. * Gets the tooltip. This property is observable.
  157732. *
  157733. * @type {String}
  157734. */
  157735. this.tooltip = undefined;
  157736. knockout.defineProperty(this, 'tooltip', function() {
  157737. if (!this.isFullscreenEnabled) {
  157738. return 'Full screen unavailable';
  157739. }
  157740. return tmpIsFullscreen() ? 'Exit full screen' : 'Full screen';
  157741. });
  157742. this._command = createCommand(function() {
  157743. if (Fullscreen.fullscreen) {
  157744. Fullscreen.exitFullscreen();
  157745. } else {
  157746. Fullscreen.requestFullscreen(that._fullscreenElement);
  157747. }
  157748. }, knockout.getObservable(this, 'isFullscreenEnabled'));
  157749. this._fullscreenElement = defaultValue(getElement(fullscreenElement), document.body);
  157750. this._callback = function() {
  157751. tmpIsFullscreen(Fullscreen.fullscreen);
  157752. };
  157753. document.addEventListener(Fullscreen.changeEventName, this._callback);
  157754. }
  157755. defineProperties(FullscreenButtonViewModel.prototype, {
  157756. /**
  157757. * Gets or sets the HTML element to place into fullscreen mode when the
  157758. * corresponding button is pressed.
  157759. * @memberof FullscreenButtonViewModel.prototype
  157760. *
  157761. * @type {Element}
  157762. */
  157763. fullscreenElement : {
  157764. //TODO:@exception {DeveloperError} value must be a valid HTML Element.
  157765. get : function() {
  157766. return this._fullscreenElement;
  157767. },
  157768. set : function(value) {
  157769. if (!(value instanceof Element)) {
  157770. throw new DeveloperError('value must be a valid Element.');
  157771. }
  157772. this._fullscreenElement = value;
  157773. }
  157774. },
  157775. /**
  157776. * Gets the Command to toggle fullscreen mode.
  157777. * @memberof FullscreenButtonViewModel.prototype
  157778. *
  157779. * @type {Command}
  157780. */
  157781. command : {
  157782. get : function() {
  157783. return this._command;
  157784. }
  157785. }
  157786. });
  157787. /**
  157788. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  157789. */
  157790. FullscreenButtonViewModel.prototype.isDestroyed = function() {
  157791. return false;
  157792. };
  157793. /**
  157794. * Destroys the view model. Should be called to
  157795. * properly clean up the view model when it is no longer needed.
  157796. */
  157797. FullscreenButtonViewModel.prototype.destroy = function() {
  157798. document.removeEventListener(Fullscreen.changeEventName, this._callback);
  157799. destroyObject(this);
  157800. };
  157801. return FullscreenButtonViewModel;
  157802. });
  157803. /*global define*/
  157804. define('Widgets/FullscreenButton/FullscreenButton',[
  157805. '../../Core/defined',
  157806. '../../Core/defineProperties',
  157807. '../../Core/destroyObject',
  157808. '../../Core/DeveloperError',
  157809. '../../ThirdParty/knockout',
  157810. '../getElement',
  157811. './FullscreenButtonViewModel'
  157812. ], function(
  157813. defined,
  157814. defineProperties,
  157815. destroyObject,
  157816. DeveloperError,
  157817. knockout,
  157818. getElement,
  157819. FullscreenButtonViewModel) {
  157820. 'use strict';
  157821. var enterFullScreenPath = 'M 83.96875 17.5625 L 83.96875 17.59375 L 76.65625 24.875 L 97.09375 24.96875 L 76.09375 45.96875 L 81.9375 51.8125 L 102.78125 30.9375 L 102.875 51.15625 L 110.15625 43.875 L 110.1875 17.59375 L 83.96875 17.5625 z M 44.125 17.59375 L 17.90625 17.625 L 17.9375 43.90625 L 25.21875 51.1875 L 25.3125 30.96875 L 46.15625 51.8125 L 52 45.96875 L 31 25 L 51.4375 24.90625 L 44.125 17.59375 z M 46.0625 76.03125 L 25.1875 96.875 L 25.09375 76.65625 L 17.8125 83.9375 L 17.8125 110.21875 L 44 110.25 L 51.3125 102.9375 L 30.90625 102.84375 L 51.875 81.875 L 46.0625 76.03125 z M 82 76.15625 L 76.15625 82 L 97.15625 103 L 76.71875 103.0625 L 84.03125 110.375 L 110.25 110.34375 L 110.21875 84.0625 L 102.9375 76.8125 L 102.84375 97 L 82 76.15625 z';
  157822. var exitFullScreenPath = 'M 104.34375 17.5625 L 83.5 38.4375 L 83.40625 18.21875 L 76.125 25.5 L 76.09375 51.78125 L 102.3125 51.8125 L 102.3125 51.78125 L 109.625 44.5 L 89.1875 44.40625 L 110.1875 23.40625 L 104.34375 17.5625 z M 23.75 17.59375 L 17.90625 23.4375 L 38.90625 44.4375 L 18.5 44.53125 L 25.78125 51.8125 L 52 51.78125 L 51.96875 25.53125 L 44.6875 18.25 L 44.625 38.46875 L 23.75 17.59375 z M 25.6875 76.03125 L 18.375 83.3125 L 38.78125 83.40625 L 17.8125 104.40625 L 23.625 110.25 L 44.5 89.375 L 44.59375 109.59375 L 51.875 102.3125 L 51.875 76.0625 L 25.6875 76.03125 z M 102.375 76.15625 L 76.15625 76.1875 L 76.1875 102.4375 L 83.46875 109.71875 L 83.5625 89.53125 L 104.40625 110.375 L 110.25 104.53125 L 89.25 83.53125 L 109.6875 83.46875 L 102.375 76.15625 z';
  157823. /**
  157824. * A single button widget for toggling fullscreen mode.
  157825. *
  157826. * @alias FullscreenButton
  157827. * @constructor
  157828. *
  157829. * @param {Element|String} container The DOM element or ID that will contain the widget.
  157830. * @param {Element|String} [fullscreenElement=document.body] The element or id to be placed into fullscreen mode.
  157831. *
  157832. * @exception {DeveloperError} Element with id "container" does not exist in the document.
  157833. *
  157834. * @see Fullscreen
  157835. */
  157836. function FullscreenButton(container, fullscreenElement) {
  157837. if (!defined(container)) {
  157838. throw new DeveloperError('container is required.');
  157839. }
  157840. container = getElement(container);
  157841. var viewModel = new FullscreenButtonViewModel(fullscreenElement);
  157842. viewModel._exitFullScreenPath = exitFullScreenPath;
  157843. viewModel._enterFullScreenPath = enterFullScreenPath;
  157844. var element = document.createElement('button');
  157845. element.type = 'button';
  157846. element.className = 'cesium-button cesium-fullscreenButton';
  157847. element.setAttribute('data-bind', '\
  157848. attr: { title: tooltip },\
  157849. click: command,\
  157850. enable: isFullscreenEnabled,\
  157851. cesiumSvgPath: { path: isFullscreen ? _exitFullScreenPath : _enterFullScreenPath, width: 128, height: 128 }');
  157852. container.appendChild(element);
  157853. knockout.applyBindings(viewModel, element);
  157854. this._container = container;
  157855. this._viewModel = viewModel;
  157856. this._element = element;
  157857. }
  157858. defineProperties(FullscreenButton.prototype, {
  157859. /**
  157860. * Gets the parent container.
  157861. * @memberof FullscreenButton.prototype
  157862. *
  157863. * @type {Element}
  157864. */
  157865. container : {
  157866. get : function() {
  157867. return this._container;
  157868. }
  157869. },
  157870. /**
  157871. * Gets the view model.
  157872. * @memberof FullscreenButton.prototype
  157873. *
  157874. * @type {FullscreenButtonViewModel}
  157875. */
  157876. viewModel : {
  157877. get : function() {
  157878. return this._viewModel;
  157879. }
  157880. }
  157881. });
  157882. /**
  157883. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  157884. */
  157885. FullscreenButton.prototype.isDestroyed = function() {
  157886. return false;
  157887. };
  157888. /**
  157889. * Destroys the widget. Should be called if permanently
  157890. * removing the widget from layout.
  157891. */
  157892. FullscreenButton.prototype.destroy = function() {
  157893. this._viewModel.destroy();
  157894. knockout.cleanNode(this._element);
  157895. this._container.removeChild(this._element);
  157896. return destroyObject(this);
  157897. };
  157898. return FullscreenButton;
  157899. });
  157900. /*global define*/
  157901. define('Widgets/Geocoder/GeocoderViewModel',[
  157902. '../../Core/BingMapsApi',
  157903. '../../Core/Cartesian3',
  157904. '../../Core/defaultValue',
  157905. '../../Core/defined',
  157906. '../../Core/defineProperties',
  157907. '../../Core/DeveloperError',
  157908. '../../Core/Event',
  157909. '../../Core/loadJsonp',
  157910. '../../Core/Matrix4',
  157911. '../../Core/Rectangle',
  157912. '../../ThirdParty/knockout',
  157913. '../../ThirdParty/when',
  157914. '../createCommand'
  157915. ], function(
  157916. BingMapsApi,
  157917. Cartesian3,
  157918. defaultValue,
  157919. defined,
  157920. defineProperties,
  157921. DeveloperError,
  157922. Event,
  157923. loadJsonp,
  157924. Matrix4,
  157925. Rectangle,
  157926. knockout,
  157927. when,
  157928. createCommand) {
  157929. 'use strict';
  157930. /**
  157931. * The view model for the {@link Geocoder} widget.
  157932. * @alias GeocoderViewModel
  157933. * @constructor
  157934. *
  157935. * @param {Object} options Object with the following properties:
  157936. * @param {Scene} options.scene The Scene instance to use.
  157937. * @param {String} [options.url='https://dev.virtualearth.net'] The base URL of the Bing Maps API.
  157938. * @param {String} [options.key] The Bing Maps key for your application, which can be
  157939. * created at {@link https://www.bingmapsportal.com}.
  157940. * If this parameter is not provided, {@link BingMapsApi.defaultKey} is used.
  157941. * If {@link BingMapsApi.defaultKey} is undefined as well, a message is
  157942. * written to the console reminding you that you must create and supply a Bing Maps
  157943. * key as soon as possible. Please do not deploy an application that uses
  157944. * this widget without creating a separate key for your application.
  157945. * @param {Number} [options.flightDuration] The duration of the camera flight to an entered location, in seconds.
  157946. */
  157947. function GeocoderViewModel(options) {
  157948. if (!defined(options) || !defined(options.scene)) {
  157949. throw new DeveloperError('options.scene is required.');
  157950. }
  157951. this._url = defaultValue(options.url, 'https://dev.virtualearth.net/');
  157952. if (this._url.length > 0 && this._url[this._url.length - 1] !== '/') {
  157953. this._url += '/';
  157954. }
  157955. this._key = BingMapsApi.getKey(options.key);
  157956. var errorCredit = BingMapsApi.getErrorCredit(options.key);
  157957. if (defined(errorCredit)) {
  157958. options.scene._frameState.creditDisplay.addDefaultCredit(errorCredit);
  157959. }
  157960. this._scene = options.scene;
  157961. this._flightDuration = options.flightDuration;
  157962. this._searchText = '';
  157963. this._isSearchInProgress = false;
  157964. this._geocodeInProgress = undefined;
  157965. this._complete = new Event();
  157966. var that = this;
  157967. this._searchCommand = createCommand(function() {
  157968. if (that.isSearchInProgress) {
  157969. cancelGeocode(that);
  157970. } else {
  157971. geocode(that);
  157972. }
  157973. });
  157974. /**
  157975. * Gets or sets a value indicating if this instance should always show its text input field.
  157976. *
  157977. * @type {Boolean}
  157978. * @default false
  157979. */
  157980. this.keepExpanded = false;
  157981. knockout.track(this, ['_searchText', '_isSearchInProgress', 'keepExpanded']);
  157982. /**
  157983. * Gets a value indicating whether a search is currently in progress. This property is observable.
  157984. *
  157985. * @type {Boolean}
  157986. */
  157987. this.isSearchInProgress = undefined;
  157988. knockout.defineProperty(this, 'isSearchInProgress', {
  157989. get : function() {
  157990. return this._isSearchInProgress;
  157991. }
  157992. });
  157993. /**
  157994. * Gets or sets the text to search for. The text can be an address, or longitude, latitude,
  157995. * and optional height, where longitude and latitude are in degrees and height is in meters.
  157996. *
  157997. * @type {String}
  157998. */
  157999. this.searchText = undefined;
  158000. knockout.defineProperty(this, 'searchText', {
  158001. get : function() {
  158002. if (this.isSearchInProgress) {
  158003. return 'Searching...';
  158004. }
  158005. return this._searchText;
  158006. },
  158007. set : function(value) {
  158008. if (typeof value !== 'string') {
  158009. throw new DeveloperError('value must be a valid string.');
  158010. }
  158011. this._searchText = value;
  158012. }
  158013. });
  158014. /**
  158015. * Gets or sets the the duration of the camera flight in seconds.
  158016. * A value of zero causes the camera to instantly switch to the geocoding location.
  158017. * The duration will be computed based on the distance when undefined.
  158018. *
  158019. * @type {Number|undefined}
  158020. * @default undefined
  158021. */
  158022. this.flightDuration = undefined;
  158023. knockout.defineProperty(this, 'flightDuration', {
  158024. get : function() {
  158025. return this._flightDuration;
  158026. },
  158027. set : function(value) {
  158028. if (defined(value) && value < 0) {
  158029. throw new DeveloperError('value must be positive.');
  158030. }
  158031. this._flightDuration = value;
  158032. }
  158033. });
  158034. }
  158035. defineProperties(GeocoderViewModel.prototype, {
  158036. /**
  158037. * Gets the Bing maps url.
  158038. * @memberof GeocoderViewModel.prototype
  158039. *
  158040. * @type {String}
  158041. */
  158042. url : {
  158043. get : function() {
  158044. return this._url;
  158045. }
  158046. },
  158047. /**
  158048. * Gets the Bing maps key.
  158049. * @memberof GeocoderViewModel.prototype
  158050. *
  158051. * @type {String}
  158052. */
  158053. key : {
  158054. get : function() {
  158055. return this._key;
  158056. }
  158057. },
  158058. /**
  158059. * Gets the event triggered on flight completion.
  158060. * @memberof GeocoderViewModel.prototype
  158061. *
  158062. * @type {Event}
  158063. */
  158064. complete : {
  158065. get : function() {
  158066. return this._complete;
  158067. }
  158068. },
  158069. /**
  158070. * Gets the scene to control.
  158071. * @memberof GeocoderViewModel.prototype
  158072. *
  158073. * @type {Scene}
  158074. */
  158075. scene : {
  158076. get : function() {
  158077. return this._scene;
  158078. }
  158079. },
  158080. /**
  158081. * Gets the Command that is executed when the button is clicked.
  158082. * @memberof GeocoderViewModel.prototype
  158083. *
  158084. * @type {Command}
  158085. */
  158086. search : {
  158087. get : function() {
  158088. return this._searchCommand;
  158089. }
  158090. }
  158091. });
  158092. function updateCamera(viewModel, destination) {
  158093. viewModel._scene.camera.flyTo({
  158094. destination : destination,
  158095. complete: function() {
  158096. viewModel._complete.raiseEvent();
  158097. },
  158098. duration : viewModel._flightDuration,
  158099. endTransform : Matrix4.IDENTITY
  158100. });
  158101. }
  158102. function geocode(viewModel) {
  158103. var query = viewModel.searchText;
  158104. if (/^\s*$/.test(query)) {
  158105. //whitespace string
  158106. return;
  158107. }
  158108. // If the user entered (longitude, latitude, [height]) in degrees/meters,
  158109. // fly without calling the geocoder.
  158110. var splitQuery = query.match(/[^\s,\n]+/g);
  158111. if ((splitQuery.length === 2) || (splitQuery.length === 3)) {
  158112. var longitude = +splitQuery[0];
  158113. var latitude = +splitQuery[1];
  158114. var height = (splitQuery.length === 3) ? +splitQuery[2] : 300.0;
  158115. if (!isNaN(longitude) && !isNaN(latitude) && !isNaN(height)) {
  158116. updateCamera(viewModel, Cartesian3.fromDegrees(longitude, latitude, height));
  158117. return;
  158118. }
  158119. }
  158120. viewModel._isSearchInProgress = true;
  158121. var promise = loadJsonp(viewModel._url + 'REST/v1/Locations', {
  158122. parameters : {
  158123. query : query,
  158124. key : viewModel._key
  158125. },
  158126. callbackParameterName : 'jsonp'
  158127. });
  158128. var geocodeInProgress = viewModel._geocodeInProgress = when(promise, function(result) {
  158129. if (geocodeInProgress.cancel) {
  158130. return;
  158131. }
  158132. viewModel._isSearchInProgress = false;
  158133. if (result.resourceSets.length === 0) {
  158134. viewModel.searchText = viewModel._searchText + ' (not found)';
  158135. return;
  158136. }
  158137. var resourceSet = result.resourceSets[0];
  158138. if (resourceSet.resources.length === 0) {
  158139. viewModel.searchText = viewModel._searchText + ' (not found)';
  158140. return;
  158141. }
  158142. var resource = resourceSet.resources[0];
  158143. viewModel._searchText = resource.name;
  158144. var bbox = resource.bbox;
  158145. var south = bbox[0];
  158146. var west = bbox[1];
  158147. var north = bbox[2];
  158148. var east = bbox[3];
  158149. updateCamera(viewModel, Rectangle.fromDegrees(west, south, east, north));
  158150. }, function() {
  158151. if (geocodeInProgress.cancel) {
  158152. return;
  158153. }
  158154. viewModel._isSearchInProgress = false;
  158155. viewModel.searchText = viewModel._searchText + ' (error)';
  158156. });
  158157. }
  158158. function cancelGeocode(viewModel) {
  158159. viewModel._isSearchInProgress = false;
  158160. if (defined(viewModel._geocodeInProgress)) {
  158161. viewModel._geocodeInProgress.cancel = true;
  158162. viewModel._geocodeInProgress = undefined;
  158163. }
  158164. }
  158165. return GeocoderViewModel;
  158166. });
  158167. /*global define*/
  158168. define('Widgets/Geocoder/Geocoder',[
  158169. '../../Core/defined',
  158170. '../../Core/defineProperties',
  158171. '../../Core/destroyObject',
  158172. '../../Core/DeveloperError',
  158173. '../../Core/FeatureDetection',
  158174. '../../ThirdParty/knockout',
  158175. '../getElement',
  158176. './GeocoderViewModel'
  158177. ], function(
  158178. defined,
  158179. defineProperties,
  158180. destroyObject,
  158181. DeveloperError,
  158182. FeatureDetection,
  158183. knockout,
  158184. getElement,
  158185. GeocoderViewModel) {
  158186. 'use strict';
  158187. var startSearchPath = 'M29.772,26.433l-7.126-7.126c0.96-1.583,1.523-3.435,1.524-5.421C24.169,8.093,19.478,3.401,13.688,3.399C7.897,3.401,3.204,8.093,3.204,13.885c0,5.789,4.693,10.481,10.484,10.481c1.987,0,3.839-0.563,5.422-1.523l7.128,7.127L29.772,26.433zM7.203,13.885c0.006-3.582,2.903-6.478,6.484-6.486c3.579,0.008,6.478,2.904,6.484,6.486c-0.007,3.58-2.905,6.476-6.484,6.484C10.106,20.361,7.209,17.465,7.203,13.885z';
  158188. var stopSearchPath = 'M24.778,21.419 19.276,15.917 24.777,10.415 21.949,7.585 16.447,13.087 10.945,7.585 8.117,10.415 13.618,15.917 8.116,21.419 10.946,24.248 16.447,18.746 21.948,24.248z';
  158189. /**
  158190. * A widget for finding addresses and landmarks, and flying the camera to them. Geocoding is
  158191. * performed using the {@link http://msdn.microsoft.com/en-us/library/ff701715.aspx|Bing Maps Locations API}.
  158192. *
  158193. * @alias Geocoder
  158194. * @constructor
  158195. *
  158196. * @param {Object} options Object with the following properties:
  158197. * @param {Element|String} options.container The DOM element or ID that will contain the widget.
  158198. * @param {Scene} options.scene The Scene instance to use.
  158199. * @param {String} [options.url='https://dev.virtualearth.net'] The base URL of the Bing Maps API.
  158200. * @param {String} [options.key] The Bing Maps key for your application, which can be
  158201. * created at {@link https://www.bingmapsportal.com}.
  158202. * If this parameter is not provided, {@link BingMapsApi.defaultKey} is used.
  158203. * If {@link BingMapsApi.defaultKey} is undefined as well, a message is
  158204. * written to the console reminding you that you must create and supply a Bing Maps
  158205. * key as soon as possible. Please do not deploy an application that uses
  158206. * this widget without creating a separate key for your application.
  158207. * @param {Number} [options.flightDuration=1.5] The duration of the camera flight to an entered location, in seconds.
  158208. */
  158209. function Geocoder(options) {
  158210. if (!defined(options) || !defined(options.container)) {
  158211. throw new DeveloperError('options.container is required.');
  158212. }
  158213. if (!defined(options.scene)) {
  158214. throw new DeveloperError('options.scene is required.');
  158215. }
  158216. var container = getElement(options.container);
  158217. var viewModel = new GeocoderViewModel(options);
  158218. viewModel._startSearchPath = startSearchPath;
  158219. viewModel._stopSearchPath = stopSearchPath;
  158220. var form = document.createElement('form');
  158221. form.setAttribute('data-bind', 'submit: search');
  158222. var textBox = document.createElement('input');
  158223. textBox.type = 'search';
  158224. textBox.className = 'cesium-geocoder-input';
  158225. textBox.setAttribute('placeholder', 'Enter an address or landmark...');
  158226. textBox.setAttribute('data-bind', '\
  158227. value: searchText,\
  158228. valueUpdate: "afterkeydown",\
  158229. disable: isSearchInProgress,\
  158230. css: { "cesium-geocoder-input-wide" : keepExpanded || searchText.length > 0 }');
  158231. this._onTextBoxFocus = function() {
  158232. // as of 2016-10-19, setTimeout is required to ensure that the
  158233. // text is focused on Safari 10
  158234. setTimeout(function() {
  158235. textBox.select();
  158236. }, 0);
  158237. };
  158238. textBox.addEventListener('focus', this._onTextBoxFocus, false);
  158239. form.appendChild(textBox);
  158240. this._textBox = textBox;
  158241. var searchButton = document.createElement('span');
  158242. searchButton.className = 'cesium-geocoder-searchButton';
  158243. searchButton.setAttribute('data-bind', '\
  158244. click: search,\
  158245. cesiumSvgPath: { path: isSearchInProgress ? _stopSearchPath : _startSearchPath, width: 32, height: 32 }');
  158246. form.appendChild(searchButton);
  158247. container.appendChild(form);
  158248. knockout.applyBindings(viewModel, form);
  158249. this._container = container;
  158250. this._viewModel = viewModel;
  158251. this._form = form;
  158252. this._onInputBegin = function(e) {
  158253. if (!container.contains(e.target)) {
  158254. textBox.blur();
  158255. }
  158256. };
  158257. this._onInputEnd = function(e) {
  158258. if (container.contains(e.target)) {
  158259. textBox.focus();
  158260. }
  158261. };
  158262. //We subscribe to both begin and end events in order to give the text box
  158263. //focus no matter where on the widget is clicked.
  158264. if (FeatureDetection.supportsPointerEvents()) {
  158265. document.addEventListener('pointerdown', this._onInputBegin, true);
  158266. document.addEventListener('pointerup', this._onInputEnd, true);
  158267. document.addEventListener('pointercancel', this._onInputEnd, true);
  158268. } else {
  158269. document.addEventListener('mousedown', this._onInputBegin, true);
  158270. document.addEventListener('mouseup', this._onInputEnd, true);
  158271. document.addEventListener('touchstart', this._onInputBegin, true);
  158272. document.addEventListener('touchend', this._onInputEnd, true);
  158273. document.addEventListener('touchcancel', this._onInputEnd, true);
  158274. }
  158275. }
  158276. defineProperties(Geocoder.prototype, {
  158277. /**
  158278. * Gets the parent container.
  158279. * @memberof Geocoder.prototype
  158280. *
  158281. * @type {Element}
  158282. */
  158283. container : {
  158284. get : function() {
  158285. return this._container;
  158286. }
  158287. },
  158288. /**
  158289. * Gets the view model.
  158290. * @memberof Geocoder.prototype
  158291. *
  158292. * @type {GeocoderViewModel}
  158293. */
  158294. viewModel : {
  158295. get : function() {
  158296. return this._viewModel;
  158297. }
  158298. }
  158299. });
  158300. /**
  158301. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  158302. */
  158303. Geocoder.prototype.isDestroyed = function() {
  158304. return false;
  158305. };
  158306. /**
  158307. * Destroys the widget. Should be called if permanently
  158308. * removing the widget from layout.
  158309. */
  158310. Geocoder.prototype.destroy = function() {
  158311. if (FeatureDetection.supportsPointerEvents()) {
  158312. document.removeEventListener('pointerdown', this._onInputBegin, true);
  158313. document.removeEventListener('pointerup', this._onInputEnd, true);
  158314. } else {
  158315. document.removeEventListener('mousedown', this._onInputBegin, true);
  158316. document.removeEventListener('mouseup', this._onInputEnd, true);
  158317. document.removeEventListener('touchstart', this._onInputBegin, true);
  158318. document.removeEventListener('touchend', this._onInputEnd, true);
  158319. }
  158320. knockout.cleanNode(this._form);
  158321. this._container.removeChild(this._form);
  158322. this._textBox.removeEventListener('focus', this._onTextBoxFocus, false);
  158323. return destroyObject(this);
  158324. };
  158325. return Geocoder;
  158326. });
  158327. /*global define*/
  158328. define('Widgets/HomeButton/HomeButtonViewModel',[
  158329. '../../Core/defined',
  158330. '../../Core/defineProperties',
  158331. '../../Core/DeveloperError',
  158332. '../../ThirdParty/knockout',
  158333. '../createCommand'
  158334. ], function(
  158335. defined,
  158336. defineProperties,
  158337. DeveloperError,
  158338. knockout,
  158339. createCommand) {
  158340. 'use strict';
  158341. /**
  158342. * The view model for {@link HomeButton}.
  158343. * @alias HomeButtonViewModel
  158344. * @constructor
  158345. *
  158346. * @param {Scene} scene The scene instance to use.
  158347. * @param {Number} [duration] The duration of the camera flight in seconds.
  158348. */
  158349. function HomeButtonViewModel(scene, duration) {
  158350. if (!defined(scene)) {
  158351. throw new DeveloperError('scene is required.');
  158352. }
  158353. this._scene = scene;
  158354. this._duration = duration;
  158355. var that = this;
  158356. this._command = createCommand(function() {
  158357. that._scene.camera.flyHome(that._duration);
  158358. });
  158359. /**
  158360. * Gets or sets the tooltip. This property is observable.
  158361. *
  158362. * @type {String}
  158363. */
  158364. this.tooltip = 'View Home';
  158365. knockout.track(this, ['tooltip']);
  158366. }
  158367. defineProperties(HomeButtonViewModel.prototype, {
  158368. /**
  158369. * Gets the scene to control.
  158370. * @memberof HomeButtonViewModel.prototype
  158371. *
  158372. * @type {Scene}
  158373. */
  158374. scene : {
  158375. get : function() {
  158376. return this._scene;
  158377. }
  158378. },
  158379. /**
  158380. * Gets the Command that is executed when the button is clicked.
  158381. * @memberof HomeButtonViewModel.prototype
  158382. *
  158383. * @type {Command}
  158384. */
  158385. command : {
  158386. get : function() {
  158387. return this._command;
  158388. }
  158389. },
  158390. /**
  158391. * Gets or sets the the duration of the camera flight in seconds.
  158392. * A value of zero causes the camera to instantly switch to home view.
  158393. * The duration will be computed based on the distance when undefined.
  158394. * @memberof HomeButtonViewModel.prototype
  158395. *
  158396. * @type {Number|undefined}
  158397. */
  158398. duration : {
  158399. get : function() {
  158400. return this._duration;
  158401. },
  158402. set : function(value) {
  158403. if (defined(value) && value < 0) {
  158404. throw new DeveloperError('value must be positive.');
  158405. }
  158406. this._duration = value;
  158407. }
  158408. }
  158409. });
  158410. return HomeButtonViewModel;
  158411. });
  158412. /*global define*/
  158413. define('Widgets/HomeButton/HomeButton',[
  158414. '../../Core/defined',
  158415. '../../Core/defineProperties',
  158416. '../../Core/destroyObject',
  158417. '../../Core/DeveloperError',
  158418. '../../ThirdParty/knockout',
  158419. '../getElement',
  158420. './HomeButtonViewModel'
  158421. ], function(
  158422. defined,
  158423. defineProperties,
  158424. destroyObject,
  158425. DeveloperError,
  158426. knockout,
  158427. getElement,
  158428. HomeButtonViewModel) {
  158429. 'use strict';
  158430. /**
  158431. * A single button widget for returning to the default camera view of the current scene.
  158432. *
  158433. * @alias HomeButton
  158434. * @constructor
  158435. *
  158436. * @param {Element|String} container The DOM element or ID that will contain the widget.
  158437. * @param {Scene} scene The Scene instance to use.
  158438. * @param {Number} [duration] The time, in seconds, it takes to complete the camera flight home.
  158439. */
  158440. function HomeButton(container, scene, duration) {
  158441. if (!defined(container)) {
  158442. throw new DeveloperError('container is required.');
  158443. }
  158444. container = getElement(container);
  158445. var viewModel = new HomeButtonViewModel(scene, duration);
  158446. viewModel._svgPath = 'M14,4l-10,8.75h20l-4.25-3.7188v-4.6562h-2.812v2.1875l-2.938-2.5625zm-7.0938,9.906v10.094h14.094v-10.094h-14.094zm2.1876,2.313h3.3122v4.25h-3.3122v-4.25zm5.8442,1.281h3.406v6.438h-3.406v-6.438z';
  158447. var element = document.createElement('button');
  158448. element.type = 'button';
  158449. element.className = 'cesium-button cesium-toolbar-button cesium-home-button';
  158450. element.setAttribute('data-bind', '\
  158451. attr: { title: tooltip },\
  158452. click: command,\
  158453. cesiumSvgPath: { path: _svgPath, width: 28, height: 28 }');
  158454. container.appendChild(element);
  158455. knockout.applyBindings(viewModel, element);
  158456. this._container = container;
  158457. this._viewModel = viewModel;
  158458. this._element = element;
  158459. }
  158460. defineProperties(HomeButton.prototype, {
  158461. /**
  158462. * Gets the parent container.
  158463. * @memberof HomeButton.prototype
  158464. *
  158465. * @type {Element}
  158466. */
  158467. container : {
  158468. get : function() {
  158469. return this._container;
  158470. }
  158471. },
  158472. /**
  158473. * Gets the view model.
  158474. * @memberof HomeButton.prototype
  158475. *
  158476. * @type {HomeButtonViewModel}
  158477. */
  158478. viewModel : {
  158479. get : function() {
  158480. return this._viewModel;
  158481. }
  158482. }
  158483. });
  158484. /**
  158485. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  158486. */
  158487. HomeButton.prototype.isDestroyed = function() {
  158488. return false;
  158489. };
  158490. /**
  158491. * Destroys the widget. Should be called if permanently
  158492. * removing the widget from layout.
  158493. */
  158494. HomeButton.prototype.destroy = function() {
  158495. knockout.cleanNode(this._element);
  158496. this._container.removeChild(this._element);
  158497. return destroyObject(this);
  158498. };
  158499. return HomeButton;
  158500. });
  158501. /*global define*/
  158502. define('Widgets/InfoBox/InfoBoxViewModel',[
  158503. '../../Core/defined',
  158504. '../../Core/defineProperties',
  158505. '../../Core/Event',
  158506. '../../ThirdParty/knockout'
  158507. ], function(
  158508. defined,
  158509. defineProperties,
  158510. Event,
  158511. knockout) {
  158512. 'use strict';
  158513. var cameraEnabledPath = 'M 13.84375 7.03125 C 11.412798 7.03125 9.46875 8.975298 9.46875 11.40625 L 9.46875 11.59375 L 2.53125 7.21875 L 2.53125 24.0625 L 9.46875 19.6875 C 9.4853444 22.104033 11.423165 24.0625 13.84375 24.0625 L 25.875 24.0625 C 28.305952 24.0625 30.28125 22.087202 30.28125 19.65625 L 30.28125 11.40625 C 30.28125 8.975298 28.305952 7.03125 25.875 7.03125 L 13.84375 7.03125 z';
  158514. var cameraDisabledPath = 'M 27.34375 1.65625 L 5.28125 27.9375 L 8.09375 30.3125 L 30.15625 4.03125 L 27.34375 1.65625 z M 13.84375 7.03125 C 11.412798 7.03125 9.46875 8.975298 9.46875 11.40625 L 9.46875 11.59375 L 2.53125 7.21875 L 2.53125 24.0625 L 9.46875 19.6875 C 9.4724893 20.232036 9.5676108 20.7379 9.75 21.21875 L 21.65625 7.03125 L 13.84375 7.03125 z M 28.21875 7.71875 L 14.53125 24.0625 L 25.875 24.0625 C 28.305952 24.0625 30.28125 22.087202 30.28125 19.65625 L 30.28125 11.40625 C 30.28125 9.8371439 29.456025 8.4902779 28.21875 7.71875 z';
  158515. /**
  158516. * The view model for {@link InfoBox}.
  158517. * @alias InfoBoxViewModel
  158518. * @constructor
  158519. */
  158520. function InfoBoxViewModel() {
  158521. this._cameraClicked = new Event();
  158522. this._closeClicked = new Event();
  158523. /**
  158524. * Gets or sets the maximum height of the info box in pixels. This property is observable.
  158525. * @type {Number}
  158526. */
  158527. this.maxHeight = 500;
  158528. /**
  158529. * Gets or sets whether the camera tracking icon is enabled.
  158530. * @type {Boolean}
  158531. */
  158532. this.enableCamera = false;
  158533. /**
  158534. * Gets or sets the status of current camera tracking of the selected object.
  158535. * @type {Boolean}
  158536. */
  158537. this.isCameraTracking = false;
  158538. /**
  158539. * Gets or sets the visibility of the info box.
  158540. * @type {Boolean}
  158541. */
  158542. this.showInfo = false;
  158543. /**
  158544. * Gets or sets the title text in the info box.
  158545. * @type {String}
  158546. */
  158547. this.titleText = '';
  158548. /**
  158549. * Gets or sets the description HTML for the info box.
  158550. * @type {String}
  158551. */
  158552. this.description = '';
  158553. knockout.track(this, ['showInfo', 'titleText', 'description', 'maxHeight', 'enableCamera', 'isCameraTracking']);
  158554. this._loadingIndicatorHtml = '<div class="cesium-infoBox-loadingContainer"><span class="cesium-infoBox-loading"></span></div>';
  158555. /**
  158556. * Gets the SVG path of the camera icon, which can change to be "crossed out" or not.
  158557. * @type {String}
  158558. */
  158559. this.cameraIconPath = undefined;
  158560. knockout.defineProperty(this, 'cameraIconPath', {
  158561. get : function() {
  158562. return (!this.enableCamera || this.isCameraTracking) ? cameraDisabledPath : cameraEnabledPath;
  158563. }
  158564. });
  158565. knockout.defineProperty(this, '_bodyless', {
  158566. get : function() {
  158567. return !defined(this.description) || this.description.length === 0;
  158568. }
  158569. });
  158570. }
  158571. /**
  158572. * Gets the maximum height of sections within the info box, minus an offset, in CSS-ready form.
  158573. * @param {Number} offset The offset in pixels.
  158574. * @returns {String}
  158575. */
  158576. InfoBoxViewModel.prototype.maxHeightOffset = function(offset) {
  158577. return (this.maxHeight - offset) + 'px';
  158578. };
  158579. defineProperties(InfoBoxViewModel.prototype, {
  158580. /**
  158581. * Gets an {@link Event} that is fired when the user clicks the camera icon.
  158582. * @memberof InfoBoxViewModel.prototype
  158583. * @type {Event}
  158584. */
  158585. cameraClicked : {
  158586. get : function() {
  158587. return this._cameraClicked;
  158588. }
  158589. },
  158590. /**
  158591. * Gets an {@link Event} that is fired when the user closes the info box.
  158592. * @memberof InfoBoxViewModel.prototype
  158593. * @type {Event}
  158594. */
  158595. closeClicked : {
  158596. get : function() {
  158597. return this._closeClicked;
  158598. }
  158599. }
  158600. });
  158601. return InfoBoxViewModel;
  158602. });
  158603. /*global define*/
  158604. define('Widgets/InfoBox/InfoBox',[
  158605. '../../Core/buildModuleUrl',
  158606. '../../Core/Color',
  158607. '../../Core/defined',
  158608. '../../Core/defineProperties',
  158609. '../../Core/destroyObject',
  158610. '../../Core/DeveloperError',
  158611. '../../ThirdParty/knockout',
  158612. '../getElement',
  158613. '../subscribeAndEvaluate',
  158614. './InfoBoxViewModel'
  158615. ], function(
  158616. buildModuleUrl,
  158617. Color,
  158618. defined,
  158619. defineProperties,
  158620. destroyObject,
  158621. DeveloperError,
  158622. knockout,
  158623. getElement,
  158624. subscribeAndEvaluate,
  158625. InfoBoxViewModel) {
  158626. 'use strict';
  158627. /**
  158628. * A widget for displaying information or a description.
  158629. *
  158630. * @alias InfoBox
  158631. * @constructor
  158632. *
  158633. * @param {Element|String} container The DOM element or ID that will contain the widget.
  158634. *
  158635. * @exception {DeveloperError} Element with id "container" does not exist in the document.
  158636. */
  158637. function InfoBox(container) {
  158638. if (!defined(container)) {
  158639. throw new DeveloperError('container is required.');
  158640. }
  158641. container = getElement(container);
  158642. var infoElement = document.createElement('div');
  158643. infoElement.className = 'cesium-infoBox';
  158644. infoElement.setAttribute('data-bind', '\
  158645. css: { "cesium-infoBox-visible" : showInfo, "cesium-infoBox-bodyless" : _bodyless }');
  158646. container.appendChild(infoElement);
  158647. var titleElement = document.createElement('div');
  158648. titleElement.className = 'cesium-infoBox-title';
  158649. titleElement.setAttribute('data-bind', 'text: titleText');
  158650. infoElement.appendChild(titleElement);
  158651. var cameraElement = document.createElement('button');
  158652. cameraElement.type = 'button';
  158653. cameraElement.className = 'cesium-button cesium-infoBox-camera';
  158654. cameraElement.setAttribute('data-bind', '\
  158655. attr: { title: "Focus camera on object" },\
  158656. click: function () { cameraClicked.raiseEvent(this); },\
  158657. enable: enableCamera,\
  158658. cesiumSvgPath: { path: cameraIconPath, width: 32, height: 32 }');
  158659. infoElement.appendChild(cameraElement);
  158660. var closeElement = document.createElement('button');
  158661. closeElement.type = 'button';
  158662. closeElement.className = 'cesium-infoBox-close';
  158663. closeElement.setAttribute('data-bind', '\
  158664. click: function () { closeClicked.raiseEvent(this); }');
  158665. closeElement.innerHTML = '&times;';
  158666. infoElement.appendChild(closeElement);
  158667. var frame = document.createElement('iframe');
  158668. frame.className = 'cesium-infoBox-iframe';
  158669. frame.setAttribute('sandbox', 'allow-same-origin allow-popups allow-forms'); //allow-pointer-lock allow-scripts allow-top-navigation
  158670. frame.setAttribute('data-bind', 'style : { maxHeight : maxHeightOffset(40) }');
  158671. frame.setAttribute('allowfullscreen', true);
  158672. infoElement.appendChild(frame);
  158673. var viewModel = new InfoBoxViewModel();
  158674. knockout.applyBindings(viewModel, infoElement);
  158675. this._container = container;
  158676. this._element = infoElement;
  158677. this._frame = frame;
  158678. this._viewModel = viewModel;
  158679. this._descriptionSubscription = undefined;
  158680. var that = this;
  158681. //We can't actually add anything into the frame until the load event is fired
  158682. frame.addEventListener('load', function() {
  158683. var frameDocument = frame.contentDocument;
  158684. //We inject default css into the content iframe,
  158685. //end users can remove it or add their own via the exposed frame property.
  158686. var cssLink = frameDocument.createElement("link");
  158687. cssLink.href = buildModuleUrl('Widgets/InfoBox/InfoBoxDescription.css');
  158688. cssLink.rel = "stylesheet";
  158689. cssLink.type = "text/css";
  158690. //div to use for description content.
  158691. var frameContent = frameDocument.createElement("div");
  158692. frameContent.className = 'cesium-infoBox-description';
  158693. frameDocument.head.appendChild(cssLink);
  158694. frameDocument.body.appendChild(frameContent);
  158695. //We manually subscribe to the description event rather than through a binding for two reasons.
  158696. //1. It's an easy way to ensure order of operation so that we can adjust the height.
  158697. //2. Knockout does not bind to elements inside of an iFrame, so we would have to apply a second binding
  158698. // model anyway.
  158699. that._descriptionSubscription = subscribeAndEvaluate(viewModel, 'description', function(value) {
  158700. // Set the frame to small height, force vertical scroll bar to appear, and text to wrap accordingly.
  158701. frame.style.height = '5px';
  158702. frameContent.innerHTML = value;
  158703. //If the snippet is a single element, then use its background
  158704. //color for the body of the InfoBox. This makes the padding match
  158705. //the content and produces much nicer results.
  158706. var background = null;
  158707. var firstElementChild = frameContent.firstElementChild;
  158708. if (firstElementChild !== null && frameContent.childNodes.length === 1) {
  158709. var style = window.getComputedStyle(firstElementChild);
  158710. if (style !== null) {
  158711. var backgroundColor = style['background-color'];
  158712. var color = Color.fromCssColorString(backgroundColor);
  158713. if (defined(color) && color.alpha !== 0) {
  158714. background = style['background-color'];
  158715. }
  158716. }
  158717. }
  158718. infoElement.style['background-color'] = background;
  158719. // Measure and set the new custom height, based on text wrapped above.
  158720. var height = frameContent.getBoundingClientRect().height;
  158721. frame.style.height = height + 'px';
  158722. });
  158723. });
  158724. //Chrome does not send the load event unless we explicitly set a src
  158725. frame.setAttribute('src', 'about:blank');
  158726. }
  158727. defineProperties(InfoBox.prototype, {
  158728. /**
  158729. * Gets the parent container.
  158730. * @memberof InfoBox.prototype
  158731. *
  158732. * @type {Element}
  158733. */
  158734. container : {
  158735. get : function() {
  158736. return this._container;
  158737. }
  158738. },
  158739. /**
  158740. * Gets the view model.
  158741. * @memberof InfoBox.prototype
  158742. *
  158743. * @type {InfoBoxViewModel}
  158744. */
  158745. viewModel : {
  158746. get : function() {
  158747. return this._viewModel;
  158748. }
  158749. },
  158750. /**
  158751. * Gets the iframe used to display the description.
  158752. * @memberof InfoBox.prototype
  158753. *
  158754. * @type {HTMLIFrameElement}
  158755. */
  158756. frame : {
  158757. get : function() {
  158758. return this._frame;
  158759. }
  158760. }
  158761. });
  158762. /**
  158763. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  158764. */
  158765. InfoBox.prototype.isDestroyed = function() {
  158766. return false;
  158767. };
  158768. /**
  158769. * Destroys the widget. Should be called if permanently
  158770. * removing the widget from layout.
  158771. */
  158772. InfoBox.prototype.destroy = function() {
  158773. var container = this._container;
  158774. knockout.cleanNode(this._element);
  158775. container.removeChild(this._element);
  158776. if (defined(this._descriptionSubscription)) {
  158777. this._descriptionSubscription.dispose();
  158778. }
  158779. return destroyObject(this);
  158780. };
  158781. return InfoBox;
  158782. });
  158783. /*global define*/
  158784. define('Widgets/NavigationHelpButton/NavigationHelpButtonViewModel',[
  158785. '../../Core/defineProperties',
  158786. '../../ThirdParty/knockout',
  158787. '../createCommand'
  158788. ], function(
  158789. defineProperties,
  158790. knockout,
  158791. createCommand) {
  158792. 'use strict';
  158793. /**
  158794. * The view model for {@link NavigationHelpButton}.
  158795. * @alias NavigationHelpButtonViewModel
  158796. * @constructor
  158797. */
  158798. function NavigationHelpButtonViewModel() {
  158799. /**
  158800. * Gets or sets whether the instructions are currently shown. This property is observable.
  158801. * @type {Boolean}
  158802. * @default false
  158803. */
  158804. this.showInstructions = false;
  158805. var that = this;
  158806. this._command = createCommand(function() {
  158807. that.showInstructions = !that.showInstructions;
  158808. });
  158809. this._showClick = createCommand(function() {
  158810. that._touch = false;
  158811. });
  158812. this._showTouch = createCommand(function() {
  158813. that._touch = true;
  158814. });
  158815. this._touch = false;
  158816. /**
  158817. * Gets or sets the tooltip. This property is observable.
  158818. *
  158819. * @type {String}
  158820. */
  158821. this.tooltip = 'Navigation Instructions';
  158822. knockout.track(this, ['tooltip', 'showInstructions', '_touch']);
  158823. }
  158824. defineProperties(NavigationHelpButtonViewModel.prototype, {
  158825. /**
  158826. * Gets the Command that is executed when the button is clicked.
  158827. * @memberof NavigationHelpButtonViewModel.prototype
  158828. *
  158829. * @type {Command}
  158830. */
  158831. command : {
  158832. get : function() {
  158833. return this._command;
  158834. }
  158835. },
  158836. /**
  158837. * Gets the Command that is executed when the mouse instructions should be shown.
  158838. * @memberof NavigationHelpButtonViewModel.prototype
  158839. *
  158840. * @type {Command}
  158841. */
  158842. showClick : {
  158843. get : function() {
  158844. return this._showClick;
  158845. }
  158846. },
  158847. /**
  158848. * Gets the Command that is executed when the touch instructions should be shown.
  158849. * @memberof NavigationHelpButtonViewModel.prototype
  158850. *
  158851. * @type {Command}
  158852. */
  158853. showTouch : {
  158854. get: function() {
  158855. return this._showTouch;
  158856. }
  158857. }
  158858. });
  158859. return NavigationHelpButtonViewModel;
  158860. });
  158861. /*global define*/
  158862. define('Widgets/NavigationHelpButton/NavigationHelpButton',[
  158863. '../../Core/buildModuleUrl',
  158864. '../../Core/defaultValue',
  158865. '../../Core/defined',
  158866. '../../Core/defineProperties',
  158867. '../../Core/destroyObject',
  158868. '../../Core/DeveloperError',
  158869. '../../Core/FeatureDetection',
  158870. '../../ThirdParty/knockout',
  158871. '../getElement',
  158872. './NavigationHelpButtonViewModel'
  158873. ], function(
  158874. buildModuleUrl,
  158875. defaultValue,
  158876. defined,
  158877. defineProperties,
  158878. destroyObject,
  158879. DeveloperError,
  158880. FeatureDetection,
  158881. knockout,
  158882. getElement,
  158883. NavigationHelpButtonViewModel) {
  158884. 'use strict';
  158885. /**
  158886. * <p>The NavigationHelpButton is a single button widget for displaying instructions for
  158887. * navigating the globe with the mouse.</p><p style="clear: both;"></p><br/>
  158888. *
  158889. * @alias NavigationHelpButton
  158890. * @constructor
  158891. *
  158892. * @param {Object} options Object with the following properties:
  158893. * @param {Element|String} options.container The DOM element or ID that will contain the widget.
  158894. * @param {Boolean} [options.instructionsInitiallyVisible=false] True if the navigation instructions should initially be visible; otherwise, false.
  158895. *
  158896. * @exception {DeveloperError} Element with id "container" does not exist in the document.
  158897. *
  158898. * @example
  158899. * // In HTML head, include a link to the NavigationHelpButton.css stylesheet,
  158900. * // and in the body, include: <div id="navigationHelpButtonContainer"></div>
  158901. *
  158902. * var navigationHelpButton = new Cesium.NavigationHelpButton({
  158903. * container : 'navigationHelpButtonContainer'
  158904. * });
  158905. */
  158906. function NavigationHelpButton(options) {
  158907. if (!defined(options) || !defined(options.container)) {
  158908. throw new DeveloperError('options.container is required.');
  158909. }
  158910. var container = getElement(options.container);
  158911. var viewModel = new NavigationHelpButtonViewModel();
  158912. var showInsructionsDefault = defaultValue(options.instructionsInitiallyVisible, false);
  158913. viewModel.showInstructions = showInsructionsDefault;
  158914. viewModel._svgPath = 'M16,1.466C7.973,1.466,1.466,7.973,1.466,16c0,8.027,6.507,14.534,14.534,14.534c8.027,0,14.534-6.507,14.534-14.534C30.534,7.973,24.027,1.466,16,1.466z M17.328,24.371h-2.707v-2.596h2.707V24.371zM17.328,19.003v0.858h-2.707v-1.057c0-3.19,3.63-3.696,3.63-5.963c0-1.034-0.924-1.826-2.134-1.826c-1.254,0-2.354,0.924-2.354,0.924l-1.541-1.915c0,0,1.519-1.584,4.137-1.584c2.487,0,4.796,1.54,4.796,4.136C21.156,16.208,17.328,16.627,17.328,19.003z';
  158915. var wrapper = document.createElement('span');
  158916. wrapper.className = 'cesium-navigationHelpButton-wrapper';
  158917. container.appendChild(wrapper);
  158918. var button = document.createElement('button');
  158919. button.type = 'button';
  158920. button.className = 'cesium-button cesium-toolbar-button cesium-navigation-help-button';
  158921. button.setAttribute('data-bind', '\
  158922. attr: { title: tooltip },\
  158923. click: command,\
  158924. cesiumSvgPath: { path: _svgPath, width: 32, height: 32 }');
  158925. wrapper.appendChild(button);
  158926. var instructionContainer = document.createElement('div');
  158927. instructionContainer.className = 'cesium-navigation-help';
  158928. instructionContainer.setAttribute('data-bind', 'css: { "cesium-navigation-help-visible" : showInstructions}');
  158929. wrapper.appendChild(instructionContainer);
  158930. var mouseButton = document.createElement('button');
  158931. mouseButton.type = 'button';
  158932. mouseButton.className = 'cesium-navigation-button cesium-navigation-button-left';
  158933. mouseButton.setAttribute('data-bind', 'click: showClick, css: {"cesium-navigation-button-selected": !_touch, "cesium-navigation-button-unselected": _touch}');
  158934. var mouseIcon = document.createElement('img');
  158935. mouseIcon.src = buildModuleUrl('Widgets/Images/NavigationHelp/Mouse.svg');
  158936. mouseIcon.className = 'cesium-navigation-button-icon';
  158937. mouseIcon.style.width = '25px';
  158938. mouseIcon.style.height = '25px';
  158939. mouseButton.appendChild(mouseIcon);
  158940. mouseButton.appendChild(document.createTextNode('Mouse'));
  158941. var touchButton = document.createElement('button');
  158942. touchButton.type = 'button';
  158943. touchButton.className = 'cesium-navigation-button cesium-navigation-button-right';
  158944. touchButton.setAttribute('data-bind', 'click: showTouch, css: {"cesium-navigation-button-selected": _touch, "cesium-navigation-button-unselected": !_touch}');
  158945. var touchIcon = document.createElement('img');
  158946. touchIcon.src = buildModuleUrl('Widgets/Images/NavigationHelp/Touch.svg');
  158947. touchIcon.className = 'cesium-navigation-button-icon';
  158948. touchIcon.style.width = '25px';
  158949. touchIcon.style.height = '25px';
  158950. touchButton.appendChild(touchIcon);
  158951. touchButton.appendChild(document.createTextNode('Touch'));
  158952. instructionContainer.appendChild(mouseButton);
  158953. instructionContainer.appendChild(touchButton);
  158954. var clickInstructions = document.createElement('div');
  158955. clickInstructions.className = 'cesium-click-navigation-help cesium-navigation-help-instructions';
  158956. clickInstructions.setAttribute('data-bind', 'css: { "cesium-click-navigation-help-visible" : !_touch}');
  158957. clickInstructions.innerHTML = '\
  158958. <table>\
  158959. <tr>\
  158960. <td><img src="' + buildModuleUrl('Widgets/Images/NavigationHelp/MouseLeft.svg') + '" width="48" height="48" /></td>\
  158961. <td>\
  158962. <div class="cesium-navigation-help-pan">Pan view</div>\
  158963. <div class="cesium-navigation-help-details">Left click + drag</div>\
  158964. </td>\
  158965. </tr>\
  158966. <tr>\
  158967. <td><img src="' + buildModuleUrl('Widgets/Images/NavigationHelp/MouseRight.svg') + '" width="48" height="48" /></td>\
  158968. <td>\
  158969. <div class="cesium-navigation-help-zoom">Zoom view</div>\
  158970. <div class="cesium-navigation-help-details">Right click + drag, or</div>\
  158971. <div class="cesium-navigation-help-details">Mouse wheel scroll</div>\
  158972. </td>\
  158973. </tr>\
  158974. <tr>\
  158975. <td><img src="' + buildModuleUrl('Widgets/Images/NavigationHelp/MouseMiddle.svg') + '" width="48" height="48" /></td>\
  158976. <td>\
  158977. <div class="cesium-navigation-help-rotate">Rotate view</div>\
  158978. <div class="cesium-navigation-help-details">Middle click + drag, or</div>\
  158979. <div class="cesium-navigation-help-details">CTRL + Left/Right click + drag</div>\
  158980. </td>\
  158981. </tr>\
  158982. </table>';
  158983. instructionContainer.appendChild(clickInstructions);
  158984. var touchInstructions = document.createElement('div');
  158985. touchInstructions.className = 'cesium-touch-navigation-help cesium-navigation-help-instructions';
  158986. touchInstructions.setAttribute('data-bind', 'css: { "cesium-touch-navigation-help-visible" : _touch}');
  158987. touchInstructions.innerHTML = '\
  158988. <table>\
  158989. <tr>\
  158990. <td><img src="' + buildModuleUrl('Widgets/Images/NavigationHelp/TouchDrag.svg') + '" width="70" height="48" /></td>\
  158991. <td>\
  158992. <div class="cesium-navigation-help-pan">Pan view</div>\
  158993. <div class="cesium-navigation-help-details">One finger drag</div>\
  158994. </td>\
  158995. </tr>\
  158996. <tr>\
  158997. <td><img src="' + buildModuleUrl('Widgets/Images/NavigationHelp/TouchZoom.svg') + '" width="70" height="48" /></td>\
  158998. <td>\
  158999. <div class="cesium-navigation-help-zoom">Zoom view</div>\
  159000. <div class="cesium-navigation-help-details">Two finger pinch</div>\
  159001. </td>\
  159002. </tr>\
  159003. <tr>\
  159004. <td><img src="' + buildModuleUrl('Widgets/Images/NavigationHelp/TouchTilt.svg') + '" width="70" height="48" /></td>\
  159005. <td>\
  159006. <div class="cesium-navigation-help-rotate">Tilt view</div>\
  159007. <div class="cesium-navigation-help-details">Two finger drag, same direction</div>\
  159008. </td>\
  159009. </tr>\
  159010. <tr>\
  159011. <td><img src="' + buildModuleUrl('Widgets/Images/NavigationHelp/TouchRotate.svg') + '" width="70" height="48" /></td>\
  159012. <td>\
  159013. <div class="cesium-navigation-help-tilt">Rotate view</div>\
  159014. <div class="cesium-navigation-help-details">Two finger drag, opposite direction</div>\
  159015. </td>\
  159016. </tr>\
  159017. </table>';
  159018. instructionContainer.appendChild(touchInstructions);
  159019. knockout.applyBindings(viewModel, wrapper);
  159020. this._container = container;
  159021. this._viewModel = viewModel;
  159022. this._wrapper = wrapper;
  159023. this._closeInstructions = function(e) {
  159024. if (!wrapper.contains(e.target)) {
  159025. viewModel.showInstructions = false;
  159026. }
  159027. };
  159028. if (FeatureDetection.supportsPointerEvents()) {
  159029. document.addEventListener('pointerdown', this._closeInstructions, true);
  159030. } else {
  159031. document.addEventListener('mousedown', this._closeInstructions, true);
  159032. document.addEventListener('touchstart', this._closeInstructions, true);
  159033. }
  159034. }
  159035. defineProperties(NavigationHelpButton.prototype, {
  159036. /**
  159037. * Gets the parent container.
  159038. * @memberof NavigationHelpButton.prototype
  159039. *
  159040. * @type {Element}
  159041. */
  159042. container : {
  159043. get : function() {
  159044. return this._container;
  159045. }
  159046. },
  159047. /**
  159048. * Gets the view model.
  159049. * @memberof NavigationHelpButton.prototype
  159050. *
  159051. * @type {NavigationHelpButtonViewModel}
  159052. */
  159053. viewModel : {
  159054. get : function() {
  159055. return this._viewModel;
  159056. }
  159057. }
  159058. });
  159059. /**
  159060. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  159061. */
  159062. NavigationHelpButton.prototype.isDestroyed = function() {
  159063. return false;
  159064. };
  159065. /**
  159066. * Destroys the widget. Should be called if permanently
  159067. * removing the widget from layout.
  159068. */
  159069. NavigationHelpButton.prototype.destroy = function() {
  159070. if (FeatureDetection.supportsPointerEvents()) {
  159071. document.removeEventListener('pointerdown', this._closeInstructions, true);
  159072. } else {
  159073. document.removeEventListener('mousedown', this._closeInstructions, true);
  159074. document.removeEventListener('touchstart', this._closeInstructions, true);
  159075. }
  159076. knockout.cleanNode(this._wrapper);
  159077. this._container.removeChild(this._wrapper);
  159078. return destroyObject(this);
  159079. };
  159080. return NavigationHelpButton;
  159081. });
  159082. /*global define*/
  159083. define('Widgets/PerformanceWatchdog/PerformanceWatchdogViewModel',[
  159084. '../../Core/defaultValue',
  159085. '../../Core/defined',
  159086. '../../Core/defineProperties',
  159087. '../../Core/destroyObject',
  159088. '../../Core/DeveloperError',
  159089. '../../Scene/FrameRateMonitor',
  159090. '../../ThirdParty/knockout',
  159091. '../createCommand'
  159092. ], function(
  159093. defaultValue,
  159094. defined,
  159095. defineProperties,
  159096. destroyObject,
  159097. DeveloperError,
  159098. FrameRateMonitor,
  159099. knockout,
  159100. createCommand) {
  159101. 'use strict';
  159102. /**
  159103. * The view model for {@link PerformanceWatchdog}.
  159104. *
  159105. * @alias PerformanceWatchdogViewModel
  159106. * @constructor
  159107. *
  159108. * @param {Object} [options] Object with the following properties:
  159109. * @param {Scene} options.scene The Scene instance for which to monitor performance.
  159110. * @param {String} [options.lowFrameRateMessage='This application appears to be performing poorly on your system. Please try using a different web browser or updating your video drivers.'] The
  159111. * message to display when a low frame rate is detected. The message is interpeted as HTML, so make sure
  159112. * it comes from a trusted source so that your application is not vulnerable to cross-site scripting attacks.
  159113. */
  159114. function PerformanceWatchdogViewModel(options) {
  159115. if (!defined(options) || !defined(options.scene)) {
  159116. throw new DeveloperError('options.scene is required.');
  159117. }
  159118. this._scene = options.scene;
  159119. /**
  159120. * Gets or sets the message to display when a low frame rate is detected. This string will be interpreted as HTML.
  159121. * @type {String}
  159122. */
  159123. this.lowFrameRateMessage = defaultValue(options.lowFrameRateMessage, 'This application appears to be performing poorly on your system. Please try using a different web browser or updating your video drivers.');
  159124. /**
  159125. * Gets or sets a value indicating whether the low frame rate message has previously been dismissed by the user. If it has
  159126. * been dismissed, the message will not be redisplayed, no matter the frame rate.
  159127. * @type {Boolean}
  159128. */
  159129. this.lowFrameRateMessageDismissed = false;
  159130. /**
  159131. * Gets or sets a value indicating whether the low frame rate message is currently being displayed.
  159132. * @type {Boolean}
  159133. */
  159134. this.showingLowFrameRateMessage = false;
  159135. knockout.track(this, ['lowFrameRateMessage', 'lowFrameRateMessageDismissed', 'showingLowFrameRateMessage']);
  159136. var that = this;
  159137. this._dismissMessage = createCommand(function() {
  159138. that.showingLowFrameRateMessage = false;
  159139. that.lowFrameRateMessageDismissed = true;
  159140. });
  159141. var monitor = FrameRateMonitor.fromScene(options.scene);
  159142. this._unsubscribeLowFrameRate = monitor.lowFrameRate.addEventListener(function() {
  159143. if (!that.lowFrameRateMessageDismissed) {
  159144. that.showingLowFrameRateMessage = true;
  159145. }
  159146. });
  159147. this._unsubscribeNominalFrameRate = monitor.nominalFrameRate.addEventListener(function() {
  159148. that.showingLowFrameRateMessage = false;
  159149. });
  159150. }
  159151. defineProperties(PerformanceWatchdogViewModel.prototype, {
  159152. /**
  159153. * Gets the {@link Scene} instance for which to monitor performance.
  159154. * @memberof PerformanceWatchdogViewModel.prototype
  159155. * @type {Scene}
  159156. */
  159157. scene : {
  159158. get : function() {
  159159. return this._scene;
  159160. }
  159161. },
  159162. /**
  159163. * Gets a command that dismisses the low frame rate message. Once it is dismissed, the message
  159164. * will not be redisplayed.
  159165. * @memberof PerformanceWatchdogViewModel.prototype
  159166. * @type {Command}
  159167. */
  159168. dismissMessage : {
  159169. get : function() {
  159170. return this._dismissMessage;
  159171. }
  159172. }
  159173. });
  159174. PerformanceWatchdogViewModel.prototype.destroy = function() {
  159175. this._unsubscribeLowFrameRate();
  159176. this._unsubscribeNominalFrameRate();
  159177. return destroyObject(this);
  159178. };
  159179. return PerformanceWatchdogViewModel;
  159180. });
  159181. /*global define*/
  159182. define('Widgets/PerformanceWatchdog/PerformanceWatchdog',[
  159183. '../../Core/defined',
  159184. '../../Core/defineProperties',
  159185. '../../Core/destroyObject',
  159186. '../../Core/DeveloperError',
  159187. '../../ThirdParty/knockout',
  159188. '../getElement',
  159189. './PerformanceWatchdogViewModel'
  159190. ], function(
  159191. defined,
  159192. defineProperties,
  159193. destroyObject,
  159194. DeveloperError,
  159195. knockout,
  159196. getElement,
  159197. PerformanceWatchdogViewModel) {
  159198. 'use strict';
  159199. /**
  159200. * Monitors performance of the application and displays a message if poor performance is detected.
  159201. *
  159202. * @alias PerformanceWatchdog
  159203. * @constructor
  159204. *
  159205. * @param {Object} [options] Object with the following properties:
  159206. * @param {Element|String} options.container The DOM element or ID that will contain the widget.
  159207. * @param {Scene} options.scene The {@link Scene} for which to monitor performance.
  159208. * @param {String} [options.lowFrameRateMessage='This application appears to be performing poorly on your system. Please try using a different web browser or updating your video drivers.'] The
  159209. * message to display when a low frame rate is detected. The message is interpeted as HTML, so make sure
  159210. * it comes from a trusted source so that your application is not vulnerable to cross-site scripting attacks.
  159211. */
  159212. function PerformanceWatchdog(options) {
  159213. if (!defined(options) || !defined(options.container)) {
  159214. throw new DeveloperError('options.container is required.');
  159215. }
  159216. if (!defined(options.scene)) {
  159217. throw new DeveloperError('options.scene is required.');
  159218. }
  159219. var container = getElement(options.container);
  159220. var viewModel = new PerformanceWatchdogViewModel(options);
  159221. var element = document.createElement('div');
  159222. element.className = 'cesium-performance-watchdog-message-area';
  159223. element.setAttribute('data-bind', 'visible: showingLowFrameRateMessage');
  159224. var dismissButton = document.createElement('button');
  159225. dismissButton.setAttribute('type', 'button');
  159226. dismissButton.className = 'cesium-performance-watchdog-message-dismiss';
  159227. dismissButton.innerHTML = '&times;';
  159228. dismissButton.setAttribute('data-bind', 'click: dismissMessage');
  159229. element.appendChild(dismissButton);
  159230. var message = document.createElement('div');
  159231. message.className = 'cesium-performance-watchdog-message';
  159232. message.setAttribute('data-bind', 'html: lowFrameRateMessage');
  159233. element.appendChild(message);
  159234. container.appendChild(element);
  159235. knockout.applyBindings(viewModel, element);
  159236. this._container = container;
  159237. this._viewModel = viewModel;
  159238. this._element = element;
  159239. }
  159240. defineProperties(PerformanceWatchdog.prototype, {
  159241. /**
  159242. * Gets the parent container.
  159243. * @memberof PerformanceWatchdog.prototype
  159244. *
  159245. * @type {Element}
  159246. */
  159247. container : {
  159248. get : function() {
  159249. return this._container;
  159250. }
  159251. },
  159252. /**
  159253. * Gets the view model.
  159254. * @memberof PerformanceWatchdog.prototype
  159255. *
  159256. * @type {PerformanceWatchdogViewModel}
  159257. */
  159258. viewModel : {
  159259. get : function() {
  159260. return this._viewModel;
  159261. }
  159262. }
  159263. });
  159264. /**
  159265. * @memberof PerformanceWatchdog
  159266. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  159267. */
  159268. PerformanceWatchdog.prototype.isDestroyed = function() {
  159269. return false;
  159270. };
  159271. /**
  159272. * Destroys the widget. Should be called if permanently
  159273. * removing the widget from layout.
  159274. * @memberof PerformanceWatchdog
  159275. */
  159276. PerformanceWatchdog.prototype.destroy = function() {
  159277. this._viewModel.destroy();
  159278. knockout.cleanNode(this._element);
  159279. this._container.removeChild(this._element);
  159280. return destroyObject(this);
  159281. };
  159282. return PerformanceWatchdog;
  159283. });
  159284. /*global define*/
  159285. define('Widgets/SceneModePicker/SceneModePickerViewModel',[
  159286. '../../Core/defaultValue',
  159287. '../../Core/defined',
  159288. '../../Core/defineProperties',
  159289. '../../Core/destroyObject',
  159290. '../../Core/DeveloperError',
  159291. '../../Core/EventHelper',
  159292. '../../Scene/SceneMode',
  159293. '../../ThirdParty/knockout',
  159294. '../createCommand'
  159295. ], function(
  159296. defaultValue,
  159297. defined,
  159298. defineProperties,
  159299. destroyObject,
  159300. DeveloperError,
  159301. EventHelper,
  159302. SceneMode,
  159303. knockout,
  159304. createCommand) {
  159305. 'use strict';
  159306. /**
  159307. * The view model for {@link SceneModePicker}.
  159308. * @alias SceneModePickerViewModel
  159309. * @constructor
  159310. *
  159311. * @param {Scene} scene The Scene to morph
  159312. * @param {Number} [duration=2.0] The duration of scene morph animations, in seconds
  159313. */
  159314. function SceneModePickerViewModel(scene, duration) {
  159315. if (!defined(scene)) {
  159316. throw new DeveloperError('scene is required.');
  159317. }
  159318. this._scene = scene;
  159319. var that = this;
  159320. var morphStart = function(transitioner, oldMode, newMode, isMorphing) {
  159321. that.sceneMode = newMode;
  159322. that.dropDownVisible = false;
  159323. };
  159324. this._eventHelper = new EventHelper();
  159325. this._eventHelper.add(scene.morphStart, morphStart);
  159326. this._duration = defaultValue(duration, 2.0);
  159327. /**
  159328. * Gets or sets the current SceneMode. This property is observable.
  159329. * @type {SceneMode}
  159330. */
  159331. this.sceneMode = scene.mode;
  159332. /**
  159333. * Gets or sets whether the button drop-down is currently visible. This property is observable.
  159334. * @type {Boolean}
  159335. * @default false
  159336. */
  159337. this.dropDownVisible = false;
  159338. /**
  159339. * Gets or sets the 2D tooltip. This property is observable.
  159340. * @type {String}
  159341. * @default '2D'
  159342. */
  159343. this.tooltip2D = '2D';
  159344. /**
  159345. * Gets or sets the 3D tooltip. This property is observable.
  159346. * @type {String}
  159347. * @default '3D'
  159348. */
  159349. this.tooltip3D = '3D';
  159350. /**
  159351. * Gets or sets the Columbus View tooltip. This property is observable.
  159352. * @type {String}
  159353. * @default 'Columbus View'
  159354. */
  159355. this.tooltipColumbusView = 'Columbus View';
  159356. knockout.track(this, ['sceneMode', 'dropDownVisible', 'tooltip2D', 'tooltip3D', 'tooltipColumbusView']);
  159357. /**
  159358. * Gets the currently active tooltip. This property is observable.
  159359. * @type {String}
  159360. */
  159361. this.selectedTooltip = undefined;
  159362. knockout.defineProperty(this, 'selectedTooltip', function() {
  159363. var mode = that.sceneMode;
  159364. if (mode === SceneMode.SCENE2D) {
  159365. return that.tooltip2D;
  159366. }
  159367. if (mode === SceneMode.SCENE3D) {
  159368. return that.tooltip3D;
  159369. }
  159370. return that.tooltipColumbusView;
  159371. });
  159372. this._toggleDropDown = createCommand(function() {
  159373. that.dropDownVisible = !that.dropDownVisible;
  159374. });
  159375. this._morphTo2D = createCommand(function() {
  159376. scene.morphTo2D(that._duration);
  159377. });
  159378. this._morphTo3D = createCommand(function() {
  159379. scene.morphTo3D(that._duration);
  159380. });
  159381. this._morphToColumbusView = createCommand(function() {
  159382. scene.morphToColumbusView(that._duration);
  159383. });
  159384. //Used by knockout
  159385. this._sceneMode = SceneMode;
  159386. }
  159387. defineProperties(SceneModePickerViewModel.prototype, {
  159388. /**
  159389. * Gets the scene
  159390. * @memberof SceneModePickerViewModel.prototype
  159391. * @type {Scene}
  159392. */
  159393. scene : {
  159394. get : function() {
  159395. return this._scene;
  159396. }
  159397. },
  159398. /**
  159399. * Gets or sets the the duration of scene mode transition animations in seconds.
  159400. * A value of zero causes the scene to instantly change modes.
  159401. * @memberof SceneModePickerViewModel.prototype
  159402. * @type {Number}
  159403. */
  159404. duration : {
  159405. get : function() {
  159406. return this._duration;
  159407. },
  159408. set : function(value) {
  159409. if (value < 0.0) {
  159410. throw new DeveloperError('duration value must be positive.');
  159411. }
  159412. this._duration = value;
  159413. }
  159414. },
  159415. /**
  159416. * Gets the command to toggle the drop down box.
  159417. * @memberof SceneModePickerViewModel.prototype
  159418. *
  159419. * @type {Command}
  159420. */
  159421. toggleDropDown : {
  159422. get : function() {
  159423. return this._toggleDropDown;
  159424. }
  159425. },
  159426. /**
  159427. * Gets the command to morph to 2D.
  159428. * @memberof SceneModePickerViewModel.prototype
  159429. *
  159430. * @type {Command}
  159431. */
  159432. morphTo2D : {
  159433. get : function() {
  159434. return this._morphTo2D;
  159435. }
  159436. },
  159437. /**
  159438. * Gets the command to morph to 3D.
  159439. * @memberof SceneModePickerViewModel.prototype
  159440. *
  159441. * @type {Command}
  159442. */
  159443. morphTo3D : {
  159444. get : function() {
  159445. return this._morphTo3D;
  159446. }
  159447. },
  159448. /**
  159449. * Gets the command to morph to Columbus View.
  159450. * @memberof SceneModePickerViewModel.prototype
  159451. *
  159452. * @type {Command}
  159453. */
  159454. morphToColumbusView : {
  159455. get : function() {
  159456. return this._morphToColumbusView;
  159457. }
  159458. }
  159459. });
  159460. /**
  159461. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  159462. */
  159463. SceneModePickerViewModel.prototype.isDestroyed = function() {
  159464. return false;
  159465. };
  159466. /**
  159467. * Destroys the view model.
  159468. */
  159469. SceneModePickerViewModel.prototype.destroy = function() {
  159470. this._eventHelper.removeAll();
  159471. destroyObject(this);
  159472. };
  159473. return SceneModePickerViewModel;
  159474. });
  159475. /*global define*/
  159476. define('Widgets/SceneModePicker/SceneModePicker',[
  159477. '../../Core/defined',
  159478. '../../Core/defineProperties',
  159479. '../../Core/destroyObject',
  159480. '../../Core/DeveloperError',
  159481. '../../Core/FeatureDetection',
  159482. '../../ThirdParty/knockout',
  159483. '../getElement',
  159484. './SceneModePickerViewModel'
  159485. ], function(
  159486. defined,
  159487. defineProperties,
  159488. destroyObject,
  159489. DeveloperError,
  159490. FeatureDetection,
  159491. knockout,
  159492. getElement,
  159493. SceneModePickerViewModel) {
  159494. 'use strict';
  159495. var globePath = 'm 32.401392,4.9330437 c -7.087603,0 -14.096095,2.884602 -19.10793,7.8946843 -5.0118352,5.010083 -7.9296167,11.987468 -7.9296167,19.072999 0,7.085531 2.9177815,14.097848 7.9296167,19.107931 4.837653,4.835961 11.541408,7.631372 18.374354,7.82482 0.05712,0.01231 0.454119,0.139729 0.454119,0.139729 l 0.03493,-0.104797 c 0.08246,7.84e-4 0.162033,0.03493 0.244525,0.03493 0.08304,0 0.161515,-0.03414 0.244526,-0.03493 l 0.03493,0.104797 c 0,0 0.309474,-0.129487 0.349323,-0.139729 6.867765,-0.168094 13.582903,-2.965206 18.444218,-7.82482 2.558195,-2.5573 4.551081,-5.638134 5.903547,-8.977584 1.297191,-3.202966 2.02607,-6.661489 2.02607,-10.130347 0,-6.237309 -2.366261,-12.31219 -6.322734,-17.116794 -0.0034,-0.02316 0.0049,-0.04488 0,-0.06986 -0.01733,-0.08745 -0.104529,-0.278855 -0.104797,-0.279458 -5.31e-4,-0.0012 -0.522988,-0.628147 -0.523984,-0.62878 \
  159496. -3.47e-4,-2.2e-4 -0.133444,-0.03532 -0.244525,-0.06987 C 51.944299,13.447603 51.751076,13.104317 51.474391,12.827728 46.462556,7.8176457 39.488996,4.9330437 32.401392,4.9330437 z m -2.130866,3.5281554 0.104797,9.6762289 c -4.111695,-0.08361 -7.109829,-0.423664 -9.257041,-0.943171 1.198093,-2.269271 2.524531,-4.124404 3.91241,-5.414496 2.167498,-2.0147811 3.950145,-2.8540169 5.239834,-3.3185619 z m 2.794579,0 c 1.280302,0.4754953 3.022186,1.3285948 5.065173,3.2486979 1.424667,1.338973 2.788862,3.303645 3.982275,5.728886 -2.29082,0.403367 -5.381258,0.621049 -8.942651,0.698645 L 33.065105,8.4611991 z m 5.728886,0.2445256 c 4.004072,1.1230822 7.793098,3.1481363 10.724195,6.0782083 0.03468,0.03466 0.07033,0.06991 0.104797,0.104797 -0.45375,0.313891 -0.923054,0.663002 -1.956205,1.082899 -0.647388,0.263114 -1.906242,0.477396 -2.829511,0.733577 -1.382296,-2.988132 \
  159497. -3.027146,-5.368585 -4.785716,-7.0213781 -0.422866,-0.397432 -0.835818,-0.6453247 -1.25756,-0.9781032 z m -15.33525,0.7685092 c -0.106753,0.09503 -0.207753,0.145402 -0.31439,0.244526 -1.684973,1.5662541 -3.298068,3.8232211 -4.680919,6.5672591 -0.343797,-0.14942 -1.035052,-0.273198 -1.292493,-0.419186 -0.956528,-0.542427 -1.362964,-1.022024 -1.537018,-1.292493 -0.0241,-0.03745 -0.01868,-0.0401 -0.03493,-0.06986 2.250095,-2.163342 4.948824,-3.869984 7.859752,-5.0302421 z m -9.641296,7.0912431 c 0.464973,0.571618 0.937729,1.169056 1.956205,1.746612 0.349907,0.198425 1.107143,0.335404 1.537018,0.523983 -1.20166,3.172984 -1.998037,7.051901 -2.165798,11.772162 C 14.256557,30.361384 12.934823,30.161483 12.280427,29.90959 10.644437,29.279855 9.6888882,28.674891 9.1714586,28.267775 8.6540289,27.860658 8.6474751,27.778724 8.6474751,27.778724 l -0.069864,0.03493 C 9.3100294,23.691285 \
  159498. 11.163248,19.798527 13.817445,16.565477 z m 37.552149,0.523984 c 2.548924,3.289983 4.265057,7.202594 4.890513,11.318043 -0.650428,0.410896 -1.756876,1.001936 -3.563088,1.606882 -1.171552,0.392383 -3.163859,0.759153 -4.960377,1.117832 -0.04367,-4.752703 -0.784809,-8.591423 -1.88634,-11.807094 0.917574,-0.263678 2.170552,-0.486495 2.864443,-0.76851 1.274693,-0.518066 2.003942,-1.001558 2.654849,-1.467153 z m -31.439008,2.619917 c 2.487341,0.672766 5.775813,1.137775 10.479669,1.222628 l 0.104797,10.689263 0,0.03493 0,0.733577 c -5.435005,-0.09059 -9.512219,-0.519044 -12.610536,-1.117831 0.106127,-4.776683 0.879334,-8.55791 2.02607,-11.562569 z m 23.264866,0.31439 c 1.073459,3.067541 1.833795,6.821314 1.816476,11.702298 -3.054474,0.423245 -7.062018,0.648559 -11.702298,0.698644 l 0,-0.838373 -0.104796,-10.654331 c 4.082416,-0.0864 7.404468,-0.403886 9.990618,-0.908238 z \
  159499. M 8.2632205,30.922625 c 0.7558676,0.510548 1.5529563,1.013339 3.0041715,1.57195 0.937518,0.360875 2.612202,0.647642 3.91241,0.978102 0.112814,3.85566 0.703989,7.107756 1.606883,9.920754 -1.147172,-0.324262 -2.644553,-0.640648 -3.423359,-0.978102 -1.516688,-0.657177 -2.386627,-1.287332 -2.864443,-1.71168 -0.477816,-0.424347 -0.489051,-0.489051 -0.489051,-0.489051 L 9.8002387,40.319395 C 8.791691,37.621767 8.1584238,34.769583 8.1584238,31.900727 c 0,-0.330153 0.090589,-0.648169 0.1047967,-0.978102 z m 48.2763445,0.419186 c 0.0047,0.188973 0.06986,0.36991 0.06986,0.558916 0,2.938869 -0.620228,5.873558 -1.676747,8.628261 -0.07435,0.07583 -0.06552,0.07411 -0.454119,0.349323 -0.606965,0.429857 -1.631665,1.042044 -3.318562,1.676747 -1.208528,0.454713 -3.204964,0.850894 -5.135038,1.25756 0.84593,-2.765726 1.41808,-6.005357 1.606883,-9.815957 2.232369,-0.413371 4.483758,-0.840201 \
  159500. 5.938479,-1.327425 1.410632,-0.472457 2.153108,-0.89469 2.96924,-1.327425 z m -38.530252,2.864443 c 3.208141,0.56697 7.372279,0.898588 12.575603,0.978103 l 0.174662,9.885821 c -4.392517,-0.06139 -8.106722,-0.320566 -10.863925,-0.803441 -1.051954,-2.664695 -1.692909,-6.043794 -1.88634,-10.060483 z m 26.793022,0.31439 c -0.246298,3.923551 -0.877762,7.263679 -1.816476,9.885822 -2.561957,0.361954 -5.766249,0.560708 -9.431703,0.62878 l -0.174661,-9.815957 c 4.491734,-0.04969 8.334769,-0.293032 11.42284,-0.698645 z M 12.035901,44.860585 c 0.09977,0.04523 0.105535,0.09465 0.209594,0.139729 1.337656,0.579602 3.441099,1.058072 5.589157,1.537018 1.545042,3.399208 3.548524,5.969402 5.589157,7.789888 -3.034411,-1.215537 -5.871615,-3.007978 -8.174142,-5.309699 -1.245911,-1.245475 -2.271794,-2.662961 -3.213766,-4.156936 z m 40.69605,0 c -0.941972,1.493975 -1.967855,2.911461 \
  159501. -3.213765,4.156936 -2.74253,2.741571 -6.244106,4.696717 -9.955686,5.868615 0.261347,-0.241079 0.507495,-0.394491 0.768509,-0.663713 1.674841,-1.727516 3.320792,-4.181056 4.645987,-7.265904 2.962447,-0.503021 5.408965,-1.122293 7.161107,-1.781544 0.284034,-0.106865 0.337297,-0.207323 0.593848,-0.31439 z m -31.404076,2.305527 c 2.645807,0.376448 5.701178,0.649995 9.466635,0.698645 l 0.139729,7.789888 c -1.38739,-0.480844 -3.316218,-1.29837 -5.659022,-3.388427 -1.388822,-1.238993 -2.743668,-3.0113 -3.947342,-5.100106 z m 20.365491,0.104797 c -1.04872,2.041937 -2.174337,3.779068 -3.353494,4.995309 -1.853177,1.911459 -3.425515,2.82679 -4.611055,3.353494 l -0.139729,-7.789887 c 3.13091,-0.05714 5.728238,-0.278725 8.104278,-0.558916 z';
  159502. var flatMapPath = 'm 2.9825053,17.550598 0,1.368113 0,26.267766 0,1.368113 1.36811,0 54.9981397,0 1.36811,0 0,-1.368113 0,-26.267766 0,-1.368113 -1.36811,0 -54.9981397,0 -1.36811,0 z m 2.73623,2.736226 10.3292497,0 0,10.466063 -10.3292497,0 0,-10.466063 z m 13.0654697,0 11.69737,0 0,10.466063 -11.69737,0 0,-10.466063 z m 14.43359,0 11.69737,0 0,10.466063 -11.69737,0 0,-10.466063 z m 14.43359,0 10.32926,0 0,10.466063 -10.32926,0 0,-10.466063 z m -41.9326497,13.202288 10.3292497,0 0,10.329252 -10.3292497,0 0,-10.329252 z m 13.0654697,0 11.69737,0 0,10.329252 -11.69737,0 0,-10.329252 z m 14.43359,0 11.69737,0 0,10.329252 -11.69737,0 0,-10.329252 z m 14.43359,0 10.32926,0 0,10.329252 -10.32926,0 0,-10.329252 z';
  159503. var columbusViewPath = 'm 14.723969,17.675598 -0.340489,0.817175 -11.1680536,26.183638 -0.817175,1.872692 2.076986,0 54.7506996,0 2.07698,0 -0.81717,-1.872692 -11.16805,-26.183638 -0.34049,-0.817175 -0.91933,0 -32.414586,0 -0.919322,0 z m 1.838643,2.723916 6.196908,0 -2.928209,10.418977 -7.729111,0 4.460412,-10.418977 z m 9.02297,0 4.903049,0 0,10.418977 -7.831258,0 2.928209,-10.418977 z m 7.626964,0 5.584031,0 2.62176,10.418977 -8.205791,0 0,-10.418977 z m 8.410081,0 5.51593,0 4.46042,10.418977 -7.38863,0 -2.58772,-10.418977 z m -30.678091,13.142892 8.103649,0 -2.89416,10.282782 -9.6018026,0 4.3923136,-10.282782 z m 10.929711,0 8.614384,0 0,10.282782 -11.508544,0 2.89416,-10.282782 z m 11.338299,0 8.852721,0 2.58772,10.282782 -11.440441,0 0,-10.282782 z m 11.678781,0 7.86531,0 4.39231,10.282782 -9.6699,0 -2.58772,-10.282782 z';
  159504. /**
  159505. * <img src="images/sceneModePicker.png" style="float: left; margin-right: 10px;" width="44" height="116" />
  159506. * <p>The SceneModePicker is a single button widget for switching between scene modes;
  159507. * shown to the left in its expanded state. Programatic switching of scene modes will
  159508. * be automatically reflected in the widget as long as the specified Scene
  159509. * is used to perform the change.</p><p style="clear: both;"></p><br/>
  159510. *
  159511. * @alias SceneModePicker
  159512. * @constructor
  159513. *
  159514. * @param {Element|String} container The DOM element or ID that will contain the widget.
  159515. * @param {Scene} scene The Scene instance to use.
  159516. * @param {Number} [duration=2.0] The time, in seconds, it takes for the scene to transition.
  159517. *
  159518. * @exception {DeveloperError} Element with id "container" does not exist in the document.
  159519. *
  159520. * @example
  159521. * // In HTML head, include a link to the SceneModePicker.css stylesheet,
  159522. * // and in the body, include: <div id="sceneModePickerContainer"></div>
  159523. * // Note: This code assumes you already have a Scene instance.
  159524. *
  159525. * var sceneModePicker = new Cesium.SceneModePicker('sceneModePickerContainer', scene);
  159526. */
  159527. function SceneModePicker(container, scene, duration) {
  159528. if (!defined(container)) {
  159529. throw new DeveloperError('container is required.');
  159530. }
  159531. if (!defined(scene)) {
  159532. throw new DeveloperError('scene is required.');
  159533. }
  159534. container = getElement(container);
  159535. var viewModel = new SceneModePickerViewModel(scene, duration);
  159536. viewModel._globePath = globePath;
  159537. viewModel._flatMapPath = flatMapPath;
  159538. viewModel._columbusViewPath = columbusViewPath;
  159539. var wrapper = document.createElement('span');
  159540. wrapper.className = 'cesium-sceneModePicker-wrapper cesium-toolbar-button';
  159541. container.appendChild(wrapper);
  159542. var button = document.createElement('button');
  159543. button.type = 'button';
  159544. button.className = 'cesium-button cesium-toolbar-button';
  159545. button.setAttribute('data-bind', '\
  159546. css: { "cesium-sceneModePicker-button2D": sceneMode === _sceneMode.SCENE2D,\
  159547. "cesium-sceneModePicker-button3D": sceneMode === _sceneMode.SCENE3D,\
  159548. "cesium-sceneModePicker-buttonColumbusView": sceneMode === _sceneMode.COLUMBUS_VIEW,\
  159549. "cesium-sceneModePicker-selected": dropDownVisible },\
  159550. attr: { title: selectedTooltip },\
  159551. click: toggleDropDown');
  159552. button.innerHTML = '\
  159553. <!-- ko cesiumSvgPath: { path: _globePath, width: 64, height: 64, css: "cesium-sceneModePicker-slide-svg cesium-sceneModePicker-icon3D" } --><!-- /ko -->\
  159554. <!-- ko cesiumSvgPath: { path: _flatMapPath, width: 64, height: 64, css: "cesium-sceneModePicker-slide-svg cesium-sceneModePicker-icon2D" } --><!-- /ko -->\
  159555. <!-- ko cesiumSvgPath: { path: _columbusViewPath, width: 64, height: 64, css: "cesium-sceneModePicker-slide-svg cesium-sceneModePicker-iconColumbusView" } --><!-- /ko -->';
  159556. wrapper.appendChild(button);
  159557. var morphTo3DButton = document.createElement('button');
  159558. morphTo3DButton.type = 'button';
  159559. morphTo3DButton.className = 'cesium-button cesium-toolbar-button cesium-sceneModePicker-dropDown-icon';
  159560. morphTo3DButton.setAttribute('data-bind', '\
  159561. css: { "cesium-sceneModePicker-visible" : (dropDownVisible && (sceneMode !== _sceneMode.SCENE3D)) || (!dropDownVisible && (sceneMode === _sceneMode.SCENE3D)),\
  159562. "cesium-sceneModePicker-none" : sceneMode === _sceneMode.SCENE3D,\
  159563. "cesium-sceneModePicker-hidden" : !dropDownVisible },\
  159564. attr: { title: tooltip3D },\
  159565. click: morphTo3D,\
  159566. cesiumSvgPath: { path: _globePath, width: 64, height: 64 }');
  159567. wrapper.appendChild(morphTo3DButton);
  159568. var morphTo2DButton = document.createElement('button');
  159569. morphTo2DButton.type = 'button';
  159570. morphTo2DButton.className = 'cesium-button cesium-toolbar-button cesium-sceneModePicker-dropDown-icon';
  159571. morphTo2DButton.setAttribute('data-bind', '\
  159572. css: { "cesium-sceneModePicker-visible" : (dropDownVisible && (sceneMode !== _sceneMode.SCENE2D)),\
  159573. "cesium-sceneModePicker-none" : sceneMode === _sceneMode.SCENE2D,\
  159574. "cesium-sceneModePicker-hidden" : !dropDownVisible },\
  159575. attr: { title: tooltip2D },\
  159576. click: morphTo2D,\
  159577. cesiumSvgPath: { path: _flatMapPath, width: 64, height: 64 }');
  159578. wrapper.appendChild(morphTo2DButton);
  159579. var morphToCVButton = document.createElement('button');
  159580. morphToCVButton.type = 'button';
  159581. morphToCVButton.className = 'cesium-button cesium-toolbar-button cesium-sceneModePicker-dropDown-icon';
  159582. morphToCVButton.setAttribute('data-bind', '\
  159583. css: { "cesium-sceneModePicker-visible" : (dropDownVisible && (sceneMode !== _sceneMode.COLUMBUS_VIEW)) || (!dropDownVisible && (sceneMode === _sceneMode.COLUMBUS_VIEW)),\
  159584. "cesium-sceneModePicker-none" : sceneMode === _sceneMode.COLUMBUS_VIEW,\
  159585. "cesium-sceneModePicker-hidden" : !dropDownVisible},\
  159586. attr: { title: tooltipColumbusView },\
  159587. click: morphToColumbusView,\
  159588. cesiumSvgPath: { path: _columbusViewPath, width: 64, height: 64 }');
  159589. wrapper.appendChild(morphToCVButton);
  159590. knockout.applyBindings(viewModel, wrapper);
  159591. this._viewModel = viewModel;
  159592. this._container = container;
  159593. this._wrapper = wrapper;
  159594. this._closeDropDown = function(e) {
  159595. if (!wrapper.contains(e.target)) {
  159596. viewModel.dropDownVisible = false;
  159597. }
  159598. };
  159599. if (FeatureDetection.supportsPointerEvents()) {
  159600. document.addEventListener('pointerdown', this._closeDropDown, true);
  159601. } else {
  159602. document.addEventListener('mousedown', this._closeDropDown, true);
  159603. document.addEventListener('touchstart', this._closeDropDown, true);
  159604. }
  159605. }
  159606. defineProperties(SceneModePicker.prototype, {
  159607. /**
  159608. * Gets the parent container.
  159609. * @memberof SceneModePicker.prototype
  159610. *
  159611. * @type {Element}
  159612. */
  159613. container : {
  159614. get : function() {
  159615. return this._container;
  159616. }
  159617. },
  159618. /**
  159619. * Gets the view model.
  159620. * @memberof SceneModePicker.prototype
  159621. *
  159622. * @type {SceneModePickerViewModel}
  159623. */
  159624. viewModel : {
  159625. get : function() {
  159626. return this._viewModel;
  159627. }
  159628. }
  159629. });
  159630. /**
  159631. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  159632. */
  159633. SceneModePicker.prototype.isDestroyed = function() {
  159634. return false;
  159635. };
  159636. /**
  159637. * Destroys the widget. Should be called if permanently
  159638. * removing the widget from layout.
  159639. */
  159640. SceneModePicker.prototype.destroy = function() {
  159641. this._viewModel.destroy();
  159642. if (FeatureDetection.supportsPointerEvents()) {
  159643. document.removeEventListener('pointerdown', this._closeDropDown, true);
  159644. } else {
  159645. document.removeEventListener('mousedown', this._closeDropDown, true);
  159646. document.removeEventListener('touchstart', this._closeDropDown, true);
  159647. }
  159648. knockout.cleanNode(this._wrapper);
  159649. this._container.removeChild(this._wrapper);
  159650. return destroyObject(this);
  159651. };
  159652. return SceneModePicker;
  159653. });
  159654. /*global define*/
  159655. define('Widgets/SelectionIndicator/SelectionIndicatorViewModel',[
  159656. '../../Core/Cartesian2',
  159657. '../../Core/defaultValue',
  159658. '../../Core/defined',
  159659. '../../Core/defineProperties',
  159660. '../../Core/DeveloperError',
  159661. '../../Core/EasingFunction',
  159662. '../../Scene/SceneTransforms',
  159663. '../../ThirdParty/knockout'
  159664. ], function(
  159665. Cartesian2,
  159666. defaultValue,
  159667. defined,
  159668. defineProperties,
  159669. DeveloperError,
  159670. EasingFunction,
  159671. SceneTransforms,
  159672. knockout) {
  159673. 'use strict';
  159674. var screenSpacePos = new Cartesian2();
  159675. var offScreen = '-1000px';
  159676. /**
  159677. * The view model for {@link SelectionIndicator}.
  159678. * @alias SelectionIndicatorViewModel
  159679. * @constructor
  159680. *
  159681. * @param {Scene} scene The scene instance to use for screen-space coordinate conversion.
  159682. * @param {Element} selectionIndicatorElement The element containing all elements that make up the selection indicator.
  159683. * @param {Element} container The DOM element that contains the widget.
  159684. */
  159685. function SelectionIndicatorViewModel(scene, selectionIndicatorElement, container) {
  159686. if (!defined(scene)) {
  159687. throw new DeveloperError('scene is required.');
  159688. }
  159689. if (!defined(selectionIndicatorElement)) {
  159690. throw new DeveloperError('selectionIndicatorElement is required.');
  159691. }
  159692. if (!defined(container)) {
  159693. throw new DeveloperError('container is required.');
  159694. }
  159695. this._scene = scene;
  159696. this._screenPositionX = offScreen;
  159697. this._screenPositionY = offScreen;
  159698. this._tweens = scene.tweens;
  159699. this._container = defaultValue(container, document.body);
  159700. this._selectionIndicatorElement = selectionIndicatorElement;
  159701. this._scale = 1;
  159702. /**
  159703. * Gets or sets the world position of the object for which to display the selection indicator.
  159704. * @type {Cartesian3}
  159705. */
  159706. this.position = undefined;
  159707. /**
  159708. * Gets or sets the visibility of the selection indicator.
  159709. * @type {Boolean}
  159710. */
  159711. this.showSelection = false;
  159712. knockout.track(this, ['position', '_screenPositionX', '_screenPositionY', '_scale', 'showSelection']);
  159713. /**
  159714. * Gets the visibility of the position indicator. This can be false even if an
  159715. * object is selected, when the selected object has no position.
  159716. * @type {Boolean}
  159717. */
  159718. this.isVisible = undefined;
  159719. knockout.defineProperty(this, 'isVisible', {
  159720. get : function() {
  159721. return this.showSelection && defined(this.position);
  159722. }
  159723. });
  159724. knockout.defineProperty(this, '_transform', {
  159725. get : function() {
  159726. return 'scale(' + (this._scale) + ')';
  159727. }
  159728. });
  159729. /**
  159730. * Gets or sets the function for converting the world position of the object to the screen space position.
  159731. *
  159732. * @member
  159733. * @type {SelectionIndicatorViewModel~ComputeScreenSpacePosition}
  159734. * @default SceneTransforms.wgs84ToWindowCoordinates
  159735. *
  159736. * @example
  159737. * selectionIndicatorViewModel.computeScreenSpacePosition = function(position, result) {
  159738. * return Cesium.SceneTransforms.wgs84ToWindowCoordinates(scene, position, result);
  159739. * };
  159740. */
  159741. this.computeScreenSpacePosition = function(position, result) {
  159742. return SceneTransforms.wgs84ToWindowCoordinates(scene, position, result);
  159743. };
  159744. }
  159745. /**
  159746. * Updates the view of the selection indicator to match the position and content properties of the view model.
  159747. * This function should be called as part of the render loop.
  159748. */
  159749. SelectionIndicatorViewModel.prototype.update = function() {
  159750. if (this.showSelection && defined(this.position)) {
  159751. var screenPosition = this.computeScreenSpacePosition(this.position, screenSpacePos);
  159752. if (!defined(screenPosition)) {
  159753. this._screenPositionX = offScreen;
  159754. this._screenPositionY = offScreen;
  159755. } else {
  159756. var container = this._container;
  159757. var containerWidth = container.parentNode.clientWidth;
  159758. var containerHeight = container.parentNode.clientHeight;
  159759. var indicatorSize = this._selectionIndicatorElement.clientWidth;
  159760. var halfSize = indicatorSize * 0.5;
  159761. screenPosition.x = Math.min(Math.max(screenPosition.x, -indicatorSize), containerWidth + indicatorSize) - halfSize;
  159762. screenPosition.y = Math.min(Math.max(screenPosition.y, -indicatorSize), containerHeight + indicatorSize) - halfSize;
  159763. this._screenPositionX = Math.floor(screenPosition.x + 0.25) + 'px';
  159764. this._screenPositionY = Math.floor(screenPosition.y + 0.25) + 'px';
  159765. }
  159766. }
  159767. };
  159768. /**
  159769. * Animate the indicator to draw attention to the selection.
  159770. */
  159771. SelectionIndicatorViewModel.prototype.animateAppear = function() {
  159772. this._tweens.addProperty({
  159773. object : this,
  159774. property : '_scale',
  159775. startValue : 2,
  159776. stopValue : 1,
  159777. duration : 0.8,
  159778. easingFunction : EasingFunction.EXPONENTIAL_OUT
  159779. });
  159780. };
  159781. /**
  159782. * Animate the indicator to release the selection.
  159783. */
  159784. SelectionIndicatorViewModel.prototype.animateDepart = function() {
  159785. this._tweens.addProperty({
  159786. object : this,
  159787. property : '_scale',
  159788. startValue : this._scale,
  159789. stopValue : 1.5,
  159790. duration : 0.8,
  159791. easingFunction : EasingFunction.EXPONENTIAL_OUT
  159792. });
  159793. };
  159794. defineProperties(SelectionIndicatorViewModel.prototype, {
  159795. /**
  159796. * Gets the HTML element containing the selection indicator.
  159797. * @memberof SelectionIndicatorViewModel.prototype
  159798. *
  159799. * @type {Element}
  159800. */
  159801. container : {
  159802. get : function() {
  159803. return this._container;
  159804. }
  159805. },
  159806. /**
  159807. * Gets the HTML element that holds the selection indicator.
  159808. * @memberof SelectionIndicatorViewModel.prototype
  159809. *
  159810. * @type {Element}
  159811. */
  159812. selectionIndicatorElement : {
  159813. get : function() {
  159814. return this._selectionIndicatorElement;
  159815. }
  159816. },
  159817. /**
  159818. * Gets the scene being used.
  159819. * @memberof SelectionIndicatorViewModel.prototype
  159820. *
  159821. * @type {Scene}
  159822. */
  159823. scene : {
  159824. get : function() {
  159825. return this._scene;
  159826. }
  159827. }
  159828. });
  159829. /**
  159830. * A function that converts the world position of an object to a screen space position.
  159831. * @callback SelectionIndicatorViewModel~ComputeScreenSpacePosition
  159832. * @param {Cartesian3} position The position in WGS84 (world) coordinates.
  159833. * @param {Cartesian2} result An object to return the input position transformed to window coordinates.
  159834. * @returns {Cartesian2} The modified result parameter.
  159835. */
  159836. return SelectionIndicatorViewModel;
  159837. });
  159838. /*global define*/
  159839. define('Widgets/SelectionIndicator/SelectionIndicator',[
  159840. '../../Core/defined',
  159841. '../../Core/defineProperties',
  159842. '../../Core/destroyObject',
  159843. '../../Core/DeveloperError',
  159844. '../../ThirdParty/knockout',
  159845. '../getElement',
  159846. './SelectionIndicatorViewModel'
  159847. ], function(
  159848. defined,
  159849. defineProperties,
  159850. destroyObject,
  159851. DeveloperError,
  159852. knockout,
  159853. getElement,
  159854. SelectionIndicatorViewModel) {
  159855. 'use strict';
  159856. /**
  159857. * A widget for displaying an indicator on a selected object.
  159858. *
  159859. * @alias SelectionIndicator
  159860. * @constructor
  159861. *
  159862. * @param {Element|String} container The DOM element or ID that will contain the widget.
  159863. * @param {Scene} scene The Scene instance to use.
  159864. *
  159865. * @exception {DeveloperError} Element with id "container" does not exist in the document.
  159866. */
  159867. function SelectionIndicator(container, scene) {
  159868. if (!defined(container)) {
  159869. throw new DeveloperError('container is required.');
  159870. }
  159871. container = getElement(container);
  159872. this._container = container;
  159873. var el = document.createElement('div');
  159874. el.className = 'cesium-selection-wrapper';
  159875. el.setAttribute('data-bind', '\
  159876. style: { "top" : _screenPositionY, "left" : _screenPositionX },\
  159877. css: { "cesium-selection-wrapper-visible" : isVisible }');
  159878. container.appendChild(el);
  159879. this._element = el;
  159880. var svgNS = 'http://www.w3.org/2000/svg';
  159881. var path = 'M -34 -34 L -34 -11.25 L -30 -15.25 L -30 -30 L -15.25 -30 L -11.25 -34 L -34 -34 z M 11.25 -34 L 15.25 -30 L 30 -30 L 30 -15.25 L 34 -11.25 L 34 -34 L 11.25 -34 z M -34 11.25 L -34 34 L -11.25 34 L -15.25 30 L -30 30 L -30 15.25 L -34 11.25 z M 34 11.25 L 30 15.25 L 30 30 L 15.25 30 L 11.25 34 L 34 34 L 34 11.25 z';
  159882. var svg = document.createElementNS(svgNS, 'svg:svg');
  159883. svg.setAttribute('width', 160);
  159884. svg.setAttribute('height', 160);
  159885. svg.setAttribute('viewBox', '0 0 160 160');
  159886. var group = document.createElementNS(svgNS, 'g');
  159887. group.setAttribute('transform', 'translate(80,80)');
  159888. svg.appendChild(group);
  159889. var pathElement = document.createElementNS(svgNS, 'path');
  159890. pathElement.setAttribute('data-bind', 'attr: { transform: _transform }');
  159891. pathElement.setAttribute('d', path);
  159892. group.appendChild(pathElement);
  159893. el.appendChild(svg);
  159894. var viewModel = new SelectionIndicatorViewModel(scene, this._element, this._container);
  159895. this._viewModel = viewModel;
  159896. knockout.applyBindings(this._viewModel, this._element);
  159897. }
  159898. defineProperties(SelectionIndicator.prototype, {
  159899. /**
  159900. * Gets the parent container.
  159901. * @memberof SelectionIndicator.prototype
  159902. *
  159903. * @type {Element}
  159904. */
  159905. container : {
  159906. get : function() {
  159907. return this._container;
  159908. }
  159909. },
  159910. /**
  159911. * Gets the view model.
  159912. * @memberof SelectionIndicator.prototype
  159913. *
  159914. * @type {SelectionIndicatorViewModel}
  159915. */
  159916. viewModel : {
  159917. get : function() {
  159918. return this._viewModel;
  159919. }
  159920. }
  159921. });
  159922. /**
  159923. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  159924. */
  159925. SelectionIndicator.prototype.isDestroyed = function() {
  159926. return false;
  159927. };
  159928. /**
  159929. * Destroys the widget. Should be called if permanently
  159930. * removing the widget from layout.
  159931. */
  159932. SelectionIndicator.prototype.destroy = function() {
  159933. var container = this._container;
  159934. knockout.cleanNode(this._element);
  159935. container.removeChild(this._element);
  159936. return destroyObject(this);
  159937. };
  159938. return SelectionIndicator;
  159939. });
  159940. /*global define*/
  159941. define('Widgets/Timeline/TimelineHighlightRange',[
  159942. '../../Core/defaultValue',
  159943. '../../Core/JulianDate'
  159944. ], function(
  159945. defaultValue,
  159946. JulianDate) {
  159947. 'use strict';
  159948. /**
  159949. * @private
  159950. */
  159951. function TimelineHighlightRange(color, heightInPx, base) {
  159952. this._color = color;
  159953. this._height = heightInPx;
  159954. this._base = defaultValue(base, 0);
  159955. }
  159956. TimelineHighlightRange.prototype.getHeight = function() {
  159957. return this._height;
  159958. };
  159959. TimelineHighlightRange.prototype.getBase = function() {
  159960. return this._base;
  159961. };
  159962. TimelineHighlightRange.prototype.getStartTime = function() {
  159963. return this._start;
  159964. };
  159965. TimelineHighlightRange.prototype.getStopTime = function() {
  159966. return this._stop;
  159967. };
  159968. TimelineHighlightRange.prototype.setRange = function(start, stop) {
  159969. this._start = start;
  159970. this._stop = stop;
  159971. };
  159972. TimelineHighlightRange.prototype.render = function(renderState) {
  159973. var range = '';
  159974. if (this._start && this._stop && this._color) {
  159975. var highlightStart = JulianDate.secondsDifference(this._start, renderState.epochJulian);
  159976. var highlightLeft = Math.round(renderState.timeBarWidth * renderState.getAlpha(highlightStart));
  159977. var highlightStop = JulianDate.secondsDifference(this._stop, renderState.epochJulian);
  159978. var highlightWidth = Math.round(renderState.timeBarWidth * renderState.getAlpha(highlightStop)) - highlightLeft;
  159979. if (highlightLeft < 0) {
  159980. highlightWidth += highlightLeft;
  159981. highlightLeft = 0;
  159982. }
  159983. if ((highlightLeft + highlightWidth) > renderState.timeBarWidth) {
  159984. highlightWidth = renderState.timeBarWidth - highlightLeft;
  159985. }
  159986. if (highlightWidth > 0) {
  159987. range = '<span class="cesium-timeline-highlight" style="left: ' + highlightLeft.toString() +
  159988. 'px; width: ' + highlightWidth.toString() + 'px; bottom: ' + this._base.toString() +
  159989. 'px; height: ' + this._height + 'px; background-color: ' + this._color + ';"></span>';
  159990. }
  159991. }
  159992. return range;
  159993. };
  159994. return TimelineHighlightRange;
  159995. });
  159996. /*global define*/
  159997. define('Widgets/Timeline/TimelineTrack',[
  159998. '../../Core/Color',
  159999. '../../Core/defined',
  160000. '../../Core/JulianDate'
  160001. ], function(
  160002. Color,
  160003. defined,
  160004. JulianDate) {
  160005. 'use strict';
  160006. /**
  160007. * @private
  160008. */
  160009. function TimelineTrack(interval, pixelHeight, color, backgroundColor) {
  160010. this.interval = interval;
  160011. this.height = pixelHeight;
  160012. this.color = color || new Color(0.5, 0.5, 0.5, 1.0);
  160013. this.backgroundColor = backgroundColor || new Color(0.0, 0.0, 0.0, 0.0);
  160014. }
  160015. TimelineTrack.prototype.render = function(context, renderState) {
  160016. var startInterval = this.interval.start;
  160017. var stopInterval = this.interval.stop;
  160018. var spanStart = renderState.startJulian;
  160019. var spanStop = JulianDate.addSeconds(renderState.startJulian, renderState.duration, new JulianDate());
  160020. if (JulianDate.lessThan(startInterval, spanStart) && JulianDate.greaterThan(stopInterval, spanStop)) {
  160021. //The track takes up the entire visible span.
  160022. context.fillStyle = this.color.toCssColorString();
  160023. context.fillRect(0, renderState.y, renderState.timeBarWidth, this.height);
  160024. } else if (JulianDate.lessThanOrEquals(startInterval, spanStop) && JulianDate.greaterThanOrEquals(stopInterval, spanStart)) {
  160025. //The track only takes up some of the visible span, compute that span.
  160026. var x;
  160027. var start, stop;
  160028. for (x = 0; x < renderState.timeBarWidth; ++x) {
  160029. var currentTime = JulianDate.addSeconds(renderState.startJulian, (x / renderState.timeBarWidth) * renderState.duration, new JulianDate());
  160030. if (!defined(start) && JulianDate.greaterThanOrEquals(currentTime, startInterval)) {
  160031. start = x;
  160032. } else if (!defined(stop) && JulianDate.greaterThanOrEquals(currentTime, stopInterval)) {
  160033. stop = x;
  160034. }
  160035. }
  160036. context.fillStyle = this.backgroundColor.toCssColorString();
  160037. context.fillRect(0, renderState.y, renderState.timeBarWidth, this.height);
  160038. if (defined(start)) {
  160039. if (!defined(stop)) {
  160040. stop = renderState.timeBarWidth;
  160041. }
  160042. context.fillStyle = this.color.toCssColorString();
  160043. context.fillRect(start, renderState.y, Math.max(stop - start, 1), this.height);
  160044. }
  160045. }
  160046. };
  160047. return TimelineTrack;
  160048. });
  160049. /*global define*/
  160050. define('Widgets/Timeline/Timeline',[
  160051. '../../Core/ClockRange',
  160052. '../../Core/defined',
  160053. '../../Core/destroyObject',
  160054. '../../Core/DeveloperError',
  160055. '../../Core/JulianDate',
  160056. '../getElement',
  160057. './TimelineHighlightRange',
  160058. './TimelineTrack'
  160059. ], function(
  160060. ClockRange,
  160061. defined,
  160062. destroyObject,
  160063. DeveloperError,
  160064. JulianDate,
  160065. getElement,
  160066. TimelineHighlightRange,
  160067. TimelineTrack) {
  160068. 'use strict';
  160069. var timelineWheelDelta = 1e12;
  160070. var timelineMouseMode = {
  160071. none : 0,
  160072. scrub : 1,
  160073. slide : 2,
  160074. zoom : 3,
  160075. touchOnly : 4
  160076. };
  160077. var timelineTouchMode = {
  160078. none : 0,
  160079. scrub : 1,
  160080. slideZoom : 2,
  160081. singleTap : 3,
  160082. ignore : 4
  160083. };
  160084. var timelineTicScales = [0.001, 0.002, 0.005, 0.01, 0.02, 0.05, 0.1, 0.25, 0.5, 1.0, 2.0, 5.0, 10.0, 15.0, 30.0, 60.0, // 1min
  160085. 120.0, // 2min
  160086. 300.0, // 5min
  160087. 600.0, // 10min
  160088. 900.0, // 15min
  160089. 1800.0, // 30min
  160090. 3600.0, // 1hr
  160091. 7200.0, // 2hr
  160092. 14400.0, // 4hr
  160093. 21600.0, // 6hr
  160094. 43200.0, // 12hr
  160095. 86400.0, // 24hr
  160096. 172800.0, // 2days
  160097. 345600.0, // 4days
  160098. 604800.0, // 7days
  160099. 1296000.0, // 15days
  160100. 2592000.0, // 30days
  160101. 5184000.0, // 60days
  160102. 7776000.0, // 90days
  160103. 15552000.0, // 180days
  160104. 31536000.0, // 365days
  160105. 63072000.0, // 2years
  160106. 126144000.0, // 4years
  160107. 157680000.0, // 5years
  160108. 315360000.0, // 10years
  160109. 630720000.0, // 20years
  160110. 1261440000.0, // 40years
  160111. 1576800000.0, // 50years
  160112. 3153600000.0, // 100years
  160113. 6307200000.0, // 200years
  160114. 12614400000.0, // 400years
  160115. 15768000000.0, // 500years
  160116. 31536000000.0 // 1000years
  160117. ];
  160118. var timelineMonthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  160119. /**
  160120. * The Timeline is a widget for displaying and controlling the current scene time.
  160121. * @alias Timeline
  160122. * @constructor
  160123. *
  160124. * @param {Element} container The parent HTML container node for this widget.
  160125. * @param {Clock} clock The clock to use.
  160126. */
  160127. function Timeline(container, clock) {
  160128. if (!defined(container)) {
  160129. throw new DeveloperError('container is required.');
  160130. }
  160131. if (!defined(clock)) {
  160132. throw new DeveloperError('clock is required.');
  160133. }
  160134. container = getElement(container);
  160135. /**
  160136. * Gets the parent container.
  160137. * @type {Element}
  160138. */
  160139. this.container = container;
  160140. var topDiv = document.createElement('div');
  160141. topDiv.className = 'cesium-timeline-main';
  160142. container.appendChild(topDiv);
  160143. this._topDiv = topDiv;
  160144. this._endJulian = undefined;
  160145. this._epochJulian = undefined;
  160146. this._lastXPos = undefined;
  160147. this._scrubElement = undefined;
  160148. this._startJulian = undefined;
  160149. this._timeBarSecondsSpan = undefined;
  160150. this._clock = clock;
  160151. this._scrubJulian = clock.currentTime;
  160152. this._mainTicSpan = -1;
  160153. this._mouseMode = timelineMouseMode.none;
  160154. this._touchMode = timelineTouchMode.none;
  160155. this._touchState = {
  160156. centerX : 0,
  160157. spanX : 0
  160158. };
  160159. this._mouseX = 0;
  160160. this._timelineDrag = 0;
  160161. this._timelineDragLocation = undefined;
  160162. this._lastHeight = undefined;
  160163. this._lastWidth = undefined;
  160164. this._topDiv.innerHTML = '<div class="cesium-timeline-bar"></div><div class="cesium-timeline-trackContainer">' +
  160165. '<canvas class="cesium-timeline-tracks" width="10" height="1">' +
  160166. '</canvas></div><div class="cesium-timeline-needle"></div><span class="cesium-timeline-ruler"></span>';
  160167. this._timeBarEle = this._topDiv.childNodes[0];
  160168. this._trackContainer = this._topDiv.childNodes[1];
  160169. this._trackListEle = this._topDiv.childNodes[1].childNodes[0];
  160170. this._needleEle = this._topDiv.childNodes[2];
  160171. this._rulerEle = this._topDiv.childNodes[3];
  160172. this._context = this._trackListEle.getContext('2d');
  160173. this._trackList = [];
  160174. this._highlightRanges = [];
  160175. this.zoomTo(clock.startTime, clock.stopTime);
  160176. this._onMouseDown = createMouseDownCallback(this);
  160177. this._onMouseUp = createMouseUpCallback(this);
  160178. this._onMouseMove = createMouseMoveCallback(this);
  160179. this._onMouseWheel = createMouseWheelCallback(this);
  160180. this._onTouchStart = createTouchStartCallback(this);
  160181. this._onTouchMove = createTouchMoveCallback(this);
  160182. this._onTouchEnd = createTouchEndCallback(this);
  160183. var timeBarEle = this._timeBarEle;
  160184. document.addEventListener('mouseup', this._onMouseUp, false);
  160185. document.addEventListener('mousemove', this._onMouseMove, false);
  160186. timeBarEle.addEventListener('mousedown', this._onMouseDown, false);
  160187. timeBarEle.addEventListener('DOMMouseScroll', this._onMouseWheel, false); // Mozilla mouse wheel
  160188. timeBarEle.addEventListener('mousewheel', this._onMouseWheel, false);
  160189. timeBarEle.addEventListener('touchstart', this._onTouchStart, false);
  160190. timeBarEle.addEventListener('touchmove', this._onTouchMove, false);
  160191. timeBarEle.addEventListener('touchend', this._onTouchEnd, false);
  160192. timeBarEle.addEventListener('touchcancel', this._onTouchEnd, false);
  160193. this._topDiv.oncontextmenu = function() {
  160194. return false;
  160195. };
  160196. clock.onTick.addEventListener(this.updateFromClock, this);
  160197. this.updateFromClock();
  160198. }
  160199. /**
  160200. * @private
  160201. */
  160202. Timeline.prototype.addEventListener = function(type, listener, useCapture) {
  160203. this._topDiv.addEventListener(type, listener, useCapture);
  160204. };
  160205. /**
  160206. * @private
  160207. */
  160208. Timeline.prototype.removeEventListener = function(type, listener, useCapture) {
  160209. this._topDiv.removeEventListener(type, listener, useCapture);
  160210. };
  160211. /**
  160212. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  160213. */
  160214. Timeline.prototype.isDestroyed = function() {
  160215. return false;
  160216. };
  160217. /**
  160218. * Destroys the widget. Should be called if permanently
  160219. * removing the widget from layout.
  160220. */
  160221. Timeline.prototype.destroy = function() {
  160222. this._clock.onTick.removeEventListener(this.updateFromClock, this);
  160223. document.removeEventListener('mouseup', this._onMouseUp, false);
  160224. document.removeEventListener('mousemove', this._onMouseMove, false);
  160225. var timeBarEle = this._timeBarEle;
  160226. timeBarEle.removeEventListener('mousedown', this._onMouseDown, false);
  160227. timeBarEle.removeEventListener('DOMMouseScroll', this._onMouseWheel, false); // Mozilla mouse wheel
  160228. timeBarEle.removeEventListener('mousewheel', this._onMouseWheel, false);
  160229. timeBarEle.removeEventListener('touchstart', this._onTouchStart, false);
  160230. timeBarEle.removeEventListener('touchmove', this._onTouchMove, false);
  160231. timeBarEle.removeEventListener('touchend', this._onTouchEnd, false);
  160232. timeBarEle.removeEventListener('touchcancel', this._onTouchEnd, false);
  160233. this.container.removeChild(this._topDiv);
  160234. destroyObject(this);
  160235. };
  160236. /**
  160237. * @private
  160238. */
  160239. Timeline.prototype.addHighlightRange = function(color, heightInPx, base) {
  160240. var newHighlightRange = new TimelineHighlightRange(color, heightInPx, base);
  160241. this._highlightRanges.push(newHighlightRange);
  160242. this.resize();
  160243. return newHighlightRange;
  160244. };
  160245. /**
  160246. * @private
  160247. */
  160248. Timeline.prototype.addTrack = function(interval, heightInPx, color, backgroundColor) {
  160249. var newTrack = new TimelineTrack(interval, heightInPx, color, backgroundColor);
  160250. this._trackList.push(newTrack);
  160251. this._lastHeight = undefined;
  160252. this.resize();
  160253. return newTrack;
  160254. };
  160255. /**
  160256. * Sets the view to the provided times.
  160257. *
  160258. * @param {JulianDate} startTime The start time.
  160259. * @param {JulianDate} stopTime The stop time.
  160260. */
  160261. Timeline.prototype.zoomTo = function(startTime, stopTime) {
  160262. if (!defined(startTime)) {
  160263. throw new DeveloperError('startTime is required.');
  160264. }
  160265. if (!defined(stopTime)) {
  160266. throw new DeveloperError('stopTime is required');
  160267. }
  160268. if (JulianDate.lessThanOrEquals(stopTime, startTime)) {
  160269. throw new DeveloperError('Start time must come before end time.');
  160270. }
  160271. this._startJulian = startTime;
  160272. this._endJulian = stopTime;
  160273. this._timeBarSecondsSpan = JulianDate.secondsDifference(stopTime, startTime);
  160274. // If clock is not unbounded, clamp timeline range to clock.
  160275. if (this._clock && (this._clock.clockRange !== ClockRange.UNBOUNDED)) {
  160276. var clockStart = this._clock.startTime;
  160277. var clockEnd = this._clock.stopTime;
  160278. var clockSpan = JulianDate.secondsDifference(clockEnd, clockStart);
  160279. var startOffset = JulianDate.secondsDifference(clockStart, this._startJulian);
  160280. var endOffset = JulianDate.secondsDifference(clockEnd, this._endJulian);
  160281. if (this._timeBarSecondsSpan >= clockSpan) {
  160282. // if new duration longer than clock range duration, clamp to full range.
  160283. this._timeBarSecondsSpan = clockSpan;
  160284. this._startJulian = this._clock.startTime;
  160285. this._endJulian = this._clock.stopTime;
  160286. } else if (startOffset > 0) {
  160287. // if timeline start is before clock start, shift right
  160288. this._endJulian = JulianDate.addSeconds(this._endJulian, startOffset, new JulianDate());
  160289. this._startJulian = clockStart;
  160290. this._timeBarSecondsSpan = JulianDate.secondsDifference(this._endJulian, this._startJulian);
  160291. } else if (endOffset < 0) {
  160292. // if timeline end is after clock end, shift left
  160293. this._startJulian = JulianDate.addSeconds(this._startJulian, endOffset, new JulianDate());
  160294. this._endJulian = clockEnd;
  160295. this._timeBarSecondsSpan = JulianDate.secondsDifference(this._endJulian, this._startJulian);
  160296. }
  160297. }
  160298. this._makeTics();
  160299. var evt = document.createEvent('Event');
  160300. evt.initEvent('setzoom', true, true);
  160301. evt.startJulian = this._startJulian;
  160302. evt.endJulian = this._endJulian;
  160303. evt.epochJulian = this._epochJulian;
  160304. evt.totalSpan = this._timeBarSecondsSpan;
  160305. evt.mainTicSpan = this._mainTicSpan;
  160306. this._topDiv.dispatchEvent(evt);
  160307. };
  160308. /**
  160309. * @private
  160310. */
  160311. Timeline.prototype.zoomFrom = function(amount) {
  160312. var centerSec = JulianDate.secondsDifference(this._scrubJulian, this._startJulian);
  160313. if ((amount > 1) || (centerSec < 0) || (centerSec > this._timeBarSecondsSpan)) {
  160314. centerSec = this._timeBarSecondsSpan * 0.5;
  160315. } else {
  160316. centerSec += (centerSec - this._timeBarSecondsSpan * 0.5);
  160317. }
  160318. var centerSecFlip = this._timeBarSecondsSpan - centerSec;
  160319. this.zoomTo(JulianDate.addSeconds(this._startJulian, centerSec - (centerSec * amount), new JulianDate()), JulianDate.addSeconds(this._endJulian, (centerSecFlip * amount) - centerSecFlip, new JulianDate()));
  160320. };
  160321. function twoDigits(num) {
  160322. return ((num < 10) ? ('0' + num.toString()) : num.toString());
  160323. }
  160324. /**
  160325. * @private
  160326. */
  160327. Timeline.prototype.makeLabel = function(time) {
  160328. var gregorian = JulianDate.toGregorianDate(time);
  160329. var millisecond = gregorian.millisecond, millisecondString = ' UTC';
  160330. if ((millisecond > 0) && (this._timeBarSecondsSpan < 3600)) {
  160331. millisecondString = Math.floor(millisecond).toString();
  160332. while (millisecondString.length < 3) {
  160333. millisecondString = '0' + millisecondString;
  160334. }
  160335. millisecondString = '.' + millisecondString;
  160336. }
  160337. return timelineMonthNames[gregorian.month - 1] + ' ' + gregorian.day + ' ' + gregorian.year + ' ' + twoDigits(gregorian.hour) +
  160338. ':' + twoDigits(gregorian.minute) + ':' + twoDigits(gregorian.second) + millisecondString;
  160339. };
  160340. /**
  160341. * @private
  160342. */
  160343. Timeline.prototype.smallestTicInPixels = 7.0;
  160344. /**
  160345. * @private
  160346. */
  160347. Timeline.prototype._makeTics = function() {
  160348. var timeBar = this._timeBarEle;
  160349. var seconds = JulianDate.secondsDifference(this._scrubJulian, this._startJulian);
  160350. var xPos = Math.round(seconds * this._topDiv.clientWidth / this._timeBarSecondsSpan);
  160351. var scrubX = xPos - 8, tic;
  160352. var widget = this;
  160353. this._needleEle.style.left = xPos.toString() + 'px';
  160354. var tics = '';
  160355. var minimumDuration = 0.01;
  160356. var maximumDuration = 31536000000.0; // ~1000 years
  160357. var epsilon = 1e-10;
  160358. // If time step size is known, enter it here...
  160359. var minSize = 0;
  160360. var duration = this._timeBarSecondsSpan;
  160361. if (duration < minimumDuration) {
  160362. duration = minimumDuration;
  160363. this._timeBarSecondsSpan = minimumDuration;
  160364. this._endJulian = JulianDate.addSeconds(this._startJulian, minimumDuration, new JulianDate());
  160365. } else if (duration > maximumDuration) {
  160366. duration = maximumDuration;
  160367. this._timeBarSecondsSpan = maximumDuration;
  160368. this._endJulian = JulianDate.addSeconds(this._startJulian, maximumDuration, new JulianDate());
  160369. }
  160370. var timeBarWidth = this._timeBarEle.clientWidth;
  160371. if (timeBarWidth < 10) {
  160372. timeBarWidth = 10;
  160373. }
  160374. var startJulian = this._startJulian;
  160375. // epsilonTime: a small fraction of one pixel width of the timeline, measured in seconds.
  160376. var epsilonTime = Math.min((duration / timeBarWidth) * 1e-5, 0.4);
  160377. // epochJulian: a nearby time to be considered "zero seconds", should be a round-ish number by human standards.
  160378. var epochJulian;
  160379. var gregorianDate = JulianDate.toGregorianDate(startJulian);
  160380. if (duration > 315360000) { // 3650+ days visible, epoch is start of the first visible century.
  160381. epochJulian = JulianDate.fromDate(new Date(Date.UTC(Math.floor(gregorianDate.year / 100) * 100, 0)));
  160382. } else if (duration > 31536000) { // 365+ days visible, epoch is start of the first visible decade.
  160383. epochJulian = JulianDate.fromDate(new Date(Date.UTC(Math.floor(gregorianDate.year / 10) * 10, 0)));
  160384. } else if (duration > 86400) { // 1+ day(s) visible, epoch is start of the year.
  160385. epochJulian = JulianDate.fromDate(new Date(Date.UTC(gregorianDate.year, 0)));
  160386. } else { // Less than a day on timeline, epoch is midnight of the visible day.
  160387. epochJulian = JulianDate.fromDate(new Date(Date.UTC(gregorianDate.year, gregorianDate.month, gregorianDate.day)));
  160388. }
  160389. // startTime: Seconds offset of the left side of the timeline from epochJulian.
  160390. var startTime = JulianDate.secondsDifference(this._startJulian, JulianDate.addSeconds(epochJulian, epsilonTime, new JulianDate()));
  160391. // endTime: Seconds offset of the right side of the timeline from epochJulian.
  160392. var endTime = startTime + duration;
  160393. this._epochJulian = epochJulian;
  160394. function getStartTic(ticScale) {
  160395. return Math.floor(startTime / ticScale) * ticScale;
  160396. }
  160397. function getNextTic(tic, ticScale) {
  160398. return Math.ceil((tic / ticScale) + 0.5) * ticScale;
  160399. }
  160400. function getAlpha(time) {
  160401. return (time - startTime) / duration;
  160402. }
  160403. function remainder(x, y) {
  160404. //return x % y;
  160405. return x - (y * Math.round(x / y));
  160406. }
  160407. // Width in pixels of a typical label, plus padding
  160408. this._rulerEle.innerHTML = this.makeLabel(JulianDate.addSeconds(this._endJulian, -minimumDuration, new JulianDate()));
  160409. var sampleWidth = this._rulerEle.offsetWidth + 20;
  160410. if (sampleWidth < 30) {
  160411. // Workaround an apparent IE bug with measuring the width after going full-screen from inside an iframe.
  160412. sampleWidth = 180;
  160413. }
  160414. var origMinSize = minSize;
  160415. minSize -= epsilon;
  160416. var renderState = {
  160417. startTime : startTime,
  160418. startJulian : startJulian,
  160419. epochJulian : epochJulian,
  160420. duration : duration,
  160421. timeBarWidth : timeBarWidth,
  160422. getAlpha : getAlpha
  160423. };
  160424. this._highlightRanges.forEach(function(highlightRange) {
  160425. tics += highlightRange.render(renderState);
  160426. });
  160427. // Calculate tic mark label spacing in the TimeBar.
  160428. var mainTic = 0.0, subTic = 0.0, tinyTic = 0.0;
  160429. // Ideal labeled tic as percentage of zoom interval
  160430. var idealTic = sampleWidth / timeBarWidth;
  160431. if (idealTic > 1.0) {
  160432. // Clamp to width of window, for thin windows.
  160433. idealTic = 1.0;
  160434. }
  160435. // Ideal labeled tic size in seconds
  160436. idealTic *= this._timeBarSecondsSpan;
  160437. var ticIndex = -1, smallestIndex = -1;
  160438. var i, ticScaleLen = timelineTicScales.length;
  160439. for (i = 0; i < ticScaleLen; ++i) {
  160440. var sc = timelineTicScales[i];
  160441. ++ticIndex;
  160442. mainTic = sc;
  160443. // Find acceptable main tic size not smaller than ideal size.
  160444. if ((sc > idealTic) && (sc > minSize)) {
  160445. break;
  160446. }
  160447. if ((smallestIndex < 0) && ((timeBarWidth * (sc / this._timeBarSecondsSpan)) >= this.smallestTicInPixels)) {
  160448. smallestIndex = ticIndex;
  160449. }
  160450. }
  160451. if (ticIndex > 0) {
  160452. while (ticIndex > 0) // Compute sub-tic size that evenly divides main tic.
  160453. {
  160454. --ticIndex;
  160455. if (Math.abs(remainder(mainTic, timelineTicScales[ticIndex])) < 0.00001) {
  160456. if (timelineTicScales[ticIndex] >= minSize) {
  160457. subTic = timelineTicScales[ticIndex];
  160458. }
  160459. break;
  160460. }
  160461. }
  160462. if (smallestIndex >= 0) {
  160463. while (smallestIndex < ticIndex) // Compute tiny tic size that evenly divides sub-tic.
  160464. {
  160465. if ((Math.abs(remainder(subTic, timelineTicScales[smallestIndex])) < 0.00001) && (timelineTicScales[smallestIndex] >= minSize)) {
  160466. tinyTic = timelineTicScales[smallestIndex];
  160467. break;
  160468. }
  160469. ++smallestIndex;
  160470. }
  160471. }
  160472. }
  160473. minSize = origMinSize;
  160474. if ((minSize > epsilon) && (tinyTic < 0.00001) && (Math.abs(minSize - mainTic) > epsilon)) {
  160475. tinyTic = minSize;
  160476. if (minSize <= (mainTic + epsilon)) {
  160477. subTic = 0.0;
  160478. }
  160479. }
  160480. var lastTextLeft = -999999, textWidth;
  160481. if ((timeBarWidth * (tinyTic / this._timeBarSecondsSpan)) >= 3.0) {
  160482. for (tic = getStartTic(tinyTic); tic <= endTime; tic = getNextTic(tic, tinyTic)) {
  160483. tics += '<span class="cesium-timeline-ticTiny" style="left: ' + Math.round(timeBarWidth * getAlpha(tic)).toString() + 'px;"></span>';
  160484. }
  160485. }
  160486. if ((timeBarWidth * (subTic / this._timeBarSecondsSpan)) >= 3.0) {
  160487. for (tic = getStartTic(subTic); tic <= endTime; tic = getNextTic(tic, subTic)) {
  160488. tics += '<span class="cesium-timeline-ticSub" style="left: ' + Math.round(timeBarWidth * getAlpha(tic)).toString() + 'px;"></span>';
  160489. }
  160490. }
  160491. if ((timeBarWidth * (mainTic / this._timeBarSecondsSpan)) >= 2.0) {
  160492. this._mainTicSpan = mainTic;
  160493. endTime += mainTic;
  160494. tic = getStartTic(mainTic);
  160495. var leapSecond = JulianDate.computeTaiMinusUtc(epochJulian);
  160496. while (tic <= endTime) {
  160497. var ticTime = JulianDate.addSeconds(startJulian, tic - startTime, new JulianDate());
  160498. if (mainTic > 2.1) {
  160499. var ticLeap = JulianDate.computeTaiMinusUtc(ticTime);
  160500. if (Math.abs(ticLeap - leapSecond) > 0.1) {
  160501. tic += (ticLeap - leapSecond);
  160502. ticTime = JulianDate.addSeconds(startJulian, tic - startTime, new JulianDate());
  160503. }
  160504. }
  160505. var ticLeft = Math.round(timeBarWidth * getAlpha(tic));
  160506. var ticLabel = this.makeLabel(ticTime);
  160507. this._rulerEle.innerHTML = ticLabel;
  160508. textWidth = this._rulerEle.offsetWidth;
  160509. if (textWidth < 10) {
  160510. // IE iframe fullscreen sampleWidth workaround, continued.
  160511. textWidth = sampleWidth;
  160512. }
  160513. var labelLeft = ticLeft - ((textWidth / 2) - 1);
  160514. if (labelLeft > lastTextLeft) {
  160515. lastTextLeft = labelLeft + textWidth + 5;
  160516. tics += '<span class="cesium-timeline-ticMain" style="left: ' + ticLeft.toString() + 'px;"></span>' + '<span class="cesium-timeline-ticLabel" style="left: ' + labelLeft.toString() +
  160517. 'px;">' + ticLabel + '</span>';
  160518. } else {
  160519. tics += '<span class="cesium-timeline-ticSub" style="left: ' + ticLeft.toString() + 'px;"></span>';
  160520. }
  160521. tic = getNextTic(tic, mainTic);
  160522. }
  160523. } else {
  160524. this._mainTicSpan = -1;
  160525. }
  160526. tics += '<span class="cesium-timeline-icon16" style="left:' + scrubX + 'px;bottom:0;background-position: 0 0;"></span>';
  160527. timeBar.innerHTML = tics;
  160528. this._scrubElement = timeBar.lastChild;
  160529. // Clear track canvas.
  160530. this._context.clearRect(0, 0, this._trackListEle.width, this._trackListEle.height);
  160531. renderState.y = 0;
  160532. this._trackList.forEach(function(track) {
  160533. track.render(widget._context, renderState);
  160534. renderState.y += track.height;
  160535. });
  160536. };
  160537. /**
  160538. * @private
  160539. */
  160540. Timeline.prototype.updateFromClock = function() {
  160541. this._scrubJulian = this._clock.currentTime;
  160542. var scrubElement = this._scrubElement;
  160543. if (defined(this._scrubElement)) {
  160544. var seconds = JulianDate.secondsDifference(this._scrubJulian, this._startJulian);
  160545. var xPos = Math.round(seconds * this._topDiv.clientWidth / this._timeBarSecondsSpan);
  160546. if (this._lastXPos !== xPos) {
  160547. this._lastXPos = xPos;
  160548. scrubElement.style.left = (xPos - 8) + 'px';
  160549. this._needleEle.style.left = xPos + 'px';
  160550. }
  160551. }
  160552. if (defined(this._timelineDragLocation)) {
  160553. this._setTimeBarTime(this._timelineDragLocation, this._timelineDragLocation * this._timeBarSecondsSpan / this._topDiv.clientWidth);
  160554. this.zoomTo(JulianDate.addSeconds(this._startJulian, this._timelineDrag, new JulianDate()), JulianDate.addSeconds(this._endJulian, this._timelineDrag, new JulianDate()));
  160555. }
  160556. };
  160557. /**
  160558. * @private
  160559. */
  160560. Timeline.prototype._setTimeBarTime = function(xPos, seconds) {
  160561. xPos = Math.round(xPos);
  160562. this._scrubJulian = JulianDate.addSeconds(this._startJulian, seconds, new JulianDate());
  160563. if (this._scrubElement) {
  160564. var scrubX = xPos - 8;
  160565. this._scrubElement.style.left = scrubX.toString() + 'px';
  160566. this._needleEle.style.left = xPos.toString() + 'px';
  160567. }
  160568. var evt = document.createEvent('Event');
  160569. evt.initEvent('settime', true, true);
  160570. evt.clientX = xPos;
  160571. evt.timeSeconds = seconds;
  160572. evt.timeJulian = this._scrubJulian;
  160573. evt.clock = this._clock;
  160574. this._topDiv.dispatchEvent(evt);
  160575. };
  160576. function createMouseDownCallback(timeline) {
  160577. return function(e) {
  160578. if (timeline._mouseMode !== timelineMouseMode.touchOnly) {
  160579. if (e.button === 0) {
  160580. timeline._mouseMode = timelineMouseMode.scrub;
  160581. if (timeline._scrubElement) {
  160582. timeline._scrubElement.style.backgroundPosition = '-16px 0';
  160583. }
  160584. timeline._onMouseMove(e);
  160585. } else {
  160586. timeline._mouseX = e.clientX;
  160587. if (e.button === 2) {
  160588. timeline._mouseMode = timelineMouseMode.zoom;
  160589. } else {
  160590. timeline._mouseMode = timelineMouseMode.slide;
  160591. }
  160592. }
  160593. }
  160594. e.preventDefault();
  160595. };
  160596. }
  160597. function createMouseUpCallback(timeline) {
  160598. return function(e) {
  160599. timeline._mouseMode = timelineMouseMode.none;
  160600. if (timeline._scrubElement) {
  160601. timeline._scrubElement.style.backgroundPosition = '0 0';
  160602. }
  160603. timeline._timelineDrag = 0;
  160604. timeline._timelineDragLocation = undefined;
  160605. };
  160606. }
  160607. function createMouseMoveCallback(timeline) {
  160608. return function(e) {
  160609. var dx;
  160610. if (timeline._mouseMode === timelineMouseMode.scrub) {
  160611. e.preventDefault();
  160612. var x = e.clientX - timeline._topDiv.getBoundingClientRect().left;
  160613. if (x < 0) {
  160614. timeline._timelineDragLocation = 0;
  160615. timeline._timelineDrag = -0.01 * timeline._timeBarSecondsSpan;
  160616. } else if (x > timeline._topDiv.clientWidth) {
  160617. timeline._timelineDragLocation = timeline._topDiv.clientWidth;
  160618. timeline._timelineDrag = 0.01 * timeline._timeBarSecondsSpan;
  160619. } else {
  160620. timeline._timelineDragLocation = undefined;
  160621. timeline._setTimeBarTime(x, x * timeline._timeBarSecondsSpan / timeline._topDiv.clientWidth);
  160622. }
  160623. } else if (timeline._mouseMode === timelineMouseMode.slide) {
  160624. dx = timeline._mouseX - e.clientX;
  160625. timeline._mouseX = e.clientX;
  160626. if (dx !== 0) {
  160627. var dsec = dx * timeline._timeBarSecondsSpan / timeline._topDiv.clientWidth;
  160628. timeline.zoomTo(JulianDate.addSeconds(timeline._startJulian, dsec, new JulianDate()), JulianDate.addSeconds(timeline._endJulian, dsec, new JulianDate()));
  160629. }
  160630. } else if (timeline._mouseMode === timelineMouseMode.zoom) {
  160631. dx = timeline._mouseX - e.clientX;
  160632. timeline._mouseX = e.clientX;
  160633. if (dx !== 0) {
  160634. timeline.zoomFrom(Math.pow(1.01, dx));
  160635. }
  160636. }
  160637. };
  160638. }
  160639. function createMouseWheelCallback(timeline) {
  160640. return function(e) {
  160641. var dy = e.wheelDeltaY || e.wheelDelta || (-e.detail);
  160642. timelineWheelDelta = Math.max(Math.min(Math.abs(dy), timelineWheelDelta), 1);
  160643. dy /= timelineWheelDelta;
  160644. timeline.zoomFrom(Math.pow(1.05, -dy));
  160645. };
  160646. }
  160647. function createTouchStartCallback(timeline) {
  160648. return function(e) {
  160649. var len = e.touches.length, seconds, xPos, leftX = timeline._topDiv.getBoundingClientRect().left;
  160650. e.preventDefault();
  160651. timeline._mouseMode = timelineMouseMode.touchOnly;
  160652. if (len === 1) {
  160653. seconds = JulianDate.secondsDifference(timeline._scrubJulian, timeline._startJulian);
  160654. xPos = Math.round(seconds * timeline._topDiv.clientWidth / timeline._timeBarSecondsSpan + leftX);
  160655. if (Math.abs(e.touches[0].clientX - xPos) < 50) {
  160656. timeline._touchMode = timelineTouchMode.scrub;
  160657. if (timeline._scrubElement) {
  160658. timeline._scrubElement.style.backgroundPosition = (len === 1) ? '-16px 0' : '0 0';
  160659. }
  160660. } else {
  160661. timeline._touchMode = timelineTouchMode.singleTap;
  160662. timeline._touchState.centerX = e.touches[0].clientX - leftX;
  160663. }
  160664. } else if (len === 2) {
  160665. timeline._touchMode = timelineTouchMode.slideZoom;
  160666. timeline._touchState.centerX = (e.touches[0].clientX + e.touches[1].clientX) * 0.5 - leftX;
  160667. timeline._touchState.spanX = Math.abs(e.touches[0].clientX - e.touches[1].clientX);
  160668. } else {
  160669. timeline._touchMode = timelineTouchMode.ignore;
  160670. }
  160671. };
  160672. }
  160673. function createTouchEndCallback(timeline) {
  160674. return function(e) {
  160675. var len = e.touches.length, leftX = timeline._topDiv.getBoundingClientRect().left;
  160676. if (timeline._touchMode === timelineTouchMode.singleTap) {
  160677. timeline._touchMode = timelineTouchMode.scrub;
  160678. timeline._onTouchMove(e);
  160679. } else if (timeline._touchMode === timelineTouchMode.scrub) {
  160680. timeline._onTouchMove(e);
  160681. }
  160682. timeline._mouseMode = timelineMouseMode.touchOnly;
  160683. if (len !== 1) {
  160684. timeline._touchMode = (len > 0) ? timelineTouchMode.ignore : timelineTouchMode.none;
  160685. } else if (timeline._touchMode === timelineTouchMode.slideZoom) {
  160686. timeline._touchState.centerX = e.touches[0].clientX - leftX;
  160687. }
  160688. if (timeline._scrubElement) {
  160689. timeline._scrubElement.style.backgroundPosition = '0 0';
  160690. }
  160691. };
  160692. }
  160693. function createTouchMoveCallback(timeline) {
  160694. return function(e) {
  160695. var dx, x, len, newCenter, newSpan, newStartTime, zoom = 1, leftX = timeline._topDiv.getBoundingClientRect().left;
  160696. if (timeline._touchMode === timelineTouchMode.singleTap) {
  160697. timeline._touchMode = timelineTouchMode.slideZoom;
  160698. }
  160699. timeline._mouseMode = timelineMouseMode.touchOnly;
  160700. if (timeline._touchMode === timelineTouchMode.scrub) {
  160701. e.preventDefault();
  160702. if (e.changedTouches.length === 1) {
  160703. x = e.changedTouches[0].clientX - leftX;
  160704. if ((x >= 0) && (x <= timeline._topDiv.clientWidth)) {
  160705. timeline._setTimeBarTime(x, x * timeline._timeBarSecondsSpan / timeline._topDiv.clientWidth);
  160706. }
  160707. }
  160708. } else if (timeline._touchMode === timelineTouchMode.slideZoom) {
  160709. len = e.touches.length;
  160710. if (len === 2) {
  160711. newCenter = (e.touches[0].clientX + e.touches[1].clientX) * 0.5 - leftX;
  160712. newSpan = Math.abs(e.touches[0].clientX - e.touches[1].clientX);
  160713. } else if (len === 1) {
  160714. newCenter = e.touches[0].clientX - leftX;
  160715. newSpan = 0;
  160716. }
  160717. if (defined(newCenter)) {
  160718. if ((newSpan > 0) && (timeline._touchState.spanX > 0)) {
  160719. // Zoom and slide
  160720. zoom = (timeline._touchState.spanX / newSpan);
  160721. newStartTime = JulianDate.addSeconds(timeline._startJulian, ((timeline._touchState.centerX * timeline._timeBarSecondsSpan) - (newCenter * timeline._timeBarSecondsSpan * zoom)) / timeline._topDiv.clientWidth, new JulianDate());
  160722. } else {
  160723. // Slide to newCenter
  160724. dx = timeline._touchState.centerX - newCenter;
  160725. newStartTime = JulianDate.addSeconds(timeline._startJulian, dx * timeline._timeBarSecondsSpan / timeline._topDiv.clientWidth, new JulianDate());
  160726. }
  160727. timeline.zoomTo(newStartTime, JulianDate.addSeconds(newStartTime, timeline._timeBarSecondsSpan * zoom, new JulianDate()));
  160728. timeline._touchState.centerX = newCenter;
  160729. timeline._touchState.spanX = newSpan;
  160730. }
  160731. }
  160732. };
  160733. }
  160734. /**
  160735. * Resizes the widget to match the container size.
  160736. */
  160737. Timeline.prototype.resize = function() {
  160738. var width = this.container.clientWidth;
  160739. var height = this.container.clientHeight;
  160740. if (width === this._lastWidth && height === this._lastHeight) {
  160741. return;
  160742. }
  160743. this._trackContainer.style.height = height + 'px';
  160744. var trackListHeight = 1;
  160745. this._trackList.forEach(function(track) {
  160746. trackListHeight += track.height;
  160747. });
  160748. this._trackListEle.style.height = trackListHeight.toString() + 'px';
  160749. this._trackListEle.width = this._trackListEle.clientWidth;
  160750. this._trackListEle.height = trackListHeight;
  160751. this._makeTics();
  160752. this._lastXPos = undefined;
  160753. this._lastWidth = width;
  160754. this._lastHeight = height;
  160755. };
  160756. return Timeline;
  160757. });
  160758. /*global define*/
  160759. define('Widgets/VRButton/VRButtonViewModel',[
  160760. '../../Core/defaultValue',
  160761. '../../Core/defined',
  160762. '../../Core/defineProperties',
  160763. '../../Core/destroyObject',
  160764. '../../Core/DeveloperError',
  160765. '../../Core/Fullscreen',
  160766. '../../ThirdParty/knockout',
  160767. '../../ThirdParty/NoSleep',
  160768. '../createCommand',
  160769. '../getElement'
  160770. ], function(
  160771. defaultValue,
  160772. defined,
  160773. defineProperties,
  160774. destroyObject,
  160775. DeveloperError,
  160776. Fullscreen,
  160777. knockout,
  160778. NoSleep,
  160779. createCommand,
  160780. getElement) {
  160781. 'use strict';
  160782. function lockScreen(orientation) {
  160783. var locked = false;
  160784. var screen = window.screen;
  160785. if (defined(screen)) {
  160786. if (defined(screen.lockOrientation)) {
  160787. locked = screen.lockOrientation(orientation);
  160788. } else if (defined(screen.mozLockOrientation)) {
  160789. locked = screen.mozLockOrientation(orientation);
  160790. } else if (defined(screen.msLockOrientation)) {
  160791. locked = screen.msLockOrientation(orientation);
  160792. } else if (defined(screen.orientation && screen.orientation.lock)) {
  160793. locked = screen.orientation.lock(orientation);
  160794. }
  160795. }
  160796. return locked;
  160797. }
  160798. function unlockScreen() {
  160799. var screen = window.screen;
  160800. if (defined(screen)) {
  160801. if (defined(screen.unlockOrientation)) {
  160802. screen.unlockOrientation();
  160803. } else if (defined(screen.mozUnlockOrientation)) {
  160804. screen.mozUnlockOrientation();
  160805. } else if (defined(screen.msUnlockOrientation)) {
  160806. screen.msUnlockOrientation();
  160807. } else if (defined(screen.orientation && screen.orientation.unlock)) {
  160808. screen.orientation.unlock();
  160809. }
  160810. }
  160811. }
  160812. function toggleVR(viewModel, scene, isVRMode) {
  160813. if (isVRMode()) {
  160814. scene.useWebVR = false;
  160815. if (viewModel._locked) {
  160816. unlockScreen();
  160817. viewModel._locked = false;
  160818. }
  160819. viewModel._noSleep.disable();
  160820. Fullscreen.exitFullscreen();
  160821. isVRMode(false);
  160822. } else {
  160823. if (!Fullscreen.fullscreen) {
  160824. Fullscreen.requestFullscreen(viewModel._vrElement);
  160825. }
  160826. viewModel._noSleep.enable();
  160827. if (!viewModel._locked) {
  160828. viewModel._locked = lockScreen('landscape');
  160829. }
  160830. scene.useWebVR = true;
  160831. isVRMode(true);
  160832. }
  160833. }
  160834. /**
  160835. * The view model for {@link VRButton}.
  160836. * @alias VRButtonViewModel
  160837. * @constructor
  160838. *
  160839. * @param {Scene} scene The scene.
  160840. * @param {Element|String} [vrElement=document.body] The element or id to be placed into VR mode.
  160841. */
  160842. function VRButtonViewModel(scene, vrElement) {
  160843. if (!defined(scene)) {
  160844. throw new DeveloperError('scene is required.');
  160845. }
  160846. var that = this;
  160847. var isEnabled = knockout.observable(Fullscreen.enabled);
  160848. var isVRMode = knockout.observable(false);
  160849. /**
  160850. * Gets whether or not VR mode is active.
  160851. *
  160852. * @type {Boolean}
  160853. */
  160854. this.isVRMode = undefined;
  160855. knockout.defineProperty(this, 'isVRMode', {
  160856. get : function() {
  160857. return isVRMode();
  160858. }
  160859. });
  160860. /**
  160861. * Gets or sets whether or not VR functionality should be enabled.
  160862. *
  160863. * @type {Boolean}
  160864. * @see Fullscreen.enabled
  160865. */
  160866. this.isVREnabled = undefined;
  160867. knockout.defineProperty(this, 'isVREnabled', {
  160868. get : function() {
  160869. return isEnabled();
  160870. },
  160871. set : function(value) {
  160872. isEnabled(value && Fullscreen.enabled);
  160873. }
  160874. });
  160875. /**
  160876. * Gets the tooltip. This property is observable.
  160877. *
  160878. * @type {String}
  160879. */
  160880. this.tooltip = undefined;
  160881. knockout.defineProperty(this, 'tooltip', function() {
  160882. if (!isEnabled()) {
  160883. return 'VR mode is unavailable';
  160884. }
  160885. return isVRMode() ? 'Exit VR mode' : 'Enter VR mode';
  160886. });
  160887. this._locked = false;
  160888. this._noSleep = new NoSleep();
  160889. this._command = createCommand(function() {
  160890. toggleVR(that, scene, isVRMode);
  160891. }, knockout.getObservable(this, 'isVREnabled'));
  160892. this._vrElement = defaultValue(getElement(vrElement), document.body);
  160893. this._callback = function() {
  160894. if (!Fullscreen.fullscreen && isVRMode()) {
  160895. scene.useWebVR = false;
  160896. if (that._locked) {
  160897. unlockScreen();
  160898. that._locked = false;
  160899. }
  160900. that._noSleep.disable();
  160901. isVRMode(false);
  160902. }
  160903. };
  160904. document.addEventListener(Fullscreen.changeEventName, this._callback);
  160905. }
  160906. defineProperties(VRButtonViewModel.prototype, {
  160907. /**
  160908. * Gets or sets the HTML element to place into VR mode when the
  160909. * corresponding button is pressed.
  160910. * @memberof VRButtonViewModel.prototype
  160911. *
  160912. * @type {Element}
  160913. */
  160914. vrElement : {
  160915. //TODO:@exception {DeveloperError} value must be a valid HTML Element.
  160916. get : function() {
  160917. return this._vrElement;
  160918. },
  160919. set : function(value) {
  160920. if (!(value instanceof Element)) {
  160921. throw new DeveloperError('value must be a valid Element.');
  160922. }
  160923. this._vrElement = value;
  160924. }
  160925. },
  160926. /**
  160927. * Gets the Command to toggle VR mode.
  160928. * @memberof VRButtonViewModel.prototype
  160929. *
  160930. * @type {Command}
  160931. */
  160932. command : {
  160933. get : function() {
  160934. return this._command;
  160935. }
  160936. }
  160937. });
  160938. /**
  160939. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  160940. */
  160941. VRButtonViewModel.prototype.isDestroyed = function() {
  160942. return false;
  160943. };
  160944. /**
  160945. * Destroys the view model. Should be called to
  160946. * properly clean up the view model when it is no longer needed.
  160947. */
  160948. VRButtonViewModel.prototype.destroy = function() {
  160949. destroyObject(this);
  160950. };
  160951. return VRButtonViewModel;
  160952. });
  160953. /*global define*/
  160954. define('Widgets/VRButton/VRButton',[
  160955. '../../Core/defined',
  160956. '../../Core/defineProperties',
  160957. '../../Core/destroyObject',
  160958. '../../Core/DeveloperError',
  160959. '../../ThirdParty/knockout',
  160960. '../getElement',
  160961. './VRButtonViewModel'
  160962. ], function(
  160963. defined,
  160964. defineProperties,
  160965. destroyObject,
  160966. DeveloperError,
  160967. knockout,
  160968. getElement,
  160969. VRButtonViewModel) {
  160970. 'use strict';
  160971. var enterVRPath = 'M 5.3125 6.375 C 4.008126 6.375 2.96875 7.4141499 2.96875 8.71875 L 2.96875 19.5 C 2.96875 20.8043 4.008126 21.875 5.3125 21.875 L 13.65625 21.875 C 13.71832 20.0547 14.845166 18.59375 16.21875 18.59375 C 17.592088 18.59375 18.71881 20.0552 18.78125 21.875 L 27.09375 21.875 C 28.398125 21.875 29.4375 20.8043 29.4375 19.5 L 29.4375 8.71875 C 29.4375 7.4141499 28.398125 6.375 27.09375 6.375 L 5.3125 6.375 z M 9.625 10.4375 C 11.55989 10.4375 13.125 12.03385 13.125 13.96875 C 13.125 15.90365 11.55989 17.46875 9.625 17.46875 C 7.69011 17.46875 6.125 15.90365 6.125 13.96875 C 6.125 12.03385 7.69011 10.4375 9.625 10.4375 z M 22.46875 10.4375 C 24.40364 10.4375 25.96875 12.03385 25.96875 13.96875 C 25.96875 15.90365 24.40364 17.46875 22.46875 17.46875 C 20.53386 17.46875 18.96875 15.90365 18.96875 13.96875 C 18.96875 12.03385 20.53386 10.4375 22.46875 10.4375 z';
  160972. var exitVRPath = 'M 25.770585,2.4552065 C 15.72282,13.962707 10.699956,19.704407 8.1768352,22.580207 c -1.261561,1.4379 -1.902282,2.1427 -2.21875,2.5 -0.141624,0.1599 -0.208984,0.2355 -0.25,0.2813 l 0.6875,0.75 c 10e-5,-10e-5 0.679191,0.727 0.6875,0.7187 0.01662,-0.016 0.02451,-0.024 0.03125,-0.031 0.01348,-0.014 0.04013,-0.038 0.0625,-0.062 0.04474,-0.05 0.120921,-0.1315 0.28125,-0.3126 0.320657,-0.3619 0.956139,-1.0921 2.2187499,-2.5312 2.5252219,-2.8781 7.5454589,-8.6169 17.5937499,-20.1250005 l -1.5,-1.3125 z m -20.5624998,3.9063 c -1.304375,0 -2.34375,1.0391 -2.34375,2.3437 l 0,10.8125005 c 0,1.3043 1.039375,2.375 2.34375,2.375 l 2.25,0 c 1.9518039,-2.2246 7.4710958,-8.5584 13.5624998,-15.5312005 l -15.8124998,0 z m 21.1249998,0 c -1.855467,2.1245 -2.114296,2.4005 -3.59375,4.0936995 1.767282,0.1815 3.15625,1.685301 3.15625,3.500001 0,1.9349 -1.56511,3.5 -3.5,3.5 -1.658043,0 -3.043426,-1.1411 -3.40625,-2.6875 -1.089617,1.2461 -2.647139,2.9988 -3.46875,3.9375 0.191501,-0.062 0.388502,-0.094 0.59375,-0.094 1.373338,0 2.50006,1.4614 2.5625,3.2812 l 8.3125,0 c 1.304375,0 2.34375,-1.0707 2.34375,-2.375 l 0,-10.8125005 c 0,-1.3046 -1.039375,-2.3437 -2.34375,-2.3437 l -0.65625,0 z M 9.5518351,10.423906 c 1.9348899,0 3.4999999,1.596401 3.4999999,3.531301 0,1.9349 -1.56511,3.5 -3.4999999,3.5 -1.9348899,0 -3.4999999,-1.5651 -3.4999999,-3.5 0,-1.9349 1.56511,-3.531301 3.4999999,-3.531301 z m 4.2187499,10.312601 c -0.206517,0.2356 -0.844218,0.9428 -1.03125,1.1562 l 0.8125,0 c 0.01392,-0.4081 0.107026,-0.7968 0.21875,-1.1562 z';
  160973. /**
  160974. * A single button widget for toggling vr mode.
  160975. *
  160976. * @alias VRButton
  160977. * @constructor
  160978. *
  160979. * @param {Element|String} container The DOM element or ID that will contain the widget.
  160980. * @param {Scene} scene The scene.
  160981. * @param {Element|String} [vrElement=document.body] The element or id to be placed into vr mode.
  160982. *
  160983. * @exception {DeveloperError} Element with id "container" does not exist in the document.
  160984. */
  160985. function VRButton(container, scene, vrElement) {
  160986. if (!defined(container)) {
  160987. throw new DeveloperError('container is required.');
  160988. }
  160989. if (!defined(scene)) {
  160990. throw new DeveloperError('scene is required.');
  160991. }
  160992. container = getElement(container);
  160993. var viewModel = new VRButtonViewModel(scene, vrElement);
  160994. viewModel._exitVRPath = exitVRPath;
  160995. viewModel._enterVRPath = enterVRPath;
  160996. var element = document.createElement('button');
  160997. element.type = 'button';
  160998. element.className = 'cesium-button cesium-vrButton';
  160999. element.setAttribute('data-bind', '\
  161000. attr: { title: tooltip },\
  161001. click: command,\
  161002. enable: isVREnabled,\
  161003. cesiumSvgPath: { path: isVRMode ? _exitVRPath : _enterVRPath, width: 32, height: 32 }');
  161004. container.appendChild(element);
  161005. knockout.applyBindings(viewModel, element);
  161006. this._container = container;
  161007. this._viewModel = viewModel;
  161008. this._element = element;
  161009. }
  161010. defineProperties(VRButton.prototype, {
  161011. /**
  161012. * Gets the parent container.
  161013. * @memberof VRButton.prototype
  161014. *
  161015. * @type {Element}
  161016. */
  161017. container : {
  161018. get : function() {
  161019. return this._container;
  161020. }
  161021. },
  161022. /**
  161023. * Gets the view model.
  161024. * @memberof VRButton.prototype
  161025. *
  161026. * @type {VRButtonViewModel}
  161027. */
  161028. viewModel : {
  161029. get : function() {
  161030. return this._viewModel;
  161031. }
  161032. }
  161033. });
  161034. /**
  161035. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  161036. */
  161037. VRButton.prototype.isDestroyed = function() {
  161038. return false;
  161039. };
  161040. /**
  161041. * Destroys the widget. Should be called if permanently
  161042. * removing the widget from layout.
  161043. */
  161044. VRButton.prototype.destroy = function() {
  161045. this._viewModel.destroy();
  161046. knockout.cleanNode(this._element);
  161047. this._container.removeChild(this._element);
  161048. return destroyObject(this);
  161049. };
  161050. return VRButton;
  161051. });
  161052. /*global define*/
  161053. define('Widgets/Viewer/Viewer',[
  161054. '../../Core/BoundingSphere',
  161055. '../../Core/Cartesian3',
  161056. '../../Core/defaultValue',
  161057. '../../Core/defined',
  161058. '../../Core/defineProperties',
  161059. '../../Core/destroyObject',
  161060. '../../Core/DeveloperError',
  161061. '../../Core/EventHelper',
  161062. '../../Core/isArray',
  161063. '../../Core/Matrix4',
  161064. '../../Core/Rectangle',
  161065. '../../Core/ScreenSpaceEventType',
  161066. '../../DataSources/BoundingSphereState',
  161067. '../../DataSources/ConstantPositionProperty',
  161068. '../../DataSources/DataSourceCollection',
  161069. '../../DataSources/DataSourceDisplay',
  161070. '../../DataSources/Entity',
  161071. '../../DataSources/EntityView',
  161072. '../../DataSources/Property',
  161073. '../../Scene/ImageryLayer',
  161074. '../../Scene/SceneMode',
  161075. '../../ThirdParty/knockout',
  161076. '../../ThirdParty/when',
  161077. '../Animation/Animation',
  161078. '../Animation/AnimationViewModel',
  161079. '../BaseLayerPicker/BaseLayerPicker',
  161080. '../BaseLayerPicker/createDefaultImageryProviderViewModels',
  161081. '../BaseLayerPicker/createDefaultTerrainProviderViewModels',
  161082. '../CesiumWidget/CesiumWidget',
  161083. '../ClockViewModel',
  161084. '../FullscreenButton/FullscreenButton',
  161085. '../Geocoder/Geocoder',
  161086. '../getElement',
  161087. '../HomeButton/HomeButton',
  161088. '../InfoBox/InfoBox',
  161089. '../NavigationHelpButton/NavigationHelpButton',
  161090. '../SceneModePicker/SceneModePicker',
  161091. '../SelectionIndicator/SelectionIndicator',
  161092. '../subscribeAndEvaluate',
  161093. '../Timeline/Timeline',
  161094. '../VRButton/VRButton'
  161095. ], function(
  161096. BoundingSphere,
  161097. Cartesian3,
  161098. defaultValue,
  161099. defined,
  161100. defineProperties,
  161101. destroyObject,
  161102. DeveloperError,
  161103. EventHelper,
  161104. isArray,
  161105. Matrix4,
  161106. Rectangle,
  161107. ScreenSpaceEventType,
  161108. BoundingSphereState,
  161109. ConstantPositionProperty,
  161110. DataSourceCollection,
  161111. DataSourceDisplay,
  161112. Entity,
  161113. EntityView,
  161114. Property,
  161115. ImageryLayer,
  161116. SceneMode,
  161117. knockout,
  161118. when,
  161119. Animation,
  161120. AnimationViewModel,
  161121. BaseLayerPicker,
  161122. createDefaultImageryProviderViewModels,
  161123. createDefaultTerrainProviderViewModels,
  161124. CesiumWidget,
  161125. ClockViewModel,
  161126. FullscreenButton,
  161127. Geocoder,
  161128. getElement,
  161129. HomeButton,
  161130. InfoBox,
  161131. NavigationHelpButton,
  161132. SceneModePicker,
  161133. SelectionIndicator,
  161134. subscribeAndEvaluate,
  161135. Timeline,
  161136. VRButton) {
  161137. 'use strict';
  161138. var boundingSphereScratch = new BoundingSphere();
  161139. function onTimelineScrubfunction(e) {
  161140. var clock = e.clock;
  161141. clock.currentTime = e.timeJulian;
  161142. clock.shouldAnimate = false;
  161143. }
  161144. function pickEntity(viewer, e) {
  161145. var picked = viewer.scene.pick(e.position);
  161146. if (defined(picked)) {
  161147. var id = defaultValue(picked.id, picked.primitive.id);
  161148. if (id instanceof Entity) {
  161149. return id;
  161150. }
  161151. }
  161152. // No regular entity picked. Try picking features from imagery layers.
  161153. if (defined(viewer.scene.globe)) {
  161154. return pickImageryLayerFeature(viewer, e.position);
  161155. }
  161156. }
  161157. function trackDataSourceClock(timeline, clock, dataSource) {
  161158. if (defined(dataSource)) {
  161159. var dataSourceClock = dataSource.clock;
  161160. if (defined(dataSourceClock)) {
  161161. dataSourceClock.getValue(clock);
  161162. if (defined(timeline)) {
  161163. timeline.updateFromClock();
  161164. timeline.zoomTo(dataSourceClock.startTime, dataSourceClock.stopTime);
  161165. }
  161166. }
  161167. }
  161168. }
  161169. var cartesian3Scratch = new Cartesian3();
  161170. function pickImageryLayerFeature(viewer, windowPosition) {
  161171. var scene = viewer.scene;
  161172. var pickRay = scene.camera.getPickRay(windowPosition);
  161173. var imageryLayerFeaturePromise = scene.imageryLayers.pickImageryLayerFeatures(pickRay, scene);
  161174. if (!defined(imageryLayerFeaturePromise)) {
  161175. return;
  161176. }
  161177. // Imagery layer feature picking is asynchronous, so put up a message while loading.
  161178. var loadingMessage = new Entity({
  161179. id : 'Loading...',
  161180. description : 'Loading feature information...'
  161181. });
  161182. when(imageryLayerFeaturePromise, function(features) {
  161183. // Has this async pick been superseded by a later one?
  161184. if (viewer.selectedEntity !== loadingMessage) {
  161185. return;
  161186. }
  161187. if (!defined(features) || features.length === 0) {
  161188. viewer.selectedEntity = createNoFeaturesEntity();
  161189. return;
  161190. }
  161191. // Select the first feature.
  161192. var feature = features[0];
  161193. var entity = new Entity({
  161194. id : feature.name,
  161195. description : feature.description
  161196. });
  161197. if (defined(feature.position)) {
  161198. var ecfPosition = viewer.scene.globe.ellipsoid.cartographicToCartesian(feature.position, cartesian3Scratch);
  161199. entity.position = new ConstantPositionProperty(ecfPosition);
  161200. }
  161201. viewer.selectedEntity = entity;
  161202. }, function() {
  161203. // Has this async pick been superseded by a later one?
  161204. if (viewer.selectedEntity !== loadingMessage) {
  161205. return;
  161206. }
  161207. viewer.selectedEntity = createNoFeaturesEntity();
  161208. });
  161209. return loadingMessage;
  161210. }
  161211. function createNoFeaturesEntity() {
  161212. return new Entity({
  161213. id : 'None',
  161214. description : 'No features found.'
  161215. });
  161216. }
  161217. function enableVRUI(viewer, enabled) {
  161218. var geocoder = viewer._geocoder;
  161219. var homeButton = viewer._homeButton;
  161220. var sceneModePicker = viewer._sceneModePicker;
  161221. var baseLayerPicker = viewer._baseLayerPicker;
  161222. var animation = viewer._animation;
  161223. var timeline = viewer._timeline;
  161224. var fullscreenButton = viewer._fullscreenButton;
  161225. var infoBox = viewer._infoBox;
  161226. var selectionIndicator = viewer._selectionIndicator;
  161227. var visibility = enabled ? 'hidden' : 'visible';
  161228. if (defined(geocoder)) {
  161229. geocoder.container.style.visibility = visibility;
  161230. }
  161231. if (defined(homeButton)) {
  161232. homeButton.container.style.visibility = visibility;
  161233. }
  161234. if(defined(sceneModePicker)) {
  161235. sceneModePicker.container.style.visibility = visibility;
  161236. }
  161237. if(defined(baseLayerPicker)) {
  161238. baseLayerPicker.container.style.visibility = visibility;
  161239. }
  161240. if (defined(animation)) {
  161241. animation.container.style.visibility = visibility;
  161242. }
  161243. if (defined(timeline)) {
  161244. timeline.container.style.visibility = visibility;
  161245. }
  161246. if (defined(fullscreenButton) && fullscreenButton.viewModel.isFullscreenEnabled) {
  161247. fullscreenButton.container.style.visibility = visibility;
  161248. }
  161249. if (defined(infoBox)) {
  161250. infoBox.container.style.visibility = visibility;
  161251. }
  161252. if (defined(selectionIndicator)) {
  161253. selectionIndicator.container.style.visibility = visibility;
  161254. }
  161255. if (viewer._container) {
  161256. var right = enabled || !defined(fullscreenButton) ? 0 : fullscreenButton.container.clientWidth;
  161257. viewer._vrButton.container.style.right = right + 'px';
  161258. viewer.forceResize();
  161259. }
  161260. }
  161261. /**
  161262. * A base widget for building applications. It composites all of the standard Cesium widgets into one reusable package.
  161263. * The widget can always be extended by using mixins, which add functionality useful for a variety of applications.
  161264. *
  161265. * @alias Viewer
  161266. * @constructor
  161267. *
  161268. * @param {Element|String} container The DOM element or ID that will contain the widget.
  161269. * @param {Object} [options] Object with the following properties:
  161270. * @param {Boolean} [options.animation=true] If set to false, the Animation widget will not be created.
  161271. * @param {Boolean} [options.baseLayerPicker=true] If set to false, the BaseLayerPicker widget will not be created.
  161272. * @param {Boolean} [options.fullscreenButton=true] If set to false, the FullscreenButton widget will not be created.
  161273. * @param {Boolean} [options.vrButton=false] If set to true, the VRButton widget will be created.
  161274. * @param {Boolean} [options.geocoder=true] If set to false, the Geocoder widget will not be created.
  161275. * @param {Boolean} [options.homeButton=true] If set to false, the HomeButton widget will not be created.
  161276. * @param {Boolean} [options.infoBox=true] If set to false, the InfoBox widget will not be created.
  161277. * @param {Boolean} [options.sceneModePicker=true] If set to false, the SceneModePicker widget will not be created.
  161278. * @param {Boolean} [options.selectionIndicator=true] If set to false, the SelectionIndicator widget will not be created.
  161279. * @param {Boolean} [options.timeline=true] If set to false, the Timeline widget will not be created.
  161280. * @param {Boolean} [options.navigationHelpButton=true] If set to false, the navigation help button will not be created.
  161281. * @param {Boolean} [options.navigationInstructionsInitiallyVisible=true] True if the navigation instructions should initially be visible, or false if the should not be shown until the user explicitly clicks the button.
  161282. * @param {Boolean} [options.scene3DOnly=false] When <code>true</code>, each geometry instance will only be rendered in 3D to save GPU memory.
  161283. * @param {Clock} [options.clock=new Clock()] The clock to use to control current time.
  161284. * @param {ProviderViewModel} [options.selectedImageryProviderViewModel] The view model for the current base imagery layer, if not supplied the first available base layer is used. This value is only valid if options.baseLayerPicker is set to true.
  161285. * @param {ProviderViewModel[]} [options.imageryProviderViewModels=createDefaultImageryProviderViewModels()] The array of ProviderViewModels to be selectable from the BaseLayerPicker. This value is only valid if options.baseLayerPicker is set to true.
  161286. * @param {ProviderViewModel} [options.selectedTerrainProviderViewModel] The view model for the current base terrain layer, if not supplied the first available base layer is used. This value is only valid if options.baseLayerPicker is set to true.
  161287. * @param {ProviderViewModel[]} [options.terrainProviderViewModels=createDefaultTerrainProviderViewModels()] The array of ProviderViewModels to be selectable from the BaseLayerPicker. This value is only valid if options.baseLayerPicker is set to true.
  161288. * @param {ImageryProvider} [options.imageryProvider=new BingMapsImageryProvider()] The imagery provider to use. This value is only valid if options.baseLayerPicker is set to false.
  161289. * @param {TerrainProvider} [options.terrainProvider=new EllipsoidTerrainProvider()] The terrain provider to use
  161290. * @param {SkyBox} [options.skyBox] The skybox used to render the stars. When <code>undefined</code>, the default stars are used.
  161291. * @param {SkyAtmosphere} [options.skyAtmosphere] Blue sky, and the glow around the Earth's limb. Set to <code>false</code> to turn it off.
  161292. * @param {Element|String} [options.fullscreenElement=document.body] The element or id to be placed into fullscreen mode when the full screen button is pressed.
  161293. * @param {Boolean} [options.useDefaultRenderLoop=true] True if this widget should control the render loop, false otherwise.
  161294. * @param {Number} [options.targetFrameRate] The target frame rate when using the default render loop.
  161295. * @param {Boolean} [options.showRenderLoopErrors=true] If true, this widget will automatically display an HTML panel to the user containing the error, if a render loop error occurs.
  161296. * @param {Boolean} [options.automaticallyTrackDataSourceClocks=true] If true, this widget will automatically track the clock settings of newly added DataSources, updating if the DataSource's clock changes. Set this to false if you want to configure the clock independently.
  161297. * @param {Object} [options.contextOptions] Context and WebGL creation properties corresponding to <code>options</code> passed to {@link Scene}.
  161298. * @param {SceneMode} [options.sceneMode=SceneMode.SCENE3D] The initial scene mode.
  161299. * @param {MapProjection} [options.mapProjection=new GeographicProjection()] The map projection to use in 2D and Columbus View modes.
  161300. * @param {Globe} [options.globe=new Globe(mapProjection.ellipsoid)] The globe to use in the scene. If set to <code>false</code>, no globe will be added.
  161301. * @param {Boolean} [options.orderIndependentTranslucency=true] If true and the configuration supports it, use order independent translucency.
  161302. * @param {Element|String} [options.creditContainer] The DOM element or ID that will contain the {@link CreditDisplay}. If not specified, the credits are added to the bottom of the widget itself.
  161303. * @param {DataSourceCollection} [options.dataSources=new DataSourceCollection()] The collection of data sources visualized by the widget. If this parameter is provided,
  161304. * the instance is assumed to be owned by the caller and will not be destroyed when the viewer is destroyed.
  161305. * @param {Number} [options.terrainExaggeration=1.0] A scalar used to exaggerate the terrain. Note that terrain exaggeration will not modify any other primitive as they are positioned relative to the ellipsoid.
  161306. * @param {Boolean} [options.shadows=false] Determines if shadows are cast by the sun.
  161307. * @param {ShadowMode} [options.terrainShadows=ShadowMode.RECEIVE_ONLY] Determines if the terrain casts or receives shadows from the sun.
  161308. * @param {MapMode2D} [options.mapMode2D=MapMode2D.INFINITE_SCROLL] Determines if the 2D map is rotatable or can be scrolled infinitely in the horizontal direction.
  161309. *
  161310. * @exception {DeveloperError} Element with id "container" does not exist in the document.
  161311. * @exception {DeveloperError} options.imageryProvider is not available when using the BaseLayerPicker widget, specify options.selectedImageryProviderViewModel instead.
  161312. * @exception {DeveloperError} options.terrainProvider is not available when using the BaseLayerPicker widget, specify options.selectedTerrainProviderViewModel instead.
  161313. * @exception {DeveloperError} options.selectedImageryProviderViewModel is not available when not using the BaseLayerPicker widget, specify options.imageryProvider instead.
  161314. * @exception {DeveloperError} options.selectedTerrainProviderViewModel is not available when not using the BaseLayerPicker widget, specify options.terrainProvider instead.
  161315. *
  161316. * @see Animation
  161317. * @see BaseLayerPicker
  161318. * @see CesiumWidget
  161319. * @see FullscreenButton
  161320. * @see HomeButton
  161321. * @see SceneModePicker
  161322. * @see Timeline
  161323. * @see viewerDragDropMixin
  161324. *
  161325. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Hello%20World.html|Cesium Sandcastle Hello World Demo}
  161326. *
  161327. * @example
  161328. * //Initialize the viewer widget with several custom options and mixins.
  161329. * var viewer = new Cesium.Viewer('cesiumContainer', {
  161330. * //Start in Columbus Viewer
  161331. * sceneMode : Cesium.SceneMode.COLUMBUS_VIEW,
  161332. * //Use standard Cesium terrain
  161333. * terrainProvider : new Cesium.CesiumTerrainProvider({
  161334. * url : 'https://assets.agi.com/stk-terrain/world'
  161335. * }),
  161336. * //Hide the base layer picker
  161337. * baseLayerPicker : false,
  161338. * //Use OpenStreetMaps
  161339. * imageryProvider : Cesium.createOpenStreetMapImageryProvider({
  161340. * url : 'https://a.tile.openstreetmap.org/'
  161341. * }),
  161342. * // Use high-res stars downloaded from https://github.com/AnalyticalGraphicsInc/cesium-assets
  161343. * skyBox : new Cesium.SkyBox({
  161344. * sources : {
  161345. * positiveX : 'stars/TychoSkymapII.t3_08192x04096_80_px.jpg',
  161346. * negativeX : 'stars/TychoSkymapII.t3_08192x04096_80_mx.jpg',
  161347. * positiveY : 'stars/TychoSkymapII.t3_08192x04096_80_py.jpg',
  161348. * negativeY : 'stars/TychoSkymapII.t3_08192x04096_80_my.jpg',
  161349. * positiveZ : 'stars/TychoSkymapII.t3_08192x04096_80_pz.jpg',
  161350. * negativeZ : 'stars/TychoSkymapII.t3_08192x04096_80_mz.jpg'
  161351. * }
  161352. * }),
  161353. * // Show Columbus View map with Web Mercator projection
  161354. * mapProjection : new Cesium.WebMercatorProjection()
  161355. * });
  161356. *
  161357. * //Add basic drag and drop functionality
  161358. * viewer.extend(Cesium.viewerDragDropMixin);
  161359. *
  161360. * //Show a pop-up alert if we encounter an error when processing a dropped file
  161361. * viewer.dropError.addEventListener(function(dropHandler, name, error) {
  161362. * console.log(error);
  161363. * window.alert(error);
  161364. * });
  161365. */
  161366. function Viewer(container, options) {
  161367. if (!defined(container)) {
  161368. throw new DeveloperError('container is required.');
  161369. }
  161370. container = getElement(container);
  161371. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  161372. var createBaseLayerPicker = (!defined(options.globe) || options.globe !== false) &&
  161373. (!defined(options.baseLayerPicker) || options.baseLayerPicker !== false);
  161374. // If using BaseLayerPicker, imageryProvider is an invalid option
  161375. if (createBaseLayerPicker && defined(options.imageryProvider)) {
  161376. throw new DeveloperError('options.imageryProvider is not available when using the BaseLayerPicker widget. \
  161377. Either specify options.selectedImageryProviderViewModel instead or set options.baseLayerPicker to false.');
  161378. }
  161379. // If not using BaseLayerPicker, selectedImageryProviderViewModel is an invalid option
  161380. if (!createBaseLayerPicker && defined(options.selectedImageryProviderViewModel)) {
  161381. throw new DeveloperError('options.selectedImageryProviderViewModel is not available when not using the BaseLayerPicker widget. \
  161382. Either specify options.imageryProvider instead or set options.baseLayerPicker to true.');
  161383. }
  161384. // If using BaseLayerPicker, terrainProvider is an invalid option
  161385. if (createBaseLayerPicker && defined(options.terrainProvider)) {
  161386. throw new DeveloperError('options.terrainProvider is not available when using the BaseLayerPicker widget. \
  161387. Either specify options.selectedTerrainProviderViewModel instead or set options.baseLayerPicker to false.');
  161388. }
  161389. // If not using BaseLayerPicker, selectedTerrainProviderViewModel is an invalid option
  161390. if (!createBaseLayerPicker && defined(options.selectedTerrainProviderViewModel)) {
  161391. throw new DeveloperError('options.selectedTerrainProviderViewModel is not available when not using the BaseLayerPicker widget. \
  161392. Either specify options.terrainProvider instead or set options.baseLayerPicker to true.');
  161393. }
  161394. var that = this;
  161395. var viewerContainer = document.createElement('div');
  161396. viewerContainer.className = 'cesium-viewer';
  161397. container.appendChild(viewerContainer);
  161398. // Cesium widget container
  161399. var cesiumWidgetContainer = document.createElement('div');
  161400. cesiumWidgetContainer.className = 'cesium-viewer-cesiumWidgetContainer';
  161401. viewerContainer.appendChild(cesiumWidgetContainer);
  161402. // Bottom container
  161403. var bottomContainer = document.createElement('div');
  161404. bottomContainer.className = 'cesium-viewer-bottom';
  161405. viewerContainer.appendChild(bottomContainer);
  161406. var scene3DOnly = defaultValue(options.scene3DOnly, false);
  161407. // Cesium widget
  161408. var cesiumWidget = new CesiumWidget(cesiumWidgetContainer, {
  161409. terrainProvider : options.terrainProvider,
  161410. imageryProvider : createBaseLayerPicker ? false : options.imageryProvider,
  161411. clock : options.clock,
  161412. skyBox : options.skyBox,
  161413. skyAtmosphere : options.skyAtmosphere,
  161414. sceneMode : options.sceneMode,
  161415. mapProjection : options.mapProjection,
  161416. globe : options.globe,
  161417. orderIndependentTranslucency : options.orderIndependentTranslucency,
  161418. contextOptions : options.contextOptions,
  161419. useDefaultRenderLoop : options.useDefaultRenderLoop,
  161420. targetFrameRate : options.targetFrameRate,
  161421. showRenderLoopErrors : options.showRenderLoopErrors,
  161422. creditContainer : defined(options.creditContainer) ? options.creditContainer : bottomContainer,
  161423. scene3DOnly : scene3DOnly,
  161424. terrainExaggeration : options.terrainExaggeration,
  161425. shadows : options.shadows,
  161426. terrainShadows : options.terrainShadows,
  161427. mapMode2D : options.mapMode2D
  161428. });
  161429. var dataSourceCollection = options.dataSources;
  161430. var destroyDataSourceCollection = false;
  161431. if (!defined(dataSourceCollection)) {
  161432. dataSourceCollection = new DataSourceCollection();
  161433. destroyDataSourceCollection = true;
  161434. }
  161435. var dataSourceDisplay = new DataSourceDisplay({
  161436. scene : cesiumWidget.scene,
  161437. dataSourceCollection : dataSourceCollection
  161438. });
  161439. var clock = cesiumWidget.clock;
  161440. var clockViewModel = new ClockViewModel(clock);
  161441. var eventHelper = new EventHelper();
  161442. eventHelper.add(clock.onTick, Viewer.prototype._onTick, this);
  161443. eventHelper.add(cesiumWidget.scene.morphStart, Viewer.prototype._clearTrackedObject, this);
  161444. // Selection Indicator
  161445. var selectionIndicator;
  161446. if (!defined(options.selectionIndicator) || options.selectionIndicator !== false) {
  161447. var selectionIndicatorContainer = document.createElement('div');
  161448. selectionIndicatorContainer.className = 'cesium-viewer-selectionIndicatorContainer';
  161449. viewerContainer.appendChild(selectionIndicatorContainer);
  161450. selectionIndicator = new SelectionIndicator(selectionIndicatorContainer, cesiumWidget.scene);
  161451. }
  161452. // Info Box
  161453. var infoBox;
  161454. if (!defined(options.infoBox) || options.infoBox !== false) {
  161455. var infoBoxContainer = document.createElement('div');
  161456. infoBoxContainer.className = 'cesium-viewer-infoBoxContainer';
  161457. viewerContainer.appendChild(infoBoxContainer);
  161458. infoBox = new InfoBox(infoBoxContainer);
  161459. var infoBoxViewModel = infoBox.viewModel;
  161460. eventHelper.add(infoBoxViewModel.cameraClicked, Viewer.prototype._onInfoBoxCameraClicked, this);
  161461. eventHelper.add(infoBoxViewModel.closeClicked, Viewer.prototype._onInfoBoxClockClicked, this);
  161462. }
  161463. // Main Toolbar
  161464. var toolbar = document.createElement('div');
  161465. toolbar.className = 'cesium-viewer-toolbar';
  161466. viewerContainer.appendChild(toolbar);
  161467. // Geocoder
  161468. var geocoder;
  161469. if (!defined(options.geocoder) || options.geocoder !== false) {
  161470. var geocoderContainer = document.createElement('div');
  161471. geocoderContainer.className = 'cesium-viewer-geocoderContainer';
  161472. toolbar.appendChild(geocoderContainer);
  161473. geocoder = new Geocoder({
  161474. container : geocoderContainer,
  161475. scene : cesiumWidget.scene
  161476. });
  161477. // Subscribe to search so that we can clear the trackedEntity when it is clicked.
  161478. eventHelper.add(geocoder.viewModel.search.beforeExecute, Viewer.prototype._clearObjects, this);
  161479. }
  161480. // HomeButton
  161481. var homeButton;
  161482. if (!defined(options.homeButton) || options.homeButton !== false) {
  161483. homeButton = new HomeButton(toolbar, cesiumWidget.scene);
  161484. if (defined(geocoder)) {
  161485. eventHelper.add(homeButton.viewModel.command.afterExecute, function() {
  161486. var viewModel = geocoder.viewModel;
  161487. viewModel.searchText = '';
  161488. if (viewModel.isSearchInProgress) {
  161489. viewModel.search();
  161490. }
  161491. });
  161492. }
  161493. // Subscribe to the home button beforeExecute event so that we can clear the trackedEntity.
  161494. eventHelper.add(homeButton.viewModel.command.beforeExecute, Viewer.prototype._clearTrackedObject, this);
  161495. }
  161496. // SceneModePicker
  161497. // By default, we silently disable the scene mode picker if scene3DOnly is true,
  161498. // but if sceneModePicker is explicitly set to true, throw an error.
  161499. if ((options.sceneModePicker === true) && scene3DOnly) {
  161500. throw new DeveloperError('options.sceneModePicker is not available when options.scene3DOnly is set to true.');
  161501. }
  161502. var sceneModePicker;
  161503. if (!scene3DOnly && (!defined(options.sceneModePicker) || options.sceneModePicker !== false)) {
  161504. sceneModePicker = new SceneModePicker(toolbar, cesiumWidget.scene);
  161505. }
  161506. // BaseLayerPicker
  161507. var baseLayerPicker;
  161508. var baseLayerPickerDropDown;
  161509. if (createBaseLayerPicker) {
  161510. var imageryProviderViewModels = defaultValue(options.imageryProviderViewModels, createDefaultImageryProviderViewModels());
  161511. var terrainProviderViewModels = defaultValue(options.terrainProviderViewModels, createDefaultTerrainProviderViewModels());
  161512. baseLayerPicker = new BaseLayerPicker(toolbar, {
  161513. globe : cesiumWidget.scene.globe,
  161514. imageryProviderViewModels : imageryProviderViewModels,
  161515. selectedImageryProviderViewModel : options.selectedImageryProviderViewModel,
  161516. terrainProviderViewModels : terrainProviderViewModels,
  161517. selectedTerrainProviderViewModel : options.selectedTerrainProviderViewModel
  161518. });
  161519. //Grab the dropdown for resize code.
  161520. var elements = toolbar.getElementsByClassName('cesium-baseLayerPicker-dropDown');
  161521. baseLayerPickerDropDown = elements[0];
  161522. }
  161523. // Navigation Help Button
  161524. var navigationHelpButton;
  161525. if (!defined(options.navigationHelpButton) || options.navigationHelpButton !== false) {
  161526. var showNavHelp = true;
  161527. try {
  161528. //window.localStorage is null if disabled in Firefox or undefined in browsers with implementation
  161529. if (defined(window.localStorage)) {
  161530. var hasSeenNavHelp = window.localStorage.getItem('cesium-hasSeenNavHelp');
  161531. if (defined(hasSeenNavHelp) && Boolean(hasSeenNavHelp)) {
  161532. showNavHelp = false;
  161533. } else {
  161534. window.localStorage.setItem('cesium-hasSeenNavHelp', 'true');
  161535. }
  161536. }
  161537. } catch (e) {
  161538. //Accessing window.localStorage throws if disabled in Chrome
  161539. //window.localStorage.setItem throws if in Safari private browsing mode or in any browser if we are over quota.
  161540. }
  161541. navigationHelpButton = new NavigationHelpButton({
  161542. container : toolbar,
  161543. instructionsInitiallyVisible : defaultValue(options.navigationInstructionsInitiallyVisible, showNavHelp)
  161544. });
  161545. }
  161546. // Animation
  161547. var animation;
  161548. if (!defined(options.animation) || options.animation !== false) {
  161549. var animationContainer = document.createElement('div');
  161550. animationContainer.className = 'cesium-viewer-animationContainer';
  161551. viewerContainer.appendChild(animationContainer);
  161552. animation = new Animation(animationContainer, new AnimationViewModel(clockViewModel));
  161553. }
  161554. // Timeline
  161555. var timeline;
  161556. if (!defined(options.timeline) || options.timeline !== false) {
  161557. var timelineContainer = document.createElement('div');
  161558. timelineContainer.className = 'cesium-viewer-timelineContainer';
  161559. viewerContainer.appendChild(timelineContainer);
  161560. timeline = new Timeline(timelineContainer, clock);
  161561. timeline.addEventListener('settime', onTimelineScrubfunction, false);
  161562. timeline.zoomTo(clock.startTime, clock.stopTime);
  161563. }
  161564. // Fullscreen
  161565. var fullscreenButton;
  161566. var fullscreenSubscription;
  161567. if (!defined(options.fullscreenButton) || options.fullscreenButton !== false) {
  161568. var fullscreenContainer = document.createElement('div');
  161569. fullscreenContainer.className = 'cesium-viewer-fullscreenContainer';
  161570. viewerContainer.appendChild(fullscreenContainer);
  161571. fullscreenButton = new FullscreenButton(fullscreenContainer, options.fullscreenElement);
  161572. //Subscribe to fullscreenButton.viewModel.isFullscreenEnabled so
  161573. //that we can hide/show the button as well as size the timeline.
  161574. fullscreenSubscription = subscribeAndEvaluate(fullscreenButton.viewModel, 'isFullscreenEnabled', function(isFullscreenEnabled) {
  161575. fullscreenContainer.style.display = isFullscreenEnabled ? 'block' : 'none';
  161576. if (defined(timeline)) {
  161577. timeline.container.style.right = fullscreenContainer.clientWidth + 'px';
  161578. timeline.resize();
  161579. }
  161580. });
  161581. }
  161582. // VR
  161583. var vrButton;
  161584. var vrSubscription;
  161585. var vrModeSubscription;
  161586. if (options.vrButton) {
  161587. var vrContainer = document.createElement('div');
  161588. vrContainer.className = 'cesium-viewer-vrContainer';
  161589. viewerContainer.appendChild(vrContainer);
  161590. vrButton = new VRButton(vrContainer, cesiumWidget.scene, options.fullScreenElement);
  161591. vrSubscription = subscribeAndEvaluate(vrButton.viewModel, 'isVREnabled', function(isVREnabled) {
  161592. vrContainer.style.display = isVREnabled ? 'block' : 'none';
  161593. if (defined(fullscreenButton)) {
  161594. vrContainer.style.right = fullscreenContainer.clientWidth + 'px';
  161595. }
  161596. if (defined(timeline)) {
  161597. timeline.container.style.right = vrContainer.clientWidth + 'px';
  161598. timeline.resize();
  161599. }
  161600. });
  161601. vrModeSubscription = subscribeAndEvaluate(vrButton.viewModel, 'isVRMode', function(isVRMode) {
  161602. enableVRUI(that, isVRMode);
  161603. });
  161604. }
  161605. //Assign all properties to this instance. No "this" assignments should
  161606. //take place above this line.
  161607. this._baseLayerPickerDropDown = baseLayerPickerDropDown;
  161608. this._fullscreenSubscription = fullscreenSubscription;
  161609. this._vrSubscription = vrSubscription;
  161610. this._vrModeSubscription = vrModeSubscription;
  161611. this._dataSourceChangedListeners = {};
  161612. this._automaticallyTrackDataSourceClocks = defaultValue(options.automaticallyTrackDataSourceClocks, true);
  161613. this._container = container;
  161614. this._bottomContainer = bottomContainer;
  161615. this._element = viewerContainer;
  161616. this._cesiumWidget = cesiumWidget;
  161617. this._selectionIndicator = selectionIndicator;
  161618. this._infoBox = infoBox;
  161619. this._dataSourceCollection = dataSourceCollection;
  161620. this._destroyDataSourceCollection = destroyDataSourceCollection;
  161621. this._dataSourceDisplay = dataSourceDisplay;
  161622. this._clockViewModel = clockViewModel;
  161623. this._toolbar = toolbar;
  161624. this._homeButton = homeButton;
  161625. this._sceneModePicker = sceneModePicker;
  161626. this._baseLayerPicker = baseLayerPicker;
  161627. this._navigationHelpButton = navigationHelpButton;
  161628. this._animation = animation;
  161629. this._timeline = timeline;
  161630. this._fullscreenButton = fullscreenButton;
  161631. this._vrButton = vrButton;
  161632. this._geocoder = geocoder;
  161633. this._eventHelper = eventHelper;
  161634. this._lastWidth = 0;
  161635. this._lastHeight = 0;
  161636. this._allowDataSourcesToSuspendAnimation = true;
  161637. this._entityView = undefined;
  161638. this._enableInfoOrSelection = defined(infoBox) || defined(selectionIndicator);
  161639. this._clockTrackedDataSource = undefined;
  161640. this._trackedEntity = undefined;
  161641. this._needTrackedEntityUpdate = false;
  161642. this._selectedEntity = undefined;
  161643. this._clockTrackedDataSource = undefined;
  161644. this._forceResize = false;
  161645. this._zoomIsFlight = false;
  161646. this._zoomTarget = undefined;
  161647. this._zoomPromise = undefined;
  161648. this._zoomOptions = undefined;
  161649. knockout.track(this, ['_trackedEntity', '_selectedEntity', '_clockTrackedDataSource']);
  161650. //Listen to data source events in order to track clock changes.
  161651. eventHelper.add(dataSourceCollection.dataSourceAdded, Viewer.prototype._onDataSourceAdded, this);
  161652. eventHelper.add(dataSourceCollection.dataSourceRemoved, Viewer.prototype._onDataSourceRemoved, this);
  161653. // Prior to each render, check if anything needs to be resized.
  161654. eventHelper.add(cesiumWidget.scene.preRender, Viewer.prototype.resize, this);
  161655. eventHelper.add(cesiumWidget.scene.postRender, Viewer.prototype._postRender, this);
  161656. // We need to subscribe to the data sources and collections so that we can clear the
  161657. // tracked object when it is removed from the scene.
  161658. // Subscribe to current data sources
  161659. var dataSourceLength = dataSourceCollection.length;
  161660. for (var i = 0; i < dataSourceLength; i++) {
  161661. this._dataSourceAdded(dataSourceCollection, dataSourceCollection.get(i));
  161662. }
  161663. this._dataSourceAdded(undefined, dataSourceDisplay.defaultDataSource);
  161664. // Hook up events so that we can subscribe to future sources.
  161665. eventHelper.add(dataSourceCollection.dataSourceAdded, Viewer.prototype._dataSourceAdded, this);
  161666. eventHelper.add(dataSourceCollection.dataSourceRemoved, Viewer.prototype._dataSourceRemoved, this);
  161667. // Subscribe to left clicks and zoom to the picked object.
  161668. function pickAndTrackObject(e) {
  161669. var entity = pickEntity(that, e);
  161670. if (defined(entity)) {
  161671. //Only track the entity if it has a valid position at the current time.
  161672. if (Property.getValueOrUndefined(entity.position, that.clock.currentTime)) {
  161673. that.trackedEntity = entity;
  161674. } else {
  161675. that.zoomTo(entity);
  161676. }
  161677. }
  161678. }
  161679. function pickAndSelectObject(e) {
  161680. that.selectedEntity = pickEntity(that, e);
  161681. }
  161682. cesiumWidget.screenSpaceEventHandler.setInputAction(pickAndSelectObject, ScreenSpaceEventType.LEFT_CLICK);
  161683. cesiumWidget.screenSpaceEventHandler.setInputAction(pickAndTrackObject, ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
  161684. }
  161685. defineProperties(Viewer.prototype, {
  161686. /**
  161687. * Gets the parent container.
  161688. * @memberof Viewer.prototype
  161689. * @type {Element}
  161690. * @readonly
  161691. */
  161692. container : {
  161693. get : function() {
  161694. return this._container;
  161695. }
  161696. },
  161697. /**
  161698. * Gets the DOM element for the area at the bottom of the window containing the
  161699. * {@link CreditDisplay} and potentially other things.
  161700. * @memberof Viewer.prototype
  161701. * @type {Element}
  161702. * @readonly
  161703. */
  161704. bottomContainer : {
  161705. get : function() {
  161706. return this._bottomContainer;
  161707. }
  161708. },
  161709. /**
  161710. * Gets the CesiumWidget.
  161711. * @memberof Viewer.prototype
  161712. * @type {CesiumWidget}
  161713. * @readonly
  161714. */
  161715. cesiumWidget : {
  161716. get : function() {
  161717. return this._cesiumWidget;
  161718. }
  161719. },
  161720. /**
  161721. * Gets the selection indicator.
  161722. * @memberof Viewer.prototype
  161723. * @type {SelectionIndicator}
  161724. * @readonly
  161725. */
  161726. selectionIndicator : {
  161727. get : function() {
  161728. return this._selectionIndicator;
  161729. }
  161730. },
  161731. /**
  161732. * Gets the info box.
  161733. * @memberof Viewer.prototype
  161734. * @type {InfoBox}
  161735. * @readonly
  161736. */
  161737. infoBox : {
  161738. get : function() {
  161739. return this._infoBox;
  161740. }
  161741. },
  161742. /**
  161743. * Gets the Geocoder.
  161744. * @memberof Viewer.prototype
  161745. * @type {Geocoder}
  161746. * @readonly
  161747. */
  161748. geocoder : {
  161749. get : function() {
  161750. return this._geocoder;
  161751. }
  161752. },
  161753. /**
  161754. * Gets the HomeButton.
  161755. * @memberof Viewer.prototype
  161756. * @type {HomeButton}
  161757. * @readonly
  161758. */
  161759. homeButton : {
  161760. get : function() {
  161761. return this._homeButton;
  161762. }
  161763. },
  161764. /**
  161765. * Gets the SceneModePicker.
  161766. * @memberof Viewer.prototype
  161767. * @type {SceneModePicker}
  161768. * @readonly
  161769. */
  161770. sceneModePicker : {
  161771. get : function() {
  161772. return this._sceneModePicker;
  161773. }
  161774. },
  161775. /**
  161776. * Gets the BaseLayerPicker.
  161777. * @memberof Viewer.prototype
  161778. * @type {BaseLayerPicker}
  161779. * @readonly
  161780. */
  161781. baseLayerPicker : {
  161782. get : function() {
  161783. return this._baseLayerPicker;
  161784. }
  161785. },
  161786. /**
  161787. * Gets the NavigationHelpButton.
  161788. * @memberof Viewer.prototype
  161789. * @type {NavigationHelpButton}
  161790. * @readonly
  161791. */
  161792. navigationHelpButton : {
  161793. get : function() {
  161794. return this._navigationHelpButton;
  161795. }
  161796. },
  161797. /**
  161798. * Gets the Animation widget.
  161799. * @memberof Viewer.prototype
  161800. * @type {Animation}
  161801. * @readonly
  161802. */
  161803. animation : {
  161804. get : function() {
  161805. return this._animation;
  161806. }
  161807. },
  161808. /**
  161809. * Gets the Timeline widget.
  161810. * @memberof Viewer.prototype
  161811. * @type {Timeline}
  161812. * @readonly
  161813. */
  161814. timeline : {
  161815. get : function() {
  161816. return this._timeline;
  161817. }
  161818. },
  161819. /**
  161820. * Gets the FullscreenButton.
  161821. * @memberof Viewer.prototype
  161822. * @type {FullscreenButton}
  161823. * @readonly
  161824. */
  161825. fullscreenButton : {
  161826. get : function() {
  161827. return this._fullscreenButton;
  161828. }
  161829. },
  161830. /**
  161831. * Gets the VRButton.
  161832. * @memberof Viewer.prototype
  161833. * @type {VRButton}
  161834. * @readonly
  161835. */
  161836. vrButton : {
  161837. get : function() {
  161838. return this._vrButton;
  161839. }
  161840. },
  161841. /**
  161842. * Gets the display used for {@link DataSource} visualization.
  161843. * @memberof Viewer.prototype
  161844. * @type {DataSourceDisplay}
  161845. * @readonly
  161846. */
  161847. dataSourceDisplay : {
  161848. get : function() {
  161849. return this._dataSourceDisplay;
  161850. }
  161851. },
  161852. /**
  161853. * Gets the collection of entities not tied to a particular data source.
  161854. * This is a shortcut to [dataSourceDisplay.defaultDataSource.entities]{@link Viewer#dataSourceDisplay}.
  161855. * @memberof Viewer.prototype
  161856. * @type {EntityCollection}
  161857. * @readonly
  161858. */
  161859. entities : {
  161860. get : function() {
  161861. return this._dataSourceDisplay.defaultDataSource.entities;
  161862. }
  161863. },
  161864. /**
  161865. * Gets the set of {@link DataSource} instances to be visualized.
  161866. * @memberof Viewer.prototype
  161867. * @type {DataSourceCollection}
  161868. * @readonly
  161869. */
  161870. dataSources : {
  161871. get : function() {
  161872. return this._dataSourceCollection;
  161873. }
  161874. },
  161875. /**
  161876. * Gets the canvas.
  161877. * @memberof Viewer.prototype
  161878. * @type {Canvas}
  161879. * @readonly
  161880. */
  161881. canvas : {
  161882. get : function() {
  161883. return this._cesiumWidget.canvas;
  161884. }
  161885. },
  161886. /**
  161887. * Gets the Cesium logo element.
  161888. * @memberof Viewer.prototype
  161889. * @type {Element}
  161890. * @readonly
  161891. */
  161892. cesiumLogo : {
  161893. get : function() {
  161894. return this._cesiumWidget.cesiumLogo;
  161895. }
  161896. },
  161897. /**
  161898. * Gets the scene.
  161899. * @memberof Viewer.prototype
  161900. * @type {Scene}
  161901. * @readonly
  161902. */
  161903. scene : {
  161904. get : function() {
  161905. return this._cesiumWidget.scene;
  161906. }
  161907. },
  161908. /**
  161909. * Determines if shadows are cast by the sun.
  161910. * @memberof Viewer.prototype
  161911. * @type {Boolean}
  161912. */
  161913. shadows : {
  161914. get : function() {
  161915. return this.scene.shadowMap.enabled;
  161916. },
  161917. set : function(value) {
  161918. this.scene.shadowMap.enabled = value;
  161919. }
  161920. },
  161921. /**
  161922. * Determines if the terrain casts or shadows from the sun.
  161923. * @memberof Viewer.prototype
  161924. * @type {ShadowMode}
  161925. */
  161926. terrainShadows : {
  161927. get : function() {
  161928. return this.scene.globe.shadows;
  161929. },
  161930. set : function(value) {
  161931. this.scene.globe.shadows = value;
  161932. }
  161933. },
  161934. /**
  161935. * Get the scene's shadow map
  161936. * @memberof Viewer.prototype
  161937. * @type {ShadowMap}
  161938. * @readonly
  161939. */
  161940. shadowMap : {
  161941. get : function() {
  161942. return this.scene.shadowMap;
  161943. }
  161944. },
  161945. /**
  161946. * Gets the collection of image layers that will be rendered on the globe.
  161947. * @memberof Viewer.prototype
  161948. *
  161949. * @type {ImageryLayerCollection}
  161950. * @readonly
  161951. */
  161952. imageryLayers : {
  161953. get : function() {
  161954. return this.scene.imageryLayers;
  161955. }
  161956. },
  161957. /**
  161958. * The terrain provider providing surface geometry for the globe.
  161959. * @memberof Viewer.prototype
  161960. *
  161961. * @type {TerrainProvider}
  161962. */
  161963. terrainProvider : {
  161964. get : function() {
  161965. return this.scene.terrainProvider;
  161966. },
  161967. set : function(terrainProvider) {
  161968. this.scene.terrainProvider = terrainProvider;
  161969. }
  161970. },
  161971. /**
  161972. * Gets the camera.
  161973. * @memberof Viewer.prototype
  161974. *
  161975. * @type {Camera}
  161976. * @readonly
  161977. */
  161978. camera : {
  161979. get : function() {
  161980. return this.scene.camera;
  161981. }
  161982. },
  161983. /**
  161984. * Gets the clock.
  161985. * @memberof Viewer.prototype
  161986. * @type {Clock}
  161987. * @readonly
  161988. */
  161989. clock : {
  161990. get : function() {
  161991. return this._cesiumWidget.clock;
  161992. }
  161993. },
  161994. /**
  161995. * Gets the screen space event handler.
  161996. * @memberof Viewer.prototype
  161997. * @type {ScreenSpaceEventHandler}
  161998. * @readonly
  161999. */
  162000. screenSpaceEventHandler : {
  162001. get : function() {
  162002. return this._cesiumWidget.screenSpaceEventHandler;
  162003. }
  162004. },
  162005. /**
  162006. * Gets or sets the target frame rate of the widget when <code>useDefaultRenderLoop</code>
  162007. * is true. If undefined, the browser's {@link requestAnimationFrame} implementation
  162008. * determines the frame rate. If defined, this value must be greater than 0. A value higher
  162009. * than the underlying requestAnimationFrame implementation will have no effect.
  162010. * @memberof Viewer.prototype
  162011. *
  162012. * @type {Number}
  162013. */
  162014. targetFrameRate : {
  162015. get : function() {
  162016. return this._cesiumWidget.targetFrameRate;
  162017. },
  162018. set : function(value) {
  162019. this._cesiumWidget.targetFrameRate = value;
  162020. }
  162021. },
  162022. /**
  162023. * Gets or sets whether or not this widget should control the render loop.
  162024. * If set to true the widget will use {@link requestAnimationFrame} to
  162025. * perform rendering and resizing of the widget, as well as drive the
  162026. * simulation clock. If set to false, you must manually call the
  162027. * <code>resize</code>, <code>render</code> methods
  162028. * as part of a custom render loop. If an error occurs during rendering, {@link Scene}'s
  162029. * <code>renderError</code> event will be raised and this property
  162030. * will be set to false. It must be set back to true to continue rendering
  162031. * after the error.
  162032. * @memberof Viewer.prototype
  162033. *
  162034. * @type {Boolean}
  162035. */
  162036. useDefaultRenderLoop : {
  162037. get : function() {
  162038. return this._cesiumWidget.useDefaultRenderLoop;
  162039. },
  162040. set : function(value) {
  162041. this._cesiumWidget.useDefaultRenderLoop = value;
  162042. }
  162043. },
  162044. /**
  162045. * Gets or sets a scaling factor for rendering resolution. Values less than 1.0 can improve
  162046. * performance on less powerful devices while values greater than 1.0 will render at a higher
  162047. * resolution and then scale down, resulting in improved visual fidelity.
  162048. * For example, if the widget is laid out at a size of 640x480, setting this value to 0.5
  162049. * will cause the scene to be rendered at 320x240 and then scaled up while setting
  162050. * it to 2.0 will cause the scene to be rendered at 1280x960 and then scaled down.
  162051. * @memberof Viewer.prototype
  162052. *
  162053. * @type {Number}
  162054. * @default 1.0
  162055. */
  162056. resolutionScale : {
  162057. get : function() {
  162058. return this._cesiumWidget.resolutionScale;
  162059. },
  162060. set : function(value) {
  162061. this._cesiumWidget.resolutionScale = value;
  162062. this._forceResize = true;
  162063. }
  162064. },
  162065. /**
  162066. * Gets or sets whether or not data sources can temporarily pause
  162067. * animation in order to avoid showing an incomplete picture to the user.
  162068. * For example, if asynchronous primitives are being processed in the
  162069. * background, the clock will not advance until the geometry is ready.
  162070. *
  162071. * @memberof Viewer.prototype
  162072. *
  162073. * @type {Boolean}
  162074. */
  162075. allowDataSourcesToSuspendAnimation : {
  162076. get : function() {
  162077. return this._allowDataSourcesToSuspendAnimation;
  162078. },
  162079. set : function(value) {
  162080. this._allowDataSourcesToSuspendAnimation = value;
  162081. }
  162082. },
  162083. /**
  162084. * Gets or sets the Entity instance currently being tracked by the camera.
  162085. * @memberof Viewer.prototype
  162086. * @type {Entity}
  162087. */
  162088. trackedEntity : {
  162089. get : function() {
  162090. return this._trackedEntity;
  162091. },
  162092. set : function(value) {
  162093. if (this._trackedEntity !== value) {
  162094. this._trackedEntity = value;
  162095. //Cancel any pending zoom
  162096. cancelZoom(this);
  162097. var scene = this.scene;
  162098. var sceneMode = scene.mode;
  162099. //Stop tracking
  162100. if (!defined(value) || !defined(value.position)) {
  162101. this._needTrackedEntityUpdate = false;
  162102. if (sceneMode === SceneMode.COLUMBUS_VIEW || sceneMode === SceneMode.SCENE2D) {
  162103. scene.screenSpaceCameraController.enableTranslate = true;
  162104. }
  162105. if (sceneMode === SceneMode.COLUMBUS_VIEW || sceneMode === SceneMode.SCENE3D) {
  162106. scene.screenSpaceCameraController.enableTilt = true;
  162107. }
  162108. this._entityView = undefined;
  162109. this.camera.lookAtTransform(Matrix4.IDENTITY);
  162110. return;
  162111. }
  162112. //We can't start tracking immediately, so we set a flag and start tracking
  162113. //when the bounding sphere is ready (most likely next frame).
  162114. this._needTrackedEntityUpdate = true;
  162115. }
  162116. }
  162117. },
  162118. /**
  162119. * Gets or sets the object instance for which to display a selection indicator.
  162120. * @memberof Viewer.prototype
  162121. * @type {Entity}
  162122. */
  162123. selectedEntity : {
  162124. get : function() {
  162125. return this._selectedEntity;
  162126. },
  162127. set : function(value) {
  162128. if (this._selectedEntity !== value) {
  162129. this._selectedEntity = value;
  162130. var selectionIndicatorViewModel = defined(this._selectionIndicator) ? this._selectionIndicator.viewModel : undefined;
  162131. if (defined(value)) {
  162132. if (defined(selectionIndicatorViewModel)) {
  162133. selectionIndicatorViewModel.animateAppear();
  162134. }
  162135. } else {
  162136. // Leave the info text in place here, it is needed during the exit animation.
  162137. if (defined(selectionIndicatorViewModel)) {
  162138. selectionIndicatorViewModel.animateDepart();
  162139. }
  162140. }
  162141. }
  162142. }
  162143. },
  162144. /**
  162145. * Gets or sets the data source to track with the viewer's clock.
  162146. * @memberof Viewer.prototype
  162147. * @type {DataSource}
  162148. */
  162149. clockTrackedDataSource : {
  162150. get : function() {
  162151. return this._clockTrackedDataSource;
  162152. },
  162153. set : function(value) {
  162154. if (this._clockTrackedDataSource !== value) {
  162155. this._clockTrackedDataSource = value;
  162156. trackDataSourceClock(this._timeline, this.clock, value);
  162157. }
  162158. }
  162159. }
  162160. });
  162161. /**
  162162. * Extends the base viewer functionality with the provided mixin.
  162163. * A mixin may add additional properties, functions, or other behavior
  162164. * to the provided viewer instance.
  162165. *
  162166. * @param {Viewer~ViewerMixin} mixin The Viewer mixin to add to this instance.
  162167. * @param {Object} [options] The options object to be passed to the mixin function.
  162168. *
  162169. * @see viewerDragDropMixin
  162170. */
  162171. Viewer.prototype.extend = function(mixin, options) {
  162172. if (!defined(mixin)) {
  162173. throw new DeveloperError('mixin is required.');
  162174. }
  162175. mixin(this, options);
  162176. };
  162177. /**
  162178. * Resizes the widget to match the container size.
  162179. * This function is called automatically as needed unless
  162180. * <code>useDefaultRenderLoop</code> is set to false.
  162181. */
  162182. Viewer.prototype.resize = function() {
  162183. var cesiumWidget = this._cesiumWidget;
  162184. var container = this._container;
  162185. var width = container.clientWidth;
  162186. var height = container.clientHeight;
  162187. var animationExists = defined(this._animation);
  162188. var timelineExists = defined(this._timeline);
  162189. if (!this._forceResize && width === this._lastWidth && height === this._lastHeight) {
  162190. return;
  162191. }
  162192. cesiumWidget.resize();
  162193. this._forceResize = false;
  162194. var panelMaxHeight = height - 125;
  162195. var baseLayerPickerDropDown = this._baseLayerPickerDropDown;
  162196. if (defined(baseLayerPickerDropDown)) {
  162197. baseLayerPickerDropDown.style.maxHeight = panelMaxHeight + 'px';
  162198. }
  162199. if (defined(this._infoBox)) {
  162200. this._infoBox.viewModel.maxHeight = panelMaxHeight;
  162201. }
  162202. var timeline = this._timeline;
  162203. var animationContainer;
  162204. var animationWidth = 0;
  162205. var creditLeft = 0;
  162206. var creditBottom = 0;
  162207. if (animationExists && window.getComputedStyle(this._animation.container).visibility !== 'hidden') {
  162208. var lastWidth = this._lastWidth;
  162209. animationContainer = this._animation.container;
  162210. if (width > 900) {
  162211. animationWidth = 169;
  162212. if (lastWidth <= 900) {
  162213. animationContainer.style.width = '169px';
  162214. animationContainer.style.height = '112px';
  162215. this._animation.resize();
  162216. }
  162217. } else if (width >= 600) {
  162218. animationWidth = 136;
  162219. if (lastWidth < 600 || lastWidth > 900) {
  162220. animationContainer.style.width = '136px';
  162221. animationContainer.style.height = '90px';
  162222. this._animation.resize();
  162223. }
  162224. } else {
  162225. animationWidth = 106;
  162226. if (lastWidth > 600 || lastWidth === 0) {
  162227. animationContainer.style.width = '106px';
  162228. animationContainer.style.height = '70px';
  162229. this._animation.resize();
  162230. }
  162231. }
  162232. creditLeft = animationWidth + 5;
  162233. }
  162234. if (timelineExists && window.getComputedStyle(this._timeline.container).visibility !== 'hidden') {
  162235. var fullscreenButton = this._fullscreenButton;
  162236. var vrButton = this._vrButton;
  162237. var timelineContainer = timeline.container;
  162238. var timelineStyle = timelineContainer.style;
  162239. creditBottom = timelineContainer.clientHeight + 3;
  162240. timelineStyle.left = animationWidth + 'px';
  162241. var pixels = 0;
  162242. if (defined(fullscreenButton)) {
  162243. pixels += fullscreenButton.container.clientWidth;
  162244. }
  162245. if (defined(vrButton)) {
  162246. pixels += vrButton.container.clientWidth;
  162247. }
  162248. timelineStyle.right = pixels + 'px';
  162249. timeline.resize();
  162250. }
  162251. this._bottomContainer.style.left = creditLeft + 'px';
  162252. this._bottomContainer.style.bottom = creditBottom + 'px';
  162253. this._lastWidth = width;
  162254. this._lastHeight = height;
  162255. };
  162256. /**
  162257. * This forces the widget to re-think its layout, including
  162258. * widget sizes and credit placement.
  162259. */
  162260. Viewer.prototype.forceResize = function() {
  162261. this._lastWidth = 0;
  162262. this.resize();
  162263. };
  162264. /**
  162265. * Renders the scene. This function is called automatically
  162266. * unless <code>useDefaultRenderLoop</code> is set to false;
  162267. */
  162268. Viewer.prototype.render = function() {
  162269. this._cesiumWidget.render();
  162270. };
  162271. /**
  162272. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  162273. */
  162274. Viewer.prototype.isDestroyed = function() {
  162275. return false;
  162276. };
  162277. /**
  162278. * Destroys the widget. Should be called if permanently
  162279. * removing the widget from layout.
  162280. */
  162281. Viewer.prototype.destroy = function() {
  162282. var i;
  162283. this.screenSpaceEventHandler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK);
  162284. this.screenSpaceEventHandler.removeInputAction(ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
  162285. // Unsubscribe from data sources
  162286. var dataSources = this.dataSources;
  162287. var dataSourceLength = dataSources.length;
  162288. for (i = 0; i < dataSourceLength; i++) {
  162289. this._dataSourceRemoved(dataSources, dataSources.get(i));
  162290. }
  162291. this._dataSourceRemoved(undefined, this._dataSourceDisplay.defaultDataSource);
  162292. this._container.removeChild(this._element);
  162293. this._element.removeChild(this._toolbar);
  162294. this._eventHelper.removeAll();
  162295. if (defined(this._geocoder)) {
  162296. this._geocoder = this._geocoder.destroy();
  162297. }
  162298. if (defined(this._homeButton)) {
  162299. this._homeButton = this._homeButton.destroy();
  162300. }
  162301. if (defined(this._sceneModePicker)) {
  162302. this._sceneModePicker = this._sceneModePicker.destroy();
  162303. }
  162304. if (defined(this._baseLayerPicker)) {
  162305. this._baseLayerPicker = this._baseLayerPicker.destroy();
  162306. }
  162307. if (defined(this._animation)) {
  162308. this._element.removeChild(this._animation.container);
  162309. this._animation = this._animation.destroy();
  162310. }
  162311. if (defined(this._timeline)) {
  162312. this._timeline.removeEventListener('settime', onTimelineScrubfunction, false);
  162313. this._element.removeChild(this._timeline.container);
  162314. this._timeline = this._timeline.destroy();
  162315. }
  162316. if (defined(this._fullscreenButton)) {
  162317. this._fullscreenSubscription.dispose();
  162318. this._element.removeChild(this._fullscreenButton.container);
  162319. this._fullscreenButton = this._fullscreenButton.destroy();
  162320. }
  162321. if (defined(this._vrButton)) {
  162322. this._vrSubscription.dispose();
  162323. this._vrModeSubscription.dispose();
  162324. this._element.removeChild(this._vrButton.container);
  162325. this._vrButton = this._vrButton.destroy();
  162326. }
  162327. if (defined(this._infoBox)) {
  162328. this._element.removeChild(this._infoBox.container);
  162329. this._infoBox = this._infoBox.destroy();
  162330. }
  162331. if (defined(this._selectionIndicator)) {
  162332. this._element.removeChild(this._selectionIndicator.container);
  162333. this._selectionIndicator = this._selectionIndicator.destroy();
  162334. }
  162335. this._clockViewModel = this._clockViewModel.destroy();
  162336. this._dataSourceDisplay = this._dataSourceDisplay.destroy();
  162337. this._cesiumWidget = this._cesiumWidget.destroy();
  162338. if (this._destroyDataSourceCollection) {
  162339. this._dataSourceCollection = this._dataSourceCollection.destroy();
  162340. }
  162341. return destroyObject(this);
  162342. };
  162343. /**
  162344. * @private
  162345. */
  162346. Viewer.prototype._dataSourceAdded = function(dataSourceCollection, dataSource) {
  162347. var entityCollection = dataSource.entities;
  162348. entityCollection.collectionChanged.addEventListener(Viewer.prototype._onEntityCollectionChanged, this);
  162349. };
  162350. /**
  162351. * @private
  162352. */
  162353. Viewer.prototype._dataSourceRemoved = function(dataSourceCollection, dataSource) {
  162354. var entityCollection = dataSource.entities;
  162355. entityCollection.collectionChanged.removeEventListener(Viewer.prototype._onEntityCollectionChanged, this);
  162356. if (defined(this.trackedEntity)) {
  162357. if (entityCollection.getById(this.trackedEntity.id) === this.trackedEntity) {
  162358. this.trackedEntity = undefined;
  162359. }
  162360. }
  162361. if (defined(this.selectedEntity)) {
  162362. if (entityCollection.getById(this.selectedEntity.id) === this.selectedEntity) {
  162363. this.selectedEntity = undefined;
  162364. }
  162365. }
  162366. };
  162367. /**
  162368. * @private
  162369. */
  162370. Viewer.prototype._onTick = function(clock) {
  162371. var time = clock.currentTime;
  162372. var isUpdated = this._dataSourceDisplay.update(time);
  162373. if (this._allowDataSourcesToSuspendAnimation) {
  162374. this._clockViewModel.canAnimate = isUpdated;
  162375. }
  162376. var entityView = this._entityView;
  162377. if (defined(entityView)) {
  162378. var trackedEntity = this._trackedEntity;
  162379. var trackedState = this._dataSourceDisplay.getBoundingSphere(trackedEntity, false, boundingSphereScratch);
  162380. if (trackedState === BoundingSphereState.DONE) {
  162381. entityView.update(time, boundingSphereScratch);
  162382. }
  162383. }
  162384. var position;
  162385. var enableCamera = false;
  162386. var selectedEntity = this.selectedEntity;
  162387. var showSelection = defined(selectedEntity) && this._enableInfoOrSelection;
  162388. if (showSelection && selectedEntity.isShowing && selectedEntity.isAvailable(time)) {
  162389. var state = this._dataSourceDisplay.getBoundingSphere(selectedEntity, true, boundingSphereScratch);
  162390. if (state !== BoundingSphereState.FAILED) {
  162391. position = boundingSphereScratch.center;
  162392. } else if (defined(selectedEntity.position)) {
  162393. position = selectedEntity.position.getValue(time, position);
  162394. }
  162395. enableCamera = defined(position);
  162396. }
  162397. var selectionIndicatorViewModel = defined(this._selectionIndicator) ? this._selectionIndicator.viewModel : undefined;
  162398. if (defined(selectionIndicatorViewModel)) {
  162399. selectionIndicatorViewModel.position = Cartesian3.clone(position, selectionIndicatorViewModel.position);
  162400. selectionIndicatorViewModel.showSelection = showSelection && enableCamera;
  162401. selectionIndicatorViewModel.update();
  162402. }
  162403. var infoBoxViewModel = defined(this._infoBox) ? this._infoBox.viewModel : undefined;
  162404. if (defined(infoBoxViewModel)) {
  162405. infoBoxViewModel.showInfo = showSelection;
  162406. infoBoxViewModel.enableCamera = enableCamera;
  162407. infoBoxViewModel.isCameraTracking = (this.trackedEntity === this.selectedEntity);
  162408. if (showSelection) {
  162409. infoBoxViewModel.titleText = defaultValue(selectedEntity.name, selectedEntity.id);
  162410. infoBoxViewModel.description = Property.getValueOrDefault(selectedEntity.description, time, '');
  162411. } else {
  162412. infoBoxViewModel.titleText = '';
  162413. infoBoxViewModel.description = '';
  162414. }
  162415. }
  162416. };
  162417. /**
  162418. * @private
  162419. */
  162420. Viewer.prototype._onEntityCollectionChanged = function(collection, added, removed) {
  162421. var length = removed.length;
  162422. for (var i = 0; i < length; i++) {
  162423. var removedObject = removed[i];
  162424. if (this.trackedEntity === removedObject) {
  162425. this.trackedEntity = undefined;
  162426. }
  162427. if (this.selectedEntity === removedObject) {
  162428. this.selectedEntity = undefined;
  162429. }
  162430. }
  162431. };
  162432. /**
  162433. * @private
  162434. */
  162435. Viewer.prototype._onInfoBoxCameraClicked = function(infoBoxViewModel) {
  162436. if (infoBoxViewModel.isCameraTracking && (this.trackedEntity === this.selectedEntity)) {
  162437. this.trackedEntity = undefined;
  162438. } else {
  162439. var selectedEntity = this.selectedEntity;
  162440. var position = selectedEntity.position;
  162441. if (defined(position)) {
  162442. this.trackedEntity = this.selectedEntity;
  162443. } else {
  162444. this.zoomTo(this.selectedEntity);
  162445. }
  162446. }
  162447. };
  162448. /**
  162449. * @private
  162450. */
  162451. Viewer.prototype._clearTrackedObject = function() {
  162452. this.trackedEntity = undefined;
  162453. };
  162454. /**
  162455. * @private
  162456. */
  162457. Viewer.prototype._onInfoBoxClockClicked = function(infoBoxViewModel) {
  162458. this.selectedEntity = undefined;
  162459. };
  162460. /**
  162461. * @private
  162462. */
  162463. Viewer.prototype._clearObjects = function() {
  162464. this.trackedEntity = undefined;
  162465. this.selectedEntity = undefined;
  162466. };
  162467. /**
  162468. * @private
  162469. */
  162470. Viewer.prototype._onDataSourceChanged = function(dataSource) {
  162471. if (this.clockTrackedDataSource === dataSource) {
  162472. trackDataSourceClock(this.timeline, this.clock, dataSource);
  162473. }
  162474. };
  162475. /**
  162476. * @private
  162477. */
  162478. Viewer.prototype._onDataSourceAdded = function(dataSourceCollection, dataSource) {
  162479. if (this._automaticallyTrackDataSourceClocks) {
  162480. this.clockTrackedDataSource = dataSource;
  162481. }
  162482. var id = dataSource.entities.id;
  162483. var removalFunc = this._eventHelper.add(dataSource.changedEvent, Viewer.prototype._onDataSourceChanged, this);
  162484. this._dataSourceChangedListeners[id] = removalFunc;
  162485. };
  162486. /**
  162487. * @private
  162488. */
  162489. Viewer.prototype._onDataSourceRemoved = function(dataSourceCollection, dataSource) {
  162490. var resetClock = (this.clockTrackedDataSource === dataSource);
  162491. var id = dataSource.entities.id;
  162492. this._dataSourceChangedListeners[id]();
  162493. this._dataSourceChangedListeners[id] = undefined;
  162494. if (resetClock) {
  162495. var numDataSources = dataSourceCollection.length;
  162496. if (this._automaticallyTrackDataSourceClocks && numDataSources > 0) {
  162497. this.clockTrackedDataSource = dataSourceCollection.get(numDataSources - 1);
  162498. } else {
  162499. this.clockTrackedDataSource = undefined;
  162500. }
  162501. }
  162502. };
  162503. /**
  162504. * Asynchronously sets the camera to view the provided entity, entities, or data source.
  162505. * If the data source is still in the process of loading or the visualization is otherwise still loading,
  162506. * this method waits for the data to be ready before performing the zoom.
  162507. *
  162508. * <p>The offset is heading/pitch/range in the local east-north-up reference frame centered at the center of the bounding sphere.
  162509. * The heading and the pitch angles are defined in the local east-north-up reference frame.
  162510. * The heading is the angle from y axis and increasing towards the x axis. Pitch is the rotation from the xy-plane. Positive pitch
  162511. * angles are above the plane. Negative pitch angles are below the plane. The range is the distance from the center. If the range is
  162512. * zero, a range will be computed such that the whole bounding sphere is visible.</p>
  162513. *
  162514. * <p>In 2D, there must be a top down view. The camera will be placed above the target looking down. The height above the
  162515. * target will be the range. The heading will be determined from the offset. If the heading cannot be
  162516. * determined from the offset, the heading will be north.</p>
  162517. *
  162518. * @param {Entity|Entity[]|EntityCollection|DataSource|ImageryLayer|Promise.<Entity|Entity[]|EntityCollection|DataSource|ImageryLayer>} target The entity, array of entities, entity collection, data source or imagery layer to view. You can also pass a promise that resolves to one of the previously mentioned types.
  162519. * @param {HeadingPitchRange} [offset] The offset from the center of the entity in the local east-north-up reference frame.
  162520. * @returns {Promise.<Boolean>} A Promise that resolves to true if the zoom was successful or false if the entity is not currently visualized in the scene or the zoom was cancelled.
  162521. */
  162522. Viewer.prototype.zoomTo = function(target, offset) {
  162523. return zoomToOrFly(this, target, offset, false);
  162524. };
  162525. /**
  162526. * Flies the camera to the provided entity, entities, or data source.
  162527. * If the data source is still in the process of loading or the visualization is otherwise still loading,
  162528. * this method waits for the data to be ready before performing the flight.
  162529. *
  162530. * <p>The offset is heading/pitch/range in the local east-north-up reference frame centered at the center of the bounding sphere.
  162531. * The heading and the pitch angles are defined in the local east-north-up reference frame.
  162532. * The heading is the angle from y axis and increasing towards the x axis. Pitch is the rotation from the xy-plane. Positive pitch
  162533. * angles are above the plane. Negative pitch angles are below the plane. The range is the distance from the center. If the range is
  162534. * zero, a range will be computed such that the whole bounding sphere is visible.</p>
  162535. *
  162536. * <p>In 2D, there must be a top down view. The camera will be placed above the target looking down. The height above the
  162537. * target will be the range. The heading will be determined from the offset. If the heading cannot be
  162538. * determined from the offset, the heading will be north.</p>
  162539. *
  162540. * @param {Entity|Entity[]|EntityCollection|DataSource|ImageryLayer|Promise.<Entity|Entity[]|EntityCollection|DataSource|ImageryLayer>} target The entity, array of entities, entity collection, data source or imagery layer to view. You can also pass a promise that resolves to one of the previously mentioned types.
  162541. * @param {Object} [options] Object with the following properties:
  162542. * @param {Number} [options.duration=3.0] The duration of the flight in seconds.
  162543. * @param {Number} [options.maximumHeight] The maximum height at the peak of the flight.
  162544. * @param {HeadingPitchRange} [options.offset] The offset from the target in the local east-north-up reference frame centered at the target.
  162545. * @returns {Promise.<Boolean>} A Promise that resolves to true if the flight was successful or false if the entity is not currently visualized in the scene or the flight was cancelled.
  162546. */
  162547. Viewer.prototype.flyTo = function(target, options) {
  162548. return zoomToOrFly(this, target, options, true);
  162549. };
  162550. function zoomToOrFly(that, zoomTarget, options, isFlight) {
  162551. if (!defined(zoomTarget)) {
  162552. throw new DeveloperError('zoomTarget is required.');
  162553. }
  162554. cancelZoom(that);
  162555. //We can't actually perform the zoom until all visualization is ready and
  162556. //bounding spheres have been computed. Therefore we create and return
  162557. //a deferred which will be resolved as part of the post-render step in the
  162558. //frame that actually performs the zoom
  162559. var zoomPromise = when.defer();
  162560. that._zoomPromise = zoomPromise;
  162561. that._zoomIsFlight = isFlight;
  162562. that._zoomOptions = options;
  162563. when(zoomTarget, function(zoomTarget) {
  162564. //Only perform the zoom if it wasn't cancelled before the promise resolved.
  162565. if (that._zoomPromise !== zoomPromise) {
  162566. return;
  162567. }
  162568. //If the zoom target is a rectangular imagery in an ImageLayer
  162569. if (zoomTarget instanceof ImageryLayer) {
  162570. zoomTarget.getViewableRectangle().then(function(rectangle) {
  162571. //Only perform the zoom if it wasn't cancelled before the promise was resolved
  162572. if (that._zoomPromise === zoomPromise) {
  162573. that._zoomTarget = rectangle;
  162574. }
  162575. });
  162576. return;
  162577. }
  162578. //If the zoom target is a data source, and it's in the middle of loading, wait for it to finish loading.
  162579. if (zoomTarget.isLoading && defined(zoomTarget.loadingEvent)) {
  162580. var removeEvent = zoomTarget.loadingEvent.addEventListener(function() {
  162581. removeEvent();
  162582. //Only perform the zoom if it wasn't cancelled before the data source finished.
  162583. if (that._zoomPromise === zoomPromise) {
  162584. that._zoomTarget = zoomTarget.entities.values.slice(0);
  162585. }
  162586. });
  162587. return;
  162588. }
  162589. //Zoom target is already an array, just copy it and return.
  162590. if (isArray(zoomTarget)) {
  162591. that._zoomTarget = zoomTarget.slice(0);
  162592. return;
  162593. }
  162594. //If zoomTarget is an EntityCollection, this will retrieve the array
  162595. zoomTarget = defaultValue(zoomTarget.values, zoomTarget);
  162596. //If zoomTarget is a DataSource, this will retrieve the array.
  162597. if (defined(zoomTarget.entities)) {
  162598. zoomTarget = zoomTarget.entities.values;
  162599. }
  162600. if (isArray(zoomTarget)) {
  162601. that._zoomTarget = zoomTarget.slice(0);
  162602. } else {
  162603. //Single entity
  162604. that._zoomTarget = [zoomTarget];
  162605. }
  162606. });
  162607. return zoomPromise.promise;
  162608. }
  162609. function clearZoom(viewer) {
  162610. viewer._zoomPromise = undefined;
  162611. viewer._zoomTarget = undefined;
  162612. viewer._zoomOptions = undefined;
  162613. }
  162614. function cancelZoom(viewer) {
  162615. var zoomPromise = viewer._zoomPromise;
  162616. if (defined(zoomPromise)) {
  162617. clearZoom(viewer);
  162618. zoomPromise.resolve(false);
  162619. }
  162620. }
  162621. /**
  162622. * @private
  162623. */
  162624. Viewer.prototype._postRender = function() {
  162625. updateZoomTarget(this);
  162626. updateTrackedEntity(this);
  162627. };
  162628. function updateZoomTarget(viewer) {
  162629. var entities = viewer._zoomTarget;
  162630. if (!defined(entities) || viewer.scene.mode === SceneMode.MORPHING) {
  162631. return;
  162632. }
  162633. var scene = viewer.scene;
  162634. var camera = scene.camera;
  162635. var zoomPromise = viewer._zoomPromise;
  162636. var zoomOptions = defaultValue(viewer._zoomOptions, {});
  162637. //If zoomTarget was an ImageryLayer
  162638. if (entities instanceof Rectangle) {
  162639. var options = {
  162640. destination : entities,
  162641. duration : zoomOptions.duration,
  162642. maximumHeight : zoomOptions.maximumHeight,
  162643. complete : function() {
  162644. zoomPromise.resolve(true);
  162645. },
  162646. cancel : function() {
  162647. zoomPromise.resolve(false);
  162648. }
  162649. };
  162650. if (viewer._zoomIsFlight) {
  162651. camera.flyTo(options);
  162652. } else {
  162653. camera.setView(options);
  162654. zoomPromise.resolve(true);
  162655. }
  162656. clearZoom(viewer);
  162657. return;
  162658. }
  162659. var boundingSpheres = [];
  162660. for (var i = 0, len = entities.length; i < len; i++) {
  162661. var state = viewer._dataSourceDisplay.getBoundingSphere(entities[i], false, boundingSphereScratch);
  162662. if (state === BoundingSphereState.PENDING) {
  162663. return;
  162664. } else if (state !== BoundingSphereState.FAILED) {
  162665. boundingSpheres.push(BoundingSphere.clone(boundingSphereScratch));
  162666. }
  162667. }
  162668. if (boundingSpheres.length === 0) {
  162669. cancelZoom(viewer);
  162670. return;
  162671. }
  162672. //Stop tracking the current entity.
  162673. viewer.trackedEntity = undefined;
  162674. var boundingSphere = BoundingSphere.fromBoundingSpheres(boundingSpheres);
  162675. var controller = scene.screenSpaceCameraController;
  162676. controller.minimumZoomDistance = Math.min(controller.minimumZoomDistance, boundingSphere.radius * 0.5);
  162677. if (!viewer._zoomIsFlight) {
  162678. camera.viewBoundingSphere(boundingSphere, viewer._zoomOptions);
  162679. camera.lookAtTransform(Matrix4.IDENTITY);
  162680. clearZoom(viewer);
  162681. zoomPromise.resolve(true);
  162682. } else {
  162683. clearZoom(viewer);
  162684. camera.flyToBoundingSphere(boundingSphere, {
  162685. duration : zoomOptions.duration,
  162686. maximumHeight : zoomOptions.maximumHeight,
  162687. complete : function() {
  162688. zoomPromise.resolve(true);
  162689. },
  162690. cancel : function() {
  162691. zoomPromise.resolve(false);
  162692. },
  162693. offset : zoomOptions.offset
  162694. });
  162695. }
  162696. }
  162697. function updateTrackedEntity(viewer) {
  162698. if (!viewer._needTrackedEntityUpdate) {
  162699. return;
  162700. }
  162701. var trackedEntity = viewer._trackedEntity;
  162702. var currentTime = viewer.clock.currentTime;
  162703. //Verify we have a current position at this time. This is only triggered if a position
  162704. //has become undefined after trackedEntity is set but before the boundingSphere has been
  162705. //computed. In this case, we will track the entity once it comes back into existence.
  162706. var currentPosition = Property.getValueOrUndefined(trackedEntity.position, currentTime);
  162707. if (!defined(currentPosition)) {
  162708. return;
  162709. }
  162710. var scene = viewer.scene;
  162711. var state = viewer._dataSourceDisplay.getBoundingSphere(trackedEntity, false, boundingSphereScratch);
  162712. if (state === BoundingSphereState.PENDING) {
  162713. return;
  162714. }
  162715. var sceneMode = scene.mode;
  162716. if (sceneMode === SceneMode.COLUMBUS_VIEW || sceneMode === SceneMode.SCENE2D) {
  162717. scene.screenSpaceCameraController.enableTranslate = false;
  162718. }
  162719. if (sceneMode === SceneMode.COLUMBUS_VIEW || sceneMode === SceneMode.SCENE3D) {
  162720. scene.screenSpaceCameraController.enableTilt = false;
  162721. }
  162722. var bs = state !== BoundingSphereState.FAILED ? boundingSphereScratch : undefined;
  162723. viewer._entityView = new EntityView(trackedEntity, scene, scene.mapProjection.ellipsoid);
  162724. viewer._entityView.update(currentTime, bs);
  162725. viewer._needTrackedEntityUpdate = false;
  162726. }
  162727. /**
  162728. * A function that augments a Viewer instance with additional functionality.
  162729. * @callback Viewer~ViewerMixin
  162730. * @param {Viewer} viewer The viewer instance.
  162731. * @param {Object} options Options object to be passed to the mixin function.
  162732. *
  162733. * @see Viewer#extend
  162734. */
  162735. return Viewer;
  162736. });
  162737. /*global define*/
  162738. define('Widgets/Viewer/viewerCesiumInspectorMixin',[
  162739. '../../Core/defined',
  162740. '../../Core/defineProperties',
  162741. '../../Core/DeveloperError',
  162742. '../CesiumInspector/CesiumInspector'
  162743. ], function(
  162744. defined,
  162745. defineProperties,
  162746. DeveloperError,
  162747. CesiumInspector) {
  162748. 'use strict';
  162749. /**
  162750. * A mixin which adds the CesiumInspector widget to the Viewer widget.
  162751. * Rather than being called directly, this function is normally passed as
  162752. * a parameter to {@link Viewer#extend}, as shown in the example below.
  162753. * @exports viewerCesiumInspectorMixin
  162754. *
  162755. * @param {Viewer} viewer The viewer instance.
  162756. *
  162757. * @exception {DeveloperError} viewer is required.
  162758. *
  162759. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Cesium%20Inspector.html|Cesium Sandcastle Cesium Inspector Demo}
  162760. *
  162761. * @example
  162762. * var viewer = new Cesium.Viewer('cesiumContainer');
  162763. * viewer.extend(Cesium.viewerCesiumInspectorMixin);
  162764. */
  162765. function viewerCesiumInspectorMixin(viewer) {
  162766. if (!defined(viewer)) {
  162767. throw new DeveloperError('viewer is required.');
  162768. }
  162769. var cesiumInspectorContainer = document.createElement('div');
  162770. cesiumInspectorContainer.className = 'cesium-viewer-cesiumInspectorContainer';
  162771. viewer.container.appendChild(cesiumInspectorContainer);
  162772. var cesiumInspector = new CesiumInspector(cesiumInspectorContainer, viewer.scene);
  162773. defineProperties(viewer, {
  162774. cesiumInspector : {
  162775. get : function() {
  162776. return cesiumInspector;
  162777. }
  162778. }
  162779. });
  162780. viewer.scene.postRender.addEventListener(function() {
  162781. viewer.cesiumInspector.viewModel.update();
  162782. });
  162783. }
  162784. return viewerCesiumInspectorMixin;
  162785. });
  162786. /*global define*/
  162787. define('Widgets/Viewer/viewerDragDropMixin',[
  162788. '../../Core/defaultValue',
  162789. '../../Core/defined',
  162790. '../../Core/defineProperties',
  162791. '../../Core/DeveloperError',
  162792. '../../Core/Event',
  162793. '../../Core/wrapFunction',
  162794. '../../DataSources/CzmlDataSource',
  162795. '../../DataSources/GeoJsonDataSource',
  162796. '../../DataSources/KmlDataSource',
  162797. '../getElement'
  162798. ], function(
  162799. defaultValue,
  162800. defined,
  162801. defineProperties,
  162802. DeveloperError,
  162803. Event,
  162804. wrapFunction,
  162805. CzmlDataSource,
  162806. GeoJsonDataSource,
  162807. KmlDataSource,
  162808. getElement) {
  162809. 'use strict';
  162810. /**
  162811. * A mixin which adds default drag and drop support for CZML files to the Viewer widget.
  162812. * Rather than being called directly, this function is normally passed as
  162813. * a parameter to {@link Viewer#extend}, as shown in the example below.
  162814. * @exports viewerDragDropMixin
  162815. *
  162816. * @param {Viewer} viewer The viewer instance.
  162817. * @param {Object} [options] Object with the following properties:
  162818. * @param {Element|String} [options.dropTarget=viewer.container] The DOM element which will serve as the drop target.
  162819. * @param {Boolean} [options.clearOnDrop=true] When true, dropping files will clear all existing data sources first, when false, new data sources will be loaded after the existing ones.
  162820. * @param {Boolean} [options.flyToOnDrop=true] When true, dropping files will fly to the data source once it is loaded.
  162821. * @param {Boolean} [options.clampToGround=true] When true, datasources are clamped to the ground.
  162822. * @param {DefaultProxy} [options.proxy] The proxy to be used for KML network links.
  162823. *
  162824. * @exception {DeveloperError} Element with id <options.dropTarget> does not exist in the document.
  162825. * @exception {DeveloperError} dropTarget is already defined by another mixin.
  162826. * @exception {DeveloperError} dropEnabled is already defined by another mixin.
  162827. * @exception {DeveloperError} dropError is already defined by another mixin.
  162828. * @exception {DeveloperError} clearOnDrop is already defined by another mixin.
  162829. *
  162830. * @example
  162831. * // Add basic drag and drop support and pop up an alert window on error.
  162832. * var viewer = new Cesium.Viewer('cesiumContainer');
  162833. * viewer.extend(Cesium.viewerDragDropMixin);
  162834. * viewer.dropError.addEventListener(function(viewerArg, source, error) {
  162835. * window.alert('Error processing ' + source + ':' + error);
  162836. * });
  162837. */
  162838. function viewerDragDropMixin(viewer, options) {
  162839. if (!defined(viewer)) {
  162840. throw new DeveloperError('viewer is required.');
  162841. }
  162842. if (viewer.hasOwnProperty('dropTarget')) {
  162843. throw new DeveloperError('dropTarget is already defined by another mixin.');
  162844. }
  162845. if (viewer.hasOwnProperty('dropEnabled')) {
  162846. throw new DeveloperError('dropEnabled is already defined by another mixin.');
  162847. }
  162848. if (viewer.hasOwnProperty('dropError')) {
  162849. throw new DeveloperError('dropError is already defined by another mixin.');
  162850. }
  162851. if (viewer.hasOwnProperty('clearOnDrop')) {
  162852. throw new DeveloperError('clearOnDrop is already defined by another mixin.');
  162853. }
  162854. if (viewer.hasOwnProperty('flyToOnDrop')) {
  162855. throw new DeveloperError('flyToOnDrop is already defined by another mixin.');
  162856. }
  162857. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  162858. //Local variables to be closed over by defineProperties.
  162859. var dropEnabled = true;
  162860. var flyToOnDrop = defaultValue(options.flyToOnDrop, true);
  162861. var dropError = new Event();
  162862. var clearOnDrop = defaultValue(options.clearOnDrop, true);
  162863. var dropTarget = defaultValue(options.dropTarget, viewer.container);
  162864. var clampToGround = defaultValue(options.clampToGround, true);
  162865. var proxy = options.proxy;
  162866. dropTarget = getElement(dropTarget);
  162867. defineProperties(viewer, {
  162868. /**
  162869. * Gets or sets the element to serve as the drop target.
  162870. * @memberof viewerDragDropMixin.prototype
  162871. * @type {Element}
  162872. */
  162873. dropTarget : {
  162874. //TODO See https://github.com/AnalyticalGraphicsInc/cesium/issues/832
  162875. get : function() {
  162876. return dropTarget;
  162877. },
  162878. set : function(value) {
  162879. if (!defined(value)) {
  162880. throw new DeveloperError('value is required.');
  162881. }
  162882. unsubscribe(dropTarget, handleDrop);
  162883. dropTarget = value;
  162884. subscribe(dropTarget, handleDrop);
  162885. }
  162886. },
  162887. /**
  162888. * Gets or sets a value indicating if drag and drop support is enabled.
  162889. * @memberof viewerDragDropMixin.prototype
  162890. * @type {Element}
  162891. */
  162892. dropEnabled : {
  162893. get : function() {
  162894. return dropEnabled;
  162895. },
  162896. set : function(value) {
  162897. if (value !== dropEnabled) {
  162898. if (value) {
  162899. subscribe(dropTarget, handleDrop);
  162900. } else {
  162901. unsubscribe(dropTarget, handleDrop);
  162902. }
  162903. dropEnabled = value;
  162904. }
  162905. }
  162906. },
  162907. /**
  162908. * Gets the event that will be raised when an error is encountered during drop processing.
  162909. * @memberof viewerDragDropMixin.prototype
  162910. * @type {Event}
  162911. */
  162912. dropError : {
  162913. get : function() {
  162914. return dropError;
  162915. }
  162916. },
  162917. /**
  162918. * Gets or sets a value indicating if existing data sources should be cleared before adding the newly dropped sources.
  162919. * @memberof viewerDragDropMixin.prototype
  162920. * @type {Boolean}
  162921. */
  162922. clearOnDrop : {
  162923. get : function() {
  162924. return clearOnDrop;
  162925. },
  162926. set : function(value) {
  162927. clearOnDrop = value;
  162928. }
  162929. },
  162930. /**
  162931. * Gets or sets a value indicating if the camera should fly to the data source after it is loaded.
  162932. * @memberof viewerDragDropMixin.prototype
  162933. * @type {Boolean}
  162934. */
  162935. flyToOnDrop : {
  162936. get : function() {
  162937. return flyToOnDrop;
  162938. },
  162939. set : function(value) {
  162940. flyToOnDrop = value;
  162941. }
  162942. },
  162943. /**
  162944. * Gets or sets the proxy to be used for KML.
  162945. * @memberof viewerDragDropMixin.prototype
  162946. * @type {DefaultProxy}
  162947. */
  162948. proxy : {
  162949. get : function() {
  162950. return proxy;
  162951. },
  162952. set : function(value) {
  162953. proxy = value;
  162954. }
  162955. },
  162956. /**
  162957. * Gets or sets a value indicating if the datasources should be clamped to the ground
  162958. * @memberof viewerDragDropMixin.prototype
  162959. * @type {Boolean}
  162960. */
  162961. clampToGround : {
  162962. get : function() {
  162963. return clampToGround;
  162964. },
  162965. set : function(value) {
  162966. clampToGround = value;
  162967. }
  162968. }
  162969. });
  162970. function handleDrop(event) {
  162971. stop(event);
  162972. if (clearOnDrop) {
  162973. viewer.entities.removeAll();
  162974. viewer.dataSources.removeAll();
  162975. }
  162976. var files = event.dataTransfer.files;
  162977. var length = files.length;
  162978. for (var i = 0; i < length; i++) {
  162979. var file = files[i];
  162980. var reader = new FileReader();
  162981. reader.onload = createOnLoadCallback(viewer, file, proxy, clampToGround);
  162982. reader.onerror = createDropErrorCallback(viewer, file);
  162983. reader.readAsText(file);
  162984. }
  162985. }
  162986. //Enable drop by default;
  162987. subscribe(dropTarget, handleDrop);
  162988. //Wrap the destroy function to make sure all events are unsubscribed from
  162989. viewer.destroy = wrapFunction(viewer, viewer.destroy, function() {
  162990. viewer.dropEnabled = false;
  162991. });
  162992. //Specs need access to handleDrop
  162993. viewer._handleDrop = handleDrop;
  162994. }
  162995. function stop(event) {
  162996. event.stopPropagation();
  162997. event.preventDefault();
  162998. }
  162999. function unsubscribe(dropTarget, handleDrop) {
  163000. var currentTarget = dropTarget;
  163001. if (defined(currentTarget)) {
  163002. currentTarget.removeEventListener('drop', handleDrop, false);
  163003. currentTarget.removeEventListener('dragenter', stop, false);
  163004. currentTarget.removeEventListener('dragover', stop, false);
  163005. currentTarget.removeEventListener('dragexit', stop, false);
  163006. }
  163007. }
  163008. function subscribe(dropTarget, handleDrop) {
  163009. dropTarget.addEventListener('drop', handleDrop, false);
  163010. dropTarget.addEventListener('dragenter', stop, false);
  163011. dropTarget.addEventListener('dragover', stop, false);
  163012. dropTarget.addEventListener('dragexit', stop, false);
  163013. }
  163014. function createOnLoadCallback(viewer, file, proxy, clampToGround) {
  163015. var scene = viewer.scene;
  163016. return function(evt) {
  163017. var fileName = file.name;
  163018. try {
  163019. var loadPromise;
  163020. if (/\.czml$/i.test(fileName)) {
  163021. loadPromise = CzmlDataSource.load(JSON.parse(evt.target.result), {
  163022. sourceUri : fileName
  163023. });
  163024. } else if (/\.geojson$/i.test(fileName) || /\.json$/i.test(fileName) || /\.topojson$/i.test(fileName)) {
  163025. loadPromise = GeoJsonDataSource.load(JSON.parse(evt.target.result), {
  163026. sourceUri : fileName,
  163027. clampToGround : clampToGround
  163028. });
  163029. } else if (/\.(kml|kmz)$/i.test(fileName)) {
  163030. loadPromise = KmlDataSource.load(file, {
  163031. sourceUri : fileName,
  163032. proxy : proxy,
  163033. camera : scene.camera,
  163034. canvas : scene.canvas
  163035. });
  163036. } else {
  163037. viewer.dropError.raiseEvent(viewer, fileName, 'Unrecognized file: ' + fileName);
  163038. return;
  163039. }
  163040. if (defined(loadPromise)) {
  163041. viewer.dataSources.add(loadPromise).then(function(dataSource) {
  163042. if (viewer.flyToOnDrop) {
  163043. viewer.flyTo(dataSource);
  163044. }
  163045. }).otherwise(function(error) {
  163046. viewer.dropError.raiseEvent(viewer, fileName, error);
  163047. });
  163048. }
  163049. } catch (error) {
  163050. viewer.dropError.raiseEvent(viewer, fileName, error);
  163051. }
  163052. };
  163053. }
  163054. function createDropErrorCallback(viewer, file) {
  163055. return function(evt) {
  163056. viewer.dropError.raiseEvent(viewer, file.name, evt.target.error);
  163057. };
  163058. }
  163059. return viewerDragDropMixin;
  163060. });
  163061. /*global define*/
  163062. define('Widgets/Viewer/viewerPerformanceWatchdogMixin',[
  163063. '../../Core/defaultValue',
  163064. '../../Core/defined',
  163065. '../../Core/defineProperties',
  163066. '../../Core/DeveloperError',
  163067. '../PerformanceWatchdog/PerformanceWatchdog'
  163068. ], function(
  163069. defaultValue,
  163070. defined,
  163071. defineProperties,
  163072. DeveloperError,
  163073. PerformanceWatchdog) {
  163074. 'use strict';
  163075. /**
  163076. * A mixin which adds the {@link PerformanceWatchdog} widget to the {@link Viewer} widget.
  163077. * Rather than being called directly, this function is normally passed as
  163078. * a parameter to {@link Viewer#extend}, as shown in the example below.
  163079. * @exports viewerPerformanceWatchdogMixin
  163080. *
  163081. * @param {Viewer} viewer The viewer instance.
  163082. * @param {String} [options.lowFrameRateMessage='This application appears to be performing poorly on your system. Please try using a different web browser or updating your video drivers.'] The
  163083. * message to display when a low frame rate is detected. The message is interpeted as HTML, so make sure
  163084. * it comes from a trusted source so that your application is not vulnerable to cross-site scripting attacks.
  163085. *
  163086. * @exception {DeveloperError} viewer is required.
  163087. *
  163088. * @example
  163089. * var viewer = new Cesium.Viewer('cesiumContainer');
  163090. * viewer.extend(Cesium.viewerPerformanceWatchdogMixin, {
  163091. * lowFrameRateMessage : 'Why is this going so <em>slowly</em>?'
  163092. * });
  163093. */
  163094. function viewerPerformanceWatchdogMixin(viewer, options) {
  163095. if (!defined(viewer)) {
  163096. throw new DeveloperError('viewer is required.');
  163097. }
  163098. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  163099. var performanceWatchdog = new PerformanceWatchdog({
  163100. scene : viewer.scene,
  163101. container : viewer.bottomContainer,
  163102. lowFrameRateMessage : options.lowFrameRateMessage
  163103. });
  163104. defineProperties(viewer, {
  163105. performanceWatchdog : {
  163106. get : function() {
  163107. return performanceWatchdog;
  163108. }
  163109. }
  163110. });
  163111. }
  163112. return viewerPerformanceWatchdogMixin;
  163113. });
  163114. /*global define*/
  163115. define('Workers/createTaskProcessorWorker',[
  163116. '../Core/defaultValue',
  163117. '../Core/defined',
  163118. '../Core/formatError'
  163119. ], function(
  163120. defaultValue,
  163121. defined,
  163122. formatError) {
  163123. 'use strict';
  163124. /**
  163125. * Creates an adapter function to allow a calculation function to operate as a Web Worker,
  163126. * paired with TaskProcessor, to receive tasks and return results.
  163127. *
  163128. * @exports createTaskProcessorWorker
  163129. *
  163130. * @param {createTaskProcessorWorker~WorkerFunction} workerFunction The calculation function,
  163131. * which takes parameters and returns a result.
  163132. * @returns {createTaskProcessorWorker~TaskProcessorWorkerFunction} A function that adapts the
  163133. * calculation function to work as a Web Worker onmessage listener with TaskProcessor.
  163134. *
  163135. *
  163136. * @example
  163137. * function doCalculation(parameters, transferableObjects) {
  163138. * // calculate some result using the inputs in parameters
  163139. * return result;
  163140. * }
  163141. *
  163142. * return Cesium.createTaskProcessorWorker(doCalculation);
  163143. * // the resulting function is compatible with TaskProcessor
  163144. *
  163145. * @see TaskProcessor
  163146. * @see {@link http://www.w3.org/TR/workers/|Web Workers}
  163147. * @see {@link http://www.w3.org/TR/html5/common-dom-interfaces.html#transferable-objects|Transferable objects}
  163148. */
  163149. function createTaskProcessorWorker(workerFunction) {
  163150. var postMessage;
  163151. var transferableObjects = [];
  163152. var responseMessage = {
  163153. id : undefined,
  163154. result : undefined,
  163155. error : undefined
  163156. };
  163157. return function(event) {
  163158. /*global self*/
  163159. var data = event.data;
  163160. transferableObjects.length = 0;
  163161. responseMessage.id = data.id;
  163162. responseMessage.error = undefined;
  163163. responseMessage.result = undefined;
  163164. try {
  163165. responseMessage.result = workerFunction(data.parameters, transferableObjects);
  163166. } catch (e) {
  163167. if (e instanceof Error) {
  163168. // Errors can't be posted in a message, copy the properties
  163169. responseMessage.error = {
  163170. name : e.name,
  163171. message : e.message,
  163172. stack : e.stack
  163173. };
  163174. } else {
  163175. responseMessage.error = e;
  163176. }
  163177. }
  163178. if (!defined(postMessage)) {
  163179. postMessage = defaultValue(self.webkitPostMessage, self.postMessage);
  163180. }
  163181. if (!data.canTransferArrayBuffer) {
  163182. transferableObjects.length = 0;
  163183. }
  163184. try {
  163185. postMessage(responseMessage, transferableObjects);
  163186. } catch (e) {
  163187. // something went wrong trying to post the message, post a simpler
  163188. // error that we can be sure will be cloneable
  163189. responseMessage.result = undefined;
  163190. responseMessage.error = 'postMessage failed with error: ' + formatError(e) + '\n with responseMessage: ' + JSON.stringify(responseMessage);
  163191. postMessage(responseMessage);
  163192. }
  163193. };
  163194. }
  163195. /**
  163196. * A function that performs a calculation in a Web Worker.
  163197. * @callback createTaskProcessorWorker~WorkerFunction
  163198. *
  163199. * @param {Object} parameters Parameters to the calculation.
  163200. * @param {Array} transferableObjects An array that should be filled with references to objects inside
  163201. * the result that should be transferred back to the main document instead of copied.
  163202. * @returns {Object} The result of the calculation.
  163203. *
  163204. * @example
  163205. * function calculate(parameters, transferableObjects) {
  163206. * // perform whatever calculation is necessary.
  163207. * var typedArray = new Float32Array(0);
  163208. *
  163209. * // typed arrays are transferable
  163210. * transferableObjects.push(typedArray)
  163211. *
  163212. * return {
  163213. * typedArray : typedArray
  163214. * };
  163215. * }
  163216. */
  163217. /**
  163218. * A Web Worker message event handler function that handles the interaction with TaskProcessor,
  163219. * specifically, task ID management and posting a response message containing the result.
  163220. * @callback createTaskProcessorWorker~TaskProcessorWorkerFunction
  163221. *
  163222. * @param {Object} event The onmessage event object.
  163223. */
  163224. return createTaskProcessorWorker;
  163225. });
  163226. /*global define*/
  163227. define('Cesium',['./Core/appendForwardSlash', './Core/ArcGisImageServerTerrainProvider', './Core/arrayRemoveDuplicates', './Core/AssociativeArray', './Core/AttributeCompression', './Core/AxisAlignedBoundingBox', './Core/barycentricCoordinates', './Core/binarySearch', './Core/BingMapsApi', './Core/BoundingRectangle', './Core/BoundingSphere', './Core/BoxGeometry', './Core/BoxOutlineGeometry', './Core/buildModuleUrl', './Core/cancelAnimationFrame', './Core/Cartesian2', './Core/Cartesian3', './Core/Cartesian4', './Core/Cartographic', './Core/CatmullRomSpline', './Core/CesiumTerrainProvider', './Core/Check', './Core/CircleGeometry', './Core/CircleOutlineGeometry', './Core/Clock', './Core/ClockRange', './Core/ClockStep', './Core/clone', './Core/Color', './Core/ColorGeometryInstanceAttribute', './Core/combine', './Core/ComponentDatatype', './Core/CornerType', './Core/CorridorGeometry', './Core/CorridorGeometryLibrary', './Core/CorridorOutlineGeometry', './Core/createGuid', './Core/Credit', './Core/CubicRealPolynomial', './Core/CylinderGeometry', './Core/CylinderGeometryLibrary', './Core/CylinderOutlineGeometry', './Core/DefaultProxy', './Core/defaultValue', './Core/defined', './Core/defineProperties', './Core/deprecationWarning', './Core/destroyObject', './Core/DeveloperError', './Core/DistanceDisplayCondition', './Core/DistanceDisplayConditionGeometryInstanceAttribute', './Core/EarthOrientationParameters', './Core/EarthOrientationParametersSample', './Core/EasingFunction', './Core/EllipseGeometry', './Core/EllipseGeometryLibrary', './Core/EllipseOutlineGeometry', './Core/Ellipsoid', './Core/EllipsoidalOccluder', './Core/EllipsoidGeodesic', './Core/EllipsoidGeometry', './Core/EllipsoidOutlineGeometry', './Core/EllipsoidTangentPlane', './Core/EllipsoidTerrainProvider', './Core/EncodedCartesian3', './Core/Event', './Core/EventHelper', './Core/ExtrapolationType', './Core/FeatureDetection', './Core/formatError', './Core/freezeObject', './Core/Fullscreen', './Core/GeographicProjection', './Core/GeographicTilingScheme', './Core/Geometry', './Core/GeometryAttribute', './Core/GeometryAttributes', './Core/GeometryInstance', './Core/GeometryInstanceAttribute', './Core/GeometryPipeline', './Core/GeometryType', './Core/getAbsoluteUri', './Core/getBaseUri', './Core/getExtensionFromUri', './Core/getFilenameFromUri', './Core/getImagePixels', './Core/getMagic', './Core/getStringFromTypedArray', './Core/getTimestamp', './Core/GregorianDate', './Core/HeadingPitchRange', './Core/HeadingPitchRoll', './Core/HeightmapTerrainData', './Core/HeightmapTessellator', './Core/HermitePolynomialApproximation', './Core/HermiteSpline', './Core/Iau2000Orientation', './Core/Iau2006XysData', './Core/Iau2006XysSample', './Core/IauOrientationAxes', './Core/IauOrientationParameters', './Core/IndexDatatype', './Core/InterpolationAlgorithm', './Core/Intersect', './Core/Intersections2D', './Core/IntersectionTests', './Core/Interval', './Core/isArray', './Core/isCrossOriginUrl', './Core/isLeapYear', './Core/Iso8601', './Core/joinUrls', './Core/JulianDate', './Core/KeyboardEventModifier', './Core/LagrangePolynomialApproximation', './Core/LeapSecond', './Core/LinearApproximation', './Core/LinearSpline', './Core/loadArrayBuffer', './Core/loadBlob', './Core/loadImage', './Core/loadImageFromTypedArray', './Core/loadImageViaBlob', './Core/loadJson', './Core/loadJsonp', './Core/loadText', './Core/loadWithXhr', './Core/loadXML', './Core/MapboxApi', './Core/MapProjection', './Core/Math', './Core/Matrix2', './Core/Matrix3', './Core/Matrix4', './Core/mergeSort', './Core/NearFarScalar', './Core/objectToQuery', './Core/Occluder', './Core/oneTimeWarning', './Core/OrientedBoundingBox', './Core/Packable', './Core/PackableForInterpolation', './Core/parseResponseHeaders', './Core/PinBuilder', './Core/PixelFormat', './Core/Plane', './Core/PointGeometry', './Core/pointInsideTriangle', './Core/PolygonGeometry', './Core/PolygonGeometryLibrary', './Core/PolygonHierarchy', './Core/PolygonOutlineGeometry', './Core/PolygonPipeline', './Core/PolylineGeometry', './Core/PolylinePipeline', './Core/PolylineVolumeGeometry', './Core/PolylineVolumeGeometryLibrary', './Core/PolylineVolumeOutlineGeometry', './Core/PrimitiveType', './Core/QuadraticRealPolynomial', './Core/QuantizedMeshTerrainData', './Core/QuarticRealPolynomial', './Core/Quaternion', './Core/QuaternionSpline', './Core/queryToObject', './Core/Queue', './Core/Ray', './Core/Rectangle', './Core/RectangleGeometry', './Core/RectangleGeometryLibrary', './Core/RectangleOutlineGeometry', './Core/ReferenceFrame', './Core/requestAnimationFrame', './Core/RequestErrorEvent', './Core/RuntimeError', './Core/sampleTerrain', './Core/scaleToGeodeticSurface', './Core/ScreenSpaceEventHandler', './Core/ScreenSpaceEventType', './Core/ShowGeometryInstanceAttribute', './Core/Simon1994PlanetaryPositions', './Core/SimplePolylineGeometry', './Core/SphereGeometry', './Core/SphereOutlineGeometry', './Core/Spherical', './Core/Spline', './Core/subdivideArray', './Core/TaskProcessor', './Core/TerrainData', './Core/TerrainEncoding', './Core/TerrainMesh', './Core/TerrainProvider', './Core/TerrainQuantization', './Core/throttleRequestByServer', './Core/TileProviderError', './Core/TilingScheme', './Core/TimeConstants', './Core/TimeInterval', './Core/TimeIntervalCollection', './Core/TimeStandard', './Core/Tipsify', './Core/Transforms', './Core/TranslationRotationScale', './Core/TridiagonalSystemSolver', './Core/TrustedServers', './Core/VertexFormat', './Core/VideoSynchronizer', './Core/Visibility', './Core/VRTheWorldTerrainProvider', './Core/WallGeometry', './Core/WallGeometryLibrary', './Core/WallOutlineGeometry', './Core/WebGLConstants', './Core/WebMercatorProjection', './Core/WebMercatorTilingScheme', './Core/WindingOrder', './Core/wrapFunction', './Core/writeTextToCanvas', './DataSources/BillboardGraphics', './DataSources/BillboardVisualizer', './DataSources/BoundingSphereState', './DataSources/BoxGeometryUpdater', './DataSources/BoxGraphics', './DataSources/CallbackProperty', './DataSources/CheckerboardMaterialProperty', './DataSources/ColorMaterialProperty', './DataSources/CompositeEntityCollection', './DataSources/CompositeMaterialProperty', './DataSources/CompositePositionProperty', './DataSources/CompositeProperty', './DataSources/ConstantPositionProperty', './DataSources/ConstantProperty', './DataSources/CorridorGeometryUpdater', './DataSources/CorridorGraphics', './DataSources/createMaterialPropertyDescriptor', './DataSources/createPropertyDescriptor', './DataSources/createRawPropertyDescriptor', './DataSources/CustomDataSource', './DataSources/CylinderGeometryUpdater', './DataSources/CylinderGraphics', './DataSources/CzmlDataSource', './DataSources/DataSource', './DataSources/DataSourceClock', './DataSources/DataSourceCollection', './DataSources/DataSourceDisplay', './DataSources/dynamicGeometryGetBoundingSphere', './DataSources/DynamicGeometryUpdater', './DataSources/EllipseGeometryUpdater', './DataSources/EllipseGraphics', './DataSources/EllipsoidGeometryUpdater', './DataSources/EllipsoidGraphics', './DataSources/Entity', './DataSources/EntityCluster', './DataSources/EntityCollection', './DataSources/EntityView', './DataSources/GeoJsonDataSource', './DataSources/GeometryUpdater', './DataSources/GeometryVisualizer', './DataSources/GridMaterialProperty', './DataSources/ImageMaterialProperty', './DataSources/KmlDataSource', './DataSources/LabelGraphics', './DataSources/LabelVisualizer', './DataSources/MaterialProperty', './DataSources/ModelGraphics', './DataSources/ModelVisualizer', './DataSources/NodeTransformationProperty', './DataSources/PathGraphics', './DataSources/PathVisualizer', './DataSources/PointGraphics', './DataSources/PointVisualizer', './DataSources/PolygonGeometryUpdater', './DataSources/PolygonGraphics', './DataSources/PolylineArrowMaterialProperty', './DataSources/PolylineGeometryUpdater', './DataSources/PolylineGlowMaterialProperty', './DataSources/PolylineGraphics', './DataSources/PolylineOutlineMaterialProperty', './DataSources/PolylineVolumeGeometryUpdater', './DataSources/PolylineVolumeGraphics', './DataSources/PositionProperty', './DataSources/PositionPropertyArray', './DataSources/Property', './DataSources/PropertyArray', './DataSources/PropertyBag', './DataSources/RectangleGeometryUpdater', './DataSources/RectangleGraphics', './DataSources/ReferenceProperty', './DataSources/Rotation', './DataSources/SampledPositionProperty', './DataSources/SampledProperty', './DataSources/ScaledPositionProperty', './DataSources/StaticGeometryColorBatch', './DataSources/StaticGeometryPerMaterialBatch', './DataSources/StaticGroundGeometryColorBatch', './DataSources/StaticOutlineGeometryBatch', './DataSources/StripeMaterialProperty', './DataSources/StripeOrientation', './DataSources/TimeIntervalCollectionPositionProperty', './DataSources/TimeIntervalCollectionProperty', './DataSources/VelocityOrientationProperty', './DataSources/VelocityVectorProperty', './DataSources/Visualizer', './DataSources/WallGeometryUpdater', './DataSources/WallGraphics', './Renderer/AutomaticUniforms', './Renderer/Buffer', './Renderer/BufferUsage', './Renderer/ClearCommand', './Renderer/ComputeCommand', './Renderer/ComputeEngine', './Renderer/Context', './Renderer/ContextLimits', './Renderer/createUniform', './Renderer/createUniformArray', './Renderer/CubeMap', './Renderer/CubeMapFace', './Renderer/DrawCommand', './Renderer/Framebuffer', './Renderer/loadCubeMap', './Renderer/MipmapHint', './Renderer/Pass', './Renderer/PassState', './Renderer/PickFramebuffer', './Renderer/PixelDatatype', './Renderer/Renderbuffer', './Renderer/RenderbufferFormat', './Renderer/RenderState', './Renderer/Sampler', './Renderer/ShaderCache', './Renderer/ShaderProgram', './Renderer/ShaderSource', './Renderer/Texture', './Renderer/TextureMagnificationFilter', './Renderer/TextureMinificationFilter', './Renderer/TextureWrap', './Renderer/UniformState', './Renderer/VertexArray', './Renderer/VertexArrayFacade', './Scene/Appearance', './Scene/ArcGisMapServerImageryProvider', './Scene/BatchTable', './Scene/Billboard', './Scene/BillboardCollection', './Scene/BingMapsImageryProvider', './Scene/BingMapsStyle', './Scene/BlendEquation', './Scene/BlendFunction', './Scene/BlendingState', './Scene/Camera', './Scene/CameraEventAggregator', './Scene/CameraEventType', './Scene/CameraFlightPath', './Scene/ColorBlendMode', './Scene/createOpenStreetMapImageryProvider', './Scene/createTangentSpaceDebugPrimitive', './Scene/createTileMapServiceImageryProvider', './Scene/CreditDisplay', './Scene/CullFace', './Scene/CullingVolume', './Scene/DebugAppearance', './Scene/DebugCameraPrimitive', './Scene/DebugModelMatrixPrimitive', './Scene/DepthFunction', './Scene/DepthPlane', './Scene/DeviceOrientationCameraController', './Scene/DiscardMissingTileImagePolicy', './Scene/EllipsoidPrimitive', './Scene/EllipsoidSurfaceAppearance', './Scene/Fog', './Scene/FrameRateMonitor', './Scene/FrameState', './Scene/FrustumCommands', './Scene/FXAA', './Scene/getAttributeOrUniformBySemantic', './Scene/getBinaryAccessor', './Scene/GetFeatureInfoFormat', './Scene/Globe', './Scene/GlobeDepth', './Scene/GlobeSurfaceShaderSet', './Scene/GlobeSurfaceTile', './Scene/GlobeSurfaceTileProvider', './Scene/GoogleEarthImageryProvider', './Scene/GridImageryProvider', './Scene/GroundPrimitive', './Scene/HeightReference', './Scene/HorizontalOrigin', './Scene/Imagery', './Scene/ImageryLayer', './Scene/ImageryLayerCollection', './Scene/ImageryLayerFeatureInfo', './Scene/ImageryProvider', './Scene/ImageryState', './Scene/Label', './Scene/LabelCollection', './Scene/LabelStyle', './Scene/MapboxImageryProvider', './Scene/MapMode2D', './Scene/Material', './Scene/MaterialAppearance', './Scene/Model', './Scene/ModelAnimation', './Scene/ModelAnimationCache', './Scene/ModelAnimationCollection', './Scene/ModelAnimationLoop', './Scene/ModelAnimationState', './Scene/ModelMaterial', './Scene/modelMaterialsCommon', './Scene/ModelMesh', './Scene/ModelNode', './Scene/Moon', './Scene/NeverTileDiscardPolicy', './Scene/OIT', './Scene/OrthographicFrustum', './Scene/PerformanceDisplay', './Scene/PerInstanceColorAppearance', './Scene/PerspectiveFrustum', './Scene/PerspectiveOffCenterFrustum', './Scene/PickDepth', './Scene/PointAppearance', './Scene/PointPrimitive', './Scene/PointPrimitiveCollection', './Scene/Polyline', './Scene/PolylineCollection', './Scene/PolylineColorAppearance', './Scene/PolylineMaterialAppearance', './Scene/Primitive', './Scene/PrimitiveCollection', './Scene/PrimitivePipeline', './Scene/PrimitiveState', './Scene/QuadtreeOccluders', './Scene/QuadtreePrimitive', './Scene/QuadtreeTile', './Scene/QuadtreeTileLoadState', './Scene/QuadtreeTileProvider', './Scene/Scene', './Scene/SceneMode', './Scene/SceneTransforms', './Scene/SceneTransitioner', './Scene/ScreenSpaceCameraController', './Scene/ShadowMap', './Scene/ShadowMapShader', './Scene/ShadowMode', './Scene/SingleTileImageryProvider', './Scene/SkyAtmosphere', './Scene/SkyBox', './Scene/StencilFunction', './Scene/StencilOperation', './Scene/Sun', './Scene/SunPostProcess', './Scene/TerrainState', './Scene/TextureAtlas', './Scene/TileBoundingBox', './Scene/TileCoordinatesImageryProvider', './Scene/TileDiscardPolicy', './Scene/TileImagery', './Scene/TileReplacementQueue', './Scene/TileState', './Scene/TileTerrain', './Scene/TweenCollection', './Scene/UrlTemplateImageryProvider', './Scene/VerticalOrigin', './Scene/ViewportQuad', './Scene/WebMapServiceImageryProvider', './Scene/WebMapTileServiceImageryProvider', './Shaders/AdjustTranslucentFS', './Shaders/Appearances/AllMaterialAppearanceFS', './Shaders/Appearances/AllMaterialAppearanceVS', './Shaders/Appearances/BasicMaterialAppearanceFS', './Shaders/Appearances/BasicMaterialAppearanceVS', './Shaders/Appearances/EllipsoidSurfaceAppearanceFS', './Shaders/Appearances/EllipsoidSurfaceAppearanceVS', './Shaders/Appearances/PerInstanceColorAppearanceFS', './Shaders/Appearances/PerInstanceColorAppearanceVS', './Shaders/Appearances/PerInstanceFlatColorAppearanceFS', './Shaders/Appearances/PerInstanceFlatColorAppearanceVS', './Shaders/Appearances/PointAppearanceFS', './Shaders/Appearances/PointAppearanceVS', './Shaders/Appearances/PolylineColorAppearanceVS', './Shaders/Appearances/PolylineMaterialAppearanceVS', './Shaders/Appearances/TexturedMaterialAppearanceFS', './Shaders/Appearances/TexturedMaterialAppearanceVS', './Shaders/BillboardCollectionFS', './Shaders/BillboardCollectionVS', './Shaders/Builtin/Constants/degreesPerRadian', './Shaders/Builtin/Constants/depthRange', './Shaders/Builtin/Constants/epsilon1', './Shaders/Builtin/Constants/epsilon2', './Shaders/Builtin/Constants/epsilon3', './Shaders/Builtin/Constants/epsilon4', './Shaders/Builtin/Constants/epsilon5', './Shaders/Builtin/Constants/epsilon6', './Shaders/Builtin/Constants/epsilon7', './Shaders/Builtin/Constants/infinity', './Shaders/Builtin/Constants/oneOverPi', './Shaders/Builtin/Constants/oneOverTwoPi', './Shaders/Builtin/Constants/passCompute', './Shaders/Builtin/Constants/passEnvironment', './Shaders/Builtin/Constants/passGlobe', './Shaders/Builtin/Constants/passGround', './Shaders/Builtin/Constants/passOpaque', './Shaders/Builtin/Constants/passOverlay', './Shaders/Builtin/Constants/passTranslucent', './Shaders/Builtin/Constants/pi', './Shaders/Builtin/Constants/piOverFour', './Shaders/Builtin/Constants/piOverSix', './Shaders/Builtin/Constants/piOverThree', './Shaders/Builtin/Constants/piOverTwo', './Shaders/Builtin/Constants/radiansPerDegree', './Shaders/Builtin/Constants/sceneMode2D', './Shaders/Builtin/Constants/sceneMode3D', './Shaders/Builtin/Constants/sceneModeColumbusView', './Shaders/Builtin/Constants/sceneModeMorphing', './Shaders/Builtin/Constants/solarRadius', './Shaders/Builtin/Constants/threePiOver2', './Shaders/Builtin/Constants/twoPi', './Shaders/Builtin/Constants/webMercatorMaxLatitude', './Shaders/Builtin/CzmBuiltins', './Shaders/Builtin/Functions/alphaWeight', './Shaders/Builtin/Functions/antialias', './Shaders/Builtin/Functions/cascadeColor', './Shaders/Builtin/Functions/cascadeDistance', './Shaders/Builtin/Functions/cascadeMatrix', './Shaders/Builtin/Functions/cascadeWeights', './Shaders/Builtin/Functions/columbusViewMorph', './Shaders/Builtin/Functions/computePosition', './Shaders/Builtin/Functions/cosineAndSine', './Shaders/Builtin/Functions/decompressTextureCoordinates', './Shaders/Builtin/Functions/eastNorthUpToEyeCoordinates', './Shaders/Builtin/Functions/ellipsoidContainsPoint', './Shaders/Builtin/Functions/ellipsoidNew', './Shaders/Builtin/Functions/ellipsoidWgs84TextureCoordinates', './Shaders/Builtin/Functions/equalsEpsilon', './Shaders/Builtin/Functions/eyeOffset', './Shaders/Builtin/Functions/eyeToWindowCoordinates', './Shaders/Builtin/Functions/fog', './Shaders/Builtin/Functions/geodeticSurfaceNormal', './Shaders/Builtin/Functions/getDefaultMaterial', './Shaders/Builtin/Functions/getLambertDiffuse', './Shaders/Builtin/Functions/getSpecular', './Shaders/Builtin/Functions/getWaterNoise', './Shaders/Builtin/Functions/getWgs84EllipsoidEC', './Shaders/Builtin/Functions/hue', './Shaders/Builtin/Functions/isEmpty', './Shaders/Builtin/Functions/isFull', './Shaders/Builtin/Functions/latitudeToWebMercatorFraction', './Shaders/Builtin/Functions/luminance', './Shaders/Builtin/Functions/metersPerPixel', './Shaders/Builtin/Functions/modelToWindowCoordinates', './Shaders/Builtin/Functions/multiplyWithColorBalance', './Shaders/Builtin/Functions/nearFarScalar', './Shaders/Builtin/Functions/octDecode', './Shaders/Builtin/Functions/packDepth', './Shaders/Builtin/Functions/phong', './Shaders/Builtin/Functions/pointAlongRay', './Shaders/Builtin/Functions/rayEllipsoidIntersectionInterval', './Shaders/Builtin/Functions/RGBToXYZ', './Shaders/Builtin/Functions/saturation', './Shaders/Builtin/Functions/shadowDepthCompare', './Shaders/Builtin/Functions/shadowVisibility', './Shaders/Builtin/Functions/signNotZero', './Shaders/Builtin/Functions/tangentToEyeSpaceMatrix', './Shaders/Builtin/Functions/translateRelativeToEye', './Shaders/Builtin/Functions/translucentPhong', './Shaders/Builtin/Functions/transpose', './Shaders/Builtin/Functions/unpackDepth', './Shaders/Builtin/Functions/windowToEyeCoordinates', './Shaders/Builtin/Functions/XYZToRGB', './Shaders/Builtin/Structs/depthRangeStruct', './Shaders/Builtin/Structs/ellipsoid', './Shaders/Builtin/Structs/material', './Shaders/Builtin/Structs/materialInput', './Shaders/Builtin/Structs/ray', './Shaders/Builtin/Structs/raySegment', './Shaders/Builtin/Structs/shadowParameters', './Shaders/CompositeOITFS', './Shaders/DepthPlaneFS', './Shaders/DepthPlaneVS', './Shaders/EllipsoidFS', './Shaders/EllipsoidVS', './Shaders/GlobeFS', './Shaders/GlobeVS', './Shaders/GroundAtmosphere', './Shaders/Materials/BumpMapMaterial', './Shaders/Materials/CheckerboardMaterial', './Shaders/Materials/DotMaterial', './Shaders/Materials/FadeMaterial', './Shaders/Materials/GridMaterial', './Shaders/Materials/NormalMapMaterial', './Shaders/Materials/PolylineArrowMaterial', './Shaders/Materials/PolylineGlowMaterial', './Shaders/Materials/PolylineOutlineMaterial', './Shaders/Materials/RimLightingMaterial', './Shaders/Materials/StripeMaterial', './Shaders/Materials/Water', './Shaders/PointPrimitiveCollectionFS', './Shaders/PointPrimitiveCollectionVS', './Shaders/PolylineCommon', './Shaders/PolylineFS', './Shaders/PolylineVS', './Shaders/PostProcessFilters/AdditiveBlend', './Shaders/PostProcessFilters/BrightPass', './Shaders/PostProcessFilters/FXAA', './Shaders/PostProcessFilters/GaussianBlur1D', './Shaders/PostProcessFilters/PassThrough', './Shaders/ReprojectWebMercatorFS', './Shaders/ReprojectWebMercatorVS', './Shaders/ShadowVolumeFS', './Shaders/ShadowVolumeVS', './Shaders/SkyAtmosphereFS', './Shaders/SkyAtmosphereVS', './Shaders/SkyBoxFS', './Shaders/SkyBoxVS', './Shaders/SunFS', './Shaders/SunTextureFS', './Shaders/SunVS', './Shaders/ViewportQuadFS', './Shaders/ViewportQuadVS', './ThirdParty/Autolinker', './ThirdParty/earcut-2.1.1', './ThirdParty/gltfDefaults', './ThirdParty/kdbush', './ThirdParty/knockout-3.4.0', './ThirdParty/knockout-es5', './ThirdParty/knockout', './ThirdParty/measureText', './ThirdParty/mersenne-twister', './ThirdParty/NoSleep', './ThirdParty/sprintf', './ThirdParty/topojson', './ThirdParty/Tween', './ThirdParty/Uri', './ThirdParty/when', './ThirdParty/zip', './Widgets/Animation/Animation', './Widgets/Animation/AnimationViewModel', './Widgets/BaseLayerPicker/BaseLayerPicker', './Widgets/BaseLayerPicker/BaseLayerPickerViewModel', './Widgets/BaseLayerPicker/createDefaultImageryProviderViewModels', './Widgets/BaseLayerPicker/createDefaultTerrainProviderViewModels', './Widgets/BaseLayerPicker/ProviderViewModel', './Widgets/CesiumInspector/CesiumInspector', './Widgets/CesiumInspector/CesiumInspectorViewModel', './Widgets/CesiumWidget/CesiumWidget', './Widgets/ClockViewModel', './Widgets/Command', './Widgets/createCommand', './Widgets/FullscreenButton/FullscreenButton', './Widgets/FullscreenButton/FullscreenButtonViewModel', './Widgets/Geocoder/Geocoder', './Widgets/Geocoder/GeocoderViewModel', './Widgets/getElement', './Widgets/HomeButton/HomeButton', './Widgets/HomeButton/HomeButtonViewModel', './Widgets/InfoBox/InfoBox', './Widgets/InfoBox/InfoBoxViewModel', './Widgets/NavigationHelpButton/NavigationHelpButton', './Widgets/NavigationHelpButton/NavigationHelpButtonViewModel', './Widgets/PerformanceWatchdog/PerformanceWatchdog', './Widgets/PerformanceWatchdog/PerformanceWatchdogViewModel', './Widgets/SceneModePicker/SceneModePicker', './Widgets/SceneModePicker/SceneModePickerViewModel', './Widgets/SelectionIndicator/SelectionIndicator', './Widgets/SelectionIndicator/SelectionIndicatorViewModel', './Widgets/subscribeAndEvaluate', './Widgets/SvgPathBindingHandler', './Widgets/Timeline/Timeline', './Widgets/Timeline/TimelineHighlightRange', './Widgets/Timeline/TimelineTrack', './Widgets/ToggleButtonViewModel', './Widgets/Viewer/Viewer', './Widgets/Viewer/viewerCesiumInspectorMixin', './Widgets/Viewer/viewerDragDropMixin', './Widgets/Viewer/viewerPerformanceWatchdogMixin', './Widgets/VRButton/VRButton', './Widgets/VRButton/VRButtonViewModel', './Workers/createTaskProcessorWorker'], function(Core_appendForwardSlash, Core_ArcGisImageServerTerrainProvider, Core_arrayRemoveDuplicates, Core_AssociativeArray, Core_AttributeCompression, Core_AxisAlignedBoundingBox, Core_barycentricCoordinates, Core_binarySearch, Core_BingMapsApi, Core_BoundingRectangle, Core_BoundingSphere, Core_BoxGeometry, Core_BoxOutlineGeometry, Core_buildModuleUrl, Core_cancelAnimationFrame, Core_Cartesian2, Core_Cartesian3, Core_Cartesian4, Core_Cartographic, Core_CatmullRomSpline, Core_CesiumTerrainProvider, Core_Check, Core_CircleGeometry, Core_CircleOutlineGeometry, Core_Clock, Core_ClockRange, Core_ClockStep, Core_clone, Core_Color, Core_ColorGeometryInstanceAttribute, Core_combine, Core_ComponentDatatype, Core_CornerType, Core_CorridorGeometry, Core_CorridorGeometryLibrary, Core_CorridorOutlineGeometry, Core_createGuid, Core_Credit, Core_CubicRealPolynomial, Core_CylinderGeometry, Core_CylinderGeometryLibrary, Core_CylinderOutlineGeometry, Core_DefaultProxy, Core_defaultValue, Core_defined, Core_defineProperties, Core_deprecationWarning, Core_destroyObject, Core_DeveloperError, Core_DistanceDisplayCondition, Core_DistanceDisplayConditionGeometryInstanceAttribute, Core_EarthOrientationParameters, Core_EarthOrientationParametersSample, Core_EasingFunction, Core_EllipseGeometry, Core_EllipseGeometryLibrary, Core_EllipseOutlineGeometry, Core_Ellipsoid, Core_EllipsoidalOccluder, Core_EllipsoidGeodesic, Core_EllipsoidGeometry, Core_EllipsoidOutlineGeometry, Core_EllipsoidTangentPlane, Core_EllipsoidTerrainProvider, Core_EncodedCartesian3, Core_Event, Core_EventHelper, Core_ExtrapolationType, Core_FeatureDetection, Core_formatError, Core_freezeObject, Core_Fullscreen, Core_GeographicProjection, Core_GeographicTilingScheme, Core_Geometry, Core_GeometryAttribute, Core_GeometryAttributes, Core_GeometryInstance, Core_GeometryInstanceAttribute, Core_GeometryPipeline, Core_GeometryType, Core_getAbsoluteUri, Core_getBaseUri, Core_getExtensionFromUri, Core_getFilenameFromUri, Core_getImagePixels, Core_getMagic, Core_getStringFromTypedArray, Core_getTimestamp, Core_GregorianDate, Core_HeadingPitchRange, Core_HeadingPitchRoll, Core_HeightmapTerrainData, Core_HeightmapTessellator, Core_HermitePolynomialApproximation, Core_HermiteSpline, Core_Iau2000Orientation, Core_Iau2006XysData, Core_Iau2006XysSample, Core_IauOrientationAxes, Core_IauOrientationParameters, Core_IndexDatatype, Core_InterpolationAlgorithm, Core_Intersect, Core_Intersections2D, Core_IntersectionTests, Core_Interval, Core_isArray, Core_isCrossOriginUrl, Core_isLeapYear, Core_Iso8601, Core_joinUrls, Core_JulianDate, Core_KeyboardEventModifier, Core_LagrangePolynomialApproximation, Core_LeapSecond, Core_LinearApproximation, Core_LinearSpline, Core_loadArrayBuffer, Core_loadBlob, Core_loadImage, Core_loadImageFromTypedArray, Core_loadImageViaBlob, Core_loadJson, Core_loadJsonp, Core_loadText, Core_loadWithXhr, Core_loadXML, Core_MapboxApi, Core_MapProjection, Core_Math, Core_Matrix2, Core_Matrix3, Core_Matrix4, Core_mergeSort, Core_NearFarScalar, Core_objectToQuery, Core_Occluder, Core_oneTimeWarning, Core_OrientedBoundingBox, Core_Packable, Core_PackableForInterpolation, Core_parseResponseHeaders, Core_PinBuilder, Core_PixelFormat, Core_Plane, Core_PointGeometry, Core_pointInsideTriangle, Core_PolygonGeometry, Core_PolygonGeometryLibrary, Core_PolygonHierarchy, Core_PolygonOutlineGeometry, Core_PolygonPipeline, Core_PolylineGeometry, Core_PolylinePipeline, Core_PolylineVolumeGeometry, Core_PolylineVolumeGeometryLibrary, Core_PolylineVolumeOutlineGeometry, Core_PrimitiveType, Core_QuadraticRealPolynomial, Core_QuantizedMeshTerrainData, Core_QuarticRealPolynomial, Core_Quaternion, Core_QuaternionSpline, Core_queryToObject, Core_Queue, Core_Ray, Core_Rectangle, Core_RectangleGeometry, Core_RectangleGeometryLibrary, Core_RectangleOutlineGeometry, Core_ReferenceFrame, Core_requestAnimationFrame, Core_RequestErrorEvent, Core_RuntimeError, Core_sampleTerrain, Core_scaleToGeodeticSurface, Core_ScreenSpaceEventHandler, Core_ScreenSpaceEventType, Core_ShowGeometryInstanceAttribute, Core_Simon1994PlanetaryPositions, Core_SimplePolylineGeometry, Core_SphereGeometry, Core_SphereOutlineGeometry, Core_Spherical, Core_Spline, Core_subdivideArray, Core_TaskProcessor, Core_TerrainData, Core_TerrainEncoding, Core_TerrainMesh, Core_TerrainProvider, Core_TerrainQuantization, Core_throttleRequestByServer, Core_TileProviderError, Core_TilingScheme, Core_TimeConstants, Core_TimeInterval, Core_TimeIntervalCollection, Core_TimeStandard, Core_Tipsify, Core_Transforms, Core_TranslationRotationScale, Core_TridiagonalSystemSolver, Core_TrustedServers, Core_VertexFormat, Core_VideoSynchronizer, Core_Visibility, Core_VRTheWorldTerrainProvider, Core_WallGeometry, Core_WallGeometryLibrary, Core_WallOutlineGeometry, Core_WebGLConstants, Core_WebMercatorProjection, Core_WebMercatorTilingScheme, Core_WindingOrder, Core_wrapFunction, Core_writeTextToCanvas, DataSources_BillboardGraphics, DataSources_BillboardVisualizer, DataSources_BoundingSphereState, DataSources_BoxGeometryUpdater, DataSources_BoxGraphics, DataSources_CallbackProperty, DataSources_CheckerboardMaterialProperty, DataSources_ColorMaterialProperty, DataSources_CompositeEntityCollection, DataSources_CompositeMaterialProperty, DataSources_CompositePositionProperty, DataSources_CompositeProperty, DataSources_ConstantPositionProperty, DataSources_ConstantProperty, DataSources_CorridorGeometryUpdater, DataSources_CorridorGraphics, DataSources_createMaterialPropertyDescriptor, DataSources_createPropertyDescriptor, DataSources_createRawPropertyDescriptor, DataSources_CustomDataSource, DataSources_CylinderGeometryUpdater, DataSources_CylinderGraphics, DataSources_CzmlDataSource, DataSources_DataSource, DataSources_DataSourceClock, DataSources_DataSourceCollection, DataSources_DataSourceDisplay, DataSources_dynamicGeometryGetBoundingSphere, DataSources_DynamicGeometryUpdater, DataSources_EllipseGeometryUpdater, DataSources_EllipseGraphics, DataSources_EllipsoidGeometryUpdater, DataSources_EllipsoidGraphics, DataSources_Entity, DataSources_EntityCluster, DataSources_EntityCollection, DataSources_EntityView, DataSources_GeoJsonDataSource, DataSources_GeometryUpdater, DataSources_GeometryVisualizer, DataSources_GridMaterialProperty, DataSources_ImageMaterialProperty, DataSources_KmlDataSource, DataSources_LabelGraphics, DataSources_LabelVisualizer, DataSources_MaterialProperty, DataSources_ModelGraphics, DataSources_ModelVisualizer, DataSources_NodeTransformationProperty, DataSources_PathGraphics, DataSources_PathVisualizer, DataSources_PointGraphics, DataSources_PointVisualizer, DataSources_PolygonGeometryUpdater, DataSources_PolygonGraphics, DataSources_PolylineArrowMaterialProperty, DataSources_PolylineGeometryUpdater, DataSources_PolylineGlowMaterialProperty, DataSources_PolylineGraphics, DataSources_PolylineOutlineMaterialProperty, DataSources_PolylineVolumeGeometryUpdater, DataSources_PolylineVolumeGraphics, DataSources_PositionProperty, DataSources_PositionPropertyArray, DataSources_Property, DataSources_PropertyArray, DataSources_PropertyBag, DataSources_RectangleGeometryUpdater, DataSources_RectangleGraphics, DataSources_ReferenceProperty, DataSources_Rotation, DataSources_SampledPositionProperty, DataSources_SampledProperty, DataSources_ScaledPositionProperty, DataSources_StaticGeometryColorBatch, DataSources_StaticGeometryPerMaterialBatch, DataSources_StaticGroundGeometryColorBatch, DataSources_StaticOutlineGeometryBatch, DataSources_StripeMaterialProperty, DataSources_StripeOrientation, DataSources_TimeIntervalCollectionPositionProperty, DataSources_TimeIntervalCollectionProperty, DataSources_VelocityOrientationProperty, DataSources_VelocityVectorProperty, DataSources_Visualizer, DataSources_WallGeometryUpdater, DataSources_WallGraphics, Renderer_AutomaticUniforms, Renderer_Buffer, Renderer_BufferUsage, Renderer_ClearCommand, Renderer_ComputeCommand, Renderer_ComputeEngine, Renderer_Context, Renderer_ContextLimits, Renderer_createUniform, Renderer_createUniformArray, Renderer_CubeMap, Renderer_CubeMapFace, Renderer_DrawCommand, Renderer_Framebuffer, Renderer_loadCubeMap, Renderer_MipmapHint, Renderer_Pass, Renderer_PassState, Renderer_PickFramebuffer, Renderer_PixelDatatype, Renderer_Renderbuffer, Renderer_RenderbufferFormat, Renderer_RenderState, Renderer_Sampler, Renderer_ShaderCache, Renderer_ShaderProgram, Renderer_ShaderSource, Renderer_Texture, Renderer_TextureMagnificationFilter, Renderer_TextureMinificationFilter, Renderer_TextureWrap, Renderer_UniformState, Renderer_VertexArray, Renderer_VertexArrayFacade, Scene_Appearance, Scene_ArcGisMapServerImageryProvider, Scene_BatchTable, Scene_Billboard, Scene_BillboardCollection, Scene_BingMapsImageryProvider, Scene_BingMapsStyle, Scene_BlendEquation, Scene_BlendFunction, Scene_BlendingState, Scene_Camera, Scene_CameraEventAggregator, Scene_CameraEventType, Scene_CameraFlightPath, Scene_ColorBlendMode, Scene_createOpenStreetMapImageryProvider, Scene_createTangentSpaceDebugPrimitive, Scene_createTileMapServiceImageryProvider, Scene_CreditDisplay, Scene_CullFace, Scene_CullingVolume, Scene_DebugAppearance, Scene_DebugCameraPrimitive, Scene_DebugModelMatrixPrimitive, Scene_DepthFunction, Scene_DepthPlane, Scene_DeviceOrientationCameraController, Scene_DiscardMissingTileImagePolicy, Scene_EllipsoidPrimitive, Scene_EllipsoidSurfaceAppearance, Scene_Fog, Scene_FrameRateMonitor, Scene_FrameState, Scene_FrustumCommands, Scene_FXAA, Scene_getAttributeOrUniformBySemantic, Scene_getBinaryAccessor, Scene_GetFeatureInfoFormat, Scene_Globe, Scene_GlobeDepth, Scene_GlobeSurfaceShaderSet, Scene_GlobeSurfaceTile, Scene_GlobeSurfaceTileProvider, Scene_GoogleEarthImageryProvider, Scene_GridImageryProvider, Scene_GroundPrimitive, Scene_HeightReference, Scene_HorizontalOrigin, Scene_Imagery, Scene_ImageryLayer, Scene_ImageryLayerCollection, Scene_ImageryLayerFeatureInfo, Scene_ImageryProvider, Scene_ImageryState, Scene_Label, Scene_LabelCollection, Scene_LabelStyle, Scene_MapboxImageryProvider, Scene_MapMode2D, Scene_Material, Scene_MaterialAppearance, Scene_Model, Scene_ModelAnimation, Scene_ModelAnimationCache, Scene_ModelAnimationCollection, Scene_ModelAnimationLoop, Scene_ModelAnimationState, Scene_ModelMaterial, Scene_modelMaterialsCommon, Scene_ModelMesh, Scene_ModelNode, Scene_Moon, Scene_NeverTileDiscardPolicy, Scene_OIT, Scene_OrthographicFrustum, Scene_PerformanceDisplay, Scene_PerInstanceColorAppearance, Scene_PerspectiveFrustum, Scene_PerspectiveOffCenterFrustum, Scene_PickDepth, Scene_PointAppearance, Scene_PointPrimitive, Scene_PointPrimitiveCollection, Scene_Polyline, Scene_PolylineCollection, Scene_PolylineColorAppearance, Scene_PolylineMaterialAppearance, Scene_Primitive, Scene_PrimitiveCollection, Scene_PrimitivePipeline, Scene_PrimitiveState, Scene_QuadtreeOccluders, Scene_QuadtreePrimitive, Scene_QuadtreeTile, Scene_QuadtreeTileLoadState, Scene_QuadtreeTileProvider, Scene_Scene, Scene_SceneMode, Scene_SceneTransforms, Scene_SceneTransitioner, Scene_ScreenSpaceCameraController, Scene_ShadowMap, Scene_ShadowMapShader, Scene_ShadowMode, Scene_SingleTileImageryProvider, Scene_SkyAtmosphere, Scene_SkyBox, Scene_StencilFunction, Scene_StencilOperation, Scene_Sun, Scene_SunPostProcess, Scene_TerrainState, Scene_TextureAtlas, Scene_TileBoundingBox, Scene_TileCoordinatesImageryProvider, Scene_TileDiscardPolicy, Scene_TileImagery, Scene_TileReplacementQueue, Scene_TileState, Scene_TileTerrain, Scene_TweenCollection, Scene_UrlTemplateImageryProvider, Scene_VerticalOrigin, Scene_ViewportQuad, Scene_WebMapServiceImageryProvider, Scene_WebMapTileServiceImageryProvider, Shaders_AdjustTranslucentFS, Shaders_Appearances_AllMaterialAppearanceFS, Shaders_Appearances_AllMaterialAppearanceVS, Shaders_Appearances_BasicMaterialAppearanceFS, Shaders_Appearances_BasicMaterialAppearanceVS, Shaders_Appearances_EllipsoidSurfaceAppearanceFS, Shaders_Appearances_EllipsoidSurfaceAppearanceVS, Shaders_Appearances_PerInstanceColorAppearanceFS, Shaders_Appearances_PerInstanceColorAppearanceVS, Shaders_Appearances_PerInstanceFlatColorAppearanceFS, Shaders_Appearances_PerInstanceFlatColorAppearanceVS, Shaders_Appearances_PointAppearanceFS, Shaders_Appearances_PointAppearanceVS, Shaders_Appearances_PolylineColorAppearanceVS, Shaders_Appearances_PolylineMaterialAppearanceVS, Shaders_Appearances_TexturedMaterialAppearanceFS, Shaders_Appearances_TexturedMaterialAppearanceVS, Shaders_BillboardCollectionFS, Shaders_BillboardCollectionVS, Shaders_Builtin_Constants_degreesPerRadian, Shaders_Builtin_Constants_depthRange, Shaders_Builtin_Constants_epsilon1, Shaders_Builtin_Constants_epsilon2, Shaders_Builtin_Constants_epsilon3, Shaders_Builtin_Constants_epsilon4, Shaders_Builtin_Constants_epsilon5, Shaders_Builtin_Constants_epsilon6, Shaders_Builtin_Constants_epsilon7, Shaders_Builtin_Constants_infinity, Shaders_Builtin_Constants_oneOverPi, Shaders_Builtin_Constants_oneOverTwoPi, Shaders_Builtin_Constants_passCompute, Shaders_Builtin_Constants_passEnvironment, Shaders_Builtin_Constants_passGlobe, Shaders_Builtin_Constants_passGround, Shaders_Builtin_Constants_passOpaque, Shaders_Builtin_Constants_passOverlay, Shaders_Builtin_Constants_passTranslucent, Shaders_Builtin_Constants_pi, Shaders_Builtin_Constants_piOverFour, Shaders_Builtin_Constants_piOverSix, Shaders_Builtin_Constants_piOverThree, Shaders_Builtin_Constants_piOverTwo, Shaders_Builtin_Constants_radiansPerDegree, Shaders_Builtin_Constants_sceneMode2D, Shaders_Builtin_Constants_sceneMode3D, Shaders_Builtin_Constants_sceneModeColumbusView, Shaders_Builtin_Constants_sceneModeMorphing, Shaders_Builtin_Constants_solarRadius, Shaders_Builtin_Constants_threePiOver2, Shaders_Builtin_Constants_twoPi, Shaders_Builtin_Constants_webMercatorMaxLatitude, Shaders_Builtin_CzmBuiltins, Shaders_Builtin_Functions_alphaWeight, Shaders_Builtin_Functions_antialias, Shaders_Builtin_Functions_cascadeColor, Shaders_Builtin_Functions_cascadeDistance, Shaders_Builtin_Functions_cascadeMatrix, Shaders_Builtin_Functions_cascadeWeights, Shaders_Builtin_Functions_columbusViewMorph, Shaders_Builtin_Functions_computePosition, Shaders_Builtin_Functions_cosineAndSine, Shaders_Builtin_Functions_decompressTextureCoordinates, Shaders_Builtin_Functions_eastNorthUpToEyeCoordinates, Shaders_Builtin_Functions_ellipsoidContainsPoint, Shaders_Builtin_Functions_ellipsoidNew, Shaders_Builtin_Functions_ellipsoidWgs84TextureCoordinates, Shaders_Builtin_Functions_equalsEpsilon, Shaders_Builtin_Functions_eyeOffset, Shaders_Builtin_Functions_eyeToWindowCoordinates, Shaders_Builtin_Functions_fog, Shaders_Builtin_Functions_geodeticSurfaceNormal, Shaders_Builtin_Functions_getDefaultMaterial, Shaders_Builtin_Functions_getLambertDiffuse, Shaders_Builtin_Functions_getSpecular, Shaders_Builtin_Functions_getWaterNoise, Shaders_Builtin_Functions_getWgs84EllipsoidEC, Shaders_Builtin_Functions_hue, Shaders_Builtin_Functions_isEmpty, Shaders_Builtin_Functions_isFull, Shaders_Builtin_Functions_latitudeToWebMercatorFraction, Shaders_Builtin_Functions_luminance, Shaders_Builtin_Functions_metersPerPixel, Shaders_Builtin_Functions_modelToWindowCoordinates, Shaders_Builtin_Functions_multiplyWithColorBalance, Shaders_Builtin_Functions_nearFarScalar, Shaders_Builtin_Functions_octDecode, Shaders_Builtin_Functions_packDepth, Shaders_Builtin_Functions_phong, Shaders_Builtin_Functions_pointAlongRay, Shaders_Builtin_Functions_rayEllipsoidIntersectionInterval, Shaders_Builtin_Functions_RGBToXYZ, Shaders_Builtin_Functions_saturation, Shaders_Builtin_Functions_shadowDepthCompare, Shaders_Builtin_Functions_shadowVisibility, Shaders_Builtin_Functions_signNotZero, Shaders_Builtin_Functions_tangentToEyeSpaceMatrix, Shaders_Builtin_Functions_translateRelativeToEye, Shaders_Builtin_Functions_translucentPhong, Shaders_Builtin_Functions_transpose, Shaders_Builtin_Functions_unpackDepth, Shaders_Builtin_Functions_windowToEyeCoordinates, Shaders_Builtin_Functions_XYZToRGB, Shaders_Builtin_Structs_depthRangeStruct, Shaders_Builtin_Structs_ellipsoid, Shaders_Builtin_Structs_material, Shaders_Builtin_Structs_materialInput, Shaders_Builtin_Structs_ray, Shaders_Builtin_Structs_raySegment, Shaders_Builtin_Structs_shadowParameters, Shaders_CompositeOITFS, Shaders_DepthPlaneFS, Shaders_DepthPlaneVS, Shaders_EllipsoidFS, Shaders_EllipsoidVS, Shaders_GlobeFS, Shaders_GlobeVS, Shaders_GroundAtmosphere, Shaders_Materials_BumpMapMaterial, Shaders_Materials_CheckerboardMaterial, Shaders_Materials_DotMaterial, Shaders_Materials_FadeMaterial, Shaders_Materials_GridMaterial, Shaders_Materials_NormalMapMaterial, Shaders_Materials_PolylineArrowMaterial, Shaders_Materials_PolylineGlowMaterial, Shaders_Materials_PolylineOutlineMaterial, Shaders_Materials_RimLightingMaterial, Shaders_Materials_StripeMaterial, Shaders_Materials_Water, Shaders_PointPrimitiveCollectionFS, Shaders_PointPrimitiveCollectionVS, Shaders_PolylineCommon, Shaders_PolylineFS, Shaders_PolylineVS, Shaders_PostProcessFilters_AdditiveBlend, Shaders_PostProcessFilters_BrightPass, Shaders_PostProcessFilters_FXAA, Shaders_PostProcessFilters_GaussianBlur1D, Shaders_PostProcessFilters_PassThrough, Shaders_ReprojectWebMercatorFS, Shaders_ReprojectWebMercatorVS, Shaders_ShadowVolumeFS, Shaders_ShadowVolumeVS, Shaders_SkyAtmosphereFS, Shaders_SkyAtmosphereVS, Shaders_SkyBoxFS, Shaders_SkyBoxVS, Shaders_SunFS, Shaders_SunTextureFS, Shaders_SunVS, Shaders_ViewportQuadFS, Shaders_ViewportQuadVS, ThirdParty_Autolinker, ThirdParty_earcut_2_1_1, ThirdParty_gltfDefaults, ThirdParty_kdbush, ThirdParty_knockout_3_4_0, ThirdParty_knockout_es5, ThirdParty_knockout, ThirdParty_measureText, ThirdParty_mersenne_twister, ThirdParty_NoSleep, ThirdParty_sprintf, ThirdParty_topojson, ThirdParty_Tween, ThirdParty_Uri, ThirdParty_when, ThirdParty_zip, Widgets_Animation_Animation, Widgets_Animation_AnimationViewModel, Widgets_BaseLayerPicker_BaseLayerPicker, Widgets_BaseLayerPicker_BaseLayerPickerViewModel, Widgets_BaseLayerPicker_createDefaultImageryProviderViewModels, Widgets_BaseLayerPicker_createDefaultTerrainProviderViewModels, Widgets_BaseLayerPicker_ProviderViewModel, Widgets_CesiumInspector_CesiumInspector, Widgets_CesiumInspector_CesiumInspectorViewModel, Widgets_CesiumWidget_CesiumWidget, Widgets_ClockViewModel, Widgets_Command, Widgets_createCommand, Widgets_FullscreenButton_FullscreenButton, Widgets_FullscreenButton_FullscreenButtonViewModel, Widgets_Geocoder_Geocoder, Widgets_Geocoder_GeocoderViewModel, Widgets_getElement, Widgets_HomeButton_HomeButton, Widgets_HomeButton_HomeButtonViewModel, Widgets_InfoBox_InfoBox, Widgets_InfoBox_InfoBoxViewModel, Widgets_NavigationHelpButton_NavigationHelpButton, Widgets_NavigationHelpButton_NavigationHelpButtonViewModel, Widgets_PerformanceWatchdog_PerformanceWatchdog, Widgets_PerformanceWatchdog_PerformanceWatchdogViewModel, Widgets_SceneModePicker_SceneModePicker, Widgets_SceneModePicker_SceneModePickerViewModel, Widgets_SelectionIndicator_SelectionIndicator, Widgets_SelectionIndicator_SelectionIndicatorViewModel, Widgets_subscribeAndEvaluate, Widgets_SvgPathBindingHandler, Widgets_Timeline_Timeline, Widgets_Timeline_TimelineHighlightRange, Widgets_Timeline_TimelineTrack, Widgets_ToggleButtonViewModel, Widgets_Viewer_Viewer, Widgets_Viewer_viewerCesiumInspectorMixin, Widgets_Viewer_viewerDragDropMixin, Widgets_Viewer_viewerPerformanceWatchdogMixin, Widgets_VRButton_VRButton, Widgets_VRButton_VRButtonViewModel, Workers_createTaskProcessorWorker) {
  163228. 'use strict';
  163229. /*jshint sub:true*/
  163230. var Cesium = {
  163231. VERSION : "1.29",
  163232. _shaders : {}
  163233. };
  163234. Cesium['appendForwardSlash'] = Core_appendForwardSlash;
  163235. Cesium['ArcGisImageServerTerrainProvider'] = Core_ArcGisImageServerTerrainProvider;
  163236. Cesium['arrayRemoveDuplicates'] = Core_arrayRemoveDuplicates;
  163237. Cesium['AssociativeArray'] = Core_AssociativeArray;
  163238. Cesium['AttributeCompression'] = Core_AttributeCompression;
  163239. Cesium['AxisAlignedBoundingBox'] = Core_AxisAlignedBoundingBox;
  163240. Cesium['barycentricCoordinates'] = Core_barycentricCoordinates;
  163241. Cesium['binarySearch'] = Core_binarySearch;
  163242. Cesium['BingMapsApi'] = Core_BingMapsApi;
  163243. Cesium['BoundingRectangle'] = Core_BoundingRectangle;
  163244. Cesium['BoundingSphere'] = Core_BoundingSphere;
  163245. Cesium['BoxGeometry'] = Core_BoxGeometry;
  163246. Cesium['BoxOutlineGeometry'] = Core_BoxOutlineGeometry;
  163247. Cesium['buildModuleUrl'] = Core_buildModuleUrl;
  163248. Cesium['cancelAnimationFrame'] = Core_cancelAnimationFrame;
  163249. Cesium['Cartesian2'] = Core_Cartesian2;
  163250. Cesium['Cartesian3'] = Core_Cartesian3;
  163251. Cesium['Cartesian4'] = Core_Cartesian4;
  163252. Cesium['Cartographic'] = Core_Cartographic;
  163253. Cesium['CatmullRomSpline'] = Core_CatmullRomSpline;
  163254. Cesium['CesiumTerrainProvider'] = Core_CesiumTerrainProvider;
  163255. Cesium['Check'] = Core_Check;
  163256. Cesium['CircleGeometry'] = Core_CircleGeometry;
  163257. Cesium['CircleOutlineGeometry'] = Core_CircleOutlineGeometry;
  163258. Cesium['Clock'] = Core_Clock;
  163259. Cesium['ClockRange'] = Core_ClockRange;
  163260. Cesium['ClockStep'] = Core_ClockStep;
  163261. Cesium['clone'] = Core_clone;
  163262. Cesium['Color'] = Core_Color;
  163263. Cesium['ColorGeometryInstanceAttribute'] = Core_ColorGeometryInstanceAttribute;
  163264. Cesium['combine'] = Core_combine;
  163265. Cesium['ComponentDatatype'] = Core_ComponentDatatype;
  163266. Cesium['CornerType'] = Core_CornerType;
  163267. Cesium['CorridorGeometry'] = Core_CorridorGeometry;
  163268. Cesium['CorridorGeometryLibrary'] = Core_CorridorGeometryLibrary;
  163269. Cesium['CorridorOutlineGeometry'] = Core_CorridorOutlineGeometry;
  163270. Cesium['createGuid'] = Core_createGuid;
  163271. Cesium['Credit'] = Core_Credit;
  163272. Cesium['CubicRealPolynomial'] = Core_CubicRealPolynomial;
  163273. Cesium['CylinderGeometry'] = Core_CylinderGeometry;
  163274. Cesium['CylinderGeometryLibrary'] = Core_CylinderGeometryLibrary;
  163275. Cesium['CylinderOutlineGeometry'] = Core_CylinderOutlineGeometry;
  163276. Cesium['DefaultProxy'] = Core_DefaultProxy;
  163277. Cesium['defaultValue'] = Core_defaultValue;
  163278. Cesium['defined'] = Core_defined;
  163279. Cesium['defineProperties'] = Core_defineProperties;
  163280. Cesium['deprecationWarning'] = Core_deprecationWarning;
  163281. Cesium['destroyObject'] = Core_destroyObject;
  163282. Cesium['DeveloperError'] = Core_DeveloperError;
  163283. Cesium['DistanceDisplayCondition'] = Core_DistanceDisplayCondition;
  163284. Cesium['DistanceDisplayConditionGeometryInstanceAttribute'] = Core_DistanceDisplayConditionGeometryInstanceAttribute;
  163285. Cesium['EarthOrientationParameters'] = Core_EarthOrientationParameters;
  163286. Cesium['EarthOrientationParametersSample'] = Core_EarthOrientationParametersSample;
  163287. Cesium['EasingFunction'] = Core_EasingFunction;
  163288. Cesium['EllipseGeometry'] = Core_EllipseGeometry;
  163289. Cesium['EllipseGeometryLibrary'] = Core_EllipseGeometryLibrary;
  163290. Cesium['EllipseOutlineGeometry'] = Core_EllipseOutlineGeometry;
  163291. Cesium['Ellipsoid'] = Core_Ellipsoid;
  163292. Cesium['EllipsoidalOccluder'] = Core_EllipsoidalOccluder;
  163293. Cesium['EllipsoidGeodesic'] = Core_EllipsoidGeodesic;
  163294. Cesium['EllipsoidGeometry'] = Core_EllipsoidGeometry;
  163295. Cesium['EllipsoidOutlineGeometry'] = Core_EllipsoidOutlineGeometry;
  163296. Cesium['EllipsoidTangentPlane'] = Core_EllipsoidTangentPlane;
  163297. Cesium['EllipsoidTerrainProvider'] = Core_EllipsoidTerrainProvider;
  163298. Cesium['EncodedCartesian3'] = Core_EncodedCartesian3;
  163299. Cesium['Event'] = Core_Event;
  163300. Cesium['EventHelper'] = Core_EventHelper;
  163301. Cesium['ExtrapolationType'] = Core_ExtrapolationType;
  163302. Cesium['FeatureDetection'] = Core_FeatureDetection;
  163303. Cesium['formatError'] = Core_formatError;
  163304. Cesium['freezeObject'] = Core_freezeObject;
  163305. Cesium['Fullscreen'] = Core_Fullscreen;
  163306. Cesium['GeographicProjection'] = Core_GeographicProjection;
  163307. Cesium['GeographicTilingScheme'] = Core_GeographicTilingScheme;
  163308. Cesium['Geometry'] = Core_Geometry;
  163309. Cesium['GeometryAttribute'] = Core_GeometryAttribute;
  163310. Cesium['GeometryAttributes'] = Core_GeometryAttributes;
  163311. Cesium['GeometryInstance'] = Core_GeometryInstance;
  163312. Cesium['GeometryInstanceAttribute'] = Core_GeometryInstanceAttribute;
  163313. Cesium['GeometryPipeline'] = Core_GeometryPipeline;
  163314. Cesium['GeometryType'] = Core_GeometryType;
  163315. Cesium['getAbsoluteUri'] = Core_getAbsoluteUri;
  163316. Cesium['getBaseUri'] = Core_getBaseUri;
  163317. Cesium['getExtensionFromUri'] = Core_getExtensionFromUri;
  163318. Cesium['getFilenameFromUri'] = Core_getFilenameFromUri;
  163319. Cesium['getImagePixels'] = Core_getImagePixels;
  163320. Cesium['getMagic'] = Core_getMagic;
  163321. Cesium['getStringFromTypedArray'] = Core_getStringFromTypedArray;
  163322. Cesium['getTimestamp'] = Core_getTimestamp;
  163323. Cesium['GregorianDate'] = Core_GregorianDate;
  163324. Cesium['HeadingPitchRange'] = Core_HeadingPitchRange;
  163325. Cesium['HeadingPitchRoll'] = Core_HeadingPitchRoll;
  163326. Cesium['HeightmapTerrainData'] = Core_HeightmapTerrainData;
  163327. Cesium['HeightmapTessellator'] = Core_HeightmapTessellator;
  163328. Cesium['HermitePolynomialApproximation'] = Core_HermitePolynomialApproximation;
  163329. Cesium['HermiteSpline'] = Core_HermiteSpline;
  163330. Cesium['Iau2000Orientation'] = Core_Iau2000Orientation;
  163331. Cesium['Iau2006XysData'] = Core_Iau2006XysData;
  163332. Cesium['Iau2006XysSample'] = Core_Iau2006XysSample;
  163333. Cesium['IauOrientationAxes'] = Core_IauOrientationAxes;
  163334. Cesium['IauOrientationParameters'] = Core_IauOrientationParameters;
  163335. Cesium['IndexDatatype'] = Core_IndexDatatype;
  163336. Cesium['InterpolationAlgorithm'] = Core_InterpolationAlgorithm;
  163337. Cesium['Intersect'] = Core_Intersect;
  163338. Cesium['Intersections2D'] = Core_Intersections2D;
  163339. Cesium['IntersectionTests'] = Core_IntersectionTests;
  163340. Cesium['Interval'] = Core_Interval;
  163341. Cesium['isArray'] = Core_isArray;
  163342. Cesium['isCrossOriginUrl'] = Core_isCrossOriginUrl;
  163343. Cesium['isLeapYear'] = Core_isLeapYear;
  163344. Cesium['Iso8601'] = Core_Iso8601;
  163345. Cesium['joinUrls'] = Core_joinUrls;
  163346. Cesium['JulianDate'] = Core_JulianDate;
  163347. Cesium['KeyboardEventModifier'] = Core_KeyboardEventModifier;
  163348. Cesium['LagrangePolynomialApproximation'] = Core_LagrangePolynomialApproximation;
  163349. Cesium['LeapSecond'] = Core_LeapSecond;
  163350. Cesium['LinearApproximation'] = Core_LinearApproximation;
  163351. Cesium['LinearSpline'] = Core_LinearSpline;
  163352. Cesium['loadArrayBuffer'] = Core_loadArrayBuffer;
  163353. Cesium['loadBlob'] = Core_loadBlob;
  163354. Cesium['loadImage'] = Core_loadImage;
  163355. Cesium['loadImageFromTypedArray'] = Core_loadImageFromTypedArray;
  163356. Cesium['loadImageViaBlob'] = Core_loadImageViaBlob;
  163357. Cesium['loadJson'] = Core_loadJson;
  163358. Cesium['loadJsonp'] = Core_loadJsonp;
  163359. Cesium['loadText'] = Core_loadText;
  163360. Cesium['loadWithXhr'] = Core_loadWithXhr;
  163361. Cesium['loadXML'] = Core_loadXML;
  163362. Cesium['MapboxApi'] = Core_MapboxApi;
  163363. Cesium['MapProjection'] = Core_MapProjection;
  163364. Cesium['Math'] = Core_Math;
  163365. Cesium['Matrix2'] = Core_Matrix2;
  163366. Cesium['Matrix3'] = Core_Matrix3;
  163367. Cesium['Matrix4'] = Core_Matrix4;
  163368. Cesium['mergeSort'] = Core_mergeSort;
  163369. Cesium['NearFarScalar'] = Core_NearFarScalar;
  163370. Cesium['objectToQuery'] = Core_objectToQuery;
  163371. Cesium['Occluder'] = Core_Occluder;
  163372. Cesium['oneTimeWarning'] = Core_oneTimeWarning;
  163373. Cesium['OrientedBoundingBox'] = Core_OrientedBoundingBox;
  163374. Cesium['Packable'] = Core_Packable;
  163375. Cesium['PackableForInterpolation'] = Core_PackableForInterpolation;
  163376. Cesium['parseResponseHeaders'] = Core_parseResponseHeaders;
  163377. Cesium['PinBuilder'] = Core_PinBuilder;
  163378. Cesium['PixelFormat'] = Core_PixelFormat;
  163379. Cesium['Plane'] = Core_Plane;
  163380. Cesium['PointGeometry'] = Core_PointGeometry;
  163381. Cesium['pointInsideTriangle'] = Core_pointInsideTriangle;
  163382. Cesium['PolygonGeometry'] = Core_PolygonGeometry;
  163383. Cesium['PolygonGeometryLibrary'] = Core_PolygonGeometryLibrary;
  163384. Cesium['PolygonHierarchy'] = Core_PolygonHierarchy;
  163385. Cesium['PolygonOutlineGeometry'] = Core_PolygonOutlineGeometry;
  163386. Cesium['PolygonPipeline'] = Core_PolygonPipeline;
  163387. Cesium['PolylineGeometry'] = Core_PolylineGeometry;
  163388. Cesium['PolylinePipeline'] = Core_PolylinePipeline;
  163389. Cesium['PolylineVolumeGeometry'] = Core_PolylineVolumeGeometry;
  163390. Cesium['PolylineVolumeGeometryLibrary'] = Core_PolylineVolumeGeometryLibrary;
  163391. Cesium['PolylineVolumeOutlineGeometry'] = Core_PolylineVolumeOutlineGeometry;
  163392. Cesium['PrimitiveType'] = Core_PrimitiveType;
  163393. Cesium['QuadraticRealPolynomial'] = Core_QuadraticRealPolynomial;
  163394. Cesium['QuantizedMeshTerrainData'] = Core_QuantizedMeshTerrainData;
  163395. Cesium['QuarticRealPolynomial'] = Core_QuarticRealPolynomial;
  163396. Cesium['Quaternion'] = Core_Quaternion;
  163397. Cesium['QuaternionSpline'] = Core_QuaternionSpline;
  163398. Cesium['queryToObject'] = Core_queryToObject;
  163399. Cesium['Queue'] = Core_Queue;
  163400. Cesium['Ray'] = Core_Ray;
  163401. Cesium['Rectangle'] = Core_Rectangle;
  163402. Cesium['RectangleGeometry'] = Core_RectangleGeometry;
  163403. Cesium['RectangleGeometryLibrary'] = Core_RectangleGeometryLibrary;
  163404. Cesium['RectangleOutlineGeometry'] = Core_RectangleOutlineGeometry;
  163405. Cesium['ReferenceFrame'] = Core_ReferenceFrame;
  163406. Cesium['requestAnimationFrame'] = Core_requestAnimationFrame;
  163407. Cesium['RequestErrorEvent'] = Core_RequestErrorEvent;
  163408. Cesium['RuntimeError'] = Core_RuntimeError;
  163409. Cesium['sampleTerrain'] = Core_sampleTerrain;
  163410. Cesium['scaleToGeodeticSurface'] = Core_scaleToGeodeticSurface;
  163411. Cesium['ScreenSpaceEventHandler'] = Core_ScreenSpaceEventHandler;
  163412. Cesium['ScreenSpaceEventType'] = Core_ScreenSpaceEventType;
  163413. Cesium['ShowGeometryInstanceAttribute'] = Core_ShowGeometryInstanceAttribute;
  163414. Cesium['Simon1994PlanetaryPositions'] = Core_Simon1994PlanetaryPositions;
  163415. Cesium['SimplePolylineGeometry'] = Core_SimplePolylineGeometry;
  163416. Cesium['SphereGeometry'] = Core_SphereGeometry;
  163417. Cesium['SphereOutlineGeometry'] = Core_SphereOutlineGeometry;
  163418. Cesium['Spherical'] = Core_Spherical;
  163419. Cesium['Spline'] = Core_Spline;
  163420. Cesium['subdivideArray'] = Core_subdivideArray;
  163421. Cesium['TaskProcessor'] = Core_TaskProcessor;
  163422. Cesium['TerrainData'] = Core_TerrainData;
  163423. Cesium['TerrainEncoding'] = Core_TerrainEncoding;
  163424. Cesium['TerrainMesh'] = Core_TerrainMesh;
  163425. Cesium['TerrainProvider'] = Core_TerrainProvider;
  163426. Cesium['TerrainQuantization'] = Core_TerrainQuantization;
  163427. Cesium['throttleRequestByServer'] = Core_throttleRequestByServer;
  163428. Cesium['TileProviderError'] = Core_TileProviderError;
  163429. Cesium['TilingScheme'] = Core_TilingScheme;
  163430. Cesium['TimeConstants'] = Core_TimeConstants;
  163431. Cesium['TimeInterval'] = Core_TimeInterval;
  163432. Cesium['TimeIntervalCollection'] = Core_TimeIntervalCollection;
  163433. Cesium['TimeStandard'] = Core_TimeStandard;
  163434. Cesium['Tipsify'] = Core_Tipsify;
  163435. Cesium['Transforms'] = Core_Transforms;
  163436. Cesium['TranslationRotationScale'] = Core_TranslationRotationScale;
  163437. Cesium['TridiagonalSystemSolver'] = Core_TridiagonalSystemSolver;
  163438. Cesium['TrustedServers'] = Core_TrustedServers;
  163439. Cesium['VertexFormat'] = Core_VertexFormat;
  163440. Cesium['VideoSynchronizer'] = Core_VideoSynchronizer;
  163441. Cesium['Visibility'] = Core_Visibility;
  163442. Cesium['VRTheWorldTerrainProvider'] = Core_VRTheWorldTerrainProvider;
  163443. Cesium['WallGeometry'] = Core_WallGeometry;
  163444. Cesium['WallGeometryLibrary'] = Core_WallGeometryLibrary;
  163445. Cesium['WallOutlineGeometry'] = Core_WallOutlineGeometry;
  163446. Cesium['WebGLConstants'] = Core_WebGLConstants;
  163447. Cesium['WebMercatorProjection'] = Core_WebMercatorProjection;
  163448. Cesium['WebMercatorTilingScheme'] = Core_WebMercatorTilingScheme;
  163449. Cesium['WindingOrder'] = Core_WindingOrder;
  163450. Cesium['wrapFunction'] = Core_wrapFunction;
  163451. Cesium['writeTextToCanvas'] = Core_writeTextToCanvas;
  163452. Cesium['BillboardGraphics'] = DataSources_BillboardGraphics;
  163453. Cesium['BillboardVisualizer'] = DataSources_BillboardVisualizer;
  163454. Cesium['BoundingSphereState'] = DataSources_BoundingSphereState;
  163455. Cesium['BoxGeometryUpdater'] = DataSources_BoxGeometryUpdater;
  163456. Cesium['BoxGraphics'] = DataSources_BoxGraphics;
  163457. Cesium['CallbackProperty'] = DataSources_CallbackProperty;
  163458. Cesium['CheckerboardMaterialProperty'] = DataSources_CheckerboardMaterialProperty;
  163459. Cesium['ColorMaterialProperty'] = DataSources_ColorMaterialProperty;
  163460. Cesium['CompositeEntityCollection'] = DataSources_CompositeEntityCollection;
  163461. Cesium['CompositeMaterialProperty'] = DataSources_CompositeMaterialProperty;
  163462. Cesium['CompositePositionProperty'] = DataSources_CompositePositionProperty;
  163463. Cesium['CompositeProperty'] = DataSources_CompositeProperty;
  163464. Cesium['ConstantPositionProperty'] = DataSources_ConstantPositionProperty;
  163465. Cesium['ConstantProperty'] = DataSources_ConstantProperty;
  163466. Cesium['CorridorGeometryUpdater'] = DataSources_CorridorGeometryUpdater;
  163467. Cesium['CorridorGraphics'] = DataSources_CorridorGraphics;
  163468. Cesium['createMaterialPropertyDescriptor'] = DataSources_createMaterialPropertyDescriptor;
  163469. Cesium['createPropertyDescriptor'] = DataSources_createPropertyDescriptor;
  163470. Cesium['createRawPropertyDescriptor'] = DataSources_createRawPropertyDescriptor;
  163471. Cesium['CustomDataSource'] = DataSources_CustomDataSource;
  163472. Cesium['CylinderGeometryUpdater'] = DataSources_CylinderGeometryUpdater;
  163473. Cesium['CylinderGraphics'] = DataSources_CylinderGraphics;
  163474. Cesium['CzmlDataSource'] = DataSources_CzmlDataSource;
  163475. Cesium['DataSource'] = DataSources_DataSource;
  163476. Cesium['DataSourceClock'] = DataSources_DataSourceClock;
  163477. Cesium['DataSourceCollection'] = DataSources_DataSourceCollection;
  163478. Cesium['DataSourceDisplay'] = DataSources_DataSourceDisplay;
  163479. Cesium['dynamicGeometryGetBoundingSphere'] = DataSources_dynamicGeometryGetBoundingSphere;
  163480. Cesium['DynamicGeometryUpdater'] = DataSources_DynamicGeometryUpdater;
  163481. Cesium['EllipseGeometryUpdater'] = DataSources_EllipseGeometryUpdater;
  163482. Cesium['EllipseGraphics'] = DataSources_EllipseGraphics;
  163483. Cesium['EllipsoidGeometryUpdater'] = DataSources_EllipsoidGeometryUpdater;
  163484. Cesium['EllipsoidGraphics'] = DataSources_EllipsoidGraphics;
  163485. Cesium['Entity'] = DataSources_Entity;
  163486. Cesium['EntityCluster'] = DataSources_EntityCluster;
  163487. Cesium['EntityCollection'] = DataSources_EntityCollection;
  163488. Cesium['EntityView'] = DataSources_EntityView;
  163489. Cesium['GeoJsonDataSource'] = DataSources_GeoJsonDataSource;
  163490. Cesium['GeometryUpdater'] = DataSources_GeometryUpdater;
  163491. Cesium['GeometryVisualizer'] = DataSources_GeometryVisualizer;
  163492. Cesium['GridMaterialProperty'] = DataSources_GridMaterialProperty;
  163493. Cesium['ImageMaterialProperty'] = DataSources_ImageMaterialProperty;
  163494. Cesium['KmlDataSource'] = DataSources_KmlDataSource;
  163495. Cesium['LabelGraphics'] = DataSources_LabelGraphics;
  163496. Cesium['LabelVisualizer'] = DataSources_LabelVisualizer;
  163497. Cesium['MaterialProperty'] = DataSources_MaterialProperty;
  163498. Cesium['ModelGraphics'] = DataSources_ModelGraphics;
  163499. Cesium['ModelVisualizer'] = DataSources_ModelVisualizer;
  163500. Cesium['NodeTransformationProperty'] = DataSources_NodeTransformationProperty;
  163501. Cesium['PathGraphics'] = DataSources_PathGraphics;
  163502. Cesium['PathVisualizer'] = DataSources_PathVisualizer;
  163503. Cesium['PointGraphics'] = DataSources_PointGraphics;
  163504. Cesium['PointVisualizer'] = DataSources_PointVisualizer;
  163505. Cesium['PolygonGeometryUpdater'] = DataSources_PolygonGeometryUpdater;
  163506. Cesium['PolygonGraphics'] = DataSources_PolygonGraphics;
  163507. Cesium['PolylineArrowMaterialProperty'] = DataSources_PolylineArrowMaterialProperty;
  163508. Cesium['PolylineGeometryUpdater'] = DataSources_PolylineGeometryUpdater;
  163509. Cesium['PolylineGlowMaterialProperty'] = DataSources_PolylineGlowMaterialProperty;
  163510. Cesium['PolylineGraphics'] = DataSources_PolylineGraphics;
  163511. Cesium['PolylineOutlineMaterialProperty'] = DataSources_PolylineOutlineMaterialProperty;
  163512. Cesium['PolylineVolumeGeometryUpdater'] = DataSources_PolylineVolumeGeometryUpdater;
  163513. Cesium['PolylineVolumeGraphics'] = DataSources_PolylineVolumeGraphics;
  163514. Cesium['PositionProperty'] = DataSources_PositionProperty;
  163515. Cesium['PositionPropertyArray'] = DataSources_PositionPropertyArray;
  163516. Cesium['Property'] = DataSources_Property;
  163517. Cesium['PropertyArray'] = DataSources_PropertyArray;
  163518. Cesium['PropertyBag'] = DataSources_PropertyBag;
  163519. Cesium['RectangleGeometryUpdater'] = DataSources_RectangleGeometryUpdater;
  163520. Cesium['RectangleGraphics'] = DataSources_RectangleGraphics;
  163521. Cesium['ReferenceProperty'] = DataSources_ReferenceProperty;
  163522. Cesium['Rotation'] = DataSources_Rotation;
  163523. Cesium['SampledPositionProperty'] = DataSources_SampledPositionProperty;
  163524. Cesium['SampledProperty'] = DataSources_SampledProperty;
  163525. Cesium['ScaledPositionProperty'] = DataSources_ScaledPositionProperty;
  163526. Cesium['StaticGeometryColorBatch'] = DataSources_StaticGeometryColorBatch;
  163527. Cesium['StaticGeometryPerMaterialBatch'] = DataSources_StaticGeometryPerMaterialBatch;
  163528. Cesium['StaticGroundGeometryColorBatch'] = DataSources_StaticGroundGeometryColorBatch;
  163529. Cesium['StaticOutlineGeometryBatch'] = DataSources_StaticOutlineGeometryBatch;
  163530. Cesium['StripeMaterialProperty'] = DataSources_StripeMaterialProperty;
  163531. Cesium['StripeOrientation'] = DataSources_StripeOrientation;
  163532. Cesium['TimeIntervalCollectionPositionProperty'] = DataSources_TimeIntervalCollectionPositionProperty;
  163533. Cesium['TimeIntervalCollectionProperty'] = DataSources_TimeIntervalCollectionProperty;
  163534. Cesium['VelocityOrientationProperty'] = DataSources_VelocityOrientationProperty;
  163535. Cesium['VelocityVectorProperty'] = DataSources_VelocityVectorProperty;
  163536. Cesium['Visualizer'] = DataSources_Visualizer;
  163537. Cesium['WallGeometryUpdater'] = DataSources_WallGeometryUpdater;
  163538. Cesium['WallGraphics'] = DataSources_WallGraphics;
  163539. Cesium['AutomaticUniforms'] = Renderer_AutomaticUniforms;
  163540. Cesium['Buffer'] = Renderer_Buffer;
  163541. Cesium['BufferUsage'] = Renderer_BufferUsage;
  163542. Cesium['ClearCommand'] = Renderer_ClearCommand;
  163543. Cesium['ComputeCommand'] = Renderer_ComputeCommand;
  163544. Cesium['ComputeEngine'] = Renderer_ComputeEngine;
  163545. Cesium['Context'] = Renderer_Context;
  163546. Cesium['ContextLimits'] = Renderer_ContextLimits;
  163547. Cesium['createUniform'] = Renderer_createUniform;
  163548. Cesium['createUniformArray'] = Renderer_createUniformArray;
  163549. Cesium['CubeMap'] = Renderer_CubeMap;
  163550. Cesium['CubeMapFace'] = Renderer_CubeMapFace;
  163551. Cesium['DrawCommand'] = Renderer_DrawCommand;
  163552. Cesium['Framebuffer'] = Renderer_Framebuffer;
  163553. Cesium['loadCubeMap'] = Renderer_loadCubeMap;
  163554. Cesium['MipmapHint'] = Renderer_MipmapHint;
  163555. Cesium['Pass'] = Renderer_Pass;
  163556. Cesium['PassState'] = Renderer_PassState;
  163557. Cesium['PickFramebuffer'] = Renderer_PickFramebuffer;
  163558. Cesium['PixelDatatype'] = Renderer_PixelDatatype;
  163559. Cesium['Renderbuffer'] = Renderer_Renderbuffer;
  163560. Cesium['RenderbufferFormat'] = Renderer_RenderbufferFormat;
  163561. Cesium['RenderState'] = Renderer_RenderState;
  163562. Cesium['Sampler'] = Renderer_Sampler;
  163563. Cesium['ShaderCache'] = Renderer_ShaderCache;
  163564. Cesium['ShaderProgram'] = Renderer_ShaderProgram;
  163565. Cesium['ShaderSource'] = Renderer_ShaderSource;
  163566. Cesium['Texture'] = Renderer_Texture;
  163567. Cesium['TextureMagnificationFilter'] = Renderer_TextureMagnificationFilter;
  163568. Cesium['TextureMinificationFilter'] = Renderer_TextureMinificationFilter;
  163569. Cesium['TextureWrap'] = Renderer_TextureWrap;
  163570. Cesium['UniformState'] = Renderer_UniformState;
  163571. Cesium['VertexArray'] = Renderer_VertexArray;
  163572. Cesium['VertexArrayFacade'] = Renderer_VertexArrayFacade;
  163573. Cesium['Appearance'] = Scene_Appearance;
  163574. Cesium['ArcGisMapServerImageryProvider'] = Scene_ArcGisMapServerImageryProvider;
  163575. Cesium['BatchTable'] = Scene_BatchTable;
  163576. Cesium['Billboard'] = Scene_Billboard;
  163577. Cesium['BillboardCollection'] = Scene_BillboardCollection;
  163578. Cesium['BingMapsImageryProvider'] = Scene_BingMapsImageryProvider;
  163579. Cesium['BingMapsStyle'] = Scene_BingMapsStyle;
  163580. Cesium['BlendEquation'] = Scene_BlendEquation;
  163581. Cesium['BlendFunction'] = Scene_BlendFunction;
  163582. Cesium['BlendingState'] = Scene_BlendingState;
  163583. Cesium['Camera'] = Scene_Camera;
  163584. Cesium['CameraEventAggregator'] = Scene_CameraEventAggregator;
  163585. Cesium['CameraEventType'] = Scene_CameraEventType;
  163586. Cesium['CameraFlightPath'] = Scene_CameraFlightPath;
  163587. Cesium['ColorBlendMode'] = Scene_ColorBlendMode;
  163588. Cesium['createOpenStreetMapImageryProvider'] = Scene_createOpenStreetMapImageryProvider;
  163589. Cesium['createTangentSpaceDebugPrimitive'] = Scene_createTangentSpaceDebugPrimitive;
  163590. Cesium['createTileMapServiceImageryProvider'] = Scene_createTileMapServiceImageryProvider;
  163591. Cesium['CreditDisplay'] = Scene_CreditDisplay;
  163592. Cesium['CullFace'] = Scene_CullFace;
  163593. Cesium['CullingVolume'] = Scene_CullingVolume;
  163594. Cesium['DebugAppearance'] = Scene_DebugAppearance;
  163595. Cesium['DebugCameraPrimitive'] = Scene_DebugCameraPrimitive;
  163596. Cesium['DebugModelMatrixPrimitive'] = Scene_DebugModelMatrixPrimitive;
  163597. Cesium['DepthFunction'] = Scene_DepthFunction;
  163598. Cesium['DepthPlane'] = Scene_DepthPlane;
  163599. Cesium['DeviceOrientationCameraController'] = Scene_DeviceOrientationCameraController;
  163600. Cesium['DiscardMissingTileImagePolicy'] = Scene_DiscardMissingTileImagePolicy;
  163601. Cesium['EllipsoidPrimitive'] = Scene_EllipsoidPrimitive;
  163602. Cesium['EllipsoidSurfaceAppearance'] = Scene_EllipsoidSurfaceAppearance;
  163603. Cesium['Fog'] = Scene_Fog;
  163604. Cesium['FrameRateMonitor'] = Scene_FrameRateMonitor;
  163605. Cesium['FrameState'] = Scene_FrameState;
  163606. Cesium['FrustumCommands'] = Scene_FrustumCommands;
  163607. Cesium['FXAA'] = Scene_FXAA;
  163608. Cesium['getAttributeOrUniformBySemantic'] = Scene_getAttributeOrUniformBySemantic;
  163609. Cesium['getBinaryAccessor'] = Scene_getBinaryAccessor;
  163610. Cesium['GetFeatureInfoFormat'] = Scene_GetFeatureInfoFormat;
  163611. Cesium['Globe'] = Scene_Globe;
  163612. Cesium['GlobeDepth'] = Scene_GlobeDepth;
  163613. Cesium['GlobeSurfaceShaderSet'] = Scene_GlobeSurfaceShaderSet;
  163614. Cesium['GlobeSurfaceTile'] = Scene_GlobeSurfaceTile;
  163615. Cesium['GlobeSurfaceTileProvider'] = Scene_GlobeSurfaceTileProvider;
  163616. Cesium['GoogleEarthImageryProvider'] = Scene_GoogleEarthImageryProvider;
  163617. Cesium['GridImageryProvider'] = Scene_GridImageryProvider;
  163618. Cesium['GroundPrimitive'] = Scene_GroundPrimitive;
  163619. Cesium['HeightReference'] = Scene_HeightReference;
  163620. Cesium['HorizontalOrigin'] = Scene_HorizontalOrigin;
  163621. Cesium['Imagery'] = Scene_Imagery;
  163622. Cesium['ImageryLayer'] = Scene_ImageryLayer;
  163623. Cesium['ImageryLayerCollection'] = Scene_ImageryLayerCollection;
  163624. Cesium['ImageryLayerFeatureInfo'] = Scene_ImageryLayerFeatureInfo;
  163625. Cesium['ImageryProvider'] = Scene_ImageryProvider;
  163626. Cesium['ImageryState'] = Scene_ImageryState;
  163627. Cesium['Label'] = Scene_Label;
  163628. Cesium['LabelCollection'] = Scene_LabelCollection;
  163629. Cesium['LabelStyle'] = Scene_LabelStyle;
  163630. Cesium['MapboxImageryProvider'] = Scene_MapboxImageryProvider;
  163631. Cesium['MapMode2D'] = Scene_MapMode2D;
  163632. Cesium['Material'] = Scene_Material;
  163633. Cesium['MaterialAppearance'] = Scene_MaterialAppearance;
  163634. Cesium['Model'] = Scene_Model;
  163635. Cesium['ModelAnimation'] = Scene_ModelAnimation;
  163636. Cesium['ModelAnimationCache'] = Scene_ModelAnimationCache;
  163637. Cesium['ModelAnimationCollection'] = Scene_ModelAnimationCollection;
  163638. Cesium['ModelAnimationLoop'] = Scene_ModelAnimationLoop;
  163639. Cesium['ModelAnimationState'] = Scene_ModelAnimationState;
  163640. Cesium['ModelMaterial'] = Scene_ModelMaterial;
  163641. Cesium['modelMaterialsCommon'] = Scene_modelMaterialsCommon;
  163642. Cesium['ModelMesh'] = Scene_ModelMesh;
  163643. Cesium['ModelNode'] = Scene_ModelNode;
  163644. Cesium['Moon'] = Scene_Moon;
  163645. Cesium['NeverTileDiscardPolicy'] = Scene_NeverTileDiscardPolicy;
  163646. Cesium['OIT'] = Scene_OIT;
  163647. Cesium['OrthographicFrustum'] = Scene_OrthographicFrustum;
  163648. Cesium['PerformanceDisplay'] = Scene_PerformanceDisplay;
  163649. Cesium['PerInstanceColorAppearance'] = Scene_PerInstanceColorAppearance;
  163650. Cesium['PerspectiveFrustum'] = Scene_PerspectiveFrustum;
  163651. Cesium['PerspectiveOffCenterFrustum'] = Scene_PerspectiveOffCenterFrustum;
  163652. Cesium['PickDepth'] = Scene_PickDepth;
  163653. Cesium['PointAppearance'] = Scene_PointAppearance;
  163654. Cesium['PointPrimitive'] = Scene_PointPrimitive;
  163655. Cesium['PointPrimitiveCollection'] = Scene_PointPrimitiveCollection;
  163656. Cesium['Polyline'] = Scene_Polyline;
  163657. Cesium['PolylineCollection'] = Scene_PolylineCollection;
  163658. Cesium['PolylineColorAppearance'] = Scene_PolylineColorAppearance;
  163659. Cesium['PolylineMaterialAppearance'] = Scene_PolylineMaterialAppearance;
  163660. Cesium['Primitive'] = Scene_Primitive;
  163661. Cesium['PrimitiveCollection'] = Scene_PrimitiveCollection;
  163662. Cesium['PrimitivePipeline'] = Scene_PrimitivePipeline;
  163663. Cesium['PrimitiveState'] = Scene_PrimitiveState;
  163664. Cesium['QuadtreeOccluders'] = Scene_QuadtreeOccluders;
  163665. Cesium['QuadtreePrimitive'] = Scene_QuadtreePrimitive;
  163666. Cesium['QuadtreeTile'] = Scene_QuadtreeTile;
  163667. Cesium['QuadtreeTileLoadState'] = Scene_QuadtreeTileLoadState;
  163668. Cesium['QuadtreeTileProvider'] = Scene_QuadtreeTileProvider;
  163669. Cesium['Scene'] = Scene_Scene;
  163670. Cesium['SceneMode'] = Scene_SceneMode;
  163671. Cesium['SceneTransforms'] = Scene_SceneTransforms;
  163672. Cesium['SceneTransitioner'] = Scene_SceneTransitioner;
  163673. Cesium['ScreenSpaceCameraController'] = Scene_ScreenSpaceCameraController;
  163674. Cesium['ShadowMap'] = Scene_ShadowMap;
  163675. Cesium['ShadowMapShader'] = Scene_ShadowMapShader;
  163676. Cesium['ShadowMode'] = Scene_ShadowMode;
  163677. Cesium['SingleTileImageryProvider'] = Scene_SingleTileImageryProvider;
  163678. Cesium['SkyAtmosphere'] = Scene_SkyAtmosphere;
  163679. Cesium['SkyBox'] = Scene_SkyBox;
  163680. Cesium['StencilFunction'] = Scene_StencilFunction;
  163681. Cesium['StencilOperation'] = Scene_StencilOperation;
  163682. Cesium['Sun'] = Scene_Sun;
  163683. Cesium['SunPostProcess'] = Scene_SunPostProcess;
  163684. Cesium['TerrainState'] = Scene_TerrainState;
  163685. Cesium['TextureAtlas'] = Scene_TextureAtlas;
  163686. Cesium['TileBoundingBox'] = Scene_TileBoundingBox;
  163687. Cesium['TileCoordinatesImageryProvider'] = Scene_TileCoordinatesImageryProvider;
  163688. Cesium['TileDiscardPolicy'] = Scene_TileDiscardPolicy;
  163689. Cesium['TileImagery'] = Scene_TileImagery;
  163690. Cesium['TileReplacementQueue'] = Scene_TileReplacementQueue;
  163691. Cesium['TileState'] = Scene_TileState;
  163692. Cesium['TileTerrain'] = Scene_TileTerrain;
  163693. Cesium['TweenCollection'] = Scene_TweenCollection;
  163694. Cesium['UrlTemplateImageryProvider'] = Scene_UrlTemplateImageryProvider;
  163695. Cesium['VerticalOrigin'] = Scene_VerticalOrigin;
  163696. Cesium['ViewportQuad'] = Scene_ViewportQuad;
  163697. Cesium['WebMapServiceImageryProvider'] = Scene_WebMapServiceImageryProvider;
  163698. Cesium['WebMapTileServiceImageryProvider'] = Scene_WebMapTileServiceImageryProvider;
  163699. Cesium._shaders['AdjustTranslucentFS'] = Shaders_AdjustTranslucentFS;
  163700. Cesium._shaders['AllMaterialAppearanceFS'] = Shaders_Appearances_AllMaterialAppearanceFS;
  163701. Cesium._shaders['AllMaterialAppearanceVS'] = Shaders_Appearances_AllMaterialAppearanceVS;
  163702. Cesium._shaders['BasicMaterialAppearanceFS'] = Shaders_Appearances_BasicMaterialAppearanceFS;
  163703. Cesium._shaders['BasicMaterialAppearanceVS'] = Shaders_Appearances_BasicMaterialAppearanceVS;
  163704. Cesium._shaders['EllipsoidSurfaceAppearanceFS'] = Shaders_Appearances_EllipsoidSurfaceAppearanceFS;
  163705. Cesium._shaders['EllipsoidSurfaceAppearanceVS'] = Shaders_Appearances_EllipsoidSurfaceAppearanceVS;
  163706. Cesium._shaders['PerInstanceColorAppearanceFS'] = Shaders_Appearances_PerInstanceColorAppearanceFS;
  163707. Cesium._shaders['PerInstanceColorAppearanceVS'] = Shaders_Appearances_PerInstanceColorAppearanceVS;
  163708. Cesium._shaders['PerInstanceFlatColorAppearanceFS'] = Shaders_Appearances_PerInstanceFlatColorAppearanceFS;
  163709. Cesium._shaders['PerInstanceFlatColorAppearanceVS'] = Shaders_Appearances_PerInstanceFlatColorAppearanceVS;
  163710. Cesium._shaders['PointAppearanceFS'] = Shaders_Appearances_PointAppearanceFS;
  163711. Cesium._shaders['PointAppearanceVS'] = Shaders_Appearances_PointAppearanceVS;
  163712. Cesium._shaders['PolylineColorAppearanceVS'] = Shaders_Appearances_PolylineColorAppearanceVS;
  163713. Cesium._shaders['PolylineMaterialAppearanceVS'] = Shaders_Appearances_PolylineMaterialAppearanceVS;
  163714. Cesium._shaders['TexturedMaterialAppearanceFS'] = Shaders_Appearances_TexturedMaterialAppearanceFS;
  163715. Cesium._shaders['TexturedMaterialAppearanceVS'] = Shaders_Appearances_TexturedMaterialAppearanceVS;
  163716. Cesium._shaders['BillboardCollectionFS'] = Shaders_BillboardCollectionFS;
  163717. Cesium._shaders['BillboardCollectionVS'] = Shaders_BillboardCollectionVS;
  163718. Cesium._shaders['degreesPerRadian'] = Shaders_Builtin_Constants_degreesPerRadian;
  163719. Cesium._shaders['depthRange'] = Shaders_Builtin_Constants_depthRange;
  163720. Cesium._shaders['epsilon1'] = Shaders_Builtin_Constants_epsilon1;
  163721. Cesium._shaders['epsilon2'] = Shaders_Builtin_Constants_epsilon2;
  163722. Cesium._shaders['epsilon3'] = Shaders_Builtin_Constants_epsilon3;
  163723. Cesium._shaders['epsilon4'] = Shaders_Builtin_Constants_epsilon4;
  163724. Cesium._shaders['epsilon5'] = Shaders_Builtin_Constants_epsilon5;
  163725. Cesium._shaders['epsilon6'] = Shaders_Builtin_Constants_epsilon6;
  163726. Cesium._shaders['epsilon7'] = Shaders_Builtin_Constants_epsilon7;
  163727. Cesium._shaders['infinity'] = Shaders_Builtin_Constants_infinity;
  163728. Cesium._shaders['oneOverPi'] = Shaders_Builtin_Constants_oneOverPi;
  163729. Cesium._shaders['oneOverTwoPi'] = Shaders_Builtin_Constants_oneOverTwoPi;
  163730. Cesium._shaders['passCompute'] = Shaders_Builtin_Constants_passCompute;
  163731. Cesium._shaders['passEnvironment'] = Shaders_Builtin_Constants_passEnvironment;
  163732. Cesium._shaders['passGlobe'] = Shaders_Builtin_Constants_passGlobe;
  163733. Cesium._shaders['passGround'] = Shaders_Builtin_Constants_passGround;
  163734. Cesium._shaders['passOpaque'] = Shaders_Builtin_Constants_passOpaque;
  163735. Cesium._shaders['passOverlay'] = Shaders_Builtin_Constants_passOverlay;
  163736. Cesium._shaders['passTranslucent'] = Shaders_Builtin_Constants_passTranslucent;
  163737. Cesium._shaders['pi'] = Shaders_Builtin_Constants_pi;
  163738. Cesium._shaders['piOverFour'] = Shaders_Builtin_Constants_piOverFour;
  163739. Cesium._shaders['piOverSix'] = Shaders_Builtin_Constants_piOverSix;
  163740. Cesium._shaders['piOverThree'] = Shaders_Builtin_Constants_piOverThree;
  163741. Cesium._shaders['piOverTwo'] = Shaders_Builtin_Constants_piOverTwo;
  163742. Cesium._shaders['radiansPerDegree'] = Shaders_Builtin_Constants_radiansPerDegree;
  163743. Cesium._shaders['sceneMode2D'] = Shaders_Builtin_Constants_sceneMode2D;
  163744. Cesium._shaders['sceneMode3D'] = Shaders_Builtin_Constants_sceneMode3D;
  163745. Cesium._shaders['sceneModeColumbusView'] = Shaders_Builtin_Constants_sceneModeColumbusView;
  163746. Cesium._shaders['sceneModeMorphing'] = Shaders_Builtin_Constants_sceneModeMorphing;
  163747. Cesium._shaders['solarRadius'] = Shaders_Builtin_Constants_solarRadius;
  163748. Cesium._shaders['threePiOver2'] = Shaders_Builtin_Constants_threePiOver2;
  163749. Cesium._shaders['twoPi'] = Shaders_Builtin_Constants_twoPi;
  163750. Cesium._shaders['webMercatorMaxLatitude'] = Shaders_Builtin_Constants_webMercatorMaxLatitude;
  163751. Cesium._shaders['CzmBuiltins'] = Shaders_Builtin_CzmBuiltins;
  163752. Cesium._shaders['alphaWeight'] = Shaders_Builtin_Functions_alphaWeight;
  163753. Cesium._shaders['antialias'] = Shaders_Builtin_Functions_antialias;
  163754. Cesium._shaders['cascadeColor'] = Shaders_Builtin_Functions_cascadeColor;
  163755. Cesium._shaders['cascadeDistance'] = Shaders_Builtin_Functions_cascadeDistance;
  163756. Cesium._shaders['cascadeMatrix'] = Shaders_Builtin_Functions_cascadeMatrix;
  163757. Cesium._shaders['cascadeWeights'] = Shaders_Builtin_Functions_cascadeWeights;
  163758. Cesium._shaders['columbusViewMorph'] = Shaders_Builtin_Functions_columbusViewMorph;
  163759. Cesium._shaders['computePosition'] = Shaders_Builtin_Functions_computePosition;
  163760. Cesium._shaders['cosineAndSine'] = Shaders_Builtin_Functions_cosineAndSine;
  163761. Cesium._shaders['decompressTextureCoordinates'] = Shaders_Builtin_Functions_decompressTextureCoordinates;
  163762. Cesium._shaders['eastNorthUpToEyeCoordinates'] = Shaders_Builtin_Functions_eastNorthUpToEyeCoordinates;
  163763. Cesium._shaders['ellipsoidContainsPoint'] = Shaders_Builtin_Functions_ellipsoidContainsPoint;
  163764. Cesium._shaders['ellipsoidNew'] = Shaders_Builtin_Functions_ellipsoidNew;
  163765. Cesium._shaders['ellipsoidWgs84TextureCoordinates'] = Shaders_Builtin_Functions_ellipsoidWgs84TextureCoordinates;
  163766. Cesium._shaders['equalsEpsilon'] = Shaders_Builtin_Functions_equalsEpsilon;
  163767. Cesium._shaders['eyeOffset'] = Shaders_Builtin_Functions_eyeOffset;
  163768. Cesium._shaders['eyeToWindowCoordinates'] = Shaders_Builtin_Functions_eyeToWindowCoordinates;
  163769. Cesium._shaders['fog'] = Shaders_Builtin_Functions_fog;
  163770. Cesium._shaders['geodeticSurfaceNormal'] = Shaders_Builtin_Functions_geodeticSurfaceNormal;
  163771. Cesium._shaders['getDefaultMaterial'] = Shaders_Builtin_Functions_getDefaultMaterial;
  163772. Cesium._shaders['getLambertDiffuse'] = Shaders_Builtin_Functions_getLambertDiffuse;
  163773. Cesium._shaders['getSpecular'] = Shaders_Builtin_Functions_getSpecular;
  163774. Cesium._shaders['getWaterNoise'] = Shaders_Builtin_Functions_getWaterNoise;
  163775. Cesium._shaders['getWgs84EllipsoidEC'] = Shaders_Builtin_Functions_getWgs84EllipsoidEC;
  163776. Cesium._shaders['hue'] = Shaders_Builtin_Functions_hue;
  163777. Cesium._shaders['isEmpty'] = Shaders_Builtin_Functions_isEmpty;
  163778. Cesium._shaders['isFull'] = Shaders_Builtin_Functions_isFull;
  163779. Cesium._shaders['latitudeToWebMercatorFraction'] = Shaders_Builtin_Functions_latitudeToWebMercatorFraction;
  163780. Cesium._shaders['luminance'] = Shaders_Builtin_Functions_luminance;
  163781. Cesium._shaders['metersPerPixel'] = Shaders_Builtin_Functions_metersPerPixel;
  163782. Cesium._shaders['modelToWindowCoordinates'] = Shaders_Builtin_Functions_modelToWindowCoordinates;
  163783. Cesium._shaders['multiplyWithColorBalance'] = Shaders_Builtin_Functions_multiplyWithColorBalance;
  163784. Cesium._shaders['nearFarScalar'] = Shaders_Builtin_Functions_nearFarScalar;
  163785. Cesium._shaders['octDecode'] = Shaders_Builtin_Functions_octDecode;
  163786. Cesium._shaders['packDepth'] = Shaders_Builtin_Functions_packDepth;
  163787. Cesium._shaders['phong'] = Shaders_Builtin_Functions_phong;
  163788. Cesium._shaders['pointAlongRay'] = Shaders_Builtin_Functions_pointAlongRay;
  163789. Cesium._shaders['rayEllipsoidIntersectionInterval'] = Shaders_Builtin_Functions_rayEllipsoidIntersectionInterval;
  163790. Cesium._shaders['RGBToXYZ'] = Shaders_Builtin_Functions_RGBToXYZ;
  163791. Cesium._shaders['saturation'] = Shaders_Builtin_Functions_saturation;
  163792. Cesium._shaders['shadowDepthCompare'] = Shaders_Builtin_Functions_shadowDepthCompare;
  163793. Cesium._shaders['shadowVisibility'] = Shaders_Builtin_Functions_shadowVisibility;
  163794. Cesium._shaders['signNotZero'] = Shaders_Builtin_Functions_signNotZero;
  163795. Cesium._shaders['tangentToEyeSpaceMatrix'] = Shaders_Builtin_Functions_tangentToEyeSpaceMatrix;
  163796. Cesium._shaders['translateRelativeToEye'] = Shaders_Builtin_Functions_translateRelativeToEye;
  163797. Cesium._shaders['translucentPhong'] = Shaders_Builtin_Functions_translucentPhong;
  163798. Cesium._shaders['transpose'] = Shaders_Builtin_Functions_transpose;
  163799. Cesium._shaders['unpackDepth'] = Shaders_Builtin_Functions_unpackDepth;
  163800. Cesium._shaders['windowToEyeCoordinates'] = Shaders_Builtin_Functions_windowToEyeCoordinates;
  163801. Cesium._shaders['XYZToRGB'] = Shaders_Builtin_Functions_XYZToRGB;
  163802. Cesium._shaders['depthRangeStruct'] = Shaders_Builtin_Structs_depthRangeStruct;
  163803. Cesium._shaders['ellipsoid'] = Shaders_Builtin_Structs_ellipsoid;
  163804. Cesium._shaders['material'] = Shaders_Builtin_Structs_material;
  163805. Cesium._shaders['materialInput'] = Shaders_Builtin_Structs_materialInput;
  163806. Cesium._shaders['ray'] = Shaders_Builtin_Structs_ray;
  163807. Cesium._shaders['raySegment'] = Shaders_Builtin_Structs_raySegment;
  163808. Cesium._shaders['shadowParameters'] = Shaders_Builtin_Structs_shadowParameters;
  163809. Cesium._shaders['CompositeOITFS'] = Shaders_CompositeOITFS;
  163810. Cesium._shaders['DepthPlaneFS'] = Shaders_DepthPlaneFS;
  163811. Cesium._shaders['DepthPlaneVS'] = Shaders_DepthPlaneVS;
  163812. Cesium._shaders['EllipsoidFS'] = Shaders_EllipsoidFS;
  163813. Cesium._shaders['EllipsoidVS'] = Shaders_EllipsoidVS;
  163814. Cesium._shaders['GlobeFS'] = Shaders_GlobeFS;
  163815. Cesium._shaders['GlobeVS'] = Shaders_GlobeVS;
  163816. Cesium._shaders['GroundAtmosphere'] = Shaders_GroundAtmosphere;
  163817. Cesium._shaders['BumpMapMaterial'] = Shaders_Materials_BumpMapMaterial;
  163818. Cesium._shaders['CheckerboardMaterial'] = Shaders_Materials_CheckerboardMaterial;
  163819. Cesium._shaders['DotMaterial'] = Shaders_Materials_DotMaterial;
  163820. Cesium._shaders['FadeMaterial'] = Shaders_Materials_FadeMaterial;
  163821. Cesium._shaders['GridMaterial'] = Shaders_Materials_GridMaterial;
  163822. Cesium._shaders['NormalMapMaterial'] = Shaders_Materials_NormalMapMaterial;
  163823. Cesium._shaders['PolylineArrowMaterial'] = Shaders_Materials_PolylineArrowMaterial;
  163824. Cesium._shaders['PolylineGlowMaterial'] = Shaders_Materials_PolylineGlowMaterial;
  163825. Cesium._shaders['PolylineOutlineMaterial'] = Shaders_Materials_PolylineOutlineMaterial;
  163826. Cesium._shaders['RimLightingMaterial'] = Shaders_Materials_RimLightingMaterial;
  163827. Cesium._shaders['StripeMaterial'] = Shaders_Materials_StripeMaterial;
  163828. Cesium._shaders['Water'] = Shaders_Materials_Water;
  163829. Cesium._shaders['PointPrimitiveCollectionFS'] = Shaders_PointPrimitiveCollectionFS;
  163830. Cesium._shaders['PointPrimitiveCollectionVS'] = Shaders_PointPrimitiveCollectionVS;
  163831. Cesium._shaders['PolylineCommon'] = Shaders_PolylineCommon;
  163832. Cesium._shaders['PolylineFS'] = Shaders_PolylineFS;
  163833. Cesium._shaders['PolylineVS'] = Shaders_PolylineVS;
  163834. Cesium._shaders['AdditiveBlend'] = Shaders_PostProcessFilters_AdditiveBlend;
  163835. Cesium._shaders['BrightPass'] = Shaders_PostProcessFilters_BrightPass;
  163836. Cesium._shaders['FXAA'] = Shaders_PostProcessFilters_FXAA;
  163837. Cesium._shaders['GaussianBlur1D'] = Shaders_PostProcessFilters_GaussianBlur1D;
  163838. Cesium._shaders['PassThrough'] = Shaders_PostProcessFilters_PassThrough;
  163839. Cesium._shaders['ReprojectWebMercatorFS'] = Shaders_ReprojectWebMercatorFS;
  163840. Cesium._shaders['ReprojectWebMercatorVS'] = Shaders_ReprojectWebMercatorVS;
  163841. Cesium._shaders['ShadowVolumeFS'] = Shaders_ShadowVolumeFS;
  163842. Cesium._shaders['ShadowVolumeVS'] = Shaders_ShadowVolumeVS;
  163843. Cesium._shaders['SkyAtmosphereFS'] = Shaders_SkyAtmosphereFS;
  163844. Cesium._shaders['SkyAtmosphereVS'] = Shaders_SkyAtmosphereVS;
  163845. Cesium._shaders['SkyBoxFS'] = Shaders_SkyBoxFS;
  163846. Cesium._shaders['SkyBoxVS'] = Shaders_SkyBoxVS;
  163847. Cesium._shaders['SunFS'] = Shaders_SunFS;
  163848. Cesium._shaders['SunTextureFS'] = Shaders_SunTextureFS;
  163849. Cesium._shaders['SunVS'] = Shaders_SunVS;
  163850. Cesium._shaders['ViewportQuadFS'] = Shaders_ViewportQuadFS;
  163851. Cesium._shaders['ViewportQuadVS'] = Shaders_ViewportQuadVS;
  163852. Cesium['Autolinker'] = ThirdParty_Autolinker;
  163853. Cesium['earcut-2.1.1'] = ThirdParty_earcut_2_1_1;
  163854. Cesium['gltfDefaults'] = ThirdParty_gltfDefaults;
  163855. Cesium['kdbush'] = ThirdParty_kdbush;
  163856. Cesium['knockout-3.4.0'] = ThirdParty_knockout_3_4_0;
  163857. Cesium['knockout-es5'] = ThirdParty_knockout_es5;
  163858. Cesium['knockout'] = ThirdParty_knockout;
  163859. Cesium['measureText'] = ThirdParty_measureText;
  163860. Cesium['mersenne-twister'] = ThirdParty_mersenne_twister;
  163861. Cesium['NoSleep'] = ThirdParty_NoSleep;
  163862. Cesium['sprintf'] = ThirdParty_sprintf;
  163863. Cesium['topojson'] = ThirdParty_topojson;
  163864. Cesium['Tween'] = ThirdParty_Tween;
  163865. Cesium['Uri'] = ThirdParty_Uri;
  163866. Cesium['when'] = ThirdParty_when;
  163867. Cesium['zip'] = ThirdParty_zip;
  163868. Cesium['Animation'] = Widgets_Animation_Animation;
  163869. Cesium['AnimationViewModel'] = Widgets_Animation_AnimationViewModel;
  163870. Cesium['BaseLayerPicker'] = Widgets_BaseLayerPicker_BaseLayerPicker;
  163871. Cesium['BaseLayerPickerViewModel'] = Widgets_BaseLayerPicker_BaseLayerPickerViewModel;
  163872. Cesium['createDefaultImageryProviderViewModels'] = Widgets_BaseLayerPicker_createDefaultImageryProviderViewModels;
  163873. Cesium['createDefaultTerrainProviderViewModels'] = Widgets_BaseLayerPicker_createDefaultTerrainProviderViewModels;
  163874. Cesium['ProviderViewModel'] = Widgets_BaseLayerPicker_ProviderViewModel;
  163875. Cesium['CesiumInspector'] = Widgets_CesiumInspector_CesiumInspector;
  163876. Cesium['CesiumInspectorViewModel'] = Widgets_CesiumInspector_CesiumInspectorViewModel;
  163877. Cesium['CesiumWidget'] = Widgets_CesiumWidget_CesiumWidget;
  163878. Cesium['ClockViewModel'] = Widgets_ClockViewModel;
  163879. Cesium['Command'] = Widgets_Command;
  163880. Cesium['createCommand'] = Widgets_createCommand;
  163881. Cesium['FullscreenButton'] = Widgets_FullscreenButton_FullscreenButton;
  163882. Cesium['FullscreenButtonViewModel'] = Widgets_FullscreenButton_FullscreenButtonViewModel;
  163883. Cesium['Geocoder'] = Widgets_Geocoder_Geocoder;
  163884. Cesium['GeocoderViewModel'] = Widgets_Geocoder_GeocoderViewModel;
  163885. Cesium['getElement'] = Widgets_getElement;
  163886. Cesium['HomeButton'] = Widgets_HomeButton_HomeButton;
  163887. Cesium['HomeButtonViewModel'] = Widgets_HomeButton_HomeButtonViewModel;
  163888. Cesium['InfoBox'] = Widgets_InfoBox_InfoBox;
  163889. Cesium['InfoBoxViewModel'] = Widgets_InfoBox_InfoBoxViewModel;
  163890. Cesium['NavigationHelpButton'] = Widgets_NavigationHelpButton_NavigationHelpButton;
  163891. Cesium['NavigationHelpButtonViewModel'] = Widgets_NavigationHelpButton_NavigationHelpButtonViewModel;
  163892. Cesium['PerformanceWatchdog'] = Widgets_PerformanceWatchdog_PerformanceWatchdog;
  163893. Cesium['PerformanceWatchdogViewModel'] = Widgets_PerformanceWatchdog_PerformanceWatchdogViewModel;
  163894. Cesium['SceneModePicker'] = Widgets_SceneModePicker_SceneModePicker;
  163895. Cesium['SceneModePickerViewModel'] = Widgets_SceneModePicker_SceneModePickerViewModel;
  163896. Cesium['SelectionIndicator'] = Widgets_SelectionIndicator_SelectionIndicator;
  163897. Cesium['SelectionIndicatorViewModel'] = Widgets_SelectionIndicator_SelectionIndicatorViewModel;
  163898. Cesium['subscribeAndEvaluate'] = Widgets_subscribeAndEvaluate;
  163899. Cesium['SvgPathBindingHandler'] = Widgets_SvgPathBindingHandler;
  163900. Cesium['Timeline'] = Widgets_Timeline_Timeline;
  163901. Cesium['TimelineHighlightRange'] = Widgets_Timeline_TimelineHighlightRange;
  163902. Cesium['TimelineTrack'] = Widgets_Timeline_TimelineTrack;
  163903. Cesium['ToggleButtonViewModel'] = Widgets_ToggleButtonViewModel;
  163904. Cesium['Viewer'] = Widgets_Viewer_Viewer;
  163905. Cesium['viewerCesiumInspectorMixin'] = Widgets_Viewer_viewerCesiumInspectorMixin;
  163906. Cesium['viewerDragDropMixin'] = Widgets_Viewer_viewerDragDropMixin;
  163907. Cesium['viewerPerformanceWatchdogMixin'] = Widgets_Viewer_viewerPerformanceWatchdogMixin;
  163908. Cesium['VRButton'] = Widgets_VRButton_VRButton;
  163909. Cesium['VRButtonViewModel'] = Widgets_VRButton_VRButtonViewModel;
  163910. Cesium['createTaskProcessorWorker'] = Workers_createTaskProcessorWorker;
  163911. return Cesium;
  163912. });
  163913. /*global require*/
  163914. // require in the complete Cesium object and reassign it globally.
  163915. // This is meant for use with the Almond loader.
  163916. require([
  163917. 'Cesium'
  163918. ], function(
  163919. Cesium) {
  163920. 'use strict';
  163921. /*global self*/
  163922. var scope = typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : {};
  163923. scope.Cesium = Cesium;
  163924. }, undefined, true);
  163925. }());