BuildingBox.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. import * as THREE from "../../../../libs/three.js/build/three.module.js";
  2. import {ctrlPolygon} from '../../objects/tool/ctrlPolygon.js'
  3. import {LineDraw, MeshDraw } from "../../utils/DrawUtil.js";
  4. import math from "../../utils/math.js";
  5. import Sprite from '../../objects/Sprite.js'
  6. /* import {config} from '../settings' */
  7. import searchRings from "../../utils/searchRings.js";
  8. import DepthBasicMaterial from "../../materials/DepthBasicMaterial.js";
  9. let texLoader = new THREE.TextureLoader()
  10. let markerMats
  11. let markerSizeInfo = {width2d:35}
  12. let color = new THREE.Color('#FFF')
  13. let faceMats
  14. let getFaceMat = (name)=>{
  15. if(!faceMats){ //navvis材质可以搜gridTexture
  16. let gridTex = texLoader.load( Potree.resourcePath+'/textures/gridmap.png' )
  17. gridTex.wrapS = gridTex.wrapT = THREE.RepeatWrapping
  18. //gridTex.repeat.set(0.5,0.5)//放大一些
  19. faceMats = {
  20. dataset: new THREE.MeshStandardMaterial({
  21. color:812922,
  22. side:THREE.DoubleSide,
  23. opacity:0.2,
  24. transparent:true,
  25. depthTest:false,
  26. wireframe:true
  27. }),
  28. building: new THREE.MeshStandardMaterial({
  29. color:812922, metalness: 0.2, roughness:0.8,
  30. side:THREE.DoubleSide,
  31. opacity:0.1,
  32. transparent:true,
  33. depthTest:true
  34. }),
  35. buildingSelect: new THREE.MeshStandardMaterial({
  36. color:36582, metalness: 0, roughness:1,
  37. side:THREE.DoubleSide,
  38. opacity:0.1,
  39. transparent:true,
  40. depthTest:true
  41. }),
  42. floor: new THREE.MeshStandardMaterial({
  43. color:11708469, metalness: 0.1, roughness:1,
  44. side:THREE.DoubleSide,//BackSide,
  45. opacity:0.05,
  46. transparent:true,
  47. depthTest:true,
  48. }),
  49. floorSelect: new DepthBasicMaterial({
  50. map: gridTex,
  51. color:16707151,
  52. side:THREE.DoubleSide,//BackSide,
  53. opacity:1,
  54. transparent:true,
  55. useDepth : true,
  56. clipDistance : 1, occlusionDistance:1, /* occlusionDistance:变为backColor距离, clipDistance:opacity到达0或者1-maxClipFactor时的距离 */
  57. maxClipFactor:0.9, backColor:'#efe' //backColor:"#669988" ,
  58. }),
  59. room: new THREE.MeshStandardMaterial({
  60. color:"#ff44ee", metalness: 0, roughness:1,
  61. side:THREE.DoubleSide,//BackSide,
  62. opacity:0.08,
  63. transparent:true,
  64. depthTest:false,
  65. }),
  66. roomSelect: new DepthBasicMaterial({
  67. map: gridTex,
  68. color:"#ff44ee",
  69. side:THREE.DoubleSide,//BackSide,
  70. opacity:1,
  71. transparent:true,
  72. useDepth : true,
  73. clipDistance : 1, occlusionDistance:0.5, /* occlusionDistance:变为backColor距离, clipDistance:opacity到达0或者1-maxClipFactor时的距离 */
  74. maxClipFactor:0.8, backColor:'#ff88dd'//"#cc99c2" ,
  75. })
  76. }
  77. }
  78. return faceMats[name]
  79. }
  80. export class BuildingBox extends ctrlPolygon{//建筑实体,包括building, floor, room
  81. constructor(prop) {
  82. prop.dimension = '3d'
  83. //prop.name = Potree.config.siteModel.names[prop.buildType] +
  84. super('siteModel_'+prop.buildType, prop);
  85. this.midMarkers = []
  86. this.buildChildren = []//子实体
  87. this.holes = [] //在这创建的hole
  88. this.parentHoles = [];//floor从building那得到的当层holes
  89. this.mats = {} //材质
  90. this.panos = this.panos || [];
  91. this.center //中心点
  92. if(this.buildType=='floor'){
  93. this.points = prop.points = this.buildParent.points;//完全等于建筑的点
  94. this.buildParent.holes.forEach(hole=>{//从building获取holes
  95. let floorHole = new BuildingBox({
  96. buildType : 'hole',
  97. buildParent:this,
  98. originHole : hole, //整栋大楼在当层的hole
  99. ifDraw: this.ifDraw || Potree.settings.drawEntityData
  100. });
  101. this.parentHoles.push(floorHole)
  102. this.add(floorHole)
  103. floorHole.points = hole.points//完全等于建筑的点
  104. })
  105. }
  106. if(this.buildType == 'room' || this.buildType == 'hole'){
  107. this.restrictArea = this.buildParent //不能超出的区域
  108. }
  109. if(this.buildParent)this.dontDragFloorHeight = this.buildParent.dontDragFloorHeight
  110. if(this.buildType != 'hole'){
  111. this.box = this.createBox() //无论是否edit都绘制的原因:为了将在外的点移到在内,需要用mesh来获取intersect
  112. this.add(this.box)
  113. this.box.visible = !!this.ifDraw
  114. }
  115. if(this.ifDraw){ //只存储空间模型信息,不绘制
  116. {
  117. this.createPrismLines(color)
  118. this.lineMesh.visible = false
  119. Potree.Utils.setObjectLayers(this.lineMesh, 'bothMapAndScene' )
  120. }
  121. this.addEventListener('dragChange',(e)=>{ //修改中点
  122. this.updateTwoMidMarker(e.index)
  123. })
  124. }
  125. this.initData(prop)
  126. }
  127. initData(prop){
  128. if(prop.ifDraw){
  129. super.initData(prop)
  130. }else{
  131. if(prop.points){
  132. this.points = prop.points
  133. }
  134. }
  135. }
  136. intersectPointcloudVolume(pointcloud){//和pointcloud的重叠体积
  137. return this.intersectPointcloudArea(pointcloud) * this.coverPointcloudHeight(pointcloud)
  138. }
  139. coverPointcloudHeight(pointcloud, getPercent){
  140. let bound2 = pointcloud.bound;
  141. let {zMin , zMax} = this.getRealZ()
  142. let min = Math.min(zMin, bound2.min.z);
  143. let max = Math.max(zMax, bound2.max.z);
  144. let height1 = zMax - zMin
  145. let height2 = bound2.max.z-bound2.min.z
  146. let coverHeight = height1 + height2 - (max-min)//重叠高度 <=0是没重叠
  147. if(getPercent){
  148. return coverHeight / height1
  149. }
  150. return coverHeight
  151. }
  152. intersectPointcloudArea(pointcloud, getPercent){//和pointcloud的重叠面积
  153. var bound = this.getBound()
  154. let bound2 = pointcloud.bound;
  155. if(!bound.intersectsBox(bound2)) return 0;
  156. let boxPoints = pointcloud.getUnrotBoundPoint() //获取tightBound的四个点。 如果是有旋转角度的点云,这个和pointcloud.bound的四个点是不一致的,覆盖面积小于pointcloud.bound
  157. let areaWhole = 0
  158. let area1 = this.getArea()
  159. let area2 = Math.abs(math.getArea(boxPoints))
  160. {//计算points与点云总面积 (但是把hole也加入了面积)(并集,重叠部分只算一次)
  161. let rings = math.getPolygonsMixedRings([this.points, boxPoints] )
  162. rings.forEach(e=>{
  163. areaWhole+=e.area
  164. })
  165. }
  166. let coverHoleArea = 0 //holes与数据集重叠的部分
  167. let holes = this.holes.concat(this.parentHoles)
  168. let holesArea = 0 //所有holes面积相加
  169. let areaHoleWithPointcloud = 0 //hole和点云的面积并集
  170. if(holes.length>0){//还要再扣除holes与数据集重叠的部分。其中holes为mix轮廓
  171. let outHoles = []//没有重合的holes的外轮廓
  172. /* if(holes.length>=2){//合并holes。如果能在绘制时直接合并holes就好啦,这步就转移到那去,但是要删除hole好麻烦
  173. let holes_ = holes.map(e=>e.points)
  174. outHoles = math.getPolygonsMixedRings(holes_, true )
  175. outHoles.forEach(e=>{
  176. holesArea+=e.area
  177. })
  178. outHoles = outHoles.map(e=>e.points)
  179. }else{
  180. outHoles = holes.map(e=>e.points)
  181. outHoles.forEach(e=> holesArea += Math.abs(math.getArea(e)))
  182. } */
  183. holesArea = this.getHolesArea()
  184. //holes与数据集重叠的部分
  185. {
  186. let polygons = outHoles.concat([boxPoints])
  187. let rings = math.getPolygonsMixedRings(polygons)
  188. rings.forEach(e=>{
  189. areaHoleWithPointcloud+=e.area
  190. })
  191. coverHoleArea = holesArea + area2 - areaHoleWithPointcloud//hole和点云的交集
  192. }
  193. }
  194. let coverArea = area1 + area2 - areaWhole - coverHoleArea; //重叠面积
  195. if(getPercent){
  196. return {
  197. toEntity:coverArea / this.getArea(true), //占entity
  198. toPointcloud:coverArea / area2 //占点云
  199. }
  200. }
  201. return coverArea
  202. }
  203. addHole(points=[]){
  204. let prop = {
  205. buildType : 'hole',
  206. zMin : this.zMin,
  207. zMax : this.zMax,
  208. points,
  209. buildParent:this,
  210. ifDraw: this.ifDraw || Potree.settings.drawEntityData
  211. }
  212. //hole的zMin zMax跟随buildParent
  213. var hole = new BuildingBox(prop);
  214. this.holes.push(hole)
  215. if(this.buildType == 'building'){//为每一层添加对应的hole
  216. this.buildChildren.forEach(floor=>{
  217. let floorHole = new BuildingBox({
  218. buildType : 'hole',
  219. zMin : this.zMin,
  220. zMax : this.zMax,
  221. buildParent:floor,
  222. originHole : hole, //整栋大楼在当层的hole
  223. ifDraw: this.ifDraw || Potree.settings.drawEntityData
  224. });
  225. floor.parentHoles.push(floorHole)
  226. floor.add(floorHole)
  227. floorHole.points = hole.points//完全等于建筑的点
  228. })
  229. }
  230. this.add(hole);//直接加在这,不加meshGroup了
  231. this.update() //update box mesh
  232. return hole
  233. //hole不创建box,只有它的buildParent需要更新box。 但有线条和marker. hole不在buildChildren里,但有buildParent
  234. }
  235. removeHole(hole){// 这个hole不会是parentHoles里的。
  236. hole.dispose()
  237. if(this.buildType == 'building'){ //若是整栋大楼的hole,在每层去除它的对应hole
  238. this.buildChildren.forEach(floor=>{
  239. let holeAtFloor = floor.parentHoles.find(e=>e.originHole == this )
  240. let index = floor.parentHoles.indexOf(holeAtFloor)
  241. index > -1 && floor.parentHoles.splice(index, 1)
  242. holeAtFloor.dispose()
  243. })
  244. }
  245. let index = this.holes.indexOf(hole)
  246. if(index>-1){
  247. this.holes.splice(index, 1)
  248. }
  249. this.remove(hole)
  250. this.update()
  251. }
  252. createBox(){
  253. var geometry = new THREE.Geometry();
  254. this.mats.boxDefault = getFaceMat(this.buildType)
  255. this.mats.boxSelected = getFaceMat(this.buildType+'Select')
  256. var mesh = new THREE.Mesh(geometry, this.mats.boxDefault)
  257. mesh.name = 'buildingBox';
  258. if(this.buildType == 'floor'){
  259. Potree.Utils.setObjectLayers(mesh, 'mapUnvisi' ) //楼层默认在地图不显示,为了不会叠加透明度
  260. //mesh.renderOrder = 1
  261. }else{
  262. /* if(this.buildType == 'room'){
  263. mesh.renderOrder = 2
  264. } */
  265. Potree.Utils.setObjectLayers(mesh, 'bothMapAndScene' )
  266. }
  267. //mesh.frustumCulled = false;
  268. return mesh
  269. }
  270. addMarker(o={} ){
  271. if(this.buildType=='floor')return; //楼层不需要marker
  272. let marker = new Sprite({mat:this.getMarkerMaterial('default'), renderOrder : 3, sizeInfo: markerSizeInfo, dontFixOrient: true, name:"building_marker"} )
  273. Potree.Utils.setObjectLayers(marker, 'onlyMapVisi' )
  274. o.marker = marker
  275. super.addMarker(o)
  276. if(!this.selected)Potree.Utils.updateVisible(marker,'select',false)
  277. let addClickEvent = (e)=>{
  278. let click = (e) => {
  279. this.dispatchEvent({type:'clickMarker', marker } ) //由entity发送给sitemodel统一处理
  280. };
  281. marker.addEventListener('click', click);
  282. marker.addEventListener('clickSelect', (e)=>{
  283. this.setMarkerSelected(marker, e.state ? 'select' : 'unselect' );
  284. });
  285. marker.removeEventListener('addHoverEvent',addClickEvent)
  286. }
  287. marker.addEventListener('addHoverEvent',addClickEvent)//当非isNew时才添加事件
  288. if(!this.isNew){
  289. marker.dispatchEvent('addHoverEvent')
  290. }
  291. return marker
  292. }
  293. removeMarker(index){
  294. super.removeMarker(index);
  295. if(!this.isNew){
  296. //重新添加midMarkers
  297. this.midMarkers.forEach(e=>this.remove(e));
  298. this.midMarkers = []
  299. this.addMidMarkers()
  300. }
  301. this.update();
  302. if(this.points.length == 2 && this.box){//清除原先length>=3时候的
  303. this.box.geometry = new THREE.Geometry();
  304. }
  305. }
  306. addMidMarker(index, point){
  307. if(this.buildType=='floor')return; //楼层不需要marker
  308. let marker = new Sprite({mat:this.getMarkerMaterial('midPrepare'), sizeInfo: markerSizeInfo, dontFixOrient: true, name:"building_midMarker"} )
  309. this.midMarkers = [...this.midMarkers.slice(0,index), marker, ...this.midMarkers.slice(index,this.midMarkers.length)]
  310. marker.renderOrder = 3
  311. Potree.Utils.setObjectLayers(marker, 'onlyMapVisi' )
  312. { // Event Listeners
  313. let mouseover = (e) => {
  314. this.setMarkerSelected(e.object, 'hover', 'single');
  315. viewer.dispatchEvent({
  316. type : "CursorChange", action : "add", name:"markerMove"
  317. })
  318. };
  319. let mouseleave = (e) => {
  320. this.setMarkerSelected(e.object, 'unhover', 'single');
  321. viewer.dispatchEvent({
  322. type : "CursorChange", action : "remove", name:"markerMove"
  323. })
  324. }
  325. let drag = (e) => {
  326. this.dispatchEvent('startDragging')
  327. let index = this.midMarkers.indexOf(marker)
  328. let newMarker = this.addMarker({index:(index+1), point:marker.position.clone() })
  329. this.addMidMarker(index+1, new THREE.Vector3 )
  330. this.updateTwoMidMarker(index+1)
  331. this.setMarkerSelected(marker, 'unhover')
  332. viewer.inputHandler.startDragging(newMarker , {/* dragViewport:viewer.mapViewer.viewports[0], */ } ); //notPressMouse代表不是通过按下鼠标来拖拽. dragViewport指定了只能在地图上拖拽
  333. }
  334. marker.addEventListener('drag', drag );
  335. marker.addEventListener('mouseover', mouseover);
  336. marker.addEventListener('mouseleave', mouseleave);
  337. }
  338. this.add(marker)
  339. this.updateMarker(marker, point)
  340. if(!this.selected)Potree.Utils.updateVisible(marker,'select',false)
  341. return marker
  342. }
  343. addMidMarkers(){//第一次画好所有marker后,一次性为线段增加中点marker
  344. let length = this.points.length
  345. this.points.forEach((point,index)=>{
  346. let nextPoint = this.points[(index+1)%length]
  347. let midPoint = new THREE.Vector3().addVectors(point, nextPoint).multiplyScalar(0.5)
  348. this.addMidMarker(index, midPoint )
  349. })
  350. }
  351. updateTwoMidMarker(index){//更新第index个marker两边的midMarker
  352. if(!this.midMarkers.length)return
  353. let length = this.points.length
  354. let last = this.points[(index-1+length)%length] //它之前的marker位置
  355. let next = this.points[(index+1)%length];//它之后的marker位置
  356. let current = this.points[index]//当前位置
  357. let lastMid = new THREE.Vector3().addVectors(last, current).multiplyScalar(0.5)//上一个中点
  358. let nextMid = new THREE.Vector3().addVectors(next, current).multiplyScalar(0.5)//下一个中点
  359. let lastMidMarker = this.midMarkers[(index-1+length)%length];
  360. let nextMidMarker = this.midMarkers[index]
  361. this.updateMarker(lastMidMarker, lastMid)
  362. this.updateMarker(nextMidMarker, nextMid)
  363. }
  364. dispose(){//销毁geo、remove from parent
  365. super.dispose()
  366. this.box && this.box.geometry.dispose();
  367. this.lineMesh && this.lineMesh.geometry.dispose();
  368. this.holes.forEach(e=>e.dispose())
  369. this.parentHoles.forEach(e=>e.dispose())
  370. //this.buildChildren.forEach(e=>e.dispose())
  371. this.dispatchEvent('dispose')
  372. }
  373. updateBox(){
  374. if(!this.box)return
  375. this.box.geometry.dispose()
  376. var shrink = this.buildType == 'room' ? 0.11 : this.buildType == 'floor' ? 0.082 : 0.2 ;//防止mesh重叠冲突(给一个不寻常的数字) 但离远了还是会有点闪烁
  377. if(this.points.length >= 3){
  378. let holes = this.holes.concat(this.parentHoles)
  379. let holesPoints = holes.filter(e=>e.points.length>2).map(e=>e.points)
  380. this.box.geometry = MeshDraw.getExtrudeGeo(this.points, holesPoints, {
  381. depth:this.zMax-this.zMin-shrink,
  382. UVGenerator: new MetricUVGenerator()
  383. })
  384. if(this.buildType == 'building' ){
  385. this.box.position.z = this.zMin - shrink / 2
  386. }else{
  387. this.box.position.z = this.zMin + shrink / 2
  388. }
  389. }
  390. }
  391. update(options={}){
  392. super.update(this.buildType != 'floor' && options.ifUpdateMarkers)
  393. let length = this.points.length
  394. {//确保一下一样
  395. if(this.originHole){
  396. this.points = this.originHole.points //完全等于building的hole
  397. }
  398. if(this.buildType == 'hole'){
  399. this.zMin = this.buildParent.zMin;
  400. this.zMax = this.buildParent.zMax;
  401. }
  402. }
  403. if(!options.dontUpdateBox){
  404. let boxOwner
  405. if(this.buildType == 'hole'){
  406. if(this.buildParent.buildType == 'building'){ //若是整栋大楼的hole,在每层都要更新下它的对应hole
  407. this.buildParent.buildChildren.forEach(floor=>{
  408. let holeAtFloor = floor.parentHoles.find(e=>e.originHole == this )
  409. holeAtFloor && holeAtFloor.update() //刚开始创建时还没创建对应的 holeAtFloor会为null
  410. })
  411. }
  412. boxOwner = this.buildParent
  413. }else{
  414. boxOwner = this
  415. }
  416. boxOwner.updateBox()
  417. }
  418. this.updatePrismLines()//update lines
  419. if(!options.dontUpdateChildren){
  420. if(this.buildType == 'building' ){
  421. this.buildChildren.forEach(floor=>{
  422. floor.points = this.points
  423. floor.update()
  424. })
  425. }
  426. {
  427. let holes = this.holes.concat(this.parentHoles)
  428. holes.forEach(hole=> {
  429. hole.update({dontUpdateBox:true})//父级更新了box,hole就不需要更新box了
  430. })
  431. }
  432. }
  433. }
  434. getHolesArea(){
  435. let holes = this.holes.concat(this.parentHoles)
  436. let outHoles, holesArea = 0
  437. if(holes.length>=2){//合并holes。如果能在绘制时直接合并holes就好啦,这步就转移到那去,但是要删除hole好麻烦
  438. let holes_ = holes.map(e=>e.points)
  439. outHoles = math.getPolygonsMixedRings(holes_, true )
  440. outHoles.forEach(e=>{
  441. holesArea+=e.area
  442. })
  443. outHoles = outHoles.map(e=>e.points)
  444. }else{
  445. outHoles = holes.map(e=>e.points)
  446. outHoles.forEach(e=> holesArea += Math.abs(math.getArea(e)))
  447. }
  448. return holesArea
  449. }
  450. getArea(ifRidOfHoles){//面积
  451. //不排除hole
  452. return Math.abs(math.getArea(this.points)) - (ifRidOfHoles ? this.getHolesArea() : 0)
  453. }
  454. getVolume(ifRidOfHoles){//体积
  455. let {zMin , zMax} = this.getRealZ()
  456. let height = zMax - zMin;
  457. if(isNaN(height))height = 0
  458. return this.getArea(ifRidOfHoles) * height
  459. }
  460. getRealZ(){//求真实高度时用到的
  461. let zMin , zMax
  462. if (this.buildType == 'building') {
  463. //因为building只有一个地基平面 所以自身的zMin == 自身的zMax 所以要算
  464. let top = this.buildChildren[this.buildChildren.length - 1]
  465. let btm = this.buildChildren[0]
  466. zMin = btm ? btm.zMin : 0 //建好的建筑不加楼的话是0。
  467. zMax = top ? top.zMax : 0
  468. }else if(this.buildType == 'hole'){
  469. return this.buildParent.getRealZ()
  470. }else{
  471. zMin = this.zMin, zMax = this.zMax
  472. }
  473. return {zMin,zMax}
  474. }
  475. //架站式多楼层SG-t-ihjV2cDVFlE 有初始的z, 但是总高度范围小于数据集。 不允许修改高度。
  476. /* getDrawZ(){ //画线和box时用到的z
  477. let zMin , zMax
  478. if(this.buildType == 'hole'){
  479. if(this.buildParent.buildType == 'building' && atFloor){
  480. zMin = atFloor.zMin, zMax = atFloor.zMax
  481. }else{
  482. zMin = this.buildParent.zMin, zMax = this.buildParent.zMax
  483. }
  484. }else{
  485. zMin = this.zMin, zMax = this.zMax
  486. }
  487. return {zMin, zMax}
  488. } */
  489. getBound(){
  490. let bound = new THREE.Box3
  491. let {zMin , zMax} = this.getRealZ()
  492. let points = this.buildType == 'floor' ? this.buildParent.points : this.points
  493. points.forEach(p=>{
  494. bound.expandByPoint(p.clone().setZ(zMin))
  495. bound.expandByPoint(p.clone().setZ(zMax))
  496. })
  497. return bound
  498. }
  499. getMarkerMaterial(type) {
  500. if(!markerMats){
  501. markerMats = {
  502. default: new THREE.MeshBasicMaterial({
  503. transparent: !0,
  504. color,
  505. opacity: 0.8,
  506. map: texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png' ),
  507. depthTest:false,
  508. }),
  509. midPrepare: new THREE.MeshBasicMaterial({ //线中心的半透明点
  510. transparent: !0,
  511. color,
  512. opacity: 0.4,
  513. map: texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png' ),
  514. depthTest:false,
  515. }),
  516. hover: new THREE.MeshBasicMaterial({
  517. transparent: !0,
  518. color,
  519. opacity: 1,
  520. map: texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png' ),
  521. depthTest:false,
  522. }),
  523. select: new THREE.MeshBasicMaterial({
  524. transparent: !0,
  525. color:new THREE.Color('#00C8AF'),
  526. opacity: 1,
  527. map: texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png' ),
  528. depthTest:false,
  529. }),
  530. }
  531. }
  532. return markerMats[type]
  533. }
  534. setMarkerSelected(marker, state, hoverObject){
  535. //console.warn(marker.id , state, hoverObject)
  536. if(state == 'select'){
  537. marker.selected = true
  538. marker.material = this.getMarkerMaterial('select')
  539. }else if(state == 'unselect'){
  540. marker.selected = false
  541. marker.material = this.getMarkerMaterial('default')
  542. }else{
  543. if(marker.selected)return //选中时不允许修改为除了'unselect'以外的状态
  544. if(state == 'hover'){
  545. marker.material = this.getMarkerMaterial('hover')
  546. }else if(state == 'unhover'){
  547. if(marker.name.includes('mid')){
  548. marker.material = this.getMarkerMaterial('midPrepare')
  549. }else{
  550. marker.material = this.getMarkerMaterial('default')
  551. }
  552. }
  553. }
  554. }
  555. select(){
  556. //最多再显示一层子级的线,如building不会显示room中的hole的线
  557. //box是一直显示的,但会切换材质
  558. /*
  559. 选中 box 线
  560. building 自己(底盘)选中 自己, floor不带hole
  561. floor 自己选中 自己, room不带hole
  562. room 自己选中 自己
  563. */ //注:自己的就代表定包括hole,如果有parentHoles的也(building上的hole的对应)
  564. //console.log('select '+this.name, this.selected)
  565. if(this.selected)return
  566. if(this.box){
  567. this.box.material = this.mats.boxSelected;
  568. }
  569. if(this.buildType == 'building'|| this.buildType == 'floor'){
  570. this.buildChildren.forEach(e=>{
  571. e.lineMesh.visible = true
  572. })
  573. if(this.buildType == 'floor'){
  574. Potree.Utils.setObjectLayers(this.box, 'bothMapAndScene' )
  575. Potree.Utils.setObjectLayers(this.buildParent.box, 'mapUnvisi' ) //当选中floor或room时,building在地图不可见
  576. }
  577. }else if(this.buildType == 'room'){
  578. Potree.Utils.setObjectLayers(this.buildParent.box, 'bothMapAndScene' )
  579. Potree.Utils.setObjectLayers(this.buildParent.buildParent.box, 'mapUnvisi' )
  580. }
  581. this.lineMesh.visible = true
  582. this.markers && this.markers.forEach(e=>Potree.Utils.updateVisible(e,'select',true) )
  583. this.midMarkers && this.midMarkers.forEach(e=>Potree.Utils.updateVisible(e,'select',true) )
  584. let holes = this.holes.concat(this.parentHoles)
  585. holes.forEach(e=>e.select())
  586. this.selected = true
  587. this.dispatchEvent({type:'select'})
  588. }
  589. unselect(){
  590. if(!this.selected)return
  591. //console.log('unselect '+this.name )
  592. if(this.box){
  593. this.box.material = this.mats.boxDefault;
  594. }
  595. if(this.buildType == 'building' || this.buildType == 'floor'){
  596. this.buildChildren.forEach(e=>{ //(这里要保证选中前要先取消选中,否则如选中房间后取消了楼层,房间线就隐藏了)
  597. e.lineMesh.visible = false
  598. })
  599. if(this.buildType == 'floor'){
  600. Potree.Utils.setObjectLayers(this.box, 'mapUnvisi' )
  601. Potree.Utils.setObjectLayers(this.buildParent.box, 'bothMapAndScene' )
  602. }
  603. }else if(this.buildType == 'room'){
  604. Potree.Utils.setObjectLayers(this.buildParent.box, 'mapUnvisi' )
  605. Potree.Utils.setObjectLayers(this.buildParent.buildParent.box, 'bothMapAndScene' )
  606. }
  607. this.lineMesh.visible = false
  608. this.markers && this.markers.forEach(e=>Potree.Utils.updateVisible(e,'select',false) )
  609. this.midMarkers && this.midMarkers.forEach(e=>Potree.Utils.updateVisible(e,'select',false) )
  610. let holes = this.holes.concat(this.parentHoles)
  611. holes.forEach(e=>e.unselect())
  612. this.selected = false
  613. this.dispatchEvent({type:'unselect'})
  614. }
  615. ifContainsPoint(position){//看它所定义的空间是否包含某个坐标(要排除hole)
  616. let {zMin , zMax} = this.getRealZ()
  617. if(position.z < zMin || position.z > zMax ) return
  618. let holes = this.holes.concat(this.parentHoles)
  619. let holesPoints = holes.filter(e=>e!=this && e.points.length>2).map(e=>e.points)
  620. let inShape = math.isPointInArea(this.points, holesPoints, position)
  621. return !!inShape
  622. }
  623. }
  624. class MetricUVGenerator{
  625. constructor(){
  626. this.a = new THREE.Vector3,
  627. this.b = new THREE.Vector3,
  628. this.c = new THREE.Vector3,
  629. this.d = new THREE.Vector3
  630. }
  631. generateTopUV(t, e, n, r, o) {
  632. return [new THREE.Vector2(e[3 * n],e[3 * n + 1]), new THREE.Vector2(e[3 * r],e[3 * r + 1]), new THREE.Vector2(e[3 * o],e[3 * o + 1])]
  633. }
  634. generateSideWallUV(t, e, n, r, o, a) {
  635. var s = e;
  636. this.a.set(s[3 * n], s[3 * n + 1], s[3 * n + 2]),
  637. this.b.set(s[3 * r], s[3 * r + 1], s[3 * r + 2]),
  638. this.c.set(s[3 * o], s[3 * o + 1], s[3 * o + 2]),
  639. this.d.set(s[3 * a], s[3 * a + 1], s[3 * a + 2]);
  640. var c = this.a.x !== this.b.x
  641. , l = c ? this.b : this.d
  642. , u = this.a.distanceTo(l)
  643. , d = l.distanceTo(this.c);
  644. return [new THREE.Vector2(this.a.x,0), c ? new THREE.Vector2(this.a.x + u,0) : new THREE.Vector2(this.a.x,d), new THREE.Vector2(this.a.x + u,d), c ? new THREE.Vector2(this.a.x,d) : new THREE.Vector2(this.a.x + u,0)]
  645. }
  646. }