import math from './math' import Colors from '@sdk/modules/core/enum/Colors' import config from '@sdk/internal/configs' //画线等函数--by 许钟文 import { Fatline, LineGeometry, LineMaterial } from '@sdk/modules/core/objects/Line.js' var defaultColor = Colors.lightGreen let player = null var LineDraw = { /* 多段普通线 (第二个点和第三个点之间是没有线段的, 所以不用在意线段顺序) */ createLine: function (posArr, o) { var mat if (o.mat) { mat = o.mat } else { let prop = { color: o.color || defaultColor, transparent: o.dontAlwaysSeen ? false : true, depthTest: o.dontAlwaysSeen ? true : false, } if (o.deshed) { prop.lineWidth = o.lineWidth || 1 //windows无效。 似乎mac/ios上粗细有效 ? prop.dashSize = o.dashSize || 0.1 prop.gapSize = o.gapSize || 0.1 } mat = new THREE[o.deshed ? 'LineDashedMaterial' : 'LineBasicMaterial'](prop) } var line = new THREE.LineSegments(new THREE.BufferGeometry(), mat) line.renderOrder = o.renderOrder || 4 this.moveLine(line, posArr) return line }, moveLine: function (line, posArr) { if (posArr.length == 0) { return console.log(1) } let position = [] posArr.forEach(e => position.push(e.x, e.y, e.z)) line.geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(position), 3)) line.geometry.attributes.position.needsUpdate = true line.geometry.computeBoundingSphere() if (line.material instanceof THREE.LineDashedMaterial) { line.computeLineDistances() } }, createFatLineMat: function (o) { let matParam = Object.assign( {}, { //默认 lineWidth: 5, color: 0xffffff, transparent: true, depthWrite: false, depthTest: false, dashSize: 0.1, gapSize: 0.1, }, o, { //修正覆盖: // dashed /* polygonOffset: true, //是否开启多边形偏移 for not cover the lineMesh polygonOffsetFactor: -o.width * 2.5 || -5, //多边形偏移因子 polygonOffsetUnits: -4.0, //多边形偏移单位 */ } ) var mat = new LineMaterial(matParam) return mat }, /* 创建可以改变粗细的线。 */ createFatLine: function (posArr, o) { let geometry = new LineGeometry() geometry.setColors(o.color || [1, 1, 1]) var matLine = o.material || this.createFatLineMat(o) let line = new Fatline(geometry, matLine) //line.computeLineDistances(); line.scale.set(1, 1, 1) line.renderOrder = 2 this.moveFatLine(line, posArr) return line }, /* createFatLine: function (posArr, o) { var geometry = new THREE.BufferGeometry() geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(posArr), 3)) geometry.setAttribute('color', new THREE.BufferAttribute(new Float32Array(o.color || [1, 1, 1]), 3)) var matLine = o.material || this.createFatLineMat(o) var line = new THREE.Line(geometry, matLine) line.computeLineDistances() line.scale.set(1, 1, 1) line.renderOrder = 2 return line }, */ moveFatLine: function (line, posArr) { var geometry = line.geometry var positions = [] posArr.forEach(e => positions.push(e.x, e.y, e.z)) if (positions.length > 0) { if (!geometry) { geometry = line.geometry = new LineGeometry() } if (geometry.attributes.instanceEnd && geometry.attributes.instanceEnd.data.array.length != positions.length) { //positions个数改变会有部分显示不出来,所以重建 geometry.dispose() geometry = new LineGeometry() line.geometry = geometry } geometry.setPositions(positions) if (line.material.dashed) { //line.geometry.computeBoundingSphere(); line.computeLineDistances() } } else { geometry.dispose() line.geometry = new LineGeometry() } }, /* moveFatLine: function (line, posArr) { var geometry = line.geometry geometry.setPositions(posArr) }, */ /* 为line创建用于检测鼠标的透明mesh,实际是个1-2段圆台。 由于近大远小的原因,假设没有透视畸变、创建的是等粗的圆柱的话, 所看到的线上每个位置的粗细应该和距离成反比。所以将圆柱改为根据距离线性渐变其截面半径的圆台,在最近点(相机到线的垂足)最细。如果最近点在线段上,则分成两段圆台,否则一段。 */ createBoldLine: function (points, o, p) { player = p o = o || {} var cylinder = o && o.cylinder var CD = points[1].clone().sub(points[0]) var rotate = function () { //根据端点旋转好模型 cylinder.lastVector = CD //记录本次的端点向量 var AB = new THREE.Vector3(0, -1, 0) var axisVec = AB.clone().cross(CD).normalize() //得到垂直于它们的向量,也就是旋转轴 var rotationAngle = AB.angleTo(CD) cylinder.quaternion.setFromAxisAngle(axisVec, rotationAngle) } if (o && o.type == 'init') { cylinder = new THREE.Mesh() cylinder.material = o.mat if (CD.length() == 0) return cylinder rotate() } if (CD.length() == 0) return cylinder if (o.type != 'update') { var CDcenter = points[0].clone().add(points[1]).multiplyScalar(0.5) cylinder.position.copy(CDcenter) if (!cylinder.lastVector || o.type == 'moveAndRotate') rotate() else if (cylinder.lastVector && CD.angleTo(cylinder.lastVector) > 0) rotate() //线方向改了or线反向了 重新旋转一下模型 // if (config.isEdit && !objects.mainDesign.editing) return cylinder //节省初始加载时间? } //为了保证线段任何地方的可检测点击范围看起来一样大,更新圆台的结构(但是在镜头边缘会比中心看起来大) var height = points[0].distanceTo(points[1]) var standPos = (o && o.standPos) || player.position var k = config.isMobile ? 20 : 40 var dis1 = points[0].distanceTo(standPos) var dis2 = points[1].distanceTo(standPos) var foot = math.getFootPoint(standPos, points[0], points[1]) //垂足 if (o.constantBold || player.mode != 'panorama') { var width = 0.1 //0.08; var pts = [new THREE.Vector2(width, height / 2), new THREE.Vector2(width, -height / 2)] } else if (foot.clone().sub(points[0]).dot(foot.clone().sub(points[1])) > 0) { //foot不在线段上 var pts = [new THREE.Vector2(dis1 / k, height / 2), new THREE.Vector2(dis2 / k, -height / 2)] } else { //在线段上的话,要在垂足这加一个节点,因它距离站位最近,而两端较远 var dis3 = foot.distanceTo(standPos) var len = foot.distanceTo(points[0]) var pts = [new THREE.Vector2(dis1 / k, height / 2), new THREE.Vector2(dis3 / k, height / 2 - len), new THREE.Vector2(dis2 / k, -height / 2)] } cylinder.geometry && cylinder.geometry.dispose() //若不删除会占用内存 cylinder.geometry = new THREE.LatheBufferGeometry(pts, 4 /* Math.min(dis1,dis2)<10?4:3 */) cylinder.renderOrder = 2 return cylinder }, updateBoldLine: function (cylinder, points, type, standPos, constantBold) { this.createBoldLine(points, { type: type, cylinder: cylinder, standPos: standPos, constantBold }, player) //type:move:平移 会改长短 , type:update根据距离和角度更新 不改长短 }, Fatline, fatLineGeometry:LineGeometry, } export default LineDraw