Path.js 48 KB

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