14
import { asPnt, makeAx3, makeAx2, Point, Vector } from "./geom";
15
import { getOC } from "./oclib.js";
16
import { localGC } from "./register.js";
17
import zip from "./utils/zip";
18
import { GeomAPI_PointsToBSpline } from "replicad-opencascadejs";
20
export const makeLine = (v1: Point, v2: Point): Edge => {
23
new oc.BRepBuilderAPI_MakeEdge_3(asPnt(v1), asPnt(v2)).Edge()
27
export const makeCircle = (
29
center: Point = [0, 0, 0],
30
normal: Point = [0, 0, 1]
33
const [r, gc] = localGC();
35
const ax = r(makeAx2(center, normal));
37
const circleGp = r(new oc.gp_Circ_2(ax, radius));
38
const edgeMaker = r(new oc.BRepBuilderAPI_MakeEdge_8(circleGp));
39
const shape = new Edge(edgeMaker.Edge());
45
export const makeEllipse = (
48
center: Point = [0, 0, 0],
49
normal: Point = [0, 0, 1],
53
const [r, gc] = localGC();
55
const ax = r(makeAx2(center, normal, xDir));
57
if (minorRadius > majorRadius) {
58
throw new Error("The minor radius must be smaller than the major one");
60
const ellipseGp = r(new oc.gp_Elips_2(ax, majorRadius, minorRadius));
61
const edgeMaker = r(new oc.BRepBuilderAPI_MakeEdge_12(ellipseGp));
62
const shape = new Edge(edgeMaker.Edge());
68
export const makeHelix = (
72
center: Point = [0, 0, 0],
73
dir: Point = [0, 0, 1],
77
const [r, gc] = localGC();
78
let myDir = 2 * Math.PI;
85
r(new oc.gp_Pnt2d_3(0.0, 0.0)),
86
r(new oc.gp_Dir2d_4(myDir, pitch))
90
// 3. put it together into a wire
91
const nTurns = height / pitch;
92
const uStart = geomLine.Value(0.0);
93
const uStop = geomLine.Value(
94
nTurns * Math.sqrt((2 * Math.PI) ** 2 + pitch ** 2)
96
const geomSeg = r(new oc.GCE2d_MakeSegment_1(uStart, uStop));
98
// We do not GC this surface (or it can break for some reason)
99
const geomSurf = new oc.Geom_CylindricalSurface_1(
100
r(makeAx3(center, dir)),
105
new oc.BRepBuilderAPI_MakeEdge_30(
106
r(new oc.Handle_Geom2d_Curve_2(geomSeg.Value().get())),
107
r(new oc.Handle_Geom_Surface_2(geomSurf))
111
// 4. Convert to wire and fix building 3d geom from 2d geom
112
const w = r(new oc.BRepBuilderAPI_MakeWire_2(e)).Wire();
113
oc.BRepLib.BuildCurves3d_2(w);
120
export const makeThreePointArc = (v1: Point, v2: Point, v3: Point): Edge => {
122
const circleGeom = new oc.GC_MakeArcOfCircle_4(
128
const curve = new oc.Handle_Geom_Curve_2(circleGeom.get());
129
return new Edge(new oc.BRepBuilderAPI_MakeEdge_24(curve).Edge());
132
export const makeEllipseArc = (
137
center: Point = [0, 0, 0],
138
normal: Point = [0, 0, 1],
142
const [r, gc] = localGC();
144
const ax = r(makeAx2(center, normal, xDir));
145
if (minorRadius > majorRadius) {
146
throw new Error("The minor radius must be smaller than the major one");
149
const ellipseGp = r(new oc.gp_Elips_2(ax, majorRadius, minorRadius));
151
new oc.BRepBuilderAPI_MakeEdge_13(ellipseGp, startAngle, endAngle)
153
const shape = new Edge(edgeMaker.Edge());
159
export interface BSplineApproximationConfig {
163
smoothing?: null | [number, number, number];
166
export const makeBSplineApproximation = function makeBSplineApproximation(
173
}: BSplineApproximationConfig = {}
176
const [r, gc] = localGC();
178
const pnts = r(new oc.TColgp_Array1OfPnt_2(1, points.length));
180
points.forEach((point, index) => {
181
pnts.SetValue(index + 1, r(asPnt(point)));
184
let splineBuilder: GeomAPI_PointsToBSpline;
188
new oc.GeomAPI_PointsToBSpline_5(
194
oc.GeomAbs_Shape.GeomAbs_C2 as any,
200
new oc.GeomAPI_PointsToBSpline_2(
204
oc.GeomAbs_Shape.GeomAbs_C2 as any,
210
if (!splineBuilder.IsDone()) {
212
throw new Error("B-spline approximation failed");
215
const splineGeom = r(splineBuilder.Curve());
217
const curve = r(new oc.Handle_Geom_Curve_2(splineGeom.get()));
218
const edge = new Edge(new oc.BRepBuilderAPI_MakeEdge_24(curve).Edge());
223
export const makeBezierCurve = (points: Point[]): Edge => {
225
const arrayOfPoints = new oc.TColgp_Array1OfPnt_2(1, points.length);
226
points.forEach((p, i) => {
227
arrayOfPoints.SetValue(i + 1, asPnt(p));
229
const bezCurve = new oc.Geom_BezierCurve_1(arrayOfPoints);
231
const curve = new oc.Handle_Geom_Curve_2(bezCurve);
232
return new Edge(new oc.BRepBuilderAPI_MakeEdge_24(curve).Edge());
235
export const makeTangentArc = (
241
const [r, gc] = localGC();
242
const circleGeom = r(
243
new oc.GC_MakeArcOfCircle_5(
244
r(asPnt(startPoint)),
245
new Vector(startTgt).wrapped,
250
const curve = r(new oc.Handle_Geom_Curve_2(circleGeom.get()));
251
const edge = new Edge(r(new oc.BRepBuilderAPI_MakeEdge_24(curve)).Edge());
257
const assembleEdgesAsWire = (listOfEdges: (Edge)[]): Wire => {
264
export const assembleWire = (listOfEdges: (Edge | Wire)[]): Wire => {
266
const wireBuilder = new oc.BRepBuilderAPI_MakeWire_1();
267
listOfEdges.forEach((e) => {
268
if (e instanceof Edge) {
269
wireBuilder.Add_1(e.wrapped);
271
if (e instanceof Wire) {
272
wireBuilder.Add_2(e.wrapped);
276
const progress = new oc.Message_ProgressRange_1();
277
wireBuilder.Build(progress);
278
const res = wireBuilder.Error();
279
if (res !== oc.BRepBuilderAPI_WireError.BRepBuilderAPI_WireDone) {
280
const errorNames = new Map([
281
[oc.BRepBuilderAPI_WireError.BRepBuilderAPI_EmptyWire, "empty wire"],
283
oc.BRepBuilderAPI_WireError.BRepBuilderAPI_NonManifoldWire,
287
oc.BRepBuilderAPI_WireError.BRepBuilderAPI_DisconnectedWire,
292
`Failed to build the wire, ${errorNames.get(res) || "unknown error"}`
296
const wire = new Wire(wireBuilder.Wire());
297
wireBuilder.delete();
302
export const makeFace = (wire: Wire, holes?: Wire[]): Face => {
304
const faceBuilder = new oc.BRepBuilderAPI_MakeFace_15(wire.wrapped, false);
305
holes?.forEach((hole) => {
306
faceBuilder.Add(hole.wrapped);
308
if (!faceBuilder.IsDone()) {
309
faceBuilder.delete();
310
throw new Error("Failed to build the face. Your wire might be non planar.");
312
const face = faceBuilder.Face();
313
faceBuilder.delete();
315
return new Face(face);
318
export const makeNewFaceWithinFace = (originFace: Face, wire: Wire) => {
320
const [r, gc] = localGC();
321
const surface = r(oc.BRep_Tool.Surface_2(originFace.wrapped));
322
const faceBuilder = r(
323
new oc.BRepBuilderAPI_MakeFace_21(surface, wire.wrapped, true)
325
const face = faceBuilder.Face();
328
return new Face(face);
331
export const makeNonPlanarFace = (wire: Wire): Face => {
333
const [r, gc] = localGC();
335
const faceBuilder = r(
336
new oc.BRepOffsetAPI_MakeFilling(
349
wire.edges.forEach((edge) => {
352
oc.GeomAbs_Shape.GeomAbs_C0 as any,
357
const progress = r(new oc.Message_ProgressRange_1());
358
faceBuilder.Build(progress);
359
const newFace = cast(faceBuilder.Shape());
363
if (!(newFace instanceof Face)) {
364
throw new Error("Failed to create a face");
369
export const makeCylinder = (
372
location: Point = [0, 0, 0],
373
direction: Point = [0, 0, 1]
376
const axis = makeAx2(location, direction);
378
const cylinder = new oc.BRepPrimAPI_MakeCylinder_3(axis, radius, height);
379
const solid = new Solid(cylinder.Shape());
385
export const makeSphere = (radius: number): Solid => {
388
const sphereMaker = new oc.BRepPrimAPI_MakeSphere_1(radius);
389
const sphere = new Solid(sphereMaker.Shape());
390
sphereMaker.delete();
394
export const makeVertex = (point: Point): Vertex => {
396
const pnt = asPnt(point);
398
const vertexMaker = new oc.BRepBuilderAPI_MakeVertex(pnt);
399
const vertex = vertexMaker.Vertex();
400
vertexMaker.delete();
402
return new Vertex(vertex);
405
export const makeOffset = (
411
const progress = new oc.Message_ProgressRange_1();
412
const offsetBuilder = new oc.BRepOffsetAPI_MakeOffsetShape();
413
offsetBuilder.PerformByJoin(
417
oc.BRepOffset_Mode.BRepOffset_Skin as any,
420
oc.GeomAbs_JoinType.GeomAbs_Arc as any,
425
const newShape = cast(downcast(offsetBuilder.Shape()));
426
offsetBuilder.delete();
429
if (!isShape3D(newShape)) throw new Error("Could not offset to a 3d shape");
433
export const compoundShapes = (shapeArray: AnyShape[]): AnyShape => {
435
const builder = new oc.TopoDS_Builder();
436
const compound = new oc.TopoDS_Compound();
437
builder.MakeCompound(compound);
439
shapeArray.forEach((s) => {
440
builder.Add(compound, s.wrapped);
444
const newShape = cast(compound);
448
export const makeCompound = compoundShapes;
450
export function makeSolid(facesOrShells: Array<Face | Shell>): Solid {
452
const [r, gc] = localGC();
453
const shellBuilder = r(
454
new oc.BRepBuilderAPI_Sewing(1e-6, true, true, true, false)
457
facesOrShells.forEach(({ wrapped }) => {
458
shellBuilder.Add(wrapped);
461
shellBuilder.Perform(r(new oc.Message_ProgressRange_1()));
463
const shell = r(downcast(shellBuilder.SewedShape()));
464
const solid = cast(r(new oc.ShapeFix_Solid_1()).SolidFromShell(shell));
467
if (!(solid instanceof Solid))
468
throw new Error("Could not make a solid of faces and shells");
473
export const addHolesInFace = (face: Face, holes: Wire[]): Face => {
475
const [r, gc] = localGC();
477
const faceMaker = r(new oc.BRepBuilderAPI_MakeFace_2(face.wrapped));
478
holes.forEach((wire) => {
479
faceMaker.Add(wire.wrapped);
482
const builtFace = r(faceMaker.Face());
484
const fixer = r(new oc.ShapeFix_Face_2(builtFace));
485
fixer.FixOrientation_1();
486
const newFace = fixer.Face();
489
return new Face(newFace);
492
export const makePolygon = (points: Point[]): Face => {
493
if (points.length < 3)
494
throw new Error("You need at least 3 points to make a polygon");
495
const edges = zip([points, [...points.slice(1), points[0]]]).map(
496
([p1, p2]: any) => makeLine(p1, p2)
498
return makeFace(assembleWire(edges));