fluidcad 0.0.26 → 0.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/dist/common/shape-factory.d.ts +1 -1
- package/lib/dist/common/shapes.d.ts +0 -1
- package/lib/dist/common/shapes.js +0 -1
- package/lib/dist/core/extrude.d.ts +12 -13
- package/lib/dist/core/extrude.js +19 -1
- package/lib/dist/core/part.d.ts +2 -1
- package/lib/dist/core/part.js +4 -1
- package/lib/dist/core/sketch.d.ts +4 -3
- package/lib/dist/core/sketch.js +4 -1
- package/lib/dist/features/extrude-base.d.ts +7 -1
- package/lib/dist/features/extrude-base.js +36 -3
- package/lib/dist/features/extrude-to-face.d.ts +1 -1
- package/lib/dist/features/extrude-to-face.js +29 -17
- package/lib/dist/features/extrude-two-distances.d.ts +1 -1
- package/lib/dist/features/extrude-two-distances.js +23 -12
- package/lib/dist/features/extrude.d.ts +1 -1
- package/lib/dist/features/extrude.js +47 -15
- package/lib/dist/features/mirror-shape.d.ts +1 -3
- package/lib/dist/features/mirror-shape.js +2 -1
- package/lib/dist/features/revolve.js +4 -2
- package/lib/dist/features/rotate.js +1 -0
- package/lib/dist/features/simple-extruder.js +5 -0
- package/lib/dist/features/translate.js +3 -1
- package/lib/dist/filters/face/face-filter.d.ts +12 -0
- package/lib/dist/filters/face/face-filter.js +21 -0
- package/lib/dist/filters/face/torus-filter.d.ts +19 -0
- package/lib/dist/filters/face/torus-filter.js +38 -0
- package/lib/dist/helpers/scene-helpers.d.ts +3 -1
- package/lib/dist/helpers/scene-helpers.js +6 -3
- package/lib/dist/index.d.ts +1 -0
- package/lib/dist/oc/boolean-ops.d.ts +5 -3
- package/lib/dist/oc/boolean-ops.js +15 -2
- package/lib/dist/oc/face-ops.d.ts +0 -1
- package/lib/dist/oc/face-ops.js +0 -13
- package/lib/dist/oc/face-query.d.ts +2 -0
- package/lib/dist/oc/face-query.js +30 -0
- package/lib/dist/oc/fillet-ops.js +84 -66
- package/lib/dist/oc/mesh.d.ts +25 -2
- package/lib/dist/oc/mesh.js +112 -35
- package/lib/dist/oc/shape-ops.d.ts +1 -21
- package/lib/dist/oc/shape-ops.js +0 -103
- package/lib/dist/rendering/mesh-transform.js +17 -1
- package/lib/dist/rendering/render-solid.js +19 -6
- package/lib/dist/rendering/render-wire.js +2 -0
- package/lib/dist/rendering/render.d.ts +12 -2
- package/lib/dist/rendering/render.js +195 -220
- package/lib/dist/scene-manager.d.ts +2 -0
- package/lib/dist/scene-manager.js +4 -3
- package/lib/dist/tests/features/extrude.test.js +71 -0
- package/lib/dist/tests/features/fillet2d.test.js +16 -1
- package/lib/dist/tests/features/select.test.js +50 -0
- package/lib/dist/tests/setup.js +3 -2
- package/lib/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/ui/dist/assets/{index-BeLxRMCv.js → index-55iqIwnj.js} +37 -37
- package/ui/dist/index.html +1 -1
- package/lib/dist/common/solid-face.d.ts +0 -9
- package/lib/dist/common/solid-face.js +0 -22
package/lib/dist/oc/mesh.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { getOC } from "./init.js";
|
|
2
|
+
// Flip to false to benchmark single-threaded meshing.
|
|
3
|
+
const DEFAULT_LIN_DEFLECTION = 0.1;
|
|
4
|
+
const DEFAULT_ANG_DEFLECTION = 0.5;
|
|
2
5
|
export class Mesh {
|
|
3
6
|
// Wrapper methods (public API for external callers)
|
|
4
7
|
static triangulateFace(face, vertexOffset = 0) {
|
|
@@ -7,23 +10,33 @@ export class Mesh {
|
|
|
7
10
|
static discretizeEdge(edge) {
|
|
8
11
|
return Mesh.discretizeEdgeRaw(edge.getShape());
|
|
9
12
|
}
|
|
10
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Triangulates `shape` only if it doesn't already have an up-to-date
|
|
15
|
+
* triangulation at the requested deflection. Returns true when a fresh
|
|
16
|
+
* mesh was built, false when the stored one was reused.
|
|
17
|
+
*/
|
|
18
|
+
static ensureTriangulated(shape, opts = {}) {
|
|
11
19
|
const oc = getOC();
|
|
12
|
-
const
|
|
20
|
+
const linDefl = opts.linDefl ?? DEFAULT_LIN_DEFLECTION;
|
|
21
|
+
const angDefl = opts.angDefl ?? DEFAULT_ANG_DEFLECTION;
|
|
22
|
+
const relative = opts.relative ?? false;
|
|
23
|
+
const checkFreeEdges = opts.checkFreeEdges ?? true;
|
|
24
|
+
if (oc.BRepTools.Triangulation(shape, linDefl, checkFreeEdges)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
const inc = new oc.BRepMesh_IncrementalMesh(shape, linDefl, relative, angDefl, false);
|
|
13
28
|
inc.delete();
|
|
29
|
+
return true;
|
|
14
30
|
}
|
|
15
31
|
// Raw methods (for oc-internal use)
|
|
16
32
|
static triangulateFaceRaw(face, vertexOffset = 0) {
|
|
17
|
-
const oc = getOC();
|
|
18
|
-
let inc;
|
|
19
33
|
try {
|
|
20
|
-
|
|
34
|
+
Mesh.ensureTriangulated(face);
|
|
21
35
|
}
|
|
22
36
|
catch (e) {
|
|
23
37
|
console.error("Face mesh failed", e);
|
|
24
38
|
return null;
|
|
25
39
|
}
|
|
26
|
-
inc.delete();
|
|
27
40
|
return Mesh.extractFaceTriangulationRaw(face, vertexOffset);
|
|
28
41
|
}
|
|
29
42
|
static extractFaceTriangulationRaw(face, vertexOffset = 0) {
|
|
@@ -80,39 +93,103 @@ export class Mesh {
|
|
|
80
93
|
aLocation.delete();
|
|
81
94
|
return { vertices, normals, indices, count: nbNodes };
|
|
82
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Reads the polyline stored for `edge` as a polygon-on-triangulation of
|
|
98
|
+
* `face`. Node indices point into the face's triangulation, so the edge
|
|
99
|
+
* samples coincide exactly with the face mesh vertices (watertight).
|
|
100
|
+
*/
|
|
101
|
+
static discretizeEdgeOnFace(edge, face) {
|
|
102
|
+
const oc = getOC();
|
|
103
|
+
if (oc.BRep_Tool.Degenerated(edge)) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
const loc = new oc.TopLoc_Location();
|
|
107
|
+
const triHandle = oc.BRep_Tool.Triangulation(face, loc, 0);
|
|
108
|
+
if (triHandle.IsNull()) {
|
|
109
|
+
triHandle.delete();
|
|
110
|
+
loc.delete();
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const polyHandle = oc.BRep_Tool.PolygonOnTriangulation(edge, triHandle, loc);
|
|
114
|
+
if (polyHandle.IsNull()) {
|
|
115
|
+
polyHandle.delete();
|
|
116
|
+
triHandle.delete();
|
|
117
|
+
loc.delete();
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
const tri = triHandle.get();
|
|
121
|
+
const poly = polyHandle.get();
|
|
122
|
+
const nbNodes = poly.NbNodes();
|
|
123
|
+
const tx = loc.Transformation();
|
|
124
|
+
const vertices = new Array(nbNodes * 3);
|
|
125
|
+
for (let i = 1; i <= nbNodes; i++) {
|
|
126
|
+
const nodeIdx = poly.Node(i);
|
|
127
|
+
const p = tri.Node(nodeIdx);
|
|
128
|
+
const pT = p.Transformed(tx);
|
|
129
|
+
const base = (i - 1) * 3;
|
|
130
|
+
vertices[base] = pT.X();
|
|
131
|
+
vertices[base + 1] = pT.Y();
|
|
132
|
+
vertices[base + 2] = pT.Z();
|
|
133
|
+
p.delete();
|
|
134
|
+
pT.delete();
|
|
135
|
+
}
|
|
136
|
+
const indices = new Array((nbNodes - 1) * 2);
|
|
137
|
+
for (let i = 0; i < nbNodes - 1; i++) {
|
|
138
|
+
indices[i * 2] = i;
|
|
139
|
+
indices[i * 2 + 1] = i + 1;
|
|
140
|
+
}
|
|
141
|
+
tx.delete();
|
|
142
|
+
polyHandle.delete();
|
|
143
|
+
triHandle.delete();
|
|
144
|
+
loc.delete();
|
|
145
|
+
return { vertices, normals: [], indices };
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Reads the stored 3D polygon for a free edge (one not attached to a
|
|
149
|
+
* meshed face). Caller must have already run `ensureTriangulated` on the
|
|
150
|
+
* edge or its parent wire.
|
|
151
|
+
*/
|
|
83
152
|
static discretizeEdgeRaw(edge) {
|
|
84
153
|
const oc = getOC();
|
|
85
154
|
const ocEdge = oc.TopoDS.Edge(edge);
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const last = adaptor.LastParameter();
|
|
90
|
-
const points = [];
|
|
91
|
-
if (type === oc.GeomAbs_CurveType.GeomAbs_Line) {
|
|
92
|
-
const startPnt = adaptor.Value(first);
|
|
93
|
-
const endPnt = adaptor.Value(last);
|
|
94
|
-
points.push(startPnt.X(), startPnt.Y(), startPnt.Z());
|
|
95
|
-
points.push(endPnt.X(), endPnt.Y(), endPnt.Z());
|
|
96
|
-
startPnt.delete();
|
|
97
|
-
endPnt.delete();
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
const numSegments = Math.max(1, Math.floor((last - first) / 0.01));
|
|
101
|
-
for (let i = 0; i <= numSegments; i++) {
|
|
102
|
-
const t = first + ((last - first) * i) / numSegments;
|
|
103
|
-
const pnt = adaptor.Value(t);
|
|
104
|
-
points.push(pnt.X(), pnt.Y(), pnt.Z());
|
|
105
|
-
pnt.delete();
|
|
106
|
-
}
|
|
155
|
+
if (oc.BRep_Tool.Degenerated(ocEdge)) {
|
|
156
|
+
ocEdge.delete();
|
|
157
|
+
return { vertices: [], normals: [], indices: [] };
|
|
107
158
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
159
|
+
Mesh.ensureTriangulated(edge);
|
|
160
|
+
const loc = new oc.TopLoc_Location();
|
|
161
|
+
const polyHandle = oc.BRep_Tool.Polygon3D(ocEdge, loc);
|
|
162
|
+
if (polyHandle.IsNull()) {
|
|
163
|
+
polyHandle.delete();
|
|
164
|
+
loc.delete();
|
|
165
|
+
ocEdge.delete();
|
|
166
|
+
console.warn("Edge has no stored Polygon3D after meshing; returning empty polyline.");
|
|
167
|
+
return { vertices: [], normals: [], indices: [] };
|
|
115
168
|
}
|
|
116
|
-
|
|
169
|
+
const poly = polyHandle.get();
|
|
170
|
+
const nbNodes = poly.NbNodes();
|
|
171
|
+
const nodes = poly.Nodes();
|
|
172
|
+
const tx = loc.Transformation();
|
|
173
|
+
const vertices = new Array(nbNodes * 3);
|
|
174
|
+
for (let i = 1; i <= nbNodes; i++) {
|
|
175
|
+
const p = nodes.Value(i);
|
|
176
|
+
const pT = p.Transformed(tx);
|
|
177
|
+
const base = (i - 1) * 3;
|
|
178
|
+
vertices[base] = pT.X();
|
|
179
|
+
vertices[base + 1] = pT.Y();
|
|
180
|
+
vertices[base + 2] = pT.Z();
|
|
181
|
+
p.delete();
|
|
182
|
+
pT.delete();
|
|
183
|
+
}
|
|
184
|
+
const indices = new Array((nbNodes - 1) * 2);
|
|
185
|
+
for (let i = 0; i < nbNodes - 1; i++) {
|
|
186
|
+
indices[i * 2] = i;
|
|
187
|
+
indices[i * 2 + 1] = i + 1;
|
|
188
|
+
}
|
|
189
|
+
tx.delete();
|
|
190
|
+
polyHandle.delete();
|
|
191
|
+
loc.delete();
|
|
192
|
+
ocEdge.delete();
|
|
193
|
+
return { vertices, normals: [], indices };
|
|
117
194
|
}
|
|
118
195
|
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import type { TopTools_ListOfShape,
|
|
1
|
+
import type { TopTools_ListOfShape, TopoDS_Shape } from "occjs-wrapper";
|
|
2
2
|
import { Matrix4 } from "../math/matrix4.js";
|
|
3
|
-
import { Vector3d } from "../math/vector3d.js";
|
|
4
3
|
import { Shape } from "../common/shape.js";
|
|
5
|
-
import { Face } from "../common/face.js";
|
|
6
|
-
import { Solid } from "../common/solid.js";
|
|
7
4
|
import { BoundingBox } from "../helpers/types.js";
|
|
8
|
-
import { Axis } from "../math/axis.js";
|
|
9
5
|
export declare class ShapeOps {
|
|
10
6
|
static transform(shape: Shape, matrix: Matrix4): Shape;
|
|
11
7
|
static getBoundingBox(shape: Shape | TopoDS_Shape): BoundingBox;
|
|
@@ -14,21 +10,5 @@ export declare class ShapeOps {
|
|
|
14
10
|
static makeCompoundRaw(shapes: TopoDS_Shape[]): import("occjs-wrapper").TopoDS_Compound;
|
|
15
11
|
static cleanShape(shape: Shape): Shape;
|
|
16
12
|
static cleanShapeRaw(shape: TopoDS_Shape): TopoDS_Shape;
|
|
17
|
-
static getSolidOutwardNormal(face: Face, solid: Solid): Vector3d;
|
|
18
|
-
static getSolidOutwardNormalRaw(face: TopoDS_Face, solid: TopoDS_Solid): Vector3d;
|
|
19
|
-
static mirrorShape(shape: Shape, mirrorPoint: {
|
|
20
|
-
x: number;
|
|
21
|
-
y: number;
|
|
22
|
-
z: number;
|
|
23
|
-
}): Shape;
|
|
24
|
-
static mirrorShapeRaw(shape: TopoDS_Shape, mirrorPoint: {
|
|
25
|
-
x: number;
|
|
26
|
-
y: number;
|
|
27
|
-
z: number;
|
|
28
|
-
}): TopoDS_Shape;
|
|
29
|
-
static translateShape(shape: Shape, direction: Vector3d): Shape;
|
|
30
|
-
static translateShapeRaw(shape: TopoDS_Shape, direction: Vector3d): TopoDS_Shape;
|
|
31
|
-
static rotateShape(shape: TopoDS_Shape, axis: Axis, angle: number): TopoDS_Shape;
|
|
32
13
|
static shapeListToArray(list: TopTools_ListOfShape): TopoDS_Shape[];
|
|
33
|
-
static edgeMiddlePoint(edge: TopoDS_Edge): import("occjs-wrapper").gp_Pnt;
|
|
34
14
|
}
|
package/lib/dist/oc/shape-ops.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { getOC } from "./init.js";
|
|
2
2
|
import { Convert } from "./convert.js";
|
|
3
|
-
import { Vector3d } from "../math/vector3d.js";
|
|
4
3
|
import { Shape } from "../common/shape.js";
|
|
5
4
|
import { ShapeFactory } from "../common/shape-factory.js";
|
|
6
5
|
export class ShapeOps {
|
|
@@ -94,98 +93,6 @@ export class ShapeOps {
|
|
|
94
93
|
progress.delete();
|
|
95
94
|
return fixed;
|
|
96
95
|
}
|
|
97
|
-
static getSolidOutwardNormal(face, solid) {
|
|
98
|
-
return ShapeOps.getSolidOutwardNormalRaw(face.getShape(), solid.getShape());
|
|
99
|
-
}
|
|
100
|
-
static getSolidOutwardNormalRaw(face, solid) {
|
|
101
|
-
const oc = getOC();
|
|
102
|
-
const surfaceAdaptor = new oc.BRepAdaptor_Surface(face, true);
|
|
103
|
-
const type = surfaceAdaptor.GetType();
|
|
104
|
-
if (type !== oc.GeomAbs_SurfaceType.GeomAbs_Plane) {
|
|
105
|
-
surfaceAdaptor.delete();
|
|
106
|
-
throw new Error("Non-planar faces not supported for normal calculation");
|
|
107
|
-
}
|
|
108
|
-
const uFirst = surfaceAdaptor.FirstUParameter();
|
|
109
|
-
const uLast = surfaceAdaptor.LastUParameter();
|
|
110
|
-
const vFirst = surfaceAdaptor.FirstVParameter();
|
|
111
|
-
const vLast = surfaceAdaptor.LastVParameter();
|
|
112
|
-
const u = (uFirst + uLast) / 2.0;
|
|
113
|
-
const v = (vFirst + vLast) / 2.0;
|
|
114
|
-
const testPoint = new oc.gp_Pnt();
|
|
115
|
-
const du = new oc.gp_Vec();
|
|
116
|
-
const dv = new oc.gp_Vec();
|
|
117
|
-
surfaceAdaptor.D1(u, v, testPoint, du, dv);
|
|
118
|
-
const geometricNormal = surfaceAdaptor.Plane().Position().Direction();
|
|
119
|
-
if (face.Orientation() === oc.TopAbs_Orientation.TopAbs_REVERSED) {
|
|
120
|
-
geometricNormal.Reverse();
|
|
121
|
-
}
|
|
122
|
-
const offset = 1e-6;
|
|
123
|
-
const testPointOffset = new oc.gp_Pnt(testPoint.X() + geometricNormal.X() * offset, testPoint.Y() + geometricNormal.Y() * offset, testPoint.Z() + geometricNormal.Z() * offset);
|
|
124
|
-
const classifier = new oc.BRepClass3d_SolidClassifier(solid, testPointOffset, oc.Precision.Confusion());
|
|
125
|
-
const state = classifier.State();
|
|
126
|
-
let result;
|
|
127
|
-
if (state === oc.TopAbs_State.TopAbs_IN) {
|
|
128
|
-
result = new Vector3d(-geometricNormal.X(), -geometricNormal.Y(), -geometricNormal.Z());
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
result = new Vector3d(geometricNormal.X(), geometricNormal.Y(), geometricNormal.Z());
|
|
132
|
-
}
|
|
133
|
-
classifier.delete();
|
|
134
|
-
testPointOffset.delete();
|
|
135
|
-
geometricNormal.delete();
|
|
136
|
-
du.delete();
|
|
137
|
-
dv.delete();
|
|
138
|
-
testPoint.delete();
|
|
139
|
-
surfaceAdaptor.delete();
|
|
140
|
-
return result;
|
|
141
|
-
}
|
|
142
|
-
static mirrorShape(shape, mirrorPoint) {
|
|
143
|
-
const result = ShapeOps.mirrorShapeRaw(shape.getShape(), mirrorPoint);
|
|
144
|
-
return ShapeFactory.fromShape(result);
|
|
145
|
-
}
|
|
146
|
-
static mirrorShapeRaw(shape, mirrorPoint) {
|
|
147
|
-
const oc = getOC();
|
|
148
|
-
const point = new oc.gp_Pnt(mirrorPoint.x, mirrorPoint.y, mirrorPoint.z);
|
|
149
|
-
const trsf = new oc.gp_Trsf();
|
|
150
|
-
trsf.SetMirror(point);
|
|
151
|
-
const transformer = new oc.BRepBuilderAPI_Transform(trsf);
|
|
152
|
-
transformer.Perform(shape, true);
|
|
153
|
-
const result = transformer.Shape();
|
|
154
|
-
transformer.delete();
|
|
155
|
-
trsf.delete();
|
|
156
|
-
point.delete();
|
|
157
|
-
return result;
|
|
158
|
-
}
|
|
159
|
-
static translateShape(shape, direction) {
|
|
160
|
-
const result = ShapeOps.translateShapeRaw(shape.getShape(), direction);
|
|
161
|
-
return ShapeFactory.fromShape(result);
|
|
162
|
-
}
|
|
163
|
-
static translateShapeRaw(shape, direction) {
|
|
164
|
-
const oc = getOC();
|
|
165
|
-
const [vec, disposeVec] = Convert.toGpVec(direction);
|
|
166
|
-
const trsf = new oc.gp_Trsf();
|
|
167
|
-
trsf.SetTranslation(vec);
|
|
168
|
-
const transformer = new oc.BRepBuilderAPI_Transform(trsf);
|
|
169
|
-
transformer.Perform(shape, false);
|
|
170
|
-
const result = transformer.Shape();
|
|
171
|
-
transformer.delete();
|
|
172
|
-
trsf.delete();
|
|
173
|
-
disposeVec();
|
|
174
|
-
return result;
|
|
175
|
-
}
|
|
176
|
-
static rotateShape(shape, axis, angle) {
|
|
177
|
-
const oc = getOC();
|
|
178
|
-
const trsf = new oc.gp_Trsf();
|
|
179
|
-
const [gpAxis, disposeGpAxis] = Convert.toGpAx1(axis);
|
|
180
|
-
trsf.SetRotation(gpAxis, angle);
|
|
181
|
-
const transformer = new oc.BRepBuilderAPI_Transform(trsf);
|
|
182
|
-
transformer.Perform(shape, false);
|
|
183
|
-
const result = transformer.Shape();
|
|
184
|
-
transformer.delete();
|
|
185
|
-
trsf.delete();
|
|
186
|
-
disposeGpAxis();
|
|
187
|
-
return result;
|
|
188
|
-
}
|
|
189
96
|
static shapeListToArray(list) {
|
|
190
97
|
let res = [];
|
|
191
98
|
while (list.Size() > 0) {
|
|
@@ -195,14 +102,4 @@ export class ShapeOps {
|
|
|
195
102
|
list.delete();
|
|
196
103
|
return res;
|
|
197
104
|
}
|
|
198
|
-
static edgeMiddlePoint(edge) {
|
|
199
|
-
const oc = getOC();
|
|
200
|
-
const curveAdaptor = new oc.BRepAdaptor_Curve(oc.TopoDS.Edge(edge));
|
|
201
|
-
const curve = curveAdaptor.Curve();
|
|
202
|
-
const midParam = (curve.FirstParameter() + curve.LastParameter()) / 2.0;
|
|
203
|
-
const midPoint = curve.Value(midParam);
|
|
204
|
-
const result = new oc.gp_Pnt(midPoint.X(), midPoint.Y(), midPoint.Z());
|
|
205
|
-
curveAdaptor.delete();
|
|
206
|
-
return result;
|
|
207
|
-
}
|
|
208
105
|
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
export function transformMeshes(meshes, matrix) {
|
|
2
2
|
const m = matrix.elements;
|
|
3
|
+
// Determinant of the 3x3 linear part. Negative for mirror/reflection
|
|
4
|
+
// transforms — those flip triangle winding, so we have to swap indices
|
|
5
|
+
// to keep faces front-facing after the vertex transform.
|
|
6
|
+
const det3 = m[0] * (m[5] * m[10] - m[9] * m[6]) -
|
|
7
|
+
m[4] * (m[1] * m[10] - m[9] * m[2]) +
|
|
8
|
+
m[8] * (m[1] * m[6] - m[5] * m[2]);
|
|
9
|
+
const flipWinding = det3 < 0;
|
|
3
10
|
return meshes.map(mesh => {
|
|
4
11
|
const srcV = mesh.vertices;
|
|
5
12
|
const srcN = mesh.normals;
|
|
@@ -17,6 +24,15 @@ export function transformMeshes(meshes, matrix) {
|
|
|
17
24
|
newN[i + 1] = m[1] * nx + m[5] * ny + m[9] * nz;
|
|
18
25
|
newN[i + 2] = m[2] * nx + m[6] * ny + m[10] * nz;
|
|
19
26
|
}
|
|
20
|
-
|
|
27
|
+
let newIndices = mesh.indices;
|
|
28
|
+
if (flipWinding && mesh.indices.length % 3 === 0) {
|
|
29
|
+
newIndices = new Array(mesh.indices.length);
|
|
30
|
+
for (let i = 0; i < mesh.indices.length; i += 3) {
|
|
31
|
+
newIndices[i] = mesh.indices[i];
|
|
32
|
+
newIndices[i + 1] = mesh.indices[i + 2];
|
|
33
|
+
newIndices[i + 2] = mesh.indices[i + 1];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return { ...mesh, vertices: newV, normals: newN, indices: newIndices };
|
|
21
37
|
});
|
|
22
38
|
}
|
|
@@ -1,23 +1,36 @@
|
|
|
1
|
-
import { renderEdge } from "./render-edge.js";
|
|
2
1
|
import { Explorer } from "../oc/explorer.js";
|
|
3
2
|
import { Mesh } from "../oc/mesh.js";
|
|
3
|
+
import { getOC } from "../oc/init.js";
|
|
4
4
|
export function renderSolid(shapeObj) {
|
|
5
|
-
Mesh.
|
|
5
|
+
Mesh.ensureTriangulated(shapeObj.getShape());
|
|
6
6
|
const facesMeshes = getFacesMesh(shapeObj);
|
|
7
7
|
const edgesMesh = getEdgesMesh(shapeObj);
|
|
8
8
|
return [...facesMeshes, ...edgesMesh];
|
|
9
9
|
}
|
|
10
10
|
function getEdgesMesh(shapeObj) {
|
|
11
|
+
const oc = getOC();
|
|
11
12
|
const result = [];
|
|
13
|
+
const edgeToFaces = new oc.TopTools_IndexedDataMapOfShapeListOfShape();
|
|
14
|
+
oc.TopExp.MapShapesAndAncestors(shapeObj.getShape(), oc.TopAbs_ShapeEnum.TopAbs_EDGE, oc.TopAbs_ShapeEnum.TopAbs_FACE, edgeToFaces);
|
|
12
15
|
const edges = Explorer.findEdgesWrapped(shapeObj);
|
|
13
16
|
for (let edgeIdx = 0; edgeIdx < edges.length; edgeIdx++) {
|
|
14
|
-
const
|
|
17
|
+
const edgeShape = edges[edgeIdx].getShape();
|
|
18
|
+
const parents = edgeToFaces.Seek(edgeShape);
|
|
19
|
+
if (!parents || parents.Size() === 0) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const parentFace = oc.TopoDS.Face(parents.First());
|
|
23
|
+
const edgeResult = Mesh.discretizeEdgeOnFace(edgeShape, parentFace);
|
|
24
|
+
parentFace.delete();
|
|
15
25
|
if (edgeResult) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
26
|
+
result.push({
|
|
27
|
+
...edgeResult,
|
|
28
|
+
label: 'solid-edges',
|
|
29
|
+
edgeIndex: edgeIdx,
|
|
30
|
+
});
|
|
19
31
|
}
|
|
20
32
|
}
|
|
33
|
+
edgeToFaces.delete();
|
|
21
34
|
return result;
|
|
22
35
|
}
|
|
23
36
|
function getFacesMesh(shapeObj) {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { renderEdge } from "./render-edge.js";
|
|
2
2
|
import { Edge } from "../common/edge.js";
|
|
3
3
|
import { Explorer } from "../oc/explorer.js";
|
|
4
|
+
import { Mesh } from "../oc/mesh.js";
|
|
4
5
|
export function renderWire(shapeObj) {
|
|
5
6
|
const shape = shapeObj.getShape();
|
|
7
|
+
Mesh.ensureTriangulated(shape);
|
|
6
8
|
const edges = Explorer.findShapes(shape, Explorer.getOcShapeType("edge"));
|
|
7
9
|
const allVertices = [];
|
|
8
10
|
const allNormals = [];
|
|
@@ -1,3 +1,13 @@
|
|
|
1
1
|
import { Scene } from "./scene.js";
|
|
2
|
-
export declare
|
|
3
|
-
|
|
2
|
+
export declare class SceneRenderer {
|
|
3
|
+
private readonly meshBuilder;
|
|
4
|
+
render(scene: Scene): Scene;
|
|
5
|
+
renderRollback(scene: Scene, rollbackIndex: number): Scene;
|
|
6
|
+
private renderObject;
|
|
7
|
+
private buildObject;
|
|
8
|
+
private getOrBuildMeshes;
|
|
9
|
+
private toRenderedShape;
|
|
10
|
+
private computeVisibility;
|
|
11
|
+
private aggregateContainerDurations;
|
|
12
|
+
private emitRendered;
|
|
13
|
+
}
|