import * as THREE from "../../../../libs/three.js/build/three.module.js";
import {TextSprite} from "../TextSprite.js";
import {Utils} from "../../../utils.js";
import Label from "../Label.js";
import {LineDraw} from "../../utils/DrawUtil.js";
import math from "../../utils/math.js";
import DepthBasicMaterial from "../../materials/DepthBasicMaterial.js";
import BasicMaterial from '../../materials/BasicMaterial.js'
import Sprite from '../Sprite.js'
import {config} from '../../settings.js'
import browser from "../../utils/browser.js";
import {ctrlPolygon} from './ctrlPolygon.js'
let texLoader = new THREE.TextureLoader()
let defaultColor = new THREE.Color(config.measure.default.color);
let highlightColor = new THREE.Color(config.measure.highlight.color);
let color = new THREE.Color(config.measure.color)
let textColor = new THREE.Color(config.measure.textColor)
let markerMaps
const textSizeRatio = math.linearClamp(window.outerWidth * window.outerHeight , [360*720, 1920*1080], [0.7, 1]) //pc字显示大一些 用
const lineDepthInfo = {
clipDistance : 15,//4,//消失距离
occlusionDistance: 3,//1,//变为backColor距离
}
const markerMapShrink = browser.isMobile() ? 0.4 : 0.8 //触屏需要更大的热区
const markerSizeInfo = {
width2d : 18 / markerMapShrink , // nearBound : 1.5, farBound : 15,
}
/* const markerSizeInfo = {
minSize : 10 , maxSize : 15 , nearBound : 1.5, farBound : 15,
} */
const labelSizeInfo = {width2d:200}
const mainLabelProp = {
//backgroundColor: {r: defaultColor.r*255, g: defaultColor.g*255, b: defaultColor.b*255, a:config.measure.default.opacity},
backgroundColor: {r: 0, g: 0, b: 0, a:0},
textColor: {r: textColor.r*255, g: textColor.g*255, b: textColor.b*255, a: 1.0},
textBorderColor: {r:255, g: 255, b:255, a: 1.0},
textBorderThick:3 ,
fontsize: 14 * textSizeRatio,
borderRadius : 12, margin:{x:20,y:4},
renderOrder : Potree.config.renderOrders.measureLabel,
pickOrder: Potree.config.renderOrders.measureLabel,
transform2D: {x:0, y:-0.15},
useDepth : true ,
// 2023.10 尽量不让数字被挡住
clipDistance : 10,//消失距离
occlusionDistance: 10,//变为backColor距离
maxOcclusionFactor:0.3,
maxClipFactor:0.8,
maxLineWidth: 300,
lineSpace:6
}
const subLabelProp = {
backgroundColor: {r: 255, g: 255, b: 255, a:0},
textColor: {r: textColor.r*255, g: textColor.g*255, b: textColor.b*255, a: 1.0},
textBorderColor: {r:255, g: 255, b:255, a: 1.0},
textBorderThick:3 ,
fontsize: 13 * textSizeRatio,
renderOrder : Potree.config.renderOrders.measureLabelSub,
pickOrder: Potree.config.renderOrders.measureLabelSub,
transform2D: {x:0, y:-0.13},
}
const angle = THREE.Math.degToRad(config.measure.guideLineMinAngle || 5); //显示水平垂直辅助线的最小角度
const guideShowMinAngle = {min: angle, max: Math.PI/2 - angle}
export class Measure extends ctrlPolygon{
constructor (prop) {
prop.dimension = '2d'
super('measure',prop);
this.constructor.counter = (this.constructor.counter === undefined) ? 0 : this.constructor.counter + 1;
this.name = this.name || this.measureType + this.constructor.counter
this.selectStates = {}
this.edgeLabels = [];
this.coordinateLabels = [];
this.area = {value:0,string:''}
this.expands = []
if( this.showArea ){
this.areaLabel = this.createAreaLabel();
this.add(this.areaLabel)
}
//add:
if(this.atPlane || this.faceDirection){ //是一个平面上的话
this.createGuideLine();
}
if(this.measureType == 'Distance' /* || this.measureType.includes('MulDistance') */){
this.createHorVerGuideLine()
}
this.setUnitSystem(prop.unit || viewer.unitConvert.UnitService.defaultSystem)
//Potree.Utils.setObjectLayers(this, 'measure' ) //取消:scene单独渲染应该不需要设置layer
if(this.measureType == 'MulDistance' || this.measureType == 'Hor MulDistance' || this.measureType == 'Ver MulDistance'){
//this.showTotalDis = true
this.totalDisLabel = this.createTotalDisLabel()
this.add(this.totalDisLabel)
}
//addMarkers:
this.initData(prop)
this.pointsPos2d = new Map //屏幕上的二维坐标
this.points_datasets || (this.points_datasets = []) //存每个点是哪个数据集
this.addEventListener('marker_dropped',(e)=>{
this.updateDatasetBelong(e.index)
})
this.addEventListener('isVisible', ()=>{
viewer.mapViewer && viewer.mapViewer.dispatchEvent({type:'content_changed'})
})
this.lastDropTime = 0
}
initData(prop){
let makeIt = super.initData(prop)
if(makeIt){
this.edges.forEach(edge=>{edge.dispatchEvent('addHoverEvent') })
}else{
this.failBuilded = true
}
if(prop.expands){ //基本不会从这加
for(let data of prop.expands){
this.addExpand(data)
}
}
}
updateDatasetBelong(changeIndex){//更新所属数据集
if(Potree.settings.editType == "merge" || this.measureType == 'MulDistance Ring'){//点直接跟着数据集走,不用找整体的datasetId
this.dataset_points[changeIndex] = Potree.Utils.datasetPosTransform({toDataset:true, datasetId:this.points_datasets[changeIndex], position:this.points[changeIndex].clone()})
return
}
let old = this.datasetId
let maxCount = {id:null,count:0}
let datasets = {}
this.points_datasets.forEach(e=>{
if(e == void 0)return
if(datasets[e]){
datasets[e] ++
}else{
datasets[e] = 1
}
})
for(let i in datasets) {
if(datasets[i]>maxCount.count){
maxCount = {id:i, count:datasets[i]}
}
}
this.datasetId = maxCount.count > 0 ? maxCount.id : null
//if(this.datasetId != old){
//this.dispatchEvent({type:'changeDatasetId'})
if(this.datasetId == void 0){
this.dataset_points = null //可能为空或[null,null...]
}else{
this.dataset_points = this.points.map(e=>{
return Potree.Utils.datasetPosTransform({toDataset:true,datasetId:this.datasetId, position:e.clone()})
})
}
//}
}
transformByPointcloud(){//每次移动点云 or 加载测量线时要获取一下当前position //有地图时
if(this.datasetId == void 0)return
this.points = this.dataset_points.map(e=>{
return Potree.Utils.datasetPosTransform({fromDataset:true, datasetId:this.datasetId, position:e.clone()})
})
this.getPoint2dInfo(this.points)
this.update({ifUpdateMarkers:true})
this.setSelected(false)//隐藏edgelabel
}
changeColor(color){
this.color = color //'#ffffff'
this.edges.forEach(e=>e.material = this.getMat('edgeDefault')) //update
this.markers.forEach(e=>e.material = this.getMat('markerDefault'))
this.areaPlane && (this.areaPlane.material = this.getMat('planeDefault') )
this.expands.forEach(e=>e.edges.forEach(a=>a.material = this.getMat('edgeExpand')))
viewer.dispatchEvent('content_changed')
}
update(options={}) {
if(options.index == -1)return
super.update(options)
if(this.showCoordinates && this.points.length>0){
let position = this.points[0];
this.markers[0].position.copy(position);
{ // coordinate labels
let coordinateLabel = this.coordinateLabels[0];
let pos = [
position.toArray()
]
if(viewer.transform){
let lonlat = viewer.transform.lonlatToLocal.inverse(position.toArray())
let EPSG4550 = viewer.transform.lonlatTo4550.forward(lonlat)
pos.push(lonlat,EPSG4550)
}
//let msg = position.toArray().map(p => Utils.addCommas(p.toFixed(2))).join(" / ");
let msg = pos.map(a=>
a.map(p => Utils.addCommas(p.toFixed(10))).join(", ")
).join("
")
coordinateLabel.setText(msg);
coordinateLabel.setPos(position)
coordinateLabel.setVisible(true)//this.showCoordinates;
}
return
}
let setEdgeLabel = (label,p1,p2,distance,type)=>{//设置label位置和字
this.setEdgeLabelPos(label,p1,p2)
distance = distance == void 0 ? p1.distanceTo(p2) : distance;
//var text = viewer.unitConvert.convert(distance, 'distance', Potree.settings.precision, this.unitSystem, 1 , true)//distance要传0.1 这个factor
var text = this.getConvertString(distance, 'distance')
this.showArea || type == 'addTitle' && (text = this.labelAddName(text))
label.setText(text)
return distance
}
let lastIndex = this.points.length - 1
let setLabel = (index)=>{
if(index == null)return
let previousIndex = this.getIndex(index, -1)
let nextIndex = this.getIndex(index, +1)
let previousPoint = this.points[previousIndex];
let point = this.points[index];
let nextPoint = this.points[nextIndex];
if(this.showDistances ){ // edge labels
let edgeLabel = this.edgeLabels[index];
let distance = nextPoint && point.distanceTo(nextPoint)
this.edges[index].distance_ = distance
edgeLabel.shouldVisi = nextPoint && (index < lastIndex || this.isRect || this.closed && !this.isNew ) && distance>0
//this.closed || edgeLabel.setVisible(edgeLabel.shouldVisi) //closed的在setEdgesDisplay中设置
Utils.updateVisible(edgeLabel, 'shouldVisi', edgeLabel.shouldVisi, 2)
if(edgeLabel.shouldVisi){
edgeLabel.lineDir = new THREE.Vector3().subVectors(point,nextPoint).normalize() //[point,nextPoint]
setEdgeLabel(edgeLabel,point,nextPoint,distance, this.measureType != 'MulDistance' && 'addTitle')
}
}
}
if(options.index != void 0){//更新第几个点
setLabel(options.index)
let previousIndex = this.getIndex(options.index, -1)
setLabel(previousIndex)
}else{
for (let index = 0; index <= lastIndex; index++) {
setLabel(index)
}
}
if(Potree.config.measure.mulLabelHideFaraway ){
this.measureType == 'MulDistance' && this.clearEdgeLabelVisi()
}
if(this.measureType == 'Distance' && this.points.length>1){//设置水平垂直辅助线
var pTop, pBtm
if(this.points[0].z > this.points[1].z ){
pTop = this.points[0];
pBtm = this.points[1];
}else{
pTop = this.points[1];
pBtm = this.points[0];
}
let projectPos = new THREE.Vector3(pTop.x, pTop.y, pBtm.z);//两条guideline的交点
{//倾斜角度太小的时候不显示
let tan = pTop.distanceTo(projectPos) / pBtm.distanceTo(projectPos)
let angle = Math.atan(tan);
this.shouldShowHorVerGuide = angle > guideShowMinAngle.min && angle < guideShowMinAngle.max
if(this.showAngleToGround){
let deg = math.toPrecision(THREE.Math.radToDeg(angle), 2) + '°'
this.angleToGroundLabel.setText(deg)
let vec1 = new THREE.Vector3().subVectors(pTop,pBtm).normalize()
let vec2 = new THREE.Vector3().subVectors(projectPos,pBtm).normalize()
let midVec = new THREE.Vector3().addVectors(vec1,vec2).normalize()
//this.angleToGroundLabel.lineDir = midVec
this.angleToGroundLabel.setPos(new THREE.Vector3().addVectors(pBtm, midVec.clone().multiplyScalar(0.15) ))
// 最好是让label垂直于midVec然后transform2Dpercent向上,这样无论向左看向右看都可以,但字斜着不直观
//绘制夹角弧线(省略成直线)
let midDis = 0.1
let sideLen = midDis * Math.cos(angle / 2)
let p1 = new THREE.Vector3().addVectors(pBtm, vec1.multiplyScalar(sideLen))
let p2 = new THREE.Vector3().addVectors(pBtm, vec2.multiplyScalar(sideLen))
LineDraw.updateLine(this.angleLine, [p1, p2])
this.angleLine.visible = this.angleToGroundLabel.visible = this.shouldShowHorVerGuide
}
}
LineDraw.updateLine(this.verGuideEdge, [pTop, projectPos])
LineDraw.updateLine(this.horGuideEdge, [pBtm, projectPos])
setEdgeLabel(this.verEdgeLabel,pTop,projectPos)
setEdgeLabel(this.horEdgeLabel,pBtm,projectPos)
this.verGuideEdge.visible = this.horGuideEdge.visible = this.shouldShowHorVerGuide
this.verEdgeLabel.visible = this.horEdgeLabel.visible = this.shouldShowHorVerGuide
}
if(this.showArea && this.points.length > 2){ // update area
let msg = this.getArea().string
msg = this.labelAddName(msg)
this.areaLabel.setPos(this.getCenter('areaPlaneCenter'))
this.areaLabel.setText(msg);
Utils.updateVisible(this.areaLabel, 'setVisible', true) //this.areaLabel.setVisible(true)
}
if(this.totalDisLabel){
this.ifShowTotalDis()
Utils.updateVisible(this.totalDisLabel,'setVisible', this.showTotalDis)
this.edgeLabels.forEach(e=> Utils.updateVisible(e, 'showTotalDis', !this.showTotalDis))
if(this.showTotalDis){
let dis = this.getTotalDistance()
let msg = this.getConvertString(dis, 'distance')
msg = this.labelAddName(msg)
this.center = null
this.center = this.getCenter()
this.totalDisLabel.setPos(this.center);
this.totalDisLabel.setText(msg);
}
}
this.expands.forEach(e=>e.update(options))
};
labelAddName(msg){
if(Potree.config.measure.showName && this.title?.trim()){
msg = [this.title,msg]
}
return msg
}
getArea(){
let area
if(this._area != void 0){
area = this._area
}else if(this.point2dInfo){
area = Math.abs(math.getArea(this.point2dInfo.points2d))//this.getArea();
}else{//mulDistance Ring 2d面
area = Math.abs(math.getArea(this.points))
}
let msg = this.getConvertString(area, 'area')
//let msg = viewer.unitConvert.convert(area, 'area', Potree.settings.precision, this.unitSystem/* , 0.1 */ )
this.area = {value:area, string:msg}
return this.area
}
getConvertString(num, type){
return viewer.unitConvert.convert(num, type, Potree.settings.precision, this.unitSystem, true ,
{
'imperial': {minFactor: 0.01 },
'metric': {minFactor: 0.01}
}
)
}
ifShowTotalDis(){
let show = this.points.length > 2
if(show){
let maxDis = 0.15
let lastIndex = this.points.length - 1;
for(let i=0;i maxDis){
show = false; break;
}
}
}
this.showTotalDis = show
/* 连续测量:
1. ≥2次测量,单个距离<15cm时,居中显示总长, hover、选中时显示每段长度
2. 若连续测量的线段中,大于等于1段超出15cm,所有线段均显示长度
-------------------
*/
}
clearEdgeLabelVisi(){//修改点位置后清空,下次render时会自动getEdgeLabelVisi
let lastIndex = this.points.length - 1;
for (let index = 0; index <= lastIndex; index++) {
if(!this.closed && index == lastIndex)continue
let edgeLabel = this.edgeLabels[index];
edgeLabel.visiMap.clear()
}
}
getEdgeLabelVisi(viewport){//获取多折线的edgelabel在不同视图里的可见性。要保证任何时候label能出现的线最小二维长度一致
let camera = viewport.camera
let lastIndex = this.points.length - 1;
/* let pos2ds = this.points.map(point=> point.clone().project(camera) ) //即使只是旋转也会变动,尤其是转到屏幕外后变为显示。所以不用这种
let minDis = 0.01; */
let minDis = 0.02 , minAngleRatio = 0.07, minAngle
let vecs
let forceShow
if(camera.type == 'OrthographicCamera'){
minDis *= Math.pow(camera.top / camera.zoom, 2);
//console.log(minDis)
}else{
if(Potree.settings.displayMode == 'showPanos' && viewer.images360.zoomLevel == Potree.settings.zoom.max){
forceShow = true //当zoom到最大时强制显示,避免有的线太短永远显示不出长度
}else{
vecs = this.points.map(point=> new THREE.Vector3().subVectors(point, camera.position).normalize())
minAngleRatio /= viewport.resolution.y / 1000 / textSizeRatio //角度占fov最小比率
minAngle = minAngleRatio * THREE.Math.degToRad(camera.fov)
}
}
for (let index = 0; index <= lastIndex; index++) {
if(!this.closed && index == lastIndex)continue
let edgeLabel = this.edgeLabels[index];
let nextIndex = (index + 1 > lastIndex) ? 0 : index + 1;
let previousIndex = (index === 0) ? lastIndex : index - 1;
let point = this.points[index];
let nextPoint = this.points[nextIndex];
/* let point2d = pos2ds[index];
let nextPoint2d = pos2ds[nextIndex];
let dis2d = point2d.distanceToSquared(nextPoint2d)
let v = dis2d > minDis //可见长度太小,为避免拥挤,不显示
edgeLabel.visiMap.set(camera, v) */
let v
if(forceShow){
v = true
}else if(camera.type == 'OrthographicCamera'){
let vec = new THREE.Vector3().subVectors(point,nextPoint)
let projVec = vec.projectOnPlane(viewport.view.direction)
v = projVec.lengthSq() > minDis
}else{
let vec0 = vecs[index];
let vec1 = vecs[nextIndex];
v = Math.acos(vec0.dot(vec1)) > minAngle //角度过小代表可见长度太小,为避免拥挤,不显示
}
edgeLabel.visiMap.set(camera, v)
}
}
setEdgeLabelPos(label,p1,p2){ //调整label的位置,使倾斜后看起来在线的中心,而不要挡住端点
let center = new THREE.Vector3().addVectors(p1,p2).multiplyScalar(0.5);
return label.setPos(center)
if(label.lineDir && label.lineDir.length() > 0){
if(viewer.mainViewport.camera.type == 'OrthographicCamera'){
label.setPos(center)
}else{
//根据视线和线的夹角(后又加入相机和两个端点距离差)来决定标签偏移位置。+
let eyePos = viewer.mainViewport.camera.position;
let dir = viewer.mainViewport.view.direction //new THREE.Vector3().subVectors(center,eyePos).normalize()
/*let centerDir = new THREE.Vector3().subVectors(center,eyePos).normalize()
if(centerDir.dot(dir)<0){//中点在相机后方,就不设置
label.setPos(center)
return
} */
let cos = dir.dot(label.lineDir)
let nearPoint = cos > 0 ? p2 : p1 //近端点。
let far = cos > 0 ? p1 : p2 //远端点。
let nearPointDir = new THREE.Vector3().subVectors(nearPoint,eyePos)//.normalize()
//使label在中点和近端点中变化, 近端点可能到了相机后方,需要投影到相机所在平面上
if(nearPointDir.dot(dir)<0){//近端点到了相机后方,前移。
//let hfov = cameraLight.getHFOVForCamera(viewer.mainViewport.camera , true ); //暂且只看水平fov
//if(nearPointDir.dot(dir)0?label.lineDir:label.lineDir.clone().negate())
let camDirPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(dir, eyePos)
nearPoint = ray.ray.intersectPlane(camDirPlane, new THREE.Vector3())
if(!nearPoint){//线是垂直的,视线是水平的时候
return label.setPos(center)
}
}
//防止离远了之后也偏移很多,但远了之后相机到端点vec和到中点的vec的夹角接近,不需要怎么偏移的。
let dis1 = nearPoint.distanceToSquared(eyePos)
let dis2 = far.distanceToSquared(eyePos)
let diff = Math.abs(dis1/dis2)
diff<1 && (diff = 1/diff)
diff = math.linearClamp(diff,[0, 30], [ 0,1 ])
let efficiency = 0.7; // 0-1 数值越高,r越容易接近1或-1,label越容易在倾斜后靠近近端点。
//let r = 0.5*efficiency*cos + 0.5
let r = 0.5*efficiency*diff*cos + 0.5
r = THREE.Math.clamp(r,0.1,0.9)
//视线越接近线的方向,标签应该越往近端点偏移,防止看起来几乎在远端。
if(cos > 0){
center = p1.clone().multiplyScalar(1-r).add(nearPoint.clone().multiplyScalar(r)); //label在线上滑动,使尽量保持在视觉中心
}else{
center = nearPoint.clone().multiplyScalar(1-r).add(p2.clone().multiplyScalar(r)); //label在线上滑动,使尽量保持在视觉中心
}
label.setPos(center)
}
//归零
//this.orient2dInfo = null
//this.markers.forEach(e=>e.needsUpdate=true)
}else{
label.setPos(center)
}
}
cloneMarker(cloneIndex, index){
return this.addMarker({
index,
point: this.points[cloneIndex],
dataset_point:this.dataset_points && this.dataset_points[cloneIndex],
points_dataset:this.points_datasets[cloneIndex]
})
}
addMarker (o={}) {
var index = o.index == void 0 ? this.points.length : o.index //要当第几个
let marker = o.marker || new Sprite({mat:this.getMat('markerDefault'), sizeInfo: markerSizeInfo, name:"measure_point"} )
//Potree.Utils.setObjectLayers(marker, 'measure' )
marker.pickOrder = marker.renderOrder = Potree.config.renderOrders.measureMarker
marker.markerSelectStates = {}
marker.addEventListener('startDragging',(e)=>{
/* if(e.drag.dragViewport.name == 'MainView') */viewer.inputHandler.dispatchEvent( {type: 'measuring',v:true, cause:'startDragging', situation:'dragging', object:this})
//add for 调试,方便后期增加点
if(!this.isNew && viewer.inputHandler.pressedKeys['M'.charCodeAt(0)] && this.points.length{
if( e.button != THREE.MOUSE.LEFT )return
viewer.inputHandler.dispatchEvent({type: 'measuring', v:false, cause:'stopDragging', situation:'dragging', object:this} )
this.lastDropTime = Date.now()
if(Potree.settings.adsorption){
this.isNew || viewer.viewports.forEach((viewport)=>{
this.getPointsPos2d(viewport, true )//forceUpdate
})
}
this.isNew || viewer.measuringTool.history.afterChange(this)
})
marker.addEventListener('click',()=>{
if(viewer.measuringTool.editMode == 'delPoint' ){
/* if(this.points.length == this.minMarkers){//--前端去重绘
viewer.scene.removeMeasurement(this)
}else{ */
viewer.measuringTool.history.beforeChange(this)
let index = this.markers.indexOf(marker)
this.removeMarker(index)
viewer.measuringTool.history.afterChange(this)
this.dispatchEvent('changed')
//}
}
})
//marker.measure = this
let edge
{ // edges
edge = o.edge || LineDraw.createFatLine( [ ],{mat:this.getMat('edgeDefault')} )
edge.pickOrder = 0
//Potree.Utils.setObjectLayers(edge, 'measure' )
let addHoverEvent = ()=>{ //当非isNew时才添加事件
let mouseover = (e) => {
/* if(this.measureType == 'MulDistance'){
} */
this.setSelected(true, 'edge')
};
let mouseleave = (e) => {
this.setSelected(false, 'edge')
};
edge.addEventListener('mouseover', mouseover);
edge.addEventListener('mouseleave', mouseleave);
edge.removeEventListener('addHoverEvent', addHoverEvent);
edge.addEventListener('click',(e)=>{
let now = Date.now()
if(now - this.lastDropTime<100)return ;//防止拖拽marker时误触导致focus, 以及点到marker不focus
if(viewer.measuringTool.editMode == 'addPoint' && this.points.length < this.maxMarkers){
viewer.measuringTool.history.beforeChange(this)
let index = this.edges.indexOf(edge) + 1
let nextIndex = index % this.edges.length
let point = math.getFootPoint(e.hoveredElement.point, this.points[index-1], this.points[nextIndex] );
this.addMarker({
index,
point,
dataset_point: this.dataset_points && new THREE.Vector3 , //初始化
points_dataset : this.points_datasets[index-1] //使用前一个的
})
this.updateDatasetBelong(index) //获取dataset_point
viewer.measuringTool.history.afterChange(this)
this.dispatchEvent('changed')
//this.update({})
}else{
this.isNew || viewer.measuringTool.isAdding || viewer.focusOnObject(this, 'measure') //正在添加测量线时不要focus其他线(容易误触)
}
})
}
edge.addEventListener('addHoverEvent', addHoverEvent);
if(!this.isNew){
edge.dispatchEvent('addHoverEvent')
}
}
super.addMarker(Object.assign(o, {index, marker, edge}))
if(this.showEdges){ // edge labels
const edgeLabel = this.createEdgeLabel('edgeLabel', !this.closed)
this.edgeLabels = [...this.edgeLabels.slice(0,index), edgeLabel, ...this.edgeLabels.slice(index,this.edgeLabels.length)]
}
if(this.showCoordinates){ // coordinate labels
let coordinateLabel = new Label({
className:'measure_pointPos',
camera: viewer.scene.getActiveCamera()
})
coordinateLabel.setVisible(false)
this.coordinateLabels.push(coordinateLabel);
}
let event = {
type: 'marker_added',
measurement: this,
marker: marker
};
this.dispatchEvent(event);
this.expands.forEach(e=>e.addMarker(o))
//this.setMarker(this.points.length - 1, point);
this.update({index})//更新一下倒数第二条线
return marker;//add
};
editStateChange(state){ //主要针对edgeLabels显示切换,编辑时显示
super.editStateChange(state)
if(!state){
this.editStateTimer = setTimeout(()=>{
if(!this.isEditing){
this.dispatchEvent({type:'editStateChange',state:false})
this.setEdgesDisplay(false)
this.areaPlane && Potree.Utils.updateVisible(this.areaPlane, 'intersectLastLine', true)
this.areaLabel && Potree.Utils.updateVisible(this.areaLabel, 'intersectLastLine', true)
}
},100)
}else{
if(!this.isEditing){
this.dispatchEvent({type:'editStateChange',state:true})
this.setEdgesDisplay(true)
clearTimeout(this.editStateTimer)
}
}
this.isEditing = state
}
setMarkerSelected(marker, state, hoverObject){
//console.warn(marker.id , state, hoverObject)
marker.markerSelectStates[hoverObject] = state
let absoluteState = false
for(var i in marker.markerSelectStates){
if(marker.markerSelectStates[i] == 'hover'){
absoluteState = true; break;
}
}
if(absoluteState){
marker.material = this.getMat('markerSelect')
marker.renderOrder = marker.pickOrder = Potree.config.renderOrders.measureMarker+1
}else{
marker.material = this.getMat('markerDefault')
marker.renderOrder = marker.pickOrder = Potree.config.renderOrders.measureMarker
}
marker.selected = absoluteState
viewer.mapViewer && viewer.mapViewer.dispatchEvent('content_changed')
viewer.dispatchEvent('content_changed')
}
setEdgesDisplay(state, ignoreGuideLine){
this.closed && this.edgeLabels.forEach(e=>Utils.updateVisible(e,'hover',state))
if(this.totalDisLabel && !viewer.screenshoting){
this.edgeLabels.forEach(e=> Utils.updateVisible(e, 'hover', state, 1, state ? 'add' : 'cancel'))
Utils.updateVisible(this.totalDisLabel,'hover', !state )
}
if(!this.horVerShowAlways && !ignoreGuideLine && this.measureType == 'Distance'){
this.horEdgeLabel.visible = this.verEdgeLabel.visible = this.horGuideEdge.visible = this.verGuideEdge.visible = !!(state && this.shouldShowHorVerGuide)
if(this.showAngleToGround){
this.angleToGroundLabel.visible = this.angleLine.visible = !!(state && this.shouldShowHorVerGuide)
}
}
}
setSelected(state, hoverObject){//add
//console.log('setSelected',state, hoverObject)
let absoluteState = !!state
if(hoverObject){//如果没有hoverObject且state为false 就强制取消选中态
this.selectStates[hoverObject] = state
for(var i in this.selectStates){
if(this.selectStates[i]){
absoluteState = true; break;
}
}
}
if(absoluteState){
this.markers.forEach(e=>this.setMarkerSelected(e, 'hover', 'selectAll' ) )
this.edges.forEach(e=>{
e.renderOrder = Potree.config.renderOrders.line + 1
e.material = this.getMat('edgeSelect')
})
this.areaPlane && (this.areaPlane.material = this.getMat('planeSelected'))
//this.areaLabel && this.areaLabel.elem.addClass('highLight')
//this.closed || this.edgeLabels.forEach(e=>e.elem.addClass('highLight') )
this.setEdgesDisplay(true, hoverObject=="screenshot")
this.areaLabel && setLabelHightState(this.areaLabel, true)
this.closed || this.edgeLabels.forEach(e=>setLabelHightState(e, true) )
}else{
this.markers.forEach(e=>this.setMarkerSelected(e, 'unhover', 'selectAll' ))
this.edges.forEach(e=>e.material = this.getMat('edgeDefault') )
this.areaPlane && (this.areaPlane.material = this.getMat('planeDefault'))
this.setEdgesDisplay(false, hoverObject=="screenshot")
//this.areaLabel && this.areaLabel.elem.removeClass('highLight')
//this.closed || this.edgeLabels.forEach(e=>e.elem.removeClass('highLight') )
this.areaLabel && setLabelHightState(this.areaLabel, false)
this.closed || this.edgeLabels.forEach(e=>setLabelHightState(e, false) )
}
this.selected = absoluteState
if(hoverObject != 'byList'){
//this.bus && this.bus.emit('highlight', this.selected)
this.dispatchEvent({type:'highlight',state:this.selected})//列表高亮
}
viewer.dispatchEvent('content_changed')
viewer.mapViewer && viewer.mapViewer.dispatchEvent('content_changed')
}
removeMarker(index ){
super.removeMarker(index)
this.points_datasets.splice(index, 1);
this.dataset_points && this.dataset_points.splice(index, 1)
this.coordinateLabels.splice(index, 1);
let edgeIndex = index//(index === 0) ? 0 : (index - 1);
if(this.edgeLabels[edgeIndex]){
this.edgeLabels[edgeIndex].dispose()
this.edgeLabels.splice(edgeIndex, 1);
}
this.expands.forEach(e=>e.removeMarker(index))
this.closed || this.points.length && (this.edges[this.points.length-1].visible = false)
this.update({index: this.getIndex(index, -1)});
this.dispatchEvent({type: 'marker_removed', measurement: this});
}
setPosition(index, position) {
super.setPosition(index, position)
let event = {
type: 'marker_moved',
measure: this,
index: index,
position: position.clone()
};
this.dispatchEvent(event);
}
dispose(){//add
var labels = this.edgeLabels.concat(this.coordinateLabels)
this.areaLabel && labels.push(this.areaLabel)
labels.forEach(e=>e.dispose())
this.expands.forEach(e=>e.dispose())
this.expands.length = 0
super.dispose()
this.dispatchEvent('disposed')
}
getAngleBetweenLines (cornerPoint, point1, point2) {
let v1 = new THREE.Vector3().subVectors(point1, cornerPoint);
let v2 = new THREE.Vector3().subVectors(point2, cornerPoint);
// avoid the error printed by threejs if denominator is 0
const denominator = Math.sqrt( v1.lengthSq() * v2.lengthSq() );
if(denominator === 0){
return 0;
}else{
return v1.angleTo(v2);
}
};
getAngle (index) {
if (this.points.length < 3 || index >= this.points.length) {
return 0;
}
let previous = (index === 0) ? this.points[this.points.length - 1] : this.points[index - 1];
let point = this.points[index];
let next = this.points[(index + 1) % (this.points.length)];
return this.getAngleBetweenLines(point, previous, next);
}
// updateAzimuth(){
// // if(this.points.length !== 2){
// // return;
// // }
// // const azimuth = this.azimuth;
// // const [p0, p1] = this.points;
// // const r = p0.distanceTo(p1);
// }
createGuideLine(){//add 辅助线
var guideLine = LineDraw.createFatLine([ ],{mat:this.getMat('edgeGuide')} )
guideLine.visible = false
this.guideLine = guideLine
this.add(guideLine);
}
createHorVerGuideLine(){//创建水平与垂直辅助线,仅距离测量有。
var verGuideEdge = LineDraw.createFatLine([ ],{mat:this.getMat('edgeGuide')} )
verGuideEdge.visible = false
this.verGuideEdge = verGuideEdge
verGuideEdge.name = 'verGuideEdge'
var horGuideEdge = LineDraw.createFatLine([ ],{mat:this.getMat('edgeGuide')} )
horGuideEdge.visible = false
horGuideEdge.name = 'horGuideEdge'
this.horGuideEdge = horGuideEdge
this.add(this.verGuideEdge);
this.add(this.horGuideEdge);
//label:
this.verEdgeLabel = this.createEdgeLabel('verGuideEdge')
this.horEdgeLabel = this.createEdgeLabel('horGuideEdge')
if(this.showAngleToGround){
this.angleToGroundLabel = new TextSprite(
$.extend({}, subLabelProp, {
sizeInfo: labelSizeInfo, name:'angleToGroundLabel', transform2D:null
})
)
this.angleLine = LineDraw.createFatLine([ ],{mat:this.getMat('angle')} )
this.add(this.angleToGroundLabel)
this.add(this.angleLine)
}
}
createEdgeLabel(name, hasHoverEvent){
let inf = {
sizeInfo: labelSizeInfo, name:name||'edgeLabel',
}
if(name && name.includes('Guide')){
inf.fontsize = 12
}
const edgeLabel = new TextSprite(
$.extend({}, hasHoverEvent ? mainLabelProp : subLabelProp, inf)
)
if(hasHoverEvent){
edgeLabel.addEventListener('mouseover',()=>{
this.setSelected(true, 'edgeLabel')
})
edgeLabel.addEventListener('mouseleave',()=>{
this.setSelected(false, 'edgeLabel')
})
edgeLabel.addEventListener('click',(e)=>{
this.isNew || viewer.measuringTool.isAdding || e.button == THREE.MOUSE.LEFT && viewer.focusOnObject(this, 'measure')
})
}
edgeLabel.visible = false
edgeLabel.measure = this
edgeLabel.sprite.material.depthTestWhenPick = true
//Potree.Utils.setObjectLayers(edgeLabel, 'measure' )
this.add(edgeLabel)
if(this.measureType == 'MulDistance'){
edgeLabel.visiMap = new Map()
}
return edgeLabel
}
createAreaLabel(){
const areaLabel = this.createCenterLabel('areaLabel')
return areaLabel;
}
createTotalDisLabel(){
const totalDisLabel = this.createCenterLabel('totalDisLabel')
return totalDisLabel;
}
createCenterLabel(name){
const centerLabel = new TextSprite(
$.extend({},mainLabelProp,{sizeInfo: labelSizeInfo, name, transform2D:null, fontsize:16*textSizeRatio} )
)
centerLabel.addEventListener('mouseover',()=>{
this.isNew || this.setSelected(true, 'centerLabel')
})
centerLabel.addEventListener('mouseleave',()=>{
this.isNew || this.setSelected(false, 'centerLabel')
})
centerLabel.addEventListener('click',()=>{
this.isNew || viewer.measuringTool.isAdding || viewer.focusOnObject(this, 'measure')
})
//Potree.Utils.setObjectLayers(centerLabel, 'measure' )
Utils.updateVisible(centerLabel, 'setVisible', false)
return centerLabel;
}
getMat(type) {
if(!Measure.Mats){ //不变色的部分
Measure.Mats = {
edgeGuide: LineDraw.createFatLineMat($.extend({},lineDepthInfo,{
color:config.measure.guide.color,
dashSize: 0.1,
gapSize: 0.02,
dashed: true,
lineWidth: config.measure.lineWidth/2
})),
angle: LineDraw.createFatLineMat($.extend({},lineDepthInfo,{
color:config.measure.guide.color,
lineWidth: config.measure.lineWidth/2
})),
multiColors:{}
}
{
markerMaps = [texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png' ), //pic_point_s32
texLoader.load(Potree.resourcePath+'/textures/pic_point32.png' )]
markerMaps.forEach(map=>{
map.repeat.set(1/markerMapShrink,1/markerMapShrink)
map.offset.set((markerMapShrink-1)/2/markerMapShrink, (markerMapShrink-1)/2/markerMapShrink)
})
markerMaps[0].minFilter = 1006 //禁黑边
}
}
let mat = Measure.Mats[type]
let multiColors = Measure.Mats.multiColors
//console.log('getMat', this.name, this.color, type)
if(!mat){
let colorObject = multiColors[this.color]
if(!colorObject){
let c = new THREE.Color().set(this.color).getHSL({ h: 0, s: 0, l: 0 })
let expandColor = new THREE.Color().setHSL(c.h, c.s, c.l >= 0.4 ? c.l - 0.3: c.l + 0.3)
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 )
colorObject = {
edgeDefault: LineDraw.createFatLineMat($.extend({},lineDepthInfo,{
color: this.color || config.measure.default.color,
lineWidth: config.measure.lineWidth,
useDepth :true,
dashWithDepth :true, // 只在被遮住的部分显示虚线,因为实线容易挡住label
dashed :true,
dashSize : 0.04,
gapSize: 0.04,
transparent: true,
opacity: config.measure.default.opacity,
depthTestWhenPick:true,
})),
edgeSelect: LineDraw.createFatLineMat($.extend({},lineDepthInfo,{
color: this.color || config.measure.highlight.color,//'#f0ff00',
dashSize: 0.5,
gapSize: 0.2,
lineWidth: config.measure.lineWidth ,
transparent: true,
opacity: config.measure.highlight.opacity
})),
edgeExpand : LineDraw.createFatLineMat($.extend({},lineDepthInfo,{
color: expandColor,
useDepth :true,
lineWidth: 2 ,
transparent: true,
opacity: config.measure.default.opacity,
})),
'edgeExpand-selected': LineDraw.createFatLineMat($.extend({},lineDepthInfo,{
color: expandSelectedColor,
useDepth :true,
lineWidth: 2 ,
transparent: true,
opacity: config.measure.highlight.opacity,
})),
markerDefault: new DepthBasicMaterial($.extend({},lineDepthInfo,{
transparent: !0,
opacity: 1,
map: markerMaps[0] ,
useDepth:true ,
color: this.color,
//mapScale: markerMapShrink
})),
markerSelect: new BasicMaterial({
transparent: !0,
opacity: 1,
depthTest:false,
map: markerMaps[1],
}),
planeDefault : new DepthBasicMaterial( $.extend({},lineDepthInfo,{
color : this.color || color,
side:THREE.DoubleSide,
opacity:0.2,
transparent:true,
useDepth:true,
})),
planeSelected: new THREE.MeshBasicMaterial({
color: this.color || color,
side:THREE.DoubleSide,
opacity:0.3,
transparent:true,
//wireframe:true
})
}
colorObject.markerSelect.defines.replaceColor = '' //将绿色部分替换成color
colorObject.markerSelect.uniforms.newMapColor = {type:'v3', value: new THREE.Color(this.color)}
colorObject.markerSelect.onBeforeCompile = function ( shader ) {
shader.fragmentShader = shader.fragmentShader
.replace( 'uniform sampler2D map;', `uniform sampler2D map; uniform vec3 newMapColor;` )//将图中绿色#00C8AF换成指定色
.replace( 'gl_FragColor = texColor * color_;', `
vec3 texWhite = vec3(1.0,1.0,1.0); //中心部分白色不变,外围原本绿色的r刚好为0,所以r值越高越往白色过渡
texColor.rgb = mix(newMapColor, texWhite, texColor.r);
gl_FragColor = texColor * color_;` )
}
multiColors[this.color] = colorObject
{//清理不用的colorObject
let measures = viewer.scene.measurements.slice()
measures.includes(this) || measures.push(this)
for(let co in multiColors){
multiColors[co].useCount = 0
}
measures.forEach(e=>{
multiColors[e.color].useCount ++
})
let deletes = []
for(let co in multiColors){
if(multiColors[co].useCount == 0){
deletes.push(co)
delete multiColors[co].useCount
for(let i in multiColors[co]){
multiColors[co][i].dispose()
}
}
}
deletes.forEach(co=>delete multiColors[co])
}
}
mat = colorObject[type]
}
return mat
}
createAreaPlane(){
return super.createAreaPlane(this.getMat('planeDefault'))
}
raycast (raycaster, intersects) {
for (let i = 0; i < this.points.length; i++) {
let marker = this.markers[i];
marker.raycast(raycaster, intersects);
}
// recalculate distances because they are not necessarely correct
// for scaled objects.
// see https://github.com/mrdoob/three.js/issues/5827
// TODO: remove this once the bug has been fixed
for (let i = 0; i < intersects.length; i++) {
let I = intersects[i];
I.distance = raycaster.ray.origin.distanceTo(I.point);
}
intersects.sort(function (a, b) { return a.distance - b.distance; });
};
getPointsPos2d(viewport, update){//获取屏幕上的二维坐标
let ps = this.pointsPos2d.get(viewport)
if(update || !ps){
let points = this.points.map(e=>{
let p = Potree.Utils.getPos2d(e, viewport, viewer.renderArea )
p.pos3d = e.clone(), p.object = this
return p
});
this.pointsPos2d.set(viewport, points)
console.log('updatePointsPos2d',this.uuid,viewport.name)
}
return this.pointsPos2d.get(viewport)
}
transformData(prop){
if(prop.measureType == 'Point'){
prop.showCoordinates = true,
prop.closed = true,
prop.maxMarkers = 1,
prop.minMarkers = 1
}else if(prop.measureType == 'Distance'){
prop.showDistances = true,
prop.showEdges = true,
prop.maxMarkers = 2,
prop.minMarkers = 2
}else if(prop.measureType == 'MulDistance'){
prop.showDistances = true,
prop.showEdges = true,
prop.minMarkers = 2
}else if(prop.measureType == 'MulDistance Ring'){
prop.showDistances = true,
prop.showEdges = true,
prop.showArea = true,
prop.closed = true,
prop.minMarkers = 3
}else if(prop.measureType == 'Ver MulDistance'){
prop.showDistances = true,
prop.atPlane = true,
prop.showEdges = true,
prop.minMarkers = 2
prop.faceDirection = "vertical"
prop.unableDragAtMap = true
}else if(prop.measureType == 'Hor MulDistance'){
prop.showDistances = true,
prop.atPlane = true,
prop.showEdges = true,
prop.minMarkers = 2
prop.faceDirection = "horizontal"
}else if(prop.measureType == 'Ver Distance'){
prop.showDistances = true,
prop.showEdges = true,
prop.maxMarkers = 2,
prop.minMarkers = 2,
prop.faceDirection = "vertical"
prop.unableDragAtMap = true
}else if(prop.measureType == 'Hor Distance'){
prop.showDistances = true,
prop.showEdges = true,
prop.maxMarkers = 2,
prop.minMarkers = 2,
prop.faceDirection = "horizontal"
}else if(prop.measureType == 'Area'){
prop.showDistances = true,
Potree.settings.areaAtNotPlane || (prop.atPlane = true)
prop.showEdges = true,
prop.closed = true,
prop.minMarkers = 3
}else if(prop.measureType == 'Hor Area'){
prop.showDistances = true,
prop.atPlane = true,
prop.showEdges = true,
prop.closed = true,
prop.minMarkers = 3
prop.faceDirection = "horizontal"
}else if(prop.measureType == 'Ver Area'){
prop.showDistances = true,
prop.atPlane = true,
prop.showEdges = true,
prop.closed = true,
prop.minMarkers = 3
prop.faceDirection = "vertical"
prop.unableDragAtMap = true
}else if(prop.measureType == 'Rect Area'){
prop.showDistances = true,
prop.atPlane = true,
prop.showEdges = true,
prop.closed = true,
prop.minMarkers = 4
prop.maxMarkers = 4
}else if(prop.measureType == 'Hor Rect Area'){
prop.showDistances = true,
prop.atPlane = true,
prop.showEdges = true,
prop.closed = true,
prop.minMarkers = 4
prop.maxMarkers = 4
prop.isRect = true
prop.faceDirection = "horizontal"
}else if(prop.measureType == 'Ver Rect Area'){
prop.showDistances = true,
prop.atPlane = true,
prop.showEdges = true,
prop.closed = true,
prop.minMarkers = 4
prop.maxMarkers = 4
prop.isRect = true
prop.faceDirection = "vertical"
prop.unableDragAtMap = true
}
if(prop.atPlane && prop.closed){ //atPlane在同一平面上
prop.showArea = true
}
super.transformData(prop)
}
setUnitSystem(unitSystem){
//console.log(this.name +':' +this.unitSystem)
if(unitSystem != this.unitSystem){
if(unitSystem == "metric"){
}else if(unitSystem == 'imperial'){
}
this.unitSystem = unitSystem
this.expands.forEach(e=>e.unitSystem = unitSystem)
this.update()
}
}
reDraw(restMarkerCount=0){//重新开始画
super.reDraw(restMarkerCount)
if(this.measureType == 'Distance'){
this.shouldShowHorVerGuide = false
this.setEdgesDisplay(false)
}
if(this.showArea){
this.area = {value:0};
this.areaLabel && Utils.updateVisible(this.areaLabel, 'setVisible', false )
}
if(this.totalDisLabel && this.showTotalDis){
Utils.updateVisible(this.totalDisLabel, 'setVisible', false )
}
viewer.inputHandler.dispatchEvent( {type:'measuring', v:true, cause:'reDraw',object:this, situation:'dragging'} )
}
addExpand(data){//{offset,color}
data.measure = this
let expand = new ExpandLine(data)
this.expands.push(expand)
viewer.scene.overlayScene.add(expand) //this.add(expand) //因为其可见性不随父结点所以分开
}
removeExpand(expand){
let index = this.expands.indexOf(expand)
if(index > -1){
expand.dispose()
this.expands.splice(index,1)
//this.remove(expand)
}
}
}
function setLabelHightState(label, state){
if(state){
let color = new THREE.Color(Potree.config.measure.highlight.color)
//label.sprite.material.opacity = config.measure.highlight.opacity
//label.setBackgroundColor({r:255*color.r, g:255*color.g, b:255*color.b, a:config.measure.highlight.opacity})
label.sprite.material.useDepth = false;
//label.textColor = {r: this.color.r*255, g: this.color.g*255, b: this.color.b*255, a: 1}
}else{
//label.setBackgroundColor({r: this.color.r*255, g: this.color.g*255, b: this.color.b*255, a:config.measure.default.opacity})
label.sprite.material.useDepth = true
//label.sprite.material.opacity = 0.98
//label.textColor = {r: 255, g: 255, b: 255, a: 1}
}
label.updateTexture()
}
function createCircleRadiusLabel(){
const circleRadiusLabel = new TextSprite("");
circleRadiusLabel.setTextColor({r: 140, g: 250, b: 140, a: 1.0});
circleRadiusLabel.setBorderColor({r: 0, g: 0, b: 0, a: 1.0});
circleRadiusLabel.setBackgroundColor({r: 0, g: 0, b: 0, a: 1.0});
circleRadiusLabel.fontsize = 16;
circleRadiusLabel.material.depthTest = false;
circleRadiusLabel.material.opacity = 1;
circleRadiusLabel.visible = false;
return circleRadiusLabel;
}
function createCircleRadiusLine(){
var circleRadiusLine = LineDraw.createFatLine([ ],{
color:0xff0000,
dashSize: 0.5,
gapSize: 0.2,
lineWidth: config.measure.lineWidth
})
circleRadiusLine.visible = false;
return circleRadiusLine;
}
function createCircleLine(){
const coordinates = [];
let n = 128;
for(let i = 0; i <= n; i++){
let u0 = 2 * Math.PI * (i / n);
let u1 = 2 * Math.PI * (i + 1) / n;
let p0 = new THREE.Vector3(
Math.cos(u0),
Math.sin(u0),
0
);
let p1 = new THREE.Vector3(
Math.cos(u1),
Math.sin(u1),
0
);
coordinates.push(
p0,
p1
);
}
var circleLine = LineDraw.createFatLine(coordinates,{
color: 0xff0000,
dashSize: 0.5,
gapSize: 0.2,
lineWidth: config.measure.lineWidth
})
return circleLine;
}
function createLine(){
const line = LineDraw.createFatLine([ ],{
color: 0xff0000,
dashSize: 0.5,
gapSize: 0.2,
lineWidth: config.measure.lineWidth
})
return line;
}
function createCircle(){
const coordinates = [];
let n = 128;
for(let i = 0; i <= n; i++){
let u0 = 2 * Math.PI * (i / n);
let u1 = 2 * Math.PI * (i + 1) / n;
let p0 = new THREE.Vector3(
Math.cos(u0),
Math.sin(u0),
0
);
let p1 = new THREE.Vector3(
Math.cos(u1),
Math.sin(u1),
0
);
coordinates.push(
p0,
p1
);
}
var line = LineDraw.createFatLine(coordinates,{
color: 0xff0000,
dashSize: 0.5,
gapSize: 0.2,
lineWidth: config.measure.lineWidth
})
return line;
}
//缓冲区扩展,随measure改变,不可拖拽
class ExpandLine extends ctrlPolygon{
constructor (prop) {
prop.points = prop.measure.points.map(e=>e.clone()) //先复制 用来加marker
prop.unitSystem = prop.measure.unitSystem
prop.atPlane = prop.measure.atPlane
prop.closed = prop.measure.closed
super('expandLine',prop);
this.name = 'measureExpand_'+prop.measure.name
this.initData(prop)
//offset 正数为朝外
}
update(options={}){//暂时每次都全部更新,以后再改
let points = this.measure.points
let count = this.measure.points.length
let newPoints = []
let facePlane = this.getFacePlane(true) //更新normal. 不用measure的是因为measure没更新normal
let normal = facePlane?.normal //this.measure.facePlane.normal
if(!normal)return //暂时不知道怎么写
let offset = this.offset //Potree.math.getArea(this.measure.point2dInfo.points2d) > 0 ? -this.offset : this.offset // 时针受normal影响
//console.log('offset',offset, 'normal', normal.toArray(), 'clockwise', Potree.math.getArea(this.measure.point2dInfo.points2d) > 0)
for(let i=0; i{
e.material = this.measure.getMat(state ? 'edgeExpand-selected' : 'edgeExpand')
})
viewer.dispatchEvent('content_changed')
}
}
ExpandLine.prototype.getPoint2dInfo = Measure.prototype.getPoint2dInfo
ExpandLine.prototype.getConvertString = Measure.prototype.getConvertString
/*
按alt鼠标滚轮或WS键放慢。
按Alt键可以平行屏幕拖拽点。&dragPolyBeyondPoint 后缀在拖拽到无点云区域也是此效果。
按M键拖拽点可以复制出当前点
*/