Measure.js 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744
  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} from "../../utils/DrawUtil.js";
  6. import math from "../../utils/math.js";
  7. import DepthBasicMaterial from "../../materials/DepthBasicMaterial.js";
  8. import BasicMaterial from '../../materials/BasicMaterial.js'
  9. import Sprite from '../Sprite.js'
  10. import {config} from '../../settings.js'
  11. import browser from "../../utils/browser.js";
  12. import {ctrlPolygon} from './ctrlPolygon.js'
  13. let texLoader = new THREE.TextureLoader()
  14. let defaultColor = new THREE.Color(config.measure.default.color);
  15. let highlightColor = new THREE.Color(config.measure.highlight.color);
  16. let color = new THREE.Color(config.measure.color)
  17. let textColor = new THREE.Color(config.measure.textColor)
  18. let markerMaps
  19. const textSizeRatio = math.linearClamp(window.outerWidth * window.outerHeight , [360*720, 1920*1080], [0.7, 1]) //pc字显示大一些 用
  20. const lineDepthInfo = {
  21. clipDistance : 15,//4,//消失距离
  22. occlusionDistance: 3,//1,//变为backColor距离
  23. }
  24. const markerMapShrink = browser.isMobile() ? 0.4 : 0.8 //触屏需要更大的热区
  25. const markerSizeInfo = {
  26. width2d : 18 / markerMapShrink , // nearBound : 1.5, farBound : 15,
  27. }
  28. /* const markerSizeInfo = {
  29. minSize : 10 , maxSize : 15 , nearBound : 1.5, farBound : 15,
  30. } */
  31. const labelSizeInfo = {width2d:200}
  32. const mainLabelProp = {
  33. //backgroundColor: {r: defaultColor.r*255, g: defaultColor.g*255, b: defaultColor.b*255, a:config.measure.default.opacity},
  34. backgroundColor: {r: 0, g: 0, b: 0, a:0},
  35. textColor: {r: textColor.r*255, g: textColor.g*255, b: textColor.b*255, a: 1.0},
  36. textBorderColor: {r:255, g: 255, b:255, a: 1.0},
  37. textBorderThick:3 ,
  38. fontsize: 14 * textSizeRatio,
  39. borderRadius : 12, margin:{x:20,y:4},
  40. renderOrder : Potree.config.renderOrders.measureLabel,
  41. pickOrder: Potree.config.renderOrders.measureLabel,
  42. transform2D: {x:0, y:-0.15},
  43. useDepth : true ,
  44. // 2023.10 尽量不让数字被挡住
  45. clipDistance : 10,//消失距离
  46. occlusionDistance: 10,//变为backColor距离
  47. maxOcclusionFactor:0.3,
  48. maxClipFactor:0.8,
  49. maxLineWidth: 300,
  50. lineSpace:6
  51. }
  52. const subLabelProp = {
  53. backgroundColor: {r: 255, g: 255, b: 255, a:0},
  54. textColor: {r: textColor.r*255, g: textColor.g*255, b: textColor.b*255, a: 1.0},
  55. textBorderColor: {r:255, g: 255, b:255, a: 1.0},
  56. textBorderThick:3 ,
  57. fontsize: 13 * textSizeRatio,
  58. renderOrder : Potree.config.renderOrders.measureLabelSub,
  59. pickOrder: Potree.config.renderOrders.measureLabelSub,
  60. transform2D: {x:0, y:-0.13},
  61. }
  62. const angle = THREE.Math.degToRad(config.measure.guideLineMinAngle || 5); //显示水平垂直辅助线的最小角度
  63. const guideShowMinAngle = {min: angle, max: Math.PI/2 - angle}
  64. export class Measure extends ctrlPolygon{
  65. constructor (prop) {
  66. prop.dimension = '2d'
  67. super('measure',prop);
  68. this.constructor.counter = (this.constructor.counter === undefined) ? 0 : this.constructor.counter + 1;
  69. this.name = this.name || this.measureType + this.constructor.counter
  70. this.selectStates = {}
  71. this.edgeLabels = [];
  72. this.coordinateLabels = [];
  73. this.area = {value:0,string:''}
  74. this.expands = []
  75. if( this.showArea ){
  76. this.areaLabel = this.createAreaLabel();
  77. this.add(this.areaLabel)
  78. }
  79. //add:
  80. if(this.atPlane || this.faceDirection){ //是一个平面上的话
  81. this.createGuideLine();
  82. }
  83. if(this.measureType == 'Distance' /* || this.measureType.includes('MulDistance') */){
  84. this.createHorVerGuideLine()
  85. }
  86. this.setUnitSystem(prop.unit || viewer.unitConvert.UnitService.defaultSystem)
  87. //Potree.Utils.setObjectLayers(this, 'measure' ) //取消:scene单独渲染应该不需要设置layer
  88. if(this.measureType == 'MulDistance' || this.measureType == 'Hor MulDistance' || this.measureType == 'Ver MulDistance'){
  89. //this.showTotalDis = true
  90. this.totalDisLabel = this.createTotalDisLabel()
  91. this.add(this.totalDisLabel)
  92. }
  93. //addMarkers:
  94. this.initData(prop)
  95. this.pointsPos2d = new Map //屏幕上的二维坐标
  96. this.points_datasets || (this.points_datasets = []) //存每个点是哪个数据集
  97. this.addEventListener('marker_dropped',(e)=>{
  98. this.updateDatasetBelong(e.index)
  99. })
  100. this.addEventListener('isVisible', ()=>{
  101. viewer.mapViewer && viewer.mapViewer.dispatchEvent({type:'content_changed'})
  102. })
  103. this.lastDropTime = 0
  104. }
  105. initData(prop){
  106. let makeIt = super.initData(prop)
  107. if(makeIt){
  108. this.edges.forEach(edge=>{edge.dispatchEvent('addHoverEvent') })
  109. }else{
  110. this.failBuilded = true
  111. }
  112. if(prop.expands){ //基本不会从这加
  113. for(let data of prop.expands){
  114. this.addExpand(data)
  115. }
  116. }
  117. }
  118. updateDatasetBelong(changeIndex){//更新所属数据集
  119. if(Potree.settings.editType == "merge" || this.measureType == 'MulDistance Ring'){//点直接跟着数据集走,不用找整体的datasetId
  120. this.dataset_points[changeIndex] = Potree.Utils.datasetPosTransform({toDataset:true, datasetId:this.points_datasets[changeIndex], position:this.points[changeIndex].clone()})
  121. return
  122. }
  123. let old = this.datasetId
  124. let maxCount = {id:null,count:0}
  125. let datasets = {}
  126. this.points_datasets.forEach(e=>{
  127. if(e == void 0)return
  128. if(datasets[e]){
  129. datasets[e] ++
  130. }else{
  131. datasets[e] = 1
  132. }
  133. })
  134. for(let i in datasets) {
  135. if(datasets[i]>maxCount.count){
  136. maxCount = {id:i, count:datasets[i]}
  137. }
  138. }
  139. this.datasetId = maxCount.count > 0 ? maxCount.id : null
  140. //if(this.datasetId != old){
  141. //this.dispatchEvent({type:'changeDatasetId'})
  142. if(this.datasetId == void 0){
  143. this.dataset_points = null //可能为空或[null,null...]
  144. }else{
  145. this.dataset_points = this.points.map(e=>{
  146. return Potree.Utils.datasetPosTransform({toDataset:true,datasetId:this.datasetId, position:e.clone()})
  147. })
  148. }
  149. //}
  150. }
  151. transformByPointcloud(){//每次移动点云 or 加载测量线时要获取一下当前position //有地图时
  152. if(this.datasetId == void 0)return
  153. this.points = this.dataset_points.map(e=>{
  154. return Potree.Utils.datasetPosTransform({fromDataset:true, datasetId:this.datasetId, position:e.clone()})
  155. })
  156. this.getPoint2dInfo(this.points)
  157. this.update({ifUpdateMarkers:true})
  158. this.setSelected(false)//隐藏edgelabel
  159. }
  160. changeColor(color){
  161. this.color = color //'#ffffff'
  162. this.edges.forEach(e=>e.material = this.getMat('edgeDefault')) //update
  163. this.markers.forEach(e=>e.material = this.getMat('markerDefault'))
  164. this.areaPlane && (this.areaPlane.material = this.getMat('planeDefault') )
  165. this.expands.forEach(e=>e.edges.forEach(a=>a.material = this.getMat('edgeExpand')))
  166. viewer.dispatchEvent('content_changed')
  167. }
  168. update(options={}) {
  169. if(options.index == -1)return
  170. super.update(options)
  171. if(this.showCoordinates && this.points.length>0){
  172. let position = this.points[0];
  173. this.markers[0].position.copy(position);
  174. { // coordinate labels
  175. let coordinateLabel = this.coordinateLabels[0];
  176. let pos = [
  177. position.toArray()
  178. ]
  179. if(viewer.transform){
  180. let lonlat = viewer.transform.lonlatToLocal.inverse(position.toArray())
  181. let EPSG4550 = viewer.transform.lonlatTo4550.forward(lonlat)
  182. pos.push(lonlat,EPSG4550)
  183. }
  184. //let msg = position.toArray().map(p => Utils.addCommas(p.toFixed(2))).join(" / ");
  185. let msg = pos.map(a=>
  186. a.map(p => Utils.addCommas(p.toFixed(10))).join(", ")
  187. ).join("<br>")
  188. coordinateLabel.setText(msg);
  189. coordinateLabel.setPos(position)
  190. coordinateLabel.setVisible(true)//this.showCoordinates;
  191. }
  192. return
  193. }
  194. let setEdgeLabel = (label,p1,p2,distance,type)=>{//设置label位置和字
  195. this.setEdgeLabelPos(label,p1,p2)
  196. distance = distance == void 0 ? p1.distanceTo(p2) : distance;
  197. //var text = viewer.unitConvert.convert(distance, 'distance', Potree.settings.precision, this.unitSystem, 1 , true)//distance要传0.1 这个factor
  198. var text = this.getConvertString(distance, 'distance')
  199. this.showArea || type == 'addTitle' && (text = this.labelAddName(text))
  200. label.setText(text)
  201. return distance
  202. }
  203. let lastIndex = this.points.length - 1
  204. let setLabel = (index)=>{
  205. if(index == null)return
  206. let previousIndex = this.getIndex(index, -1)
  207. let nextIndex = this.getIndex(index, +1)
  208. let previousPoint = this.points[previousIndex];
  209. let point = this.points[index];
  210. let nextPoint = this.points[nextIndex];
  211. if(this.showDistances ){ // edge labels
  212. let edgeLabel = this.edgeLabels[index];
  213. let distance = nextPoint && point.distanceTo(nextPoint)
  214. this.edges[index].distance_ = distance
  215. edgeLabel.shouldVisi = nextPoint && (index < lastIndex || this.isRect || this.closed && !this.isNew ) && distance>0
  216. //this.closed || edgeLabel.setVisible(edgeLabel.shouldVisi) //closed的在setEdgesDisplay中设置
  217. Utils.updateVisible(edgeLabel, 'shouldVisi', edgeLabel.shouldVisi, 2)
  218. if(edgeLabel.shouldVisi){
  219. edgeLabel.lineDir = new THREE.Vector3().subVectors(point,nextPoint).normalize() //[point,nextPoint]
  220. setEdgeLabel(edgeLabel,point,nextPoint,distance, this.measureType != 'MulDistance' && 'addTitle')
  221. }
  222. }
  223. }
  224. if(options.index != void 0){//更新第几个点
  225. setLabel(options.index)
  226. let previousIndex = this.getIndex(options.index, -1)
  227. setLabel(previousIndex)
  228. }else{
  229. for (let index = 0; index <= lastIndex; index++) {
  230. setLabel(index)
  231. }
  232. }
  233. if(Potree.config.measure.mulLabelHideFaraway ){
  234. this.measureType == 'MulDistance' && this.clearEdgeLabelVisi()
  235. }
  236. if(this.measureType == 'Distance' && this.points.length>1){//设置水平垂直辅助线
  237. var pTop, pBtm
  238. if(this.points[0].z > this.points[1].z ){
  239. pTop = this.points[0];
  240. pBtm = this.points[1];
  241. }else{
  242. pTop = this.points[1];
  243. pBtm = this.points[0];
  244. }
  245. let projectPos = new THREE.Vector3(pTop.x, pTop.y, pBtm.z);//两条guideline的交点
  246. {//倾斜角度太小的时候不显示
  247. let tan = pTop.distanceTo(projectPos) / pBtm.distanceTo(projectPos)
  248. let angle = Math.atan(tan);
  249. this.shouldShowHorVerGuide = angle > guideShowMinAngle.min && angle < guideShowMinAngle.max
  250. if(this.showAngleToGround){
  251. let deg = math.toPrecision(THREE.Math.radToDeg(angle), 2) + '°'
  252. this.angleToGroundLabel.setText(deg)
  253. let vec1 = new THREE.Vector3().subVectors(pTop,pBtm).normalize()
  254. let vec2 = new THREE.Vector3().subVectors(projectPos,pBtm).normalize()
  255. let midVec = new THREE.Vector3().addVectors(vec1,vec2).normalize()
  256. //this.angleToGroundLabel.lineDir = midVec
  257. this.angleToGroundLabel.setPos(new THREE.Vector3().addVectors(pBtm, midVec.clone().multiplyScalar(0.15) ))
  258. // 最好是让label垂直于midVec然后transform2Dpercent向上,这样无论向左看向右看都可以,但字斜着不直观
  259. //绘制夹角弧线(省略成直线)
  260. let midDis = 0.1
  261. let sideLen = midDis * Math.cos(angle / 2)
  262. let p1 = new THREE.Vector3().addVectors(pBtm, vec1.multiplyScalar(sideLen))
  263. let p2 = new THREE.Vector3().addVectors(pBtm, vec2.multiplyScalar(sideLen))
  264. LineDraw.updateLine(this.angleLine, [p1, p2])
  265. this.angleLine.visible = this.angleToGroundLabel.visible = this.shouldShowHorVerGuide
  266. }
  267. }
  268. LineDraw.updateLine(this.verGuideEdge, [pTop, projectPos])
  269. LineDraw.updateLine(this.horGuideEdge, [pBtm, projectPos])
  270. setEdgeLabel(this.verEdgeLabel,pTop,projectPos)
  271. setEdgeLabel(this.horEdgeLabel,pBtm,projectPos)
  272. this.verGuideEdge.visible = this.horGuideEdge.visible = this.shouldShowHorVerGuide
  273. this.verEdgeLabel.visible = this.horEdgeLabel.visible = this.shouldShowHorVerGuide
  274. }
  275. if(this.showArea && this.points.length > 2){ // update area
  276. let msg = this.getArea().string
  277. msg = this.labelAddName(msg)
  278. this.areaLabel.setPos(this.getCenter('areaPlaneCenter'))
  279. this.areaLabel.setText(msg);
  280. Utils.updateVisible(this.areaLabel, 'setVisible', true) //this.areaLabel.setVisible(true)
  281. }
  282. if(this.totalDisLabel){
  283. this.ifShowTotalDis()
  284. Utils.updateVisible(this.totalDisLabel,'setVisible', this.showTotalDis)
  285. this.edgeLabels.forEach(e=> Utils.updateVisible(e, 'showTotalDis', !this.showTotalDis))
  286. if(this.showTotalDis){
  287. let dis = this.getTotalDistance()
  288. let msg = this.getConvertString(dis, 'distance')
  289. msg = this.labelAddName(msg)
  290. this.center = null
  291. this.center = this.getCenter()
  292. this.totalDisLabel.setPos(this.center);
  293. this.totalDisLabel.setText(msg);
  294. }
  295. }
  296. this.expands.forEach(e=>e.update(options))
  297. };
  298. labelAddName(msg){
  299. if(Potree.config.measure.showName && this.title?.trim()){
  300. msg = [this.title,msg]
  301. }
  302. return msg
  303. }
  304. getArea(){
  305. let area
  306. if(this._area != void 0){
  307. area = this._area
  308. }else if(this.point2dInfo){
  309. area = Math.abs(math.getArea(this.point2dInfo.points2d))//this.getArea();
  310. }else{//mulDistance Ring 2d面
  311. area = Math.abs(math.getArea(this.points))
  312. }
  313. let msg = this.getConvertString(area, 'area')
  314. //let msg = viewer.unitConvert.convert(area, 'area', Potree.settings.precision, this.unitSystem/* , 0.1 */ )
  315. this.area = {value:area, string:msg}
  316. return this.area
  317. }
  318. getConvertString(num, type){
  319. return viewer.unitConvert.convert(num, type, Potree.settings.precision, this.unitSystem, true ,
  320. {
  321. 'imperial': {minFactor: 0.01 },
  322. 'metric': {minFactor: 0.01}
  323. }
  324. )
  325. }
  326. ifShowTotalDis(){
  327. let show = this.points.length > 2
  328. if(show){
  329. let maxDis = 0.15
  330. let lastIndex = this.points.length - 1;
  331. for(let i=0;i<lastIndex;i++){
  332. let len = this.edges[i].distance_
  333. if(len > maxDis){
  334. show = false; break;
  335. }
  336. }
  337. }
  338. this.showTotalDis = show
  339. /* 连续测量:
  340. 1. ≥2次测量,单个距离<15cm时,居中显示总长, hover、选中时显示每段长度
  341. 2. 若连续测量的线段中,大于等于1段超出15cm,所有线段均显示长度
  342. -------------------
  343. */
  344. }
  345. clearEdgeLabelVisi(){//修改点位置后清空,下次render时会自动getEdgeLabelVisi
  346. let lastIndex = this.points.length - 1;
  347. for (let index = 0; index <= lastIndex; index++) {
  348. if(!this.closed && index == lastIndex)continue
  349. let edgeLabel = this.edgeLabels[index];
  350. edgeLabel.visiMap.clear()
  351. }
  352. }
  353. getEdgeLabelVisi(viewport){//获取多折线的edgelabel在不同视图里的可见性。要保证任何时候label能出现的线最小二维长度一致
  354. let camera = viewport.camera
  355. let lastIndex = this.points.length - 1;
  356. /* let pos2ds = this.points.map(point=> point.clone().project(camera) ) //即使只是旋转也会变动,尤其是转到屏幕外后变为显示。所以不用这种
  357. let minDis = 0.01; */
  358. let minDis = 0.02 , minAngleRatio = 0.07, minAngle
  359. let vecs
  360. let forceShow
  361. if(camera.type == 'OrthographicCamera'){
  362. minDis *= Math.pow(camera.top / camera.zoom, 2);
  363. //console.log(minDis)
  364. }else{
  365. if(Potree.settings.displayMode == 'showPanos' && viewer.images360.zoomLevel == Potree.settings.zoom.max){
  366. forceShow = true //当zoom到最大时强制显示,避免有的线太短永远显示不出长度
  367. }else{
  368. vecs = this.points.map(point=> new THREE.Vector3().subVectors(point, camera.position).normalize())
  369. minAngleRatio /= viewport.resolution.y / 1000 / textSizeRatio //角度占fov最小比率
  370. minAngle = minAngleRatio * THREE.Math.degToRad(camera.fov)
  371. }
  372. }
  373. for (let index = 0; index <= lastIndex; index++) {
  374. if(!this.closed && index == lastIndex)continue
  375. let edgeLabel = this.edgeLabels[index];
  376. let nextIndex = (index + 1 > lastIndex) ? 0 : index + 1;
  377. let previousIndex = (index === 0) ? lastIndex : index - 1;
  378. let point = this.points[index];
  379. let nextPoint = this.points[nextIndex];
  380. /* let point2d = pos2ds[index];
  381. let nextPoint2d = pos2ds[nextIndex];
  382. let dis2d = point2d.distanceToSquared(nextPoint2d)
  383. let v = dis2d > minDis //可见长度太小,为避免拥挤,不显示
  384. edgeLabel.visiMap.set(camera, v) */
  385. let v
  386. if(forceShow){
  387. v = true
  388. }else if(camera.type == 'OrthographicCamera'){
  389. let vec = new THREE.Vector3().subVectors(point,nextPoint)
  390. let projVec = vec.projectOnPlane(viewport.view.direction)
  391. v = projVec.lengthSq() > minDis
  392. }else{
  393. let vec0 = vecs[index];
  394. let vec1 = vecs[nextIndex];
  395. v = Math.acos(vec0.dot(vec1)) > minAngle //角度过小代表可见长度太小,为避免拥挤,不显示
  396. }
  397. edgeLabel.visiMap.set(camera, v)
  398. }
  399. }
  400. setEdgeLabelPos(label,p1,p2){ //调整label的位置,使倾斜后看起来在线的中心,而不要挡住端点
  401. let center = new THREE.Vector3().addVectors(p1,p2).multiplyScalar(0.5);
  402. return label.setPos(center)
  403. if(label.lineDir && label.lineDir.length() > 0){
  404. if(viewer.mainViewport.camera.type == 'OrthographicCamera'){
  405. label.setPos(center)
  406. }else{
  407. //根据视线和线的夹角(后又加入相机和两个端点距离差)来决定标签偏移位置。+
  408. let eyePos = viewer.mainViewport.camera.position;
  409. let dir = viewer.mainViewport.view.direction //new THREE.Vector3().subVectors(center,eyePos).normalize()
  410. /*let centerDir = new THREE.Vector3().subVectors(center,eyePos).normalize()
  411. if(centerDir.dot(dir)<0){//中点在相机后方,就不设置
  412. label.setPos(center)
  413. return
  414. } */
  415. let cos = dir.dot(label.lineDir)
  416. let nearPoint = cos > 0 ? p2 : p1 //近端点。
  417. let far = cos > 0 ? p1 : p2 //远端点。
  418. let nearPointDir = new THREE.Vector3().subVectors(nearPoint,eyePos)//.normalize()
  419. //使label在中点和近端点中变化, 近端点可能到了相机后方,需要投影到相机所在平面上
  420. if(nearPointDir.dot(dir)<0){//近端点到了相机后方,前移。
  421. //let hfov = cameraLight.getHFOVForCamera(viewer.mainViewport.camera , true ); //暂且只看水平fov
  422. //if(nearPointDir.dot(dir)<Math.cos(hfov/2)){//近端点在镜头外,前移。 --但是这个就得把点转化成在镜头边缘而非左右两边(camDirPlane上)
  423. let ray = new THREE.Raycaster()
  424. ray.set(nearPoint, cos>0?label.lineDir:label.lineDir.clone().negate())
  425. let camDirPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(dir, eyePos)
  426. nearPoint = ray.ray.intersectPlane(camDirPlane, new THREE.Vector3())
  427. if(!nearPoint){//线是垂直的,视线是水平的时候
  428. return label.setPos(center)
  429. }
  430. }
  431. //防止离远了之后也偏移很多,但远了之后相机到端点vec和到中点的vec的夹角接近,不需要怎么偏移的。
  432. let dis1 = nearPoint.distanceToSquared(eyePos)
  433. let dis2 = far.distanceToSquared(eyePos)
  434. let diff = Math.abs(dis1/dis2)
  435. diff<1 && (diff = 1/diff)
  436. diff = math.linearClamp(diff,[0, 30], [ 0,1 ])
  437. let efficiency = 0.7; // 0-1 数值越高,r越容易接近1或-1,label越容易在倾斜后靠近近端点。
  438. //let r = 0.5*efficiency*cos + 0.5
  439. let r = 0.5*efficiency*diff*cos + 0.5
  440. r = THREE.Math.clamp(r,0.1,0.9)
  441. //视线越接近线的方向,标签应该越往近端点偏移,防止看起来几乎在远端。
  442. if(cos > 0){
  443. center = p1.clone().multiplyScalar(1-r).add(nearPoint.clone().multiplyScalar(r)); //label在线上滑动,使尽量保持在视觉中心
  444. }else{
  445. center = nearPoint.clone().multiplyScalar(1-r).add(p2.clone().multiplyScalar(r)); //label在线上滑动,使尽量保持在视觉中心
  446. }
  447. label.setPos(center)
  448. }
  449. //归零
  450. //this.orient2dInfo = null
  451. //this.markers.forEach(e=>e.needsUpdate=true)
  452. }else{
  453. label.setPos(center)
  454. }
  455. }
  456. cloneMarker(cloneIndex, index){
  457. return this.addMarker({
  458. index,
  459. point: this.points[cloneIndex],
  460. dataset_point:this.dataset_points && this.dataset_points[cloneIndex],
  461. points_dataset:this.points_datasets[cloneIndex]
  462. })
  463. }
  464. addMarker (o={}) {
  465. var index = o.index == void 0 ? this.points.length : o.index //要当第几个
  466. let marker = o.marker || new Sprite({mat:this.getMat('markerDefault'), sizeInfo: markerSizeInfo, name:"measure_point"} )
  467. //Potree.Utils.setObjectLayers(marker, 'measure' )
  468. marker.pickOrder = marker.renderOrder = Potree.config.renderOrders.measureMarker
  469. marker.markerSelectStates = {}
  470. marker.addEventListener('startDragging',(e)=>{
  471. /* if(e.drag.dragViewport.name == 'MainView') */viewer.inputHandler.dispatchEvent( {type: 'measuring',v:true, cause:'startDragging', situation:'dragging', object:this})
  472. //add for 调试,方便后期增加点
  473. if(!this.isNew && viewer.inputHandler.pressedKeys['M'.charCodeAt(0)] && this.points.length<this.maxMarkers){
  474. viewer.measuringTool.history.beforeChange(this)
  475. let curIndex = this.markers.indexOf(marker)
  476. this.cloneMarker(curIndex, curIndex+1)
  477. }
  478. this.isNew || viewer.measuringTool.history.beforeChange(this)
  479. })
  480. marker.addEventListener('drop',(e)=>{
  481. if( e.button != THREE.MOUSE.LEFT )return
  482. viewer.inputHandler.dispatchEvent({type: 'measuring', v:false, cause:'stopDragging', situation:'dragging', object:this} )
  483. this.lastDropTime = Date.now()
  484. if(Potree.settings.adsorption){
  485. this.isNew || viewer.viewports.forEach((viewport)=>{
  486. this.getPointsPos2d(viewport, true )//forceUpdate
  487. })
  488. }
  489. this.isNew || viewer.measuringTool.history.afterChange(this)
  490. })
  491. marker.addEventListener('click',()=>{
  492. if(viewer.measuringTool.editMode == 'delPoint' ){
  493. /* if(this.points.length == this.minMarkers){//--前端去重绘
  494. viewer.scene.removeMeasurement(this)
  495. }else{ */
  496. viewer.measuringTool.history.beforeChange(this)
  497. let index = this.markers.indexOf(marker)
  498. this.removeMarker(index)
  499. viewer.measuringTool.history.afterChange(this)
  500. this.dispatchEvent('changed')
  501. //}
  502. }
  503. })
  504. //marker.measure = this
  505. let edge
  506. { // edges
  507. edge = o.edge || LineDraw.createFatLine( [ ],{mat:this.getMat('edgeDefault')} )
  508. edge.pickOrder = 0
  509. //Potree.Utils.setObjectLayers(edge, 'measure' )
  510. let addHoverEvent = ()=>{ //当非isNew时才添加事件
  511. let mouseover = (e) => {
  512. /* if(this.measureType == 'MulDistance'){
  513. } */
  514. this.setSelected(true, 'edge')
  515. };
  516. let mouseleave = (e) => {
  517. this.setSelected(false, 'edge')
  518. };
  519. edge.addEventListener('mouseover', mouseover);
  520. edge.addEventListener('mouseleave', mouseleave);
  521. edge.removeEventListener('addHoverEvent', addHoverEvent);
  522. edge.addEventListener('click',(e)=>{
  523. let now = Date.now()
  524. if(now - this.lastDropTime<100)return ;//防止拖拽marker时误触导致focus, 以及点到marker不focus
  525. if(viewer.measuringTool.editMode == 'addPoint' && this.points.length < this.maxMarkers){
  526. viewer.measuringTool.history.beforeChange(this)
  527. let index = this.edges.indexOf(edge) + 1
  528. let nextIndex = index % this.edges.length
  529. let point = math.getFootPoint(e.hoveredElement.point, this.points[index-1], this.points[nextIndex] );
  530. this.addMarker({
  531. index,
  532. point,
  533. dataset_point: this.dataset_points && new THREE.Vector3 , //初始化
  534. points_dataset : this.points_datasets[index-1] //使用前一个的
  535. })
  536. this.updateDatasetBelong(index) //获取dataset_point
  537. viewer.measuringTool.history.afterChange(this)
  538. this.dispatchEvent('changed')
  539. //this.update({})
  540. }else{
  541. this.isNew || viewer.measuringTool.isAdding || viewer.focusOnObject(this, 'measure') //正在添加测量线时不要focus其他线(容易误触)
  542. }
  543. })
  544. }
  545. edge.addEventListener('addHoverEvent', addHoverEvent);
  546. if(!this.isNew){
  547. edge.dispatchEvent('addHoverEvent')
  548. }
  549. }
  550. super.addMarker(Object.assign(o, {index, marker, edge}))
  551. if(this.showEdges){ // edge labels
  552. const edgeLabel = this.createEdgeLabel('edgeLabel', !this.closed)
  553. this.edgeLabels = [...this.edgeLabels.slice(0,index), edgeLabel, ...this.edgeLabels.slice(index,this.edgeLabels.length)]
  554. }
  555. if(this.showCoordinates){ // coordinate labels
  556. let coordinateLabel = new Label({
  557. className:'measure_pointPos',
  558. camera: viewer.scene.getActiveCamera()
  559. })
  560. coordinateLabel.setVisible(false)
  561. this.coordinateLabels.push(coordinateLabel);
  562. }
  563. let event = {
  564. type: 'marker_added',
  565. measurement: this,
  566. marker: marker
  567. };
  568. this.dispatchEvent(event);
  569. this.expands.forEach(e=>e.addMarker(o))
  570. //this.setMarker(this.points.length - 1, point);
  571. this.update({index})//更新一下倒数第二条线
  572. return marker;//add
  573. };
  574. editStateChange(state){ //主要针对edgeLabels显示切换,编辑时显示
  575. super.editStateChange(state)
  576. if(!state){
  577. this.editStateTimer = setTimeout(()=>{
  578. if(!this.isEditing){
  579. this.dispatchEvent({type:'editStateChange',state:false})
  580. this.setEdgesDisplay(false)
  581. this.areaPlane && Potree.Utils.updateVisible(this.areaPlane, 'intersectLastLine', true)
  582. this.areaLabel && Potree.Utils.updateVisible(this.areaLabel, 'intersectLastLine', true)
  583. }
  584. },100)
  585. }else{
  586. if(!this.isEditing){
  587. this.dispatchEvent({type:'editStateChange',state:true})
  588. this.setEdgesDisplay(true)
  589. clearTimeout(this.editStateTimer)
  590. }
  591. }
  592. this.isEditing = state
  593. }
  594. setMarkerSelected(marker, state, hoverObject){
  595. //console.warn(marker.id , state, hoverObject)
  596. marker.markerSelectStates[hoverObject] = state
  597. let absoluteState = false
  598. for(var i in marker.markerSelectStates){
  599. if(marker.markerSelectStates[i] == 'hover'){
  600. absoluteState = true; break;
  601. }
  602. }
  603. if(absoluteState){
  604. marker.material = this.getMat('markerSelect')
  605. marker.renderOrder = marker.pickOrder = Potree.config.renderOrders.measureMarker+1
  606. }else{
  607. marker.material = this.getMat('markerDefault')
  608. marker.renderOrder = marker.pickOrder = Potree.config.renderOrders.measureMarker
  609. }
  610. marker.selected = absoluteState
  611. viewer.mapViewer && viewer.mapViewer.dispatchEvent('content_changed')
  612. viewer.dispatchEvent('content_changed')
  613. }
  614. setEdgesDisplay(state, ignoreGuideLine){
  615. this.closed && this.edgeLabels.forEach(e=>Utils.updateVisible(e,'hover',state))
  616. if(this.totalDisLabel && !viewer.screenshoting){
  617. this.edgeLabels.forEach(e=> Utils.updateVisible(e, 'hover', state, 1, state ? 'add' : 'cancel'))
  618. Utils.updateVisible(this.totalDisLabel,'hover', !state )
  619. }
  620. if(!this.horVerShowAlways && !ignoreGuideLine && this.measureType == 'Distance'){
  621. this.horEdgeLabel.visible = this.verEdgeLabel.visible = this.horGuideEdge.visible = this.verGuideEdge.visible = !!(state && this.shouldShowHorVerGuide)
  622. if(this.showAngleToGround){
  623. this.angleToGroundLabel.visible = this.angleLine.visible = !!(state && this.shouldShowHorVerGuide)
  624. }
  625. }
  626. }
  627. setSelected(state, hoverObject){//add
  628. //console.log('setSelected',state, hoverObject)
  629. let absoluteState = !!state
  630. if(hoverObject){//如果没有hoverObject且state为false 就强制取消选中态
  631. this.selectStates[hoverObject] = state
  632. for(var i in this.selectStates){
  633. if(this.selectStates[i]){
  634. absoluteState = true; break;
  635. }
  636. }
  637. }
  638. if(absoluteState){
  639. this.markers.forEach(e=>this.setMarkerSelected(e, 'hover', 'selectAll' ) )
  640. this.edges.forEach(e=>{
  641. e.renderOrder = Potree.config.renderOrders.line + 1
  642. e.material = this.getMat('edgeSelect')
  643. })
  644. this.areaPlane && (this.areaPlane.material = this.getMat('planeSelected'))
  645. //this.areaLabel && this.areaLabel.elem.addClass('highLight')
  646. //this.closed || this.edgeLabels.forEach(e=>e.elem.addClass('highLight') )
  647. this.setEdgesDisplay(true, hoverObject=="screenshot")
  648. this.areaLabel && setLabelHightState(this.areaLabel, true)
  649. this.closed || this.edgeLabels.forEach(e=>setLabelHightState(e, true) )
  650. }else{
  651. this.markers.forEach(e=>this.setMarkerSelected(e, 'unhover', 'selectAll' ))
  652. this.edges.forEach(e=>e.material = this.getMat('edgeDefault') )
  653. this.areaPlane && (this.areaPlane.material = this.getMat('planeDefault'))
  654. this.setEdgesDisplay(false, hoverObject=="screenshot")
  655. //this.areaLabel && this.areaLabel.elem.removeClass('highLight')
  656. //this.closed || this.edgeLabels.forEach(e=>e.elem.removeClass('highLight') )
  657. this.areaLabel && setLabelHightState(this.areaLabel, false)
  658. this.closed || this.edgeLabels.forEach(e=>setLabelHightState(e, false) )
  659. }
  660. this.selected = absoluteState
  661. if(hoverObject != 'byList'){
  662. //this.bus && this.bus.emit('highlight', this.selected)
  663. this.dispatchEvent({type:'highlight',state:this.selected})//列表高亮
  664. }
  665. viewer.dispatchEvent('content_changed')
  666. viewer.mapViewer && viewer.mapViewer.dispatchEvent('content_changed')
  667. }
  668. removeMarker(index ){
  669. super.removeMarker(index)
  670. this.points_datasets.splice(index, 1);
  671. this.dataset_points && this.dataset_points.splice(index, 1)
  672. this.coordinateLabels.splice(index, 1);
  673. let edgeIndex = index//(index === 0) ? 0 : (index - 1);
  674. if(this.edgeLabels[edgeIndex]){
  675. this.edgeLabels[edgeIndex].dispose()
  676. this.edgeLabels.splice(edgeIndex, 1);
  677. }
  678. this.expands.forEach(e=>e.removeMarker(index))
  679. this.closed || this.points.length && (this.edges[this.points.length-1].visible = false)
  680. this.update({index: this.getIndex(index, -1)});
  681. this.dispatchEvent({type: 'marker_removed', measurement: this});
  682. }
  683. setPosition(index, position) {
  684. super.setPosition(index, position)
  685. let event = {
  686. type: 'marker_moved',
  687. measure: this,
  688. index: index,
  689. position: position.clone()
  690. };
  691. this.dispatchEvent(event);
  692. }
  693. dispose(){//add
  694. var labels = this.edgeLabels.concat(this.coordinateLabels)
  695. this.areaLabel && labels.push(this.areaLabel)
  696. labels.forEach(e=>e.dispose())
  697. this.expands.forEach(e=>e.dispose())
  698. this.expands.length = 0
  699. super.dispose()
  700. this.dispatchEvent('disposed')
  701. }
  702. getAngleBetweenLines (cornerPoint, point1, point2) {
  703. let v1 = new THREE.Vector3().subVectors(point1, cornerPoint);
  704. let v2 = new THREE.Vector3().subVectors(point2, cornerPoint);
  705. // avoid the error printed by threejs if denominator is 0
  706. const denominator = Math.sqrt( v1.lengthSq() * v2.lengthSq() );
  707. if(denominator === 0){
  708. return 0;
  709. }else{
  710. return v1.angleTo(v2);
  711. }
  712. };
  713. getAngle (index) {
  714. if (this.points.length < 3 || index >= this.points.length) {
  715. return 0;
  716. }
  717. let previous = (index === 0) ? this.points[this.points.length - 1] : this.points[index - 1];
  718. let point = this.points[index];
  719. let next = this.points[(index + 1) % (this.points.length)];
  720. return this.getAngleBetweenLines(point, previous, next);
  721. }
  722. // updateAzimuth(){
  723. // // if(this.points.length !== 2){
  724. // // return;
  725. // // }
  726. // // const azimuth = this.azimuth;
  727. // // const [p0, p1] = this.points;
  728. // // const r = p0.distanceTo(p1);
  729. // }
  730. createGuideLine(){//add 辅助线
  731. var guideLine = LineDraw.createFatLine([ ],{mat:this.getMat('edgeGuide')} )
  732. guideLine.visible = false
  733. this.guideLine = guideLine
  734. this.add(guideLine);
  735. }
  736. createHorVerGuideLine(){//创建水平与垂直辅助线,仅距离测量有。
  737. var verGuideEdge = LineDraw.createFatLine([ ],{mat:this.getMat('edgeGuide')} )
  738. verGuideEdge.visible = false
  739. this.verGuideEdge = verGuideEdge
  740. verGuideEdge.name = 'verGuideEdge'
  741. var horGuideEdge = LineDraw.createFatLine([ ],{mat:this.getMat('edgeGuide')} )
  742. horGuideEdge.visible = false
  743. horGuideEdge.name = 'horGuideEdge'
  744. this.horGuideEdge = horGuideEdge
  745. this.add(this.verGuideEdge);
  746. this.add(this.horGuideEdge);
  747. //label:
  748. this.verEdgeLabel = this.createEdgeLabel('verGuideEdge')
  749. this.horEdgeLabel = this.createEdgeLabel('horGuideEdge')
  750. if(this.showAngleToGround){
  751. this.angleToGroundLabel = new TextSprite(
  752. $.extend({}, subLabelProp, {
  753. sizeInfo: labelSizeInfo, name:'angleToGroundLabel', transform2D:null
  754. })
  755. )
  756. this.angleLine = LineDraw.createFatLine([ ],{mat:this.getMat('angle')} )
  757. this.add(this.angleToGroundLabel)
  758. this.add(this.angleLine)
  759. }
  760. }
  761. createEdgeLabel(name, hasHoverEvent){
  762. let inf = {
  763. sizeInfo: labelSizeInfo, name:name||'edgeLabel',
  764. }
  765. if(name && name.includes('Guide')){
  766. inf.fontsize = 12
  767. }
  768. const edgeLabel = new TextSprite(
  769. $.extend({}, hasHoverEvent ? mainLabelProp : subLabelProp, inf)
  770. )
  771. if(hasHoverEvent){
  772. edgeLabel.addEventListener('mouseover',()=>{
  773. this.setSelected(true, 'edgeLabel')
  774. })
  775. edgeLabel.addEventListener('mouseleave',()=>{
  776. this.setSelected(false, 'edgeLabel')
  777. })
  778. edgeLabel.addEventListener('click',(e)=>{
  779. this.isNew || viewer.measuringTool.isAdding || e.button == THREE.MOUSE.LEFT && viewer.focusOnObject(this, 'measure')
  780. })
  781. }
  782. edgeLabel.visible = false
  783. edgeLabel.measure = this
  784. edgeLabel.sprite.material.depthTestWhenPick = true
  785. //Potree.Utils.setObjectLayers(edgeLabel, 'measure' )
  786. this.add(edgeLabel)
  787. if(this.measureType == 'MulDistance'){
  788. edgeLabel.visiMap = new Map()
  789. }
  790. return edgeLabel
  791. }
  792. createAreaLabel(){
  793. const areaLabel = this.createCenterLabel('areaLabel')
  794. return areaLabel;
  795. }
  796. createTotalDisLabel(){
  797. const totalDisLabel = this.createCenterLabel('totalDisLabel')
  798. return totalDisLabel;
  799. }
  800. createCenterLabel(name){
  801. const centerLabel = new TextSprite(
  802. $.extend({},mainLabelProp,{sizeInfo: labelSizeInfo, name, transform2D:null, fontsize:16*textSizeRatio} )
  803. )
  804. centerLabel.addEventListener('mouseover',()=>{
  805. this.isNew || this.setSelected(true, 'centerLabel')
  806. })
  807. centerLabel.addEventListener('mouseleave',()=>{
  808. this.isNew || this.setSelected(false, 'centerLabel')
  809. })
  810. centerLabel.addEventListener('click',()=>{
  811. this.isNew || viewer.measuringTool.isAdding || viewer.focusOnObject(this, 'measure')
  812. })
  813. //Potree.Utils.setObjectLayers(centerLabel, 'measure' )
  814. Utils.updateVisible(centerLabel, 'setVisible', false)
  815. return centerLabel;
  816. }
  817. getMat(type) {
  818. if(!Measure.Mats){ //不变色的部分
  819. Measure.Mats = {
  820. edgeGuide: LineDraw.createFatLineMat($.extend({},lineDepthInfo,{
  821. color:config.measure.guide.color,
  822. dashSize: 0.1,
  823. gapSize: 0.02,
  824. dashed: true,
  825. lineWidth: config.measure.lineWidth/2
  826. })),
  827. angle: LineDraw.createFatLineMat($.extend({},lineDepthInfo,{
  828. color:config.measure.guide.color,
  829. lineWidth: config.measure.lineWidth/2
  830. })),
  831. multiColors:{}
  832. }
  833. {
  834. markerMaps = [texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png' ), //pic_point_s32
  835. texLoader.load(Potree.resourcePath+'/textures/pic_point32.png' )]
  836. markerMaps.forEach(map=>{
  837. map.repeat.set(1/markerMapShrink,1/markerMapShrink)
  838. map.offset.set((markerMapShrink-1)/2/markerMapShrink, (markerMapShrink-1)/2/markerMapShrink)
  839. })
  840. markerMaps[0].minFilter = 1006 //禁黑边
  841. }
  842. }
  843. let mat = Measure.Mats[type]
  844. let multiColors = Measure.Mats.multiColors
  845. //console.log('getMat', this.name, this.color, type)
  846. if(!mat){
  847. let colorObject = multiColors[this.color]
  848. if(!colorObject){
  849. let c = new THREE.Color().set(this.color).getHSL({ h: 0, s: 0, l: 0 })
  850. let expandColor = new THREE.Color().setHSL(c.h, c.s, c.l >= 0.4 ? c.l - 0.3: c.l + 0.3)
  851. let expandSelectedColor = new THREE.Color().setHSL(c.h, c.s > 0.5 ? c.s - 0.2 : c.s + 0.2, c.l >= 0.6 ? c.l - 0.1 : c.l + 0.1 )
  852. colorObject = {
  853. edgeDefault: LineDraw.createFatLineMat($.extend({},lineDepthInfo,{
  854. color: this.color || config.measure.default.color,
  855. lineWidth: config.measure.lineWidth,
  856. useDepth :true,
  857. dashWithDepth :true, // 只在被遮住的部分显示虚线,因为实线容易挡住label
  858. dashed :true,
  859. dashSize : 0.04,
  860. gapSize: 0.04,
  861. transparent: true,
  862. opacity: config.measure.default.opacity,
  863. depthTestWhenPick:true,
  864. })),
  865. edgeSelect: LineDraw.createFatLineMat($.extend({},lineDepthInfo,{
  866. color: this.color || config.measure.highlight.color,//'#f0ff00',
  867. dashSize: 0.5,
  868. gapSize: 0.2,
  869. lineWidth: config.measure.lineWidth ,
  870. transparent: true,
  871. opacity: config.measure.highlight.opacity
  872. })),
  873. edgeExpand : LineDraw.createFatLineMat($.extend({},lineDepthInfo,{
  874. color: expandColor,
  875. useDepth :true,
  876. lineWidth: 2 ,
  877. transparent: true,
  878. opacity: config.measure.default.opacity,
  879. })),
  880. 'edgeExpand-selected': LineDraw.createFatLineMat($.extend({},lineDepthInfo,{
  881. color: expandSelectedColor,
  882. useDepth :true,
  883. lineWidth: 2 ,
  884. transparent: true,
  885. opacity: config.measure.highlight.opacity,
  886. })),
  887. markerDefault: new DepthBasicMaterial($.extend({},lineDepthInfo,{
  888. transparent: !0,
  889. opacity: 1,
  890. map: markerMaps[0] ,
  891. useDepth:true ,
  892. color: this.color,
  893. //mapScale: markerMapShrink
  894. })),
  895. markerSelect: new BasicMaterial({
  896. transparent: !0,
  897. opacity: 1,
  898. depthTest:false,
  899. map: markerMaps[1],
  900. }),
  901. planeDefault : new DepthBasicMaterial( $.extend({},lineDepthInfo,{
  902. color : this.color || color,
  903. side:THREE.DoubleSide,
  904. opacity:0.2,
  905. transparent:true,
  906. useDepth:true,
  907. })),
  908. planeSelected: new THREE.MeshBasicMaterial({
  909. color: this.color || color,
  910. side:THREE.DoubleSide,
  911. opacity:0.3,
  912. transparent:true,
  913. //wireframe:true
  914. })
  915. }
  916. colorObject.markerSelect.defines.replaceColor = '' //将绿色部分替换成color
  917. colorObject.markerSelect.uniforms.newMapColor = {type:'v3', value: new THREE.Color(this.color)}
  918. colorObject.markerSelect.onBeforeCompile = function ( shader ) {
  919. shader.fragmentShader = shader.fragmentShader
  920. .replace( 'uniform sampler2D map;', `uniform sampler2D map; uniform vec3 newMapColor;` )//将图中绿色#00C8AF换成指定色
  921. .replace( 'gl_FragColor = texColor * color_;', `
  922. vec3 texWhite = vec3(1.0,1.0,1.0); //中心部分白色不变,外围原本绿色的r刚好为0,所以r值越高越往白色过渡
  923. texColor.rgb = mix(newMapColor, texWhite, texColor.r);
  924. gl_FragColor = texColor * color_;` )
  925. }
  926. multiColors[this.color] = colorObject
  927. {//清理不用的colorObject
  928. let measures = viewer.scene.measurements.slice()
  929. measures.includes(this) || measures.push(this)
  930. for(let co in multiColors){
  931. multiColors[co].useCount = 0
  932. }
  933. measures.forEach(e=>{
  934. multiColors[e.color].useCount ++
  935. })
  936. let deletes = []
  937. for(let co in multiColors){
  938. if(multiColors[co].useCount == 0){
  939. deletes.push(co)
  940. delete multiColors[co].useCount
  941. for(let i in multiColors[co]){
  942. multiColors[co][i].dispose()
  943. }
  944. }
  945. }
  946. deletes.forEach(co=>delete multiColors[co])
  947. }
  948. }
  949. mat = colorObject[type]
  950. }
  951. return mat
  952. }
  953. createAreaPlane(){
  954. return super.createAreaPlane(this.getMat('planeDefault'))
  955. }
  956. raycast (raycaster, intersects) {
  957. for (let i = 0; i < this.points.length; i++) {
  958. let marker = this.markers[i];
  959. marker.raycast(raycaster, intersects);
  960. }
  961. // recalculate distances because they are not necessarely correct
  962. // for scaled objects.
  963. // see https://github.com/mrdoob/three.js/issues/5827
  964. // TODO: remove this once the bug has been fixed
  965. for (let i = 0; i < intersects.length; i++) {
  966. let I = intersects[i];
  967. I.distance = raycaster.ray.origin.distanceTo(I.point);
  968. }
  969. intersects.sort(function (a, b) { return a.distance - b.distance; });
  970. };
  971. getPointsPos2d(viewport, update){//获取屏幕上的二维坐标
  972. let ps = this.pointsPos2d.get(viewport)
  973. if(update || !ps){
  974. let points = this.points.map(e=>{
  975. let p = Potree.Utils.getPos2d(e, viewport, viewer.renderArea )
  976. p.pos3d = e.clone(), p.object = this
  977. return p
  978. });
  979. this.pointsPos2d.set(viewport, points)
  980. console.log('updatePointsPos2d',this.uuid,viewport.name)
  981. }
  982. return this.pointsPos2d.get(viewport)
  983. }
  984. transformData(prop){
  985. if(prop.measureType == 'Point'){
  986. prop.showCoordinates = true,
  987. prop.closed = true,
  988. prop.maxMarkers = 1,
  989. prop.minMarkers = 1
  990. }else if(prop.measureType == 'Distance'){
  991. prop.showDistances = true,
  992. prop.showEdges = true,
  993. prop.maxMarkers = 2,
  994. prop.minMarkers = 2
  995. }else if(prop.measureType == 'MulDistance'){
  996. prop.showDistances = true,
  997. prop.showEdges = true,
  998. prop.minMarkers = 2
  999. }else if(prop.measureType == 'MulDistance Ring'){
  1000. prop.showDistances = true,
  1001. prop.showEdges = true,
  1002. prop.showArea = true,
  1003. prop.closed = true,
  1004. prop.minMarkers = 3
  1005. }else if(prop.measureType == 'Ver MulDistance'){
  1006. prop.showDistances = true,
  1007. prop.atPlane = true,
  1008. prop.showEdges = true,
  1009. prop.minMarkers = 2
  1010. prop.faceDirection = "vertical"
  1011. prop.unableDragAtMap = true
  1012. }else if(prop.measureType == 'Hor MulDistance'){
  1013. prop.showDistances = true,
  1014. prop.atPlane = true,
  1015. prop.showEdges = true,
  1016. prop.minMarkers = 2
  1017. prop.faceDirection = "horizontal"
  1018. }else if(prop.measureType == 'Ver Distance'){
  1019. prop.showDistances = true,
  1020. prop.showEdges = true,
  1021. prop.maxMarkers = 2,
  1022. prop.minMarkers = 2,
  1023. prop.faceDirection = "vertical"
  1024. prop.unableDragAtMap = true
  1025. }else if(prop.measureType == 'Hor Distance'){
  1026. prop.showDistances = true,
  1027. prop.showEdges = true,
  1028. prop.maxMarkers = 2,
  1029. prop.minMarkers = 2,
  1030. prop.faceDirection = "horizontal"
  1031. }else if(prop.measureType == 'Area'){
  1032. prop.showDistances = true,
  1033. Potree.settings.areaAtNotPlane || (prop.atPlane = true)
  1034. prop.showEdges = true,
  1035. prop.closed = true,
  1036. prop.minMarkers = 3
  1037. }else if(prop.measureType == 'Hor Area'){
  1038. prop.showDistances = true,
  1039. prop.atPlane = true,
  1040. prop.showEdges = true,
  1041. prop.closed = true,
  1042. prop.minMarkers = 3
  1043. prop.faceDirection = "horizontal"
  1044. }else if(prop.measureType == 'Ver Area'){
  1045. prop.showDistances = true,
  1046. prop.atPlane = true,
  1047. prop.showEdges = true,
  1048. prop.closed = true,
  1049. prop.minMarkers = 3
  1050. prop.faceDirection = "vertical"
  1051. prop.unableDragAtMap = true
  1052. }else if(prop.measureType == 'Rect Area'){
  1053. prop.showDistances = true,
  1054. prop.atPlane = true,
  1055. prop.showEdges = true,
  1056. prop.closed = true,
  1057. prop.minMarkers = 4
  1058. prop.maxMarkers = 4
  1059. }else if(prop.measureType == 'Hor Rect Area'){
  1060. prop.showDistances = true,
  1061. prop.atPlane = true,
  1062. prop.showEdges = true,
  1063. prop.closed = true,
  1064. prop.minMarkers = 4
  1065. prop.maxMarkers = 4
  1066. prop.isRect = true
  1067. prop.faceDirection = "horizontal"
  1068. }else if(prop.measureType == 'Ver Rect Area'){
  1069. prop.showDistances = true,
  1070. prop.atPlane = true,
  1071. prop.showEdges = true,
  1072. prop.closed = true,
  1073. prop.minMarkers = 4
  1074. prop.maxMarkers = 4
  1075. prop.isRect = true
  1076. prop.faceDirection = "vertical"
  1077. prop.unableDragAtMap = true
  1078. }
  1079. if(prop.atPlane && prop.closed){ //atPlane在同一平面上
  1080. prop.showArea = true
  1081. }
  1082. super.transformData(prop)
  1083. }
  1084. setUnitSystem(unitSystem){
  1085. //console.log(this.name +':' +this.unitSystem)
  1086. if(unitSystem != this.unitSystem){
  1087. if(unitSystem == "metric"){
  1088. }else if(unitSystem == 'imperial'){
  1089. }
  1090. this.unitSystem = unitSystem
  1091. this.expands.forEach(e=>e.unitSystem = unitSystem)
  1092. this.update()
  1093. }
  1094. }
  1095. reDraw(restMarkerCount=0){//重新开始画
  1096. super.reDraw(restMarkerCount)
  1097. if(this.measureType == 'Distance'){
  1098. this.shouldShowHorVerGuide = false
  1099. this.setEdgesDisplay(false)
  1100. }
  1101. if(this.showArea){
  1102. this.area = {value:0};
  1103. this.areaLabel && Utils.updateVisible(this.areaLabel, 'setVisible', false )
  1104. }
  1105. if(this.totalDisLabel && this.showTotalDis){
  1106. Utils.updateVisible(this.totalDisLabel, 'setVisible', false )
  1107. }
  1108. viewer.inputHandler.dispatchEvent( {type:'measuring', v:true, cause:'reDraw',object:this, situation:'dragging'} )
  1109. }
  1110. addExpand(data){//{offset,color}
  1111. data.measure = this
  1112. let expand = new ExpandLine(data)
  1113. this.expands.push(expand)
  1114. viewer.scene.overlayScene.add(expand) //this.add(expand) //因为其可见性不随父结点所以分开
  1115. }
  1116. removeExpand(expand){
  1117. let index = this.expands.indexOf(expand)
  1118. if(index > -1){
  1119. expand.dispose()
  1120. this.expands.splice(index,1)
  1121. //this.remove(expand)
  1122. }
  1123. }
  1124. }
  1125. function setLabelHightState(label, state){
  1126. if(state){
  1127. let color = new THREE.Color(Potree.config.measure.highlight.color)
  1128. //label.sprite.material.opacity = config.measure.highlight.opacity
  1129. //label.setBackgroundColor({r:255*color.r, g:255*color.g, b:255*color.b, a:config.measure.highlight.opacity})
  1130. label.sprite.material.useDepth = false;
  1131. //label.textColor = {r: this.color.r*255, g: this.color.g*255, b: this.color.b*255, a: 1}
  1132. }else{
  1133. //label.setBackgroundColor({r: this.color.r*255, g: this.color.g*255, b: this.color.b*255, a:config.measure.default.opacity})
  1134. label.sprite.material.useDepth = true
  1135. //label.sprite.material.opacity = 0.98
  1136. //label.textColor = {r: 255, g: 255, b: 255, a: 1}
  1137. }
  1138. label.updateTexture()
  1139. }
  1140. function createCircleRadiusLabel(){
  1141. const circleRadiusLabel = new TextSprite("");
  1142. circleRadiusLabel.setTextColor({r: 140, g: 250, b: 140, a: 1.0});
  1143. circleRadiusLabel.setBorderColor({r: 0, g: 0, b: 0, a: 1.0});
  1144. circleRadiusLabel.setBackgroundColor({r: 0, g: 0, b: 0, a: 1.0});
  1145. circleRadiusLabel.fontsize = 16;
  1146. circleRadiusLabel.material.depthTest = false;
  1147. circleRadiusLabel.material.opacity = 1;
  1148. circleRadiusLabel.visible = false;
  1149. return circleRadiusLabel;
  1150. }
  1151. function createCircleRadiusLine(){
  1152. var circleRadiusLine = LineDraw.createFatLine([ ],{
  1153. color:0xff0000,
  1154. dashSize: 0.5,
  1155. gapSize: 0.2,
  1156. lineWidth: config.measure.lineWidth
  1157. })
  1158. circleRadiusLine.visible = false;
  1159. return circleRadiusLine;
  1160. }
  1161. function createCircleLine(){
  1162. const coordinates = [];
  1163. let n = 128;
  1164. for(let i = 0; i <= n; i++){
  1165. let u0 = 2 * Math.PI * (i / n);
  1166. let u1 = 2 * Math.PI * (i + 1) / n;
  1167. let p0 = new THREE.Vector3(
  1168. Math.cos(u0),
  1169. Math.sin(u0),
  1170. 0
  1171. );
  1172. let p1 = new THREE.Vector3(
  1173. Math.cos(u1),
  1174. Math.sin(u1),
  1175. 0
  1176. );
  1177. coordinates.push(
  1178. p0,
  1179. p1
  1180. );
  1181. }
  1182. var circleLine = LineDraw.createFatLine(coordinates,{
  1183. color: 0xff0000,
  1184. dashSize: 0.5,
  1185. gapSize: 0.2,
  1186. lineWidth: config.measure.lineWidth
  1187. })
  1188. return circleLine;
  1189. }
  1190. function createLine(){
  1191. const line = LineDraw.createFatLine([ ],{
  1192. color: 0xff0000,
  1193. dashSize: 0.5,
  1194. gapSize: 0.2,
  1195. lineWidth: config.measure.lineWidth
  1196. })
  1197. return line;
  1198. }
  1199. function createCircle(){
  1200. const coordinates = [];
  1201. let n = 128;
  1202. for(let i = 0; i <= n; i++){
  1203. let u0 = 2 * Math.PI * (i / n);
  1204. let u1 = 2 * Math.PI * (i + 1) / n;
  1205. let p0 = new THREE.Vector3(
  1206. Math.cos(u0),
  1207. Math.sin(u0),
  1208. 0
  1209. );
  1210. let p1 = new THREE.Vector3(
  1211. Math.cos(u1),
  1212. Math.sin(u1),
  1213. 0
  1214. );
  1215. coordinates.push(
  1216. p0,
  1217. p1
  1218. );
  1219. }
  1220. var line = LineDraw.createFatLine(coordinates,{
  1221. color: 0xff0000,
  1222. dashSize: 0.5,
  1223. gapSize: 0.2,
  1224. lineWidth: config.measure.lineWidth
  1225. })
  1226. return line;
  1227. }
  1228. //缓冲区扩展,随measure改变,不可拖拽
  1229. class ExpandLine extends ctrlPolygon{
  1230. constructor (prop) {
  1231. prop.points = prop.measure.points.map(e=>e.clone()) //先复制 用来加marker
  1232. prop.unitSystem = prop.measure.unitSystem
  1233. prop.atPlane = prop.measure.atPlane
  1234. prop.closed = prop.measure.closed
  1235. super('expandLine',prop);
  1236. this.name = 'measureExpand_'+prop.measure.name
  1237. this.initData(prop)
  1238. //offset 正数为朝外
  1239. }
  1240. update(options={}){//暂时每次都全部更新,以后再改
  1241. let points = this.measure.points
  1242. let count = this.measure.points.length
  1243. let newPoints = []
  1244. let facePlane = this.getFacePlane(true) //更新normal. 不用measure的是因为measure没更新normal
  1245. let normal = facePlane?.normal //this.measure.facePlane.normal
  1246. if(!normal)return //暂时不知道怎么写
  1247. let offset = this.offset //Potree.math.getArea(this.measure.point2dInfo.points2d) > 0 ? -this.offset : this.offset // 时针受normal影响
  1248. //console.log('offset',offset, 'normal', normal.toArray(), 'clockwise', Potree.math.getArea(this.measure.point2dInfo.points2d) > 0)
  1249. for(let i=0; i<count; i++){
  1250. let O = points[i] //该点
  1251. let A = this.measure.getPoint(i,-1)//points[i-1] //上一个点
  1252. let B = this.measure.getPoint(i,1)//points[i+1] //下一个点
  1253. let p1, p2 //该点两边的折点
  1254. let sideVec //该点两边对应的向量
  1255. //如果是线段的话,
  1256. if(!A || !B){ //端点
  1257. let vec = new THREE.Vector3().subVectors(i==0 ? B : O, i==0 ? O : A)
  1258. sideVec = new THREE.Vector3().crossVectors(normal, vec).normalize().multiplyScalar(offset)
  1259. //sideVec = new THREE.Vector3().copy(math.getNormal2d({p1: i==0 ? B : O, p2: i==0 ? O : A})).setZ(0).multiplyScalar(this.halfPathWidth) //垂线
  1260. }else{
  1261. let OA = new THREE.Vector3().subVectors(A,O).normalize() //只保证俯视角度正确。(如果两点有高度差,该段四个点不会在同一平面,看起来有扭转,有的地方会肥大,但从俯视角度看是正确的。)
  1262. let OB = new THREE.Vector3().subVectors(B,O).normalize()
  1263. let angle = math.getAngle(OA, OB, normal)
  1264. if(math.closeTo(angle,0,1e-4) || math.closeTo(angle,Math.PI,1e-4) || math.closeTo(angle, -Math.PI,1e-4)){ //这时候直接加两个向量算出的平分线不准,故直接找垂线
  1265. let vec = new THREE.Vector3().subVectors(O, A)
  1266. sideVec = new THREE.Vector3().crossVectors(normal, vec).normalize().multiplyScalar(offset)
  1267. //sideVec = new THREE.Vector3().copy(math.getNormal2d({p1: O, p2: A})) //垂线
  1268. //console.log('接近0或180',angle, sideVec)
  1269. }else{
  1270. let midVecLength = offset / Math.sin(angle/2)
  1271. sideVec = new THREE.Vector3().addVectors(OA,OB).normalize().multiplyScalar(midVecLength) //角平分线 ( 和上一个方向保持在同一侧,故而顺时针和逆时针方向不同 )
  1272. }
  1273. }
  1274. let p = new THREE.Vector3().addVectors(O, sideVec)
  1275. newPoints.push(p)
  1276. }
  1277. this.points = newPoints
  1278. super.update()
  1279. }
  1280. changeOffset(offset){
  1281. this.offset = offset
  1282. this.update()
  1283. }
  1284. addMarker({point,index }={}){
  1285. super.addMarker({index, point, edge: LineDraw.createFatLine( [ ],{ mat: this.measure.getMat('edgeExpand') })})
  1286. }
  1287. getArea(){
  1288. if(!this.closed)return
  1289. this.getPoint2dInfo(this.points)
  1290. this.measure.getArea.call(this)
  1291. this.measure.getArea()
  1292. let area = Math.abs(this.measure.area.value - this.area.value)
  1293. this.area = {value:area, string: this.getConvertString(area, 'area') }
  1294. return this.area
  1295. }
  1296. setSelected(state){
  1297. this.edges.forEach(e=>{
  1298. e.material = this.measure.getMat(state ? 'edgeExpand-selected' : 'edgeExpand')
  1299. })
  1300. viewer.dispatchEvent('content_changed')
  1301. }
  1302. }
  1303. ExpandLine.prototype.getPoint2dInfo = Measure.prototype.getPoint2dInfo
  1304. ExpandLine.prototype.getConvertString = Measure.prototype.getConvertString
  1305. /*
  1306. 按alt鼠标滚轮或WS键放慢。
  1307. 按Alt键可以平行屏幕拖拽点。&dragPolyBeyondPoint 后缀在拖拽到无点云区域也是此效果。
  1308. 按M键拖拽点可以复制出当前点
  1309. */