var ClipPlaneManager = { clipMeshInfos: [], activeMeshInfo: undefined, anyMeshIsActive: false, adjustedClipPlanesMesh: function (params) { this.clipMeshInfos.forEach((clipMeshInfo, index) => { if (clipMeshInfo.Index != undefined) return; clipMeshInfo.Object.material.uniforms.fSharpness.value = params[0]; clipMeshInfo.Object.material.uniforms.fBrightness.value = params[1]; clipMeshInfo.Object.material.uniforms.fContrast.value = params[2]; }); }, //通过三点生成切面 generateClipPlaneByPoints: function (points, callback) { if (points.length < 3) return false; this.resetClipInfo(); //生成切面 let clipPlane = new THREE.Plane(); clipPlane.setFromCoplanarPoints(points[0], points[1], points[2]); //根据cube中心点判断切面的方向 let zero = new THREE.Vector3(0, 0, 0); cube.localToWorld(zero); let cubeVector = points[0].clone().sub(zero); let direction = cubeVector.dot(clipPlane.normal); if (direction > 0) { clipPlane.normal.negate(); clipPlane.constant = -clipPlane.constant; //cube中心点为(width/2,height/2,depth/2) //切面在中心点左侧,留cube右半部分,故相机位置在cube中心点左侧,相机距cube中心点距离 width *(2+1/2) camera.position.set(-width * 2, height / 2, depth / 2); } else { //切面在中心点右侧,留cube左半部分,故相机位置在cube中心点右侧,相机距cube中心点距离 width *(3-1/2) camera.position.set(width * 3, height / 2, depth / 2); } orbitCtl.update(); //生成切面对应的mesh let mesh = new THREE.Mesh( new THREE.PlaneGeometry(), ShaderMaterialHelper(new THREE.Texture(), []) ); scene.add(mesh); //添加切面信息 let clipMeshInfo = ClipMeshInfo.createNew(mesh, clipPlane); this.addClipMeshInfo(clipMeshInfo); this.activeMeshInfo = ActiveMeshInfo.createNew( clipMeshInfo, zero, MeshType.additionalMesh ); refreshClipMesh(clipPlane, mesh, clipMeshInfo.ImageName, function () { if (SpriteManager.clipType == ClipType.MoveClipPlane) { addRotateInfo(); } if (callback != undefined) { callback(); } }); return true; }, //通过切割线生成切面 generateClipPlane: function () { if (!LinesDrawingManager.clipLine.visible) { return; } let endPoint = LinesDrawingManager.clipLine.geometry.userData; let normal = this.activeMeshInfo.getClonedNormal(); let startPoint = this.activeMeshInfo.Point; if (startPoint.distanceTo(endPoint) == 0) return; let clipLine = startPoint.clone().sub(endPoint); let normalVector = new THREE.Vector3(); normalVector.crossVectors(clipLine, normal).normalize(); //根据cube中心点判断切面的方向 let zero = new THREE.Vector3(0, 0, 0); cube.localToWorld(zero); let cubeVector = startPoint.clone().sub(zero); if (cubeVector.dot(normalVector) > 0) { normalVector.negate(); } //生成切面 let clipPlane = new THREE.Plane(); clipPlane.setFromNormalAndCoplanarPoint(normalVector, endPoint); //移除现有切面中无用的切面 this.removeUselessClipPlane(clipPlane); //生成切面对应的mesh let mesh = new THREE.Mesh( new THREE.PlaneGeometry(), ShaderMaterialHelper(new THREE.Texture(), []) ); scene.add(mesh); //添加切面信息 let clipMeshInfo = ClipMeshInfo.createNew(mesh, clipPlane); this.addClipMeshInfo(clipMeshInfo); refreshClipMesh(clipPlane, mesh, clipMeshInfo.ImageName); LinesDrawingManager.hideClipLine(); }, //通过cube表面切面 generateCubeFaceClipPlane: function () { let clipMeshInfo = undefined; //计算切面信息(normal,distance) let normal = this.activeMeshInfo.getClonedNormal().negate(); // zero to face's first point. let faceVector = cube.localToWorld( this.activeMeshInfo.Mesh.object.geometry.vertices[ this.activeMeshInfo.Mesh.face.a ].clone() ); let distance = Math.abs(faceVector.dot(normal)) + 5; //判断切面是否已存在 if (this.clipMeshInfos.length > 0) { clipMeshInfo = this.clipMeshInfos.find( (m) => m.Plane.normal.equals(normal) && m.Plane.constant == distance ); } if (clipMeshInfo == undefined) { //生成切面对应的mesh let material = cube.material[this.activeMeshInfo.Mesh.face.materialIndex].clone(); material.clippingPlanes = []; let mesh = new THREE.Mesh(new THREE.PlaneGeometry(), material); scene.add(mesh); //生成切面 let faceClipPlane = new THREE.Plane(normal, distance); //添加切面信息 clipMeshInfo = ClipMeshInfo.createNew( mesh, faceClipPlane, this.activeMeshInfo.Mesh.face.materialIndex ); this.addClipMeshInfo(clipMeshInfo); } this.activeMeshInfo.Mesh = clipMeshInfo; this.activeMeshInfo.MeshType = MeshType.additionalMesh; }, //移除切面数组里指定位置的元素,若index未定义则移除最后一个元素 removeClipPlane: function (index) { if (index == undefined) { index = this.clipMeshInfos.length - 1; this.resetActiveMeshInfo(); } if (index < 0) return; if (this.clipMeshInfos.length <= 0) return; let clipPlane = this.clipMeshInfos[index].Plane; cube.material.forEach((material) => { ClipPlaneManager.removeMaterialClipPlane( material.clippingPlanes, clipPlane ); }); this.clipMeshInfos.forEach((m) => { if (m.Object.material.clippingPlanes.length > 0) { ClipPlaneManager.removeMaterialClipPlane( m.Object.material.clippingPlanes, clipPlane ); } }); scene.remove(this.clipMeshInfos[index].Object); // jsObj.DeleteClipImageData(this.clipMeshInfos[index].ImageName); Dart_deleteClipImageData(this.clipMeshInfos[index].ImageName); this.clipMeshInfos[index].dispose(); this.clipMeshInfos.splice(index, 1); }, //排序:将最后激活的切面移到切面列表的最后 moveElementToEnd: function (clipMeshInfo) { let index = this.clipMeshInfos.findIndex( (n) => n.Object == clipMeshInfo.Object && n.Plane == clipMeshInfo.Plane ); this.clipMeshInfos.splice(index, 1); this.clipMeshInfos.push(clipMeshInfo); }, //获取鼠标点击时激活的面信息 getActiveMeshInfo: function (raycaster) { let intersects = raycaster.intersectObject(cube); if (intersects.length <= 0) { //not intersect cube return undefined; } if (this.clipMeshInfos.length > 0) { let distance = 0; let intersectMesh = undefined; let clipMeshInfo = undefined; this.clipMeshInfos.forEach((m) => { let meshIntersectObject = raycaster.intersectObject(m.Object); //取鼠标最远拾取的mesh if (meshIntersectObject.length > 0) { if (distance < meshIntersectObject[0].distance) { intersectMesh = meshIntersectObject[0]; clipMeshInfo = m; distance = meshIntersectObject[0].distance; } } }); if (distance > 0) { return ActiveMeshInfo.createNew( clipMeshInfo, intersectMesh.point, MeshType.additionalMesh ); } } return ActiveMeshInfo.createNew( intersects[0], intersects[0].point, MeshType.cube ); }, //获取激活面的边框线 getActiveMeshBorders: function () { let meshBorders = []; if (this.activeMeshInfo.Vertices.length > 1) { for ( let cursor = 0; cursor < this.activeMeshInfo.Vertices.length - 1; cursor++ ) { meshBorders.push( new THREE.Line3( this.activeMeshInfo.Vertices[cursor], this.activeMeshInfo.Vertices[cursor + 1] ) ); } } return meshBorders; }, //获取使用同一转轴的相邻面(非激活面)的法向量 getNeighbourPlaneNormal: function (line, clipMeshInfo) { //查找包含旋转轴line的切面法向量 let projectStartPoint = new THREE.Vector3(); let projectEndPoint = new THREE.Vector3(); let clippingPlanes = clipMeshInfo.Object.material.clippingPlanes; if (clippingPlanes != undefined && clippingPlanes.length > 0) { for (let cursor = 0; cursor < clippingPlanes.length; cursor++) { clippingPlanes[cursor].projectPoint(line.start, projectStartPoint); clippingPlanes[cursor].projectPoint(line.end, projectEndPoint); if ( line.start.distanceTo(projectStartPoint) < Accuracy && line.end.distanceTo(projectEndPoint) < Accuracy ) { return clippingPlanes[cursor].normal; } } } //查找包含旋转轴line的cube face法向量 //判断旋转轴是否在cube的左/右面上且cubeFace在旋转范围内 if ( this.isLineInCubeFaceByFaceNormal(line, CubeFaceNormalHelper.Left) && this.isWithinRotateRange( CubeFaceNormalHelper.Left, clipMeshInfo.Plane.normal ) ) { return CubeFaceNormalHelper.Left; } //判断旋转轴是否在cube的前/后面上且cubeFace在旋转范围内 if ( this.isLineInCubeFaceByFaceNormal(line, CubeFaceNormalHelper.Front) && this.isWithinRotateRange( CubeFaceNormalHelper.Front, clipMeshInfo.Plane.normal ) ) { return CubeFaceNormalHelper.Front; } //判断旋转轴是否在cube的上/下面上且cubeFace在旋转范围内 if ( this.isLineInCubeFaceByFaceNormal(line, CubeFaceNormalHelper.Down) && this.isWithinRotateRange( CubeFaceNormalHelper.Down, clipMeshInfo.Plane.normal ) ) { return CubeFaceNormalHelper.Down; } return undefined; }, //判断线line是否在法向量为normal的cube面或其对面上 isLineInCubeFaceByFaceNormal: function (line, normal) { let startValue = Math.round(Math.abs(line.start.dot(normal))); let endValue = Math.round(Math.abs(line.end.dot(normal))); //(width,height,depth)与向量点乘 let faceValue = Math.abs( normal.x * width + normal.y * height + normal.z * depth ); if ( (startValue == 0 && endValue == 0) || (startValue == faceValue && endValue == faceValue) ) { return true; } return false; }, //判断平面向量是否在切面旋转范围内 isWithinRotateRange: function (planeNormal, currentClipPlaneNormal) { let angle = Math.abs(planeNormal.angleTo(currentClipPlaneNormal)); if (angle > MinRotateAngle && angle < MaxRotateAngle) { return true; } return false; }, //重置切面信息 resetActiveMeshInfo: function () { this.activeMeshInfo = undefined; }, //检查当前鼠标选中的面是否被完全切掉 isActivePlaneCompleteClipped: function () { if (this.activeMeshInfo == undefined) return true; let clipPlanes = this.activeMeshInfo.Mesh.Object.material.clippingPlanes; let existedPoints = []; if (clipPlanes != null) { let projectPoint = new THREE.Vector3(); this.activeMeshInfo.Vertices.forEach((point) => { if (pointIsDuplicate(existedPoints, point)) { return; } //检查当前point是否被切割掉 let isClipped = clipPlanes.some((clipPlane) => { clipPlane.projectPoint(point, projectPoint); if (point.xyzFixedEq(projectPoint, 3)) { return false; } let projectDirection = point.clone().sub(projectPoint); //点到投影点的向量与平面夹角为锐角或直角则未被切掉 if (projectDirection.dot(clipPlane.normal) >= 0) { return false; } return true; }); if (!isClipped) { existedPoints.push(point); } }); if (existedPoints.length <= 2) { return true; } return false; } return false; }, //计算当前切面可向前推动的最大距离 setMaxForwardDistance: function () { let farClipPoint = this.getFarClipPoint( this.activeMeshInfo.Mesh, this.activeMeshInfo.Vertices ); this.activeMeshInfo.MaxForwardDistance = -farClipPoint.dot(this.activeMeshInfo.Mesh.Plane.normal) + 10; //放在正方向前面一点 }, //计算当前切面可向前推到的最远点 getFarClipPoint: function (clipMeshInfo, activePoints) { //求cube顶点到切面的最大距离 let maxDistance = clipMeshInfo.Plane.distanceToPoint( cube.localToWorld(cube.geometry.vertices[0].clone()) ); cube.geometry.vertices.forEach((m) => { let distance = clipMeshInfo.Plane.distanceToPoint( cube.localToWorld(m.clone()) ); if (distance > maxDistance) { maxDistance = distance; } }); //获取切面中心点 let centerPoint = PolyPointsTool.getPolyCenter(activePoints); var meshCenterToVertices = { createNew: function (line) { var node = {}; node.line = line; node.intersectWithPlane = false; return node; }, }; //最远距离的顶点到切面可见中心点的连线集合 let lineNodes = []; cube.geometry.vertices.forEach((m) => { let vector = cube.localToWorld(m.clone()); let distance = clipMeshInfo.Plane.distanceToPoint(vector); if (distance == maxDistance) { lineNodes.push( meshCenterToVertices.createNew(new THREE.Line3(centerPoint, vector)) ); } }); //取与中心点的连线相交的切面 let intersectPlanes = clipMeshInfo.Object.material.clippingPlanes.filter( (m) => { let result = false; lineNodes.forEach((lineNode) => { if (m.intersectsLine(lineNode.line)) { result = true; //被切面挡住了就标记这根线跟面相交过 lineNode.intersectWithPlane = true; } }); return result; } ); //如果存在未与切面相交的线,则最远距离即为cube顶点到切面的最大距离 let lineNode = lineNodes.find((m) => m.intersectWithPlane == false); if (lineNode != undefined) { return lineNode.line.end; } let farPoints = []; //获取所有与中心点的连线相交切面的顶点 intersectPlanes.forEach((m) => { let node = this.clipMeshInfos.find((n) => n.Plane == m); let points = LineIntersectionHelper.getActiveMeshPoints( node.Object.material.clippingPlanes, node.Object.geometry.vertices, node.Plane.normal ); farPoints = farPoints.concat(points); }); //遍历顶点求出最远距离点 let farClipPoint = undefined; maxDistance = 0; farPoints.forEach((m) => { let distance = clipMeshInfo.Plane.distanceToPoint(m); if (distance > maxDistance) { farClipPoint = m; maxDistance = distance; } }); return farClipPoint; }, //添加切面信息 addClipMeshInfo: function (clipMeshInfo) { cube.material.forEach((material) => { material.clippingPlanes.push(clipMeshInfo.Plane); }); this.clipMeshInfos.forEach((m) => { m.Object.material.clippingPlanes.push(clipMeshInfo.Plane); }); this.clipMeshInfos.forEach((m) => { clipMeshInfo.Object.material.clippingPlanes.push(m.Plane); }); this.clipMeshInfos.push(clipMeshInfo); }, //移除纹理切面列表中的指定切面 removeMaterialClipPlane: function (clipPlanes, clipPlane) { let index = clipPlanes.findIndex((n) => n == clipPlane); if (index != -1) { clipPlanes.splice(index, 1); } }, //移除无用的切面 removeUselessClipPlane: function (newClipPlane) { let removeNodes = []; //遍历所有切面 this.clipMeshInfos.forEach((clipMeshInfo) => { //获取切面顶点信息 let vertices = clipMeshInfo.Object.geometry.vertices; vertices = LineIntersectionHelper.getActiveMeshPoints( clipMeshInfo.Object.material.clippingPlanes, vertices, clipMeshInfo.Plane.normal ); let projectPoint = new THREE.Vector3(); let tempResult = []; //遍历所有顶点,计算顶点到新切面的投影向量与新切面法向量的点乘信息 vertices.forEach((m) => { newClipPlane.projectPoint(m, projectPoint); tempResult.push(m.clone().sub(projectPoint).dot(newClipPlane.normal)); }); let minValue = tempResult.min(); let maxValue = tempResult.max(); if (minValue * maxValue > 0) { //切面所有顶点都在新切面的一侧 if (maxValue < 0) { //切面顶点到新切面的向量与新切面的法向量夹角的最大值为锐角,该切面需要删除 removeNodes.push(clipMeshInfo); } } }); //删除切面 removeNodes.forEach((m) => { let index = this.clipMeshInfos.findIndex((n) => n == m); if (index != -1) { this.removeClipPlane(index); } }); }, //移除所有切面 removeAllClipPlane: function () { this.clipMeshInfos.forEach((m) => { scene.remove(m.Object); m.dispose(); }); this.clipMeshInfos.splice(0, this.clipMeshInfos.length); cube.material.forEach((material) => { material.clippingPlanes.splice(0, material.clippingPlanes.length); }); // jsObj.DeleteAllClipImageData(); Dart_deleteAllClipImageData("useless arg"); this.resetActiveMeshInfo(); }, //获取当前切割面的信息以供测量使用 getSelectedClipInfo: function () { let activeMeshInfo = this.activeMeshInfo; if ( activeMeshInfo == undefined || activeMeshInfo.Vertices == undefined || activeMeshInfo.Vertices.length < 3 ) { return undefined; } let points = []; activeMeshInfo.Vertices.forEach((m) => { if (!pointIsDuplicate(points, m)) { points.push(m.clone()); } }); convertToVTKPoints(points); let mappingPoints = []; points.forEach((item) => { mappingPoints.push(new cefMappingPoint(item.x, item.y, item.z)); }); let faceType; let flip = false; if (activeMeshInfo.MeshType == MeshType.cube) { faceType = CubeFaceNormalHelper.getClipFaceType( activeMeshInfo.Mesh.face.normal.clone().negate() ); flip = faceType === ClipFaceType.Left || faceType === ClipFaceType.Down || faceType === ClipFaceType.Front; } else { faceType = CubeFaceNormalHelper.getClipFaceType( activeMeshInfo.Mesh.Normal ); if (activeMeshInfo.Mesh.Index != undefined) { flip = faceType === ClipFaceType.Left || faceType === ClipFaceType.Down || faceType === ClipFaceType.Front; } else { flip = activeMeshInfo.Mesh.Object.geometry.faces[0].b > activeMeshInfo.Mesh.Object.geometry.faces[0].c; } } let clipCategory = faceType === ClipFaceType.Up || faceType === ClipFaceType.Down ? ClipCategory.Soleplate : ClipCategory.Flank; let clipInformation = { PointsList: mappingPoints, ClipCategory: clipCategory, Flip: flip, }; return clipInformation; }, drawActiveMeshEdges: function () { let activeMeshInfo = this.activeMeshInfo; if (activeMeshInfo == undefined) return; let drawVertices; let clippingPlanes = activeMeshInfo.getClipPlanes(); if (activeMeshInfo.MeshType === MeshType.cube) { drawVertices = getCubeFaceVertices(activeMeshInfo, clippingPlanes); drawVertices = LineIntersectionHelper.getActiveMeshPoints( clippingPlanes, drawVertices, activeMeshInfo.Mesh.face.normal ); } else { drawVertices = activeMeshInfo.getClonedVertices(); ClipPlaneManager.moveElementToEnd(activeMeshInfo.Mesh); drawVertices = LineIntersectionHelper.getActiveMeshPoints( clippingPlanes, drawVertices, activeMeshInfo.Mesh.Plane.normal ); } LinesDrawingManager.showMeshEdgeLines(drawVertices, clippingPlanes); activeMeshInfo.Vertices = drawVertices; //获取选中cube面的顶点信息 function getCubeFaceVertices(activeMeshInfo) { let vertices = activeMeshInfo.getClonedVertices(); let selectedCubeFace = activeMeshInfo.Mesh.object.geometry.faces.find( (m) => m.normal == activeMeshInfo.Mesh.face.normal ); let besideCubeFace = activeMeshInfo.Mesh.object.geometry.faces.find( (m) => m != selectedCubeFace && m.materialIndex == selectedCubeFace.materialIndex ); let tempIndexArray = [ besideCubeFace.a, besideCubeFace.b, besideCubeFace.c, ]; let diagonalIndex = tempIndexArray.find( (m) => m != selectedCubeFace.a && m != selectedCubeFace.b && m != selectedCubeFace.c ); let tempPoints = [ vertices[selectedCubeFace.a].clone(), vertices[selectedCubeFace.b].clone(), vertices[selectedCubeFace.c].clone(), vertices[diagonalIndex].clone(), ]; tempPoints.forEach((vector) => { cube.localToWorld(vector); }); //顶点排序 let drawVertices = PolyPointsTool.clockwiseSortPoints( tempPoints, activeMeshInfo.Mesh.face.normal ); return drawVertices; } }, resetClipInfo: function () { LinesDrawingManager.hideClipLine(); this.removeAllClipPlane(); removeRotateInfo(); LinesDrawingManager.hideAll(); }, meshIsActive: function () { if (!ClipPlaneManager.anyMeshIsActive) { ClipPlaneManager.anyMeshIsActive = true; // jsObj.MeshActiveStatusChanged(true); Dart_meshActiveStatusChanged(true); return; } }, meshIsInactive() { if (ClipPlaneManager.anyMeshIsActive) { ClipPlaneManager.anyMeshIsActive = false; // jsObj.MeshActiveStatusChanged(false); Dart_meshActiveStatusChanged(false); return; } }, };