fix #IUBJH EdgeGeometry显示错误和死循环

pull/269/MERGE
ChenX 6 years ago
parent 2aa49984c1
commit ee40d14343

@ -0,0 +1,21 @@
import { LoadEntityFromFileData } from "../Utils/LoadEntity.util";
import { Board } from "../../src/DatabaseServices/Board";
import { RenderType } from "../../src/GraphicsSystem/RenderType";
import { Line } from "three";
test('EdgeGeometry生成', () =>
{
let d = [1, "Board", 3, 2, 101, false, 1, 2, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -646.2420911908739, 230.97217145381728, -423.9845986472139, 1], 2, 484.63826594239083, 642.7439363026181, 18, false, "Polyline", 3, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 54.03714224287984, -40.88462318428341, 0, 1], 2, 6, [226.89796571085776, 338.3121692475904], 0, [248.97426264670497, 525.5228891266743], 0, [-54.03714224287984, 287.9783168893773], 0, [141.82369879876416, 40.88462318428341], 0, [588.7067940597382, 306.7620304373949], 0, [320.72013691164284, 378.99785818408446], 0, true, 1, 2, 109.48289947281157, 198.20905225226585, 18, false, "Polyline", 3, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -208.29382686305865, -201.59010496470867, 0, 1], 2, 4, [298.05328308824403, 206.16728215262995], 0, [208.29382686305865, 201.59010496470867], 0, [267.90926007565713, 311.07300443752024], 0, [406.5028791153245, 272.1962944735834], 0, true, 0, 3, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -646.2420911908739, 493.3031405597556, -263.2791168667886, 1], 3, 0, 0, 0, 2, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -314.3564875158372, 4019.556363898919, -46.81305616698228, 1], 1, "右侧板", "{\"roomName\":\"\",\"cabinetName\":\"\",\"boardName\":\"\",\"material\":\"\",\"color\":\"\",\"lines\":0,\"bigHoleDir\":0,\"drillType\":\"three\",\"composingFace\":2,\"highSealed\":[],\"sealedUp\":\"1\",\"sealedDown\":\"1\",\"sealedLeft\":\"1\",\"sealedRight\":\"1\",\"spliteHeight\":\"\",\"spliteWidth\":\"\",\"spliteThickness\":\"\"}", 0, 0];
let br: Board = LoadEntityFromFileData(d)[0] as Board;
let obj = br.GetDrawObjectFromRenderType(RenderType.Wireframe);
let line = obj.children[0] as Line;
let geo = line.geometry;
//@ts-ignore
expect(geo.attributes.position.length).toBe(240);
});

@ -7,7 +7,7 @@ import { Circle } from '../Circle';
import { Contour } from '../Contour';
import { Shape } from '../Shape';
import { Solid3D } from "./Solid3D";
import { EdgesGeometry2 } from '../../Geometry/EdgeGeometry';
import { EdgesGeometry } from '../../Geometry/EdgeGeometry';
import { ColorMaterial } from '../../Common/ColorPalette';
import { DisposeThreeObj } from '../../Common/Dispose';
@ -87,7 +87,7 @@ export class GangDrill extends Solid3D
{
if (renderType === RenderType.Wireframe)
{
return new LineSegments(new EdgesGeometry2(this.CreateGeometry(), 2), ColorMaterial.GetLineMaterial(this.ColorIndex));
return new LineSegments(new EdgesGeometry(this.CreateGeometry(), 2), ColorMaterial.GetLineMaterial(this.ColorIndex));
}
else
return new THREE.Mesh(this.CreateGeometry(), new MeshNormalMaterial());

@ -10,7 +10,7 @@ import { PhysicalMaterialRecord } from '../PhysicalMaterialRecord';
import { IsPointInPolyLine } from '../PointInPolyline';
import { Polyline } from '../Polyline';
import { Solid3D } from "./Solid3D";
import { EdgesGeometry2 } from '../../Geometry/EdgeGeometry';
import { EdgesGeometry } from '../../Geometry/EdgeGeometry';
import { ColorMaterial } from '../../Common/ColorPalette';
import { DisposeThreeObj } from '../../Common/Dispose';
@ -111,7 +111,7 @@ export class SweepSolid extends Solid3D
{
if (renderType === RenderType.Wireframe)
{
let geo = new EdgesGeometry2(this.CreateGeomtry(), 2);
let geo = new EdgesGeometry(this.CreateGeomtry());
return new LineSegments(geo, ColorMaterial.GetLineMaterial(this.ColorIndex));
}
else

@ -8,7 +8,7 @@ import { Status, UpdateDraw } from "../Common/Status";
import { ObjectSnapMode } from "../Editor/ObjectSnapMode";
import { boardUVGenerator } from "../Geometry/BoardUVGenerator";
import { BSPGroupParse } from "../Geometry/BSPGroupParse";
import { EdgesGeometry2 } from "../Geometry/EdgeGeometry";
import { EdgesGeometry } from "../Geometry/EdgeGeometry";
import { cZeroVec, equaln, equalv2, equalv3, isIntersect, isParallelTo, MoveMatrix } from "../Geometry/GeUtils";
import { CSG } from "../Geometry/ThreeCSG";
import { ScaleUV } from "../Geometry/UVUtils";
@ -999,13 +999,13 @@ export class ExtureSolid extends Entity
this._MeshGeometry = this.GeneralGeometry();
return this._MeshGeometry;
}
private _EdgeGeometry: EdgesGeometry2;
private _EdgeGeometry: EdgesGeometry;
private get EdgeGeometry()
{
if (this._EdgeGeometry)
return this._EdgeGeometry;
this._EdgeGeometry = new EdgesGeometry2(this.MeshGeometry, 2);
this._EdgeGeometry = new EdgesGeometry(this.MeshGeometry);
return this._EdgeGeometry;
}

@ -1,155 +1,21 @@
import { BufferGeometry, Vector3, Geometry, Line3, Face3, Float32BufferAttribute } from "three";
import { BufferGeometry, Face3, Float32BufferAttribute, Geometry, Line3, Triangle, Vector3 } from "three";
import { arraySortByNumber } from "../Common/ArrayExt";
//ref: https://github.com/mrdoob/js/issues/10517
export class OutlinesGeometry extends BufferGeometry
{
constructor(geometry, thresholdAngle: number)
{
super();
thresholdAngle = (thresholdAngle !== undefined) ? thresholdAngle : 1;
let thresholdDot = Math.cos(Math.PI / 180 * thresholdAngle);
let edge = [0, 0], hash = {}, i, j, l, face, key;
function sortFunction(a, b)
{
return a - b;
}
let keys = ['a', 'b', 'c'];
let geometry2;
if (geometry.isBufferGeometry)
{
geometry2 = new Geometry();
geometry2.fromBufferGeometry(geometry);
}
else
{
geometry2 = geometry.clone();
}
geometry2.mergeVertices();
geometry2.computeFaceNormals();
let vertices = geometry2.vertices;
let faces = geometry2.faces;
for (i = 0; i < faces.length; i++)
{
face = faces[i];
for (j = 0; j < 3; j++)
{
edge[0] = face[keys[j]];
edge[1] = face[keys[(j + 1) % 3]];
let line = new Line3(vertices[edge[0]], vertices[edge[1]]);
// for each vertex checks if it lies in the edge
for (let e = vertices.length - 1; e >= 0; e--)
{
if (e === edge[0] || e === edge[1]) continue;
let v = vertices[e];
let closestPoint = line.closestPointToPoint(v, true, new Vector3());
if ((new Line3(closestPoint, v)).distance() < 1e-5)
{ //1e-5
// mark the current face as splitted so that his cords won't be considered
face.splitted = true;
// Add two new faces, created splitting the face in two
faces.push(new Face3(
e, face[keys[(j + 2) % 3]], face[keys[(j) % 3]],
face.normal, face.color, face.materialIndex
));
faces.push(new Face3(
e, face[keys[(j + 2) % 3]], face[keys[(j + 1) % 3]],
face.normal, face.color, face.materialIndex
));
break;
}
}
if (face.splitted) break;
}
}
for (i = faces.length - 1; i >= 0; i--)
{
face = faces[i];
if (face.splitted) continue;
for (j = 0; j < 3; j++)
{
edge[0] = face[keys[j]];
edge[1] = face[keys[(j + 1) % 3]];
edge.sort(sortFunction);
key = edge.toString();
if (hash[key] === undefined)
{
hash[key] = { vert1: edge[0], vert2: edge[1], face1: i, face2: undefined };
}
else
{
hash[key].face2 = i;
}
}
}
const keys = ['a', 'b', 'c'];
let coords = [];
for (key in hash)
export class EdgesGeometry extends BufferGeometry
{
let h = hash[key];
// An edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree.
if (h.face2 !== undefined && faces[h.face1].normal.dot(faces[h.face2].normal) <= thresholdDot)
{
let vertex = vertices[h.vert1];
coords.push(vertex.x);
coords.push(vertex.y);
coords.push(vertex.z);
vertex = vertices[h.vert2];
coords.push(vertex.x);
coords.push(vertex.y);
coords.push(vertex.z);
}
}
this.addAttribute('position', new Float32BufferAttribute(coords, 3));
}
}
export class EdgesGeometry2 extends BufferGeometry
{
constructor(geometry, thresholdAngle: number)
constructor(geometry, thresholdAngle: number = 1)
{
super();
thresholdAngle = (thresholdAngle !== undefined) ? thresholdAngle : 1;
let thresholdDot = Math.cos(Math.PI / 180 * thresholdAngle);
let edge = [0, 0], hash = {};
function sortFunction(a, b)
{
return a - b;
}
let keys = ['a', 'b', 'c'];
let geometry2;
let geometry2: Geometry;
if (geometry.isBufferGeometry)
{
geometry2 = new Geometry();
geometry2.fromBufferGeometry(geometry);
}
geometry2 = new Geometry().fromBufferGeometry(geometry);
else
{
geometry2 = geometry.clone();
}
geometry2.mergeVertices();
geometry2.computeFaceNormals();
@ -157,75 +23,88 @@ export class EdgesGeometry2 extends BufferGeometry
let vertices = geometry2.vertices;
let faces = geometry2.faces;
let faceHash = new Set<string>();
for (let i = 0; i < faces.length; i++)
{
if (i > 1000)//出错
break;
let face = faces[i];
//fix CSG produces duplicate faces
let faceStr = `${face.a},${face.b},${face.c}`;
if (faceHash.has(faceStr))
continue;
faceHash.add(faceStr);
for (let j = 0; j < 3; j++)
{
let e1 = face[keys[j]];
let e2 = face[keys[(j + 1) % 3]];
let e3 = face[keys[(j + 2) % 3]];
edge[0] = face[keys[j]];
edge[1] = face[keys[(j + 1) % 3]];
let line = new Line3(vertices[edge[0]], vertices[edge[1]]);
let line = new Line3(vertices[e1], vertices[e2]);
//split triangle
for (let e = 0, l = vertices.length; e < l; e++)
{
if (e === edge[0] || e === edge[1]) continue;
let v = vertices[e];
let closestPoint = line.closestPointToPoint(v, true, new Vector3());
if (closestPoint.equals(vertices[edge[0]]) || closestPoint.equals(vertices[edge[0]])) continue;
if ((new Line3(closestPoint, v)).distance() < 1e-5)
{ //1e-5
// mark the current face as splitted so that his cords won't be considered
face.splitted = true;
// split the face in two using the new point
faces.push(new Face3(
e, face[keys[(j + 2) % 3]], face[keys[(j) % 3]],
face.normal, face.color, face.materialIndex
));
faces.push(new Face3(
e, face[keys[(j + 2) % 3]], face[keys[(j + 1) % 3]],
face.normal, face.color, face.materialIndex
));
if (e === e1 || e === e2 || e === e3)
continue;
let p = vertices[e];
let closestPoint = line.closestPointToPoint(p, true, new Vector3());
if (closestPoint.equals(vertices[e1]) || closestPoint.equals(vertices[e2]))
continue;
if (closestPoint.distanceTo(p) < 1e-5)
{
face["splitted"] = true;
let f1 = new Face3(e, e3, e1, face.normal);
let f2 = new Face3(e, e3, e2, face.normal);
if (FaceArea(f1, vertices) > 1
&& FaceArea(f2, vertices) > 1)
faces.push(f1, f2);
break;
}
}
if (face.splitted) break;
if (face["splitted"])
break;
}
}
let edge = [0, 0];
let hash: { [key: string]: { vert1: number, vert2: number, face1: Face3, face2?: Face3 } } = {};
for (let i = 0, l = faces.length; i < l; i++)
{
let face = faces[i];
if (face.splitted) continue;
if (face["splitted"]) continue;
for (let j = 0; j < 3; j++)
{
edge[0] = face[keys[j]];
edge[1] = face[keys[(j + 1) % 3]];
edge.sort(sortFunction);
arraySortByNumber(edge);
let key = edge.toString();
if (hash[key] === undefined)
{
hash[key] = { vert1: edge[0], vert2: edge[1], face1: i, face2: undefined };
}
hash[key] = { vert1: edge[0], vert2: edge[1], face1: face };
else
{
hash[key].face2 = i;
hash[key].face2 = face;
}
}
}
let coords = [];
let coords: number[] = [];
let thresholdDot = Math.cos(Math.PI / 180 * thresholdAngle);
for (let key in hash)
{
let h = hash[key];
// An edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree.
if (h.face2 !== undefined && faces[h.face1].normal.dot(faces[h.face2].normal) <= thresholdDot)
if (h.face2 && h.face1.normal.dot(h.face2.normal) <= thresholdDot)
{
let vertex = vertices[h.vert1];
coords.push(vertex.x);
@ -241,3 +120,13 @@ export class EdgesGeometry2 extends BufferGeometry
this.addAttribute('position', new Float32BufferAttribute(coords, 3));
}
}
let triangle = new Triangle();
function FaceArea(f: Face3, pts: Vector3[])
{
triangle.a = pts[f.a];
triangle.b = pts[f.b];
triangle.c = pts[f.c];
return triangle.getArea()
}

Loading…
Cancel
Save