viewer.js 109 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550
  1. import * as THREE from "../../libs/three.js/build/three.module.js";
  2. import {ClipTask, ClipMethod, CameraMode, LengthUnits, ElevationGradientRepeat} from "../defines.js";
  3. import {Renderer} from "../PotreeRenderer.js";
  4. import {PotreeRenderer} from "./PotreeRenderer.js";
  5. import {EDLRenderer} from "./EDLRenderer.js";
  6. import {HQSplatRenderer} from "./HQSplatRenderer.js";
  7. import {Scene} from "./Scene.js";
  8. import {ClippingTool} from "../objects/tool/ClippingTool.js";
  9. import {TransformationTool} from "../objects/tool/TransformationTool.js";
  10. import {Utils} from "../utils.js";
  11. import {MapView} from "./map.js";
  12. import {MapViewer} from "./map/MapViewer.js";
  13. import {ProfileWindow, ProfileWindowController} from "./profile.js";
  14. import {BoxVolume} from "../objects/tool/Volume.js";
  15. import {Features} from "../Features.js";
  16. import {Message} from "../utils/Message.js";
  17. import {Sidebar} from "./sidebar.js";
  18. import {AnnotationTool} from "../objects/tool/AnnotationTool.js";
  19. import {MeasuringTool} from "../objects/tool/MeasuringTool.js";
  20. import {ProfileTool} from "../objects/tool/ProfileTool.js";
  21. import {VolumeTool} from "../objects/tool/VolumeTool.js";
  22. import {InputHandler} from "../navigation/InputHandler.js";
  23. import {NavigationCube} from "./NavigationCube.js";
  24. import {Compass} from "../objects/tool/Compass.js";
  25. import {OrbitControls} from "../navigation/OrbitControls.js";
  26. import {FirstPersonControls} from "../navigation/FirstPersonControls.js";
  27. import {EarthControls} from "../navigation/EarthControls.js";
  28. import {DeviceOrientationControls} from "../navigation/DeviceOrientationControls.js";
  29. import {VRControls} from "../navigation/VRControls.js";
  30. import { ClassificationScheme } from "../materials/ClassificationScheme.js";
  31. import { VRButton } from '../../libs/three.js/extra/VRButton.js';
  32. import {transitions, easing, lerp} from '../utils/transitions.js'
  33. import JSON5 from "../../libs/json5-2.1.3/json5.mjs";
  34. import CursorDeal from '../utils/CursorDeal'
  35. import Common from '../utils/Common'
  36. import {Clip} from '../modules/clipModel/Clip'
  37. import {Alignment} from "../modules/datasetAlignment/Alignment.js";
  38. import {SiteModel} from "../modules/siteModel/SiteModel.js";
  39. import {Images360} from "../modules/Images360/Images360.js";
  40. import Magnifier from "../objects/Magnifier.js";
  41. import Reticule from "../objects/Reticule.js";
  42. import Viewport from "./Viewport.js"
  43. import {ViewerBase} from "./viewerBase.js"
  44. import SplitScreen from '../utils/SplitScreen'
  45. import cameraLight from "../utils/cameraLight.js";
  46. import math from "../utils/math.js";
  47. import {UoMService} from '../utils/UnitConvert'
  48. import {RouteGuider} from '../modules/route/RouteGuider'
  49. import ParticleEditor from '../modules/Particles/ParticleEditor'
  50. import {MeshDraw} from '../utils/DrawUtil'
  51. import {OBJLoader} from "../../libs/three.js/loaders/OBJLoader.js";
  52. import {MTLLoader} from "../../libs/three.js/loaders/MTLLoader.js";
  53. let mapArea;
  54. export class Viewer extends ViewerBase{
  55. constructor(domElement, mapArea_, args = {}){
  56. super(domElement, $.extend(args,{name:'mainViewer'}));
  57. window.viewer = this
  58. this.modules = { //add
  59. Clip : Clip,
  60. Alignment : Alignment,
  61. SiteModel : SiteModel,
  62. RouteGuider : new RouteGuider,
  63. ParticleEditor,
  64. }
  65. this.testingMaxLevel = true
  66. //add --------
  67. this.navigateMode = 'free' // 'panorama'; 'free'自由模式是只显示点云或者未进入到漫游点,
  68. this.isEdit = true
  69. this.waitQueue = []
  70. this.unitConvert = new UoMService();
  71. mapArea = mapArea_
  72. this.visible = true
  73. //-------------
  74. var supportExtFragDepth = !!Features.EXT_DEPTH.isSupported() ;//iphoneX居然不支持
  75. //这意味着边缘增强和测量线遮挡失效
  76. if(!supportExtFragDepth)console.error('ExtFragDepth unsupported! 边缘增强和测量线遮挡失效')
  77. this.guiLoaded = false;
  78. this.guiLoadTasks = [];
  79. this.onVrListeners = [];
  80. this.messages = [];
  81. this.elMessages = $(`
  82. <div id="message_listing"
  83. style="position: absolute; z-index: 1000; left: 10px; bottom: 10px">
  84. </div>`);
  85. $(domElement).append(this.elMessages);
  86. this.paused
  87. document.addEventListener('visibilitychange',(e)=>{
  88. //console.log('visibilitychange', !document.hidden )
  89. this.emit('pageVisible', !document.hidden )
  90. /* if(document.hidden){
  91. this.paused = true
  92. }else{
  93. setTimeout(()=>{
  94. if(!document.hidden) this.paused = false
  95. },1000)
  96. } */
  97. })
  98. try{
  99. if(!Potree.settings.isOfficial)
  100. { // generate missing dom hierarchy
  101. if ($(domElement).find('#potree_map').length === 0) {
  102. let potreeMap = $(`
  103. <div id="potree_map" class="mapBox" style="position: absolute; left: 50px; top: 50px; width: 400px; height: 400px; display: none">
  104. <div id="potree_map_header" style="position: absolute; width: 100%; height: 25px; top: 0px; background-color: rgba(0,0,0,0.5); z-index: 1000; border-top-left-radius: 3px; border-top-right-radius: 3px;">
  105. </div>
  106. <div id="potree_map_content" class="map" style="position: absolute; z-index: 100; top: 25px; width: 100%; height: calc(100% - 25px); border: 2px solid rgba(0,0,0,0.5); box-sizing: border-box;"></div>
  107. </div>
  108. `);
  109. $(domElement).append(potreeMap);
  110. }
  111. if ($(domElement).find('#potree_description').length === 0) {
  112. let potreeDescription = $(`<div id="potree_description" class="potree_info_text"></div>`);
  113. $(domElement).append(potreeDescription);
  114. }
  115. if ($(domElement).find('#potree_annotations').length === 0) {
  116. let potreeAnnotationContainer = $(`
  117. <div id="potree_annotation_container"
  118. style="position: absolute; z-index: 100000; width: 100%; height: 100%; pointer-events: none;"></div>`);
  119. $(domElement).append(potreeAnnotationContainer);
  120. }
  121. if ($(domElement).find('#potree_quick_buttons').length === 0) {
  122. let potreeMap = $(`
  123. <div id="potree_quick_buttons" class="quick_buttons_container" style="">
  124. </div>
  125. `);
  126. $(domElement).append(potreeMap);
  127. }
  128. //add
  129. {
  130. if(!mapArea){
  131. $(domElement).append($("<div id='potree_labels'></div>"))
  132. mapArea = $("<div id='mapGaode'></div>")
  133. $(domElement).append(mapArea)
  134. mapArea = mapArea[0]
  135. }
  136. }
  137. let domRoot = this.renderer.domElement.parentElement;
  138. let elAttach = $("<input type='button' value='test'></input>");
  139. elAttach.css({
  140. position : "absolute",
  141. right : '10%',
  142. bottom: '20px',
  143. zIndex: "10000",
  144. fontSize:'1em', color:"black",
  145. background:'rgba(255,255,255,0.8)',
  146. })
  147. let state = false
  148. elAttach.on("click", () => {
  149. window.buttonFunction && window.buttonFunction()
  150. });
  151. domRoot.appendChild(elAttach[0]);
  152. }
  153. this.pointCloudLoadedCallback = args.onPointCloudLoaded || function () {};
  154. // if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
  155. // defaultSettings.navigation = "Orbit";
  156. // }
  157. this.server = null;
  158. this.fov = 60;
  159. this.isFlipYZ = false;
  160. this.useDEMCollisions = false;
  161. this.generateDEM = false;
  162. this.minNodeSize = 30;
  163. this.edlStrength = 1.0;
  164. this.edlRadius = 1.4;
  165. this.edlOpacity = 1.0;
  166. this.useEDL = false;
  167. this.description = "";
  168. this.classifications = ClassificationScheme.DEFAULT;
  169. this.moveSpeed = 10;
  170. this.lengthUnit = LengthUnits.METER;
  171. this.lengthUnitDisplay = LengthUnits.METER;
  172. this.showBoundingBox = false;
  173. this.showAnnotations = true;
  174. this.freeze = false;
  175. this.clipTask = ClipTask.HIGHLIGHT;
  176. this.clipMethod = ClipMethod.INSIDE_ANY;
  177. this.elevationGradientRepeat = ElevationGradientRepeat.CLAMP;
  178. this.filterReturnNumberRange = [0, 7];
  179. this.filterNumberOfReturnsRange = [0, 7];
  180. this.filterGPSTimeRange = [-Infinity, Infinity];
  181. this.filterPointSourceIDRange = [0, 65535];
  182. this.potreeRenderer = null;
  183. this.edlRenderer = null;
  184. this.pRenderer = null;
  185. this.scene = null;
  186. this.sceneVR = null;
  187. this.overlay = null;
  188. this.overlayCamera = null;
  189. this.inputHandler = null;
  190. this.controls = null;
  191. this.clippingTool = null;
  192. this.transformationTool = null;
  193. this.navigationCube = null;
  194. this.compass = null;
  195. this.skybox = null;
  196. this.clock = new THREE.Clock();
  197. this.background = null;
  198. if(args.noDragAndDrop){
  199. }else{
  200. this.initDragAndDrop();
  201. }
  202. if(typeof Stats !== "undefined"){
  203. this.stats = new Stats();
  204. this.stats.showPanel( 0 ); // 0: fps, 1: ms, 2: mb, 3+: custom
  205. document.body.appendChild( this.stats.dom );
  206. }
  207. {
  208. let canvas = this.renderer.domElement;
  209. canvas.addEventListener("webglcontextlost", (e) => {
  210. console.log(e);
  211. this.postMessage("WebGL context lost. \u2639");
  212. let gl = this.renderer.getContext();
  213. let error = gl.getError();
  214. console.log(error);
  215. this.emit('webglError', 'webglcontextlost')
  216. }, false);
  217. }
  218. {
  219. this.overlay = new THREE.Scene();
  220. this.overlayCamera = new THREE.OrthographicCamera(
  221. 0, 1,
  222. 1, 0,
  223. -1000, 1000
  224. );
  225. }
  226. this.pRenderer = new Renderer(this.renderer);
  227. {
  228. let near = 2.5;
  229. let far = 10.0;
  230. let fov = 90;
  231. this.shadowTestCam = new THREE.PerspectiveCamera(90, 1, near, far);
  232. this.shadowTestCam.position.set(3.50, -2.80, 8.561);
  233. this.shadowTestCam.lookAt(new THREE.Vector3(0, 0, 4.87));
  234. }
  235. let scene = new Scene(this.renderer);
  236. { // create VR scene
  237. this.sceneVR = new THREE.Scene();
  238. // let texture = new THREE.TextureLoader().load(`${Potree.resourcePath}/images/vr_controller_help.jpg`);
  239. // let plane = new THREE.PlaneBufferGeometry(1, 1, 1, 1);
  240. // let infoMaterial = new THREE.MeshBasicMaterial({map: texture});
  241. // let infoNode = new THREE.Mesh(plane, infoMaterial);
  242. // infoNode.position.set(-0.5, 1, 0);
  243. // infoNode.scale.set(0.4, 0.3, 1);
  244. // infoNode.lookAt(0, 1, 0)
  245. // this.sceneVR.add(infoNode);
  246. // window.infoNode = infoNode;
  247. }
  248. this.setScene(scene);
  249. {
  250. this.inputHandler = new InputHandler(this, this.scene.scene);
  251. //this.inputHandler.setScene(this.scene);
  252. //this.inputHandler.addInputListener(this);//add
  253. this.clippingTool = new ClippingTool(this);
  254. this.transformationTool = new TransformationTool(this);
  255. this.navigationCube = new NavigationCube(this);
  256. this.navigationCube.visible = false;
  257. this.compass = new Compass(this);
  258. //add----------
  259. this.magnifier = new Magnifier(this);
  260. this.reticule = new Reticule(this)
  261. this.scene.scene.add(this.magnifier)
  262. this.scene.scene.add(this.reticule)
  263. this.mainViewport = new Viewport( this.scene.view, this.scene.cameraP, {
  264. left:0, bottom:0, width:1, height: 1, name:'MainView'
  265. })
  266. this.viewports = [this.mainViewport]
  267. this.mapViewer = new MapViewer(mapArea/* $('#mapGaode')[0] */)
  268. //---------------------------
  269. this.createControls();
  270. this.clippingTool.setScene(this.scene);
  271. let onPointcloudAdded = (e) => {
  272. if (this.scene.pointclouds.length === 1) {
  273. let speed = e.pointcloud.boundingBox.getSize(new THREE.Vector3()).length();
  274. speed = speed / 2000;
  275. this.setMoveSpeed(speed);
  276. }
  277. };
  278. let onVolumeRemoved = (e) => {
  279. this.inputHandler.deselect(e.volume);
  280. };
  281. this.addEventListener('scene_changed', (e) => {
  282. this.inputHandler.setScene(e.scene);
  283. this.clippingTool.setScene(this.scene);
  284. if(!e.scene.hasEventListener("pointcloud_added", onPointcloudAdded)){
  285. e.scene.addEventListener("pointcloud_added", onPointcloudAdded);
  286. }
  287. if(!e.scene.hasEventListener("volume_removed", onPointcloudAdded)){
  288. e.scene.addEventListener("volume_removed", onVolumeRemoved);
  289. }
  290. });
  291. this.scene.addEventListener("volume_removed", onVolumeRemoved);
  292. this.scene.addEventListener('pointcloud_added', onPointcloudAdded);
  293. }
  294. { // set defaults
  295. this.setFOV(60);
  296. this.setEDLEnabled(false);
  297. this.setEDLRadius(1.4);
  298. this.setEDLStrength(0.4);
  299. this.setEDLOpacity(1.0);
  300. this.setClipTask(ClipTask.HIGHLIGHT);
  301. this.setClipMethod(ClipMethod.INSIDE_ANY);
  302. this.setPointBudget(1*1000*1000);
  303. this.setShowBoundingBox(false);
  304. this.setFreeze(false);
  305. this.setControls(this.fpControls/* orbitControls */);
  306. this.setBackground( new THREE.Color(Potree.config.background),1 /* 'gradient' */ );
  307. this.scaleFactor = 1;
  308. this.loadSettingsFromURL();
  309. }
  310. // start rendering!
  311. //if(args.useDefaultRenderLoop === undefined || args.useDefaultRenderLoop === true){
  312. //requestAnimationFrame(this.loop.bind(this));
  313. //}
  314. this.renderer.setAnimationLoop(this.loop.bind(this));
  315. this.loadGUI = this.loadGUI.bind(this);
  316. this.annotationTool = new AnnotationTool(this);
  317. this.measuringTool = new MeasuringTool(this);
  318. this.profileTool = new ProfileTool(this);
  319. this.volumeTool = new VolumeTool(this);
  320. //-----------
  321. CursorDeal.init(this)//ADD
  322. this.modules.SiteModel.init()
  323. this.modules.Alignment.init()
  324. this.modules.ParticleEditor.init()
  325. //-----------
  326. }catch(e){
  327. this.onCrash(e);
  328. }
  329. //-----------------------add----------------------------------------------------
  330. /* {
  331. let ratio
  332. this.addEventListener('resize',(e)=>{
  333. if(ratio != e.deviceRatio){ //因为devicePixelRatio会影响到点云大小,所以改变时计算下点云大小
  334. viewer.scene.pointclouds.forEach(p => {
  335. p.changePointSize()
  336. })
  337. }
  338. ratio = e.deviceRatio
  339. })
  340. } */
  341. {
  342. let pointDensity = ''
  343. Object.defineProperty(Potree.settings , "pointDensity",{
  344. get: function() {
  345. return pointDensity
  346. },
  347. set: (density)=>{
  348. if(density && density != pointDensity){
  349. let pointBudget;
  350. var config = Potree.config.pointDensity[density];
  351. if(this.magnifier.visible){//放大镜打开时不要切换pointBudget,否则点云会闪烁。这时使用最高密度。
  352. pointBudget = Potree.config.pointDensity['magnifier'].pointBudget
  353. }else{
  354. pointBudget = config.pointBudget
  355. }
  356. viewer.setPointBudget(pointBudget );
  357. //Potree.maxPointLevel = config.maxLevel
  358. pointDensity = density
  359. this.setPointLevel()
  360. }
  361. }
  362. })
  363. let UserPointDensity = ''
  364. Object.defineProperty(Potree.settings , "UserPointDensity",{
  365. get: function() {
  366. return UserPointDensity
  367. },
  368. set: (density)=>{
  369. if(UserPointDensity != density){
  370. if(Potree.settings.displayMode == 'showPointCloud' && this.viewports.length != 4){//漫游模式和四屏时都有自己的pointDensity
  371. Potree.settings.pointDensity = density
  372. }
  373. UserPointDensity = density
  374. }
  375. }
  376. })
  377. this.on('updateNodeMaxLevel',(pointcloud,nodeMaxLevel)=>{
  378. if(!viewer.testNodeLevelTimer && viewer.testingMaxLevel ){
  379. viewer.testNodeLevelTimer = setTimeout(()=>{//先加载一段时间最高level的点云。但希望不会刚好附近的点云都没有达到最高的level,否则就要走一段才能了。
  380. viewer.testingMaxLevel = false
  381. console.log('结束testingMaxLevel')
  382. //Potree.settings.pointDensity = Potree.settings.pointDensity
  383. this.setPointLevel()//重新计算
  384. },3000)
  385. viewer.beginTestTime = Date.now()
  386. }
  387. //console.log('updateNodeMaxLevel ' + pointcloud.dataset_id + " : "+ nodeMaxLevel)
  388. if(nodeMaxLevel >= 10 && viewer.testingMaxLevel){//10的时候差不多能加载到11和12了。假设最高只有12的话,就到10就可以。不过大多数场景都到不了10,也不知有没有大于10的,如果没有,这里可以写5.
  389. viewer.testingMaxLevel = false
  390. console.log('提前结束testingMaxLevel,用时:'+(Date.now()-viewer.beginTestTime))
  391. //我的电脑用时大概1500
  392. }
  393. //Potree.settings.pointDensity = Potree.settings.pointDensity //重新计算
  394. this.setPointLevel()//重新计算
  395. if(!Potree.settings.sizeFitToLevel){
  396. pointcloud.changePointSize()
  397. }
  398. //见过最小加载到的nodeMaxLevel是4
  399. })
  400. }
  401. {
  402. let cameraFar = Potree.settings.cameraFar
  403. Object.defineProperty(Potree.settings , "cameraFar",{
  404. get: function() {
  405. return cameraFar
  406. },
  407. set: (far)=>{
  408. if(far != cameraFar){
  409. if(Potree.settings.displayMode != 'showPanos'){
  410. this.mainViewport.camera.far = far;
  411. this.mainViewport.camera.updateProjectionMatrix()
  412. }
  413. cameraFar = far
  414. }
  415. }
  416. })
  417. }
  418. }
  419. setPointLevel(){
  420. var pointDensity = Potree.settings.pointDensity
  421. var config = Potree.config.pointDensity[pointDensity];
  422. this.scene.pointclouds.forEach(e=>{
  423. if(this.testingMaxLevel){
  424. e.maxLevel = 12;//先加载到最大的直到测试完毕。由于5个level为一组来加载,所以如果写4最高能加载到5,如果写5最高能加载到下一个级别的最高也就是10
  425. //console.log('maxLevel: '+e.maxLevel + ' testingMaxLevel中 ' )
  426. }else{
  427. let percent = config.percentByUser && Potree.settings.UserDensityPercent != void 0 ? Potree.settings.UserDensityPercent : config.maxLevelPercent
  428. e.maxLevel = Math.round( percent * e.nodeMaxLevel);
  429. //console.log('maxLevel: '+e.maxLevel + ', density : '+Potree.settings.pointDensity, ", percent :"+percent);
  430. if(Potree.settings.sizeFitToLevel){
  431. e.changePointSize()
  432. }
  433. e.changePointOpacity()
  434. }
  435. })
  436. /* if(!viewer.testingMaxLevel && Potree.sdk){
  437. Potree.sdk.scene.changePointSize()
  438. Potree.sdk.scene.changePointOpacity()
  439. } */
  440. }
  441. onCrash(error){
  442. $(this.renderArea).empty();
  443. if ($(this.renderArea).find('#potree_failpage').length === 0) {
  444. let elFailPage = $(`
  445. <div id="#potree_failpage" class="potree_failpage">
  446. <h1>Potree Encountered An Error </h1>
  447. <p>
  448. This may happen if your browser or graphics card is not supported.
  449. <br>
  450. We recommend to use
  451. <a href="https://www.google.com/chrome/browser" target="_blank" style="color:initial">Chrome</a>
  452. or
  453. <a href="https://www.mozilla.org/" target="_blank">Firefox</a>.
  454. </p>
  455. <p>
  456. Please also visit <a href="http://webglreport.com/" target="_blank">webglreport.com</a> and
  457. check whether your system supports WebGL.
  458. </p>
  459. <p>
  460. If you are already using one of the recommended browsers and WebGL is enabled,
  461. consider filing an issue report at <a href="https://github.com/potree/potree/issues" target="_blank">github</a>,<br>
  462. including your operating system, graphics card, browser and browser version, as well as the
  463. error message below.<br>
  464. Please do not report errors on unsupported browsers.
  465. </p>
  466. <pre id="potree_error_console" style="width: 100%; height: 100%"></pre>
  467. </div>`);
  468. let elErrorMessage = elFailPage.find('#potree_error_console');
  469. elErrorMessage.html(error.stack);
  470. $(this.renderArea).append(elFailPage);
  471. }
  472. throw error;
  473. }
  474. // ------------------------------------------------------------------------------------
  475. // Viewer API
  476. // ------------------------------------------------------------------------------------
  477. setScene (scene) {
  478. if (scene === this.scene) {
  479. return;
  480. }
  481. let oldScene = this.scene;
  482. this.scene = scene;
  483. this.dispatchEvent({
  484. type: 'scene_changed',
  485. oldScene: oldScene,
  486. scene: scene
  487. });
  488. { // Annotations
  489. $('.annotation').detach();
  490. // for(let annotation of this.scene.annotations){
  491. // this.renderArea.appendChild(annotation.domElement[0]);
  492. // }
  493. this.scene.annotations.traverse(annotation => {
  494. this.renderArea.appendChild(annotation.domElement[0]);
  495. });
  496. if (!this.onAnnotationAdded) {
  497. this.onAnnotationAdded = e => {
  498. // console.log("annotation added: " + e.annotation.title);
  499. e.annotation.traverse(node => {
  500. $("#potree_annotation_container").append(node.domElement);
  501. //this.renderArea.appendChild(node.domElement[0]);
  502. node.scene = this.scene;
  503. });
  504. };
  505. }
  506. if (oldScene) {
  507. oldScene.annotations.removeEventListener('annotation_added', this.onAnnotationAdded);
  508. }
  509. this.scene.annotations.addEventListener('annotation_added', this.onAnnotationAdded);
  510. }
  511. };
  512. setControls(controls/* , setSpeed */){
  513. if (controls !== this.controls) {
  514. if (this.controls) {
  515. this.controls.setEnable(false)
  516. //this.inputHandler.removeInputListener(this.controls);
  517. this.controls.moveSpeed = this.moveSpeed; //记录 (因为orbit的radius很大,转为firstPerson时要缩小)
  518. }
  519. this.controls = controls;
  520. controls.moveSpeed && this.setMoveSpeed(controls.moveSpeed) //add
  521. this.controls.setEnable(true)
  522. //this.inputHandler.addInputListener(this.controls);
  523. }
  524. }
  525. getControls () {
  526. if(this.renderer.xr.isPresenting){
  527. return this.vrControls;
  528. }else{
  529. return this.controls;
  530. }
  531. }
  532. getMinNodeSize () {
  533. return this.minNodeSize;
  534. };
  535. setMinNodeSize (value) {
  536. if (this.minNodeSize !== value) {
  537. this.minNodeSize = value;
  538. this.dispatchEvent({'type': 'minnodesize_changed', 'viewer': this});
  539. }
  540. };
  541. getBackground () {
  542. return this.background;
  543. }
  544. setBackground(bg){
  545. if (this.background === bg) {
  546. return;
  547. }
  548. if(bg === "skybox"){
  549. this.skybox = Utils.loadSkybox(new URL(Potree.resourcePath + '/textures/skybox2/').href);
  550. }
  551. this.background = bg;
  552. this.backgroundOpacity = 1//add
  553. this.dispatchEvent({'type': 'background_changed', 'viewer': this});
  554. }
  555. setDescription (value) {
  556. this.description = value;
  557. $('#potree_description').html(value);
  558. //$('#potree_description').text(value);
  559. }
  560. getDescription(){
  561. return this.description;
  562. }
  563. setShowBoundingBox (value) {
  564. if (this.showBoundingBox !== value) {
  565. this.showBoundingBox = value;
  566. this.dispatchEvent({'type': 'show_boundingbox_changed', 'viewer': this});
  567. }
  568. };
  569. getShowBoundingBox () {
  570. return this.showBoundingBox;
  571. };
  572. setMoveSpeed (value) {
  573. if (this.getMoveSpeed() !== value) {
  574. this.mainViewport.setMoveSpeed(value)
  575. this.dispatchEvent({'type': 'move_speed_changed', 'viewer': this, 'speed': value});
  576. }
  577. };
  578. getMoveSpeed () {
  579. return this.mainViewport.moveSpeed;
  580. };
  581. setWeightClassification (w) {
  582. for (let i = 0; i < this.scene.pointclouds.length; i++) {
  583. this.scene.pointclouds[i].material.weightClassification = w;
  584. this.dispatchEvent({'type': 'attribute_weights_changed' + i, 'viewer': this});
  585. }
  586. };
  587. setFreeze (value) {
  588. value = Boolean(value);
  589. if (this.freeze !== value) {
  590. this.freeze = value;
  591. this.dispatchEvent({'type': 'freeze_changed', 'viewer': this});
  592. }
  593. };
  594. getFreeze () {
  595. return this.freeze;
  596. };
  597. getClipTask(){
  598. return this.clipTask;
  599. }
  600. getClipMethod(){
  601. return this.clipMethod;
  602. }
  603. setClipTask(value){
  604. if(this.clipTask !== value){
  605. this.clipTask = value;
  606. this.dispatchEvent({
  607. type: "cliptask_changed",
  608. viewer: this});
  609. }
  610. }
  611. setClipMethod(value){
  612. if(this.clipMethod !== value){
  613. this.clipMethod = value;
  614. this.dispatchEvent({
  615. type: "clipmethod_changed",
  616. viewer: this});
  617. }
  618. }
  619. setElevationGradientRepeat(value){
  620. if(this.elevationGradientRepeat !== value){
  621. this.elevationGradientRepeat = value;
  622. this.dispatchEvent({
  623. type: "elevation_gradient_repeat_changed",
  624. viewer: this});
  625. }
  626. }
  627. setPointBudget (value) {
  628. if (Potree.pointBudget !== value) {
  629. Potree.pointBudget = parseInt(value);
  630. this.dispatchEvent({'type': 'point_budget_changed', 'viewer': this});
  631. }
  632. };
  633. getPointBudget () {
  634. return Potree.pointBudget;
  635. };
  636. setShowAnnotations (value) {
  637. if (this.showAnnotations !== value) {
  638. this.showAnnotations = value;
  639. this.dispatchEvent({'type': 'show_annotations_changed', 'viewer': this});
  640. }
  641. }
  642. getShowAnnotations () {
  643. return this.showAnnotations;
  644. }
  645. setDEMCollisionsEnabled(value){
  646. if(this.useDEMCollisions !== value){
  647. this.useDEMCollisions = value;
  648. this.dispatchEvent({'type': 'use_demcollisions_changed', 'viewer': this});
  649. };
  650. };
  651. getDEMCollisionsEnabled () {
  652. return this.useDEMCollisions;
  653. };
  654. setEDLEnabled (value) {
  655. value = Boolean(value) && Features.SHADER_EDL.isSupported();
  656. if (this.useEDL !== value) {
  657. this.useEDL = value;
  658. this.dispatchEvent({'type': 'use_edl_changed', 'viewer': this});
  659. }
  660. };
  661. getEDLEnabled () {
  662. return this.useEDL;
  663. };
  664. setEDLRadius (value) {
  665. if (this.edlRadius !== value) {
  666. this.edlRadius = value;
  667. this.dispatchEvent({'type': 'edl_radius_changed', 'viewer': this});
  668. }
  669. };
  670. getEDLRadius () {
  671. return this.edlRadius;
  672. };
  673. setEDLStrength (value) {
  674. if (this.edlStrength !== value) {
  675. this.edlStrength = value;
  676. this.dispatchEvent({'type': 'edl_strength_changed', 'viewer': this});
  677. }
  678. };
  679. getEDLStrength () {
  680. return this.edlStrength;
  681. };
  682. setEDLOpacity (value) {
  683. if (this.edlOpacity !== value) {
  684. this.edlOpacity = value;
  685. this.dispatchEvent({'type': 'edl_opacity_changed', 'viewer': this});
  686. }
  687. };
  688. getEDLOpacity () {
  689. return this.edlOpacity;
  690. };
  691. setFOV (value) {
  692. if (this.fov !== value) {
  693. let oldFov = this.fov
  694. this.fov = value;
  695. this.scene.cameraP.fov = this.fov;
  696. this.scene.cameraP.updateProjectionMatrix()
  697. this.dispatchEvent({'type': 'fov_changed', 'viewer': this, oldFov, fov:this.fov});
  698. }
  699. };
  700. getFOV () {
  701. return this.fov;
  702. };
  703. disableAnnotations () {
  704. this.scene.annotations.traverse(annotation => {
  705. annotation.domElement.css('pointer-events', 'none');
  706. // return annotation.visible;
  707. });
  708. };
  709. enableAnnotations () {
  710. this.scene.annotations.traverse(annotation => {
  711. annotation.domElement.css('pointer-events', 'auto');
  712. // return annotation.visible;
  713. });
  714. }
  715. setClassifications(classifications){
  716. this.classifications = classifications;
  717. this.dispatchEvent({'type': 'classifications_changed', 'viewer': this});
  718. }
  719. setClassificationVisibility (key, value) {
  720. if (!this.classifications[key]) {
  721. this.classifications[key] = {visible: value, name: 'no name'};
  722. this.dispatchEvent({'type': 'classification_visibility_changed', 'viewer': this});
  723. } else if (this.classifications[key].visible !== value) {
  724. this.classifications[key].visible = value;
  725. this.dispatchEvent({'type': 'classification_visibility_changed', 'viewer': this});
  726. }
  727. }
  728. toggleAllClassificationsVisibility(){
  729. let numVisible = 0;
  730. let numItems = 0;
  731. for(const key of Object.keys(this.classifications)){
  732. if(this.classifications[key].visible){
  733. numVisible++;
  734. }
  735. numItems++;
  736. }
  737. let visible = true;
  738. if(numVisible === numItems){
  739. visible = false;
  740. }
  741. let somethingChanged = false;
  742. for(const key of Object.keys(this.classifications)){
  743. if(this.classifications[key].visible !== visible){
  744. this.classifications[key].visible = visible;
  745. somethingChanged = true;
  746. }
  747. }
  748. if(somethingChanged){
  749. this.dispatchEvent({'type': 'classification_visibility_changed', 'viewer': this});
  750. }
  751. }
  752. setFilterReturnNumberRange(from, to){
  753. this.filterReturnNumberRange = [from, to];
  754. this.dispatchEvent({'type': 'filter_return_number_range_changed', 'viewer': this});
  755. }
  756. setFilterNumberOfReturnsRange(from, to){
  757. this.filterNumberOfReturnsRange = [from, to];
  758. this.dispatchEvent({'type': 'filter_number_of_returns_range_changed', 'viewer': this});
  759. }
  760. setFilterGPSTimeRange(from, to){
  761. this.filterGPSTimeRange = [from, to];
  762. this.dispatchEvent({'type': 'filter_gps_time_range_changed', 'viewer': this});
  763. }
  764. setFilterPointSourceIDRange(from, to){
  765. this.filterPointSourceIDRange = [from, to]
  766. this.dispatchEvent({'type': 'filter_point_source_id_range_changed', 'viewer': this});
  767. }
  768. setLengthUnit (value) {
  769. switch (value) {
  770. case 'm':
  771. this.lengthUnit = LengthUnits.METER;
  772. this.lengthUnitDisplay = LengthUnits.METER;
  773. break;
  774. case 'ft':
  775. this.lengthUnit = LengthUnits.FEET;
  776. this.lengthUnitDisplay = LengthUnits.FEET;
  777. break;
  778. case 'in':
  779. this.lengthUnit = LengthUnits.INCH;
  780. this.lengthUnitDisplay = LengthUnits.INCH;
  781. break;
  782. }
  783. this.dispatchEvent({ 'type': 'length_unit_changed', 'viewer': this, value: value});
  784. };
  785. setLengthUnitAndDisplayUnit(lengthUnitValue, lengthUnitDisplayValue) {
  786. switch (lengthUnitValue) {
  787. case 'm':
  788. this.lengthUnit = LengthUnits.METER;
  789. break;
  790. case 'ft':
  791. this.lengthUnit = LengthUnits.FEET;
  792. break;
  793. case 'in':
  794. this.lengthUnit = LengthUnits.INCH;
  795. break;
  796. }
  797. switch (lengthUnitDisplayValue) {
  798. case 'm':
  799. this.lengthUnitDisplay = LengthUnits.METER;
  800. break;
  801. case 'ft':
  802. this.lengthUnitDisplay = LengthUnits.FEET;
  803. break;
  804. case 'in':
  805. this.lengthUnitDisplay = LengthUnits.INCH;
  806. break;
  807. }
  808. this.dispatchEvent({ 'type': 'length_unit_changed', 'viewer': this, value: lengthUnitValue });
  809. };
  810. zoomTo(node, factor, animationDuration = 0){
  811. let view = this.scene.view;
  812. let camera = this.scene.cameraP.clone();
  813. camera.rotation.copy(this.scene.cameraP.rotation);
  814. camera.rotation.order = "ZXY";
  815. camera.rotation.x = Math.PI / 2 + view.pitch;
  816. camera.rotation.z = view.yaw;
  817. camera.updateMatrix();
  818. camera.updateMatrixWorld();
  819. camera.zoomTo(node, factor);
  820. let bs;
  821. if (node.boundingSphere) {
  822. bs = node.boundingSphere;
  823. } else if (node.geometry && node.geometry.boundingSphere) {
  824. bs = node.geometry.boundingSphere;
  825. } else {
  826. bs = node.boundingBox.getBoundingSphere(new THREE.Sphere());
  827. }
  828. bs = bs.clone().applyMatrix4(node.matrixWorld);
  829. let startPosition = view.position.clone();
  830. let endPosition = camera.position.clone();
  831. let startTarget = view.getPivot();
  832. let endTarget = bs.center;
  833. let startRadius = view.radius;
  834. let endRadius = endPosition.distanceTo(endTarget);
  835. let easing = TWEEN.Easing.Quartic.Out;
  836. { // animate camera position
  837. let pos = startPosition.clone();
  838. let tween = new TWEEN.Tween(pos).to(endPosition, animationDuration);
  839. tween.easing(easing);
  840. tween.onUpdate(() => {
  841. view.position.copy(pos);
  842. });
  843. tween.start();
  844. }
  845. { // animate camera target
  846. let target = startTarget.clone();
  847. let tween = new TWEEN.Tween(target).to(endTarget, animationDuration);
  848. tween.easing(easing);
  849. tween.onUpdate(() => {
  850. view.lookAt(target);
  851. });
  852. tween.onComplete(() => {
  853. view.lookAt(target);
  854. this.dispatchEvent({type: 'focusing_finished', target: this});
  855. });
  856. this.dispatchEvent({type: 'focusing_started', target: this});
  857. tween.start();
  858. }
  859. };
  860. moveToGpsTimeVicinity(time){
  861. const result = Potree.Utils.findClosestGpsTime(time, viewer);
  862. const box = result.node.pointcloud.deepestNodeAt(result.position).getBoundingBox();
  863. const diameter = box.min.distanceTo(box.max);
  864. const camera = this.scene.getActiveCamera();
  865. const offset = camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(diameter);
  866. const newCamPos = result.position.clone().sub(offset);
  867. this.scene.view.position.copy(newCamPos);
  868. this.scene.view.lookAt(result.position);
  869. }
  870. showAbout () {
  871. $(function () {
  872. $('#about-panel').dialog();
  873. });
  874. };
  875. getGpsTimeExtent(){
  876. const range = [Infinity, -Infinity];
  877. for(const pointcloud of this.scene.pointclouds){
  878. const attributes = pointcloud.pcoGeometry.pointAttributes.attributes;
  879. const aGpsTime = attributes.find(a => a.name === "gps-time");
  880. if(aGpsTime){
  881. range[0] = Math.min(range[0], aGpsTime.range[0]);
  882. range[1] = Math.max(range[1], aGpsTime.range[1]);
  883. }
  884. }
  885. return range;
  886. }
  887. fitToScreen (factor = 1, animationDuration = 0) {
  888. let box = this.getBoundingBox(this.scene.pointclouds);
  889. let node = new THREE.Object3D();
  890. node.boundingBox = box;
  891. this.zoomTo(node, factor, animationDuration);
  892. this.controls.stop();
  893. };
  894. toggleNavigationCube() {
  895. this.navigationCube.visible = !this.navigationCube.visible;
  896. }
  897. /* setView(pos, view) {
  898. if(!pos) return;
  899. switch(pos) {
  900. case "F":
  901. this.setFrontView(view);
  902. break;
  903. case "B":
  904. this.setBackView(view);
  905. break;
  906. case "L":
  907. this.setLeftView(view);
  908. break;
  909. case "R":
  910. this.setRightView(view);
  911. break;
  912. case "U":
  913. this.setTopView(view);
  914. break;
  915. case "D":
  916. this.setBottomView(view);
  917. break;
  918. }
  919. } */
  920. setTopView(view){
  921. view = view || this.scene.view
  922. view.setCubeView("Top")
  923. this.fitToScreen();
  924. };
  925. setBottomView(){
  926. this.scene.view.yaw = -Math.PI;
  927. this.scene.view.pitch = Math.PI / 2;
  928. this.fitToScreen();
  929. };
  930. setFrontView(view){
  931. view = view || this.scene.view
  932. view.yaw = 0;
  933. view.pitch = 0;
  934. this.fitToScreen();
  935. };
  936. setBackView(view){
  937. view = view || this.scene.view
  938. view.yaw = Math.PI;
  939. view.pitch = 0;
  940. this.fitToScreen();
  941. };
  942. setLeftView(){
  943. this.scene.view.yaw = -Math.PI / 2;
  944. this.scene.view.pitch = 0;
  945. this.fitToScreen();
  946. };
  947. setRightView () {
  948. this.scene.view.yaw = Math.PI / 2;
  949. this.scene.view.pitch = 0;
  950. this.fitToScreen();
  951. };
  952. flipYZ () {
  953. this.isFlipYZ = !this.isFlipYZ;
  954. // TODO flipyz
  955. console.log('TODO');
  956. }
  957. setCameraMode(mode){
  958. this.scene.cameraMode = mode;
  959. for(let pointcloud of this.scene.pointclouds) {
  960. pointcloud.material.useOrthographicCamera = mode == CameraMode.ORTHOGRAPHIC;
  961. }
  962. }
  963. getProjection(){
  964. const pointcloud = this.scene.pointclouds[0];
  965. if(pointcloud){
  966. return pointcloud.projection;
  967. }else{
  968. return null;
  969. }
  970. }
  971. async loadProject(url,done){
  972. const response = await fetch(url);
  973. if(response.ok){
  974. const text = await response.text();
  975. const json = JSON5.parse(text);
  976. // const json = JSON.parse(text);
  977. if(json.type === "Potree"){
  978. Potree.loadProject(viewer, json, done);
  979. }
  980. }else{
  981. console.warn("未能加载:"+url )
  982. }
  983. }
  984. saveProject(){
  985. return Potree.saveProject(this);
  986. }
  987. loadSettingsFromURL(){
  988. if(Utils.getParameterByName("pointSize")){
  989. this.setPointSize(parseFloat(Utils.getParameterByName("pointSize")));
  990. }
  991. if(Utils.getParameterByName("FOV")){
  992. this.setFOV(parseFloat(Utils.getParameterByName("FOV")));
  993. }
  994. if(Utils.getParameterByName("opacity")){
  995. this.setOpacity(parseFloat(Utils.getParameterByName("opacity")));
  996. }
  997. if(Utils.getParameterByName("edlEnabled")){
  998. let enabled = Utils.getParameterByName("edlEnabled") === "true";
  999. this.setEDLEnabled(enabled);
  1000. }
  1001. if (Utils.getParameterByName('edlRadius')) {
  1002. this.setEDLRadius(parseFloat(Utils.getParameterByName('edlRadius')));
  1003. }
  1004. if (Utils.getParameterByName('edlStrength')) {
  1005. this.setEDLStrength(parseFloat(Utils.getParameterByName('edlStrength')));
  1006. }
  1007. if (Utils.getParameterByName('pointBudget')) {
  1008. this.setPointBudget(parseFloat(Utils.getParameterByName('pointBudget')));
  1009. }
  1010. if (Utils.getParameterByName('showBoundingBox')) {
  1011. let enabled = Utils.getParameterByName('showBoundingBox') === 'true';
  1012. if (enabled) {
  1013. this.setShowBoundingBox(true);
  1014. } else {
  1015. this.setShowBoundingBox(false);
  1016. }
  1017. }
  1018. if (Utils.getParameterByName('material')) {
  1019. let material = Utils.getParameterByName('material');
  1020. this.setMaterial(material);
  1021. }
  1022. if (Utils.getParameterByName('pointSizing')) {
  1023. let sizing = Utils.getParameterByName('pointSizing');
  1024. this.setPointSizing(sizing);
  1025. }
  1026. if (Utils.getParameterByName('quality')) {
  1027. let quality = Utils.getParameterByName('quality');
  1028. this.setQuality(quality);
  1029. }
  1030. if (Utils.getParameterByName('position')) {
  1031. let value = Utils.getParameterByName('position');
  1032. value = value.replace('[', '').replace(']', '');
  1033. let tokens = value.split(';');
  1034. let x = parseFloat(tokens[0]);
  1035. let y = parseFloat(tokens[1]);
  1036. let z = parseFloat(tokens[2]);
  1037. this.scene.view.position.set(x, y, z);
  1038. }
  1039. if (Utils.getParameterByName('target')) {
  1040. let value = Utils.getParameterByName('target');
  1041. value = value.replace('[', '').replace(']', '');
  1042. let tokens = value.split(';');
  1043. let x = parseFloat(tokens[0]);
  1044. let y = parseFloat(tokens[1]);
  1045. let z = parseFloat(tokens[2]);
  1046. this.scene.view.lookAt(new THREE.Vector3(x, y, z));
  1047. }
  1048. if (Utils.getParameterByName('background')) {
  1049. let value = Utils.getParameterByName('background');
  1050. this.setBackground(value);
  1051. }
  1052. // if(Utils.getParameterByName("elevationRange")){
  1053. // let value = Utils.getParameterByName("elevationRange");
  1054. // value = value.replace("[", "").replace("]", "");
  1055. // let tokens = value.split(";");
  1056. // let x = parseFloat(tokens[0]);
  1057. // let y = parseFloat(tokens[1]);
  1058. //
  1059. // this.setElevationRange(x, y);
  1060. // //this.scene.view.target.set(x, y, z);
  1061. // }
  1062. };
  1063. // ------------------------------------------------------------------------------------
  1064. // Viewer Internals
  1065. // ------------------------------------------------------------------------------------
  1066. createControls () {
  1067. { // create FIRST PERSON CONTROLS
  1068. this.fpControls = new FirstPersonControls(this, this.mainViewport);
  1069. this.fpControls.enabled = false;
  1070. this.fpControls.addEventListener('start', this.disableAnnotations.bind(this));
  1071. this.fpControls.addEventListener('end', this.enableAnnotations.bind(this));
  1072. /* this.addEventListener("loadPointCloudDone", ()=>{
  1073. let boundPlane = new THREE.Box3()
  1074. boundPlane.expandByPoint(this.bound.boundingBox.min.clone())//最低高度为bound的最低
  1075. boundPlane.expandByPoint(this.bound.boundingBox.max.clone().setZ(this.bound.center.z))//最高高度为bound的中心高度
  1076. FirstPersonControls.boundPlane = boundPlane
  1077. FirstPersonControls.standardSpeed = THREE.Math.clamp( Math.sqrt(this.bound.boundSize.length() )/ 100 , 0.02,0.5); //在这个boundPlane中的速度
  1078. }) */
  1079. }
  1080. // { // create GEO CONTROLS
  1081. // this.geoControls = new GeoControls(this.scene.camera, this.renderer.domElement);
  1082. // this.geoControls.enabled = false;
  1083. // this.geoControls.addEventListener("start", this.disableAnnotations.bind(this));
  1084. // this.geoControls.addEventListener("end", this.enableAnnotations.bind(this));
  1085. // this.geoControls.addEventListener("move_speed_changed", (event) => {
  1086. // this.setMoveSpeed(this.geoControls.moveSpeed);
  1087. // });
  1088. // }
  1089. { // create ORBIT CONTROLS
  1090. this.orbitControls = new OrbitControls(this);
  1091. this.orbitControls.enabled = false;
  1092. this.orbitControls.addEventListener('start', this.disableAnnotations.bind(this));
  1093. this.orbitControls.addEventListener('end', this.enableAnnotations.bind(this));
  1094. }
  1095. { // create EARTH CONTROLS
  1096. this.earthControls = new EarthControls(this);
  1097. this.earthControls.enabled = false;
  1098. this.earthControls.addEventListener('start', this.disableAnnotations.bind(this));
  1099. this.earthControls.addEventListener('end', this.enableAnnotations.bind(this));
  1100. }
  1101. { // create DEVICE ORIENTATION CONTROLS
  1102. this.deviceControls = new DeviceOrientationControls(this);
  1103. this.deviceControls.enabled = false;
  1104. this.deviceControls.addEventListener('start', this.disableAnnotations.bind(this));
  1105. this.deviceControls.addEventListener('end', this.enableAnnotations.bind(this));
  1106. }
  1107. { // create VR CONTROLS
  1108. this.vrControls = new VRControls(this);
  1109. this.vrControls.enabled = false;
  1110. this.vrControls.addEventListener('start', this.disableAnnotations.bind(this));
  1111. this.vrControls.addEventListener('end', this.enableAnnotations.bind(this));
  1112. }
  1113. };
  1114. toggleSidebar () {
  1115. let renderArea = $('#potree_render_area');
  1116. let isVisible = renderArea.css('left') !== '0px';
  1117. if (isVisible) {
  1118. renderArea.css('left', '0px');
  1119. } else {
  1120. renderArea.css('left', '300px');
  1121. }
  1122. };
  1123. toggleMap () {
  1124. // let map = $('#potree_map');
  1125. // map.toggle(100);
  1126. if (this.mapView) {
  1127. this.mapView.toggle();
  1128. }
  1129. };
  1130. onGUILoaded(callback){
  1131. if(this.guiLoaded){
  1132. callback();
  1133. }else{
  1134. this.guiLoadTasks.push(callback);
  1135. }
  1136. }
  1137. promiseGuiLoaded(){
  1138. return new Promise( resolve => {
  1139. if(this.guiLoaded){
  1140. resolve();
  1141. }else{
  1142. this.guiLoadTasks.push(resolve);
  1143. }
  1144. });
  1145. }
  1146. loadGUI(callback){
  1147. if(callback){
  1148. this.onGUILoaded(callback);
  1149. }
  1150. let viewer = this;
  1151. let sidebarContainer = $('#potree_sidebar_container');
  1152. sidebarContainer.load(new URL(Potree.scriptPath + '/sidebar.html').href, () => {
  1153. sidebarContainer.css('width', '300px');
  1154. sidebarContainer.css('height', '100%');
  1155. let imgMenuToggle = document.createElement('img');
  1156. imgMenuToggle.src = new URL(Potree.resourcePath + '/icons/menu_button.svg').href;
  1157. imgMenuToggle.onclick = this.toggleSidebar;
  1158. imgMenuToggle.classList.add('potree_menu_toggle');
  1159. let imgMapToggle = document.createElement('img');
  1160. imgMapToggle.src = new URL(Potree.resourcePath + '/icons/map_icon.png').href;
  1161. imgMapToggle.style.display = 'none';
  1162. imgMapToggle.onclick = e => { this.toggleMap(); };
  1163. imgMapToggle.id = 'potree_map_toggle';
  1164. let elButtons = $("#potree_quick_buttons").get(0);
  1165. elButtons.append(imgMenuToggle);
  1166. elButtons.append(imgMapToggle);
  1167. /*
  1168. VRButton.createButton(this.renderer).then(vrButton => {
  1169. if(vrButton == null){
  1170. console.log("VR not supported or active.");
  1171. return;
  1172. }
  1173. this.renderer.xr.enabled = true;
  1174. let element = vrButton.element;
  1175. element.style.position = "";
  1176. element.style.bottom = "";
  1177. element.style.left = "";
  1178. element.style.margin = "4px";
  1179. element.style.fontSize = "100%";
  1180. element.style.width = "2.5em";
  1181. element.style.height = "2.5em";
  1182. element.style.padding = "0";
  1183. element.style.textShadow = "black 2px 2px 2px";
  1184. element.style.display = "block";
  1185. elButtons.append(element);
  1186. vrButton.onStart(() => {
  1187. this.dispatchEvent({type: "vr_start"});
  1188. });
  1189. vrButton.onEnd(() => {
  1190. this.dispatchEvent({type: "vr_end"});
  1191. });
  1192. });
  1193. this.mapView = new MapView(this);
  1194. this.mapView.init(); */
  1195. i18n.init({
  1196. lng: 'en',
  1197. resGetPath: Potree.resourcePath + '/lang/__lng__/__ns__.json',
  1198. preload: ['en', 'fr', 'de', 'jp', 'se', 'es', 'zh'],
  1199. getAsync: true,
  1200. debug: false
  1201. }, function (t) {
  1202. // Start translation once everything is loaded
  1203. $('body').i18n();
  1204. });
  1205. $(() => {
  1206. //initSidebar(this);
  1207. let sidebar = new Sidebar(this);
  1208. sidebar.init();
  1209. this.sidebar = sidebar;
  1210. //if (callback) {
  1211. // $(callback);
  1212. //}
  1213. let elProfile = $('<div>').load(new URL(Potree.scriptPath + '/profile.html').href, () => {
  1214. $(document.body).append(elProfile.children());
  1215. this.profileWindow = new ProfileWindow(this);
  1216. this.profileWindowController = new ProfileWindowController(this);
  1217. $('#profile_window').draggable({
  1218. handle: $('#profile_titlebar'),
  1219. containment: $(document.body)
  1220. });
  1221. $('#profile_window').resizable({
  1222. containment: $(document.body),
  1223. handles: 'n, e, s, w'
  1224. });
  1225. $(() => {
  1226. this.guiLoaded = true;
  1227. for(let task of this.guiLoadTasks){
  1228. task();
  1229. }
  1230. });
  1231. });
  1232. });
  1233. });
  1234. return this.promiseGuiLoaded();
  1235. }
  1236. setLanguage (lang) {
  1237. i18n.setLng(lang);
  1238. $('body').i18n();
  1239. }
  1240. setServer (server) {
  1241. this.server = server;
  1242. }
  1243. initDragAndDrop(){
  1244. function allowDrag(e) {
  1245. e.dataTransfer.dropEffect = 'copy';
  1246. e.preventDefault();
  1247. }
  1248. let dropHandler = async (event) => {
  1249. console.log(event);
  1250. event.preventDefault();
  1251. for(const item of event.dataTransfer.items){
  1252. console.log(item);
  1253. if(item.kind !== "file"){
  1254. continue;
  1255. }
  1256. const file = item.getAsFile();
  1257. const isJson = file.name.toLowerCase().endsWith(".json");
  1258. const isGeoPackage = file.name.toLowerCase().endsWith(".gpkg");
  1259. if(isJson){
  1260. try{
  1261. const text = await file.text();
  1262. const json = JSON.parse(text);
  1263. if(json.type === "Potree"){
  1264. Potree.loadProject(viewer, json);
  1265. }
  1266. }catch(e){
  1267. console.error("failed to parse the dropped file as JSON");
  1268. console.error(e);
  1269. }
  1270. }else if(isGeoPackage){
  1271. const hasPointcloud = viewer.scene.pointclouds.length > 0;
  1272. if(!hasPointcloud){
  1273. let msg = "At least one point cloud is needed that specifies the ";
  1274. msg += "coordinate reference system before loading vector data.";
  1275. console.error(msg);
  1276. }else{
  1277. proj4.defs("WGS84", "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
  1278. proj4.defs("pointcloud", this.getProjection());
  1279. let transform = proj4("WGS84", "pointcloud");
  1280. const buffer = await file.arrayBuffer();
  1281. const params = {
  1282. transform: transform,
  1283. source: file.name,
  1284. };
  1285. const geo = await Potree.GeoPackageLoader.loadBuffer(buffer, params);
  1286. viewer.scene.addGeopackage(geo);
  1287. }
  1288. }
  1289. }
  1290. };
  1291. $("body")[0].addEventListener("dragenter", allowDrag);
  1292. $("body")[0].addEventListener("dragover", allowDrag);
  1293. $("body")[0].addEventListener("drop", dropHandler);
  1294. }
  1295. updateAnnotations () {
  1296. if(!this.visibleAnnotations){
  1297. this.visibleAnnotations = new Set();
  1298. }
  1299. this.scene.annotations.updateBounds();
  1300. this.scene.cameraP.updateMatrixWorld();
  1301. this.scene.cameraO.updateMatrixWorld();
  1302. let distances = [];
  1303. let renderAreaSize = this.renderer.getSize(new THREE.Vector2());
  1304. let viewer = this;
  1305. let visibleNow = [];
  1306. this.scene.annotations.traverse(annotation => {
  1307. if (annotation === this.scene.annotations) {
  1308. return true;
  1309. }
  1310. if (!annotation.visible) {
  1311. return false;
  1312. }
  1313. annotation.scene = this.scene;
  1314. let element = annotation.domElement;
  1315. let position = annotation.position.clone();
  1316. position.add(annotation.offset);
  1317. if (!position) {
  1318. position = annotation.boundingBox.getCenter(new THREE.Vector3());
  1319. }
  1320. let distance = viewer.scene.cameraP.position.distanceTo(position);
  1321. let radius = annotation.boundingBox.getBoundingSphere(new THREE.Sphere()).radius;
  1322. let screenPos = new THREE.Vector3();
  1323. let screenSize = 0;
  1324. {
  1325. // SCREEN POS
  1326. screenPos.copy(position).project(this.scene.getActiveCamera());
  1327. screenPos.x = renderAreaSize.x * (screenPos.x + 1) / 2;
  1328. screenPos.y = renderAreaSize.y * (1 - (screenPos.y + 1) / 2);
  1329. // SCREEN SIZE
  1330. if(viewer.scene.cameraMode == CameraMode.PERSPECTIVE) {
  1331. let fov = Math.PI * viewer.scene.cameraP.fov / 180;
  1332. let slope = Math.tan(fov / 2.0);
  1333. let projFactor = 0.5 * renderAreaSize.y / (slope * distance);
  1334. screenSize = radius * projFactor;
  1335. } else {
  1336. screenSize = Utils.projectedRadiusOrtho(radius, viewer.scene.cameraO.projectionMatrix, renderAreaSize.x, renderAreaSize.y);
  1337. }
  1338. }
  1339. element.css("left", screenPos.x + "px");
  1340. element.css("top", screenPos.y + "px");
  1341. //element.css("display", "block");
  1342. let zIndex = 10000000 - distance * (10000000 / this.scene.cameraP.far);
  1343. if(annotation.descriptionVisible){
  1344. zIndex += 10000000;
  1345. }
  1346. element.css("z-index", parseInt(zIndex));
  1347. if(annotation.children.length > 0){
  1348. let expand = screenSize > annotation.collapseThreshold || annotation.boundingBox.containsPoint(this.scene.getActiveCamera().position);
  1349. annotation.expand = expand;
  1350. if (!expand) {
  1351. //annotation.display = (screenPos.z >= -1 && screenPos.z <= 1);
  1352. let inFrustum = (screenPos.z >= -1 && screenPos.z <= 1);
  1353. if(inFrustum){
  1354. visibleNow.push(annotation);
  1355. }
  1356. }
  1357. return expand;
  1358. } else {
  1359. //annotation.display = (screenPos.z >= -1 && screenPos.z <= 1);
  1360. let inFrustum = (screenPos.z >= -1 && screenPos.z <= 1);
  1361. if(inFrustum){
  1362. visibleNow.push(annotation);
  1363. }
  1364. }
  1365. });
  1366. let notVisibleAnymore = new Set(this.visibleAnnotations);
  1367. for(let annotation of visibleNow){
  1368. annotation.display = true;
  1369. notVisibleAnymore.delete(annotation);
  1370. }
  1371. this.visibleAnnotations = visibleNow;
  1372. for(let annotation of notVisibleAnymore){
  1373. annotation.display = false;
  1374. }
  1375. }
  1376. updateMaterialDefaults(pointcloud){
  1377. // PROBLEM STATEMENT:
  1378. // * [min, max] of intensity, source id, etc. are computed as point clouds are loaded
  1379. // * the point cloud material won't know the range it should use until some data is loaded
  1380. // * users can modify the range at runtime, but sensible default ranges should be
  1381. // applied even if no GUI is present
  1382. // * display ranges shouldn't suddenly change even if the actual range changes over time.
  1383. // e.g. the root node has intensity range [1, 478]. One of the descendants increases range to
  1384. // [0, 2047]. We should not automatically change to the new range because that would result
  1385. // in sudden and drastic changes of brightness. We should adjust the min/max of the sidebar slider.
  1386. const material = pointcloud.material;
  1387. const attIntensity = pointcloud.getAttribute("intensity");
  1388. if(attIntensity != null && material.intensityRange[0] === Infinity){
  1389. material.intensityRange = [...attIntensity.range];
  1390. }
  1391. // const attIntensity = pointcloud.getAttribute("intensity");
  1392. // if(attIntensity && material.intensityRange[0] === Infinity){
  1393. // material.intensityRange = [...attIntensity.range];
  1394. // }
  1395. // let attributes = pointcloud.getAttributes();
  1396. // for(let attribute of attributes.attributes){
  1397. // if(attribute.range){
  1398. // let range = [...attribute.range];
  1399. // material.computedRange.set(attribute.name, range);
  1400. // //material.setRange(attribute.name, range);
  1401. // }
  1402. // }
  1403. }
  1404. update(delta, timestamp){
  1405. if(Potree.measureTimings) performance.mark("update-start");
  1406. this.dispatchEvent({
  1407. type: 'update_start',
  1408. delta: delta,
  1409. timestamp: timestamp});
  1410. this.updateScreenSize() //判断是否改变canvas大小
  1411. const scene = this.scene;
  1412. const camera = scene.getActiveCamera();
  1413. const visiblePointClouds = this.scene.pointclouds.filter(pc => pc.visible)
  1414. Potree.pointLoadLimit = Potree.pointBudget * 2;
  1415. const lTarget = camera.position.clone().add(camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(1000));
  1416. this.scene.directionalLight.position.copy(camera.position);
  1417. this.scene.directionalLight.lookAt(lTarget);
  1418. for (let pointcloud of visiblePointClouds) {
  1419. pointcloud.showBoundingBox = this.showBoundingBox;
  1420. pointcloud.generateDEM = this.generateDEM;
  1421. pointcloud.minimumNodePixelSize = this.minNodeSize;
  1422. let material = pointcloud.material;
  1423. material.uniforms.uFilterReturnNumberRange.value = this.filterReturnNumberRange;
  1424. material.uniforms.uFilterNumberOfReturnsRange.value = this.filterNumberOfReturnsRange;
  1425. material.uniforms.uFilterGPSTimeClipRange.value = this.filterGPSTimeRange;
  1426. material.uniforms.uFilterPointSourceIDClipRange.value = this.filterPointSourceIDRange;
  1427. material.classification = this.classifications;
  1428. material.recomputeClassification();
  1429. this.updateMaterialDefaults(pointcloud);
  1430. }
  1431. {
  1432. if(this.showBoundingBox){
  1433. let bbRoot = this.scene.scene.getObjectByName("potree_bounding_box_root");
  1434. if(!bbRoot){
  1435. let node = new THREE.Object3D();
  1436. node.name = "potree_bounding_box_root";
  1437. this.scene.scene.add(node);
  1438. bbRoot = node;
  1439. }
  1440. let visibleBoxes = [];
  1441. for(let pointcloud of this.scene.pointclouds){
  1442. for(let node of pointcloud.visibleNodes.filter(vn => vn.boundingBoxNode !== undefined)){
  1443. let box = node.boundingBoxNode;
  1444. visibleBoxes.push(box);
  1445. }
  1446. }
  1447. bbRoot.children = visibleBoxes;
  1448. }
  1449. }
  1450. if (!this.freeze) {
  1451. /*let cameraGroup = []
  1452. let size = this.renderer.getSize(new THREE.Vector2())
  1453. if(this.viewports){
  1454. this.viewports.forEach(viewport=>{
  1455. if(!viewport.active)return
  1456. cameraGroup.push({camera:viewport.camera, areaSize:new THREE.Vector2(Math.floor(size.x * viewport.width), Math.floor(size.y * viewport.height))})
  1457. })
  1458. }else{
  1459. cameraGroup.push({camera, areaSize:size})
  1460. }
  1461. let result = Potree.updatePointClouds(scene.pointclouds, cameraGroup );
  1462. */
  1463. // DEBUG - ONLY DISPLAY NODES THAT INTERSECT MOUSE
  1464. //if(false){
  1465. // let renderer = viewer.renderer;
  1466. // let mouse = viewer.inputHandler.mouse;
  1467. // let nmouse = {
  1468. // x: (mouse.x / renderer.domElement.clientWidth) * 2 - 1,
  1469. // y: -(mouse.y / renderer.domElement.clientHeight) * 2 + 1
  1470. // };
  1471. // let pickParams = {};
  1472. // //if(params.pickClipped){
  1473. // // pickParams.pickClipped = params.pickClipped;
  1474. // //}
  1475. // pickParams.x = mouse.x;
  1476. // pickParams.y = renderer.domElement.clientHeight - mouse.y;
  1477. // let raycaster = new THREE.Raycaster();
  1478. // raycaster.setFromCamera(nmouse, camera);
  1479. // let ray = raycaster.ray;
  1480. // for(let pointcloud of scene.pointclouds){
  1481. // let nodes = pointcloud.nodesOnRay(pointcloud.visibleNodes, ray);
  1482. // pointcloud.visibleNodes = nodes;
  1483. // }
  1484. //}
  1485. // const tStart = performance.now();
  1486. // const worldPos = new THREE.Vector3();
  1487. // const camPos = viewer.scene.getActiveCamera().getWorldPosition(new THREE.Vector3());
  1488. // let lowestDistance = Infinity;
  1489. // let numNodes = 0;
  1490. // viewer.scene.scene.traverse(node => {
  1491. // node.getWorldPosition(worldPos);
  1492. // const distance = worldPos.distanceTo(camPos);
  1493. // lowestDistance = Math.min(lowestDistance, distance);
  1494. // numNodes++;
  1495. // if(Number.isNaN(distance)){
  1496. // console.error(":(");
  1497. // }
  1498. // });
  1499. // const duration = (performance.now() - tStart).toFixed(2);
  1500. // Potree.debug.computeNearDuration = duration;
  1501. // Potree.debug.numNodes = numNodes;
  1502. //console.log(lowestDistance.toString(2), duration);
  1503. //搬走
  1504. /* const tStart = performance.now();
  1505. const campos = camera.position;
  1506. let closestImage = Infinity;
  1507. for(const images of this.scene.orientedImages){
  1508. for(const image of images.images){
  1509. const distance = image.mesh.position.distanceTo(campos);
  1510. closestImage = Math.min(closestImage, distance);
  1511. }
  1512. }
  1513. const tEnd = performance.now();
  1514. if(result.lowestSpacing !== Infinity){
  1515. let near = result.lowestSpacing * 10.0;
  1516. let far = -this.getBoundingBox().applyMatrix4(camera.matrixWorldInverse).min.z;
  1517. far = Math.max(far * 1.5, 10000);
  1518. near = Math.min(100.0, Math.max(0.01, near));
  1519. near = Math.min(near, closestImage);
  1520. far = Math.max(far, near + 10000);
  1521. if(near === Infinity){
  1522. near = 0.1;
  1523. }
  1524. camera.near = near;
  1525. camera.far = far;
  1526. }else{
  1527. // don't change near and far in this case
  1528. }
  1529. if(this.scene.cameraMode == CameraMode.ORTHOGRAPHIC) {
  1530. camera.near = -camera.far;
  1531. }*/
  1532. }
  1533. this.scene.cameraP.fov = this.fov;
  1534. let controls = this.getControls();
  1535. if (controls === this.deviceControls) {
  1536. this.controls.setScene(scene);
  1537. this.controls.update(delta);
  1538. this.scene.cameraP.position.copy(scene.view.position);
  1539. this.scene.cameraO.position.copy(scene.view.position);
  1540. } else if (controls !== null) {
  1541. controls.setScene(scene);
  1542. controls.update(delta);
  1543. //更新camera
  1544. this.viewports.forEach(viewport=>{
  1545. if(!viewport.active)return
  1546. viewport.view.applyToCamera(viewport.camera)
  1547. })
  1548. }
  1549. /* this.viewports.forEach(e=>{//判断camera画面是否改变
  1550. if(e.cameraChanged()){
  1551. this.dispatchEvent({
  1552. type: "camera_changed",
  1553. camera: e.camera,
  1554. viewport : e
  1555. })
  1556. }
  1557. }) */
  1558. this.cameraChanged()//判断camera画面是否改变
  1559. /* {//判断camera画面是否改变
  1560. if(this._previousCamera === undefined){
  1561. this._previousCamera = this.scene.getActiveCamera().clone();
  1562. this._previousCamera.rotation.copy(this.scene.getActiveCamera().rotation);
  1563. }
  1564. if(!this._previousCamera.matrixWorld.equals(camera.matrixWorld) ||
  1565. !this._previousCamera.projectionMatrix.equals(camera.projectionMatrix)
  1566. ){
  1567. this.dispatchEvent({
  1568. type: "camera_changed",
  1569. previous: this._previousCamera,
  1570. camera: camera
  1571. });
  1572. }
  1573. this._previousCamera = this.scene.getActiveCamera().clone();
  1574. this._previousCamera.rotation.copy(this.scene.getActiveCamera().rotation);
  1575. } */
  1576. { // update clip boxes
  1577. let boxes = [];
  1578. // volumes with clipping enabled
  1579. //boxes.push(...this.scene.volumes.filter(v => (v.clip)));
  1580. boxes.push(...this.scene.volumes.filter(v => (v.clip && v instanceof BoxVolume)));
  1581. // profile segments
  1582. for(let profile of this.scene.profiles){
  1583. boxes.push(...profile.boxes);
  1584. }
  1585. // Needed for .getInverse(), pre-empt a determinant of 0, see #815 / #816
  1586. let degenerate = (box) => box.matrixWorld.determinant() !== 0;
  1587. let clipBoxes = boxes.filter(degenerate).map( box => {
  1588. box.updateMatrixWorld();
  1589. let boxInverse = box.matrixWorld.clone().invert();
  1590. let boxPosition = box.getWorldPosition(new THREE.Vector3());
  1591. return {box: box, inverse: boxInverse, position: boxPosition};
  1592. });
  1593. let clipPolygons = this.scene.polygonClipVolumes.filter(vol => vol.initialized);
  1594. // set clip volumes in material
  1595. for(let pointcloud of visiblePointClouds){
  1596. pointcloud.material.setClipBoxes(clipBoxes);
  1597. pointcloud.material.setClipPolygons(clipPolygons, this.clippingTool.maxPolygonVertices);
  1598. pointcloud.material.clipTask = this.clipTask;
  1599. pointcloud.material.clipMethod = this.clipMethod;
  1600. }
  1601. }
  1602. {
  1603. for(let pointcloud of visiblePointClouds){
  1604. pointcloud.material.elevationGradientRepeat = this.elevationGradientRepeat;
  1605. }
  1606. }
  1607. { // update navigation cube
  1608. this.navigationCube.update(camera.rotation);
  1609. }
  1610. this.updateAnnotations();
  1611. if(this.mapView){
  1612. this.mapView.update(delta);
  1613. if(this.mapView.sceneProjection){
  1614. $( "#potree_map_toggle" ).css("display", "block");
  1615. }
  1616. }
  1617. TWEEN.update(timestamp);
  1618. transitions.update(delta);
  1619. this.transformationTool.update();
  1620. this.modules.ParticleEditor.update(delta)
  1621. this.dispatchEvent({
  1622. type: 'update',
  1623. delta: delta,
  1624. timestamp: timestamp});
  1625. if(Potree.measureTimings) {
  1626. performance.mark("update-end");
  1627. performance.measure("update", "update-start", "update-end");
  1628. }
  1629. //add ------
  1630. this.reticule.updateVisible()
  1631. this.mapViewer.update(delta)
  1632. }
  1633. updateViewPointcloud(camera, areaSize, isViewport){
  1634. let result = Potree.updatePointClouds(this.scene.pointclouds, camera, areaSize );
  1635. //if(isViewport)return
  1636. const tStart = performance.now();
  1637. const campos = camera.position;
  1638. let closestImage = Infinity;
  1639. for(const images of this.scene.orientedImages){
  1640. for(const image of images.images){
  1641. const distance = image.mesh.position.distanceTo(campos);
  1642. closestImage = Math.min(closestImage, distance);
  1643. }
  1644. }
  1645. const tEnd = performance.now();
  1646. //改:不根据点云修改视野near far
  1647. var near = camera.near, far = camera.far
  1648. if(!camera.limitFar && result.lowestSpacing !== Infinity){
  1649. //let near = result.lowestSpacing * 10.0;
  1650. let far = -this.getBoundingBox().applyMatrix4(camera.matrixWorldInverse).min.z;
  1651. far = Math.max(far * 1.5, 10000);
  1652. //near = Math.min(100.0, Math.max(0.01, near));
  1653. //near = Math.min(near, closestImage);
  1654. far = Math.max(far, near + 10000);
  1655. /* if(near === Infinity){
  1656. near = 0.1;
  1657. } */
  1658. //camera.near = near; //为了其他物体的显示,不修改near
  1659. camera.far = far;
  1660. }
  1661. /* if(this.scene.cameraMode == CameraMode.ORTHOGRAPHIC) {//???
  1662. camera.near = -camera.far;
  1663. } */
  1664. if(/* near != camera.near || */far != camera.far){
  1665. camera.updateProjectionMatrix()
  1666. }
  1667. //注:pointcloud.visibleNodes会随着near far自动更新
  1668. }
  1669. getPRenderer(){
  1670. if(this.useHQ){
  1671. if (!this.hqRenderer) {
  1672. this.hqRenderer = new HQSplatRenderer(this);
  1673. }
  1674. this.hqRenderer.useEDL = this.useEDL;
  1675. return this.hqRenderer;
  1676. }else{
  1677. /* if (this.useEDL && Features.SHADER_EDL.isSupported()) {
  1678. if (!this.edlRenderer) {
  1679. this.edlRenderer = new EDLRenderer(this);
  1680. }
  1681. return this.edlRenderer;
  1682. } else {
  1683. if (!this.potreeRenderer) {
  1684. this.potreeRenderer = new PotreeRenderer(this);
  1685. }
  1686. return this.potreeRenderer;
  1687. } */
  1688. if (!this.edlRenderer) {
  1689. this.edlRenderer = new EDLRenderer(this);
  1690. }
  1691. return this.edlRenderer;
  1692. }
  1693. }
  1694. renderVR(){
  1695. let renderer = this.renderer;
  1696. renderer.setClearColor(0x550000, 0);
  1697. renderer.clear();
  1698. let xr = renderer.xr;
  1699. let dbg = new THREE.PerspectiveCamera();
  1700. let xrCameras = xr.getCamera(dbg);
  1701. if(xrCameras.cameras.length !== 2){
  1702. return;
  1703. }
  1704. let makeCam = this.vrControls.getCamera.bind(this.vrControls);
  1705. { // clear framebuffer
  1706. if(viewer.background === "skybox"){
  1707. renderer.setClearColor(0xff0000, 1);
  1708. }else if(viewer.background === "gradient"){
  1709. renderer.setClearColor(0x112233, 1);
  1710. }else if(viewer.background === "black"){
  1711. renderer.setClearColor(0x000000, 1);
  1712. }else if(viewer.background === "white"){
  1713. renderer.setClearColor(0xFFFFFF, 1);
  1714. }else{
  1715. renderer.setClearColor(0x000000, 0);
  1716. }
  1717. renderer.clear();
  1718. }
  1719. // render background
  1720. if(this.background === "skybox"){
  1721. let {skybox} = this;
  1722. let cam = makeCam();
  1723. skybox.camera.rotation.copy(cam.rotation);
  1724. skybox.camera.fov = cam.fov;
  1725. skybox.camera.aspect = cam.aspect;
  1726. // let dbg = new THREE.Object3D();
  1727. let dbg = skybox.parent;
  1728. // dbg.up.set(0, 0, 1);
  1729. dbg.rotation.x = Math.PI / 2;
  1730. // skybox.camera.parent = dbg;
  1731. // dbg.children.push(skybox.camera);
  1732. dbg.updateMatrix();
  1733. dbg.updateMatrixWorld();
  1734. skybox.camera.updateMatrix();
  1735. skybox.camera.updateMatrixWorld();
  1736. skybox.camera.updateProjectionMatrix();
  1737. renderer.render(skybox.scene, skybox.camera);
  1738. // renderer.render(skybox.scene, cam);
  1739. }else if(this.background === "gradient"){
  1740. // renderer.render(this.scene.sceneBG, this.scene.cameraBG);
  1741. }
  1742. this.renderer.xr.getSession().updateRenderState({
  1743. depthNear: 0.1,
  1744. depthFar: 10000
  1745. });
  1746. let cam = null;
  1747. let view = null;
  1748. { // render world scene
  1749. cam = makeCam();
  1750. cam.position.z -= 0.8 * cam.scale.x;
  1751. cam.parent = null;
  1752. // cam.near = 0.05;
  1753. cam.near = viewer.scene.getActiveCamera().near;
  1754. cam.far = viewer.scene.getActiveCamera().far;
  1755. cam.updateMatrix();
  1756. cam.updateMatrixWorld();
  1757. this.scene.scene.updateMatrix();
  1758. this.scene.scene.updateMatrixWorld();
  1759. this.scene.scene.matrixAutoUpdate = false;
  1760. let camWorld = cam.matrixWorld.clone();
  1761. view = camWorld.clone().invert();
  1762. this.scene.scene.matrix.copy(view);
  1763. this.scene.scene.matrixWorld.copy(view);
  1764. cam.matrix.identity();
  1765. cam.matrixWorld.identity();
  1766. cam.matrixWorldInverse.identity();
  1767. renderer.render(this.scene.scene, cam);
  1768. this.scene.scene.matrixWorld.identity();
  1769. }
  1770. for(let pointcloud of this.scene.pointclouds){
  1771. let viewport = xrCameras.cameras[0].viewport;
  1772. pointcloud.material.useEDL = false;
  1773. pointcloud.screenHeight = viewport.height;
  1774. pointcloud.screenWidth = viewport.width;
  1775. // automatically switch to paraboloids because they cause far less flickering in VR,
  1776. // when point sizes are larger than around 2 pixels
  1777. // if(Features.SHADER_INTERPOLATION.isSupported()){
  1778. // pointcloud.material.shape = Potree.PointShape.PARABOLOID;
  1779. // }
  1780. }
  1781. // render point clouds
  1782. for(let xrCamera of xrCameras.cameras){
  1783. let v = xrCamera.viewport;
  1784. renderer.setViewport(v.x, v.y, v.width, v.height);
  1785. // xrCamera.fov = 90;
  1786. { // estimate VR fov
  1787. let proj = xrCamera.projectionMatrix;
  1788. let inv = proj.clone().invert();
  1789. let p1 = new THREE.Vector4(0, 1, -1, 1).applyMatrix4(inv);
  1790. let rad = p1.y
  1791. let fov = 180 * (rad / Math.PI);
  1792. xrCamera.fov = fov;
  1793. }
  1794. for(let pointcloud of this.scene.pointclouds){
  1795. const {material} = pointcloud;
  1796. material.useEDL = false;
  1797. }
  1798. let vrWorld = view.clone().invert();
  1799. vrWorld.multiply(xrCamera.matrixWorld);
  1800. let vrView = vrWorld.clone().invert();
  1801. this.pRenderer.render(this.scene.scenePointCloud, xrCamera, null, {
  1802. viewOverride: vrView,
  1803. });
  1804. }
  1805. { // render VR scene
  1806. let cam = makeCam();
  1807. cam.parent = null;
  1808. renderer.render(this.sceneVR, cam);
  1809. }
  1810. renderer.resetState();
  1811. }
  1812. clear(params={}){
  1813. let background = params.background || this.background;
  1814. let backgroundOpacity = params.backgroundOpacity == void 0 ? this.backgroundOpacity : params.backgroundOpacity//如果想完全透明,只需要backgroundOpacity为0
  1815. let renderer = this.renderer
  1816. //let gl = renderer.getContext()
  1817. if(background instanceof THREE.Color){ //add
  1818. renderer.setClearColor(background, backgroundOpacity);
  1819. }else if(background === "skybox"){
  1820. renderer.setClearColor(0x000000, 0);
  1821. } else if (background === 'gradient') {
  1822. renderer.setClearColor(0x000000, 0);
  1823. } else if (background === 'black') {
  1824. renderer.setClearColor(0x000000, 1);
  1825. } else if (background === 'white') {
  1826. renderer.setClearColor(0xFFFFFF, 1);
  1827. } else {
  1828. renderer.setClearColor(background, backgroundOpacity);
  1829. }
  1830. params.target || renderer.clear();
  1831. }
  1832. renderDefault(params_={}){
  1833. if(!this.visible || this.paused )return
  1834. let pRenderer = this.getPRenderer();
  1835. let renderSize
  1836. if(params_.target){
  1837. renderSize = new THREE.Vector2(params_.target.width, params_.target.height)
  1838. if(!params_.viewports){
  1839. console.warn('必须指定target的viewport! 且target大小和viewport.resolution2相同')
  1840. }
  1841. }else{
  1842. renderSize = this.renderer.getSize(new THREE.Vector2());
  1843. }
  1844. var viewports = params_.viewports || this.viewports
  1845. let needSResize = viewports.filter(e=>e.active).length > 1 || params_.resize
  1846. viewports.forEach(view=>{
  1847. let params = $.extend({},params_);
  1848. params.viewport = view
  1849. //if(!params.target){
  1850. params.camera = params.camera || view.camera;
  1851. params.extraEnableLayers = view.extraEnableLayers
  1852. params.cameraLayers = view.cameraLayers
  1853. //}
  1854. if(!view.active)return
  1855. var left,bottom,width,height
  1856. {
  1857. left = Math.floor(renderSize.x * view.left)
  1858. bottom = Math.floor(renderSize.y * view.bottom)
  1859. /* if(params_.target){//有target时最好viewport是专门建出来的
  1860. width = Math.floor(renderSize.x * view.width)
  1861. height = Math.floor(renderSize.y * view.height)
  1862. }else{ */
  1863. width = view.resolution.x // 用的是client的width和height
  1864. height = view.resolution.y
  1865. //}
  1866. if(width == 0 || height == 0)return
  1867. let scissorTest = view.width<1 || view.height<1
  1868. if(params_.target){
  1869. params_.target.viewport.set(left, bottom, width, height);
  1870. scissorTest && params_.target.scissor.set(left, bottom, width, height);
  1871. params_.target.scissorTest = scissorTest
  1872. }else{
  1873. this.renderer.setViewport(left, bottom, width, height) //规定视口,影响图形变换
  1874. scissorTest && this.renderer.setScissor( left, bottom, width, height );//规定渲染范围
  1875. this.renderer.setScissorTest( scissorTest );//开启WebGL剪裁测试功能,如果不开启,.setScissor方法设置的范围不起作用 | width==1且height==1时开启会只有鼠标的地方刷新,很奇怪
  1876. }
  1877. }
  1878. if(needSResize){
  1879. this.emitResizeMsg( { viewport:view} )
  1880. }
  1881. //needSResize && this.emitResizeMsg({resolution: params_.target ? new THREE.Vector2(width,height) : view.resolution2, left:view.left, bottom:view.bottom })//resize everything such as lines targets
  1882. viewer.dispatchEvent({type: "render.begin", viewer: viewer, viewport:view, params });
  1883. if(view.render){
  1884. view.render({
  1885. target: params_.target, renderer:this.renderer, clear:this.clear.bind(this),
  1886. renderOverlay: this.renderOverlay.bind(this), force:!view.noPointcloud //如果要渲染点云,必须也一直渲染地图,否则地图会被覆盖(点云目前未能获取是否改变,也可能有其他动态物体,所以还是一直渲染的好)
  1887. })
  1888. }
  1889. if(!view.noPointcloud ){
  1890. //if(!params.target){
  1891. //params.width = width; params.height = height;
  1892. //}
  1893. if(view.render){
  1894. params.noBG = true
  1895. }
  1896. view.beforeRender && view.beforeRender(view)
  1897. this.updateViewPointcloud(params.camera, view.resolution2, true)
  1898. params.background = view.background
  1899. params.backgroundColor = view.backgroundColor
  1900. params.backgroundOpacity = view.backgroundOpacity
  1901. view.render || this.clear(params)
  1902. pRenderer.clearTargets(params);
  1903. pRenderer.render(params);
  1904. {//渲染和地图共有的物体
  1905. this.setCameraLayers(params.camera, [ 'bothMapAndScene' ] )
  1906. this.renderer.render(this.scene.scene, params.camera);
  1907. }
  1908. this.renderOverlay(params)
  1909. view.afterRender && view.afterRender(view)
  1910. }
  1911. this.dispatchEvent({type: "render.end", viewer: this, viewport:view });
  1912. })
  1913. this.renderer.setRenderTarget(null)
  1914. }
  1915. setLimitFar(state){//切换是否limitFar
  1916. viewer.mainViewport.camera.limitFar = !!state
  1917. if(state){
  1918. viewer.mainViewport.camera.near = 0.1;
  1919. viewer.mainViewport.camera.far = Potree.settings.displayMode == 'showPanos' ? viewer.farWhenShowPano : Potree.settings.cameraFar;
  1920. viewer.mainViewport.camera.updateProjectionMatrix()
  1921. }
  1922. }
  1923. renderOverlay(params){
  1924. let camera = params.camera ? params.camera : this.scene.getActiveCamera();
  1925. this.reticule.updateAtViewports(params.viewport)
  1926. //为什么要在点云之后渲染,否则透明失效 、 会被点云覆盖
  1927. let cameraLayers
  1928. if(params.cameraLayers) cameraLayers = params.cameraLayers
  1929. else{
  1930. if(params.isMap)cameraLayers = ['reticule']
  1931. else cameraLayers = ['sceneObjects','marker','reticule' /* 'bothMapAndScene' */];
  1932. }
  1933. if(cameraLayers.length){
  1934. this.setCameraLayers(camera, cameraLayers, params.extraEnableLayers) //透明贴图层 skybox 、reticule marker 不能遮住测量线
  1935. this.renderer.render(this.scene.scene, camera);
  1936. }
  1937. this.dispatchEvent({type: "render.pass.scene", viewer: viewer});
  1938. //清除深度 !!!!
  1939. this.renderer.clearDepth();
  1940. //this.transformationTool.update();
  1941. if(!params.magnifier){
  1942. //测量线
  1943. this.dispatchEvent({type: "render.pass.perspective_overlay", camera});
  1944. if(!params.screenshot && !params.isMap){
  1945. this.setCameraLayers(camera, ['magnifier']) //magnifier 遮住测量线
  1946. this.renderer.render(this.scene.scene, camera);
  1947. }
  1948. }
  1949. this.setCameraLayers(camera, ['volume','transformationTool'])
  1950. this.renderer.render(this.clippingTool.sceneVolume, camera);
  1951. this.renderer.render(this.transformationTool.scene, camera);
  1952. }
  1953. setCameraLayers(camera, enableLayers, extraEnableLayers=[]){//add
  1954. camera.layers.disableAll()
  1955. enableLayers.concat(extraEnableLayers).forEach(e=>{
  1956. let layer = Potree.config.renderLayers[e]
  1957. if(layer == void 0){
  1958. console.error('setCameraLayer没找到layer!');
  1959. return
  1960. }
  1961. camera.layers.enable(layer)
  1962. })
  1963. }
  1964. setObjectLayers(object, layerName){//add
  1965. let layer = Potree.config.renderLayers[layerName]
  1966. if(layer == void 0){
  1967. console.error('setCameraLayer没找到layer!');
  1968. return
  1969. }
  1970. object.traverse(e=>{
  1971. e.layers.set(layer)
  1972. })
  1973. }
  1974. updateVisible(object, reason, ifShow){//当所有加入的条件都不为false时才显示. reason='force'一般是强制、临时的
  1975. if(!object.unvisibleReasons) object.unvisibleReasons = []; //如果length>0代表不可见
  1976. /* let mapChange = ()=>{//还是算了,有时候可见性的改变 在mapViewer和mainViewer中交替,如reticule,就会频繁
  1977. var layers = ['measure','map','mapObjects','bothMapAndScene']
  1978. if(layers.some(e=> object.layers && (object.layers.mask == Potree.config.renderLayers[e]) )) {
  1979. this.mapViewer.dispatchEvent({type:'content_changed'})
  1980. }
  1981. } */
  1982. if(ifShow){
  1983. var index = object.unvisibleReasons.indexOf(reason)
  1984. if(index > -1){
  1985. object.unvisibleReasons.splice(index, 1);
  1986. if(object.unvisibleReasons.length == 0){
  1987. object.visible = true;
  1988. //mapChange()
  1989. object.dispatchEvent({
  1990. type: 'isVisible',
  1991. visible:true,
  1992. reason
  1993. })
  1994. }
  1995. }
  1996. }else{
  1997. var visiBefore = object.visible
  1998. if(!object.unvisibleReasons.includes(reason)) object.unvisibleReasons.push(reason)
  1999. object.visible = false
  2000. if(visiBefore) {
  2001. //mapChange()
  2002. object.dispatchEvent({
  2003. type: 'isVisible',
  2004. visible:false,
  2005. reason,
  2006. })
  2007. }
  2008. }
  2009. }
  2010. getObjVisiByReason(object,reason){//获取在某条件下是否可见. 注: 用户在数据集选择可不可见为"datasetSelection"
  2011. if(object.visible)return true
  2012. else{
  2013. return !object.unvisibleReasons || !object.unvisibleReasons.includes(reason)
  2014. }
  2015. }
  2016. /* 大规模WebGL应用引发浏览器崩溃的几种情况及解决办法
  2017. https://blog.csdn.net/weixin_30378311/article/details/94846947 */
  2018. render(params){//add params
  2019. if(Potree.measureTimings) performance.mark("render-start");
  2020. // if(!window.unableSetSize) return
  2021. //try{
  2022. //console.log('rendering')//在unfocus页面时就会停止渲染
  2023. const vrActive = this.renderer.xr.isPresenting;
  2024. if(vrActive){
  2025. this.renderVR();
  2026. }else{
  2027. this.renderDefault(params);
  2028. }
  2029. /* }catch(e){
  2030. this.onCrash(e);
  2031. } */
  2032. if(Potree.measureTimings){
  2033. performance.mark("render-end");
  2034. performance.measure("render", "render-start", "render-end");
  2035. }
  2036. }
  2037. startScreenshot(info={}, width=800, height=400, compressRatio){//add
  2038. let deferred = info.deferred || $.Deferred();
  2039. if(this.images360.flying){//如果在飞,飞完再截图
  2040. info.deferred = deferred
  2041. this.images360.once('cameraMoveDone', this.startScreenshot.bind(this, info, width, height, compressRatio))
  2042. return deferred.promise()
  2043. }
  2044. var sid = Date.now()
  2045. //抗锯齿待加 1 post处理 2截图大张再抗锯齿缩小
  2046. console.log('startScreenshot: '+sid)
  2047. var screenshot = ()=>{
  2048. viewer.mapViewer.needRender = true
  2049. var { buffer } = this.makeScreenshot( new THREE.Vector2(width,height) );
  2050. var dataUrl = Potree.Utils.pixelsArrayToDataUrl(buffer, width, height, compressRatio)
  2051. if(!Potree.settings.isOfficial){
  2052. Common.downloadFile(dataUrl, 'screenshot.jpg')
  2053. }
  2054. var finish = ()=>{
  2055. deferred.resolve(dataUrl)
  2056. console.log('screenshot done: '+sid)
  2057. }
  2058. {//恢复:
  2059. if(info.type == 'measure'){
  2060. this.scene.measurements.forEach(e=>this.updateVisible(e, 'screenshot',true))
  2061. info.measurement.setSelected(false, 'screenshot')
  2062. }
  2063. this.images360.panos.forEach(pano=>{
  2064. viewer.updateVisible(pano, 'screenshot', true)
  2065. })
  2066. viewer.updateVisible(this.reticule, 'screenshot', true)
  2067. viewer.updateVisible(this.mapViewer.cursor, 'screenshot', true)
  2068. if(oldStates.attachedToViewer != this.mapViewer.attachedToViewer){
  2069. if(info.type == 'measure'){
  2070. this.mapViewer.attachToMainViewer(false )
  2071. }
  2072. }
  2073. mapViewport.camera.zoom = oldStates.mapZoom
  2074. mapViewport.camera.updateProjectionMatrix()
  2075. if(Potree.settings.displayMode == 'showPanos') {
  2076. viewer.images360.flyToPano({pano:oldStates.pano, duration:0, callback:()=>{
  2077. finish()
  2078. }})
  2079. }
  2080. oldStates.viewports.forEach(old=>{//恢复相机
  2081. var viewport = [mapViewport, mainViewport].find(v=>v.name == old.name);
  2082. viewport.left = old.left;
  2083. viewport.width = old.width;
  2084. viewport.view.copy(old.view)
  2085. viewport.view.applyToCamera(viewport.camera);
  2086. })
  2087. viewer.updateScreenSize({forceUpdateSize:true})//更新像素
  2088. oldStates.viewports.forEach(old=>{//恢复相机
  2089. var viewport = [mapViewport, mainViewport].find(v=>v.name == old.name);
  2090. this.dispatchEvent({ //update map
  2091. type: "camera_changed",
  2092. camera: viewport.camera,
  2093. viewport : viewport
  2094. })
  2095. })
  2096. }
  2097. if(Potree.settings.displayMode != 'showPanos') {
  2098. finish()
  2099. }
  2100. }
  2101. let mapViewport = this.mapViewer.viewports[0]
  2102. let mainViewport = this.mainViewport
  2103. let oldStates = {
  2104. attachedToViewer : this.mapViewer.attachedToViewer,
  2105. viewports : [mapViewport, mainViewport].map(e=>{
  2106. return e.clone()
  2107. }),
  2108. mapZoom: mapViewport.camera.zoom,
  2109. pano: Potree.settings.displayMode == 'showPanos' ? viewer.images360.currentPano : null,
  2110. }
  2111. this.images360.panos.forEach(pano=>{//令漫游点不可见
  2112. viewer.updateVisible(pano, 'screenshot', false)
  2113. })
  2114. viewer.updateVisible(this.reticule, 'screenshot', false)//令reticule不可见
  2115. viewer.updateVisible(this.mapViewer.cursor, 'screenshot', false)//令mapCursor不可见
  2116. if(info.type == 'measure'){//要截图双屏
  2117. this.scene.measurements.forEach(e=>this.updateVisible(e,'screenshot',e == info.measurement) )
  2118. info.measurement.setSelected(true, 'screenshot')
  2119. this.mapViewer.attachToMainViewer(true, 'measure', 0.5 )//不要移动相机去适应
  2120. viewer.updateScreenSize({forceUpdateSize:true, width, height}) //更新viewports相机透视
  2121. //不同角度截图 得到三维的会不一样,因为focusOnObject是根据方向的
  2122. let promise = this.focusOnObject(info.measurement, 'measure', 0, /* {basePanoSize:1024} */ )
  2123. promise.done(()=>{
  2124. console.log('promise.done')
  2125. this.viewports.forEach(e=>{
  2126. e.view.applyToCamera(e.camera)
  2127. this.dispatchEvent({ //update map
  2128. type: "camera_changed",
  2129. camera: e.camera,
  2130. viewport : e
  2131. })
  2132. })
  2133. let waitMap = ()=>{
  2134. console.log('waitMap: '+sid)
  2135. this.mapViewer.waitLoadDone(screenshot.bind(this))//等待地图所有加载完
  2136. }
  2137. /* if(Potree.settings.displayMode == 'showPanos'){//如果是全景图,要等全景的tile加载完
  2138. //this.images360.checkAndWaitForTiledPanoLoad(this.images360.currentPano, this.images360.qualityManager.standardSize, ()=>{//done
  2139. //loadTiledPano
  2140. if(!this.images360.checkAndWaitForPanoLoad(this.images360.currentPano, this.images360.qualityManager.standardSize, ()=>{//done
  2141. //standardSize maxNavPanoSize
  2142. waitMap()
  2143. })){
  2144. waitMap()
  2145. }
  2146. }else{
  2147. waitMap()
  2148. } */ //512就可以
  2149. //调不通,暂时先用setTimeout
  2150. setTimeout(waitMap.bind(this), 1)
  2151. })
  2152. }else{
  2153. screenshot()
  2154. }
  2155. return deferred.promise()
  2156. }
  2157. focusOnObject(object, type, duration, o={} ) {
  2158. //飞向热点、测量线等 。
  2159. console.log('focusOnObject: '+object.name, type)
  2160. let deferred = o.deferred || $.Deferred();
  2161. let target = new THREE.Vector3, //相机focus的位置
  2162. position = new THREE.Vector3, //相机最终位置
  2163. dis; //相机距离目标
  2164. duration = duration == void 0 ? 1000 : duration;
  2165. let camera = viewer.scene.getActiveCamera()
  2166. if(this.images360.modeChanging){
  2167. this.images360.once('endChangeMode',()=>{
  2168. this.focusOnObject(object, type, duration, $.extend(o,{deferred}))
  2169. })
  2170. return deferred.promise();//不能打扰 从点云转向全景图时 的飞行
  2171. }
  2172. if (type == 'measure') {
  2173. target.copy(object.getCenter())
  2174. var cameraTemp = camera.clone()
  2175. //试试改变位置,直视测量线。能避免倾斜角度造成的非常不居中、以及看不到面的情况
  2176. if(object.facePlane/* && window.focusMeasureFaceToIt */){
  2177. let normal
  2178. if(object.facePlane){
  2179. normal = object.facePlane.normal.clone()
  2180. }
  2181. let angle = this.scene.view.direction.angleTo(normal)
  2182. let minDiff = THREE.Math.degToRad(60)
  2183. if(angle>minDiff && angle<Math.PI-minDiff){//当几乎正对时就不执行
  2184. if(angle<Math.PI/2){ //在背面
  2185. normal.negate()
  2186. }
  2187. let dir = new THREE.Vector3().subVectors(camera.position, target).normalize()
  2188. let newDir = new THREE.Vector3().addVectors(dir,normal)//两个角度的中间
  2189. cameraTemp.position.copy(target.clone().add(newDir))
  2190. }
  2191. }else if(object.points.length == 2){ //线段
  2192. let lineDir = new THREE.Vector3().subVectors(object.points[0],object.points[1]).normalize()
  2193. let angle = this.scene.view.direction.angleTo(lineDir)
  2194. let maxDiff = Math.PI*0.25// 45度
  2195. if(angle<maxDiff || angle>Math.PI-maxDiff){//当几乎正对时就不执行
  2196. if(angle>Math.PI/2){ //令dir和lineDir成钝角
  2197. lineDir.negate()
  2198. }
  2199. let dir = new THREE.Vector3().subVectors(camera.position, target).normalize()
  2200. let mid = new THREE.Vector3().addVectors(lineDir, dir).normalize() //中间法向量(如果刚好dir和lineDir反向,那得到的为零向量,就不移动了,但一般不会酱紫吧)
  2201. let newDir = new THREE.Vector3().addVectors(dir, mid)
  2202. cameraTemp.position.copy(target.clone().add(newDir))
  2203. }
  2204. }else{
  2205. console.error('measure 没有facePlane points点数还不为2?')
  2206. }
  2207. cameraTemp.lookAt(target);
  2208. cameraTemp.updateMatrix();
  2209. cameraTemp.updateMatrixWorld();
  2210. //原始的bound
  2211. let boundOri = new THREE.Box3()
  2212. object.points.forEach(e=>{
  2213. boundOri.expandByPoint(e)
  2214. })
  2215. let boundSizeOri = boundOri.getSize(new THREE.Vector3)
  2216. //对镜头的bound
  2217. var inv = cameraTemp.matrixWorldInverse;
  2218. let bound = new THREE.Box3()
  2219. object.points.forEach(e=>{
  2220. var p = e.clone().applyMatrix4(inv);
  2221. bound.expandByPoint(p)
  2222. })
  2223. let boundSize = bound.getSize(new THREE.Vector3)
  2224. if(!this.boundBox){//调试
  2225. this.boundBox = new THREE.Mesh(new THREE.BoxGeometry(1,1,1,1));
  2226. this.boundBox.material.wireframe = true
  2227. this.boundBox.up.set(0,0,1)
  2228. this.boundBox.visible = false //打开以检查box
  2229. this.setObjectLayers(this.boundBox,'sceneObjects')
  2230. this.scene.scene.add(this.boundBox);
  2231. }
  2232. this.boundBox.position.copy(target)
  2233. this.boundBox.scale.copy(boundSize)
  2234. this.boundBox.lookAt(cameraTemp.position)
  2235. {
  2236. let scale = 1.1; //稍微放大一些,不然会靠到屏幕边缘
  2237. boundSize.x *= scale
  2238. boundSize.y *= scale
  2239. }
  2240. let aspect = boundSize.x / boundSize.y
  2241. if(camera.aspect > aspect){//视野更宽则用bound的纵向来决定
  2242. dis = boundSize.y/2/ Math.tan(THREE.Math.degToRad(camera.fov / 2)) + boundSize.z/2
  2243. }else{
  2244. let hfov = cameraLight.getHFOVForCamera(camera, true);
  2245. dis = boundSize.x/2 / Math.tan(hfov / 2) + boundSize.z/2
  2246. }
  2247. //三个顶点以上的由于measure的中心不等于bound的中心,所以点会超出bound外。 且由于视椎近大远小,即使是两个点的,bound居中后线看上去仍旧不居中.
  2248. if(this.mapViewer.attachedToViewer){
  2249. //console.log('mapFocusOn: '+target.toArray())
  2250. const minBound = new THREE.Vector2(1,1)//针对垂直线,在地图上只有一个点
  2251. let boundSizeMap = boundSizeOri.clone().multiplyScalar(2)
  2252. boundSizeMap.x = Math.max(minBound.x, boundSizeMap.x )
  2253. boundSizeMap.y = Math.max(minBound.y, boundSizeMap.y )
  2254. this.mapViewer.moveTo(target.clone(), boundSizeMap, duration)
  2255. }
  2256. //获得相机最佳位置
  2257. let dir = new THREE.Vector3().subVectors(cameraTemp.position, target).normalize()
  2258. position.copy(target).add(dir.multiplyScalar(dis))
  2259. if(Potree.settings.displayMode == 'showPointCloud'){ //点云
  2260. }else if(Potree.settings.displayMode == 'showPanos'){//全景 (比较难校准)
  2261. let pano = viewer.images360.fitPanoTowardPoint({
  2262. /*point : target, //不使用目标点来判断是因为缺少measure角度的信息。比如虽然可以靠近线的中心,但是线朝向屏幕,那几乎就是一个点了。
  2263. //bestDistance : dis * 0.5, //乘以小数是为了尽量靠近
  2264. boundSphere: boundOri.getBoundingSphere(new THREE.Sphere), */
  2265. point : position,
  2266. bestDistance : 0 ,
  2267. })
  2268. pano && viewer.images360.flyToPano({pano, target, duration, deferred, dontMoveMap:true , basePanoSize:o.basePanoSize})//dontMoveMap不要移动map,否则flytopano会自动在map中focus到漫游点的位置,而非测量线了
  2269. if(!pano){
  2270. console.error('no pano')
  2271. }
  2272. return deferred
  2273. //出现过到达位置后测量线标签闪烁的情况
  2274. }
  2275. } else if (type == 'tag' || type == 'point') {
  2276. //dimension = 1
  2277. target.copy(object.position)
  2278. let bestDistance = o.distance || 2
  2279. {
  2280. //console.log('mapFocusOn: '+target.toArray())
  2281. this.mapViewer.moveTo(target.clone(), null, duration)
  2282. }
  2283. if(Potree.settings.displayMode == 'showPointCloud'){
  2284. dis = bestDistance
  2285. let dir = o.direction ? o.direction.clone().negate() : new THREE.Vector3().subVectors(camera.position, target).normalize()
  2286. position.copy(target).add(dir.multiplyScalar(dis))
  2287. }else if(Potree.settings.displayMode == 'showPanos'){
  2288. let pano = viewer.images360.fitPanoTowardPoint({
  2289. point : target,
  2290. bestDistance //越近越好,但不要太近,bestDistance左右差不多
  2291. })
  2292. pano && viewer.images360.flyToPano({pano, target, duration, deferred, dontMoveMap:true , basePanoSize:o.basePanoSize })
  2293. return deferred
  2294. }
  2295. }
  2296. /*} else if(dimension == 2){//线
  2297. }else if(dimension == 3){//面
  2298. }else{//立体
  2299. } */
  2300. viewer.scene.view.setView(position, target, duration, ()=>{
  2301. console.log('focusOnObjectSuccess: '+object.name, type)
  2302. deferred.resolve()
  2303. })
  2304. return deferred.promise()
  2305. }
  2306. flyToDataset(o={}){
  2307. var pointcloud;
  2308. if(o instanceof THREE.Object3D) pointcloud = o
  2309. else if(o.pointcloud) pointcloud = o.pointcloud
  2310. else pointcloud = this.scene.pointclouds.find(p => p.dataset_id == o.id);
  2311. var center = pointcloud.bound.getCenter(new THREE.Vector3);
  2312. let request = []
  2313. let rank = [
  2314. Images360.scoreFunctions.distanceSquared({position: center})
  2315. ]
  2316. let r = Common.sortByScore(pointcloud.panos, request, rank);
  2317. if(r && r.length){
  2318. this.images360.flyToPano({
  2319. pano:r[0].item
  2320. })
  2321. }
  2322. }
  2323. resolveTimings(timestamp){
  2324. if(Potree.measureTimings){
  2325. if(!this.toggle){
  2326. this.toggle = timestamp;
  2327. }
  2328. let duration = timestamp - this.toggle;
  2329. if(duration > 1000.0){
  2330. let measures = performance.getEntriesByType("measure");
  2331. let names = new Set();
  2332. for(let measure of measures){
  2333. names.add(measure.name);
  2334. }
  2335. let groups = new Map();
  2336. for(let name of names){
  2337. groups.set(name, {
  2338. measures: [],
  2339. sum: 0,
  2340. n: 0,
  2341. min: Infinity,
  2342. max: -Infinity
  2343. });
  2344. }
  2345. for(let measure of measures){
  2346. let group = groups.get(measure.name);
  2347. group.measures.push(measure);
  2348. group.sum += measure.duration;
  2349. group.n++;
  2350. group.min = Math.min(group.min, measure.duration);
  2351. group.max = Math.max(group.max, measure.duration);
  2352. }
  2353. let glQueries = Potree.resolveQueries(this.renderer.getContext());
  2354. for(let [key, value] of glQueries){
  2355. let group = {
  2356. measures: value.map(v => {return {duration: v}}),
  2357. sum: value.reduce( (a, i) => a + i, 0),
  2358. n: value.length,
  2359. min: Math.min(...value),
  2360. max: Math.max(...value)
  2361. };
  2362. let groupname = `[tq] ${key}`;
  2363. groups.set(groupname, group);
  2364. names.add(groupname);
  2365. }
  2366. for(let [name, group] of groups){
  2367. group.mean = group.sum / group.n;
  2368. group.measures.sort( (a, b) => a.duration - b.duration );
  2369. if(group.n === 1){
  2370. group.median = group.measures[0].duration;
  2371. }else if(group.n > 1){
  2372. group.median = group.measures[parseInt(group.n / 2)].duration;
  2373. }
  2374. }
  2375. let cn = Array.from(names).reduce( (a, i) => Math.max(a, i.length), 0) + 5;
  2376. let cmin = 10;
  2377. let cmed = 10;
  2378. let cmax = 10;
  2379. let csam = 6;
  2380. let message = ` ${"NAME".padEnd(cn)} |`
  2381. + ` ${"MIN".padStart(cmin)} |`
  2382. + ` ${"MEDIAN".padStart(cmed)} |`
  2383. + ` ${"MAX".padStart(cmax)} |`
  2384. + ` ${"SAMPLES".padStart(csam)} \n`;
  2385. message += ` ${"-".repeat(message.length) }\n`;
  2386. names = Array.from(names).sort();
  2387. for(let name of names){
  2388. let group = groups.get(name);
  2389. let min = group.min.toFixed(3);
  2390. let median = group.median.toFixed(3);
  2391. let max = group.max.toFixed(3);
  2392. let n = group.n;
  2393. message += ` ${name.padEnd(cn)} |`
  2394. + ` ${min.padStart(cmin)} |`
  2395. + ` ${median.padStart(cmed)} |`
  2396. + ` ${max.padStart(cmax)} |`
  2397. + ` ${n.toString().padStart(csam)}\n`;
  2398. }
  2399. message += `\n`;
  2400. console.log(message);
  2401. performance.clearMarks();
  2402. performance.clearMeasures();
  2403. this.toggle = timestamp;
  2404. }
  2405. }
  2406. }
  2407. loop(timestamp){
  2408. if(this.stats){
  2409. this.stats.begin();
  2410. }
  2411. if(Potree.measureTimings){
  2412. performance.mark("loop-start");
  2413. }
  2414. this.update(this.clock.getDelta(), timestamp);
  2415. this.magnifier.render();
  2416. this.render();
  2417. // let vrActive = viewer.renderer.xr.isPresenting;
  2418. // if(vrActive){
  2419. // this.update(this.clock.getDelta(), timestamp);
  2420. // this.render();
  2421. // }else{
  2422. // this.update(this.clock.getDelta(), timestamp);
  2423. // this.render();
  2424. // }
  2425. if(Potree.measureTimings){
  2426. performance.mark("loop-end");
  2427. performance.measure("loop", "loop-start", "loop-end");
  2428. }
  2429. this.resolveTimings(timestamp);
  2430. Potree.framenumber++;
  2431. if(this.stats){
  2432. this.stats.end();
  2433. }
  2434. }
  2435. postError(content, params = {}){
  2436. let message = this.postMessage(content, params);
  2437. message.element.addClass("potree_message_error");
  2438. return message;
  2439. }
  2440. postMessage(content, params = {}){
  2441. let message = new Message(content);
  2442. let animationDuration = 100;
  2443. message.element.css("display", "none");
  2444. message.elClose.click( () => {
  2445. message.element.slideToggle(animationDuration);
  2446. let index = this.messages.indexOf(message);
  2447. if(index >= 0){
  2448. this.messages.splice(index, 1);
  2449. }
  2450. });
  2451. this.elMessages.prepend(message.element);
  2452. message.element.slideToggle(animationDuration);
  2453. this.messages.push(message);
  2454. if(params.duration !== undefined){
  2455. let fadeDuration = 500;
  2456. let slideOutDuration = 200;
  2457. setTimeout(() => {
  2458. message.element.animate({
  2459. opacity: 0
  2460. }, fadeDuration);
  2461. message.element.slideToggle(slideOutDuration);
  2462. }, params.duration)
  2463. }
  2464. return message;
  2465. }
  2466. getBoundingBox (pointclouds) {
  2467. //可以直接返回viewer.bound
  2468. if(!this.bound){
  2469. this.updateModelBound()
  2470. }
  2471. return this.bound.boundingBox.clone()//this.scene.getBoundingBox(pointclouds);
  2472. };
  2473. updateModelBound(){
  2474. this.bound = Utils.computePointcloudsBound(this.scene.pointclouds)
  2475. viewer.farWhenShowPano = this.bound.boundSize.length() * 2//全景漫游时要能看到整个skybox
  2476. let boundPlane = new THREE.Box3()
  2477. boundPlane.expandByPoint(this.bound.boundingBox.min.clone())//最低高度为bound的最低
  2478. boundPlane.expandByPoint(this.bound.boundingBox.max.clone().setZ(this.bound.center.z))//最高高度为bound的中心高度
  2479. FirstPersonControls.boundPlane = boundPlane
  2480. FirstPersonControls.standardSpeed = THREE.Math.clamp( Math.sqrt(this.bound.boundSize.length() )/ 100 , 0.02,0.5); //在这个boundPlane中的速度
  2481. viewer.scene.pointclouds.forEach(e=>{//海拔范围
  2482. e.material.heightMin = this.bound.boundingBox.min.z
  2483. e.material.heightMax = this.bound.boundingBox.max.z
  2484. })
  2485. }
  2486. waitForLoad(object, isLoadedCallback){//等待加载时显示loading。主要是贴图
  2487. this.waitQueue.push({
  2488. object,
  2489. isLoadedCallback,
  2490. })
  2491. 1 === this.waitQueue.length && this.emit("loading", true)
  2492. }
  2493. ifAllLoaded(object){
  2494. if(this.waitQueue.length>0){
  2495. this.waitQueue = this.waitQueue.filter(function(e) {
  2496. return !e.isLoadedCallback()
  2497. })
  2498. }
  2499. 0 === this.waitQueue.length && this.emit("loading", false)
  2500. }
  2501. setView(o={}){
  2502. let callback = ()=>{
  2503. if(o.displayMode){
  2504. Potree.settings.displayMode = o.displayMode
  2505. }
  2506. o.callback && o.callback()
  2507. }
  2508. if(o.pano != void 0){//pano 权重高于 position
  2509. this.images360.flyToPano(o)
  2510. }else{
  2511. this.scene.view.setView(o.position, o.target, o.duration, callback)
  2512. }
  2513. }
  2514. //调试时显示transformControl来调节object
  2515. transformObject(object){
  2516. if(!object.boundingBox){
  2517. object.boundingBox = new THREE.Box3() //任意大小 只是为了显示黄色外框
  2518. //??? computeBoundingBox
  2519. }
  2520. viewer.inputHandler.toggleSelection(object);
  2521. }
  2522. addObjectTest1(){//加水管
  2523. if(Potree.settings.number == 't-8KbK1JjubE'){
  2524. let boundingBox = new THREE.Box3()
  2525. boundingBox.min.set(-1,-1,-1); boundingBox.max.set(1,1,1)
  2526. let radius = 0.08;
  2527. let radialSegments = 5
  2528. let radSegments = Math.PI*2 / radialSegments
  2529. var circlePts = [];//横截面
  2530. for(let i=0;i<radialSegments;i++){
  2531. let angle = radSegments * i;
  2532. circlePts.push(new THREE.Vector2(radius * Math.cos(angle), radius * Math.sin(angle) ))
  2533. }
  2534. var count = 0
  2535. var addMesh = (color, path, height)=>{//height:在path之上的高度,负数代表在path之下
  2536. var name = 'cylinder'+count
  2537. var mat = new THREE.MeshStandardMaterial({color, /* wireframe:true, */ depthTest:false, roughness:0.4,metalness:0.5}) 
  2538. let linePath = path.map(e=>new THREE.Vector3().copy(e).setZ(e.z+height))
  2539. let geo = MeshDraw.getExtrudeGeo( circlePts, null,{ extrudePath:linePath, tension:0.2} )
  2540. var mesh = new THREE.Mesh(geo,mat);
  2541. mesh.name = name
  2542. window[name] = mesh
  2543. mesh.boundingBox = boundingBox
  2544. mesh.matrixAutoUpdate = false
  2545. mesh.matrix.copy(viewer.scene.pointclouds[0].transformMatrix)
  2546. mesh.matrixWorldNeedsUpdate = true
  2547. this.scene.scene.add(mesh);
  2548. count ++
  2549. }
  2550. let linePath, height
  2551. //地上管子 黄色
  2552. /* linePath = [{"x":-109.83,"y":-68.33,"z":-7.52},{"x":-95.17,"y":-59.3,"z":-7.38}, {"x":-38.75,"y":-24.01,"z":-6.01},{"x":0.5,"y":0.19,"z":-3.89},{"x":42.76,"y":26.88,"z":-1.03}
  2553. , {"x":44.27,"y":28.63,"z":-0.89},{"x":40.22,"y":35.37,"z":-0.67}// 拐弯向右
  2554. , {"x":40.25,"y":36.47,"z":-0.6},{"x":38.69,"y":36.04,"z":18.04}// 拐弯向右
  2555. ] */
  2556. linePath = [{"x":-109.83,"y":-68.33,"z":-7.52},{"x":-95.17,"y":-59.3,"z":-7.38}, {"x":-38.75,"y":-24.01,"z":-6.01},{"x":0.5,"y":0.19,"z":-3.89},{"x":39.29,"y":24.41,"z":-1.31}
  2557. ,{"x":43.58,"y":27.7,"z":-0.97},{"x":40.22,"y":35.37,"z":-0.67}// 拐弯向右
  2558. , {"x":39.18,"y":36.71,"z":0.35},{"x":38.69,"y":36.04,"z":18.04} // 拐弯向上
  2559. ]
  2560. height = radius + 0.05;
  2561. addMesh('#b86', linePath, height)
  2562. //地下管子 藍色
  2563. linePath = [{"x":-108.24,"y":-70.61,"z":-7.52}, {"x":-57.8,"y":-39.31,"z":-6.72},{"x":-18.8,"y":-15.35,"z":-5.01},{"x":55.87,"y":31.67,"z":-0.04},{"x":110.53,"y":66.48,"z":5.14}
  2564. ]
  2565. height = -0.5;
  2566. addMesh('#48a', linePath, height)
  2567. }
  2568. }
  2569. loadObj(fileInfo){//加水管2
  2570. let boundingBox = new THREE.Box3()
  2571. boundingBox.min.set(-1,-1,-1); boundingBox.max.set(1,1,1)
  2572. let manager = new THREE.LoadingManager();
  2573. /* manager.onProgress = function ( item, loaded, total ) {
  2574. console.log( item, loaded, total );
  2575. }; */
  2576. let onProgress = function ( xhr ) {
  2577. if ( xhr.lengthComputable ) {
  2578. let percentComplete = xhr.loaded / xhr.total * 100;
  2579. console.log( Math.round(percentComplete, 2) + '% downloaded' );
  2580. }
  2581. };
  2582. let onError = function ( xhr ) {};
  2583. let Objloader = new OBJLoader( manager );
  2584. let MtlLoader = new MTLLoader( manager );
  2585. MtlLoader.load( fileInfo.mtlurl , (materials)=>{
  2586. materials.preload();
  2587. Objloader.setMaterials( materials ).load(fileInfo.objurl, (object)=>{
  2588. object.traverse( function ( child ) {
  2589. if ( child instanceof THREE.Mesh ) {
  2590. //child.material.map = texture;
  2591. child.material.roughness = 0.6
  2592. child.material.metalness = 0.3
  2593. }
  2594. } );
  2595. this.obj = object;
  2596. this.scene.scene.add(object);
  2597. object.boundingBox = boundingBox
  2598. object.rotation.fromArray(fileInfo.transform.rotation)
  2599. object.position.fromArray(fileInfo.transform.position)
  2600. object.updateMatrix();
  2601. object.matrixAutoUpdate = false
  2602. object.matrix.premultiply(viewer.scene.pointclouds[0].transformMatrix) //默认跟随第一个数据集
  2603. object.matrixWorldNeedsUpdate = true
  2604. /* viewer.onGUILoaded(() => {
  2605. // Add entries to object list in sidebar
  2606. let tree = $(`#jstree_scene`);
  2607. let parentNode = "other";
  2608. let bunnyID = tree.jstree('create_node', parentNode, {
  2609. text: "Bunny Textured",
  2610. icon: `${Potree.resourcePath}/icons/triangle.svg`,
  2611. data: object
  2612. },
  2613. "last", false, false);
  2614. tree.jstree(object.visible ? "check_node" : "uncheck_node", bunnyID);
  2615. //tree.jstree("open_node", parentNode);
  2616. }); */
  2617. }, onProgress, onError );
  2618. });
  2619. }
  2620. };