viewer.js 105 KB

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