BuildingBox.js 31 KB

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