Path.js 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270
  1. import * as THREE from "../../../../libs/three.js/build/three.module.js";
  2. import {TextSprite} from "../TextSprite.js";
  3. import {Utils} from "../../../utils.js";
  4. import Label from "../Label.js";
  5. import {LineDraw , MeshDraw} from "../../utils/DrawUtil.js";
  6. import math from "../../utils/math.js";
  7. import DepthBasicMaterial from "../../materials/DepthBasicMaterial.js";
  8. import Sprite from '../Sprite.js'
  9. import {config} from '../../settings.js'
  10. import browser from "../../utils/browser.js";
  11. import {ctrlPolygon} from './ctrlPolygon.js'
  12. import {Measure} from './Measure.js'
  13. import CursorDeal from "../../utils/CursorDeal.js";
  14. let texLoader = new THREE.TextureLoader()
  15. const labelSizeInfo = {width2d:180} //稍微小点防止字体模糊
  16. const titleLineHeight = 2
  17. const arrowCountMax = 1000; //箭头总数不能超过这个值。 The count value passed into the constructor represents the maximum number of instances of this mesh. You can change the number of instances at runtime to an integer value in the range [0, count].If you need more instances than the original count value, you have to create a new InstancedMesh.
  18. let lastArrowCamPos, lastArrowCount = 0
  19. const depthProps = {
  20. useDepth : true ,
  21. //startClipDis : 0.5,
  22. clipDistance : 2,//消失距离
  23. //startOcclusDis: 0.5,
  24. occlusionDistance: 0.7,//变为backColor距离
  25. maxOcclusionFactor:0.9,
  26. maxClipFactor:1
  27. }
  28. const planeGeo = new THREE.PlaneBufferGeometry(1,1)
  29. const voidGeometry = new THREE.BufferGeometry()
  30. let markerMats, dragPointMat
  31. const getMarkerMat = function (name) {
  32. if(!markerMats){
  33. markerMats = {
  34. default: new DepthBasicMaterial( $.extend({}, depthProps,{
  35. transparent: true,
  36. map: texLoader.load( Potree.resourcePath+'/textures/dot_n.png'),
  37. opacity:0.9
  38. })),
  39. drag : new DepthBasicMaterial({
  40. transparent: true, useDepth:false,
  41. map: texLoader.load( Potree.resourcePath+'/textures/dot_s.png'),
  42. }),
  43. delete : new DepthBasicMaterial({
  44. transparent: true, useDepth:false,
  45. map: texLoader.load( Potree.resourcePath+'/textures/dot_r.png'),
  46. }),
  47. adding : new DepthBasicMaterial({
  48. transparent: true, opacity:0.3, useDepth:false,
  49. map: texLoader.load( Potree.resourcePath+'/textures/dot_n.png'),
  50. }),
  51. }
  52. for(let i in markerMats){markerMats[i].map.anisotropy = 4}
  53. }
  54. return markerMats[name]
  55. }
  56. const getMeshQuaInPath = (lineDir)=>{
  57. const quaBase = new THREE.Quaternion().setFromEuler(new THREE.Euler(-Math.PI/2,0, Math.PI/2))
  58. return math.getQuaFromPosAim( new THREE.Vector3, lineDir ).multiply(quaBase)
  59. }
  60. const getEndCaps = (function () {
  61. let endCap, map
  62. return function(path){
  63. if(!endCap){
  64. map = texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png')
  65. map.anisotropy = 3
  66. map.repeat.set(0.5, 1);
  67. //map.magFilter = THREE.NearestFilter
  68. let mesh = new THREE.Mesh(planeGeo )
  69. mesh.scale.x = 0.5;
  70. mesh.position.x = -0.25
  71. //Potree.Utils.setObjectLayers(mesh,'measure')
  72. endCap = new THREE.Object3D()
  73. endCap.add(mesh)
  74. }
  75. let endCaps = []
  76. let material = path.edge.material.clone()
  77. material.map = map
  78. delete material.defines.mapOverlay
  79. for(let i=0;i<2;i++){
  80. let cap = endCap.clone()
  81. cap.children[0].material = material
  82. path.add(cap)
  83. endCaps.push(cap)
  84. }
  85. return endCaps
  86. }
  87. })()
  88. const setMarkerScale = (marker, halfPathWidth)=>{
  89. let s = halfPathWidth * 2.9
  90. marker.scale.set(s,s,s)
  91. }
  92. let fakeMarker
  93. let lastFadeTime
  94. let showFakeMarker = (path, position)=>{//添加marker时指示位置
  95. if(!fakeMarker){
  96. fakeMarker = new THREE.Mesh(planeGeo, getMarkerMat('adding'))
  97. fakeMarker.name = 'fakeMarker'
  98. fakeMarker.renderOrder = Potree.config.renderOrders.path.marker
  99. }
  100. setMarkerScale(fakeMarker, path.halfPathWidth)
  101. path.add(fakeMarker)
  102. fakeMarker.position.copy(position)
  103. Potree.Utils.updateVisible(fakeMarker,'add',true)
  104. viewer.dispatchEvent('content_changed')
  105. return fakeMarker
  106. }
  107. let hideFakeMarker = ()=>{
  108. fakeMarker && Potree.Utils.updateVisible(fakeMarker,'add',false)
  109. lastFadeTime = Date.now()
  110. }
  111. export class Path extends ctrlPolygon{
  112. constructor (prop) {
  113. super('Path', prop);
  114. this.zPlaneWhenNoIntersect = 0 //允许不在model上,直接绘制此高度的水平面上
  115. this.markerLabels = [];
  116. this.points_datasets || (this.points_datasets = []) //存每个点是哪个数据集
  117. this.hoverStates = {}
  118. this.selectStates = {}
  119. this.setFadeFar(null)
  120. this.geoPoints = []
  121. this.lineHeight = prop.lineHeight == void 0 ? titleLineHeight : prop.lineHeight
  122. {
  123. let group = new THREE.Object3D; group.name = 'titleGroup'
  124. this.titleLabel = new TextSprite(Object.assign({}, depthProps,{
  125. text: '', sizeInfo:{width2d:200},
  126. textColor:{r:255,g:255,b:255,a:1.0},
  127. backgroundColor:{r:0,g:0,b:0,a:0.5},
  128. borderRadius: 6,
  129. fontsize: this.fontsize || 13,
  130. renderOrder : Potree.config.renderOrders.path.label,
  131. pickOrder: Potree.config.renderOrders.path.label,
  132. clipDistance : 10,
  133. fadeFar: this.fadeFar,
  134. transform2Dpercent:{x:0,y:0.5}, //向上移动一半
  135. maxLineWidth: 300,
  136. textAlign: Potree.settings.isOfficial && 'left'
  137. }))
  138. this.titleLabel.sprite.material.depthTest = false
  139. let line = LineDraw.createFatLine([new THREE.Vector3(0,0,0), new THREE.Vector3(0,0, this.lineHeight)], Object.assign({},depthProps,{color: '#ffffff', lineWidth: 1, transparent:true, fadeFar: this.fadeFar}))
  140. line.renderOrder = Potree.config.renderOrders.line
  141. line.name = 'line'
  142. this.titleLine = line
  143. group.add(line)
  144. group.add(this.titleLabel)
  145. this.titleLabel.position.z = this.lineHeight
  146. this.add(group);
  147. this.setTitleVisi(this.titleLabel.parent, false, 'noPoint')
  148. this.setTitle(Potree.settings.isOfficial ? '' : 'title' )
  149. if(!dragPointMat){
  150. let map = texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png',()=>{})
  151. dragPointMat = {
  152. default: new THREE.MeshBasicMaterial({
  153. map, transparent:true, color:'#0fe', opacity:0, depthTest:false,
  154. }),
  155. hover: new THREE.MeshBasicMaterial({
  156. map, transparent:true, color:'#0fe', opacity:0.4, depthTest:false,
  157. })
  158. }
  159. }
  160. this.lineDragPoint = new THREE.Mesh(planeGeo, dragPointMat.default) //修改线高度时出现的小圆点
  161. this.lineDragPoint.scale.set(0.15,0.15,0.15);
  162. this.lineDragPoint.name = 'lineDragPoint'
  163. this.lineDragPoint.renderOrder = this.lineDragPoint.pickOrder = 10;
  164. this.titleLabel.add(this.lineDragPoint)
  165. let hoverState = {}, grabbingObject
  166. let setDragPointState = (state)=>{
  167. this.lineDragPoint.material = state ? dragPointMat.hover : dragPointMat.default
  168. this.titleLabel.sprite.material.opacity = state ? 0.5 : 1
  169. }
  170. let autoPointState = ()=>{
  171. setDragPointState(this.editEnable && (hoverState.lineDragPoint || grabbingObject == 'lineDragPoint'))
  172. }
  173. let autoCursor = ()=>{
  174. if(this.editEnable && Object.values(hoverState).some(e=>e)){
  175. CursorDeal.add('hoverGrab')
  176. }else{
  177. CursorDeal.remove('hoverGrab')
  178. }
  179. autoPointState()
  180. }
  181. [line, this.lineDragPoint].forEach(e=>e.addEventListener('mouseover',(e)=>{
  182. hoverState[e.target.name] = 1
  183. autoCursor()
  184. }));
  185. [line, this.lineDragPoint].forEach(e=>e.addEventListener('mouseleave',(e)=>{
  186. hoverState[e.target.name] = 0
  187. autoCursor()
  188. }));
  189. [line, this.lineDragPoint].forEach(e=>e.addEventListener('startDragging',(e)=>{
  190. grabbingObject = e.target.name
  191. this.editEnable && (CursorDeal.add('grabbing'), autoPointState())
  192. }));
  193. [line, this.lineDragPoint].forEach(e=>e.addEventListener('drop',(e)=>{
  194. grabbingObject = null
  195. this.editEnable && (CursorDeal.remove('grabbing'), autoPointState())
  196. }));
  197. [line, this.lineDragPoint].forEach(e=>e.addEventListener('drag',(e)=>{
  198. if(this.editEnable){//一旦用户拖动了title,title就固定了,不再随着path居中
  199. if(e.target.name == 'line'){
  200. let position
  201. if(e.intersect?.location){
  202. position = e.intersect?.location
  203. }else{
  204. let {x,y} = Potree.Utils.getPointerPosAtHeight(0,e.pointer)
  205. position = new THREE.Vector3(x,y,0)
  206. }
  207. this.updateTitlePos(position)
  208. this.dispatchEvent({type:'titlePosChanged', position , root:e.intersect?.pointcloud || e.intersect?.object})
  209. }else if(e.target.name == 'lineDragPoint'){
  210. this.dragLineLen(e)
  211. }
  212. }
  213. }));
  214. }
  215. {//和measure不同的是它的边是连在一起的一整条
  216. this.edge = new THREE.Mesh(voidGeometry, new DepthBasicMaterial( $.extend({}, depthProps,{color: this.color , /* opacity: 0.6, */side:2,/* transparent:true, */fadeFar: this.fadeFar})))
  217. //new THREE.MeshBasicMaterial({depthWrite:false, transparent:true, color:this.color || '#fff', opacity:0.5, side:2}))
  218. this.edge.material.defines.mapOverlay = true
  219. this.add(this.edge)
  220. this.edge.renderOrder = Potree.config.renderOrders.path.edge, //和tag的一样,但为何遮不住它?好在一般底下有一层地面能遮住
  221. this.edge.name = 'pathEdge'
  222. let addHoverEvent = ()=>{
  223. let mouseover = (e) => {
  224. if(this.isNew)return
  225. this.setSelected('hover')
  226. this.hoverStates.edge = true
  227. if(this.addOrRemovePoint && !this.isNew){
  228. CursorDeal.add('pen_addPoint')
  229. }
  230. };
  231. let mouseleave = (e) => {
  232. if(this.isNew)return
  233. this.setSelected('unhover')
  234. this.hoverStates.edge = false
  235. CursorDeal.remove('pen_addPoint')
  236. hideFakeMarker()
  237. };
  238. this.edge.addEventListener('mouseover', mouseover);
  239. this.edge.addEventListener('mouseleave', mouseleave);
  240. this.edge.addEventListener('mousemove', (e)=>{
  241. if(this.addOrRemovePoint && !this.isNew && !this.hoverStates.marker){
  242. let { point } = this.getPosByIntersect(e, 'onlyPoint')
  243. showFakeMarker(this, point)
  244. }
  245. });
  246. this.edge.addEventListener('click',(e)=>{
  247. let now = Date.now()
  248. if(now - this.lastDropTime<100 || this.isNew || e.button !== THREE.MOUSE.LEFT)return ;
  249. if(this.addOrRemovePoint ){
  250. let {index, prevIndex, point} = this.getPosByIntersect(e)
  251. viewer.measuringTool.history.beforeChange(this)
  252. this.addMarker({
  253. index,
  254. point,
  255. dataset_point: this.dataset_points && new THREE.Vector3 , //初始化
  256. points_dataset : this.points_datasets[prevIndex] //使用前一个的
  257. })
  258. this.updateDatasetBelong(index) //获取dataset_point
  259. viewer.measuringTool.history.afterChange(this)
  260. this.updateEdge()
  261. this.hideArrowUntilUpdate()
  262. this.dispatchEvent('changed')
  263. }else{
  264. this.isNew || viewer.measuringTool.isAdding || this.setSelected('click') //viewer.focusOnObject(this, 'measure') //正在添加测量线时不要focus其他线(容易误触)
  265. }
  266. e.consume() //防止后续双击
  267. })
  268. }
  269. this.edge.addEventListener('addHoverEvent', addHoverEvent, {once:true});
  270. if(!this.isNew){
  271. this.edge.dispatchEvent('addHoverEvent')
  272. }
  273. }
  274. {
  275. this.endCaps = getEndCaps(this) //端点处的半圆
  276. }
  277. this.addEventListener('marker_dropped',(e)=>{
  278. this.updateDatasetBelong(e.index)
  279. })
  280. this.setPathWidth(prop.width || 0.2)
  281. this.setColor(prop.color || '#fff')
  282. this.setEditEnable(true)
  283. this.lastDropTime = 0
  284. //Potree.Utils.setObjectLayers(this, 'measure' )
  285. if(!Potree.settings.isOfficial){
  286. this.setAddOrRemPoint(true)
  287. this.addEventListener('createDone',()=>{
  288. this.setAddOrRemPoint(false)
  289. })
  290. this.setArrowDisplay(true)
  291. }
  292. this.initData(prop)
  293. }
  294. updateTitlePos(pos){
  295. if(pos){
  296. this.fixedTitlePos = pos
  297. }else{
  298. if(!this.fixedTitlePos){ //居中
  299. pos = this.getCenter()
  300. }
  301. }
  302. if(pos){
  303. this.titleLabel.parent.position.copy(pos)
  304. this.titleLabel.updatePose()
  305. }
  306. }
  307. getPosByIntersect(e, type){//intersect落在线上的位置,以及在哪两个点之间
  308. if( !Potree.settings.pathSmooth ){
  309. let prevIndex = Math.floor(e.hoveredElement.faceIndex / 2) //端点1(可能是最后一个)
  310. let nextIndex = this.getIndex(prevIndex, 1) //端点2(可能是第一个)
  311. let index = prevIndex + 1 //新点在端点1后
  312. let point = math.getFootPoint(e.hoveredElement.point, this.points[prevIndex], this.points[nextIndex] );
  313. return {index, prevIndex, point }
  314. }else{
  315. let prevIndex0 = Math.floor(e.hoveredElement.faceIndex / 2) //所在的mesh片段的端点1
  316. let nextIndex0 = prevIndex0 + 1 //所在的mesh片段的端点2
  317. let point = math.getFootPoint(e.hoveredElement.point, this.geoPoints[prevIndex0], this.geoPoints[nextIndex0] ); //新点位置
  318. if(type == 'onlyPoint')return {point}
  319. let prevIndex,nextIndex
  320. let count = this.points.length - 1
  321. for(let i=0;i<count;i++){
  322. if(prevIndex == void 0 && i / count <= this.UtoTMapArr[prevIndex0] && (i+1) / count > this.UtoTMapArr[prevIndex0]){
  323. prevIndex = i //该片段端点1在原先points中哪个点之后(可包含)
  324. }
  325. if(nextIndex == void 0 && i / count <= this.UtoTMapArr[nextIndex0] && (i+1) / count > this.UtoTMapArr[nextIndex0]){
  326. nextIndex = i //该片段端点2在原先points中哪个点之后(可包含)
  327. }
  328. }
  329. if(nextIndex == void 0){//最后一个点
  330. nextIndex = count-1
  331. }
  332. if(prevIndex != nextIndex){//端点在不同points区间, 需要判断intersect的究竟在哪个区间
  333. //console.log('跨点', prevIndex, nextIndex)
  334. this.geoPoints[prevIndex]
  335. let lengths = [] //geo端点间包含points哪些点
  336. let j=prevIndex;
  337. let A = this.geoPoints[prevIndex0]
  338. let B = this.geoPoints[nextIndex0]
  339. let APlen = A.distanceTo(point); // 端点->点击点
  340. let AB = new THREE.Vector3().subVectors(B,A)
  341. let searchIndex
  342. while(j <= nextIndex){ //根据APlen长度算区间
  343. let len = AB.clone().normalize().dot(new THREE.Vector3().subVectors(this.points[j+1], A)) //在AB的投影长度
  344. if(len > APlen){
  345. searchIndex = j
  346. break
  347. }
  348. j++
  349. }
  350. searchIndex == void 0 && (searchIndex = nextIndex) //最后一个点之后
  351. prevIndex = searchIndex
  352. }
  353. nextIndex = prevIndex + 1
  354. //console.log(prevIndex, nextIndex)
  355. let index = prevIndex + 1 //新点在端点1后
  356. return {index, prevIndex, point }
  357. }
  358. }//如果后续还出现index错误的问题,可以改为绘制时用折线,完成后用曲线。
  359. createMarkerLabel(text, hasHoverEvent){
  360. const label = new TextSprite(
  361. $.extend( {}, depthProps, {
  362. sizeInfo: labelSizeInfo, name:'markerTitle',
  363. text : "" , fontsize: this.fontsize || 12,
  364. renderOrder : Potree.config.renderOrders.path.label,
  365. pickOrder: Potree.config.renderOrders.path.label,
  366. fontWeight:'',//thick
  367. backgroundColor:{r:255,g:255,b:255,a:0.5},
  368. textColor:{r:0,g:0,b:0,a:1},
  369. fadeFar: this.fadeFar,
  370. maxLineWidth: 300,
  371. transform2D: {x:0,y:0.2}, //朝上偏移一些 配合最外层z混合增高
  372. textAlign: Potree.settings.isOfficial && 'left'
  373. })
  374. )
  375. if(hasHoverEvent){
  376. label.addEventListener('mouseover',()=>{
  377. this.setSelected(true, 'label')
  378. })
  379. label.addEventListener('mouseleave',()=>{
  380. this.setSelected(false, 'label')
  381. })
  382. label.addEventListener('click',()=>{
  383. this.isNew || viewer.measuringTool.isAdding || viewer.focusOnObject(this, 'measure')
  384. })
  385. }
  386. //label.measure = this
  387. //label.sprite.material.depthTestWhenPick = true
  388. //Potree.Utils.setObjectLayers(label, 'measure' )
  389. this.add(label)
  390. return label
  391. }
  392. updateMarker(marker, pos){
  393. marker.position.copy(pos);
  394. marker.position.z += 0.01
  395. let index = this.markers.indexOf(marker)
  396. if(this.markerLabels[index]){
  397. this.markerLabels[index].position.copy(pos)
  398. this.markerLabels[index].position.z += 0.3 //混合增高
  399. this.markerLabels[index].updatePose()
  400. }
  401. }
  402. setPathWidth(w){
  403. let v = w / 2
  404. if(this.halfPathWidth == v)return
  405. this.halfPathWidth = v
  406. this.markers.forEach(e=>setMarkerScale(e, this.halfPathWidth))
  407. this.updateEdge()
  408. this.editEnable || this.updateEndCaps()
  409. this.updateArrowRepeat()
  410. viewer.dispatchEvent('content_changed')
  411. this.hideArrowUntilUpdate()
  412. }
  413. setColor(color){
  414. if(this.color == color)return
  415. this.color = color
  416. let c = new THREE.Color().set(this.color)
  417. this.titleLabel.setTextColor({r: c.r*255, g:c.g*255, b:c.b*255, a:0.5})
  418. this.updateSelectStyle() //apply color
  419. viewer.dispatchEvent('content_changed')
  420. }
  421. setLineHeight(len){
  422. if(len == this.lineHeight)return
  423. this.lineHeight = parseFloat(len)
  424. this.titleLabel.position.z = this.lineHeight
  425. this.titleLabel.updatePose()
  426. LineDraw.updateLine(this.titleLine, [new THREE.Vector3(0,0,0), new THREE.Vector3(0,0,this.lineHeight )])
  427. }
  428. dragLineLen(e){ //拖拽线的顶端修改线长度
  429. let endPos = this.titleLabel.getWorldPosition(new THREE.Vector3)
  430. let normal = new THREE.Vector3(0,0,1)
  431. const projected = endPos.clone().project(e.drag.dragViewport.camera);
  432. projected.x = e.pointer.x
  433. projected.y = e.pointer.y
  434. const unprojected = projected.clone().unproject(e.drag.dragViewport.camera);
  435. let moveVec = new THREE.Vector3().subVectors(unprojected, endPos);
  436. moveVec = moveVec.projectOnVector(normal)
  437. let newLength = Math.max(0, this.lineHeight + moveVec.dot(normal) )
  438. //console.log(moveVec,newLength)
  439. this.setLineHeight(newLength)
  440. this.dispatchEvent('dragLineLen')
  441. }
  442. updateEdge(){
  443. if(this.lastUpdatePoints_ && Potree.Common.ifSame(this.lastUpdatePoints_,this.points) && this.halfPathWidth == this.lastHalfPathWidth) return //没变 不更新
  444. //this.edge.geometry = MeshDraw.getExtrudeGeo(edgeExtrudePoints, null, {extrudePath: this.points, openEnded:true, shapeDontClose:true/* , dontSmooth:true, steps: this.points.length-1 */})
  445. //getExtrudeGeo是平滑过的曲线,和设计不一样,且容易翻转,转角有时候细分过少
  446. //只允许path水平放置
  447. let geo
  448. let points = this.getDifferentPoint(this.points)
  449. let count = points.length
  450. this.edge.geometry.dispose()
  451. if(count <= 1){
  452. geo = voidGeometry
  453. this.geoPoints = []
  454. this.curve = null
  455. }else{
  456. if(Potree.settings.pathSmooth){//使用曲线
  457. let curve = new THREE.CatmullRomCurve3(points, false )
  458. curve.UtoTMapArr = [] //用于存储 getSpacedPoints得到的点对应points的百分比对应
  459. //window.arcLengthDivisions && (curve.arcLengthDivisions = arcLengthDivisions) //默认200,但改为1也没变化呀
  460. count = Math.max(2, Math.round(this.getTotalDistance() * 400)), points = curve.getSpacedPoints(count-1) //拆分为更密集的点
  461. this.curve = curve
  462. //减少点数(拐弯的部分紧凑些,直线部分宽松些):
  463. let lastVec
  464. let newPoints = []
  465. this.UtoTMapArr = []
  466. for(let i=0;i<count;i++){
  467. let point = points[i];
  468. let last = points[i-1]
  469. let next = points[i+1]
  470. if(i == 0 || i == count-1) {
  471. newPoints.push(point) //直接加入
  472. this.UtoTMapArr.push(i == 0 ? 0 : 1)
  473. }
  474. if(i<count-1){
  475. let curVec = new THREE.Vector3().subVectors(next,point)
  476. if(!lastVec) lastVec = curVec
  477. if(i>1){// 和上一个加入点的vec之间的夹角如果过大就加入
  478. if(curVec.angleTo(lastVec) > 0.05){//最小角度
  479. newPoints.push(point)
  480. this.UtoTMapArr.push(curve.UtoTMapArr[i])
  481. lastVec = curVec
  482. }
  483. }
  484. }
  485. }
  486. points = newPoints
  487. count = points.length
  488. //delete curve.UtoTMapArr
  489. }
  490. let lastSideVec
  491. let posArr = [], faceArr = [], uvArr = []
  492. let gatherLen = 0 //累加长度
  493. this.geoPoints = points
  494. //根据点序列计算geometry
  495. for(let i=0; i<count; i++){
  496. let O = points[i] //该点
  497. let A = points[i-1] //上一个点
  498. let B = points[i+1] //下一个点
  499. let p1, p2 //该点两边的折点
  500. let sideVec //该点两边对应的向量
  501. let uvX
  502. if(i==0 || i==count-1){
  503. sideVec = new THREE.Vector3().copy(math.getNormal2d({p1: i==0 ? B : O, p2: i==0 ? O : A})).setZ(0).multiplyScalar(this.halfPathWidth) //垂线
  504. uvX = i==0 ? 0 : 1 //percent of length
  505. }else{
  506. let OA = new THREE.Vector3().subVectors(A,O).setZ(0).normalize() //只保证俯视角度正确。(如果两点有高度差,该段四个点不会在同一平面,看起来有扭转,有的地方会肥大,但从俯视角度看是正确的。)
  507. let OB = new THREE.Vector3().subVectors(B,O).setZ(0).normalize()
  508. let angle = math.getAngle(OA, OB, 'z')
  509. if(math.closeTo(angle,0,1e-4) || math.closeTo(angle,Math.PI,1e-4) || math.closeTo(angle, -Math.PI,1e-4)){ //这时候直接加两个向量算出的平分线不准,故直接找垂线
  510. sideVec = new THREE.Vector3().copy(math.getNormal2d({p1: O, p2: A})).setZ(0).multiplyScalar(this.halfPathWidth) //垂线
  511. //console.log('接近0或180',angle, sideVec)
  512. }else{
  513. let midVecLength = this.halfPathWidth / Math.sin(angle/2)
  514. sideVec = new THREE.Vector3().addVectors(OA,OB).normalize().multiplyScalar(midVecLength) //角平分线 ( 和上一个方向保持在同一侧,故而顺时针和逆时针方向不同 )
  515. }
  516. gatherLen += O.distanceTo(A)
  517. uvX = gatherLen / this.totalLength //目前为止的长度占比
  518. }
  519. let P1 = new THREE.Vector3().addVectors(O, sideVec)
  520. let P2 = new THREE.Vector3().subVectors(O, sideVec)
  521. posArr.push(P1, P2)
  522. uvArr.push({x:uvX,y:0},{x:uvX,y:1})
  523. if(i<count-1){
  524. faceArr.push([i*2,i*2+1,i*2+3],[i*2,i*2+3,i*2+2])//每一段两个三角形 013 032
  525. }
  526. lastSideVec = sideVec
  527. }
  528. geo = MeshDraw.createGeometry(posArr, faceArr, uvArr)
  529. this.updateArrowRepeat()
  530. }
  531. this.edge.geometry = geo
  532. this.lastHalfPathWidth = this.halfPathWidth
  533. this.lastUpdatePoints_ = this.points.map(e=>e.clone())
  534. }//不使用curve的曲线是因为那种geo点数较多,且改的话不知道updateArrows怎么改,除非变为贴图,但就和需求中需要调节间距违背。
  535. update(options={}) {
  536. if(options.index == -1)return
  537. super.update(options) //updateEdge marker
  538. this.points.length<=1 && this.updateEdge() //补偿上一句
  539. this.editEnable || this.updateEndCaps()
  540. {
  541. let oldVisi = this.titleLabel.parent.visible
  542. this.setTitleVisi(this.titleLabel.parent, this.markers.length>0, 'noPoint')
  543. if(this.titleLabel.parent.visible && !oldVisi)this.titleLabel.updatePose()
  544. }
  545. this.updateTitlePos()
  546. };
  547. addMarker(o={}) {
  548. var index = o.index == void 0 ? this.points.length : o.index //要当第几个
  549. let marker = new THREE.Mesh(planeGeo, getMarkerMat('default'))
  550. marker.name = 'marker'
  551. setMarkerScale(marker,this.halfPathWidth)
  552. marker.markerSelectStates = {}
  553. //Potree.Utils.setObjectLayers(marker, 'measure' )
  554. marker.renderOrder = Potree.config.renderOrders.path.marker
  555. marker.addEventListener('mouseover',(e)=>{
  556. if(this.addOrRemovePoint && !this.isNew){
  557. CursorDeal.add('pen_delPoint')
  558. //hideFakeMarker()
  559. }
  560. this.hoverStates.marker = marker
  561. }/* ,{importance:1} */)
  562. marker.addEventListener('mouseleave',(e)=>{
  563. CursorDeal.remove('pen_delPoint')
  564. marker == this.hoverStates.marker && (this.hoverStates.marker = null)
  565. })
  566. marker.addEventListener('click',(e)=>{
  567. if(this.isNew || e.button !== THREE.MOUSE.LEFT )return
  568. if(this.addOrRemovePoint ){//点击删除点
  569. this.removePoint(this.markers.indexOf(marker))
  570. }else{//点击选中点
  571. this.dispatchEvent({type:'markerSelect', marker})
  572. this.setMarkerSelected(marker, 'click' );
  573. setTimeout(()=>{
  574. viewer.addEventListener('global_click', (e)=>{ //点击空白处取消全部
  575. if(e.clickElement?.oriObject == marker)return
  576. this.dispatchEvent({type:'markerSelect', marker, cancel:true})
  577. this.setMarkerSelected(marker, 'unclick' );
  578. }, {once:true} )
  579. },10)
  580. }
  581. e.consume()
  582. })
  583. marker.addEventListener('startDragging',(e)=>{
  584. this.isNew || this.setMarkerSelected(marker, 'click' ); //选中
  585. this.isNew || viewer.measuringTool.history.beforeChange(this)
  586. this.arrows && Potree.Utils.updateVisible(this.arrows, 'dragging', false)
  587. //Potree.Common.waitTool.cancel('pathUpdateArrowDelay')
  588. })
  589. marker.addEventListener('drop',(e)=>{
  590. if(!this.isNew && this.arrows){
  591. Potree.Utils.updateVisible(this.arrows, 'dragging', true)
  592. Path.updateArrows(true)
  593. }
  594. //this.hideArrowUntilUpdate()
  595. if( e.button != THREE.MOUSE.LEFT )return
  596. viewer.inputHandler.dispatchEvent({type: 'measuring', v:false, cause:'stopDragging', situation:'dragging', object:this} )
  597. this.lastDropTime = Date.now()
  598. this.isNew || viewer.measuringTool.history.afterChange(this)
  599. this.setMarkerSelected(marker, 'unclick' );
  600. })
  601. let label = this.createMarkerLabel('')
  602. this.markerLabels = [...this.markerLabels.slice(0,index), label, ...this.markerLabels.slice(index, this.points.length)]
  603. this.setMarkerTitle(index, Potree.settings.isOfficial ? '' : 'point')
  604. super.addMarker(Object.assign(o, {index, marker }))
  605. //this.updateEdge()
  606. return marker
  607. };
  608. updateEndCaps(){
  609. let len = this.points.length
  610. let pts = this.geoPoints.length>0 ? this.geoPoints : this.points
  611. let len2 = pts.length
  612. this.endCaps.forEach((e,i)=>{
  613. Potree.Utils.updateVisible(e, 'hasPoints', len>0)
  614. if(len){
  615. if(len>1){
  616. let dir = i==0 ? new THREE.Vector3().subVectors(pts[1], pts[0])
  617. : new THREE.Vector3().subVectors(pts[len2-2], pts[len2-1])
  618. e.quaternion.copy(getMeshQuaInPath(dir))
  619. }else{
  620. i==0 ? e.quaternion.set(0,0,0,1) : e.quaternion.set(0,0,1,0) //两个半圆拼成一个圆点
  621. }
  622. e.position.copy(this.points[i==0 ? 0 : len-1])
  623. let s = this.halfPathWidth * 2.15
  624. e.scale.set(s,s,s)
  625. }
  626. })
  627. }
  628. setEditEnable(state){//是否显示可修改控件
  629. this.editEnable = !!state
  630. this.markers.forEach(e=>Potree.Utils.updateVisible(e,'editEnable', this.editEnable))
  631. this.endCaps.forEach((e,i)=>Potree.Utils.updateVisible(e,'editEnable', !this.editEnable))
  632. if(markerMats){//因为marker材质每条path都共用,所以isOfficial时请保证只有一条在编辑
  633. for(let i in markerMats){
  634. markerMats[i].fadeFar = this.fadeFar
  635. }
  636. }
  637. if(!state){
  638. this.updateEndCaps()
  639. }
  640. viewer.dispatchEvent('content_changed')
  641. }
  642. setAddOrRemPoint(state){//是否可以加减点, 此时不能拖拽marker
  643. this.addOrRemovePoint = !!state
  644. this.updateCursorState()
  645. }
  646. updateCursorState(){//可能在hover时修改addOrRemovePoint,也可能从marker和edge之间切换, 主要是addOrRemovePoint开关时要记得之前的hover状态
  647. CursorDeal[this.addOrRemovePoint ? 'add':'remove']('pen')
  648. if(this.addOrRemovePoint && !this.isNew){
  649. CursorDeal[this.hoverStates.edge ? 'add' : 'remove']('pen_addPoint')
  650. CursorDeal[this.hoverStates.marker ? 'add' : 'remove']('pen_delPoint')
  651. }else{
  652. CursorDeal.remove('pen_addPoint')
  653. CursorDeal.remove('pen_delPoint')
  654. }
  655. }
  656. setTitleVisi(label, v, reason=''){
  657. Potree.Utils.updateVisible(label, 'hideTitle-'+reason, v)
  658. viewer.dispatchEvent('content_changed')
  659. }
  660. setTitle(title=''){
  661. this.title = title
  662. this.titleLabel.setText(title)
  663. this.setTitleVisi(this.titleLabel.parent, title instanceof Array || title.trim() != '', 'noText')
  664. viewer.dispatchEvent('content_changed')
  665. }
  666. setMarkerTitle(index, title){
  667. if(!this.markerLabels[index])return
  668. this.markerLabels[index].originText = title
  669. this.markerLabels[index].setText(title)
  670. this.setTitleVisi(this.markerLabels[index], title instanceof Array || title.trim() != '', 'noText')
  671. viewer.dispatchEvent('content_changed')
  672. }
  673. editStateChange(state){ //拖动时被调用
  674. super.editStateChange(state)
  675. if(!state){
  676. this.editStateTimer = setTimeout(()=>{
  677. if(!this.isEditing){
  678. this.dispatchEvent({type:'editStateChange',state:false})
  679. }
  680. },100)
  681. }else{
  682. if(!this.isEditing){
  683. this.dispatchEvent({type:'editStateChange',state:true})
  684. clearTimeout(this.editStateTimer)
  685. }
  686. }
  687. this.isEditing = state
  688. }
  689. removePoint(index){
  690. if(index == -1){
  691. return //双击会这样,加了迅速删除, 可能因为没来得及删
  692. }
  693. viewer.measuringTool.history.beforeChange(this)
  694. this.removeMarker(index)
  695. this.hideArrowUntilUpdate()
  696. viewer.measuringTool.history.afterChange(this)
  697. this.dispatchEvent('changed')
  698. if(this.points.length == 0){
  699. //viewer.measuringTool.changeToAddState(this)
  700. viewer.measuringTool.startInsertion({resume:true, measure:this})
  701. }
  702. }
  703. setMarkerSelected(marker, state ){
  704. state == 'hover' && (marker.markerSelectStates.hover = true )
  705. state == 'unhover' && (marker.markerSelectStates.hover = false )
  706. state == 'click' && (marker.markerSelectStates.click = true ) //click or drag
  707. state == 'unclick' && (marker.markerSelectStates.click = false )
  708. if(marker.markerSelectStates.click){
  709. marker.material = getMarkerMat('drag')
  710. marker.renderOrder = marker.pickOrder = Potree.config.renderOrders.path.marker +1
  711. }else if(marker.markerSelectStates.hover){
  712. marker.material = getMarkerMat(this.addOrRemovePoint ? 'delete' : 'drag')
  713. marker.renderOrder = marker.pickOrder = Potree.config.renderOrders.path.marker +1
  714. }else{
  715. marker.material = getMarkerMat('default')
  716. marker.renderOrder = marker.pickOrder = Potree.config.renderOrders.path.marker
  717. }
  718. //marker.selected = absoluteState
  719. viewer.mapViewer && viewer.mapViewer.dispatchEvent('content_changed')
  720. viewer.dispatchEvent('content_changed')
  721. }
  722. setSelected( state, byList){
  723. if(state == 'click' && this.selectStates.click) return this.setSelected('unclick') //重复点击了
  724. state == 'hover' && (this.selectStates.hover = true, byList||this.dispatchEvent({type:'highlight', state:true}), CursorDeal.add('pointer'))
  725. state == 'unhover' && (this.selectStates.hover = false, byList||this.dispatchEvent({type:'highlight', state:false}), CursorDeal.remove('pointer'))
  726. state == 'click' && (this.selectStates.click = true, byList||this.dispatchEvent({type:'chose', state:true}) )
  727. state == 'unclick' && (this.selectStates.click = false, byList||this.dispatchEvent({type:'chose', state:false}) )
  728. /* this.arrows?.material.color.set(this.selectStates.click ? '#ffffff' : this.color);
  729. ([this.edge, this.endCaps[0].children[0]].forEach(e=>{
  730. e.material.opacity = this.selectStates.click ? 1 : this.selectStates.hover ? 0.8 : 0.6
  731. e.material.color.set(this.selectStates.click ? '#00C8AF' : this.color)
  732. })) */
  733. this.updateSelectStyle()
  734. state == 'click' && setTimeout(()=>{
  735. viewer.addEventListener('global_click', (e)=>{ //再点击取消
  736. this.setSelected('unclick')
  737. }, {once:true} )
  738. },10)
  739. viewer.dispatchEvent('content_changed')
  740. viewer.mapViewer && viewer.mapViewer.dispatchEvent('content_changed')
  741. }
  742. updateSelectStyle(){
  743. let c = new THREE.Color().set(this.color).getHSL({ h: 0, s: 0, l: 0 })
  744. let color, arrowColor
  745. if(this.selectStates.click){
  746. color = '#00C8AF'
  747. arrowColor = '#ffffff'
  748. }else if(this.selectStates.hover){
  749. color = new THREE.Color().setHSL(c.h, c.s, c.l - 0.1 )
  750. arrowColor = new THREE.Color().setHSL(c.h, c.s, c.l >= 0.4 ? c.l - 0.3 : c.l + 0.3 )
  751. }else{
  752. arrowColor = new THREE.Color().setHSL(c.h, c.s, c.l >= 0.4 ? c.l - 0.3 : c.l + 0.3 )
  753. color = this.color
  754. }
  755. if(this.arrows){
  756. this.arrows.material.color.set(arrowColor);
  757. }else{
  758. this.edge.material.uniforms.mapColor.value.set(arrowColor)
  759. }
  760. ([this.edge, this.endCaps[0].children[0]].forEach(e=>{
  761. e.material.color.set(color)
  762. }))
  763. }
  764. removeMarker(index ){
  765. super.removeMarker(index)
  766. this.points_datasets.splice(index, 1);
  767. this.dataset_points && this.dataset_points.splice(index, 1)
  768. let labelIndex = index
  769. if(this.markerLabels[labelIndex]){
  770. this.markerLabels[labelIndex].dispose()
  771. this.markerLabels.splice(labelIndex, 1);
  772. }
  773. this.update({index: this.getIndex(index, -1)});
  774. this.dispatchEvent({type: 'marker_removed', measurement: this});
  775. }
  776. setPosition(index, position) {
  777. super.setPosition(index, position)
  778. let event = {
  779. type: 'marker_moved',
  780. measure: this,
  781. index: index,
  782. position: position.clone()
  783. };
  784. this.dispatchEvent(event);
  785. }
  786. setFontSize(fontsize){
  787. this.fontsize = fontsize
  788. this.markerLabels.concat(this.titleLabel).forEach(e=>{
  789. e.fontsize = fontsize
  790. e.updateTexture();
  791. })
  792. viewer.dispatchEvent('content_changed')
  793. }
  794. setFadeFar(far){//消失距离
  795. if(far == void 0) far = 0 //不设置
  796. this.traverse((e)=>{
  797. //if(e.name == 'marker')return //因为marker材质共用的所以不改。因此正式编辑时(有marker时)别设置消失距离。
  798. if(e.material?.uniforms?.fadeFar){
  799. e.material.fadeFar = far
  800. }
  801. })
  802. this.fadeFar = far
  803. if(markerMats){//因为marker材质每条path都共用,所以isOfficial时请保证只有一条在编辑
  804. for(let i in markerMats){
  805. markerMats[i].fadeFar = this.fadeFar
  806. }
  807. }
  808. viewer.dispatchEvent('content_changed')
  809. }
  810. dispose(){
  811. super.dispose()
  812. this.titleLabel.dispose()
  813. this.markerLabels.forEach(e=>e.dispose())
  814. this.arrows?.dispose()
  815. this.arrows?.material.dispose()
  816. this.edge.geometry.dispose()
  817. this.edge.material.dispose()
  818. this.setAddOrRemPoint(false) //cursor recover
  819. this.dispatchEvent('disposed')
  820. }
  821. updateArrowRepeat(){
  822. if(!this.edge.material.map)return
  823. this.edge.material.map.repeat.x = Math.round(this.totalLength / this.halfPathWidth * 0.5) * (this.reverse ? -1 : 1)
  824. this.edge.material.map.needsUpdate = true
  825. this.edge.material.setUV()
  826. }
  827. setArrowDisplay(show){
  828. if(Potree.settings.pathSmooth){
  829. if(show){
  830. let map = texLoader.load( Potree.resourcePath+'/textures/arrow.png',()=>{
  831. viewer.dispatchEvent('content_changed')
  832. })
  833. map.anisotropy = 2
  834. map.wrapS = THREE.RepeatWrapping
  835. map.repeat.set(10,1.3)
  836. map.offset.set(0,-0.15)
  837. this.edge.material.map = map
  838. this.updateArrowRepeat()
  839. }else{
  840. this.edge.material.map?.dispose()
  841. this.edge.material.map = null
  842. }
  843. }else{
  844. if(show){
  845. if(!this.arrows){
  846. let map = texLoader.load( Potree.resourcePath+'/textures/arrow.png')
  847. //map.anisotropy = 2
  848. map.generateMipmaps = false;
  849. map.minFilter = THREE.LinearFilter //防止边缘黑边, 但会造成锯齿
  850. let material = new DepthBasicMaterial(Object.assign({}, depthProps, {
  851. map, transparent:true, side:2, fadeFar:this.fadeFar , color:this.selectStates.click ? '#ffffff' : this.color
  852. }))
  853. //let material = new THREE.MeshBasicMaterial({map )})
  854. this.arrows = new THREE.InstancedMesh(planeGeo, material, arrowCountMax); //会自动向shader添加define和instanceMatrix
  855. this.arrows.renderOrder = Potree.config.renderOrders.path.edge
  856. this.add(this.arrows)
  857. //Potree.Utils.setObjectLayers(this.arrows, 'measure' )
  858. }
  859. this.updateSelectStyle()
  860. }
  861. if(this.arrows){
  862. Potree.Utils.updateVisible(this.arrows, 'show', show)
  863. show && Path.waitUpdateArrows()
  864. }
  865. }
  866. viewer.dispatchEvent('content_changed')
  867. }
  868. setReverse(reverse){
  869. if(this.reverse != reverse){
  870. this.reverse = reverse
  871. if(Potree.settings.pathSmooth){
  872. this.updateArrowRepeat()
  873. }else{
  874. Path.updateArrows(true)
  875. }
  876. }
  877. }
  878. hideArrowUntilUpdate(){
  879. this.arrows && Potree.Utils.updateVisible(this.arrows, 'changing', false)
  880. Path.waitUpdateArrows()
  881. }
  882. static waitUpdateArrows(){
  883. if(Potree.settings.pathSmooth)return
  884. Potree.Common.waitTool.wait('pathUpdateArrowDelay',()=>{
  885. viewer.scene.measurements.forEach(e=>e instanceof Path && e.arrows && Potree.Utils.updateVisible(e.arrows, 'changing', true) )
  886. Path.updateArrows(true)
  887. viewer.dispatchEvent('content_changed')
  888. },300) //为了防止不停点击不停更新,所以隐藏一下不变了再更新
  889. }
  890. static updateArrows(force){
  891. //console.error('updateArrows?')
  892. const far = math.linearClamp(Potree.fpsRendered2, [10, 60], [200, 300]); //几乎看不见了
  893. let paths = viewer.scene.measurements.filter(e=>e instanceof Path && e.arrows?.visible)
  894. let waitAdd = []
  895. let minDisSq = Infinity
  896. let startTime = performance.now()
  897. let lines = []
  898. paths.forEach(path=>{
  899. let len = path.points.length
  900. let far_ = path.halfPathWidth * far
  901. far_ = path.fadeFar ? Math.min(far_, path.fadeFar * 1.2) : far_
  902. let farSquared_ = far_ * far_
  903. for(let i=0; i<len-1; i++){
  904. let thisPoint = path.points[i];
  905. let nextPoint = path.points[i+1]
  906. let line = new THREE.Line3(thisPoint, nextPoint)
  907. let closetPoint = line.closestPointToPoint( viewer.mainViewport.view.position, true, new THREE.Vector3() ) //过相机到line的垂足,限制在线段内
  908. let disSq = closetPoint.distanceToSquared(viewer.mainViewport.view.position)
  909. if(disSq > farSquared_ && lastArrowCount > 0)continue
  910. minDisSq = Math.min(minDisSq, disSq)
  911. lines.push({line, disSq, path})
  912. }
  913. })
  914. let spaceDis = THREE.Math.clamp( math.toPrecision(Math.pow(minDisSq, 0.1) * 5, 1), 5, 15) //箭头之间的间距,适当调节稀疏
  915. spaceDis *= math.linearClamp(Potree.fpsRendered2, [10, 60], [3, 1])
  916. if((lastArrowCamPos && math.closeTo(lastArrowCamPos, viewer.mainViewport.view.position, 2) || lines.length == 0) && !force)return //很远的时候lines空的不更新(不清空)
  917. lastArrowCamPos = viewer.mainViewport.view.position.clone()
  918. viewer.scene.measurements.forEach(e=>e instanceof Path && e.arrows && (e.arrows.count = 0)) //归零
  919. lines.sort((a,b)=>{return a.disSq - b.disSq}) //尽快收集好就近的,使后加的都比waitAdd最后一个大,减少比较
  920. lines.forEach(info=>{
  921. if(waitAdd[arrowCountMax-1] && info.disSq > waitAdd[arrowCountMax-1].disSq)return //线段最近点已经超过当前list中最远的那个
  922. info.dir = new THREE.Vector3().subVectors(info.line.end, info.line.start).normalize()
  923. let lineLen = info.line.end.distanceTo(info.line.start)
  924. let spaceDis_ = info.path.halfPathWidth * spaceDis //跟随箭头缩放
  925. let sliceCount = Math.round( lineLen / spaceDis_) //分段
  926. if(sliceCount < 1) return;
  927. if(sliceCount == 1) sliceCount = 2//至少为2
  928. let arrowCount = sliceCount - 1
  929. let sliceLen = lineLen / sliceCount
  930. let j = arrowCount
  931. while(j > 0){
  932. let pos = info.line.start.clone().add(info.dir.clone().multiplyScalar(j*sliceLen))
  933. let disSq = pos.distanceToSquared(viewer.mainViewport.view.position)
  934. j--;
  935. if(waitAdd[arrowCountMax-1] && disSq > waitAdd[arrowCountMax-1].disSq)continue
  936. //按从小到大排好。(不知道这种事先排好序的方法 和全部加入最后排序选前面的 相比哪个耗时。 因为冒泡排序更快,但如果总数很多会不会慢?)
  937. let newItem = {pos, disSq, lineInfo:info}
  938. let index = waitAdd.findIndex(e=>e.disSq>disSq)
  939. if(index == -1){
  940. waitAdd.push(newItem)
  941. }else{
  942. waitAdd = [...waitAdd.slice(0,index), newItem, ...waitAdd.slice(index, waitAdd.length)]
  943. }
  944. waitAdd.length>arrowCountMax && waitAdd.pop()
  945. }
  946. })
  947. let scaleMap = new Map
  948. waitAdd.forEach((e,i)=>{
  949. let scaleQuaMatrix = e.lineInfo.scaleQuaMatrix
  950. if(!scaleQuaMatrix){
  951. let scaleMatrix = scaleMap.get(e.lineInfo.path)
  952. if(!scaleMatrix){
  953. let s = e.lineInfo.path.halfPathWidth * 1.6
  954. scaleMatrix = new THREE.Matrix4().scale(new THREE.Vector3((e.lineInfo.path.reverse ? -1 : 1 ) *s,s,s))
  955. scaleMap.set(e.lineInfo.path, scaleMatrix)
  956. }
  957. let qua = getMeshQuaInPath(e.lineInfo.dir)//math.getQuaFromPosAim( new THREE.Vector3, e.lineInfo.dir ).multiply(quaBase)
  958. let quaMatrix = new THREE.Matrix4().makeRotationFromQuaternion(qua)
  959. scaleQuaMatrix = e.lineInfo.scaleQuaMatrix = new THREE.Matrix4().multiplyMatrices(quaMatrix, scaleMatrix)
  960. }
  961. let matrix = scaleQuaMatrix.clone().setPosition(e.pos)
  962. e.lineInfo.path.arrows.count ++
  963. e.lineInfo.path.arrows.setMatrixAt(e.lineInfo.path.arrows.count-1, matrix)
  964. e.lineInfo.path.arrows.instanceMatrix.needsUpdate = true;
  965. })
  966. lastArrowCount = waitAdd.length
  967. //console.log('updateArrows spaceDis', spaceDis, 'count', waitAdd.length, 'cost', performance.now() - startTime)
  968. }
  969. }
  970. Path.prototype.cloneMarker = Measure.prototype.cloneMarker
  971. Path.prototype.updateDatasetBelong = Measure.prototype.updateDatasetBelong
  972. Path.prototype.reDraw = Measure.prototype.reDraw
  973. /*
  974. 没有intersect的点的dataset_point怎么赋值
  975. 1 lonlat : 因为说是加在地图上。 但万一用户在添加完path之后才设置经纬度,这个点可能就飘到很远的地方? 由于模型当前的位置都是本地坐标而不是经纬度,所以模型不会跟着一起飘远。
  976. 2 就近的datasetId : 但如果path全部点都在地图上, 现场只有一个离他远的模型,但它仍被判断在该模型上。之后在路径边加了其他模型。 当它的所属模型被删除后它就像意外消失了……
  977. 3 本地坐标 : 当模型移动后该点不会跟着移动。 写起来比上一条麻烦点,但逻辑不容易误解。
  978. 目前用的3
  979. */
  980. /*
  981. const plane = new THREE.Plane(normal, dis);
  982. viewer.renderer.localClippingEnabled = true;
  983. material.clippingPlanes = [ localPlane ]
  984. #include <clipping_planes_pars_fragment>
  985. #include <clipping_planes_fragment>
  986. */